summaryrefslogtreecommitdiff
path: root/src/lib/libc/include/thread_private.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/include/thread_private.h')
-rw-r--r--src/lib/libc/include/thread_private.h175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h
new file mode 100644
index 0000000000..a7f7749078
--- /dev/null
+++ b/src/lib/libc/include/thread_private.h
@@ -0,0 +1,175 @@
1/*
2 *
3 * Support for thread-safety in libc and libc_r common code using macros
4 * to declare thread-safe data structures.
5 *
6 * $OpenBSD: thread_private.h,v 1.1 1998/11/20 11:18:41 d Exp $
7 */
8
9#ifndef _THREAD_PRIVATE_H_
10#define _THREAD_PRIVATE_H_
11
12/*
13 * Parts of this file are
14 * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
15 * All rights reserved.
16 *
17 * $Id: thread_private.h,v 1.1 1998/11/20 11:18:41 d Exp $
18 * $OpenBSD: thread_private.h,v 1.1 1998/11/20 11:18:41 d Exp $
19 */
20
21/*
22 * This global flag is non-zero when a process has created one
23 * or more threads. It is used to avoid calling locking functions
24 * when they are not required. In libc, this is always assumed
25 * to be zero.
26 */
27
28extern volatile int __isthreaded;
29
30#ifdef _THREAD_SAFE
31
32#include <pthread.h>
33#include "pthread_private.h"
34
35#ifdef __STDC__
36#define __THREAD_MUTEXP_NAME(name) _thread_mutexp_inst__ ## name
37#define __THREAD_MUTEX_NAME(name) _thread_mutex_inst__ ## name
38#define __THREAD_KEY_NAME(name) _thread_key_inst__ ## name
39#else
40#define __THREAD_MUTEXP_NAME(name) _thread_mutexp_inst__/**/name
41#define __THREAD_MUTEX_NAME(name) _thread_mutex_inst__/**/name
42#define __THREAD_KEY_NAME(name) _thread_key_inst__/**/name
43#endif
44
45/*
46 * Mutex declare, lock and unlock macros.
47 */
48
49#define _THREAD_PRIVATE_MUTEX(name) \
50 static struct pthread_mutex __THREAD_MUTEXP_NAME(name) = \
51 PTHREAD_MUTEX_STATIC_INITIALIZER; \
52 static pthread_mutex_t __THREAD_MUTEX_NAME(name) = \
53 &__THREAD_MUTEXP_NAME(name);
54
55#define _THREAD_PRIVATE_MUTEX_LOCK(name) \
56 pthread_mutex_lock(&__THREAD_MUTEX_NAME(name))
57
58#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
59 pthread_mutex_unlock(&__THREAD_MUTEX_NAME(name))
60
61/*
62 * These macros help in making persistent storage thread-specific.
63 * Libc makes extensive use of private static data structures
64 * that hold state across function invocation, and these macros
65 * are no-ops when _THREAD_SAFE is not defined.
66 * In a thread-safe library, the static variables are used only for
67 * initialising the per-thread instances of the state variables.
68 */
69
70/*
71 * a mutexed data structure used to hold the persistent state's key
72 */
73struct _thread_private_key_struct {
74 struct pthread_mutex lockd;
75 pthread_mutex_t lock;
76 int init;
77 pthread_key_t key;
78};
79
80/*
81 * Declaration of a per-thread state key.
82 */
83#define _THREAD_PRIVATE_KEY(name) \
84 static volatile struct _thread_private_key_struct \
85 __THREAD_KEY_NAME(name) = { \
86 PTHREAD_MUTEX_STATIC_INITIALIZER, \
87 &__THREAD_KEY_NAME(name).lockd, \
88 0 \
89 };
90
91/*
92 * Initialisation of storage space for a per-thread state variable.
93 * A pointer to a per-thread *copy* of the _initv parameter is returned.
94 * It calls malloc the first time and the space is automatically free'd
95 * when the thread dies. If you need something a bit more complicated
96 * than free() you will need to roll-your-own.
97 */
98#define _THREAD_PRIVATE(keyname, _initv, _errv) \
99 ({ \
100 struct _thread_private_key_struct * __k = \
101 &__THREAD_KEY_NAME(keyname); \
102 void* __p; \
103 extern void free __P((void*)); \
104 extern void* malloc __P((size_t)); \
105 \
106 if (!__isthreaded) { \
107 /* non-threaded behaviour */ \
108 __p = &(_initv); \
109 goto _ok; \
110 } \
111 \
112 /* create key for first thread */ \
113 pthread_mutex_lock(&__k->lock); \
114 if (__k->init == 0) { \
115 if (pthread_key_create(&__k->key, free)) { \
116 pthread_mutex_unlock(&__k->lock); \
117 goto _err; \
118 } \
119 __k->init = 1; \
120 } \
121 pthread_mutex_unlock(&__k->lock); \
122 \
123 if ((__p = pthread_getspecific(__k->key)) == NULL) { \
124 /* alloc space on 1st call in this thread */ \
125 if ((__p = malloc(sizeof(_initv))) == NULL) \
126 goto _err; \
127 if (pthread_setspecific(__k->key, __p) != 0) { \
128 free(__p); \
129 goto _err; \
130 } \
131 /* initialise with _initv */ \
132 memcpy(__p, &_initv, sizeof(_initv)); \
133 } \
134 goto _ok; \
135 _err: \
136 __p = (_errv); \
137 _ok: \
138 __p; \
139 })
140
141#else
142
143
144/*
145 * do-nothing macros for single-threaded case
146 */
147#define _FD_LOCK(f,o,p) (0)
148#define _FD_UNLOCK(f,o) /* nothing */
149#define _THREAD_PRIVATE_KEY(_key) /* nothing */
150#define _THREAD_PRIVATE(keyname, _initv, _errv) (&(_initv))
151#define _THREAD_PRIVATE_MUTEX(_name) /* nothing */
152#define _THREAD_PRIVATE_MUTEX_LOCK(_name) /* nothing */
153#define _THREAD_PRIVATE_MUTEX_UNLOCK(_name) /* nothing */
154
155#endif
156
157/*
158 * File lock contention is difficult to diagnose without knowing
159 * where locks were set. Allow a debug library to be built which
160 * records the source file and line number of each lock call.
161 */
162#ifdef _FLOCK_DEBUG
163#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__)
164#else
165#define _FLOCKFILE(x) flockfile(x)
166#endif
167
168/*
169 * Macros for locking and unlocking FILEs. These test if the
170 * process is threaded to avoid locking when not required.
171 */
172#define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp)
173#define FUNLOCKFILE(fp) if (__isthreaded) funlockfile(fp)
174
175#endif _THREAD_PRIVATE_H_