Ejemplo n.º 1
0
static void
thread_start(struct pthread *curthread)
{
	sigset_t set;

	if (curthread->attr.suspend == THR_CREATE_SUSPENDED)
		set = curthread->sigmask;

	/*
	 * This is used as a serialization point to allow parent
	 * to report 'new thread' event to debugger or tweak new thread's
	 * attributes before the new thread does real-world work.
	 */
	THR_LOCK(curthread);
	THR_UNLOCK(curthread);

	if (curthread->force_exit)
		_pthread_exit(PTHREAD_CANCELED);

	if (curthread->attr.suspend == THR_CREATE_SUSPENDED) {
#if 0
		/* Done in THR_UNLOCK() */
		_thr_ast(curthread);
#endif

		/*
		 * Parent thread have stored signal mask for us,
		 * we should restore it now.
		 */
		__sys_sigprocmask(SIG_SETMASK, &set, NULL);
	}

#ifdef _PTHREAD_FORCED_UNWIND
	curthread->unwind_stackend = (char *)curthread->attr.stackaddr_attr +
		curthread->attr.stacksize_attr;
#endif

	/* Run the current thread's start routine with argument: */
	_pthread_exit(curthread->start_routine(curthread->arg));

	/* This point should never be reached. */
	PANIC("Thread has resumed after exit");
}
Ejemplo n.º 2
0
void
_thr_cancel_enter2(struct pthread *curthread, int maycancel)
{
	curthread->cancel_point = 1;
	if (__predict_false(SHOULD_CANCEL(curthread) &&
	    !THR_IN_CRITICAL(curthread))) {
		if (!maycancel)
			thr_wake(curthread->tid);
		else
			_pthread_exit(PTHREAD_CANCELED);
	}
}
Ejemplo n.º 3
0
static inline void
testcancel(struct pthread *curthread)
{
	if (checkcancel(curthread) != 0) {
		/* Unlock before exiting: */
		THR_THREAD_UNLOCK(curthread, curthread);

		_thr_exit_cleanup();
		_pthread_exit(PTHREAD_CANCELED);
		PANIC("cancel");
	}
}
Ejemplo n.º 4
0
void
_thread_start(void)
{
	struct pthread	*curthread = _get_curthread();

	/* We just left the scheduler via longjmp: */
	_thread_kern_in_sched = 0;

	/* Run the current thread's start routine with argument: */
	_pthread_exit(curthread->start_routine(curthread->arg));

	/* This point should never be reached. */
	PANIC("Thread has resumed after exit");
}
Ejemplo n.º 5
0
int
_pthread_setcancelstate(int state, int *oldstate)
{
	struct pthread	*curthread = _get_curthread();
	int ostate;
	int ret;
	int need_exit = 0;

	/* Take the thread's lock while fiddling with the state: */
	THR_THREAD_LOCK(curthread, curthread);

	ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;

	switch (state) {
	case PTHREAD_CANCEL_ENABLE:
		curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
		if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
			need_exit = checkcancel(curthread);
		ret = 0;
		break;
	case PTHREAD_CANCEL_DISABLE:
		curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
		ret = 0;
		break;
	default:
		ret = EINVAL;
	}

	THR_THREAD_UNLOCK(curthread, curthread);
	if (need_exit != 0) {
		_thr_exit_cleanup();
		_pthread_exit(PTHREAD_CANCELED);
		PANIC("cancel");
	}
	if (ret == 0 && oldstate != NULL)
		*oldstate = ostate;

	return (ret);
}
Ejemplo n.º 6
0
static void
thread_start(void *arg)
{
	struct pthread *curthread = (struct pthread *)arg;

	tls_set_tcb(curthread->tcb);

	/* Thread was created with all signals blocked, unblock them. */
	__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);

	THR_LOCK(curthread);
	THR_UNLOCK(curthread);

	if (curthread->flags & THR_FLAGS_NEED_SUSPEND)
		_thr_suspend_check(curthread);
	_nmalloc_thr_init();

	/* Run the current thread's start routine with argument: */
	_pthread_exit(curthread->start_routine(curthread->arg));

	/* This point should never be reached. */
	PANIC("Thread has resumed after exit");
}
Ejemplo n.º 7
0
static int
cond_wait_user(struct pthread_cond *cvp, struct pthread_mutex *mp,
	const struct timespec *abstime, int cancel)
{
	struct pthread	*curthread = _get_curthread();
	struct sleepqueue *sq;
	int	recurse;
	int	error;

	if (curthread->wchan != NULL)
		PANIC("thread was already on queue.");

	if (cancel)
		_thr_testcancel(curthread);

	_sleepq_lock(cvp);
	/*
	 * set __has_user_waiters before unlocking mutex, this allows
	 * us to check it without locking in pthread_cond_signal().
	 */
	cvp->__has_user_waiters = 1; 
	curthread->will_sleep = 1;
	(void)_mutex_cv_unlock(mp, &recurse);
	curthread->mutex_obj = mp;
	_sleepq_add(cvp, curthread);
	for(;;) {
		_thr_clear_wake(curthread);
		_sleepq_unlock(cvp);

		if (cancel) {
			_thr_cancel_enter2(curthread, 0);
			error = _thr_sleep(curthread, cvp->__clock_id, abstime);
			_thr_cancel_leave(curthread, 0);
		} else {
			error = _thr_sleep(curthread, cvp->__clock_id, abstime);
		}

		_sleepq_lock(cvp);
		if (curthread->wchan == NULL) {
			error = 0;
			break;
		} else if (cancel && SHOULD_CANCEL(curthread)) {
			sq = _sleepq_lookup(cvp);
			cvp->__has_user_waiters = 
				_sleepq_remove(sq, curthread);
			_sleepq_unlock(cvp);
			curthread->mutex_obj = NULL;
			_mutex_cv_lock(mp, recurse);
			if (!THR_IN_CRITICAL(curthread))
				_pthread_exit(PTHREAD_CANCELED);
			else /* this should not happen */
				return (0);
		} else if (error == ETIMEDOUT) {
			sq = _sleepq_lookup(cvp);
			cvp->__has_user_waiters =
				_sleepq_remove(sq, curthread);
			break;
		}
	}
	_sleepq_unlock(cvp);
	curthread->mutex_obj = NULL;
	_mutex_cv_lock(mp, recurse);
	return (error);
}
Ejemplo n.º 8
0
int
_pthread_join(pthread_t pthread, void **thread_return)
{
	struct pthread *curthread = _get_curthread();
	void *tmp;
	kse_critical_t crit;
	int ret = 0;
 
	_thr_cancel_enter(curthread);

	/* Check if the caller has specified an invalid thread: */
	if (pthread == NULL || pthread->magic != THR_MAGIC) {
		/* Invalid thread: */
		_thr_cancel_leave(curthread, 1);
		return (EINVAL);
	}

	/* Check if the caller has specified itself: */
	if (pthread == curthread) {
		/* Avoid a deadlock condition: */
		_thr_cancel_leave(curthread, 1);
		return (EDEADLK);
	}

	/*
	 * Find the thread in the list of active threads or in the
	 * list of dead threads:
	 */
	if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) {
		/* Return an error: */
		_thr_cancel_leave(curthread, 1);
		return (ESRCH);
	}

	THR_SCHED_LOCK(curthread, pthread);
	/* Check if this thread has been detached: */
	if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
		THR_SCHED_UNLOCK(curthread, pthread);
		/* Remove the reference and return an error: */
		_thr_ref_delete(curthread, pthread);
		ret = EINVAL;
	} else {
		/* Lock the target thread while checking its state. */
		if (pthread->state == PS_DEAD) {
			/* Return the thread's return value: */
			tmp = pthread->ret;

			/* Detach the thread. */
			pthread->attr.flags |= PTHREAD_DETACHED;

			/* Unlock the thread. */
			THR_SCHED_UNLOCK(curthread, pthread);

			/*
			 * Remove the thread from the list of active
			 * threads and add it to the GC list.
			 */
			crit = _kse_critical_enter();
			KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
			THR_LIST_REMOVE(pthread);
			THR_GCLIST_ADD(pthread);
			KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
			_kse_critical_leave(crit);

			/* Remove the reference. */
			_thr_ref_delete(curthread, pthread);
			if (thread_return != NULL)
				*thread_return = tmp;
		}
		else if (pthread->joiner != NULL) {
			/* Unlock the thread and remove the reference. */
			THR_SCHED_UNLOCK(curthread, pthread);
			_thr_ref_delete(curthread, pthread);

			/* Multiple joiners are not supported. */
			ret = ENOTSUP;
		}
		else {
			/* Set the running thread to be the joiner: */
			pthread->joiner = curthread;

			/* Keep track of which thread we're joining to: */
			curthread->join_status.thread = pthread;

			/* Unlock the thread and remove the reference. */
			THR_SCHED_UNLOCK(curthread, pthread);
			_thr_ref_delete(curthread, pthread);

			THR_SCHED_LOCK(curthread, curthread);
			while (curthread->join_status.thread == pthread) {
				THR_SET_STATE(curthread, PS_JOIN);
				THR_SCHED_UNLOCK(curthread, curthread);
				/* Schedule the next thread: */
				_thr_sched_switch(curthread);
				THR_SCHED_LOCK(curthread, curthread);
			}
			THR_SCHED_UNLOCK(curthread, curthread);

			if ((curthread->cancelflags & THR_CANCELLING) &&
			   !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) {
				if (_thr_ref_add(curthread, pthread, 1) == 0) {
					THR_SCHED_LOCK(curthread, pthread);
					pthread->joiner = NULL;
					THR_SCHED_UNLOCK(curthread, pthread);
					_thr_ref_delete(curthread, pthread);
				}
				_pthread_exit(PTHREAD_CANCELED);
			}

			/*
			 * The thread return value and error are set by the
			 * thread we're joining to when it exits or detaches:
			 */
			ret = curthread->join_status.error;
			if ((ret == 0) && (thread_return != NULL))
				*thread_return = curthread->join_status.ret;
		}
	}
	_thr_cancel_leave(curthread, 1);

	/* Return the completion status: */
	return (ret);
}