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
14static pthread_key_t	key;
15static int		mt_key_initialized = 0;
16
17static int		__res_init_ctx(void);
18static void		__res_destroy_ctx(void *);
19
20#if defined(sun) && !defined(__GNUC__)
21#pragma init	(_mtctxres_init)
22#endif
23#endif
24
25static 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 */
33static 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 */
48int
49__res_enable_mt(void) {
50	return (-1);
51}
52
53int
54__res_disable_mt(void) {
55	return (0);
56}
57
58#ifdef DO_PTHREADS
59static 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
87static 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
97mtctxres_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}
130