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+= \
__pthread_mutex_init_calloc_cb_stub.c \
__xuname.c \
_once_stub.c \
_pthread_stubs.c \
_rand48.c \
_spinlock_stub.c \

View File

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

View File

@ -31,6 +31,7 @@
#include <errno.h>
#include <link.h>
#include <pthread.h>
#include <stdbool.h>
#include <string.h>
#include <sys/auxv.h>
#include "un-namespace.h"
@ -40,6 +41,8 @@ extern int _DYNAMIC;
#pragma weak _DYNAMIC
void *__elf_aux_vector;
#ifndef PIC
static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
static void
@ -61,8 +64,9 @@ __init_elf_aux_vector(void)
return;
_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 hwcap_present, hwcap2_present;
static char *canary, *pagesizes, *execpath;
@ -77,11 +81,19 @@ static void _init_aux_powerpc_fixup(void);
int _powerpc_elf_aux_info(int, void *, int);
#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
init_aux(void)
{
Elf_Auxinfo *aux;
if (aux_once)
return;
for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
switch (aux->a_type) {
case AT_BSDFLAGS:
@ -166,6 +178,8 @@ init_aux(void)
if (!powerpc_new_auxv_format)
_init_aux_powerpc_fixup();
#endif
aux_once = true;
}
#ifdef __powerpc__
@ -256,10 +270,12 @@ _elf_aux_info(int aux, void *buf, int buflen)
{
int res;
#ifndef PIC
__init_elf_aux_vector();
#endif
if (__elf_aux_vector == NULL)
return (ENOSYS);
_once(&aux_once, init_aux);
init_aux(); /* idempotent */
if (buflen < 0)
return (EINVAL);