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