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