| /* $NetBSD: mtctxres.c,v 1.4 2007/03/30 20:40:52 ghen 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 <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); |
| } |