void pthread_testcancel(void) { pthread_descr self = thread_self(); if (THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); }
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); }
void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer, int execute) { pthread_descr self = thread_self(); if (execute) buffer->__routine(buffer->__arg); THREAD_SETMEM(self, p_cleanup, buffer->__prev); THREAD_SETMEM(self, p_canceltype, buffer->__canceltype); if (THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); }
int pthread_setcanceltype(int type, int * oldtype) { pthread_descr self = thread_self(); if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) return EINVAL; if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype); THREAD_SETMEM(self, p_canceltype, type); if (THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); return 0; }
/* 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); }
int sem_wait(sem_t * sem) { __volatile__ pthread_descr self = thread_self(); pthread_extricate_if extr; int already_canceled = 0; int spurious_wakeup_count; /* Set up extrication interface */ extr.pu_object = sem; extr.pu_extricate_func = new_sem_extricate_func; __pthread_lock(&sem->__sem_lock, self); if (sem->__sem_value > 0) { sem->__sem_value--; __pthread_unlock(&sem->__sem_lock); return 0; } /* Register extrication interface */ THREAD_SETMEM(self, p_sem_avail, 0); __pthread_set_own_extricate_if(self, &extr); /* Enqueue only if not already cancelled. */ if (!(THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) enqueue(&sem->__sem_waiting, self); else already_canceled = 1; __pthread_unlock(&sem->__sem_lock); if (already_canceled) { __pthread_set_own_extricate_if(self, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } /* Wait for sem_post or cancellation, or fall through if already canceled */ spurious_wakeup_count = 0; while (1) { suspend(self); if (THREAD_GETMEM(self, p_sem_avail) == 0 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) { /* Count resumes that don't belong to us. */ spurious_wakeup_count++; continue; } break; } __pthread_set_own_extricate_if(self, 0); /* Terminate only if the wakeup came from cancellation. */ /* Otherwise ignore cancellation because we got the semaphore. */ if (THREAD_GETMEM(self, p_woken_by_cancel) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { THREAD_SETMEM(self, p_woken_by_cancel, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } /* We got the semaphore */ return 0; }
int sem_timedwait(sem_t *sem, const struct timespec *abstime) { pthread_descr self = thread_self(); pthread_extricate_if extr; int already_canceled = 0; int spurious_wakeup_count; __pthread_lock(&sem->__sem_lock, self); if (sem->__sem_value > 0) { --sem->__sem_value; __pthread_unlock(&sem->__sem_lock); return 0; } if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) { /* The standard requires that if the function would block and the time value is illegal, the function returns with an error. */ __pthread_unlock(&sem->__sem_lock); __set_errno (EINVAL); return -1; } /* Set up extrication interface */ extr.pu_object = sem; extr.pu_extricate_func = new_sem_extricate_func; /* Register extrication interface */ THREAD_SETMEM(self, p_sem_avail, 0); __pthread_set_own_extricate_if(self, &extr); /* Enqueue only if not already cancelled. */ if (!(THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) enqueue(&sem->__sem_waiting, self); else already_canceled = 1; __pthread_unlock(&sem->__sem_lock); if (already_canceled) { __pthread_set_own_extricate_if(self, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } spurious_wakeup_count = 0; while (1) { if (timedsuspend(self, abstime) == 0) { int was_on_queue; /* __pthread_lock will queue back any spurious restarts that may happen to it. */ __pthread_lock(&sem->__sem_lock, self); was_on_queue = remove_from_queue(&sem->__sem_waiting, self); __pthread_unlock(&sem->__sem_lock); if (was_on_queue) { __pthread_set_own_extricate_if(self, 0); __set_errno (ETIMEDOUT); return -1; } /* Eat the outstanding restart() from the signaller */ suspend(self); } if (THREAD_GETMEM(self, p_sem_avail) == 0 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) { /* Count resumes that don't belong to us. */ spurious_wakeup_count++; continue; } break; } __pthread_set_own_extricate_if(self, 0); /* Terminate only if the wakeup came from cancellation. */ /* Otherwise ignore cancellation because we got the semaphore. */ if (THREAD_GETMEM(self, p_woken_by_cancel) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { THREAD_SETMEM(self, p_woken_by_cancel, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } /* We got the semaphore */ return 0; }
int __old_sem_wait(old_sem_t * sem) { long oldstatus, newstatus; volatile pthread_descr self = thread_self(); pthread_descr * th; pthread_extricate_if extr; /* Set up extrication interface */ extr.pu_object = 0; extr.pu_extricate_func = old_sem_extricate_func; while (1) { /* Register extrication interface */ __pthread_set_own_extricate_if(self, &extr); do { oldstatus = sem->sem_status; if ((oldstatus & 1) && (oldstatus != 1)) newstatus = oldstatus - 2; else { newstatus = (long) self; self->p_nextwaiting = (pthread_descr) oldstatus; } } while (! sem_compare_and_swap(sem, oldstatus, newstatus)); if (newstatus & 1) { /* We got the semaphore. */ __pthread_set_own_extricate_if(self, 0); self->p_nextwaiting = NULL; return 0; } /* Wait for sem_post or cancellation */ suspend(self); __pthread_set_own_extricate_if(self, 0); /* This is a cancellation point */ if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { /* Remove ourselves from the waiting list if we're still on it */ /* First check if we're at the head of the list. */ do { oldstatus = sem->sem_status; if (oldstatus != (long) self) break; newstatus = (long) self->p_nextwaiting; } while (! sem_compare_and_swap(sem, oldstatus, newstatus)); /* Now, check if we're somewhere in the list. There's a race condition with sem_post here, but it does not matter: the net result is that at the time pthread_exit is called, self is no longer reachable from sem->sem_status. */ if (oldstatus != (long) self && (oldstatus & 1) == 0) { for (th = &(((pthread_descr) oldstatus)->p_nextwaiting); *th != NULL && *th != (pthread_descr) 1; th = &((*th)->p_nextwaiting)) { if (*th == self) { *th = self->p_nextwaiting; break; } } } __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } } }
void pthread_exit(void * retval) { __pthread_do_exit (retval, CURRENT_STACK_FRAME); }
int pthread_join(pthread_t thread_id, void ** thread_return) { volatile pthread_descr self = thread_self(); struct pthread_request request; pthread_handle handle = thread_handle(thread_id); pthread_descr th; pthread_extricate_if extr; int already_canceled = 0; PDEBUG("\n"); /* Set up extrication interface */ extr.pu_object = handle; extr.pu_extricate_func = join_extricate_func; __pthread_lock(&handle->h_lock, self); if (invalid_handle(handle, thread_id)) { __pthread_unlock(&handle->h_lock); return ESRCH; } th = handle->h_descr; if (th == self) { __pthread_unlock(&handle->h_lock); return EDEADLK; } /* If detached or already joined, error */ if (th->p_detached || th->p_joining != NULL) { __pthread_unlock(&handle->h_lock); return EINVAL; } /* If not terminated yet, suspend ourselves. */ if (! th->p_terminated) { /* Register extrication interface */ __pthread_set_own_extricate_if(self, &extr); if (!(THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) th->p_joining = self; else already_canceled = 1; __pthread_unlock(&handle->h_lock); if (already_canceled) { __pthread_set_own_extricate_if(self, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } PDEBUG("before suspend\n"); suspend(self); PDEBUG("after suspend\n"); /* Deregister extrication interface */ __pthread_set_own_extricate_if(self, 0); /* This is a cancellation point */ if (THREAD_GETMEM(self, p_woken_by_cancel) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { THREAD_SETMEM(self, p_woken_by_cancel, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } __pthread_lock(&handle->h_lock, self); } /* Get return value */ if (thread_return != NULL) *thread_return = th->p_retval; __pthread_unlock(&handle->h_lock); /* Send notification to thread manager */ if (__pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_FREE; request.req_args.free.thread_id = thread_id; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); } return 0; }