1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
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. */
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. */
15 /* The "thread manager" thread: manages creation and termination of threads */
24 #include <sys/poll.h> /* for poll */
25 #include <sys/mman.h> /* for mmap */
26 #include <sys/param.h>
28 #include <sys/wait.h> /* for waitpid macros */
31 #include "internals.h"
34 #include "semaphore.h"
36 /* Array of active threads. Entry 0 is reserved for the initial thread. */
37 struct pthread_handle_struct __pthread_handles
[PTHREAD_THREADS_MAX
] =
38 { { LOCK_INITIALIZER
, &__pthread_initial_thread
, 0},
39 { LOCK_INITIALIZER
, &__pthread_manager_thread
, 0}, /* All NULLs */ };
41 /* For debugging purposes put the maximum number of threads in a variable. */
42 const int __linuxthreads_pthread_threads_max
= PTHREAD_THREADS_MAX
;
44 /* Indicate whether at least one thread has a user-defined stack (if 1),
45 or if all threads have stacks supplied by LinuxThreads (if 0). */
46 int __pthread_nonstandard_stacks
;
48 /* Number of active entries in __pthread_handles (used by gdb) */
49 volatile int __pthread_handles_num
= 2;
51 /* Whether to use debugger additional actions for thread creation
53 volatile int __pthread_threads_debug
;
55 /* Globally enabled events. */
56 volatile td_thr_events_t __pthread_threads_events
;
58 /* Pointer to thread descriptor with last event. */
59 volatile pthread_descr __pthread_last_event
;
61 /* Mapping from stack segment to thread descriptor. */
62 /* Stack segment numbers are also indices into the __pthread_handles array. */
63 /* Stack segment number 0 is reserved for the initial thread. */
65 static inline pthread_descr
thread_segment(int seg
)
67 return (pthread_descr
)(THREAD_STACK_START_ADDRESS
- (seg
- 1) * STACK_SIZE
)
71 /* Flag set in signal handler to record child termination */
73 static volatile int terminated_children
= 0;
75 /* Flag set when the initial thread is blocked on pthread_exit waiting
76 for all other threads to terminate */
78 static int main_thread_exiting
= 0;
80 /* Counter used to generate unique thread identifier.
81 Thread identifier is pthread_threads_counter + segment. */
83 static pthread_t pthread_threads_counter
= 0;
85 /* Forward declarations */
87 static int pthread_handle_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
88 void * (*start_routine
)(void *), void *arg
,
89 sigset_t
*mask
, int father_pid
,
91 td_thr_events_t
*event_maskp
);
92 static void pthread_handle_free(pthread_t th_id
);
93 static void pthread_handle_exit(pthread_descr issuing_thread
, int exitcode
);
94 static void pthread_reap_children(void);
95 static void pthread_kill_all_threads(int sig
, int main_thread_also
);
97 /* The server thread managing requests for thread creation and termination */
99 int __pthread_manager(void *arg
)
101 int reqfd
= (int)arg
;
105 struct pthread_request request
;
107 /* If we have special thread_self processing, initialize it. */
108 #ifdef INIT_THREAD_SELF
109 INIT_THREAD_SELF(&__pthread_manager_thread
, 1);
111 /* Set the error variable. */
112 __pthread_manager_thread
.p_errnop
= &__pthread_manager_thread
.p_errno
;
113 __pthread_manager_thread
.p_h_errnop
= &__pthread_manager_thread
.p_h_errno
;
114 /* Block all signals except __pthread_sig_cancel and SIGTRAP */
116 sigdelset(&mask
, __pthread_sig_cancel
); /* for thread termination */
117 sigdelset(&mask
, SIGTRAP
); /* for debugging purposes */
118 sigprocmask(SIG_SETMASK
, &mask
, NULL
);
119 /* Raise our priority to match that of main thread */
120 __pthread_manager_adjust_prio(__pthread_main_thread
->p_priority
);
121 /* Synchronize debugging of the thread manager */
122 n
= __libc_read(reqfd
, (char *)&request
, sizeof(request
));
123 ASSERT(n
== sizeof(request
) && request
.req_kind
== REQ_DEBUG
);
126 /* Enter server loop */
128 n
= __poll(&ufd
, 1, 2000);
130 /* Check for termination of the main thread */
131 if (getppid() == 1) {
132 pthread_kill_all_threads(SIGKILL
, 0);
135 /* Check for dead children */
136 if (terminated_children
) {
137 terminated_children
= 0;
138 pthread_reap_children();
140 /* Read and execute request */
141 if (n
== 1 && (ufd
.revents
& POLLIN
)) {
142 n
= __libc_read(reqfd
, (char *)&request
, sizeof(request
));
143 ASSERT(n
== sizeof(request
));
144 switch(request
.req_kind
) {
146 request
.req_thread
->p_retcode
=
147 pthread_handle_create((pthread_t
*) &request
.req_thread
->p_retval
,
148 request
.req_args
.create
.attr
,
149 request
.req_args
.create
.fn
,
150 request
.req_args
.create
.arg
,
151 &request
.req_args
.create
.mask
,
152 request
.req_thread
->p_pid
,
153 request
.req_thread
->p_report_events
,
154 &request
.req_thread
->p_eventbuf
.eventmask
);
155 restart(request
.req_thread
);
158 pthread_handle_free(request
.req_args
.free
.thread_id
);
160 case REQ_PROCESS_EXIT
:
161 pthread_handle_exit(request
.req_thread
,
162 request
.req_args
.exit
.code
);
164 case REQ_MAIN_THREAD_EXIT
:
165 main_thread_exiting
= 1;
166 if (__pthread_main_thread
->p_nextlive
== __pthread_main_thread
) {
167 restart(__pthread_main_thread
);
172 __new_sem_post(request
.req_args
.post
);
175 /* Make gdb aware of new thread and gdb will restart the
176 new thread when it is ready to handle the new thread. */
177 if (__pthread_threads_debug
&& __pthread_sig_debug
> 0)
178 raise(__pthread_sig_debug
);
185 int __pthread_manager_event(void *arg
)
187 /* If we have special thread_self processing, initialize it. */
188 #ifdef INIT_THREAD_SELF
189 INIT_THREAD_SELF(&__pthread_manager_thread
, 1);
192 /* Get the lock the manager will free once all is correctly set up. */
193 __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread
), p_lock
), NULL
);
194 /* Free it immediately. */
195 __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread
), p_lock
));
197 return __pthread_manager(arg
);
200 /* Process creation */
202 static int pthread_start_thread(void *arg
)
204 pthread_descr self
= (pthread_descr
) arg
;
205 struct pthread_request request
;
207 /* Initialize special thread_self processing, if any. */
208 #ifdef INIT_THREAD_SELF
209 INIT_THREAD_SELF(self
, self
->p_nr
);
211 /* Make sure our pid field is initialized, just in case we get there
212 before our father has initialized it. */
213 THREAD_SETMEM(self
, p_pid
, __getpid());
214 /* Initial signal mask is that of the creating thread. (Otherwise,
215 we'd just inherit the mask of the thread manager.) */
216 sigprocmask(SIG_SETMASK
, &self
->p_start_args
.mask
, NULL
);
217 /* Set the scheduling policy and priority for the new thread, if needed */
218 if (THREAD_GETMEM(self
, p_start_args
.schedpolicy
) >= 0)
219 /* Explicit scheduling attributes were provided: apply them */
220 __sched_setscheduler(THREAD_GETMEM(self
, p_pid
),
221 THREAD_GETMEM(self
, p_start_args
.schedpolicy
),
222 &self
->p_start_args
.schedparam
);
223 else if (__pthread_manager_thread
.p_priority
> 0)
224 /* Default scheduling required, but thread manager runs in realtime
225 scheduling: switch new thread to SCHED_OTHER policy */
227 struct sched_param default_params
;
228 default_params
.sched_priority
= 0;
229 __sched_setscheduler(THREAD_GETMEM(self
, p_pid
),
230 SCHED_OTHER
, &default_params
);
232 /* Make gdb aware of new thread */
233 if (__pthread_threads_debug
&& __pthread_sig_debug
> 0) {
234 request
.req_thread
= self
;
235 request
.req_kind
= REQ_DEBUG
;
236 __libc_write(__pthread_manager_request
,
237 (char *) &request
, sizeof(request
));
240 /* Run the thread code */
241 outcome
= self
->p_start_args
.start_routine(THREAD_GETMEM(self
,
243 /* Exit with the given return value */
244 pthread_exit(outcome
);
248 static int pthread_start_thread_event(void *arg
)
250 pthread_descr self
= (pthread_descr
) arg
;
252 #ifdef INIT_THREAD_SELF
253 INIT_THREAD_SELF(self
, self
->p_nr
);
255 /* Make sure our pid field is initialized, just in case we get there
256 before our father has initialized it. */
257 THREAD_SETMEM(self
, p_pid
, __getpid());
258 /* Get the lock the manager will free once all is correctly set up. */
259 __pthread_lock (THREAD_GETMEM(self
, p_lock
), NULL
);
260 /* Free it immediately. */
261 __pthread_unlock (THREAD_GETMEM(self
, p_lock
));
263 /* Continue with the real function. */
264 return pthread_start_thread (arg
);
267 static int pthread_allocate_stack(const pthread_attr_t
*attr
,
268 pthread_descr default_new_thread
,
270 pthread_descr
* out_new_thread
,
271 char ** out_new_thread_bottom
,
272 char ** out_guardaddr
,
273 size_t * out_guardsize
)
275 pthread_descr new_thread
;
276 char * new_thread_bottom
;
278 size_t stacksize
, guardsize
;
280 if (attr
!= NULL
&& attr
->__stackaddr_set
)
282 /* The user provided a stack. */
284 (pthread_descr
) ((long)(attr
->__stackaddr
) & -sizeof(void *)) - 1;
285 new_thread_bottom
= (char *) attr
->__stackaddr
- attr
->__stacksize
;
288 __pthread_nonstandard_stacks
= 1;
292 /* Allocate space for stack and thread descriptor at default address */
293 new_thread
= default_new_thread
;
294 new_thread_bottom
= (char *) new_thread
- STACK_SIZE
;
295 if (mmap((caddr_t
)((char *)(new_thread
+ 1) - INITIAL_STACK_SIZE
),
296 INITIAL_STACK_SIZE
, PROT_READ
| PROT_WRITE
| PROT_EXEC
,
297 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
| MAP_GROWSDOWN
,
298 -1, 0) == MAP_FAILED
)
299 /* Bad luck, this segment is already mapped. */
301 /* We manage to get a stack. Now see whether we need a guard
302 and allocate it if necessary. Notice that the default
303 attributes (stack_size = STACK_SIZE - pagesize and
304 guardsize = pagesize) do not need a guard page, since
305 the RLIMIT_STACK soft limit prevents stacks from
306 running into one another. */
308 attr
->__guardsize
== 0 ||
309 (attr
->__guardsize
== pagesize
&&
310 attr
->__stacksize
== STACK_SIZE
- pagesize
))
312 /* We don't need a guard page. */
318 /* Put a bad page at the bottom of the stack */
319 stacksize
= roundup(attr
->__stacksize
, pagesize
);
320 if (stacksize
>= STACK_SIZE
- pagesize
)
321 stacksize
= STACK_SIZE
- pagesize
;
322 guardaddr
= (void *)new_thread
- stacksize
;
323 guardsize
= attr
->__guardsize
;
324 if (mmap ((caddr_t
) guardaddr
, guardsize
, 0, MAP_FIXED
, -1, 0)
327 /* We don't make this an error. */
333 /* Clear the thread data structure. */
334 memset (new_thread
, '\0', sizeof (*new_thread
));
335 *out_new_thread
= new_thread
;
336 *out_new_thread_bottom
= new_thread_bottom
;
337 *out_guardaddr
= guardaddr
;
338 *out_guardsize
= guardsize
;
342 static int pthread_handle_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
343 void * (*start_routine
)(void *), void *arg
,
344 sigset_t
* mask
, int father_pid
,
346 td_thr_events_t
*event_maskp
)
350 pthread_descr new_thread
;
351 char * new_thread_bottom
;
352 pthread_t new_thread_id
;
353 char *guardaddr
= NULL
;
354 size_t guardsize
= 0;
355 int pagesize
= __getpagesize();
357 /* First check whether we have to change the policy and if yes, whether
358 we can do this. Normally this should be done by examining the
359 return value of the __sched_setscheduler call in pthread_start_thread
360 but this is hard to implement. FIXME */
361 if (attr
!= NULL
&& attr
->__schedpolicy
!= SCHED_OTHER
&& geteuid () != 0)
363 /* Find a free segment for the thread, and allocate a stack if needed */
364 for (sseg
= 2; ; sseg
++)
366 if (sseg
>= PTHREAD_THREADS_MAX
)
368 if (__pthread_handles
[sseg
].h_descr
!= NULL
)
370 if (pthread_allocate_stack(attr
, thread_segment(sseg
), pagesize
,
371 &new_thread
, &new_thread_bottom
,
372 &guardaddr
, &guardsize
) == 0)
375 __pthread_handles_num
++;
376 /* Allocate new thread identifier */
377 pthread_threads_counter
+= PTHREAD_THREADS_MAX
;
378 new_thread_id
= sseg
+ pthread_threads_counter
;
379 /* Initialize the thread descriptor. Elements which have to be
380 initialized to zero already have this value. */
381 new_thread
->p_tid
= new_thread_id
;
382 new_thread
->p_lock
= &(__pthread_handles
[sseg
].h_lock
);
383 new_thread
->p_cancelstate
= PTHREAD_CANCEL_ENABLE
;
384 new_thread
->p_canceltype
= PTHREAD_CANCEL_DEFERRED
;
385 new_thread
->p_errnop
= &new_thread
->p_errno
;
386 new_thread
->p_h_errnop
= &new_thread
->p_h_errno
;
387 new_thread
->p_guardaddr
= guardaddr
;
388 new_thread
->p_guardsize
= guardsize
;
389 new_thread
->p_self
= new_thread
;
390 new_thread
->p_nr
= sseg
;
391 /* Initialize the thread handle */
392 __pthread_init_lock(&__pthread_handles
[sseg
].h_lock
);
393 __pthread_handles
[sseg
].h_descr
= new_thread
;
394 __pthread_handles
[sseg
].h_bottom
= new_thread_bottom
;
395 /* Determine scheduling parameters for the thread */
396 new_thread
->p_start_args
.schedpolicy
= -1;
398 new_thread
->p_detached
= attr
->__detachstate
;
399 new_thread
->p_userstack
= attr
->__stackaddr_set
;
401 switch(attr
->__inheritsched
) {
402 case PTHREAD_EXPLICIT_SCHED
:
403 new_thread
->p_start_args
.schedpolicy
= attr
->__schedpolicy
;
404 memcpy (&new_thread
->p_start_args
.schedparam
, &attr
->__schedparam
,
405 sizeof (struct sched_param
));
407 case PTHREAD_INHERIT_SCHED
:
408 new_thread
->p_start_args
.schedpolicy
= __sched_getscheduler(father_pid
);
409 __sched_getparam(father_pid
, &new_thread
->p_start_args
.schedparam
);
412 new_thread
->p_priority
=
413 new_thread
->p_start_args
.schedparam
.sched_priority
;
415 /* Finish setting up arguments to pthread_start_thread */
416 new_thread
->p_start_args
.start_routine
= start_routine
;
417 new_thread
->p_start_args
.arg
= arg
;
418 new_thread
->p_start_args
.mask
= *mask
;
419 /* Raise priority of thread manager if needed */
420 __pthread_manager_adjust_prio(new_thread
->p_priority
);
421 /* Do the cloning. We have to use two different functions depending
422 on whether we are debugging or not. */
423 pid
= 0; /* Note that the thread never can have PID zero. */
426 /* See whether the TD_CREATE event bit is set in any of the
428 int idx
= __td_eventword (TD_CREATE
);
429 uint32_t mask
= __td_eventmask (TD_CREATE
);
431 if ((mask
& (__pthread_threads_events
.event_bits
[idx
]
432 | event_maskp
->event_bits
[idx
])) != 0)
434 /* Lock the mutex the child will use now so that it will stop. */
435 __pthread_lock(new_thread
->p_lock
, NULL
);
437 /* We have to report this event. */
438 pid
= __clone(pthread_start_thread_event
, (void **) new_thread
,
439 CLONE_VM
| CLONE_FS
| CLONE_FILES
| CLONE_SIGHAND
|
440 __pthread_sig_cancel
, new_thread
);
443 /* Now fill in the information about the new thread in
444 the newly created thread's data structure. We cannot let
445 the new thread do this since we don't know whether it was
446 already scheduled when we send the event. */
447 new_thread
->p_eventbuf
.eventdata
= new_thread
;
448 new_thread
->p_eventbuf
.eventnum
= TD_CREATE
;
449 __pthread_last_event
= new_thread
;
451 /* Now call the function which signals the event. */
452 __linuxthreads_create_event ();
454 /* Now restart the thread. */
455 __pthread_unlock(new_thread
->p_lock
);
460 pid
= __clone(pthread_start_thread
, (void **) new_thread
,
461 CLONE_VM
| CLONE_FS
| CLONE_FILES
| CLONE_SIGHAND
|
462 __pthread_sig_cancel
, new_thread
);
463 /* Check if cloning succeeded */
465 /* Free the stack if we allocated it */
466 if (attr
== NULL
|| !attr
->__stackaddr_set
)
468 if (new_thread
->p_guardsize
!= 0)
469 munmap(new_thread
->p_guardaddr
, new_thread
->p_guardsize
);
470 munmap((caddr_t
)((char *)(new_thread
+1) - INITIAL_STACK_SIZE
),
473 __pthread_handles
[sseg
].h_descr
= NULL
;
474 __pthread_handles
[sseg
].h_bottom
= NULL
;
475 __pthread_handles_num
--;
478 /* Insert new thread in doubly linked list of active threads */
479 new_thread
->p_prevlive
= __pthread_main_thread
;
480 new_thread
->p_nextlive
= __pthread_main_thread
->p_nextlive
;
481 __pthread_main_thread
->p_nextlive
->p_prevlive
= new_thread
;
482 __pthread_main_thread
->p_nextlive
= new_thread
;
483 /* Set pid field of the new thread, in case we get there before the
485 new_thread
->p_pid
= pid
;
487 *thread
= new_thread_id
;
492 /* Try to free the resources of a thread when requested by pthread_join
493 or pthread_detach on a terminated thread. */
495 static void pthread_free(pthread_descr th
)
497 pthread_handle handle
;
498 ASSERT(th
->p_exited
);
499 /* Make the handle invalid */
500 handle
= thread_handle(th
->p_tid
);
501 __pthread_lock(&handle
->h_lock
, NULL
);
502 handle
->h_descr
= NULL
;
503 handle
->h_bottom
= (char *)(-1L);
504 __pthread_unlock(&handle
->h_lock
);
505 #ifdef FREE_THREAD_SELF
506 FREE_THREAD_SELF(th
, th
->p_nr
);
508 /* One fewer threads in __pthread_handles */
509 __pthread_handles_num
--;
510 /* If initial thread, nothing to free */
511 if (th
== &__pthread_initial_thread
) return;
512 if (!th
->p_userstack
)
514 /* Free the stack and thread descriptor area */
515 if (th
->p_guardsize
!= 0)
516 munmap(th
->p_guardaddr
, th
->p_guardsize
);
517 munmap((caddr_t
) ((char *)(th
+1) - STACK_SIZE
), STACK_SIZE
);
521 /* Handle threads that have exited */
523 static void pthread_exited(pid_t pid
)
527 /* Find thread with that pid */
528 for (th
= __pthread_main_thread
->p_nextlive
;
529 th
!= __pthread_main_thread
;
530 th
= th
->p_nextlive
) {
531 if (th
->p_pid
== pid
) {
532 /* Remove thread from list of active threads */
533 th
->p_nextlive
->p_prevlive
= th
->p_prevlive
;
534 th
->p_prevlive
->p_nextlive
= th
->p_nextlive
;
535 /* Mark thread as exited, and if detached, free its resources */
536 __pthread_lock(th
->p_lock
, NULL
);
538 /* If we have to signal this event do it now. */
539 if (th
->p_report_events
)
541 /* See whether TD_DEATH is in any of the mask. */
542 int idx
= __td_eventword (TD_REAP
);
543 uint32_t mask
= __td_eventmask (TD_REAP
);
545 if ((mask
& (__pthread_threads_events
.event_bits
[idx
]
546 | th
->p_eventbuf
.eventmask
.event_bits
[idx
])) != 0)
548 /* Yep, we have to signal the death. */
549 th
->p_eventbuf
.eventnum
= TD_DEATH
;
550 th
->p_eventbuf
.eventdata
= th
;
551 __pthread_last_event
= th
;
553 /* Now call the function to signal the event. */
554 __linuxthreads_reap_event();
557 detached
= th
->p_detached
;
558 __pthread_unlock(th
->p_lock
);
564 /* If all threads have exited and the main thread is pending on a
565 pthread_exit, wake up the main thread and terminate ourselves. */
566 if (main_thread_exiting
&&
567 __pthread_main_thread
->p_nextlive
== __pthread_main_thread
) {
568 restart(__pthread_main_thread
);
573 static void pthread_reap_children(void)
578 while ((pid
= __libc_waitpid(-1, &status
, WNOHANG
| __WCLONE
)) > 0) {
580 if (WIFSIGNALED(status
)) {
581 /* If a thread died due to a signal, send the same signal to
582 all other threads, including the main thread. */
583 pthread_kill_all_threads(WTERMSIG(status
), 1);
589 /* Try to free the resources of a thread when requested by pthread_join
590 or pthread_detach on a terminated thread. */
592 static void pthread_handle_free(pthread_t th_id
)
594 pthread_handle handle
= thread_handle(th_id
);
597 __pthread_lock(&handle
->h_lock
, NULL
);
598 if (invalid_handle(handle
, th_id
)) {
599 /* pthread_reap_children has deallocated the thread already,
600 nothing needs to be done */
601 __pthread_unlock(&handle
->h_lock
);
604 th
= handle
->h_descr
;
606 __pthread_unlock(&handle
->h_lock
);
609 /* The Unix process of the thread is still running.
610 Mark the thread as detached so that the thread manager will
611 deallocate its resources when the Unix process exits. */
613 __pthread_unlock(&handle
->h_lock
);
617 /* Send a signal to all running threads */
619 static void pthread_kill_all_threads(int sig
, int main_thread_also
)
622 for (th
= __pthread_main_thread
->p_nextlive
;
623 th
!= __pthread_main_thread
;
624 th
= th
->p_nextlive
) {
625 kill(th
->p_pid
, sig
);
627 if (main_thread_also
) {
628 kill(__pthread_main_thread
->p_pid
, sig
);
632 /* Process-wide exit() */
634 static void pthread_handle_exit(pthread_descr issuing_thread
, int exitcode
)
637 __pthread_exit_requested
= 1;
638 __pthread_exit_code
= exitcode
;
639 /* Send the CANCEL signal to all running threads, including the main
640 thread, but excluding the thread from which the exit request originated
641 (that thread must complete the exit, e.g. calling atexit functions
642 and flushing stdio buffers). */
643 for (th
= issuing_thread
->p_nextlive
;
644 th
!= issuing_thread
;
645 th
= th
->p_nextlive
) {
646 kill(th
->p_pid
, __pthread_sig_cancel
);
648 /* Now, wait for all these threads, so that they don't become zombies
649 and their times are properly added to the thread manager's times. */
650 for (th
= issuing_thread
->p_nextlive
;
651 th
!= issuing_thread
;
652 th
= th
->p_nextlive
) {
653 waitpid(th
->p_pid
, NULL
, __WCLONE
);
655 restart(issuing_thread
);
659 /* Handler for __pthread_sig_cancel in thread manager thread */
661 void __pthread_manager_sighandler(int sig
)
663 terminated_children
= 1;
666 /* Adjust priority of thread manager so that it always run at a priority
667 higher than all threads */
669 void __pthread_manager_adjust_prio(int thread_prio
)
671 struct sched_param param
;
673 if (thread_prio
<= __pthread_manager_thread
.p_priority
) return;
674 param
.sched_priority
=
675 thread_prio
< __sched_get_priority_max(SCHED_FIFO
)
676 ? thread_prio
+ 1 : thread_prio
;
677 __sched_setscheduler(__pthread_manager_thread
.p_pid
, SCHED_FIFO
, ¶m
);
678 __pthread_manager_thread
.p_priority
= thread_prio
;