libsys: remove usage of pthread_once and _once_stub

that existed in auxv.c, use simple bool gate instead. This leaves a
small window if two threads try to call _elf_aux_info(3) simultaneously.
The situation is safe because auxv parsing is really idempotent. The
parsed data is the same, and we store atomic types (int/long/ptr) so
double-init does not matter.

Reviewed by:	brooks, imp
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D43985
This commit is contained in:
Konstantin Belousov 2024-02-20 16:45:29 +02:00
parent af9758deff
commit 8271d9b99a
4 changed files with 19 additions and 3 deletions

View File

@ -9,6 +9,7 @@ CONFSPACKAGE= runtime
SRCS+= \ SRCS+= \
__pthread_mutex_init_calloc_cb_stub.c \ __pthread_mutex_init_calloc_cb_stub.c \
__xuname.c \ __xuname.c \
_once_stub.c \
_pthread_stubs.c \ _pthread_stubs.c \
_rand48.c \ _rand48.c \
_spinlock_stub.c \ _spinlock_stub.c \

View File

@ -33,7 +33,6 @@ PSEUDO+= _clock_gettime.o _gettimeofday.o
SRCS+= \ SRCS+= \
__error.c \ __error.c \
__getosreldate.c \ __getosreldate.c \
_once_stub.c \
getpagesize.c \ getpagesize.c \
getpagesizes.c \ getpagesizes.c \
interposing_table.c interposing_table.c

View File

@ -31,6 +31,7 @@
#include <errno.h> #include <errno.h>
#include <link.h> #include <link.h>
#include <pthread.h> #include <pthread.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <sys/auxv.h> #include <sys/auxv.h>
#include "un-namespace.h" #include "un-namespace.h"
@ -40,6 +41,8 @@ extern int _DYNAMIC;
#pragma weak _DYNAMIC #pragma weak _DYNAMIC
void *__elf_aux_vector; void *__elf_aux_vector;
#ifndef PIC
static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT; static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
static void static void
@ -61,8 +64,9 @@ __init_elf_aux_vector(void)
return; return;
_once(&aux_vector_once, init_aux_vector_once); _once(&aux_vector_once, init_aux_vector_once);
} }
#endif
static pthread_once_t aux_once = PTHREAD_ONCE_INIT; static bool aux_once = false;
static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags; static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags;
static int hwcap_present, hwcap2_present; static int hwcap_present, hwcap2_present;
static char *canary, *pagesizes, *execpath; static char *canary, *pagesizes, *execpath;
@ -77,11 +81,19 @@ static void _init_aux_powerpc_fixup(void);
int _powerpc_elf_aux_info(int, void *, int); int _powerpc_elf_aux_info(int, void *, int);
#endif #endif
/*
* This function might be called and actual body executed more than
* once in multithreading environment. Due to this, it is and must
* continue to be idempotent. All stores are atomic (no store
* tearing), because we only assign to int/long/ptr.
*/
static void static void
init_aux(void) init_aux(void)
{ {
Elf_Auxinfo *aux; Elf_Auxinfo *aux;
if (aux_once)
return;
for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
switch (aux->a_type) { switch (aux->a_type) {
case AT_BSDFLAGS: case AT_BSDFLAGS:
@ -166,6 +178,8 @@ init_aux(void)
if (!powerpc_new_auxv_format) if (!powerpc_new_auxv_format)
_init_aux_powerpc_fixup(); _init_aux_powerpc_fixup();
#endif #endif
aux_once = true;
} }
#ifdef __powerpc__ #ifdef __powerpc__
@ -256,10 +270,12 @@ _elf_aux_info(int aux, void *buf, int buflen)
{ {
int res; int res;
#ifndef PIC
__init_elf_aux_vector(); __init_elf_aux_vector();
#endif
if (__elf_aux_vector == NULL) if (__elf_aux_vector == NULL)
return (ENOSYS); return (ENOSYS);
_once(&aux_once, init_aux); init_aux(); /* idempotent */
if (buflen < 0) if (buflen < 0)
return (EINVAL); return (EINVAL);