Beispiel #1
0
/*
 * 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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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");
}
Beispiel #5
0
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);
}
Beispiel #6
0
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);
}
Beispiel #7
0
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();
}
Beispiel #8
0
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);
}