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