1198160Srrs#include <sys/cdefs.h>
2198160Srrs__FBSDID("$FreeBSD$");
3198160Srrs
4198160Srrs#include <port_before.h>
5198160Srrs#ifdef DO_PTHREADS
6198160Srrs#include <pthread.h>
7198160Srrs#ifdef _LIBC
8198160Srrs#include <pthread_np.h>
9198160Srrs#endif
10198160Srrs#endif
11198160Srrs#include <errno.h>
12198160Srrs#include <netdb.h>
13198160Srrs#include <stdlib.h>
14198160Srrs#include <string.h>
15198160Srrs#include <resolv_mt.h>
16198160Srrs#include <port_after.h>
17198160Srrs
18198160Srrs#ifdef DO_PTHREADS
19198160Srrsstatic pthread_key_t	key;
20198160Srrsstatic int		mt_key_initialized = 0;
21198160Srrs
22198160Srrsstatic int		__res_init_ctx(void);
23198160Srrsstatic void		__res_destroy_ctx(void *);
24198160Srrs
25198160Srrs#if defined(sun) && !defined(__GNUC__)
26198160Srrs#pragma init	(_mtctxres_init)
27198160Srrs#endif
28198160Srrs#endif
29198160Srrs
30198160Srrsstatic mtctxres_t	sharedctx;
31198160Srrs
32198160Srrs#ifdef DO_PTHREADS
33198160Srrs/*
34198160Srrs * Initialize the TSD key. By doing this at library load time, we're
35198160Srrs * implicitly running without interference from other threads, so there's
36198160Srrs * no need for locking.
37198160Srrs */
38198160Srrsstatic void
39198160Srrs_mtctxres_init(void) {
40198160Srrs	int pthread_keycreate_ret;
41198160Srrs
42198160Srrs	pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
43198160Srrs	if (pthread_keycreate_ret == 0)
44198160Srrs		mt_key_initialized = 1;
45198160Srrs}
46198160Srrs#endif
47198160Srrs
48198160Srrs#ifndef _LIBC
49198160Srrs/*
50198160Srrs * To support binaries that used the private MT-safe interface in
51198160Srrs * Solaris 8, we still need to provide the __res_enable_mt()
52198160Srrs * and __res_disable_mt() entry points. They're do-nothing routines.
53198160Srrs */
54198160Srrsint
55198160Srrs__res_enable_mt(void) {
56198160Srrs	return (-1);
57198160Srrs}
58198160Srrs
59198160Srrsint
60198160Srrs__res_disable_mt(void) {
61198160Srrs	return (0);
62198160Srrs}
63198160Srrs#endif
64198160Srrs
65198160Srrs#ifdef DO_PTHREADS
66198160Srrsstatic int
67198160Srrs__res_init_ctx(void) {
68198160Srrs
69198160Srrs	mtctxres_t	*mt;
70198160Srrs	int		ret;
71198160Srrs
72198160Srrs
73198160Srrs	if (pthread_getspecific(key) != 0) {
74198160Srrs		/* Already exists */
75198160Srrs		return (0);
76198160Srrs	}
77198160Srrs
78198160Srrs	if ((mt = malloc(sizeof (mtctxres_t))) == 0) {
79198160Srrs		errno = ENOMEM;
80198160Srrs		return (-1);
81198160Srrs	}
82198160Srrs
83198160Srrs	memset(mt, 0, sizeof (mtctxres_t));
84198160Srrs
85198160Srrs	if ((ret = pthread_setspecific(key, mt)) != 0) {
86198160Srrs		free(mt);
87198160Srrs		errno = ret;
88198160Srrs		return (-1);
89198160Srrs	}
90198160Srrs
91198160Srrs	return (0);
92198160Srrs}
93198160Srrs
94198160Srrsstatic void
95198160Srrs__res_destroy_ctx(void *value) {
96198160Srrs
97198160Srrs	mtctxres_t	*mt = (mtctxres_t *)value;
98198160Srrs
99198160Srrs	if (mt != 0)
100198160Srrs		free(mt);
101198160Srrs}
102198160Srrs#endif
103198160Srrs
104198160Srrsmtctxres_t *
105198160Srrs___mtctxres(void) {
106198160Srrs#ifdef DO_PTHREADS
107198160Srrs	mtctxres_t	*mt;
108198160Srrs
109198160Srrs#ifdef _LIBC
110198160Srrs	if (pthread_main_np() != 0)
111198160Srrs		return (&sharedctx);
112198160Srrs#endif
113198160Srrs
114198160Srrs	/*
115198160Srrs	 * This if clause should only be executed if we are linking
116198160Srrs	 * statically.  When linked dynamically _mtctxres_init() should
117198160Srrs	 * be called at binding time due the #pragma above.
118198160Srrs	 */
119198160Srrs	if (!mt_key_initialized) {
120198160Srrs		static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
121198160Srrs                if (pthread_mutex_lock(&keylock) == 0) {
122198160Srrs			_mtctxres_init();
123198160Srrs			(void) pthread_mutex_unlock(&keylock);
124198160Srrs		}
125198160Srrs	}
126198160Srrs
127198160Srrs	/*
128198160Srrs	 * If we have already been called in this thread return the existing
129198160Srrs	 * context.  Otherwise recreat a new context and return it.  If
130198160Srrs	 * that fails return a global context.
131198160Srrs	 */
132198160Srrs	if (mt_key_initialized) {
133198160Srrs		if (((mt = pthread_getspecific(key)) != 0) ||
134198160Srrs		    (__res_init_ctx() == 0 &&
135198160Srrs		     (mt = pthread_getspecific(key)) != 0)) {
136198160Srrs			return (mt);
137198160Srrs		}
138198160Srrs	}
139198160Srrs#endif
140198160Srrs	return (&sharedctx);
141198160Srrs}
142198160Srrs