summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authord <>2000-01-06 07:47:09 +0000
committerd <>2000-01-06 07:47:09 +0000
commit14aa38894d778e7f99f53bdcc95137de85b522d9 (patch)
treec2863bfab07c39154d85de51090b443e00948eb2 /src
parentd96347fb8fe6b519f174beb4263729992c24229c (diff)
downloadopenbsd-14aa38894d778e7f99f53bdcc95137de85b522d9.tar.gz
openbsd-14aa38894d778e7f99f53bdcc95137de85b522d9.tar.bz2
openbsd-14aa38894d778e7f99f53bdcc95137de85b522d9.zip
rewrite to use the helpers in the thread/ directory and to define weak alias macros
Diffstat (limited to 'src')
-rw-r--r--src/lib/libc/include/thread_private.h226
1 files changed, 91 insertions, 135 deletions
diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h
index 0027468269..b2677fad0e 100644
--- a/src/lib/libc/include/thread_private.h
+++ b/src/lib/libc/include/thread_private.h
@@ -1,179 +1,135 @@
1/* 1/* $OpenBSD: thread_private.h,v 1.3 2000/01/06 07:47:09 d Exp $ */
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 2
9#ifndef _THREAD_PRIVATE_H_ 3#ifndef _THREAD_PRIVATE_H_
10#define _THREAD_PRIVATE_H_ 4#define _THREAD_PRIVATE_H_
11 5
12/* 6#include <pthread.h>
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 7
21/* 8/*
22 * This global flag is non-zero when a process has created one 9 * This variable is initally 0 when there is exactly one thread.
23 * or more threads. It is used to avoid calling locking functions 10 * It should never decrease.
24 * when they are not required. In libc, this is always assumed
25 * to be zero.
26 */ 11 */
27 12extern int __isthreaded;
28extern volatile int __isthreaded;
29
30#ifdef _THREAD_SAFE
31
32#include <pthread.h>
33#include "pthread_private.h"
34 13
35/* 14/*
36 * File lock contention is difficult to diagnose without knowing 15 * Weak symbols are used in libc so that the thread library can
37 * where locks were set. Allow a debug library to be built which 16 * efficiently wrap libc functions.
38 * records the source file and line number of each lock call. 17 *
18 * Use WEAK_NAME(n) to get a libc-private name for n (_weak_n),
19 * WEAK_ALIAS(n) to generate the weak symbol n pointing to _weak_n,
20 * WEAK_PROTOTYPE(n) to generate a prototype for _weak_n (based on n).
21 *
22 * If the symbol _NO_WEAK_ALIASES is defined, then symbols will be
39 */ 23 */
40#ifdef _FLOCK_DEBUG 24
41#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__) 25#ifdef _NO_WEAK_ALIASES
26#defined _THREAD_SAFE
27#define WEAK_NAME(name) __CONCAT(_weak,name)
28#else
29#define WEAK_NAME(name) name
30#endif
31#define WEAK_ALIAS(name) /* unavailable */
32#define WEAK_PROTOTYPE(name) /* unnecessary */
33#else /* !_NO_WEAK_AILASES */
34#define WEAK_NAME(name) __CONCAT(_weak_,name)
35#define WEAK_ALIAS(name) __weak_alias(name, WEAK_NAME(name))
36#ifdef __GNUC__
37#define WEAK_PROTOTYPE(name) __typeof__(name) WEAK_NAME(name)
42#else 38#else
43#define _FLOCKFILE(x) flockfile(x) 39#define WEAK_PROTOTYPE(name) /* typeof() only in gcc */
44#endif 40#endif
41#endif /* !_NO_WEAK_ALIASES */
45 42
46/* 43/*
47 * These macros help in making persistent storage thread-specific. 44 * These macros help in making persistent storage thread-specific.
48 * Libc makes extensive use of private static data structures 45 * Libc makes extensive use of private static data structures
49 * that hold state across function invocation, and these macros 46 * that hold state across function invocation, and these macros
50 * are no-ops when _THREAD_SAFE is not defined. 47 * are no-ops when running single-threaded.
51 * In a thread-safe library, the static variables are used only for 48 *
52 * initialising the per-thread instances of the state variables. 49 * Linking against the user-thread library causes these macros to
50 * allocate storage on a per-thread basis.
53 */ 51 */
52
53#define __THREAD_MUTEX_NAME(name) __CONCAT(_libc_storage_mutex_,name)
54#define __THREAD_KEY_NAME(name) __CONCAT(_libc_storage_key_,name)
54 55
55/* 56struct _thread_private_key_struct {
56 * Give names to the private variables used to hold per-thread 57 pthread_once_t once;
57 * data structures. 58 void (*cleanfn)__P((void *));
58 */ 59 pthread_key_t key;
59#ifdef __STDC__ 60};
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 61
69/* 62void _libc_private_storage_lock(pthread_mutex_t *);
70 * Mutex declare, lock and unlock macros. 63void _libc_private_storage_unlock(pthread_mutex_t *);
71 */ 64void * _libc_private_storage(volatile struct _thread_private_key_struct *,
65 void *, size_t, void *);
66
67/* Declare a module mutex. */
72#define _THREAD_PRIVATE_MUTEX(name) \ 68#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) = \ 69 static pthread_mutex_t __THREAD_MUTEX_NAME(name) = \
76 &__THREAD_MUTEXP_NAME(name); 70 PTHREAD_MUTEX_INITIALIZER
77 71
72/* Lock a module mutex against use by any other threads. */
78#define _THREAD_PRIVATE_MUTEX_LOCK(name) \ 73#define _THREAD_PRIVATE_MUTEX_LOCK(name) \
79 pthread_mutex_lock(&__THREAD_MUTEX_NAME(name)) 74 _libc_private_storage_lock(&__THREAD_MUTEX_NAME(name))
80 75
76/* Unlock a module mutex. */
81#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ 77#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
82 pthread_mutex_unlock(&__THREAD_MUTEX_NAME(name)) 78 _libc_private_storage_unlock(&__THREAD_MUTEX_NAME(name))
83 79
84/* 80/* Declare a thread-private storage key. */
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) \ 81#define _THREAD_PRIVATE_KEY(name) \
98 static volatile struct _thread_private_key_struct \ 82 static volatile struct _thread_private_key_struct \
99 __THREAD_KEY_NAME(name) = { \ 83 __THREAD_KEY_NAME(name) = { \
100 PTHREAD_MUTEX_STATIC_INITIALIZER, \ 84 PTHREAD_ONCE_INIT, \
101 &__THREAD_KEY_NAME(name).lockd, \
102 0 \ 85 0 \
103 }; 86 }
104 87
105/* 88/*
106 * Initialisation of storage space for a per-thread state variable. 89 * In threaded mode, return a pointer to thread-private memory of
107 * A pointer to a per-thread *copy* of the _initv parameter is returned. 90 * the same size as, and (initially) with the same contents as 'storage'. If
108 * It calls malloc the first time and the space is automatically free'd 91 * an error occurs, the 'error' parameter is returned.
109 * when the thread dies. If you need something a bit more complicated 92 * In single-threaded mode, no storage is allocated. Instead, a pointer
110 * than free() you will need to roll-your-own. 93 * to storage is always returned.
94 * The 'cleanfn' function of the key structure is called to free the storage.
95 * If 'cleanfn' is NULL, then free() is used. This hook can be useful for
96 * getting rid of memory leaks.
111 */ 97 */
112#define _THREAD_PRIVATE(keyname, _initv, _errv) \ 98#define _THREAD_PRIVATE(keyname, storage, error) \
113 ({ \ 99 _libc_private_storage(&__THREAD_KEY_NAME(keyname), \
114 struct _thread_private_key_struct * __k = \ 100 &(storage), sizeof (storage), error)
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 101
155/* 102/*
156 * Macros for locking and unlocking FILEs. These test if the 103 * Macros for locking and unlocking FILEs. These test if the
157 * process is threaded to avoid locking when not required. 104 * process is threaded to avoid locking when not required.
158 */ 105 */
159#define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp) 106#ifdef _FLOCK_DEBUG
160#define FUNLOCKFILE(fp) if (__isthreaded) funlockfile(fp) 107#define FLOCKFILE(fp) _flockfile_debug(fp, __FILE__, __LINE__)
161 108#else
162#else /* !_THREAD_SAFE */ 109#define FLOCKFILE(fp) flockfile(fp)
110#endif
111#define FUNLOCKFILE(fp) funlockfile(fp)
163 112
164/* 113/*
165 * Do-nothing macros for single-threaded case. 114 * File descriptor locking definitions.
166 */ 115 */
167#define _FD_LOCK(f,o,p) (0) 116#define FD_READ 0x1
168#define _FD_UNLOCK(f,o) /* nothing */ 117#define FD_WRITE 0x2
169#define _THREAD_PRIVATE_KEY(_key) /* nothing */ 118#define FD_RDWR (FD_READ | FD_WRITE)
170#define _THREAD_PRIVATE(keyname, _initv, _errv) (&(_initv)) 119
171#define _THREAD_PRIVATE_MUTEX(_name) /* nothing */ 120#ifdef _LOCK_DEBUG
172#define _THREAD_PRIVATE_MUTEX_LOCK(_name) /* nothing */ 121#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock_debug(_fd, _type, \
173#define _THREAD_PRIVATE_MUTEX_UNLOCK(_name) /* nothing */ 122 _ts, __FILE__, __LINE__)
174#define FLOCKFILE(fp) /* nothing */ 123#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock_debug(_fd, _type, \
175#define FUNLOCKFILE(fp) /* nothing */ 124 __FILE__, __LINE__)
176 125#else
177#endif /* !_THREAD_SAFE */ 126#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts)
127#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type)
128#endif
129
130int _thread_fd_lock(int, int, struct timespec *);
131int _thread_fd_lock_debug(int, int, struct timespec *, const char *, int);
132void _thread_fd_unlock(int, int);
133void _thread_fd_unlock_debug(int, int, const char *, int);
178 134
179#endif _THREAD_PRIVATE_H_ 135#endif _THREAD_PRIVATE_H_