xref: /netbsd/lib/libc/resolv/mtctxres.c (revision 6550d01e)
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
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
50 __res_enable_mt(void) {
51 	return (-1);
52 }
53 
54 int
55 __res_disable_mt(void) {
56 	return (0);
57 }
58 
59 #ifdef DO_PTHREADS
60 static int
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
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 *
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