Use _tolower instead of tolower if possible.
[kopensolaris-gnu/glibc.git] / linuxthreads / pthread.c
1 /* Linuxthreads - a simple clone()-based implementation of Posix        */
2 /* threads for Linux.                                                   */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4 /*                                                                      */
5 /* This program is free software; you can redistribute it and/or        */
6 /* modify it under the terms of the GNU Library General Public License  */
7 /* as published by the Free Software Foundation; either version 2       */
8 /* of the License, or (at your option) any later version.               */
9 /*                                                                      */
10 /* This program is distributed in the hope that it will be useful,      */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
13 /* GNU Library General Public License for more details.                 */
14
15 /* Thread creation, initialization, and basic low-level routines */
16
17 #include <errno.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/wait.h>
25 #include <sys/resource.h>
26 #include "pthread.h"
27 #include "internals.h"
28 #include "spinlock.h"
29 #include "restart.h"
30
31 /* Descriptor of the initial thread */
32
33 struct _pthread_descr_struct __pthread_initial_thread = {
34   &__pthread_initial_thread,  /* pthread_descr p_nextlive */
35   &__pthread_initial_thread,  /* pthread_descr p_prevlive */
36   NULL,                       /* pthread_descr p_nextwaiting */
37   PTHREAD_THREADS_MAX,        /* pthread_t p_tid */
38   0,                          /* int p_pid */
39   0,                          /* int p_priority */
40   &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */
41   0,                          /* int p_signal */
42   NULL,                       /* sigjmp_buf * p_signal_buf */
43   NULL,                       /* sigjmp_buf * p_cancel_buf */
44   0,                          /* char p_terminated */
45   0,                          /* char p_detached */
46   0,                          /* char p_exited */
47   NULL,                       /* void * p_retval */
48   0,                          /* int p_retval */
49   NULL,                       /* pthread_descr p_joining */
50   NULL,                       /* struct _pthread_cleanup_buffer * p_cleanup */
51   0,                          /* char p_cancelstate */
52   0,                          /* char p_canceltype */
53   0,                          /* char p_canceled */
54   NULL,                       /* int *p_errnop */
55   0,                          /* int p_errno */
56   NULL,                       /* int *p_h_errnop */
57   0,                          /* int p_h_errno */
58   NULL,                       /* char * p_in_sighandler */
59   0,                          /* char p_sigwaiting */
60   PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
61   {NULL},                     /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */
62   {NULL},                     /* void * p_libc_specific[_LIBC_TSD_KEY_N] */
63   0,                          /* int p_userstack */
64   NULL,                       /* void * p_guardaddr */
65   0,                          /* size_t p_guardsize */
66   &__pthread_initial_thread,  /* pthread_descr p_self */
67   0                           /* Always index 0 */
68 };
69
70 /* Descriptor of the manager thread; none of this is used but the error
71    variables, the p_pid and p_priority fields,
72    and the address for identification.  */
73
74 struct _pthread_descr_struct __pthread_manager_thread = {
75   NULL,                       /* pthread_descr p_nextlive */
76   NULL,                       /* pthread_descr p_prevlive */
77   NULL,                       /* pthread_descr p_nextwaiting */
78   0,                          /* int p_tid */
79   0,                          /* int p_pid */
80   0,                          /* int p_priority */
81   NULL,                       /* struct _pthread_fastlock * p_lock */
82   0,                          /* int p_signal */
83   NULL,                       /* sigjmp_buf * p_signal_buf */
84   NULL,                       /* sigjmp_buf * p_cancel_buf */
85   0,                          /* char p_terminated */
86   0,                          /* char p_detached */
87   0,                          /* char p_exited */
88   NULL,                       /* void * p_retval */
89   0,                          /* int p_retval */
90   NULL,                       /* pthread_descr p_joining */
91   NULL,                       /* struct _pthread_cleanup_buffer * p_cleanup */
92   0,                          /* char p_cancelstate */
93   0,                          /* char p_canceltype */
94   0,                          /* char p_canceled */
95   &__pthread_manager_thread.p_errno, /* int *p_errnop */
96   0,                          /* int p_errno */
97   NULL,                       /* int *p_h_errnop */
98   0,                          /* int p_h_errno */
99   NULL,                       /* char * p_in_sighandler */
100   0,                          /* char p_sigwaiting */
101   PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
102   {NULL},                     /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */
103   {NULL},                     /* void * p_libc_specific[_LIBC_TSD_KEY_N] */
104   0,                          /* int p_userstack */
105   NULL,                       /* void * p_guardaddr */
106   0,                          /* size_t p_guardsize */
107   &__pthread_manager_thread,  /* pthread_descr p_self */
108   1                           /* Always index 1 */
109 };
110
111 /* Pointer to the main thread (the father of the thread manager thread) */
112 /* Originally, this is the initial thread, but this changes after fork() */
113
114 pthread_descr __pthread_main_thread = &__pthread_initial_thread;
115
116 /* Limit between the stack of the initial thread (above) and the
117    stacks of other threads (below). Aligned on a STACK_SIZE boundary. */
118
119 char *__pthread_initial_thread_bos = NULL;
120
121 /* File descriptor for sending requests to the thread manager. */
122 /* Initially -1, meaning that the thread manager is not running. */
123
124 int __pthread_manager_request = -1;
125
126 /* Other end of the pipe for sending requests to the thread manager. */
127
128 int __pthread_manager_reader;
129
130 /* Limits of the thread manager stack */
131
132 char *__pthread_manager_thread_bos = NULL;
133 char *__pthread_manager_thread_tos = NULL;
134
135 /* For process-wide exit() */
136
137 int __pthread_exit_requested = 0;
138 int __pthread_exit_code = 0;
139
140 /* Communicate relevant LinuxThreads constants to gdb */
141
142 const int __pthread_threads_max = PTHREAD_THREADS_MAX;
143 const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct);
144 const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct,
145                                               h_descr);
146 const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct,
147                                             p_pid);
148
149 /* Signal numbers used for the communication.  */
150 #ifdef SIGRTMIN
151 int __pthread_sig_restart;
152 int __pthread_sig_cancel;
153 int __pthread_sig_debug;
154 #else
155 int __pthread_sig_restart = DEFAULT_SIG_RESTART;
156 int __pthread_sig_cancel = DEFAULT_SIG_CANCEL;
157 int __pthread_sig_debug = 0;    /* disabled */
158 #endif
159
160 /* These variables are used by the setup code.  */
161 extern int _errno;
162 extern int _h_errno;
163
164 /* Forward declarations */
165
166 static void pthread_exit_process(int retcode, void *arg);
167 #ifndef __i386__
168 static void pthread_handle_sigcancel(int sig);
169 static void pthread_handle_sigrestart(int sig);
170 #else
171 static void pthread_handle_sigcancel(int sig, struct sigcontext ctx);
172 static void pthread_handle_sigrestart(int sig, struct sigcontext ctx);
173 #endif
174 static void pthread_handle_sigdebug(int sig);
175
176 /* Initialize the pthread library.
177    Initialization is split in two functions:
178    - a constructor function that blocks the __pthread_sig_restart signal
179      (must do this very early, since the program could capture the signal
180       mask with e.g. sigsetjmp before creating the first thread);
181    - a regular function called from pthread_create when needed. */
182
183 static void pthread_initialize(void) __attribute__((constructor));
184
185 static void pthread_initialize(void)
186 {
187   struct sigaction sa;
188   sigset_t mask;
189   struct rlimit limit;
190   int max_stack;
191
192   /* If already done (e.g. by a constructor called earlier!), bail out */
193   if (__pthread_initial_thread_bos != NULL) return;
194 #ifdef TEST_FOR_COMPARE_AND_SWAP
195   /* Test if compare-and-swap is available */
196   __pthread_has_cas = compare_and_swap_is_available();
197 #endif
198   /* For the initial stack, reserve at least STACK_SIZE bytes of stack
199      below the current stack address, and align that on a
200      STACK_SIZE boundary. */
201   __pthread_initial_thread_bos =
202     (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
203   /* Play with the stack size limit to make sure that no stack ever grows
204      beyond STACK_SIZE minus two pages (one page for the thread descriptor
205      immediately beyond, and one page to act as a guard page). */
206   getrlimit(RLIMIT_STACK, &limit);
207   max_stack = STACK_SIZE - 2 * __getpagesize();
208   if (limit.rlim_cur > max_stack) {
209     limit.rlim_cur = max_stack;
210     setrlimit(RLIMIT_STACK, &limit);
211   }
212   /* Update the descriptor for the initial thread. */
213   __pthread_initial_thread.p_pid = __getpid();
214   /* If we have special thread_self processing, initialize that for the
215      main thread now.  */
216 #ifdef INIT_THREAD_SELF
217   INIT_THREAD_SELF(&__pthread_initial_thread, 0);
218 #endif
219   /* The errno/h_errno variable of the main thread are the global ones.  */
220   __pthread_initial_thread.p_errnop = &_errno;
221   __pthread_initial_thread.p_h_errnop = &_h_errno;
222 #ifdef SIGRTMIN
223   /* Allocate the signals used.  */
224   __pthread_sig_restart = __libc_allocate_rtsig (1);
225   __pthread_sig_cancel = __libc_allocate_rtsig (1);
226   __pthread_sig_debug = __libc_allocate_rtsig (2);
227   if (__pthread_sig_restart < 0 ||
228       __pthread_sig_cancel < 0 ||
229       __pthread_sig_debug < 0)
230     {
231       /* The kernel does not support real-time signals.  Use as before
232          the available signals in the fixed set.
233          Debugging is not supported in this case. */
234       __pthread_sig_restart = DEFAULT_SIG_RESTART;
235       __pthread_sig_cancel = DEFAULT_SIG_CANCEL;
236       __pthread_sig_debug = 0;
237     }
238 #endif
239   /* Setup signal handlers for the initial thread.
240      Since signal handlers are shared between threads, these settings
241      will be inherited by all other threads. */
242 #ifndef __i386__
243   sa.sa_handler = pthread_handle_sigrestart;
244 #else
245   sa.sa_handler = (__sighandler_t) pthread_handle_sigrestart;
246 #endif
247   sigemptyset(&sa.sa_mask);
248   sa.sa_flags = 0;
249   __sigaction(__pthread_sig_restart, &sa, NULL);
250 #ifndef __i386__
251   sa.sa_handler = pthread_handle_sigcancel;
252 #else
253   sa.sa_handler = (__sighandler_t) pthread_handle_sigcancel;
254 #endif
255   sa.sa_flags = 0;
256   __sigaction(__pthread_sig_cancel, &sa, NULL);
257   if (__pthread_sig_debug > 0) {
258     sa.sa_handler = pthread_handle_sigdebug;
259     sigemptyset(&sa.sa_mask);
260     sa.sa_flags = 0;
261     __sigaction(__pthread_sig_debug, &sa, NULL);
262   }
263   /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */
264   sigemptyset(&mask);
265   sigaddset(&mask, __pthread_sig_restart);
266   sigprocmask(SIG_BLOCK, &mask, NULL);
267   /* Register an exit function to kill all other threads. */
268   /* Do it early so that user-registered atexit functions are called
269      before pthread_exit_process. */
270   __on_exit(pthread_exit_process, NULL);
271 }
272
273 void __pthread_initialize(void)
274 {
275   pthread_initialize();
276 }
277
278 int __pthread_initialize_manager(void)
279 {
280   int manager_pipe[2];
281   int pid;
282   struct pthread_request request;
283
284   /* If basic initialization not done yet (e.g. we're called from a
285      constructor run before our constructor), do it now */
286   if (__pthread_initial_thread_bos == NULL) pthread_initialize();
287   /* Setup stack for thread manager */
288   __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE);
289   if (__pthread_manager_thread_bos == NULL) return -1;
290   __pthread_manager_thread_tos =
291     __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE;
292   /* Setup pipe to communicate with thread manager */
293   if (pipe(manager_pipe) == -1) {
294     free(__pthread_manager_thread_bos);
295     return -1;
296   }
297   /* Start the thread manager */
298   pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
299                 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
300 #ifdef CLONE_PTRACE
301                 | CLONE_PTRACE
302 #endif
303                 , (void *)(long)manager_pipe[0]);
304   if (pid == -1) {
305     free(__pthread_manager_thread_bos);
306     __libc_close(manager_pipe[0]);
307     __libc_close(manager_pipe[1]);
308     return -1;
309   }
310   __pthread_manager_request = manager_pipe[1]; /* writing end */
311   __pthread_manager_reader = manager_pipe[0]; /* reading end */
312   __pthread_manager_thread.p_pid = pid;
313   /* Make gdb aware of new thread manager */
314   if (__pthread_threads_debug) raise(__pthread_sig_cancel);
315   /* Synchronize debugging of the thread manager */
316   request.req_kind = REQ_DEBUG;
317   __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
318   return 0;
319 }
320
321 /* Thread creation */
322
323 int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr,
324                          void * (*start_routine)(void *), void *arg)
325 {
326   pthread_descr self = thread_self();
327   struct pthread_request request;
328   if (__pthread_manager_request < 0) {
329     if (__pthread_initialize_manager() < 0) return EAGAIN;
330   }
331   request.req_thread = self;
332   request.req_kind = REQ_CREATE;
333   request.req_args.create.attr = attr;
334   request.req_args.create.fn = start_routine;
335   request.req_args.create.arg = arg;
336   sigprocmask(SIG_SETMASK, (const sigset_t *) NULL,
337               &request.req_args.create.mask);
338   __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
339   suspend(self);
340   if (THREAD_GETMEM(self, p_retcode) == 0)
341     *thread = (pthread_t) THREAD_GETMEM(self, p_retval);
342   return THREAD_GETMEM(self, p_retcode);
343 }
344
345 #if defined HAVE_ELF && defined PIC && defined DO_VERSIONING
346 default_symbol_version (__pthread_create_2_1, pthread_create, GLIBC_2.1);
347
348 int __pthread_create_2_0(pthread_t *thread, const pthread_attr_t *attr,
349                          void * (*start_routine)(void *), void *arg)
350 {
351   /* The ATTR attribute is not really of type `pthread_attr_t *'.  It has
352      the old size and access to the new members might crash the program.
353      We convert the struct now.  */
354   pthread_attr_t new_attr;
355
356   if (attr != NULL)
357     {
358       size_t ps = __getpagesize ();
359
360       memcpy (&new_attr, attr,
361               (size_t) &(((pthread_attr_t*)NULL)->__guardsize));
362       new_attr.__guardsize = ps;
363       new_attr.__stackaddr_set = 0;
364       new_attr.__stackaddr = NULL;
365       new_attr.__stacksize = STACK_SIZE - ps;
366       attr = &new_attr;
367     }
368   return __pthread_create_2_1 (thread, attr, start_routine, arg);
369 }
370 symbol_version (__pthread_create_2_0, pthread_create, GLIBC_2.0);
371 #else
372 strong_alias (__pthread_create_2_1, pthread_create)
373 #endif
374
375 /* Simple operations on thread identifiers */
376
377 pthread_t pthread_self(void)
378 {
379   pthread_descr self = thread_self();
380   return THREAD_GETMEM(self, p_tid);
381 }
382
383 int pthread_equal(pthread_t thread1, pthread_t thread2)
384 {
385   return thread1 == thread2;
386 }
387
388 /* Helper function for thread_self in the case of user-provided stacks */
389
390 #ifndef THREAD_SELF
391
392 pthread_descr __pthread_find_self()
393 {
394   char * sp = CURRENT_STACK_FRAME;
395   pthread_handle h;
396
397   /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is
398      the manager threads handled specially in thread_self(), so start at 2 */
399   h = __pthread_handles + 2;
400   while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++;
401   return h->h_descr;
402 }
403
404 #endif
405
406 /* Thread scheduling */
407
408 int pthread_setschedparam(pthread_t thread, int policy,
409                           const struct sched_param *param)
410 {
411   pthread_handle handle = thread_handle(thread);
412   pthread_descr th;
413
414   __pthread_lock(&handle->h_lock, NULL);
415   if (invalid_handle(handle, thread)) {
416     __pthread_unlock(&handle->h_lock);
417     return ESRCH;
418   }
419   th = handle->h_descr;
420   if (__sched_setscheduler(th->p_pid, policy, param) == -1) {
421     __pthread_unlock(&handle->h_lock);
422     return errno;
423   }
424   th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority;
425   __pthread_unlock(&handle->h_lock);
426   if (__pthread_manager_request >= 0)
427     __pthread_manager_adjust_prio(th->p_priority);
428   return 0;
429 }
430
431 int pthread_getschedparam(pthread_t thread, int *policy,
432                           struct sched_param *param)
433 {
434   pthread_handle handle = thread_handle(thread);
435   int pid, pol;
436
437   __pthread_lock(&handle->h_lock, NULL);
438   if (invalid_handle(handle, thread)) {
439     __pthread_unlock(&handle->h_lock);
440     return ESRCH;
441   }
442   pid = handle->h_descr->p_pid;
443   __pthread_unlock(&handle->h_lock);
444   pol = __sched_getscheduler(pid);
445   if (pol == -1) return errno;
446   if (__sched_getparam(pid, param) == -1) return errno;
447   *policy = pol;
448   return 0;
449 }
450
451 /* Process-wide exit() request */
452
453 static void pthread_exit_process(int retcode, void *arg)
454 {
455   struct pthread_request request;
456   pthread_descr self = thread_self();
457
458   if (__pthread_manager_request >= 0) {
459     request.req_thread = self;
460     request.req_kind = REQ_PROCESS_EXIT;
461     request.req_args.exit.code = retcode;
462     __libc_write(__pthread_manager_request,
463                  (char *) &request, sizeof(request));
464     suspend(self);
465     /* Main thread should accumulate times for thread manager and its
466        children, so that timings for main thread account for all threads. */
467     if (self == __pthread_main_thread)
468       waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
469   }
470 }
471
472 /* The handler for the RESTART signal just records the signal received
473    in the thread descriptor, and optionally performs a siglongjmp
474    (for pthread_cond_timedwait). */
475
476 #ifndef __i386__
477 static void pthread_handle_sigrestart(int sig)
478 {
479   pthread_descr self = thread_self();
480 #else
481 static void pthread_handle_sigrestart(int sig, struct sigcontext ctx)
482 {
483   pthread_descr self;
484   asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs));
485   self = thread_self();
486 #endif
487   THREAD_SETMEM(self, p_signal, sig); 
488   if (THREAD_GETMEM(self, p_signal_jmp) != NULL) 
489     siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1);
490 }
491
492 /* The handler for the CANCEL signal checks for cancellation
493    (in asynchronous mode), for process-wide exit and exec requests.
494    For the thread manager thread, redirect the signal to
495    __pthread_manager_sighandler. */
496
497 #ifndef __i386__
498 static void pthread_handle_sigcancel(int sig)
499 {
500   pthread_descr self = thread_self();
501   sigjmp_buf * jmpbuf;
502 #else
503 static void pthread_handle_sigcancel(int sig, struct sigcontext ctx)
504 {
505   pthread_descr self;
506   sigjmp_buf * jmpbuf;
507   asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs));
508   self = thread_self();
509 #endif
510
511   if (self == &__pthread_manager_thread)
512     {
513       __pthread_manager_sighandler(sig);
514       return;
515     }
516   if (__pthread_exit_requested) {
517     /* Main thread should accumulate times for thread manager and its
518        children, so that timings for main thread account for all threads. */
519     if (self == __pthread_main_thread)
520       waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
521     _exit(__pthread_exit_code);
522   }
523   if (THREAD_GETMEM(self, p_canceled)
524       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
525     if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
526       pthread_exit(PTHREAD_CANCELED);
527     jmpbuf = THREAD_GETMEM(self, p_cancel_jmp);
528     if (jmpbuf != NULL) {
529       THREAD_SETMEM(self, p_cancel_jmp, NULL);
530       siglongjmp(*jmpbuf, 1);
531     }
532   }
533 }
534
535 /* Handler for the DEBUG signal.
536    The debugging strategy is as follows:
537    On reception of a REQ_DEBUG request (sent by new threads created to
538    the thread manager under debugging mode), the thread manager throws
539    __pthread_sig_cancel to itself. The debugger (if active) intercepts
540    this signal, takes into account new threads and continue execution
541    of the thread manager by propagating the signal because it doesn't
542    know what it is specifically done for. In the current implementation,
543    the thread manager simply discards it. */
544
545 static void pthread_handle_sigdebug(int sig)
546 {
547   /* Nothing */
548 }
549
550 /* Reset the state of the thread machinery after a fork().
551    Close the pipe used for requests and set the main thread to the forked
552    thread.
553    Notice that we can't free the stack segments, as the forked thread
554    may hold pointers into them. */
555
556 void __pthread_reset_main_thread()
557 {
558   pthread_descr self = thread_self();
559
560   if (__pthread_manager_request != -1) {
561     /* Free the thread manager stack */
562     free(__pthread_manager_thread_bos);
563     __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL;
564     /* Close the two ends of the pipe */
565     __libc_close(__pthread_manager_request);
566     __libc_close(__pthread_manager_reader);
567     __pthread_manager_request = __pthread_manager_reader = -1;
568   }
569   /* Update the pid of the main thread */
570   THREAD_SETMEM(self, p_pid, __getpid());
571   /* Make the forked thread the main thread */
572   __pthread_main_thread = self;
573   THREAD_SETMEM(self, p_nextlive, self);
574   THREAD_SETMEM(self, p_prevlive, self);
575   /* Now this thread modifies the global variables.  */
576   THREAD_SETMEM(self, p_errnop, &_errno);
577   THREAD_SETMEM(self, p_h_errnop, &_h_errno);
578 }
579
580 /* Process-wide exec() request */
581
582 void __pthread_kill_other_threads_np(void)
583 {
584   /* Terminate all other threads and thread manager */
585   pthread_exit_process(0, NULL);
586   /* Make current thread the main thread in case the calling thread
587      changes its mind, does not exec(), and creates new threads instead. */
588   __pthread_reset_main_thread();
589 }
590 weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
591
592 /* Concurrency symbol level.  */
593 static int current_level;
594
595 int __pthread_setconcurrency(int level)
596 {
597   /* We don't do anything unless we have found a useful interpretation.  */
598   current_level = level;
599   return 0;
600 }
601 weak_alias (__pthread_setconcurrency, pthread_setconcurrency)
602
603 int __pthread_getconcurrency(void)
604 {
605   return current_level;
606 }
607 weak_alias (__pthread_getconcurrency, pthread_getconcurrency)
608
609 /* Debugging aid */
610
611 #ifdef DEBUG
612 #include <stdarg.h>
613
614 void __pthread_message(char * fmt, ...)
615 {
616   char buffer[1024];
617   va_list args;
618   sprintf(buffer, "%05d : ", __getpid());
619   va_start(args, fmt);
620   vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args);
621   va_end(args);
622   __libc_write(2, buffer, strlen(buffer));
623 }
624
625 #endif
626
627
628 #ifndef PIC
629 /* We need a hook to force the cancelation wrappers to be linked in when
630    static libpthread is used.  */
631 extern const int __pthread_provide_wrappers;
632 static const int *const __pthread_require_wrappers =
633   &__pthread_provide_wrappers;
634 #endif