mtctxres.c revision 297790
11638Srgrimes#include <sys/cdefs.h>
21638Srgrimes__FBSDID("$FreeBSD: head/lib/libc/resolv/mtctxres.c 297790 2016-04-10 19:33:58Z pfg $");
31638Srgrimes
41638Srgrimes#include <port_before.h>
51638Srgrimes#ifdef DO_PTHREADS
61638Srgrimes#include <pthread.h>
71638Srgrimes#ifdef _LIBC
81638Srgrimes#include <pthread_np.h>
91638Srgrimes#endif
101638Srgrimes#endif
111638Srgrimes#include <errno.h>
12263142Seadler#include <netdb.h>
131638Srgrimes#include <stdlib.h>
141638Srgrimes#include <string.h>
151638Srgrimes#include <resolv_mt.h>
161638Srgrimes#include <port_after.h>
171638Srgrimes
181638Srgrimes#ifdef DO_PTHREADS
191638Srgrimesstatic pthread_key_t	key;
201638Srgrimesstatic int		mt_key_initialized = 0;
211638Srgrimes
221638Srgrimesstatic int		__res_init_ctx(void);
231638Srgrimesstatic void		__res_destroy_ctx(void *);
241638Srgrimes
251638Srgrimes#if defined(sun) && !defined(__GNUC__)
261638Srgrimes#pragma init	(_mtctxres_init)
271638Srgrimes#endif
281638Srgrimes#endif
291638Srgrimes
301638Srgrimesstatic mtctxres_t	sharedctx;
311638Srgrimes
321638Srgrimes#ifdef DO_PTHREADS
331638Srgrimes/*
341638Srgrimes * Initialize the TSD key. By doing this at library load time, we're
351638Srgrimes * implicitly running without interference from other threads, so there's
361638Srgrimes * no need for locking.
371638Srgrimes */
381638Srgrimesstatic void
391638Srgrimes_mtctxres_init(void) {
401638Srgrimes	int pthread_keycreate_ret;
411638Srgrimes
421638Srgrimes	pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
431638Srgrimes	if (pthread_keycreate_ret == 0)
441638Srgrimes		mt_key_initialized = 1;
451638Srgrimes}
461638Srgrimes#endif
471638Srgrimes
481638Srgrimes#ifndef _LIBC
491638Srgrimes/*
501638Srgrimes * To support binaries that used the private MT-safe interface in
511638Srgrimes * Solaris 8, we still need to provide the __res_enable_mt()
521638Srgrimes * and __res_disable_mt() entry points. They're do-nothing routines.
531638Srgrimes */
541638Srgrimesint
551638Srgrimes__res_enable_mt(void) {
561638Srgrimes	return (-1);
571638Srgrimes}
581638Srgrimes
591638Srgrimesint
601638Srgrimes__res_disable_mt(void) {
611638Srgrimes	return (0);
621638Srgrimes}
631638Srgrimes#endif
641638Srgrimes
651638Srgrimes#ifdef DO_PTHREADS
661638Srgrimesstatic int
671638Srgrimes__res_init_ctx(void) {
681638Srgrimes
691638Srgrimes	mtctxres_t	*mt;
701638Srgrimes	int		ret;
711638Srgrimes
721638Srgrimes
731638Srgrimes	if (pthread_getspecific(key) != 0) {
741638Srgrimes		/* Already exists */
751638Srgrimes		return (0);
761638Srgrimes	}
771638Srgrimes
781638Srgrimes	if ((mt = malloc(sizeof(mtctxres_t))) == NULL) {
791638Srgrimes		errno = ENOMEM;
801638Srgrimes		return (-1);
811638Srgrimes	}
821638Srgrimes
831638Srgrimes	memset(mt, 0, sizeof (mtctxres_t));
841638Srgrimes
851638Srgrimes	if ((ret = pthread_setspecific(key, mt)) != 0) {
861638Srgrimes		free(mt);
871638Srgrimes		errno = ret;
881638Srgrimes		return (-1);
891638Srgrimes	}
901638Srgrimes
911638Srgrimes	return (0);
921638Srgrimes}
931638Srgrimes
941638Srgrimesstatic void
951638Srgrimes__res_destroy_ctx(void *value) {
961638Srgrimes
971638Srgrimes	free(value);
981638Srgrimes}
991638Srgrimes#endif
1001638Srgrimes
1011638Srgrimesmtctxres_t *
1021638Srgrimes___mtctxres(void) {
1031638Srgrimes#ifdef DO_PTHREADS
1041638Srgrimes	mtctxres_t	*mt;
1051638Srgrimes
1061638Srgrimes#ifdef _LIBC
1071638Srgrimes	if (pthread_main_np() != 0)
1081638Srgrimes		return (&sharedctx);
1091638Srgrimes#endif
1101638Srgrimes
1111638Srgrimes	/*
1121638Srgrimes	 * This if clause should only be executed if we are linking
1131638Srgrimes	 * statically.  When linked dynamically _mtctxres_init() should
1141638Srgrimes	 * be called at binding time due the #pragma above.
1151638Srgrimes	 */
1161638Srgrimes	if (!mt_key_initialized) {
1171638Srgrimes		static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
1181638Srgrimes                if (pthread_mutex_lock(&keylock) == 0) {
1191638Srgrimes			_mtctxres_init();
1201638Srgrimes			(void) pthread_mutex_unlock(&keylock);
1211638Srgrimes		}
1221638Srgrimes	}
1231638Srgrimes
1241638Srgrimes	/*
1251638Srgrimes	 * If we have already been called in this thread return the existing
1261638Srgrimes	 * context.  Otherwise recreat a new context and return it.  If
1271638Srgrimes	 * that fails return a global context.
1281638Srgrimes	 */
1291638Srgrimes	if (mt_key_initialized) {
1301638Srgrimes		if (((mt = pthread_getspecific(key)) != NULL) ||
1311638Srgrimes		    (__res_init_ctx() == 0 &&
1321638Srgrimes		     (mt = pthread_getspecific(key)) != NULL)) {
1331638Srgrimes			return (mt);
1341638Srgrimes		}
1351638Srgrimes	}
1361638Srgrimes#endif
1371638Srgrimes	return (&sharedctx);
1381638Srgrimes}
1391638Srgrimes