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