int __pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, const struct timespec *abstime) { pthread_descr self; pthread_extricate_if extr; if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return EINVAL; self = thread_self (); /* Set up extrication interface */ extr.pu_object = rwlock; extr.pu_extricate_func = rwlock_wr_extricate_func; /* Register extrication interface */ __pthread_set_own_extricate_if (self, &extr); while(1) { __pthread_lock (&rwlock->__rw_lock, self); if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) { rwlock->__rw_writer = self; __pthread_set_own_extricate_if (self, 0); __pthread_unlock (&rwlock->__rw_lock); return 0; } /* Suspend ourselves, then try again */ enqueue (&rwlock->__rw_write_waiting, self); __pthread_unlock (&rwlock->__rw_lock); /* This is not a cancellation point */ if (timedsuspend (self, abstime) == 0) { int was_on_queue; __pthread_lock (&rwlock->__rw_lock, self); was_on_queue = remove_from_queue (&rwlock->__rw_write_waiting, self); __pthread_unlock (&rwlock->__rw_lock); if (was_on_queue) { __pthread_set_own_extricate_if (self, 0); return ETIMEDOUT; } /* Eat the outstanding restart() from the signaller */ suspend (self); } } }
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 __pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, const struct timespec *abstime) { pthread_descr self = NULL; pthread_readlock_info *existing; int out_of_mem, have_lock_already; pthread_extricate_if extr; if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return EINVAL; have_lock_already = rwlock_have_already(&self, rwlock, &existing, &out_of_mem); if (self == NULL) self = thread_self (); /* Set up extrication interface */ extr.pu_object = rwlock; extr.pu_extricate_func = rwlock_rd_extricate_func; /* Register extrication interface */ __pthread_set_own_extricate_if (self, &extr); for (;;) { __pthread_lock (&rwlock->__rw_lock, self); if (rwlock_can_rdlock(rwlock, have_lock_already)) break; enqueue (&rwlock->__rw_read_waiting, self); __pthread_unlock (&rwlock->__rw_lock); /* This is not a cancellation point */ if (timedsuspend (self, abstime) == 0) { int was_on_queue; __pthread_lock (&rwlock->__rw_lock, self); was_on_queue = remove_from_queue (&rwlock->__rw_read_waiting, self); __pthread_unlock (&rwlock->__rw_lock); if (was_on_queue) { __pthread_set_own_extricate_if (self, 0); return ETIMEDOUT; } /* Eat the outstanding restart() from the signaller */ suspend (self); } } __pthread_set_own_extricate_if (self, 0); ++rwlock->__rw_readers; __pthread_unlock (&rwlock->__rw_lock); if (have_lock_already || out_of_mem) { if (existing != NULL) ++existing->pr_lock_count; else ++self->p_untracked_readlock_count; } 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); } } }
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; }