pthread_start_thread(void *arg) { pthread_descr self = (pthread_descr) arg; struct pthread_request request; void * outcome; #if HP_TIMING_AVAIL hp_timing_t tmpclock; #endif /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif #if HP_TIMING_AVAIL HP_TIMING_NOW (tmpclock); THREAD_SETMEM (self, p_cpuclock_offset, tmpclock); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, __getpid()); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) /* Explicit scheduling attributes were provided: apply them */ __sched_setscheduler(THREAD_GETMEM(self, p_pid), THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); else if (manager_thread->p_priority > 0) /* Default scheduling required, but thread manager runs in realtime scheduling: switch new thread to SCHED_OTHER policy */ { struct sched_param default_params; default_params.sched_priority = 0; __sched_setscheduler(THREAD_GETMEM(self, p_pid), SCHED_OTHER, &default_params); } #if !(USE_TLS && HAVE___THREAD) /* Initialize thread-locale current locale to point to the global one. With __thread support, the variable's initializer takes care of this. */ __uselocale (LC_GLOBAL_LOCALE); #else /* Initialize __resp. */ __resp = &self->p_res; #endif /* Make gdb aware of new thread */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, p_start_args.arg)); /* Exit with the given return value */ __pthread_do_exit(outcome, CURRENT_STACK_FRAME); }
/* Do some minimal initialization which has to be done during the startup of the C library. */ void __pthread_initialize_minimal(void) { /* If we have special thread_self processing, initialize * that for the main thread now. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0); #endif }
/* Do some minimal initialization which has to be done during the startup of the C library. */ void __pthread_initialize_minimal(void) { /* If we have special thread_self processing, initialize * that for the main thread now. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0); #endif __libc_multiple_threads_ptr = __libc_pthread_init (ptr_pthread_functions); }
/* Do some minimal initialization which has to be done during the startup of the C library. */ void __pthread_initialize_minimal(void) { /* If we have special thread_self processing, initialize that for the main thread now. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0); #endif #if HP_TIMING_AVAIL __pthread_initial_thread.p_cpuclock_offset = _dl_cpuclock_offset; #endif }
static void pthread_handle_sigcancel(int sig) { pthread_descr self = thread_self(); sigjmp_buf * jmpbuf; if (self == &__pthread_manager_thread) { #ifdef THREAD_SELF /* A new thread might get a cancel signal before it is fully initialized, so that the thread register might still point to the manager thread. Double check that this is really the manager thread. */ pthread_descr real_self = thread_self_stack(); if (real_self == &__pthread_manager_thread) { __pthread_manager_sighandler(sig); return; } /* Oops, thread_self() isn't working yet.. */ self = real_self; # ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); # endif #else __pthread_manager_sighandler(sig); return; #endif } if (__builtin_expect (__pthread_exit_requested, 0)) { /* Main thread should accumulate times for thread manager and its children, so that timings for main thread account for all threads. */ if (self == __pthread_main_thread) { #ifdef USE_TLS waitpid(__pthread_manager_thread->p_pid, NULL, __WCLONE); #else waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); #endif } _exit(__pthread_exit_code); } if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_exit(PTHREAD_CANCELED); jmpbuf = THREAD_GETMEM(self, p_cancel_jmp); if (jmpbuf != NULL) { THREAD_SETMEM(self, p_cancel_jmp, NULL); siglongjmp(*jmpbuf, 1); } } }
int attribute_noreturn __pthread_manager_event(void *arg) { /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_manager_thread, 1); #endif /* Get the lock the manager will free once all is correctly set up. */ __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread), p_lock), NULL); /* Free it immediately. */ __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread), p_lock)); __pthread_manager(arg); }
/* Process creation */ static int attribute_noreturn pthread_start_thread(void *arg) { pthread_descr self = (pthread_descr) arg; struct pthread_request request; void * outcome; /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif PDEBUG("\n"); /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, getpid()); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) /* Explicit scheduling attributes were provided: apply them */ sched_setscheduler(THREAD_GETMEM(self, p_pid), THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); else if (__pthread_manager_thread.p_priority > 0) /* Default scheduling required, but thread manager runs in realtime scheduling: switch new thread to SCHED_OTHER policy */ { struct sched_param default_params; default_params.sched_priority = 0; sched_setscheduler(THREAD_GETMEM(self, p_pid), SCHED_OTHER, &default_params); } /* Make gdb aware of new thread */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, p_start_args.arg)); /* Exit with the given return value */ __pthread_do_exit(outcome, CURRENT_STACK_FRAME); }
pthread_start_thread_event(void *arg) { pthread_descr self = (pthread_descr) arg; #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, __getpid()); /* Get the lock the manager will free once all is correctly set up. */ __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); /* Free it immediately. */ __pthread_unlock (THREAD_GETMEM(self, p_lock)); /* Continue with the real function. */ pthread_start_thread (arg); }
static int pthread_start_thread(void * arg) { pthread_descr self = (pthread_descr) arg; void * outcome; /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ self->p_pid = __getpid(); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (self->p_start_args.schedpolicy != SCHED_OTHER) __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy, &self->p_start_args.schedparam); /* Run the thread code */ outcome = self->p_start_args.start_routine(self->p_start_args.arg); /* Exit with the given return value */ pthread_exit(outcome); return 0; }
int attribute_noreturn __pthread_manager(void *arg) { int reqfd = (int) (long int) arg; #ifdef USE_SELECT struct timeval tv; fd_set fd; #else struct pollfd ufd; #endif sigset_t manager_mask; int n; struct pthread_request request; /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_manager_thread, 1); #endif /* Set the error variable. */ __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno; #ifdef __UCLIBC_HAS_XLOCALE__ /* Initialize thread's locale to the global locale. */ __pthread_manager_thread.locale = __global_locale; #endif /* __UCLIBC_HAS_XLOCALE__ */ /* Block all signals except __pthread_sig_cancel and SIGTRAP */ __sigfillset(&manager_mask); sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ if (__pthread_threads_debug && __pthread_sig_debug > 0) sigdelset(&manager_mask, __pthread_sig_debug); sigprocmask(SIG_SETMASK, &manager_mask, NULL); /* Raise our priority to match that of main thread */ __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); /* Synchronize debugging of the thread manager */ n = TEMP_FAILURE_RETRY(read(reqfd, (char *)&request, sizeof(request))); #ifndef USE_SELECT ufd.fd = reqfd; ufd.events = POLLIN; #endif /* Enter server loop */ while(1) { #ifdef USE_SELECT tv.tv_sec = 2; tv.tv_usec = 0; FD_ZERO (&fd); FD_SET (reqfd, &fd); n = select (reqfd + 1, &fd, NULL, NULL, &tv); #else PDEBUG("before poll\n"); n = poll(&ufd, 1, 2000); PDEBUG("after poll\n"); #endif /* Check for termination of the main thread */ if (getppid() == 1) { pthread_kill_all_threads(SIGKILL, 0); _exit(0); } /* Check for dead children */ if (terminated_children) { terminated_children = 0; pthread_reap_children(); } /* Read and execute request */ #ifdef USE_SELECT if (n == 1) #else if (n == 1 && (ufd.revents & POLLIN)) #endif { PDEBUG("before read\n"); n = read(reqfd, (char *)&request, sizeof(request)); PDEBUG("after read, n=%d\n", n); switch(request.req_kind) { case REQ_CREATE: PDEBUG("got REQ_CREATE\n"); request.req_thread->p_retcode = pthread_handle_create((pthread_t *) &request.req_thread->p_retval, request.req_args.create.attr, request.req_args.create.fn, request.req_args.create.arg, &request.req_args.create.mask, request.req_thread->p_pid, request.req_thread->p_report_events, &request.req_thread->p_eventbuf.eventmask); PDEBUG("restarting %p\n", request.req_thread); restart(request.req_thread); break; case REQ_FREE: PDEBUG("got REQ_FREE\n"); pthread_handle_free(request.req_args.free.thread_id); break; case REQ_PROCESS_EXIT: PDEBUG("got REQ_PROCESS_EXIT from %p, exit code = %d\n", request.req_thread, request.req_args.exit.code); pthread_handle_exit(request.req_thread, request.req_args.exit.code); break; case REQ_MAIN_THREAD_EXIT: PDEBUG("got REQ_MAIN_THREAD_EXIT\n"); main_thread_exiting = 1; /* Reap children in case all other threads died and the signal handler went off before we set main_thread_exiting to 1, and therefore did not do REQ_KICK. */ pthread_reap_children(); if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); /* The main thread will now call exit() which will trigger an __on_exit handler, which in turn will send REQ_PROCESS_EXIT to the thread manager. In case you are wondering how the manager terminates from its loop here. */ } break; case REQ_POST: PDEBUG("got REQ_POST\n"); sem_post(request.req_args.post); break; case REQ_DEBUG: PDEBUG("got REQ_DEBUG\n"); /* Make gdb aware of new thread and gdb will restart the new thread when it is ready to handle the new thread. */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { PDEBUG("about to call raise(__pthread_sig_debug)\n"); raise(__pthread_sig_debug); } case REQ_KICK: /* This is just a prod to get the manager to reap some threads right away, avoiding a potential delay at shutdown. */ break; } } } }
__pthread_manager(void *arg) { pthread_descr self = manager_thread = arg; int reqfd = __pthread_manager_reader; struct pollfd ufd; sigset_t manager_mask; int n; struct pthread_request request; /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, 1); #endif #if !(USE_TLS && HAVE___THREAD) /* Set the error variable. */ self->p_errnop = &self->p_errno; self->p_h_errnop = &self->p_h_errno; #endif /* Block all signals except __pthread_sig_cancel and SIGTRAP */ sigfillset(&manager_mask); sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ if (__pthread_threads_debug && __pthread_sig_debug > 0) sigdelset(&manager_mask, __pthread_sig_debug); sigprocmask(SIG_SETMASK, &manager_mask, NULL); /* Raise our priority to match that of main thread */ __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); /* Synchronize debugging of the thread manager */ n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request, sizeof(request))); ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG); ufd.fd = reqfd; ufd.events = POLLIN; /* Enter server loop */ while(1) { n = __poll(&ufd, 1, 2000); /* Check for termination of the main thread */ if (getppid() == 1) { pthread_kill_all_threads(SIGKILL, 0); _exit(0); } /* Check for dead children */ if (terminated_children) { terminated_children = 0; pthread_reap_children(); } /* Read and execute request */ if (n == 1 && (ufd.revents & POLLIN)) { n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request, sizeof(request))); #ifdef DEBUG if (n < 0) { char d[64]; write(STDERR_FILENO, d, snprintf(d, sizeof(d), "*** read err %m\n")); } else if (n != sizeof(request)) { write(STDERR_FILENO, "*** short read in manager\n", 26); } #endif switch(request.req_kind) { case REQ_CREATE: request.req_thread->p_retcode = pthread_handle_create((pthread_t *) &request.req_thread->p_retval, request.req_args.create.attr, request.req_args.create.fn, request.req_args.create.arg, &request.req_args.create.mask, request.req_thread->p_pid, request.req_thread->p_report_events, &request.req_thread->p_eventbuf.eventmask); restart(request.req_thread); break; case REQ_FREE: pthread_handle_free(request.req_args.free.thread_id); break; case REQ_PROCESS_EXIT: pthread_handle_exit(request.req_thread, request.req_args.exit.code); /* NOTREACHED */ break; case REQ_MAIN_THREAD_EXIT: main_thread_exiting = 1; /* Reap children in case all other threads died and the signal handler went off before we set main_thread_exiting to 1, and therefore did not do REQ_KICK. */ pthread_reap_children(); if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); /* The main thread will now call exit() which will trigger an __on_exit handler, which in turn will send REQ_PROCESS_EXIT to the thread manager. In case you are wondering how the manager terminates from its loop here. */ } break; case REQ_POST: sem_post(request.req_args.post); break; case REQ_DEBUG: /* Make gdb aware of new thread and gdb will restart the new thread when it is ready to handle the new thread. */ if (__pthread_threads_debug && __pthread_sig_debug > 0) raise(__pthread_sig_debug); break; case REQ_KICK: /* This is just a prod to get the manager to reap some threads right away, avoiding a potential delay at shutdown. */ break; case REQ_FOR_EACH_THREAD: pthread_for_each_thread(request.req_args.for_each.arg, request.req_args.for_each.fn); restart(request.req_thread); break; } } } }
int __pthread_manager(void * arg) { int reqfd = (int) arg; sigset_t mask; fd_set readfds; struct timeval timeout; int n; struct pthread_request request; /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_manager_thread); #endif /* Block all signals except PTHREAD_SIG_RESTART */ sigfillset(&mask); sigdelset(&mask, PTHREAD_SIG_RESTART); sigprocmask(SIG_SETMASK, &mask, NULL); /* Enter server loop */ while(1) { FD_ZERO(&readfds); FD_SET(reqfd, &readfds); timeout.tv_sec = 2; timeout.tv_usec = 0; n = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout); /* Check for termination of the main thread */ if (getppid() == 1) { pthread_kill_all_threads(SIGKILL, 0); _exit(0); } /* Check for dead children */ if (terminated_children) { terminated_children = 0; pthread_reap_children(); } /* Read and execute request */ if (n == 1 && FD_ISSET(reqfd, &readfds)) { n = read(reqfd, (char *)&request, sizeof(request)); ASSERT(n == sizeof(request)); switch(request.req_kind) { case REQ_CREATE: request.req_thread->p_retcode = pthread_handle_create((pthread_t *) &request.req_thread->p_retval, request.req_args.create.attr, request.req_args.create.fn, request.req_args.create.arg, &request.req_args.create.mask, request.req_thread->p_pid); restart(request.req_thread); break; case REQ_FREE: pthread_handle_free(request.req_args.free.thread); break; case REQ_PROCESS_EXIT: pthread_handle_exit(request.req_thread, request.req_args.exit.code); break; case REQ_MAIN_THREAD_EXIT: main_thread_exiting = 1; if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); return 0; } break; } } } }
static void pthread_initialize(void) { struct sigaction sa; sigset_t mask; #ifdef __ARCH_USE_MMU__ struct rlimit limit; rlim_t max_stack; #endif /* If already done (e.g. by a constructor called earlier!), bail out */ if (__pthread_initial_thread_bos != NULL) return; #ifdef TEST_FOR_COMPARE_AND_SWAP /* Test if compare-and-swap is available */ __pthread_has_cas = compare_and_swap_is_available(); #endif /* For the initial stack, reserve at least STACK_SIZE bytes of stack below the current stack address, and align that on a STACK_SIZE boundary. */ __pthread_initial_thread_bos = (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); /* Update the descriptor for the initial thread. */ __pthread_initial_thread.p_pid = getpid(); /* If we have special thread_self processing, initialize that for the main thread now. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0); #endif /* The errno/h_errno variable of the main thread are the global ones. */ __pthread_initial_thread.p_errnop = &_errno; __pthread_initial_thread.p_h_errnop = &_h_errno; #ifdef __UCLIBC_HAS_XLOCALE__ /* The locale of the main thread is the current locale in use. */ __pthread_initial_thread.locale = __curlocale_var; #endif /* __UCLIBC_HAS_XLOCALE__ */ { /* uClibc-specific stdio initialization for threads. */ FILE *fp; _stdio_user_locking = 0; /* 2 if threading not initialized */ for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) { if (fp->__user_locking != 1) { fp->__user_locking = 0; } } } /* Play with the stack size limit to make sure that no stack ever grows beyond STACK_SIZE minus two pages (one page for the thread descriptor immediately beyond, and one page to act as a guard page). */ #ifdef __ARCH_USE_MMU__ /* We cannot allocate a huge chunk of memory to mmap all thread stacks later * on a non-MMU system. Thus, we don't need the rlimit either. -StS */ getrlimit(RLIMIT_STACK, &limit); max_stack = STACK_SIZE - 2 * getpagesize(); if (limit.rlim_cur > max_stack) { limit.rlim_cur = max_stack; setrlimit(RLIMIT_STACK, &limit); } #else /* For non-MMU, the initial thread stack can reside anywhere in memory. * We don't have a way of knowing where the kernel started things -- top * or bottom (well, that isn't exactly true, but the solution is fairly * complex and error prone). All we can determine here is an address * that lies within that stack. Save that address as a reference so that * as other thread stacks are created, we can adjust the estimated bounds * of the initial thread's stack appropriately. * * This checking is handled in NOMMU_INITIAL_THREAD_BOUNDS(), so see that * for a few more details. */ __pthread_initial_thread_mid = CURRENT_STACK_FRAME; __pthread_initial_thread_tos = (char *) -1; __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know we have been here */ PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n", __pthread_initial_thread_bos, __pthread_initial_thread_tos); #endif /* __ARCH_USE_MMU__ */ /* Setup signal handlers for the initial thread. Since signal handlers are shared between threads, these settings will be inherited by all other threads. */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = pthread_handle_sigrestart; __libc_sigaction(__pthread_sig_restart, &sa, NULL); sa.sa_handler = pthread_handle_sigcancel; sigaddset(&sa.sa_mask, __pthread_sig_restart); __libc_sigaction(__pthread_sig_cancel, &sa, NULL); if (__pthread_sig_debug > 0) { sa.sa_handler = pthread_handle_sigdebug; __sigemptyset(&sa.sa_mask); __libc_sigaction(__pthread_sig_debug, &sa, NULL); } /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ __sigemptyset(&mask); sigaddset(&mask, __pthread_sig_restart); sigprocmask(SIG_BLOCK, &mask, NULL); /* And unblock __pthread_sig_cancel if it has been blocked. */ sigdelset(&mask, __pthread_sig_restart); sigaddset(&mask, __pthread_sig_cancel); sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Register an exit function to kill all other threads. */ /* Do it early so that user-registered atexit functions are called before pthread_onexit_process. */ on_exit(pthread_onexit_process, NULL); }
static void pthread_initialize(void) { struct sigaction sa; sigset_t mask; struct rlimit limit; int max_stack; /* If already done (e.g. by a constructor called earlier!), bail out */ if (__pthread_initial_thread_bos != NULL) return; #ifdef TEST_FOR_COMPARE_AND_SWAP /* Test if compare-and-swap is available */ __pthread_has_cas = compare_and_swap_is_available(); #endif /* For the initial stack, reserve at least STACK_SIZE bytes of stack below the current stack address, and align that on a STACK_SIZE boundary. */ __pthread_initial_thread_bos = (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); /* Update the descriptor for the initial thread. */ __pthread_initial_thread.p_pid = __getpid(); /* If we have special thread_self processing, initialize that for the main thread now. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0); #endif /* The errno/h_errno variable of the main thread are the global ones. */ __pthread_initial_thread.p_errnop = &_errno; __pthread_initial_thread.p_h_errnop = &_h_errno; /* Play with the stack size limit to make sure that no stack ever grows beyond STACK_SIZE minus two pages (one page for the thread descriptor immediately beyond, and one page to act as a guard page). */ #ifdef __UCLIBC_HAS_MMU__ /* We cannot allocate a huge chunk of memory to mmap all thread stacks later * on a non-MMU system. Thus, we don't need the rlimit either. -StS */ getrlimit(RLIMIT_STACK, &limit); max_stack = STACK_SIZE - 2 * __getpagesize(); if (limit.rlim_cur > max_stack) { limit.rlim_cur = max_stack; setrlimit(RLIMIT_STACK, &limit); } #else /* For non-MMU assume __pthread_initial_thread_tos at upper page boundary, and * __pthread_initial_thread_bos at address 0. These bounds are refined as we * malloc other stack frames such that they don't overlap. -StS */ __pthread_initial_thread_tos = (char *)(((long)CURRENT_STACK_FRAME + __getpagesize()) & ~(__getpagesize() - 1)); __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know we have been here */ PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n", __pthread_initial_thread_bos, __pthread_initial_thread_tos); #endif /* __UCLIBC_HAS_MMU__ */ /* Setup signal handlers for the initial thread. Since signal handlers are shared between threads, these settings will be inherited by all other threads. */ sa.sa_handler = pthread_handle_sigrestart; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; __libc_sigaction(__pthread_sig_restart, &sa, NULL); sa.sa_handler = pthread_handle_sigcancel; // sa.sa_flags = 0; __libc_sigaction(__pthread_sig_cancel, &sa, NULL); if (__pthread_sig_debug > 0) { sa.sa_handler = pthread_handle_sigdebug; sigemptyset(&sa.sa_mask); // sa.sa_flags = 0; __libc_sigaction(__pthread_sig_debug, &sa, NULL); } /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ sigemptyset(&mask); sigaddset(&mask, __pthread_sig_restart); sigprocmask(SIG_BLOCK, &mask, NULL); /* Register an exit function to kill all other threads. */ /* Do it early so that user-registered atexit functions are called before pthread_onexit_process. */ on_exit(pthread_onexit_process, NULL); }