/* * Validate the signal number and thread. If valid process the signal. */ int pthread_kill(pthread_t pthread, int sig) { int ret; if (sig >= 0 && sig < NSIG) { ret = _find_thread(pthread); if (ret == 0 && sig != 0) { if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { _thread_kern_sig_defer(); if (pthread->state == PS_SIGWAIT && sigismember(pthread->data.sigwait, sig)) { PTHREAD_NEW_STATE(pthread,PS_RUNNING); pthread->signo = sig; } else { _thread_kill_siginfo(sig); _thread_signal(pthread,sig); } _thread_kern_sig_undefer(); } } } else ret = EINVAL; return ret; }
int pthread_suspend_np(pthread_t thread) { int ret = -1; pthread_t pthread; PTHREAD_INIT; /* * Search for the thread in the linked list. */ for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) { /* Is this the thread? */ if (pthread == thread) { /* Found the thread. Is it running? */ if (pthread->state != PS_RUNNING && pthread->state != PS_SUSPENDED) { /* The thread operation has been interrupted */ _thread_seterrno(pthread,EINTR); } else if (pthread->state == PS_RUNNING) DosSuspendThread(pthread->threadid); /* Suspend the thread. */ PTHREAD_NEW_STATE(pthread,PS_SUSPENDED); ret = 0; } } /* Check if thread was not found. */ if (ret == -1) { /* No such thread */ errno = ESRCH; } return(ret); }
int _pthread_detach(pthread_t pthread) { int rval = 0; /* Check for invalid calling parameters: */ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) /* Return an invalid argument error: */ rval = EINVAL; /* Check if the thread has not been detached: */ else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { /* Flag the thread as detached: */ pthread->attr.flags |= PTHREAD_DETACHED; /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Check if there is a joiner: */ if (pthread->joiner != NULL) { struct pthread *joiner = pthread->joiner; /* Make the thread runnable: */ PTHREAD_NEW_STATE(joiner, PS_RUNNING); /* Set the return value for the woken thread: */ joiner->join_status.error = ESRCH; joiner->join_status.ret = NULL; joiner->join_status.thread = NULL; /* * Disconnect the joiner from the thread being detached: */ pthread->joiner = NULL; } /* * Undefer and handle pending signals, yielding if a * scheduling signal occurred while in the critical region. */ _thread_kern_sig_undefer(); } else /* Return an error: */ rval = EINVAL; /* Return the completion status: */ return (rval); }
void pthread_exit(void *status) { struct pthread *curthread = _get_curthread(); pthread_t pthread; /* Check if this thread is already in the process of exiting: */ if ((curthread->flags & PTHREAD_EXITING) != 0) { PANIC("Thread has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!"); } /* Flag this thread as exiting: */ curthread->flags |= PTHREAD_EXITING; /* Save the return value: */ curthread->ret = status; while (curthread->cleanup != NULL) { pthread_cleanup_pop(1); } if (curthread->attr.cleanup_attr != NULL) { curthread->attr.cleanup_attr(curthread->attr.arg_attr); } /* Check if there is thread specific data: */ if (curthread->specific_data != NULL) { /* Run the thread-specific data destructors: */ _thread_cleanupspecific(); } /* * Lock the garbage collector mutex to ensure that the garbage * collector is not using the dead thread list. */ if (pthread_mutex_lock(&_gc_mutex) != 0) PANIC("Cannot lock gc mutex"); /* Add this thread to the list of dead threads. */ TAILQ_INSERT_HEAD(&_dead_list, curthread, dle); /* * Signal the garbage collector thread that there is something * to clean up. */ if (pthread_cond_signal(&_gc_cond) != 0) PANIC("Cannot signal gc cond"); /* * Avoid a race condition where a scheduling signal can occur * causing the garbage collector thread to run. If this happens, * the current thread can be cleaned out from under us. */ _thread_kern_sig_defer(); /* Unlock the garbage collector mutex: */ if (pthread_mutex_unlock(&_gc_mutex) != 0) PANIC("Cannot unlock gc mutex"); /* Check if there is a thread joining this one: */ if (curthread->joiner != NULL) { pthread = curthread->joiner; curthread->joiner = NULL; switch (pthread->suspended) { case SUSP_JOIN: /* * The joining thread is suspended. Change the * suspension state to make the thread runnable when it * is resumed: */ pthread->suspended = SUSP_NO; break; case SUSP_NO: /* Make the joining thread runnable: */ PTHREAD_NEW_STATE(pthread, PS_RUNNING); break; default: PANIC("Unreachable code reached"); } /* Set the return value for the joining thread: */ pthread->join_status.ret = curthread->ret; pthread->join_status.error = 0; pthread->join_status.thread = NULL; /* Make this thread collectable by the garbage collector. */ PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) == 0), "Cannot join a detached thread"); curthread->attr.flags |= PTHREAD_DETACHED; } /* Remove this thread from the thread list: */ TAILQ_REMOVE(&_thread_list, curthread, tle); /* This thread will never be re-scheduled. */ _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__); /* This point should not be reached. */ PANIC("Dead thread has resumed"); }
int _pthread_cond_broadcast(pthread_cond_t * cond) { int rval = 0; pthread_t pthread; if (cond == NULL) rval = EINVAL; /* * If the condition variable is statically initialized, perform dynamic * initialization. */ else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { /* * Defer signals to protect the scheduling queues * from access by the signal handler: */ _thread_kern_sig_defer(); /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); /* Process according to condition variable type: */ switch ((*cond)->c_type) { /* Fast condition variable: */ case COND_TYPE_FAST: /* Increment the sequence number: */ (*cond)->c_seqno++; /* * Enter a loop to bring all threads off the * condition queue: */ while ((pthread = cond_queue_deq(*cond)) != NULL) { /* * Wake up the signaled thread: */ PTHREAD_NEW_STATE(pthread, PS_RUNNING); } /* There are no more waiting threads: */ (*cond)->c_mutex = NULL; break; /* Trap invalid condition variable types: */ default: /* Return an invalid argument error: */ rval = EINVAL; break; } /* Unlock the condition variable structure: */ _SPINUNLOCK(&(*cond)->lock); /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); } /* Return the completion status: */ return (rval); }
static inline int mutex_unlock_common(pthread_mutex_t * mutex, int add_reference) { struct pthread *curthread = _get_curthread(); int ret = 0; if (mutex == NULL || *mutex == NULL) { ret = EINVAL; } else { /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Lock the mutex structure: */ _SPINLOCK(&(*mutex)->lock); /* Process according to mutex type: */ switch ((*mutex)->m_protocol) { /* Default POSIX mutex: */ case PTHREAD_PRIO_NONE: /* * Check if the running thread is not the owner of the * mutex: */ if ((*mutex)->m_owner != curthread) { /* * Return an invalid argument error for no * owner and a permission error otherwise: */ ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; } else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && ((*mutex)->m_data.m_count > 0)) { /* Decrement the count: */ (*mutex)->m_data.m_count--; } else { /* * Clear the count in case this is recursive * mutex. */ (*mutex)->m_data.m_count = 0; /* Remove the mutex from the threads queue. */ _MUTEX_ASSERT_IS_OWNED(*mutex); TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, (*mutex), m_qe); _MUTEX_INIT_LINK(*mutex); /* * Get the next thread from the queue of * threads waiting on the mutex: */ if (((*mutex)->m_owner = mutex_queue_deq(*mutex)) != NULL) { /* Make the new owner runnable: */ PTHREAD_NEW_STATE((*mutex)->m_owner, PS_RUNNING); /* * Add the mutex to the threads list of * owned mutexes: */ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, (*mutex), m_qe); /* * The owner is no longer waiting for * this mutex: */ (*mutex)->m_owner->data.mutex = NULL; } } break; /* POSIX priority inheritence mutex: */ case PTHREAD_PRIO_INHERIT: /* * Check if the running thread is not the owner of the * mutex: */ if ((*mutex)->m_owner != curthread) { /* * Return an invalid argument error for no * owner and a permission error otherwise: */ ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; } else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && ((*mutex)->m_data.m_count > 0)) { /* Decrement the count: */ (*mutex)->m_data.m_count--; } else { /* * Clear the count in case this is recursive * mutex. */ (*mutex)->m_data.m_count = 0; /* * Restore the threads inherited priority and * recompute the active priority (being careful * not to override changes in the threads base * priority subsequent to locking the mutex). */ curthread->inherited_priority = (*mutex)->m_saved_prio; curthread->active_priority = MAX(curthread->inherited_priority, curthread->base_priority); /* * This thread now owns one less priority mutex. */ curthread->priority_mutex_count--; /* Remove the mutex from the threads queue. */ _MUTEX_ASSERT_IS_OWNED(*mutex); TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, (*mutex), m_qe); _MUTEX_INIT_LINK(*mutex); /* * Get the next thread from the queue of threads * waiting on the mutex: */ if (((*mutex)->m_owner = mutex_queue_deq(*mutex)) == NULL) /* This mutex has no priority. */ (*mutex)->m_prio = 0; else { /* * Track number of priority mutexes owned: */ (*mutex)->m_owner->priority_mutex_count++; /* * Add the mutex to the threads list * of owned mutexes: */ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, (*mutex), m_qe); /* * The owner is no longer waiting for * this mutex: */ (*mutex)->m_owner->data.mutex = NULL; /* * Set the priority of the mutex. Since * our waiting threads are in descending * priority order, the priority of the * mutex becomes the active priority of * the thread we just dequeued. */ (*mutex)->m_prio = (*mutex)->m_owner->active_priority; /* * Save the owning threads inherited * priority: */ (*mutex)->m_saved_prio = (*mutex)->m_owner->inherited_priority; /* * The owning threads inherited priority * now becomes his active priority (the * priority of the mutex). */ (*mutex)->m_owner->inherited_priority = (*mutex)->m_prio; /* * Make the new owner runnable: */ PTHREAD_NEW_STATE((*mutex)->m_owner, PS_RUNNING); } } break; /* POSIX priority ceiling mutex: */ case PTHREAD_PRIO_PROTECT: /* * Check if the running thread is not the owner of the * mutex: */ if ((*mutex)->m_owner != curthread) { /* * Return an invalid argument error for no * owner and a permission error otherwise: */ ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; } else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && ((*mutex)->m_data.m_count > 0)) { /* Decrement the count: */ (*mutex)->m_data.m_count--; } else { /* * Clear the count in case this is recursive * mutex. */ (*mutex)->m_data.m_count = 0; /* * Restore the threads inherited priority and * recompute the active priority (being careful * not to override changes in the threads base * priority subsequent to locking the mutex). */ curthread->inherited_priority = (*mutex)->m_saved_prio; curthread->active_priority = MAX(curthread->inherited_priority, curthread->base_priority); /* * This thread now owns one less priority mutex. */ curthread->priority_mutex_count--; /* Remove the mutex from the threads queue. */ _MUTEX_ASSERT_IS_OWNED(*mutex); TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, (*mutex), m_qe); _MUTEX_INIT_LINK(*mutex); /* * Enter a loop to find a waiting thread whose * active priority will not cause a ceiling * violation: */ while ((((*mutex)->m_owner = mutex_queue_deq(*mutex)) != NULL) && ((*mutex)->m_owner->active_priority > (*mutex)->m_prio)) { /* * Either the mutex ceiling priority * been lowered and/or this threads * priority has been raised subsequent * to this thread being queued on the * waiting list. */ tls_set_tcb((*mutex)->m_owner->tcb); errno = EINVAL; tls_set_tcb(curthread->tcb); PTHREAD_NEW_STATE((*mutex)->m_owner, PS_RUNNING); /* * The thread is no longer waiting for * this mutex: */ (*mutex)->m_owner->data.mutex = NULL; } /* Check for a new owner: */ if ((*mutex)->m_owner != NULL) { /* * Track number of priority mutexes owned: */ (*mutex)->m_owner->priority_mutex_count++; /* * Add the mutex to the threads list * of owned mutexes: */ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, (*mutex), m_qe); /* * The owner is no longer waiting for * this mutex: */ (*mutex)->m_owner->data.mutex = NULL; /* * Save the owning threads inherited * priority: */ (*mutex)->m_saved_prio = (*mutex)->m_owner->inherited_priority; /* * The owning thread inherits the * ceiling priority of the mutex and * executes at that priority: */ (*mutex)->m_owner->inherited_priority = (*mutex)->m_prio; (*mutex)->m_owner->active_priority = (*mutex)->m_prio; /* * Make the new owner runnable: */ PTHREAD_NEW_STATE((*mutex)->m_owner, PS_RUNNING); } } break; /* Trap invalid mutex types: */ default: /* Return an invalid argument error: */ ret = EINVAL; break; } if ((ret == 0) && (add_reference != 0)) { /* Increment the reference count: */ (*mutex)->m_refcount++; } /* Unlock the mutex structure: */ _SPINUNLOCK(&(*mutex)->lock); /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); } /* Return the completion status: */ return (ret); }
void funlockfile(FILE * fp) { int idx = file_idx(fp); struct file_lock *p; /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Lock the hash table: */ _SPINLOCK(&hash_lock); /* * Get a pointer to the lock for the file and check that * the running thread is the one with the lock: */ if ((p = find_lock(idx, fp)) != NULL && p->owner == _thread_run) { /* * Check if this thread has locked the FILE * more than once: */ if (p->count > 1) /* * Decrement the count of the number of * times the running thread has locked this * file: */ p->count--; else { /* * The running thread will release the * lock now: */ p->count = 0; /* Get the new owner of the lock: */ if ((p->owner = TAILQ_FIRST(&p->l_head)) != NULL) { /* Pop the thread off the queue: */ TAILQ_REMOVE(&p->l_head,p->owner,qe); /* * This is the first lock for the new * owner: */ p->count = 1; /* Allow the new owner to run: */ PTHREAD_NEW_STATE(p->owner,PS_RUNNING); } } } /* Unlock the hash table: */ _SPINUNLOCK(&hash_lock); /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); }
int pthread_join(pthread_t pthread, void **thread_return) { int rval = 0; int status = 0; TID tid; pthread_t pthread1; PTHREAD_INIT; /* Block signals: */ _thread_kern_sig_block(&status); /* Point to the first thread in the list: */ pthread1 = _thread_link_list; /* Search for the thread to join to: */ while (pthread1 != NULL && pthread1 != pthread) { /* Point to the next thread: */ pthread1 = pthread1->nxt; } if (pthread1 == NULL) { /* Point to the first thread in the dead thread list: */ pthread1 = _thread_dead; /* Search for the thread to join to: */ while (pthread1 != NULL && pthread1 != pthread) { /* Point to the next thread: */ pthread1 = pthread1->nxt; } } if (pthread1 == NULL) { /* Return an error: */ errno = ESRCH; rval = -1; /* Check if this thread has been detached: */ } else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { /* Return an error: */ errno = ESRCH; rval = -1; } /* Check if the thread is not dead: */ else if (pthread->state != PS_DEAD) { /* Add the running thread to the join queue: */ /* _thread_queue_enq(&(pthread->join_queue), _thread_run); */ _thread_kern_sig_unblock(status); /* Schedule the next thread: */ /* _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__); */ PTHREAD_NEW_STATE(_thread_run, PS_JOIN); tid = (pthread)->threadid; DosWaitThread(&tid, DCWW_WAIT); PTHREAD_NEW_STATE(_thread_run, PS_RUNNING); /* Block signals again: */ _thread_kern_sig_block(&status); /* Check if the thread is not detached: */ if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { /* Check if the return value is required: */ if (thread_return) { /* Return the thread's return value: */ *thread_return = pthread->ret; } } else { /* Return an error: */ errno = ESRCH; rval = -1; } } else { /* Check if the return value is required: */ if (thread_return != NULL) { /* Return the thread's return value: */ *thread_return = pthread->ret; } } /* Unblock signals: */ _thread_kern_sig_unblock(status); /* Return the completion status: */ return (rval); }