summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libc/include/cancel.h75
-rw-r--r--src/lib/libc/include/namespace.h6
-rw-r--r--src/lib/libc/include/thread_private.h306
3 files changed, 252 insertions, 135 deletions
diff --git a/src/lib/libc/include/cancel.h b/src/lib/libc/include/cancel.h
new file mode 100644
index 0000000000..4f4add471b
--- /dev/null
+++ b/src/lib/libc/include/cancel.h
@@ -0,0 +1,75 @@
1/* $OpenBSD: cancel.h,v 1.1 2016/05/07 19:05:22 guenther Exp $ */
2/*
3 * Copyright (c) 2015 Philip Guenther <guenther@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#ifndef _CANCEL_H_
19#define _CANCEL_H_
20
21#include <tib.h>
22#include "thread_private.h"
23
24__BEGIN_HIDDEN_DECLS
25/* process a cancel request at a cancel point */
26__dead void _thread_canceled(void);
27__END_HIDDEN_DECLS
28
29#ifdef LIBC
30/*
31 * Redirect macros that would use the syscall to instead use our callback
32 */
33#define __get_tcb() _thread_cb.tc_tcb()
34#endif
35
36#define PREP_CANCEL_POINT(tib) \
37 int _cantcancel = (tib)->tib_cantcancel
38
39#define ENTER_CANCEL_POINT_INNER(tib, can_cancel, delay) \
40 if (_cantcancel == 0) { \
41 (tib)->tib_cancel_point = (delay) ? \
42 CANCEL_POINT_DELAYED : CANCEL_POINT; \
43 if (can_cancel) { \
44 __asm volatile("":::"memory"); \
45 if (__predict_false((tib)->tib_canceled)) \
46 _thread_canceled(); \
47 } \
48 }
49
50#define LEAVE_CANCEL_POINT_INNER(tib, can_cancel) \
51 if (_cantcancel == 0) { \
52 (tib)->tib_cancel_point = 0; \
53 if (can_cancel) { \
54 __asm volatile("":::"memory"); \
55 if (__predict_false((tib)->tib_canceled)) \
56 _thread_canceled(); \
57 } \
58 }
59
60/*
61 * Enter or leave a cancelation point, optionally processing pending
62 * cancelation requests. Note that ENTER_CANCEL_POINT opens a block
63 * and LEAVE_CANCEL_POINT must close that same block.
64 */
65#define ENTER_CANCEL_POINT(can_cancel) \
66 { \
67 struct tib *_tib = TIB_GET(); \
68 PREP_CANCEL_POINT(_tib); \
69 ENTER_CANCEL_POINT_INNER(_tib, can_cancel, 0)
70
71#define LEAVE_CANCEL_POINT(can_cancel) \
72 LEAVE_CANCEL_POINT_INNER(_tib, can_cancel); \
73 }
74
75#endif /* _CANCEL_H_ */
diff --git a/src/lib/libc/include/namespace.h b/src/lib/libc/include/namespace.h
index 16d524f666..980c1a8dd6 100644
--- a/src/lib/libc/include/namespace.h
+++ b/src/lib/libc/include/namespace.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: namespace.h,v 1.9 2016/04/05 04:28:32 guenther Exp $ */ 1/* $OpenBSD: namespace.h,v 1.10 2016/05/07 19:05:22 guenther Exp $ */
2 2
3#ifndef _LIBC_NAMESPACE_H_ 3#ifndef _LIBC_NAMESPACE_H_
4#define _LIBC_NAMESPACE_H_ 4#define _LIBC_NAMESPACE_H_
@@ -139,12 +139,14 @@
139#define CANCEL(x) _libc_##x##_cancel 139#define CANCEL(x) _libc_##x##_cancel
140#define WRAP(x) _libc_##x##_wrap 140#define WRAP(x) _libc_##x##_wrap
141#define HIDDEN_STRING(x) "_libc_" __STRING(x) 141#define HIDDEN_STRING(x) "_libc_" __STRING(x)
142#define CANCEL_STRING(x) "_libc_" __STRING(x) "_cancel"
142#define WRAP_STRING(x) "_libc_" __STRING(x) "_wrap" 143#define WRAP_STRING(x) "_libc_" __STRING(x) "_wrap"
143 144
144#define PROTO_NORMAL(x) __dso_hidden typeof(x) x asm(HIDDEN_STRING(x)) 145#define PROTO_NORMAL(x) __dso_hidden typeof(x) x asm(HIDDEN_STRING(x))
145#define PROTO_STD_DEPRECATED(x) typeof(x) x __attribute__((deprecated)) 146#define PROTO_STD_DEPRECATED(x) typeof(x) x __attribute__((deprecated))
146#define PROTO_DEPRECATED(x) typeof(x) x __attribute__((deprecated, weak)) 147#define PROTO_DEPRECATED(x) typeof(x) x __attribute__((deprecated, weak))
147#define PROTO_CANCEL(x) PROTO_NORMAL(x), CANCEL(x) 148#define PROTO_CANCEL(x) __dso_hidden typeof(x) HIDDEN(x), \
149 x asm(CANCEL_STRING(x))
148#define PROTO_WRAP(x) PROTO_NORMAL(x), WRAP(x) 150#define PROTO_WRAP(x) PROTO_NORMAL(x), WRAP(x)
149 151
150#define DEF_STRONG(x) __strong_alias(x, HIDDEN(x)) 152#define DEF_STRONG(x) __strong_alias(x, HIDDEN(x))
diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h
index 43ebf7d96e..c2e0cf0b3f 100644
--- a/src/lib/libc/include/thread_private.h
+++ b/src/lib/libc/include/thread_private.h
@@ -1,52 +1,108 @@
1/* $OpenBSD: thread_private.h,v 1.26 2015/04/07 01:27:07 guenther Exp $ */ 1/* $OpenBSD: thread_private.h,v 1.27 2016/05/07 19:05:22 guenther Exp $ */
2 2
3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ 3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4 4
5#ifndef _THREAD_PRIVATE_H_ 5#ifndef _THREAD_PRIVATE_H_
6#define _THREAD_PRIVATE_H_ 6#define _THREAD_PRIVATE_H_
7 7
8/* 8#include <stdio.h> /* for FILE and __isthreaded */
9 * This file defines the thread library interface to libc. Thread
10 * libraries must implement the functions described here for proper
11 * inter-operation with libc. libc contains weak versions of the
12 * described functions for operation in a non-threaded environment.
13 */
14 9
15/* 10/*
16 * This variable is 0 until a second thread is created. 11 * The callbacks needed by libc to handle the threaded case.
12 * NOTE: Bump the version when you change the struct contents!
13 *
14 * tc_canceled:
15 * If not NULL, what to do when canceled (otherwise _exit(0))
16 *
17 * tc_flockfile, tc_ftrylockfile, and tc_funlockfile:
18 * If not NULL, these implement the flockfile() family.
19 * XXX In theory, you should be able to lock a FILE before
20 * XXX loading libpthread and have that be a real lock on it,
21 * XXX but that doesn't work without the libc base version
22 * XXX tracking the recursion count.
23 *
24 * tc_malloc_lock and tc_malloc_unlock:
25 * tc_atexit_lock and tc_atexit_unlock:
26 * tc_atfork_lock and tc_atfork_unlock:
27 * tc_arc4_lock and tc_arc4_unlock:
28 * The locks used by the malloc, atexit, atfork, and arc4 subsystems.
29 * These have to be ordered specially in the fork/vfork wrappers
30 * and may be implemented differently than the general mutexes
31 * in the callbacks below.
32 *
33 * tc_mutex_lock and tc_mutex_unlock:
34 * Lock and unlock the given mutex. If the given mutex is NULL
35 * a mutex is allocated and initialized automatically.
36 *
37 * tc_mutex_destroy:
38 * Destroy/deallocate the given mutex.
39 *
40 * tc_tag_lock and tc_tag_unlock:
41 * Lock and unlock the mutex associated with the given tag.
42 * If the given tag is NULL a tag is allocated and initialized
43 * automatically.
44 *
45 * tc_tag_storage:
46 * Returns a pointer to per-thread instance of data associated
47 * with the given tag. If the given tag is NULL a tag is
48 * allocated and initialized automatically.
49 *
50 * tc_fork, tc_vfork:
51 * If not NULL, they are called instead of the syscall stub, so that
52 * the thread library can do necessary locking and reinitialization.
53 *
54 *
55 * If <machine/tcb.h> doesn't define TCB_GET(), then locating the TCB in a
56 * threaded process requires a syscall (__get_tcb(2)) which is too much
57 * overhead for single-threaded processes. For those archs, there are two
58 * additional callbacks, though they are placed first in the struct for
59 * convenience in ASM:
60 *
61 * tc_errnoptr:
62 * Returns the address of the thread's errno.
63 *
64 * tc_tcb:
65 * Returns the address of the thread's TCB.
17 */ 66 */
18extern int __isthreaded;
19 67
68struct thread_callbacks {
69 int *(*tc_errnoptr)(void); /* MUST BE FIRST */
70 void *(*tc_tcb)(void);
71 __dead void (*tc_canceled)(void);
72 void (*tc_flockfile)(FILE *);
73 int (*tc_ftrylockfile)(FILE *);
74 void (*tc_funlockfile)(FILE *);
75 void (*tc_malloc_lock)(void);
76 void (*tc_malloc_unlock)(void);
77 void (*tc_atexit_lock)(void);
78 void (*tc_atexit_unlock)(void);
79 void (*tc_atfork_lock)(void);
80 void (*tc_atfork_unlock)(void);
81 void (*tc_arc4_lock)(void);
82 void (*tc_arc4_unlock)(void);
83 void (*tc_mutex_lock)(void **);
84 void (*tc_mutex_unlock)(void **);
85 void (*tc_mutex_destroy)(void **);
86 void (*tc_tag_lock)(void **);
87 void (*tc_tag_unlock)(void **);
88 void *(*tc_tag_storage)(void **, void *, size_t, void *);
89 __pid_t (*tc_fork)(void);
90 __pid_t (*tc_vfork)(void);
91};
92
93__BEGIN_PUBLIC_DECLS
20/* 94/*
21 * Weak symbols are used in libc so that the thread library can 95 * Set the callbacks used by libc
22 * efficiently wrap libc functions.
23 *
24 * Use WEAK_NAME(n) to get a libc-private name for n (_weak_n),
25 * WEAK_ALIAS(n) to generate the weak symbol n pointing to _weak_n,
26 * WEAK_PROTOTYPE(n) to generate a prototype for _weak_n (based on n).
27 */ 96 */
28#define WEAK_NAME(name) __CONCAT(_weak_,name) 97void _thread_set_callbacks(const struct thread_callbacks *_cb, size_t _len);
29#define WEAK_ALIAS(name) __weak_alias(name, WEAK_NAME(name)) 98__END_PUBLIC_DECLS
30#ifdef __GNUC__
31#define WEAK_PROTOTYPE(name) __typeof__(name) WEAK_NAME(name)
32#else
33#define WEAK_PROTOTYPE(name) /* typeof() only in gcc */
34#endif
35 99
36/* 100#ifdef __LIBC__
37 * Ditto for hand-written syscall stubs: 101__BEGIN_HIDDEN_DECLS
38 * 102/* the current set */
39 * Use STUB_NAME(n) to get the strong name of the stub: _thread_sys_n 103extern struct thread_callbacks _thread_cb;
40 * STUB_ALIAS(n) to generate the weak symbol n pointing to _thread_sys_n, 104__END_HIDDEN_DECLS
41 * STUB_PROTOTYPE(n) to generate a prototype for _thread_sys_n (based on n). 105#endif /* __LIBC__ */
42 */
43#define STUB_NAME(name) __CONCAT(_thread_sys_,name)
44#define STUB_ALIAS(name) __weak_alias(name, STUB_NAME(name))
45#ifdef __GNUC__
46#define STUB_PROTOTYPE(name) __typeof__(name) STUB_NAME(name)
47#else
48#define STUB_PROTOTYPE(name) /* typeof() only in gcc */
49#endif
50 106
51/* 107/*
52 * helper macro to make unique names in the thread namespace 108 * helper macro to make unique names in the thread namespace
@@ -54,39 +110,11 @@ extern int __isthreaded;
54#define __THREAD_NAME(name) __CONCAT(_thread_tagname_,name) 110#define __THREAD_NAME(name) __CONCAT(_thread_tagname_,name)
55 111
56/* 112/*
57 * helper functions that exist as (weak) null functions in libc and 113 * Resolver code is special cased in that it uses global keys.
58 * (strong) functions in the thread library. These functions:
59 *
60 * _thread_tag_lock:
61 * lock the mutex associated with the given tag. If the given
62 * tag is NULL a tag is first allocated.
63 *
64 * _thread_tag_unlock:
65 * unlock the mutex associated with the given tag. If the given
66 * tag is NULL a tag is first allocated.
67 *
68 * _thread_tag_storage:
69 * return a pointer to per thread instance of data associated
70 * with the given tag. If the given tag is NULL a tag is first
71 * allocated.
72 *
73 * _thread_mutex_lock:
74 * lock the given mutex. If the given mutex is NULL,
75 * rely on rthreads/pthreads implementation to initialize
76 * the mutex before locking.
77 *
78 * _thread_mutex_unlock:
79 * unlock the given mutex.
80 *
81 * _thread_mutex_destroy:
82 * destroy the given mutex.
83 */ 114 */
84void _thread_tag_lock(void **); 115extern void *__THREAD_NAME(_res);
85void _thread_tag_unlock(void **); 116extern void *__THREAD_NAME(_res_ext);
86void *_thread_tag_storage(void **, void *, size_t, void *); 117extern void *__THREAD_NAME(serv_mutex);
87void _thread_mutex_lock(void **);
88void _thread_mutex_unlock(void **);
89void _thread_mutex_destroy(void **);
90 118
91/* 119/*
92 * Macros used in libc to access thread mutex, keys, and per thread storage. 120 * Macros used in libc to access thread mutex, keys, and per thread storage.
@@ -99,13 +127,40 @@ void _thread_mutex_destroy(void **);
99 static void *__THREAD_NAME(name) 127 static void *__THREAD_NAME(name)
100#define _THREAD_PRIVATE_MUTEX(name) \ 128#define _THREAD_PRIVATE_MUTEX(name) \
101 static void *__THREAD_NAME(name) 129 static void *__THREAD_NAME(name)
130
131
132#ifndef __LIBC__ /* building some sort of reach around */
133
134#define _THREAD_PRIVATE_MUTEX_LOCK(name) do {} while (0)
135#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) do {} while (0)
136#define _THREAD_PRIVATE(keyname, storage, error) &(storage)
137#define _MUTEX_LOCK(mutex) do {} while (0)
138#define _MUTEX_UNLOCK(mutex) do {} while (0)
139#define _MUTEX_DESTROY(mutex) do {} while (0)
140#define _MALLOC_LOCK() do {} while (0)
141#define _MALLOC_UNLOCK() do {} while (0)
142#define _ATEXIT_LOCK() do {} while (0)
143#define _ATEXIT_UNLOCK() do {} while (0)
144#define _ATFORK_LOCK() do {} while (0)
145#define _ATFORK_UNLOCK() do {} while (0)
146#define _ARC4_LOCK() do {} while (0)
147#define _ARC4_UNLOCK() do {} while (0)
148
149#else /* building libc */
102#define _THREAD_PRIVATE_MUTEX_LOCK(name) \ 150#define _THREAD_PRIVATE_MUTEX_LOCK(name) \
103 _thread_tag_lock(&(__THREAD_NAME(name))) 151 do { \
152 if (_thread_cb.tc_tag_lock != NULL) \
153 _thread_cb.tc_tag_lock(&(__THREAD_NAME(name))); \
154 } while (0)
104#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ 155#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
105 _thread_tag_unlock(&(__THREAD_NAME(name))) 156 do { \
157 if (_thread_cb.tc_tag_unlock != NULL) \
158 _thread_cb.tc_tag_unlock(&(__THREAD_NAME(name))); \
159 } while (0)
106#define _THREAD_PRIVATE(keyname, storage, error) \ 160#define _THREAD_PRIVATE(keyname, storage, error) \
107 _thread_tag_storage(&(__THREAD_NAME(keyname)), &(storage), \ 161 (_thread_cb.tc_tag_storage == NULL ? &(storage) : \
108 sizeof (storage), error) 162 _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)), \
163 &(storage), sizeof(storage), error))
109 164
110/* 165/*
111 * Macros used in libc to access mutexes. 166 * Macros used in libc to access mutexes.
@@ -113,80 +168,65 @@ void _thread_mutex_destroy(void **);
113#define _MUTEX_LOCK(mutex) \ 168#define _MUTEX_LOCK(mutex) \
114 do { \ 169 do { \
115 if (__isthreaded) \ 170 if (__isthreaded) \
116 _thread_mutex_lock(mutex); \ 171 _thread_cb.tc_mutex_lock(mutex); \
117 } while (0) 172 } while (0)
118#define _MUTEX_UNLOCK(mutex) \ 173#define _MUTEX_UNLOCK(mutex) \
119 do { \ 174 do { \
120 if (__isthreaded) \ 175 if (__isthreaded) \
121 _thread_mutex_unlock(mutex); \ 176 _thread_cb.tc_mutex_unlock(mutex); \
122 } while (0) 177 } while (0)
123#define _MUTEX_DESTROY(mutex) \ 178#define _MUTEX_DESTROY(mutex) \
124 do { \ 179 do { \
125 if (__isthreaded) \ 180 if (__isthreaded) \
126 _thread_mutex_destroy(mutex); \ 181 _thread_cb.tc_mutex_destroy(mutex); \
127 } while (0) 182 } while (0)
128 183
129/* 184/*
130 * Resolver code is special cased in that it uses global keys.
131 */
132extern void *__THREAD_NAME(_res);
133extern void *__THREAD_NAME(_res_ext);
134extern void *__THREAD_NAME(serv_mutex);
135
136/*
137 * malloc lock/unlock prototypes and definitions 185 * malloc lock/unlock prototypes and definitions
138 */ 186 */
139void _thread_malloc_lock(void); 187#define _MALLOC_LOCK() \
140void _thread_malloc_unlock(void); 188 do { \
141 189 if (__isthreaded) \
142#define _MALLOC_LOCK() do { \ 190 _thread_cb.tc_malloc_lock(); \
143 if (__isthreaded) \ 191 } while (0)
144 _thread_malloc_lock(); \ 192#define _MALLOC_UNLOCK() \
145 } while (0) 193 do { \
146#define _MALLOC_UNLOCK() do { \ 194 if (__isthreaded) \
147 if (__isthreaded) \ 195 _thread_cb.tc_malloc_unlock(); \
148 _thread_malloc_unlock();\ 196 } while (0)
149 } while (0)
150
151void _thread_atexit_lock(void);
152void _thread_atexit_unlock(void);
153
154#define _ATEXIT_LOCK() do { \
155 if (__isthreaded) \
156 _thread_atexit_lock(); \
157 } while (0)
158#define _ATEXIT_UNLOCK() do { \
159 if (__isthreaded) \
160 _thread_atexit_unlock();\
161 } while (0)
162
163void _thread_atfork_lock(void);
164void _thread_atfork_unlock(void);
165
166#define _ATFORK_LOCK() do { \
167 if (__isthreaded) \
168 _thread_atfork_lock(); \
169 } while (0)
170#define _ATFORK_UNLOCK() do { \
171 if (__isthreaded) \
172 _thread_atfork_unlock();\
173 } while (0)
174
175void _thread_arc4_lock(void);
176void _thread_arc4_unlock(void);
177
178#define _ARC4_LOCK() do { \
179 if (__isthreaded) \
180 _thread_arc4_lock(); \
181 } while (0)
182#define _ARC4_UNLOCK() do { \
183 if (__isthreaded) \
184 _thread_arc4_unlock();\
185 } while (0)
186 197
187/* 198#define _ATEXIT_LOCK() \
188 * Wrapper for _thread_sys_fork() 199 do { \
189 */ 200 if (__isthreaded) \
190pid_t _thread_fork(void); 201 _thread_cb.tc_atexit_lock(); \
202 } while (0)
203#define _ATEXIT_UNLOCK() \
204 do { \
205 if (__isthreaded) \
206 _thread_cb.tc_atexit_unlock(); \
207 } while (0)
208
209#define _ATFORK_LOCK() \
210 do { \
211 if (__isthreaded) \
212 _thread_cb.tc_atfork_lock(); \
213 } while (0)
214#define _ATFORK_UNLOCK() \
215 do { \
216 if (__isthreaded) \
217 _thread_cb.tc_atfork_unlock(); \
218 } while (0)
219
220#define _ARC4_LOCK() \
221 do { \
222 if (__isthreaded) \
223 _thread_cb.tc_arc4_lock(); \
224 } while (0)
225#define _ARC4_UNLOCK() \
226 do { \
227 if (__isthreaded) \
228 _thread_cb.tc_arc4_unlock(); \
229 } while (0)
230#endif /* __LIBC__ */
191 231
192#endif /* _THREAD_PRIVATE_H_ */ 232#endif /* _THREAD_PRIVATE_H_ */