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