1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /* $NetBSD: mtctxres.c,v 1.1.1.1 2009/04/12 15:33:56 christos Exp $ */ #include <port_before.h> #ifdef DO_PTHREADS #include <pthread.h> #endif #include <errno.h> #include <netdb.h> #include <stdlib.h> #include <string.h> #include <resolv_mt.h> #include <irs.h> #include <port_after.h> #ifdef DO_PTHREADS static pthread_key_t key; static int mt_key_initialized = 0; static int __res_init_ctx(void); static void __res_destroy_ctx(void *); #if defined(sun) && !defined(__GNUC__) #pragma init (_mtctxres_init) #endif #endif static mtctxres_t sharedctx; #ifdef DO_PTHREADS /* * Initialize the TSD key. By doing this at library load time, we're * implicitly running without interference from other threads, so there's * no need for locking. */ static void _mtctxres_init(void) { int pthread_keycreate_ret; pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx); if (pthread_keycreate_ret == 0) mt_key_initialized = 1; } #endif /* * To support binaries that used the private MT-safe interface in * Solaris 8, we still need to provide the __res_enable_mt() * and __res_disable_mt() entry points. They're do-nothing routines. */ int __res_enable_mt(void) { return (-1); } int __res_disable_mt(void) { return (0); } #ifdef DO_PTHREADS static int __res_init_ctx(void) { mtctxres_t *mt; int ret; if (pthread_getspecific(key) != 0) { /* Already exists */ return (0); } if ((mt = malloc(sizeof (mtctxres_t))) == 0) { errno = ENOMEM; return (-1); } memset(mt, 0, sizeof (mtctxres_t)); if ((ret = pthread_setspecific(key, mt)) != 0) { free(mt); errno = ret; return (-1); } return (0); } static void __res_destroy_ctx(void *value) { mtctxres_t *mt = (mtctxres_t *)value; if (mt != 0) free(mt); } #endif mtctxres_t * ___mtctxres(void) { #ifdef DO_PTHREADS mtctxres_t *mt; /* * This if clause should only be executed if we are linking * statically. When linked dynamically _mtctxres_init() should * be called at binding time due the #pragma above. */ if (!mt_key_initialized) { static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER; if (pthread_mutex_lock(&keylock) == 0) { _mtctxres_init(); (void) pthread_mutex_unlock(&keylock); } } /* * If we have already been called in this thread return the existing * context. Otherwise recreat a new context and return it. If * that fails return a global context. */ if (mt_key_initialized) { if (((mt = pthread_getspecific(key)) != 0) || (__res_init_ctx() == 0 && (mt = pthread_getspecific(key)) != 0)) { return (mt); } } #endif return (&sharedctx); } |