On Sun, Apr 03, 2016 at 08:20:57PM -0700, Philip Guenther wrote:
>
> libc has a number of macros for dealing with thread safety such that it
> can operate efficiently when single-threaded but Do The Right Thing when
> multi-threaded. In include/thread_private.h are two sets of macros that
> look interchangable but that are quite different on the underside.
>
> _MUTEX_LOCK() and _MUTEX_UNLOCK() let libc treat a void* variable as a
> mutex. They're no-ops unless linked with libpthread.
>
> _THREAD_PRIVATE_MUTEX_LOCK() and _THREAD_PRIVATE_MUTEX_UNLOCK() look
> similar, but require you to declare the mutex with _THREAD_PRIVATE_MUTEX()
> and have this _THREAD_PRIVATE() extra feature for doing thread-specific
> data.
>
> The trick is that the _THREAD_PRIVATE() feature means
> _THREAD_PRIVATE_MUTEX_LOCK() is quite a bit more expensive, allocating a
> couple more chunks of memory and creating a pthread_key_t under the
> covers, which involves another spin lock, etc. If you're not using the
> per-thread storage part of _THREAD_PRIVATE* then it's a pile of overhead
> and over kill.
>
> So, diff below converts several uses of _THREAD_PRIVATE_MUTEX_*() to
> _MUTEX_*(). Regress tests libc/stdio_threading/* and asr/bin/threads
> still pass with this.
>
> ok?
I think the mutex in gen/getpwent.c and the 'lcl' and 'gmt' mutexes in
time/localtime.c could be replaced too. See comment inline.
>
> Philip Guenther
>
>
> Index: stdio/findfp.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/stdio/findfp.c,v
> retrieving revision 1.18
> diff -u -p -r1.18 findfp.c
> --- stdio/findfp.c 27 Aug 2015 04:37:09 -0000 1.18
> +++ stdio/findfp.c 4 Apr 2016 00:47:53 -0000
> @@ -56,7 +56,7 @@ static FILE usual[FOPEN_MAX - 3];
> static struct __sfileext usualext[FOPEN_MAX - 3];
> static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
> static struct glue *lastglue = &uglue;
> -_THREAD_PRIVATE_MUTEX(__sfp_mutex);
> +static void *sfp_mutex;
>
> static struct __sfileext __sFext[3];
> FILE __sF[3] = {
> @@ -108,7 +108,7 @@ __sfp(void)
> if (!__sdidinit)
> __sinit();
>
> - _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
> + _MUTEX_LOCK(&sfp_mutex);
> for (g = &__sglue; g != NULL; g = g->next) {
> for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
> if (fp->_flags == 0)
> @@ -116,16 +116,16 @@ __sfp(void)
> }
>
> /* release lock while mallocing */
> - _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
> + _MUTEX_UNLOCK(&sfp_mutex);
> if ((g = moreglue(NDYNAMIC)) == NULL)
> return (NULL);
> - _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
> + _MUTEX_LOCK(&sfp_mutex);
> lastglue->next = g;
> lastglue = g;
> fp = g->iobs;
> found:
> fp->_flags = 1; /* reserve this slot; caller sets real flags */
> - _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
> + _MUTEX_UNLOCK(&sfp_mutex);
> fp->_p = NULL; /* no current pointer */
> fp->_w = 0; /* nothing to read or write */
> fp->_r = 0;
> @@ -161,10 +161,10 @@ _cleanup(void)
> void
> __sinit(void)
> {
> - _THREAD_PRIVATE_MUTEX(__sinit_mutex);
> + static void *sinit_mutex;
> int i;
>
> - _THREAD_PRIVATE_MUTEX_LOCK(__sinit_mutex);
> + _MUTEX_LOCK(&sinit_mutex);
> if (__sdidinit)
> goto out; /* bail out if caller lost the race */
> for (i = 0; i < FOPEN_MAX - 3; i++) {
> @@ -174,5 +174,5 @@ __sinit(void)
> __atexit_register_cleanup(_cleanup); /* conservative */
> __sdidinit = 1;
> out:
> - _THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex);
> + _MUTEX_UNLOCK(&sinit_mutex);
> }
> Index: stdlib/random.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/stdlib/random.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 random.c
> --- stdlib/random.c 16 Jan 2015 16:48:51 -0000 1.29
> +++ stdlib/random.c 4 Apr 2016 00:47:53 -0000
> @@ -176,10 +176,11 @@ static int rand_sep = SEP_3;
> static int random_deterministic;
>
> _THREAD_PRIVATE_MUTEX(random);
This line can be removed.
> +static void *random_mutex;
> static long random_l(void);
>
> -#define LOCK() _THREAD_PRIVATE_MUTEX_LOCK(random)
> -#define UNLOCK() _THREAD_PRIVATE_MUTEX_UNLOCK(random)
> +#define LOCK() _MUTEX_LOCK(&random_mutex)
> +#define UNLOCK() _MUTEX_UNLOCK(&random_mutex)
>
> /*
> * srandom:
> Index: asr/res_init.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/asr/res_init.c,v
> retrieving revision 1.9
> diff -u -p -r1.9 res_init.c
> --- asr/res_init.c 23 Mar 2016 18:45:03 -0000 1.9
> +++ asr/res_init.c 4 Apr 2016 00:47:53 -0000
> @@ -37,7 +37,7 @@ int h_errno;
> int
> res_init(void)
> {
> - _THREAD_PRIVATE_MUTEX(init);
> + static void *resinit_mutex;
> struct asr_ctx *ac;
> int i;
>
> @@ -48,7 +48,7 @@ res_init(void)
> * structure from the async context, not overriding fields set early
> * by the user.
> */
> - _THREAD_PRIVATE_MUTEX_LOCK(init);
> + _MUTEX_LOCK(&resinit_mutex);
> if (!(_res.options & RES_INIT)) {
> if (_res.retry == 0)
> _res.retry = ac->ac_nsretries;
> @@ -75,7 +75,7 @@ res_init(void)
> _res.nscount = i;
> _res.options |= RES_INIT;
> }
> - _THREAD_PRIVATE_MUTEX_UNLOCK(init);
> + _MUTEX_UNLOCK(&resinit_mutex);
>
> /*
> * If the program is not threaded, we want to reflect (some) changes
> Index: net/res_random.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/net/res_random.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 res_random.c
> --- net/res_random.c 5 Oct 2015 02:57:16 -0000 1.23
> +++ net/res_random.c 4 Apr 2016 00:47:53 -0000
> @@ -230,12 +230,12 @@ __res_randomid(void)
> struct timespec ts;
> pid_t pid;
> u_int r;
> - _THREAD_PRIVATE_MUTEX(random);
> + static void *randomid_mutex;
>
> clock_gettime(CLOCK_MONOTONIC, &ts);
> pid = getpid();
>
> - _THREAD_PRIVATE_MUTEX_LOCK(random);
> + _MUTEX_LOCK(&randomid_mutex);
>
> if (ru_counter >= RU_MAX || ts.tv_sec > ru_reseed || pid != ru_pid) {
> res_initid();
> @@ -248,7 +248,7 @@ __res_randomid(void)
>
> r = permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb;
>
> - _THREAD_PRIVATE_MUTEX_UNLOCK(random);
> + _MUTEX_UNLOCK(&randomid_mutex);
>
> return (r);
> }
>