]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* thread.h: Locking and threading module definitions |
2 | ||
a7d2cc16 | 3 | Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, |
f00fe1b8 | 4 | 2008, 2009, 2010, 2011 Red Hat, Inc. |
462f4eff | 5 | |
1fd5e000 CF |
6 | This file is part of Cygwin. |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
893ac8e0 CF |
12 | #ifndef _THREAD_H |
13 | #define _THREAD_H | |
1fd5e000 | 14 | |
2d1d1eb1 | 15 | #define LOCK_MMAP_LIST 1 |
1fd5e000 CF |
16 | |
17 | #define WRITE_LOCK 1 | |
18 | #define READ_LOCK 2 | |
19 | ||
5c83f260 | 20 | #include <pthread.h> |
2ff03dc2 | 21 | #include <limits.h> |
66a83f3e | 22 | #include "security.h" |
29d52c8a | 23 | #include <errno.h> |
056b8e60 | 24 | #include "cygerrno.h" |
1fd5e000 | 25 | |
ed364fa9 CF |
26 | enum cw_sig_wait |
27 | { | |
28 | cw_sig_nosig, | |
29 | cw_sig_eintr, | |
30 | cw_sig_resume | |
31 | }; | |
32 | ||
85564567 CF |
33 | enum cw_cancel_action |
34 | { | |
35 | cw_cancel_self, | |
36 | cw_no_cancel_self, | |
37 | cw_no_cancel | |
38 | }; | |
39 | ||
39fc0d36 CF |
40 | DWORD cancelable_wait (HANDLE, DWORD, const cw_cancel_action = cw_cancel_self, |
41 | const enum cw_sig_wait = cw_sig_nosig) | |
ed364fa9 CF |
42 | __attribute__ ((regparm (3))); |
43 | ||
28194e81 | 44 | class fast_mutex |
ed9fe455 TP |
45 | { |
46 | public: | |
28194e81 TP |
47 | fast_mutex () : |
48 | lock_counter (0), win32_obj_id (0) | |
49 | { | |
50 | } | |
51 | ||
52 | ~fast_mutex () | |
53 | { | |
54 | if(win32_obj_id) | |
55 | CloseHandle (win32_obj_id); | |
56 | } | |
57 | ||
58 | bool init () | |
59 | { | |
7cba834b | 60 | lock_counter = 0; |
3700578e | 61 | win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL); |
28194e81 TP |
62 | if (!win32_obj_id) |
63 | { | |
3700578e | 64 | debug_printf ("CreateEvent failed. %E"); |
5c9ccece | 65 | return false; |
28194e81 TP |
66 | } |
67 | return true; | |
68 | } | |
69 | ||
70 | void lock () | |
71 | { | |
ed364fa9 | 72 | if (InterlockedIncrement ((long *) &lock_counter) != 1) |
85564567 | 73 | cancelable_wait (win32_obj_id, INFINITE, cw_no_cancel, cw_sig_resume); |
28194e81 TP |
74 | } |
75 | ||
76 | void unlock () | |
77 | { | |
ed364fa9 | 78 | if (InterlockedDecrement ((long *) &lock_counter)) |
3700578e | 79 | ::SetEvent (win32_obj_id); |
28194e81 TP |
80 | } |
81 | ||
ed9fe455 | 82 | private: |
28194e81 TP |
83 | unsigned long lock_counter; |
84 | HANDLE win32_obj_id; | |
ed9fe455 TP |
85 | }; |
86 | ||
1fd5e000 CF |
87 | class per_process; |
88 | class pinfo; | |
89 | ||
9a08b2c0 CF |
90 | #define PTHREAD_MAGIC 0xdf0df045 |
91 | #define PTHREAD_MUTEX_MAGIC PTHREAD_MAGIC+1 | |
92 | #define PTHREAD_KEY_MAGIC PTHREAD_MAGIC+2 | |
93 | #define PTHREAD_ATTR_MAGIC PTHREAD_MAGIC+3 | |
94 | #define PTHREAD_MUTEXATTR_MAGIC PTHREAD_MAGIC+4 | |
95 | #define PTHREAD_COND_MAGIC PTHREAD_MAGIC+5 | |
96 | #define PTHREAD_CONDATTR_MAGIC PTHREAD_MAGIC+6 | |
97 | #define SEM_MAGIC PTHREAD_MAGIC+7 | |
2ff03dc2 | 98 | #define PTHREAD_ONCE_MAGIC PTHREAD_MAGIC+8 |
00d296a3 TP |
99 | #define PTHREAD_RWLOCK_MAGIC PTHREAD_MAGIC+9 |
100 | #define PTHREAD_RWLOCKATTR_MAGIC PTHREAD_MAGIC+10 | |
f00fe1b8 | 101 | #define PTHREAD_SPINLOCK_MAGIC PTHREAD_MAGIC+11 |
5c83f260 | 102 | |
b4fa8164 | 103 | #define MUTEX_OWNER_ANONYMOUS ((pthread_t) -1) |
5d68d1de | 104 | |
2b1407d3 CF |
105 | typedef unsigned long thread_magic_t; |
106 | ||
5c83f260 | 107 | /* verifyable_object should not be defined here - it's a general purpose class */ |
1fd5e000 | 108 | |
9a08b2c0 CF |
109 | class verifyable_object |
110 | { | |
111 | public: | |
2b1407d3 | 112 | thread_magic_t magic; |
1fd5e000 | 113 | |
2b1407d3 CF |
114 | verifyable_object (thread_magic_t verifyer): magic (verifyer) {} |
115 | virtual ~verifyable_object () { magic = 0; } | |
9a08b2c0 CF |
116 | }; |
117 | ||
9c510edc | 118 | typedef enum |
86336f4f RC |
119 | { |
120 | VALID_OBJECT, | |
121 | INVALID_OBJECT, | |
122 | VALID_STATIC_OBJECT | |
123 | } verifyable_object_state; | |
124 | ||
28194e81 | 125 | template <class list_node> inline void |
94d24160 | 126 | List_insert (list_node *&head, list_node *node) |
28194e81 TP |
127 | { |
128 | if (!node) | |
129 | return; | |
94d24160 TP |
130 | do |
131 | node->next = head; | |
132 | while (InterlockedCompareExchangePointer (&head, node, node->next) != node->next); | |
28194e81 TP |
133 | } |
134 | ||
135 | template <class list_node> inline void | |
98854988 | 136 | List_remove (fast_mutex &mx, list_node *&head, list_node const *node) |
28194e81 TP |
137 | { |
138 | if (!node) | |
139 | return; | |
140 | mx.lock (); | |
94d24160 | 141 | if (head) |
28194e81 | 142 | { |
19adafdc | 143 | if (InterlockedCompareExchangePointer (&head, node->next, node) != node) |
5c9ccece CF |
144 | { |
145 | list_node *cur = head; | |
146 | ||
147 | while (cur->next && node != cur->next) | |
148 | cur = cur->next; | |
149 | if (node == cur->next) | |
150 | cur->next = cur->next->next; | |
151 | } | |
28194e81 TP |
152 | } |
153 | mx.unlock (); | |
154 | } | |
9a4d574b | 155 | |
28194e81 TP |
156 | |
157 | template <class list_node> class List | |
158 | { | |
159 | public: | |
9306ba2e TP |
160 | List() : head(NULL) |
161 | { | |
28194e81 | 162 | mx_init (); |
9306ba2e TP |
163 | } |
164 | ||
28194e81 | 165 | ~List() |
9306ba2e | 166 | { |
9306ba2e TP |
167 | } |
168 | ||
28194e81 | 169 | void fixup_after_fork () |
9306ba2e | 170 | { |
28194e81 TP |
171 | mx_init (); |
172 | } | |
15648790 | 173 | |
28194e81 TP |
174 | void insert (list_node *node) |
175 | { | |
94d24160 | 176 | List_insert (head, node); |
9306ba2e TP |
177 | } |
178 | ||
28194e81 | 179 | void remove (list_node *node) |
9306ba2e | 180 | { |
28194e81 | 181 | List_remove (mx, head, node); |
9306ba2e TP |
182 | } |
183 | ||
15648790 | 184 | void for_each (void (list_node::*callback) ()) |
9306ba2e | 185 | { |
28194e81 TP |
186 | mx.lock (); |
187 | list_node *cur = head; | |
188 | while (cur) | |
9306ba2e | 189 | { |
5c9ccece CF |
190 | (cur->*callback) (); |
191 | cur = cur->next; | |
9306ba2e | 192 | } |
28194e81 | 193 | mx.unlock (); |
9306ba2e TP |
194 | } |
195 | ||
8fbd574e CV |
196 | fast_mutex mx; |
197 | list_node *head; | |
198 | ||
af428c1e | 199 | protected: |
28194e81 TP |
200 | void mx_init () |
201 | { | |
202 | if (!mx.init ()) | |
203 | api_fatal ("Could not create mutex for list synchronisation."); | |
204 | } | |
af428c1e RC |
205 | }; |
206 | ||
9a4d574b | 207 | class pthread_key: public verifyable_object |
5c83f260 | 208 | { |
65a7ca7b | 209 | DWORD tls_index; |
5c83f260 | 210 | public: |
15648790 | 211 | static bool is_good_object (pthread_key_t const *); |
f1f13795 | 212 | |
65a7ca7b CF |
213 | int set (const void *value) {TlsSetValue (tls_index, (void *) value); return 0;} |
214 | void *get () const {return TlsGetValue (tls_index);} | |
5c83f260 | 215 | |
20b94ee9 | 216 | pthread_key (void (*)(void *)); |
aea1f301 | 217 | ~pthread_key (); |
28194e81 | 218 | static void fixup_before_fork () |
9306ba2e | 219 | { |
28194e81 | 220 | keys.for_each (&pthread_key::_fixup_before_fork); |
9306ba2e TP |
221 | } |
222 | ||
28194e81 | 223 | static void fixup_after_fork () |
9306ba2e | 224 | { |
28194e81 TP |
225 | keys.fixup_after_fork (); |
226 | keys.for_each (&pthread_key::_fixup_after_fork); | |
9306ba2e TP |
227 | } |
228 | ||
15648790 | 229 | static void run_all_destructors () |
9306ba2e | 230 | { |
15648790 | 231 | keys.for_each (&pthread_key::run_destructor); |
9306ba2e | 232 | } |
af428c1e RC |
233 | |
234 | /* List support calls */ | |
235 | class pthread_key *next; | |
f1f13795 | 236 | private: |
af428c1e | 237 | static List<pthread_key> keys; |
28194e81 TP |
238 | void _fixup_before_fork (); |
239 | void _fixup_after_fork (); | |
20b94ee9 | 240 | void (*destructor) (void *); |
15648790 | 241 | void run_destructor (); |
af428c1e | 242 | void *fork_buf; |
5c83f260 RC |
243 | }; |
244 | ||
9a4d574b | 245 | class pthread_attr: public verifyable_object |
1fd5e000 | 246 | { |
9a08b2c0 | 247 | public: |
15648790 | 248 | static bool is_good_object(pthread_attr_t const *); |
9a08b2c0 | 249 | int joinable; |
5c83f260 RC |
250 | int contentionscope; |
251 | int inheritsched; | |
252 | struct sched_param schedparam; | |
705a187e | 253 | void *stackaddr; |
9a08b2c0 CF |
254 | size_t stacksize; |
255 | ||
aea1f301 CF |
256 | pthread_attr (); |
257 | ~pthread_attr (); | |
1fd5e000 CF |
258 | }; |
259 | ||
9a4d574b | 260 | class pthread_mutexattr: public verifyable_object |
43c3c4e3 RC |
261 | { |
262 | public: | |
15648790 | 263 | static bool is_good_object(pthread_mutexattr_t const *); |
43c3c4e3 RC |
264 | int pshared; |
265 | int mutextype; | |
aea1f301 CF |
266 | pthread_mutexattr (); |
267 | ~pthread_mutexattr (); | |
43c3c4e3 RC |
268 | }; |
269 | ||
9a4d574b | 270 | class pthread_mutex: public verifyable_object |
43c3c4e3 RC |
271 | { |
272 | public: | |
15648790 | 273 | static void init_mutex (); |
2b1407d3 CF |
274 | static int init (pthread_mutex_t *, const pthread_mutexattr_t *attr, |
275 | const pthread_mutex_t); | |
478ea460 CF |
276 | static bool is_good_object (pthread_mutex_t const *); |
277 | static bool is_initializer (pthread_mutex_t const *); | |
278 | static bool is_initializer_or_object (pthread_mutex_t const *); | |
279 | static bool is_initializer_or_bad_object (pthread_mutex_t const *); | |
43c3c4e3 | 280 | |
3700578e CF |
281 | int lock (); |
282 | int trylock (); | |
283 | int unlock (); | |
284 | int destroy (); | |
478ea460 | 285 | void set_type (int in_type) {type = in_type;} |
2ff03dc2 | 286 | |
15648790 | 287 | int lock_recursive () |
2ff03dc2 | 288 | { |
478ea460 | 289 | if (recursion_counter == UINT_MAX) |
2ff03dc2 | 290 | return EAGAIN; |
478ea460 | 291 | recursion_counter++; |
2ff03dc2 TP |
292 | return 0; |
293 | } | |
294 | ||
478ea460 CF |
295 | bool can_be_unlocked (); |
296 | ||
43c3c4e3 RC |
297 | pthread_mutex (pthread_mutexattr * = NULL); |
298 | pthread_mutex (pthread_mutex_t *, pthread_mutexattr *); | |
299 | ~pthread_mutex (); | |
ed9fe455 | 300 | |
478ea460 | 301 | class pthread_mutex *next; |
9306ba2e TP |
302 | static void fixup_after_fork () |
303 | { | |
28194e81 | 304 | mutexes.fixup_after_fork (); |
15648790 | 305 | mutexes.for_each (&pthread_mutex::_fixup_after_fork); |
9306ba2e TP |
306 | } |
307 | ||
f00fe1b8 | 308 | protected: |
478ea460 CF |
309 | unsigned long lock_counter; |
310 | HANDLE win32_obj_id; | |
478ea460 CF |
311 | pthread_t owner; |
312 | #ifdef DEBUGGING | |
313 | DWORD tid; /* the thread id of the owner */ | |
314 | #endif | |
478ea460 | 315 | |
f00fe1b8 | 316 | void set_shared (int in_shared) { pshared = in_shared; } |
478ea460 CF |
317 | void set_owner (pthread_t self) |
318 | { | |
319 | recursion_counter = 1; | |
320 | owner = self; | |
321 | #ifdef DEBUGGING | |
322 | tid = GetCurrentThreadId (); | |
323 | #endif | |
324 | } | |
f00fe1b8 | 325 | |
478ea460 CF |
326 | static const pthread_t _new_mutex; |
327 | static const pthread_t _unlocked_mutex; | |
328 | static const pthread_t _destroyed_mutex; | |
329 | ||
f00fe1b8 CV |
330 | private: |
331 | unsigned int recursion_counter; | |
332 | LONG condwaits; | |
333 | int type; | |
334 | int pshared; | |
335 | ||
478ea460 | 336 | bool no_owner (); |
15648790 | 337 | void _fixup_after_fork (); |
2ff03dc2 | 338 | |
9306ba2e | 339 | static List<pthread_mutex> mutexes; |
28194e81 | 340 | static fast_mutex mutex_initialization_lock; |
478ea460 | 341 | friend class pthread_cond; |
43c3c4e3 RC |
342 | }; |
343 | ||
f00fe1b8 CV |
344 | class pthread_spinlock: public pthread_mutex |
345 | { | |
346 | public: | |
347 | static bool is_good_object (pthread_spinlock_t const *); | |
348 | static int init (pthread_spinlock_t *, int); | |
349 | ||
350 | int lock (); | |
351 | int unlock (); | |
352 | ||
353 | pthread_spinlock (int); | |
354 | }; | |
355 | ||
09cbb9d6 | 356 | #define WAIT_CANCELED (WAIT_OBJECT_0 + 1) |
c9a76075 | 357 | #define WAIT_SIGNALED (WAIT_OBJECT_0 + 2) |
09cbb9d6 | 358 | |
e431827c | 359 | class _cygtls; |
9a4d574b | 360 | class pthread: public verifyable_object |
1fd5e000 CF |
361 | { |
362 | public: | |
9a08b2c0 CF |
363 | HANDLE win32_obj_id; |
364 | class pthread_attr attr; | |
365 | void *(*function) (void *); | |
1dc16fc7 CF |
366 | void *arg; |
367 | void *return_ptr; | |
c6e0f665 | 368 | bool valid; |
1dc16fc7 | 369 | bool suspended; |
42faed41 | 370 | bool canceled; |
5c83f260 | 371 | int cancelstate, canceltype; |
e431827c | 372 | _cygtls *cygtls; |
d288c1c7 | 373 | HANDLE cancel_event; |
e9259cb2 | 374 | pthread_t joiner; |
5c83f260 | 375 | |
7d7e7a21 | 376 | virtual bool create (void *(*)(void *), pthread_attr *, void *); |
4e786173 | 377 | |
aea1f301 CF |
378 | pthread (); |
379 | virtual ~pthread (); | |
9a08b2c0 | 380 | |
56a188d1 | 381 | static void init_mainthread (); |
15648790 | 382 | static bool is_good_object(pthread_t const *); |
aea1f301 CF |
383 | static void atforkprepare(); |
384 | static void atforkparent(); | |
385 | static void atforkchild(); | |
9a08b2c0 | 386 | |
aea1f301 CF |
387 | /* API calls */ |
388 | static int cancel (pthread_t); | |
389 | static int join (pthread_t * thread, void **return_val); | |
390 | static int detach (pthread_t * thread); | |
391 | static int create (pthread_t * thread, const pthread_attr_t * attr, | |
01f58e41 | 392 | void *(*start_routine) (void *), void *arg); |
aea1f301 CF |
393 | static int once (pthread_once_t *, void (*)(void)); |
394 | static int atfork(void (*)(void), void (*)(void), void (*)(void)); | |
395 | static int suspend (pthread_t * thread); | |
396 | static int resume (pthread_t * thread); | |
01f58e41 | 397 | |
9a4d574b | 398 | virtual void exit (void *value_ptr) __attribute__ ((noreturn)); |
d288c1c7 | 399 | |
aea1f301 | 400 | virtual int cancel (); |
9d1e72a1 | 401 | |
aea1f301 | 402 | virtual void testcancel (); |
a91ac4dc | 403 | static HANDLE get_cancel_event (); |
aea1f301 | 404 | static void static_cancel_self (); |
d288c1c7 | 405 | |
aea1f301 CF |
406 | virtual int setcancelstate (int state, int *oldstate); |
407 | virtual int setcanceltype (int type, int *oldtype); | |
d288c1c7 | 408 | |
aea1f301 CF |
409 | virtual void push_cleanup_handler (__pthread_cleanup_handler *handler); |
410 | virtual void pop_cleanup_handler (int const execute); | |
007276b3 | 411 | |
aea1f301 | 412 | static pthread* self (); |
c350feda | 413 | static DWORD WINAPI thread_init_wrapper (void *); |
007276b3 | 414 | |
aea1f301 | 415 | virtual unsigned long getsequence_np(); |
4e786173 | 416 | |
a4cea440 TP |
417 | static int equal (pthread_t t1, pthread_t t2) |
418 | { | |
419 | return t1 == t2; | |
420 | } | |
421 | ||
e1e196a2 TP |
422 | /* List support calls */ |
423 | class pthread *next; | |
424 | static void fixup_after_fork () | |
425 | { | |
28194e81 | 426 | threads.fixup_after_fork (); |
e1e196a2 TP |
427 | threads.for_each (&pthread::_fixup_after_fork); |
428 | } | |
429 | ||
c6e0f665 TP |
430 | static void suspend_all_except_self () |
431 | { | |
432 | threads.for_each (&pthread::suspend_except_self); | |
433 | } | |
434 | ||
435 | static void resume_all () | |
436 | { | |
437 | threads.for_each (&pthread::resume); | |
438 | } | |
439 | ||
9a08b2c0 | 440 | private: |
e1e196a2 | 441 | static List<pthread> threads; |
aea1f301 CF |
442 | DWORD thread_id; |
443 | __pthread_cleanup_handler *cleanup_stack; | |
444 | pthread_mutex mutex; | |
70300fdb | 445 | _cygtls *parent_tls; |
aea1f301 | 446 | |
c6e0f665 TP |
447 | void suspend_except_self (); |
448 | void resume (); | |
449 | ||
e1e196a2 TP |
450 | void _fixup_after_fork (); |
451 | ||
2f9ae2ed | 452 | void pop_all_cleanup_handlers (); |
aea1f301 CF |
453 | void precreate (pthread_attr *); |
454 | void postcreate (); | |
c76d70d7 | 455 | bool create_cancel_event (); |
56a188d1 | 456 | static void set_tls_self_pointer (pthread *); |
aea1f301 | 457 | void cancel_self (); |
15648790 | 458 | DWORD get_thread_id (); |
4e786173 RC |
459 | }; |
460 | ||
15648790 | 461 | class pthread_null : public pthread |
4e786173 | 462 | { |
d04cf16c | 463 | public: |
15648790 TP |
464 | static pthread *get_null_pthread(); |
465 | ~pthread_null(); | |
aea1f301 CF |
466 | |
467 | /* From pthread These should never get called | |
468 | * as the ojbect is not verifyable | |
469 | */ | |
7d7e7a21 | 470 | bool create (void *(*)(void *), pthread_attr *, void *); |
9a4d574b | 471 | void exit (void *value_ptr) __attribute__ ((noreturn)); |
aea1f301 CF |
472 | int cancel (); |
473 | void testcancel (); | |
474 | int setcancelstate (int state, int *oldstate); | |
475 | int setcanceltype (int type, int *oldtype); | |
476 | void push_cleanup_handler (__pthread_cleanup_handler *handler); | |
477 | void pop_cleanup_handler (int const execute); | |
478 | unsigned long getsequence_np(); | |
4e786173 RC |
479 | |
480 | private: | |
15648790 TP |
481 | pthread_null (); |
482 | static pthread_null _instance; | |
1fd5e000 CF |
483 | }; |
484 | ||
9a4d574b | 485 | class pthread_condattr: public verifyable_object |
1fd5e000 CF |
486 | { |
487 | public: | |
15648790 | 488 | static bool is_good_object(pthread_condattr_t const *); |
1dc16fc7 | 489 | int shared; |
9a08b2c0 | 490 | |
462f4eff CF |
491 | pthread_condattr (); |
492 | ~pthread_condattr (); | |
1fd5e000 CF |
493 | }; |
494 | ||
9a4d574b | 495 | class pthread_cond: public verifyable_object |
5ccbf4b6 CF |
496 | { |
497 | public: | |
15648790 | 498 | static bool is_good_object (pthread_cond_t const *); |
478ea460 CF |
499 | static bool is_initializer (pthread_cond_t const *); |
500 | static bool is_initializer_or_object (pthread_cond_t const *); | |
501 | static bool is_initializer_or_bad_object (pthread_cond_t const *); | |
15648790 | 502 | static void init_mutex (); |
ed9fe455 TP |
503 | static int init (pthread_cond_t *, const pthread_condattr_t *); |
504 | ||
5ccbf4b6 | 505 | int shared; |
f592b05d TP |
506 | |
507 | unsigned long waiting; | |
508 | unsigned long pending; | |
15648790 | 509 | HANDLE sem_wait; |
f592b05d | 510 | |
15648790 TP |
511 | pthread_mutex mtx_in; |
512 | pthread_mutex mtx_out; | |
f592b05d | 513 | |
15648790 | 514 | pthread_mutex_t mtx_cond; |
f592b05d | 515 | |
15648790 TP |
516 | void unblock (const bool all); |
517 | int wait (pthread_mutex_t mutex, DWORD dwMilliseconds = INFINITE); | |
9a08b2c0 | 518 | |
aea1f301 CF |
519 | pthread_cond (pthread_condattr *); |
520 | ~pthread_cond (); | |
ed9fe455 | 521 | |
9306ba2e TP |
522 | class pthread_cond * next; |
523 | static void fixup_after_fork () | |
524 | { | |
28194e81 | 525 | conds.fixup_after_fork (); |
15648790 | 526 | conds.for_each (&pthread_cond::_fixup_after_fork); |
9306ba2e TP |
527 | } |
528 | ||
ed9fe455 | 529 | private: |
15648790 TP |
530 | void _fixup_after_fork (); |
531 | ||
9306ba2e | 532 | static List<pthread_cond> conds; |
28194e81 | 533 | static fast_mutex cond_initialization_lock; |
5c83f260 RC |
534 | }; |
535 | ||
9a4d574b | 536 | class pthread_rwlockattr: public verifyable_object |
00d296a3 TP |
537 | { |
538 | public: | |
15648790 | 539 | static bool is_good_object(pthread_rwlockattr_t const *); |
00d296a3 TP |
540 | int shared; |
541 | ||
542 | pthread_rwlockattr (); | |
543 | ~pthread_rwlockattr (); | |
544 | }; | |
545 | ||
9a4d574b | 546 | class pthread_rwlock: public verifyable_object |
00d296a3 TP |
547 | { |
548 | public: | |
15648790 | 549 | static bool is_good_object (pthread_rwlock_t const *); |
478ea460 CF |
550 | static bool is_initializer (pthread_rwlock_t const *); |
551 | static bool is_initializer_or_object (pthread_rwlock_t const *); | |
552 | static bool is_initializer_or_bad_object (pthread_rwlock_t const *); | |
15648790 | 553 | static void init_mutex (); |
00d296a3 TP |
554 | static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *); |
555 | ||
556 | int shared; | |
557 | ||
15648790 TP |
558 | unsigned long waiting_readers; |
559 | unsigned long waiting_writers; | |
00d296a3 TP |
560 | pthread_t writer; |
561 | struct RWLOCK_READER | |
562 | { | |
563 | struct RWLOCK_READER *next; | |
564 | pthread_t thread; | |
f8190b57 | 565 | unsigned long n; |
00d296a3 | 566 | } *readers; |
28194e81 | 567 | fast_mutex readers_mx; |
00d296a3 | 568 | |
15648790 TP |
569 | int rdlock (); |
570 | int tryrdlock (); | |
00d296a3 | 571 | |
15648790 TP |
572 | int wrlock (); |
573 | int trywrlock (); | |
00d296a3 | 574 | |
15648790 | 575 | int unlock (); |
00d296a3 TP |
576 | |
577 | pthread_mutex mtx; | |
15648790 TP |
578 | pthread_cond cond_readers; |
579 | pthread_cond cond_writers; | |
00d296a3 | 580 | |
00d296a3 TP |
581 | pthread_rwlock (pthread_rwlockattr *); |
582 | ~pthread_rwlock (); | |
583 | ||
9306ba2e TP |
584 | class pthread_rwlock * next; |
585 | static void fixup_after_fork () | |
586 | { | |
28194e81 | 587 | rwlocks.fixup_after_fork (); |
15648790 | 588 | rwlocks.for_each (&pthread_rwlock::_fixup_after_fork); |
9306ba2e TP |
589 | } |
590 | ||
00d296a3 | 591 | private: |
9306ba2e TP |
592 | static List<pthread_rwlock> rwlocks; |
593 | ||
15648790 TP |
594 | void add_reader (struct RWLOCK_READER *rd); |
595 | void remove_reader (struct RWLOCK_READER *rd); | |
596 | struct RWLOCK_READER *lookup_reader (pthread_t thread); | |
00d296a3 | 597 | |
ffb576fb TP |
598 | void release () |
599 | { | |
600 | if (waiting_writers) | |
601 | { | |
5c9ccece CF |
602 | if (!readers) |
603 | cond_writers.unblock (false); | |
ffb576fb TP |
604 | } |
605 | else if (waiting_readers) | |
606 | cond_readers.unblock (true); | |
607 | } | |
608 | ||
609 | ||
15648790 TP |
610 | static void rdlock_cleanup (void *arg); |
611 | static void wrlock_cleanup (void *arg); | |
00d296a3 | 612 | |
15648790 TP |
613 | void _fixup_after_fork (); |
614 | ||
28194e81 | 615 | static fast_mutex rwlock_initialization_lock; |
00d296a3 TP |
616 | }; |
617 | ||
5c83f260 RC |
618 | class pthread_once |
619 | { | |
620 | public: | |
621 | pthread_mutex_t mutex; | |
622 | int state; | |
5ccbf4b6 | 623 | }; |
1fd5e000 | 624 | |
9a08b2c0 | 625 | /* shouldn't be here */ |
9a4d574b | 626 | class semaphore: public verifyable_object |
1fd5e000 | 627 | { |
9a08b2c0 | 628 | public: |
15648790 | 629 | static bool is_good_object(sem_t const *); |
01f58e41 | 630 | /* API calls */ |
8fbd574e CV |
631 | static int init (sem_t *sem, int pshared, unsigned int value); |
632 | static int destroy (sem_t *sem); | |
633 | static sem_t *open (unsigned long long hash, LUID luid, int fd, int oflag, | |
634 | mode_t mode, unsigned int value, bool &wasopen); | |
635 | static int close (sem_t *sem); | |
636 | static int wait (sem_t *sem); | |
637 | static int post (sem_t *sem); | |
638 | static int getvalue (sem_t *sem, int *sval); | |
639 | static int trywait (sem_t *sem); | |
640 | static int timedwait (sem_t *sem, const struct timespec *abstime); | |
641 | ||
642 | static int getinternal (sem_t *sem, int *sfd, unsigned long long *shash, | |
643 | LUID *sluid, unsigned int *sval); | |
9d1e72a1 | 644 | |
9a08b2c0 CF |
645 | HANDLE win32_obj_id; |
646 | int shared; | |
f9229ef7 | 647 | long currentvalue; |
8fbd574e CV |
648 | int fd; |
649 | unsigned long long hash; | |
650 | LUID luid; | |
651 | sem_t *sem; | |
9a08b2c0 | 652 | |
aea1f301 | 653 | semaphore (int, unsigned int); |
8fbd574e | 654 | semaphore (unsigned long long, LUID, int, sem_t *, int, mode_t, unsigned int); |
aea1f301 | 655 | ~semaphore (); |
9306ba2e TP |
656 | |
657 | class semaphore * next; | |
658 | static void fixup_after_fork () | |
659 | { | |
28194e81 | 660 | semaphores.fixup_after_fork (); |
15648790 | 661 | semaphores.for_each (&semaphore::_fixup_after_fork); |
9306ba2e | 662 | } |
8fbd574e CV |
663 | static void terminate () |
664 | { | |
056b8e60 | 665 | save_errno save; |
8fbd574e CV |
666 | semaphores.for_each (&semaphore::_terminate); |
667 | } | |
9306ba2e | 668 | |
9306ba2e | 669 | private: |
c9a76075 | 670 | int _wait (); |
15648790 | 671 | void _post (); |
07233966 | 672 | int _getvalue (int *sval); |
15648790 | 673 | int _trywait (); |
07233966 | 674 | int _timedwait (const struct timespec *abstime); |
15648790 TP |
675 | |
676 | void _fixup_after_fork (); | |
8fbd574e | 677 | void _terminate (); |
15648790 | 678 | |
9306ba2e | 679 | static List<semaphore> semaphores; |
9a08b2c0 CF |
680 | }; |
681 | ||
39b6859a CF |
682 | class callback |
683 | { | |
684 | public: | |
685 | void (*cb)(void); | |
686 | class callback * next; | |
687 | }; | |
688 | ||
9a4d574b | 689 | struct MTinterface |
1fd5e000 | 690 | { |
1dc16fc7 | 691 | // General |
5c83f260 | 692 | int concurrency; |
e6b98fc8 | 693 | long int threadcount; |
1fd5e000 | 694 | |
39b6859a CF |
695 | callback *pthread_prepare; |
696 | callback *pthread_child; | |
697 | callback *pthread_parent; | |
5c83f260 | 698 | |
c8fa3426 | 699 | void Init (); |
2f9ae2ed CF |
700 | void fixup_before_fork (); |
701 | void fixup_after_fork (); | |
1fd5e000 | 702 | |
29d52c8a | 703 | #if 0 // avoid initialization since zero is implied and |
f8c8e13b | 704 | MTinterface () : |
9a4d574b | 705 | concurrency (0), threadcount (0), |
29d52c8a | 706 | pthread_prepare (NULL), pthread_child (NULL), pthread_parent (NULL) |
aea1f301 | 707 | { |
aea1f301 | 708 | } |
9a4d574b | 709 | #endif |
1fd5e000 CF |
710 | }; |
711 | ||
f8c8e13b | 712 | #define MT_INTERFACE user_data->threadinterface |
893ac8e0 | 713 | #endif // _THREAD_H |