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.h179
1 files changed, 179 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..0027468269
--- /dev/null
+++ b/src/lib/libc/include/thread_private.h
@@ -0,0 +1,179 @@
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.2 1999/01/06 05:19:32 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.2 1999/01/06 05:19:32 d Exp $
18 * $OpenBSD: thread_private.h,v 1.2 1999/01/06 05:19:32 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/*
36 * File lock contention is difficult to diagnose without knowing
37 * where locks were set. Allow a debug library to be built which
38 * records the source file and line number of each lock call.
39 */
40#ifdef _FLOCK_DEBUG
41#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__)
42#else
43#define _FLOCKFILE(x) flockfile(x)
44#endif
45
46/*
47 * These macros help in making persistent storage thread-specific.
48 * Libc makes extensive use of private static data structures
49 * that hold state across function invocation, and these macros
50 * are no-ops when _THREAD_SAFE is not defined.
51 * In a thread-safe library, the static variables are used only for
52 * initialising the per-thread instances of the state variables.
53 */
54
55/*
56 * Give names to the private variables used to hold per-thread
57 * data structures.
58 */
59#ifdef __STDC__
60#define __THREAD_MUTEXP_NAME(name) _thread_mutexp_inst__ ## name
61#define __THREAD_MUTEX_NAME(name) _thread_mutex_inst__ ## name
62#define __THREAD_KEY_NAME(name) _thread_key_inst__ ## name
63#else
64#define __THREAD_MUTEXP_NAME(name) _thread_mutexp_inst__/**/name
65#define __THREAD_MUTEX_NAME(name) _thread_mutex_inst__/**/name
66#define __THREAD_KEY_NAME(name) _thread_key_inst__/**/name
67#endif
68
69/*
70 * Mutex declare, lock and unlock macros.
71 */
72#define _THREAD_PRIVATE_MUTEX(name) \
73 static struct pthread_mutex __THREAD_MUTEXP_NAME(name) = \
74 PTHREAD_MUTEX_STATIC_INITIALIZER; \
75 static pthread_mutex_t __THREAD_MUTEX_NAME(name) = \
76 &__THREAD_MUTEXP_NAME(name);
77
78#define _THREAD_PRIVATE_MUTEX_LOCK(name) \
79 pthread_mutex_lock(&__THREAD_MUTEX_NAME(name))
80
81#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
82 pthread_mutex_unlock(&__THREAD_MUTEX_NAME(name))
83
84/*
85 * A mutexed data structure used to hold the persistent state's key.
86 */
87struct _thread_private_key_struct {
88 struct pthread_mutex lockd;
89 pthread_mutex_t lock;
90 int init;
91 pthread_key_t key;
92};
93
94/*
95 * Declaration of a per-thread state key.
96 */
97#define _THREAD_PRIVATE_KEY(name) \
98 static volatile struct _thread_private_key_struct \
99 __THREAD_KEY_NAME(name) = { \
100 PTHREAD_MUTEX_STATIC_INITIALIZER, \
101 &__THREAD_KEY_NAME(name).lockd, \
102 0 \
103 };
104
105/*
106 * Initialisation of storage space for a per-thread state variable.
107 * A pointer to a per-thread *copy* of the _initv parameter is returned.
108 * It calls malloc the first time and the space is automatically free'd
109 * when the thread dies. If you need something a bit more complicated
110 * than free() you will need to roll-your-own.
111 */
112#define _THREAD_PRIVATE(keyname, _initv, _errv) \
113 ({ \
114 struct _thread_private_key_struct * __k = \
115 &__THREAD_KEY_NAME(keyname); \
116 void* __p; \
117 extern void free __P((void*)); \
118 extern void* malloc __P((size_t)); \
119 \
120 if (!__isthreaded) { \
121 /* non-threaded behaviour */ \
122 __p = &(_initv); \
123 goto _ok; \
124 } \
125 \
126 /* create key for first thread */ \
127 pthread_mutex_lock(&__k->lock); \
128 if (__k->init == 0) { \
129 if (pthread_key_create(&__k->key, free)) { \
130 pthread_mutex_unlock(&__k->lock); \
131 goto _err; \
132 } \
133 __k->init = 1; \
134 } \
135 pthread_mutex_unlock(&__k->lock); \
136 \
137 if ((__p = pthread_getspecific(__k->key)) == NULL) { \
138 /* alloc space on 1st call in this thread */ \
139 if ((__p = malloc(sizeof(_initv))) == NULL) \
140 goto _err; \
141 if (pthread_setspecific(__k->key, __p) != 0) { \
142 free(__p); \
143 goto _err; \
144 } \
145 /* initialise with _initv */ \
146 memcpy(__p, &_initv, sizeof(_initv)); \
147 } \
148 goto _ok; \
149 _err: \
150 __p = (_errv); \
151 _ok: \
152 __p; \
153 })
154
155/*
156 * Macros for locking and unlocking FILEs. These test if the
157 * process is threaded to avoid locking when not required.
158 */
159#define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp)
160#define FUNLOCKFILE(fp) if (__isthreaded) funlockfile(fp)
161
162#else /* !_THREAD_SAFE */
163
164/*
165 * Do-nothing macros for single-threaded case.
166 */
167#define _FD_LOCK(f,o,p) (0)
168#define _FD_UNLOCK(f,o) /* nothing */
169#define _THREAD_PRIVATE_KEY(_key) /* nothing */
170#define _THREAD_PRIVATE(keyname, _initv, _errv) (&(_initv))
171#define _THREAD_PRIVATE_MUTEX(_name) /* nothing */
172#define _THREAD_PRIVATE_MUTEX_LOCK(_name) /* nothing */
173#define _THREAD_PRIVATE_MUTEX_UNLOCK(_name) /* nothing */
174#define FLOCKFILE(fp) /* nothing */
175#define FUNLOCKFILE(fp) /* nothing */
176
177#endif /* !_THREAD_SAFE */
178
179#endif _THREAD_PRIVATE_H_