Bug Summary

File:thread/pthread.c
Warning:line 871, column 12
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name pthread.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/isvv/naviserver/nsthread -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsthread -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c pthread.c
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
50static pthread_cond_t *GetCond(Ns_Cond *cond) NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_RETURNS_NONNULL;
51static void CleanupTls(void *arg) NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
52static 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
71static 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
90void
91Nsthreads_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
143void **
144NsGetTls(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
178const char *
179NsThreadLibName(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
201void *
202NsLockAlloc(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
232void
233NsLockFree(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
263void
264NsLockSet(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);
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
293bool_Bool
294NsLockTry(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
328void
329NsLockUnset(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
359void
360NsCreateThread(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
453void
454NsThreadExit(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 */
483void *
484NsThreadResult(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
506void
507Ns_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
536void
537Ns_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
559uintptr_t
560Ns_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
584void
585Ns_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
613void
614Ns_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
648void
649Ns_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
682void
683Ns_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
712void
713Ns_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
742void
743Ns_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
773Ns_ReturnCode
774Ns_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
835static pthread_cond_t *
836GetCond(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
867static void *
868ThreadMain(void *arg)
869{
870 NsThreadMain(arg);
871 return NULL((void*)0);
This statement is never executed
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
895static void
896CleanupTls(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 */