예제 #1
0
int
_pthread_detach(pthread_t pthread)
{
	struct pthread *curthread = _get_curthread();
	int rval;

	if (pthread == NULL)
		return (EINVAL);

	if ((rval = _thr_find_thread(curthread, pthread,
			/*include dead*/1)) != 0) {
		return (rval);
	}

	/* Check if the thread is already detached or has a joiner. */
	if ((pthread->flags & THR_FLAGS_DETACHED) != 0 ||
	    (pthread->joiner != NULL)) {
		THR_THREAD_UNLOCK(curthread, pthread);
		return (EINVAL);
	}

	/* Flag the thread as detached. */
	pthread->flags |= THR_FLAGS_DETACHED;
	_thr_try_gc(curthread, pthread); /* thread lock released */

	return (0);
}
예제 #2
0
int
_pthread_setprio(pthread_t pthread, int prio)
{
	struct pthread	*curthread = _get_curthread();
	struct sched_param	param;
	int	ret;

	param.sched_priority = prio;
	if (pthread == curthread)
		THR_LOCK(curthread);
	else if ((ret = _thr_find_thread(curthread, pthread, /*include dead*/0)))
		return (ret);
	if (pthread->attr.sched_policy == SCHED_OTHER ||
	    pthread->attr.prio == prio) {
		pthread->attr.prio = prio;
		ret = 0;
	} else {
		ret = _thr_setscheduler(pthread->tid,
			pthread->attr.sched_policy, &param);
		if (ret == -1)
			ret = errno;
		else
			pthread->attr.prio = prio;
	}
	THR_THREAD_UNLOCK(curthread, pthread);
	return (ret);
}
예제 #3
0
int
_pthread_detach(pthread_t pthread)
{
	struct pthread *curthread = tls_get_curthread();
	int rval;

	if (pthread == NULL)
		return (EINVAL);

	THREAD_LIST_LOCK(curthread);
	if ((rval = _thr_find_thread(curthread, pthread,
			/*include dead*/1)) != 0) {
		THREAD_LIST_UNLOCK(curthread);
		return (rval);
	}

	/* Check if the thread is already detached or has a joiner. */
	if ((pthread->tlflags & TLFLAGS_DETACHED) != 0 ||
	    (pthread->joiner != NULL)) {
		THREAD_LIST_UNLOCK(curthread);
		return (EINVAL);
	}

	/* Flag the thread as detached. */
	pthread->tlflags |= TLFLAGS_DETACHED;
	if (pthread->state == PS_DEAD)
		THR_GCLIST_ADD(pthread);
	THREAD_LIST_UNLOCK(curthread);

	return (0);
}
예제 #4
0
/*
 * Set a thread's scheduling parameters, this should be done
 * in kernel, doing it in userland is no-op.
 */
int
_pthread_setschedparam(pthread_t pthread, int policy, 
	const struct sched_param *param)
{
	struct pthread	*curthread = _get_curthread();
	int	ret;

	if (pthread == curthread)
		THR_LOCK(curthread);
	else if ((ret = _thr_find_thread(curthread, pthread,
		 /*include dead*/0)) != 0)
		return (ret);
	if (pthread->attr.sched_policy == policy &&
	    (policy == SCHED_OTHER ||
	     pthread->attr.prio == param->sched_priority)) {
		pthread->attr.prio = param->sched_priority;
		THR_THREAD_UNLOCK(curthread, pthread);
		return (0);
	}
	ret = _thr_setscheduler(pthread->tid, policy, param);
	if (ret == -1)
		ret = errno;
	else {
		pthread->attr.sched_policy = policy;
		pthread->attr.prio = param->sched_priority;
	}
	THR_THREAD_UNLOCK(curthread, pthread);
	return (ret);
}
예제 #5
0
int
_pthread_kill(pthread_t pthread, int sig)
{
	struct pthread *curthread;
	int ret;

	/* Check for invalid signal numbers: */
	if (sig < 0 || sig > _SIG_MAXSIG)
		/* Invalid signal: */
		return (EINVAL);

	curthread = _get_curthread();

	/*
	 * Ensure the thread is in the list of active threads, and the
	 * signal is valid (signal 0 specifies error checking only) and
	 * not being ignored:
	 */
	if (curthread == pthread) {
		if (sig > 0)
			_thr_send_sig(pthread, sig);
		ret = 0;
	} else if ((ret = _thr_find_thread(curthread, pthread,
	    /*include dead*/0)) == 0) {
		if (sig > 0)
			_thr_send_sig(pthread, sig);
		THR_THREAD_UNLOCK(curthread, pthread);
	}

	/* Return the completion status: */
	return (ret);
}
예제 #6
0
int
_pthread_cancel(pthread_t pthread)
{
	struct pthread *curthread = _get_curthread();
	int ret;

	/*
	 * POSIX says _pthread_cancel should be async cancellation safe.
	 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical
	 * region automatically.
	 */
	if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) {
		if (!pthread->cancel_pending) {
			pthread->cancel_pending = 1;
			if (pthread->state != PS_DEAD)
				_thr_send_sig(pthread, SIGCANCEL);
		}
		THR_THREAD_UNLOCK(curthread, pthread);
	}
	return (ret);
}
예제 #7
0
int
_pthread_getaffinity_np(pthread_t td, size_t cpusetsize, cpuset_t *cpusetp)
{
	struct pthread	*curthread = _get_curthread();
	lwpid_t tid;
	int error;

	if (td == curthread) {
		error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
			-1, cpusetsize, cpusetp);
		if (error == -1)
			error = errno;
	} else if ((error = _thr_find_thread(curthread, td, 0)) == 0) {
		tid = TID(td);
		error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, tid,
			    cpusetsize, cpusetp);
		if (error == -1)
			error = errno;
		THR_THREAD_UNLOCK(curthread, td);
	}
	return (error);
}
예제 #8
0
int
_pthread_getschedparam(pthread_t pthread, int *policy, 
	struct sched_param *param)
{
	struct pthread *curthread = _get_curthread();
	int ret = 0;

	if (policy == NULL || param == NULL)
		return (EINVAL);

	/*
	 * Avoid searching the thread list when it is the current
	 * thread.
	 */
	if (pthread == curthread)
		THR_LOCK(curthread);
	else if ((ret = _thr_find_thread(curthread, pthread, /*include dead*/0)))
		return (ret);
	*policy = pthread->attr.sched_policy;
	param->sched_priority = pthread->attr.prio;
	THR_THREAD_UNLOCK(curthread, pthread);
	return (ret);
}
예제 #9
0
/* Set the thread name for debug. */
void
_pthread_set_name_np(pthread_t thread, const char *name)
{
	struct pthread *curthread = _get_curthread();
	int ret = 0;

	if (curthread == thread) {
		if (thr_set_name(thread->tid, name))
			ret = errno;
	} else {
		if ((ret=_thr_find_thread(curthread, thread, 0)) == 0) {
			if (thread->state != PS_DEAD) {
				if (thr_set_name(thread->tid, name))
					ret = errno;
			}
			THR_THREAD_UNLOCK(curthread, thread);
		}
	}
#if 0
	/* XXX should return error code. */
	return (ret);
#endif
}
예제 #10
0
static int
join_common(pthread_t pthread, void **thread_return,
	const struct timespec *abstime)
{
	struct pthread *curthread = tls_get_curthread();
	struct timespec ts, ts2, *tsp;
	void *tmp;
	long state;
	int oldcancel;
	int ret = 0;
 
	if (pthread == NULL)
		return (EINVAL);

	if (pthread == curthread)
		return (EDEADLK);

	THREAD_LIST_LOCK(curthread);
	if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) {
		ret = ESRCH;
	} else if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) {
		ret = ESRCH;
	} else if (pthread->joiner != NULL) {
		/* Multiple joiners are not supported. */
		ret = ENOTSUP;
	}
	if (ret) {
		THREAD_LIST_UNLOCK(curthread);
		return (ret);
	}
	/* Set the running thread to be the joiner: */
	pthread->joiner = curthread;

	THREAD_LIST_UNLOCK(curthread);

	THR_CLEANUP_PUSH(curthread, backout_join, pthread);
	oldcancel = _thr_cancel_enter(curthread);

	while ((state = pthread->state) != PS_DEAD) {
		if (abstime != NULL) {
			clock_gettime(CLOCK_REALTIME, &ts);
			TIMESPEC_SUB(&ts2, abstime, &ts);
			if (ts2.tv_sec < 0) {
				ret = ETIMEDOUT;
				break;
			}
			tsp = &ts2;
		} else
			tsp = NULL;
		ret = _thr_umtx_wait(&pthread->state, state, tsp,
			 CLOCK_REALTIME);
		if (ret == ETIMEDOUT)
			break;
	}

	_thr_cancel_leave(curthread, oldcancel);
	THR_CLEANUP_POP(curthread, 0);

	if (ret == ETIMEDOUT) {
		THREAD_LIST_LOCK(curthread);
		pthread->joiner = NULL;
		THREAD_LIST_UNLOCK(curthread);
	} else {
		ret = 0;
		tmp = pthread->ret;
		THREAD_LIST_LOCK(curthread);
		pthread->tlflags |= TLFLAGS_DETACHED;
		pthread->joiner = NULL;
		THR_GCLIST_ADD(pthread);
		THREAD_LIST_UNLOCK(curthread);

		if (thread_return != NULL)
			*thread_return = tmp;
	}
	return (ret);
}
예제 #11
0
/*
 * Cancellation behavior:
 *   if the thread is canceled, joinee is not recycled.
 */
static int
join_common(pthread_t pthread, void **thread_return,
	const struct timespec *abstime)
{
	struct pthread *curthread = _get_curthread();
	struct timespec ts, ts2, *tsp;
	void *tmp;
	long tid;
	int ret = 0;

	if (pthread == NULL)
		return (EINVAL);

	if (pthread == curthread)
		return (EDEADLK);

	if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0)
		return (ESRCH);

	if ((pthread->flags & THR_FLAGS_DETACHED) != 0) {
		ret = EINVAL;
	} else if (pthread->joiner != NULL) {
		/* Multiple joiners are not supported. */
		ret = ENOTSUP;
	}
	if (ret) {
		THR_THREAD_UNLOCK(curthread, pthread);
		return (ret);
	}
	/* Set the running thread to be the joiner: */
	pthread->joiner = curthread;

	THR_THREAD_UNLOCK(curthread, pthread);

	THR_CLEANUP_PUSH(curthread, backout_join, pthread);
	_thr_cancel_enter(curthread);

	tid = pthread->tid;
	while (pthread->tid != TID_TERMINATED) {
		_thr_testcancel(curthread);
		if (abstime != NULL) {
			clock_gettime(CLOCK_REALTIME, &ts);
			TIMESPEC_SUB(&ts2, abstime, &ts);
			if (ts2.tv_sec < 0) {
				ret = ETIMEDOUT;
				break;
			}
			tsp = &ts2;
		} else
			tsp = NULL;
		ret = _thr_umtx_wait(&pthread->tid, tid, tsp);
		if (ret == ETIMEDOUT)
			break;
	}

	_thr_cancel_leave(curthread, 0);
	THR_CLEANUP_POP(curthread, 0);

	if (ret == ETIMEDOUT) {
		THR_THREAD_LOCK(curthread, pthread);
		pthread->joiner = NULL;
		THR_THREAD_UNLOCK(curthread, pthread);
	} else {
		ret = 0;
		tmp = pthread->ret;
		THR_THREAD_LOCK(curthread, pthread);
		pthread->flags |= THR_FLAGS_DETACHED;
		pthread->joiner = NULL;
		_thr_try_gc(curthread, pthread); /* thread lock released */

		if (thread_return != NULL)
			*thread_return = tmp;
	}
	return (ret);
}