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