File: | thread/pthread.c |
Warning: | line 272, column 9 This statement is never executed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * The contents of this file are subject to the Mozilla Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://mozilla.org/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | #ifndef _WIN32 |
31 | #include <nsconfig.h> |
32 | #endif |
33 | |
34 | #ifdef HAVE_PTHREAD1 |
35 | |
36 | /* |
37 | * pthread.c -- |
38 | * |
39 | * Interface routines for nsthreads using pthreads. |
40 | * |
41 | */ |
42 | |
43 | #include "thread.h" |
44 | #include <pthread.h> |
45 | |
46 | /* |
47 | * Local functions defined in this file. |
48 | */ |
49 | |
50 | static pthread_cond_t *GetCond(Ns_Cond *cond) NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_RETURNS_NONNULL; |
51 | static void CleanupTls(void *arg) NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); |
52 | static void *ThreadMain(void *arg); |
53 | |
54 | /* |
55 | * Solaris has weird way to declare this one so |
56 | * we just make a shortcut because this is what |
57 | * the (solaris) definition really does. |
58 | */ |
59 | |
60 | #if defined(__sun__) |
61 | #define PTHREAD_STACK_MIN__sysconf (75) ((size_t)sysconf(_SC_THREAD_STACK_MIN_SC_THREAD_STACK_MIN)) |
62 | #endif |
63 | |
64 | /* |
65 | * The following single TLS key is used to store the nsthread |
66 | * TLS slots. Due to system limitation(s), we stuff all of the |
67 | * slots into a private array keyed onto this per-thread key, |
68 | * instead of using separate TLS keys for each consumer. |
69 | */ |
70 | |
71 | static pthread_key_t key; |
72 | |
73 | |
74 | /* |
75 | *---------------------------------------------------------------------- |
76 | * |
77 | * Nsthreads_LibInit -- |
78 | * |
79 | * Pthread library initialization routine. |
80 | * |
81 | * Results: |
82 | * None. |
83 | * |
84 | * Side effects: |
85 | * Creates pthread key. |
86 | * |
87 | *---------------------------------------------------------------------- |
88 | */ |
89 | |
90 | void |
91 | Nsthreads_LibInit(void) |
92 | { |
93 | static bool_Bool initialized = NS_FALSE0; |
94 | |
95 | if (!initialized) { |
96 | int err; |
97 | |
98 | initialized = NS_TRUE1; |
99 | #ifdef __linux1 |
100 | { |
101 | size_t n; |
102 | |
103 | n = confstr(_CS_GNU_LIBPTHREAD_VERSION_CS_GNU_LIBPTHREAD_VERSION, NULL((void*)0), 0); |
104 | if (n > 0) { |
105 | char *buf = ns_malloc(n); |
106 | |
107 | confstr(_CS_GNU_LIBPTHREAD_VERSION_CS_GNU_LIBPTHREAD_VERSION, buf, n); |
108 | if (!strstr (buf, "NPTL")) { |
109 | Tcl_Panic("Linux \"NPTL\" thread library required. Found: \"%s\"", buf); |
110 | } |
111 | ns_free(buf); |
112 | } |
113 | } |
114 | #endif |
115 | err = pthread_key_create(&key, CleanupTls); |
116 | if (err != 0) { |
117 | NsThreadFatal("Nsthreads_LibInit", "pthread_key_create", err); |
118 | } |
119 | NsInitThreads(); |
120 | } |
121 | } |
122 | |
123 | |
124 | /* |
125 | *---------------------------------------------------------------------- |
126 | * |
127 | * NsGetTls -- |
128 | * |
129 | * Return the TLS slots. |
130 | * |
131 | * Results: |
132 | * Pointer to slots array. |
133 | * |
134 | * Side effects: |
135 | * Storage for the slot array is allocated bypassing the |
136 | * currently configured memory allocator because at the |
137 | * time this storage is to be reclaimed (see: CleanupTls) |
138 | * the allocator may already be finalized for this thread. |
139 | * |
140 | *---------------------------------------------------------------------- |
141 | */ |
142 | |
143 | void ** |
144 | NsGetTls(void) |
145 | { |
146 | void **slots; |
147 | |
148 | slots = pthread_getspecific(key); |
149 | if (slots == NULL((void*)0)) { |
150 | slots = calloc(NS_THREAD_MAXTLS100, sizeof(void *)); |
151 | if (slots == NULL((void*)0)) { |
152 | fprintf(stderr, "Fatal: NsGetTls failed to allocate %" PRIuz " bytes.\n",__fprintf_chk (stderr, 2 - 1, "Fatal: NsGetTls failed to allocate %" "zu" " bytes.\n", 100 * sizeof(void *)) |
153 | NS_THREAD_MAXTLS * sizeof(void *))__fprintf_chk (stderr, 2 - 1, "Fatal: NsGetTls failed to allocate %" "zu" " bytes.\n", 100 * sizeof(void *)); |
154 | abort(); |
155 | } |
156 | pthread_setspecific(key, slots); |
157 | } |
158 | return slots; |
159 | } |
160 | |
161 | |
162 | /* |
163 | *---------------------------------------------------------------------- |
164 | * |
165 | * NsThreadLibName -- |
166 | * |
167 | * Return the string name of the thread library. |
168 | * |
169 | * Results: |
170 | * Pointer to static string. |
171 | * |
172 | * Side effects: |
173 | * None. |
174 | * |
175 | *---------------------------------------------------------------------- |
176 | */ |
177 | |
178 | const char * |
179 | NsThreadLibName(void) |
180 | { |
181 | return "pthread"; |
182 | } |
183 | |
184 | |
185 | /* |
186 | *---------------------------------------------------------------------- |
187 | * |
188 | * NsLockAlloc -- |
189 | * |
190 | * Allocate and initialize a mutex lock. |
191 | * |
192 | * Results: |
193 | * None. |
194 | * |
195 | * Side effects: |
196 | * None. |
197 | * |
198 | *---------------------------------------------------------------------- |
199 | */ |
200 | |
201 | void * |
202 | NsLockAlloc(void) |
203 | { |
204 | pthread_mutex_t *lock; |
205 | int err; |
206 | |
207 | lock = ns_malloc(sizeof(pthread_mutex_t)); |
208 | err = pthread_mutex_init(lock, NULL((void*)0)); |
209 | if (err != 0) { |
210 | NsThreadFatal("NsLockAlloc", "pthread_mutex_init", err); |
211 | } |
212 | return lock; |
213 | } |
214 | |
215 | |
216 | /* |
217 | *---------------------------------------------------------------------- |
218 | * |
219 | * NsLockFree -- |
220 | * |
221 | * Free a mutex lock. |
222 | * |
223 | * Results: |
224 | * None. |
225 | * |
226 | * Side effects: |
227 | * None. |
228 | * |
229 | *---------------------------------------------------------------------- |
230 | */ |
231 | |
232 | void |
233 | NsLockFree(void *lock) |
234 | { |
235 | int err; |
236 | |
237 | NS_NONNULL_ASSERT(lock != NULL)((void) (0)); |
238 | |
239 | err = pthread_mutex_destroy((pthread_mutex_t *) lock); |
240 | if (err != 0) { |
241 | NsThreadFatal("NsLockFree", "pthread_mutex_destroy", err); |
242 | } |
243 | ns_free(lock); |
244 | } |
245 | |
246 | |
247 | /* |
248 | *---------------------------------------------------------------------- |
249 | * |
250 | * NsLockSet -- |
251 | * |
252 | * Set a mutex lock. |
253 | * |
254 | * Results: |
255 | * None. |
256 | * |
257 | * Side effects: |
258 | * May wait wakeup event if lock already held. |
259 | * |
260 | *---------------------------------------------------------------------- |
261 | */ |
262 | |
263 | void |
264 | NsLockSet(void *lock) |
265 | { |
266 | int err; |
267 | |
268 | NS_NONNULL_ASSERT(lock != NULL)((void) (0)); |
269 | |
270 | err = pthread_mutex_lock((pthread_mutex_t *) lock); |
271 | if (err != 0) { |
272 | NsThreadFatal("NsLockSet", "pthread_mutex_lock", err); |
This statement is never executed | |
273 | } |
274 | } |
275 | |
276 | |
277 | /* |
278 | *---------------------------------------------------------------------- |
279 | * |
280 | * NsLockTry -- |
281 | * |
282 | * Try to set a mutex lock once. |
283 | * |
284 | * Results: |
285 | * NS_TRUE if lock set, NS_FALSE otherwise. |
286 | * |
287 | * Side effects: |
288 | * None. |
289 | * |
290 | *---------------------------------------------------------------------- |
291 | */ |
292 | |
293 | bool_Bool |
294 | NsLockTry(void *lock) |
295 | { |
296 | int err; |
297 | |
298 | NS_NONNULL_ASSERT(lock != NULL)((void) (0)); |
299 | |
300 | err = pthread_mutex_trylock((pthread_mutex_t *) lock); |
301 | if (unlikely(err == EBUSY)(__builtin_expect((err == 16), 0))) { |
302 | return NS_FALSE0; |
303 | } |
304 | if (unlikely(err != 0)(__builtin_expect((err != 0), 0))) { |
305 | NsThreadFatal("NsLockTry", "pthread_mutex_trylock", err); |
306 | } |
307 | |
308 | return NS_TRUE1; |
309 | } |
310 | |
311 | |
312 | /* |
313 | *---------------------------------------------------------------------- |
314 | * |
315 | * NsLockUnset -- |
316 | * |
317 | * Unset a mutex lock. |
318 | * |
319 | * Results: |
320 | * None. |
321 | * |
322 | * Side effects: |
323 | * May signal wakeup event for a waiting thread. |
324 | * |
325 | *---------------------------------------------------------------------- |
326 | */ |
327 | |
328 | void |
329 | NsLockUnset(void *lock) |
330 | { |
331 | int err; |
332 | |
333 | NS_NONNULL_ASSERT(lock != NULL)((void) (0)); |
334 | |
335 | err = pthread_mutex_unlock((pthread_mutex_t *) lock); |
336 | if (unlikely(err != 0)(__builtin_expect((err != 0), 0))) { |
337 | NsThreadFatal("NsLockUnset", "pthread_mutex_unlock", err); |
338 | } |
339 | } |
340 | |
341 | |
342 | /* |
343 | *---------------------------------------------------------------------- |
344 | * |
345 | * NsCreateThread -- |
346 | * |
347 | * Pthread specific thread create function called by |
348 | * Ns_ThreadCreate. |
349 | * |
350 | * Results: |
351 | * None. |
352 | * |
353 | * Side effects: |
354 | * Depends on thread startup routine. |
355 | * |
356 | *---------------------------------------------------------------------- |
357 | */ |
358 | |
359 | void |
360 | NsCreateThread(void *arg, ssize_t stacksize, Ns_Thread *threadPtr) |
361 | { |
362 | static const char *func = "NsCreateThread"; |
363 | pthread_attr_t attr; |
364 | pthread_t thr; |
365 | int err; |
366 | |
367 | err = pthread_attr_init(&attr); |
368 | if (err != 0) { |
369 | NsThreadFatal(func, "pthread_attr_init", err); |
370 | } |
371 | |
372 | /* |
373 | * Set the stack size if specified explicitly. It is smarter |
374 | * to leave the default on platforms which map large stacks |
375 | * with guard zones (e.g., Solaris and Linux). |
376 | */ |
377 | |
378 | if (stacksize > 0) { |
379 | if (stacksize < PTHREAD_STACK_MIN__sysconf (75)) { |
380 | stacksize = PTHREAD_STACK_MIN__sysconf (75); |
381 | } else { |
382 | /* |
383 | * The stack-size has to be a multiple of the page-size, |
384 | * otherwise pthread_attr_setstacksize fails. When we have |
385 | * _SC_PAGESIZE defined, try to be friendly and round the |
386 | * stack-size to the next multiple of the page-size. |
387 | */ |
388 | #if defined(_SC_PAGESIZE_SC_PAGESIZE) |
389 | long pageSize = sysconf(_SC_PAGESIZE_SC_PAGESIZE); |
390 | stacksize = (((stacksize-1) / pageSize) + 1) * pageSize; |
391 | #endif |
392 | } |
393 | err = pthread_attr_setstacksize(&attr, (size_t) stacksize); |
394 | if (err != 0) { |
395 | NsThreadFatal(func, "pthread_attr_setstacksize", err); |
396 | } |
397 | } |
398 | |
399 | /* |
400 | * System scope always preferred, ignore any unsupported error. |
401 | */ |
402 | err = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEMPTHREAD_SCOPE_SYSTEM); |
403 | if (err != 0 && err != ENOTSUP95) { |
404 | NsThreadFatal(func, "pthread_setscope", err); |
405 | } |
406 | |
407 | /* |
408 | * In case, there is no threadPtr given, create a detached thread. |
409 | */ |
410 | if (threadPtr == NULL((void*)0)) { |
411 | err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHEDPTHREAD_CREATE_DETACHED); |
412 | if (err != 0 && err != ENOTSUP95) { |
413 | NsThreadFatal(func, "pthread_setdetachstate", err); |
414 | } |
415 | } |
416 | |
417 | /* |
418 | * Create the work horse thread |
419 | */ |
420 | err = pthread_create(&thr, &attr, ThreadMain, arg); |
421 | if (err != 0) { |
422 | NsThreadFatal(func, "pthread_create", err); |
423 | } else if (threadPtr != NULL((void*)0)) { |
424 | *threadPtr = (Ns_Thread)(uintptr_t) thr; |
425 | } |
426 | |
427 | /* |
428 | * |
429 | */ |
430 | err = pthread_attr_destroy(&attr); |
431 | if (err != 0) { |
432 | NsThreadFatal(func, "pthread_attr_destroy", err); |
433 | } |
434 | } |
435 | |
436 | |
437 | /* |
438 | *---------------------------------------------------------------------- |
439 | * |
440 | * NsThreadExit -- |
441 | * |
442 | * Terminate a thread. |
443 | * |
444 | * Results: |
445 | * None. |
446 | * |
447 | * Side effects: |
448 | * Thread will clean itself up via the TLS cleanup code. |
449 | * |
450 | *---------------------------------------------------------------------- |
451 | */ |
452 | |
453 | void |
454 | NsThreadExit(void *arg) |
455 | { |
456 | /* |
457 | * Exit the thread really. This will invoke all of the |
458 | * registered TLS cleanup callbacks again (no harm). |
459 | */ |
460 | |
461 | pthread_exit(arg); |
462 | } |
463 | |
464 | /* |
465 | *---------------------------------------------------------------------- |
466 | * |
467 | * NsThreadResult -- |
468 | * |
469 | * Stub function, which is not necessary when pthreads are used, since |
470 | * pthread_exit passes a pointer values). However, the situation for |
471 | * windows is different, and we keep this function here for symmetry with |
472 | * the version using windows native threads. For background, see |
473 | * winthread.c. |
474 | * |
475 | * Results: |
476 | * Pointer value (can be NULL). |
477 | * |
478 | * Side effects: |
479 | * None. |
480 | * |
481 | *---------------------------------------------------------------------- |
482 | */ |
483 | void * |
484 | NsThreadResult(void *arg) |
485 | { |
486 | return arg; |
487 | } |
488 | |
489 | |
490 | /* |
491 | *---------------------------------------------------------------------- |
492 | * |
493 | * Ns_ThreadJoin -- |
494 | * |
495 | * Wait for exit of a non-detached thread. |
496 | * |
497 | * Results: |
498 | * None. |
499 | * |
500 | * Side effects: |
501 | * Requested thread is destroyed after join. |
502 | * |
503 | *---------------------------------------------------------------------- |
504 | */ |
505 | |
506 | void |
507 | Ns_ThreadJoin(Ns_Thread *thread, void **argPtr) |
508 | { |
509 | int err; |
510 | |
511 | NS_NONNULL_ASSERT(thread != NULL)((void) (0)); |
512 | |
513 | err = pthread_join((pthread_t)(uintptr_t)*thread, argPtr); |
514 | if (err != 0) { |
515 | NsThreadFatal("Ns_ThreadJoin", "pthread_join", err); |
516 | } |
517 | } |
518 | |
519 | |
520 | /* |
521 | *---------------------------------------------------------------------- |
522 | * |
523 | * Ns_ThreadYield -- |
524 | * |
525 | * Yield the CPU to another thread. |
526 | * |
527 | * Results: |
528 | * None. |
529 | * |
530 | * Side effects: |
531 | * See sched_yield(). |
532 | * |
533 | *---------------------------------------------------------------------- |
534 | */ |
535 | |
536 | void |
537 | Ns_ThreadYield(void) |
538 | { |
539 | sched_yield(); |
540 | } |
541 | |
542 | |
543 | /* |
544 | *---------------------------------------------------------------------- |
545 | * |
546 | * Ns_ThreadId -- |
547 | * |
548 | * Return the numeric thread id. |
549 | * |
550 | * Results: |
551 | * Integer thread id. |
552 | * |
553 | * Side effects: |
554 | * None. |
555 | * |
556 | *---------------------------------------------------------------------- |
557 | */ |
558 | |
559 | uintptr_t |
560 | Ns_ThreadId(void) |
561 | { |
562 | pthread_t result = pthread_self(); |
563 | |
564 | return (uintptr_t) result; |
565 | } |
566 | |
567 | |
568 | /* |
569 | *---------------------------------------------------------------------- |
570 | * |
571 | * Ns_ThreadSelf -- |
572 | * |
573 | * Return thread handle suitable for Ns_ThreadJoin. |
574 | * |
575 | * Results: |
576 | * None. |
577 | * |
578 | * Side effects: |
579 | * Value at threadPtr is updated with thread's handle. |
580 | * |
581 | *---------------------------------------------------------------------- |
582 | */ |
583 | |
584 | void |
585 | Ns_ThreadSelf(Ns_Thread *threadPtr) |
586 | { |
587 | pthread_t result = pthread_self(); |
588 | |
589 | NS_NONNULL_ASSERT(threadPtr != NULL)((void) (0)); |
590 | |
591 | *threadPtr = (Ns_Thread)result; |
592 | } |
593 | |
594 | |
595 | /* |
596 | *---------------------------------------------------------------------- |
597 | * |
598 | * Ns_CondInit -- |
599 | * |
600 | * Pthread condition variable initialization. Note this routine |
601 | * isn't used directly very often as static condition variables |
602 | * are now self-initialized when first used. |
603 | * |
604 | * Results: |
605 | * None. |
606 | * |
607 | * Side effects: |
608 | * None. |
609 | * |
610 | *---------------------------------------------------------------------- |
611 | */ |
612 | |
613 | void |
614 | Ns_CondInit(Ns_Cond *cond) |
615 | { |
616 | pthread_cond_t *condPtr; |
617 | int err; |
618 | |
619 | NS_NONNULL_ASSERT(cond != NULL)((void) (0)); |
620 | |
621 | condPtr = ns_malloc(sizeof(pthread_cond_t)); |
622 | err = pthread_cond_init(condPtr, NULL((void*)0)); |
623 | if (err != 0) { |
624 | NsThreadFatal("Ns_CondInit", "pthread_cond_init", err); |
625 | } |
626 | *cond = (Ns_Cond) condPtr; |
627 | } |
628 | |
629 | |
630 | /* |
631 | *---------------------------------------------------------------------- |
632 | * |
633 | * Ns_CondDestroy -- |
634 | * |
635 | * Pthread condition destroy. Note this routine is almost never |
636 | * used as condition variables normally exist in memory until |
637 | * the process exits. |
638 | * |
639 | * Results: |
640 | * None. |
641 | * |
642 | * Side effects: |
643 | * None. |
644 | * |
645 | *---------------------------------------------------------------------- |
646 | */ |
647 | |
648 | void |
649 | Ns_CondDestroy(Ns_Cond *cond) |
650 | { |
651 | pthread_cond_t *condPtr = (pthread_cond_t *) *cond; |
652 | |
653 | if (condPtr != NULL((void*)0)) { |
654 | int err; |
655 | |
656 | err = pthread_cond_destroy(condPtr); |
657 | if (err != 0) { |
658 | NsThreadFatal("Ns_CondDestroy", "pthread_cond_destroy", err); |
659 | } |
660 | ns_free(condPtr); |
661 | *cond = NULL((void*)0); |
662 | } |
663 | } |
664 | |
665 | |
666 | /* |
667 | *---------------------------------------------------------------------- |
668 | * |
669 | * Ns_CondSignal -- |
670 | * |
671 | * Pthread condition signal. |
672 | * |
673 | * Results: |
674 | * None. |
675 | * |
676 | * Side effects: |
677 | * See pthread_cond_signal. |
678 | * |
679 | *---------------------------------------------------------------------- |
680 | */ |
681 | |
682 | void |
683 | Ns_CondSignal(Ns_Cond *cond) |
684 | { |
685 | int err; |
686 | |
687 | NS_NONNULL_ASSERT(cond != NULL)((void) (0)); |
688 | |
689 | err = pthread_cond_signal(GetCond(cond)); |
690 | if (err != 0) { |
691 | NsThreadFatal("Ns_CondSignal", "pthread_cond_signal", err); |
692 | } |
693 | } |
694 | |
695 | |
696 | /* |
697 | *---------------------------------------------------------------------- |
698 | * |
699 | * Ns_CondBroadcast -- |
700 | * |
701 | * Pthread condition broadcast. |
702 | * |
703 | * Results: |
704 | * None. |
705 | * |
706 | * Side effects: |
707 | * See pthread_cond_broadcast. |
708 | * |
709 | *---------------------------------------------------------------------- |
710 | */ |
711 | |
712 | void |
713 | Ns_CondBroadcast(Ns_Cond *cond) |
714 | { |
715 | int err; |
716 | |
717 | NS_NONNULL_ASSERT(cond != NULL)((void) (0)); |
718 | |
719 | err = pthread_cond_broadcast(GetCond(cond)); |
720 | if (err != 0) { |
721 | NsThreadFatal("Ns_CondBroadcast", "pthread_cond_broadcast", err); |
722 | } |
723 | } |
724 | |
725 | |
726 | /* |
727 | *---------------------------------------------------------------------- |
728 | * |
729 | * Ns_CondWait -- |
730 | * |
731 | * Pthread indefinite condition wait. |
732 | * |
733 | * Results: |
734 | * None. |
735 | * |
736 | * Side effects: |
737 | * See pthread_cond_wait. |
738 | * |
739 | *---------------------------------------------------------------------- |
740 | */ |
741 | |
742 | void |
743 | Ns_CondWait(Ns_Cond *cond, Ns_Mutex *mutex) |
744 | { |
745 | int err; |
746 | |
747 | NS_NONNULL_ASSERT(cond != NULL)((void) (0)); |
748 | NS_NONNULL_ASSERT(mutex != NULL)((void) (0)); |
749 | |
750 | err = pthread_cond_wait(GetCond(cond), NsGetLock(mutex)); |
751 | if (err != 0) { |
752 | NsThreadFatal("Ns_CondWait", "pthread_cond_wait", err); |
753 | } |
754 | } |
755 | |
756 | |
757 | /* |
758 | *---------------------------------------------------------------------- |
759 | * |
760 | * Ns_CondTimedWait -- |
761 | * |
762 | * Pthread absolute time wait. |
763 | * |
764 | * Results: |
765 | * None. |
766 | * |
767 | * Side effects: |
768 | * See pthread_cond_timewait. |
769 | * |
770 | *---------------------------------------------------------------------- |
771 | */ |
772 | |
773 | Ns_ReturnCode |
774 | Ns_CondTimedWait(Ns_Cond *cond, Ns_Mutex *mutex, const Ns_Time *timePtr) |
775 | { |
776 | int err; |
777 | Ns_ReturnCode status; |
778 | struct timespec ts; |
779 | |
780 | NS_NONNULL_ASSERT(cond != NULL)((void) (0)); |
781 | NS_NONNULL_ASSERT(mutex != NULL)((void) (0)); |
782 | |
783 | if (timePtr == NULL((void*)0)) { |
784 | Ns_CondWait(cond, mutex); |
785 | return NS_OK; |
786 | } |
787 | |
788 | /* |
789 | * Convert the microsecond-based Ns_Time to a nanosecond-based |
790 | * struct timespec. |
791 | */ |
792 | |
793 | ts.tv_sec = timePtr->sec; |
794 | ts.tv_nsec = timePtr->usec * 1000; |
795 | |
796 | /* |
797 | * As documented on Linux, pthread_cond_timedwait may return |
798 | * NS_EINTR if a signal arrives. We have noticed that |
799 | * NS_EINTR can be returned on Solaris as well although this |
800 | * is not documented. We assume the wakeup is truly |
801 | * spurious and simply restart the wait knowing that the |
802 | * ts structure has not been modified. |
803 | */ |
804 | |
805 | do { |
806 | err = pthread_cond_timedwait(GetCond(cond), NsGetLock(mutex), &ts); |
807 | } while (err == NS_EINTR4); |
808 | if (err == ETIMEDOUT110) { |
809 | status = NS_TIMEOUT; |
810 | } else if (err != 0) { |
811 | NsThreadFatal("Ns_CondTimedWait", "pthread_cond_timedwait", err); |
812 | } else { |
813 | status = NS_OK; |
814 | } |
815 | return status; |
816 | } |
817 | |
818 | |
819 | /* |
820 | *---------------------------------------------------------------------- |
821 | * |
822 | * GetCond -- |
823 | * |
824 | * Cast an Ns_Cond to pthread_cond_t, initializing if needed. |
825 | * |
826 | * Results: |
827 | * Pointer to pthread_cond_t. |
828 | * |
829 | * Side effects: |
830 | * Ns_Cond is initialized the first time. |
831 | * |
832 | *---------------------------------------------------------------------- |
833 | */ |
834 | |
835 | static pthread_cond_t * |
836 | GetCond(Ns_Cond *cond) |
837 | { |
838 | NS_NONNULL_ASSERT(cond != NULL)((void) (0)); |
839 | |
840 | if (*cond == NULL((void*)0)) { |
841 | Ns_MasterLock(); |
842 | if (*cond == NULL((void*)0)) { |
843 | Ns_CondInit(cond); |
844 | } |
845 | Ns_MasterUnlock(); |
846 | } |
847 | return (pthread_cond_t *) *cond; |
848 | } |
849 | |
850 | |
851 | /* |
852 | *---------------------------------------------------------------------- |
853 | * |
854 | * ThreadMain -- |
855 | * |
856 | * Pthread startup routine. |
857 | * |
858 | * Results: |
859 | * Does not return. |
860 | * |
861 | * Side effects: |
862 | * NsThreadMain will call Ns_ThreadExit. |
863 | * |
864 | *---------------------------------------------------------------------- |
865 | */ |
866 | |
867 | static void * |
868 | ThreadMain(void *arg) |
869 | { |
870 | NsThreadMain(arg); |
871 | return NULL((void*)0); |
872 | } |
873 | |
874 | |
875 | /* |
876 | *---------------------------------------------------------------------- |
877 | * |
878 | * CleanupTls -- |
879 | * |
880 | * Pthread TLS cleanup. This routine is called during thread |
881 | * exit. This routine could be called more than once if some |
882 | * other pthread cleanup requires nsthread's TLS. |
883 | * |
884 | * Results: |
885 | * None. |
886 | * |
887 | * Side effects: |
888 | * Storage for the TLS slot array is reclaimed bypassing the |
889 | * current memory allocator. It is because at this point, |
890 | * the allocator may already be finalized for this thread. |
891 | * |
892 | *---------------------------------------------------------------------- |
893 | */ |
894 | |
895 | static void |
896 | CleanupTls(void *arg) |
897 | { |
898 | void **slots = arg; |
899 | Ns_Thread thread = NULL((void*)0); |
900 | |
901 | NS_NONNULL_ASSERT(arg != NULL)((void) (0)); |
902 | |
903 | /* |
904 | * Restore the current slots during cleanup so handlers can access |
905 | * TLS in other slots. |
906 | */ |
907 | |
908 | pthread_setspecific(key, arg); |
909 | Ns_ThreadSelf(&thread); |
910 | NsCleanupTls(slots); |
911 | pthread_setspecific(key, NULL((void*)0)); |
912 | free(slots); |
913 | } |
914 | #else |
915 | # ifndef _WIN32 |
916 | # error "pthread support is required" |
917 | # endif |
918 | #endif |
919 | |
920 | |
921 | /* |
922 | * Local Variables: |
923 | * mode: c |
924 | * c-basic-offset: 4 |
925 | * fill-column: 78 |
926 | * indent-tabs-mode: nil |
927 | * End: |
928 | */ |