Beispiel #1
0
int
_pthread_cancel(pthread_t pthread)
{
	struct pthread *curthread = tls_get_curthread();
	int oldval, newval = 0;
	int oldtype;
	int ret;

	/*
	 * POSIX says _pthread_cancel should be async cancellation safe,
	 * so we temporarily disable async cancellation.
	 */
	_pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
	if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0) {
		_pthread_setcanceltype(oldtype, NULL);
		return (ret);
	}

	do {
		oldval = pthread->cancelflags;
		if (oldval & THR_CANCEL_NEEDED)
			break;
		newval = oldval | THR_CANCEL_NEEDED;
	} while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval));

	if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval))
		_thr_send_sig(pthread, SIGCANCEL);

	_thr_ref_delete(curthread, pthread);
	_pthread_setcanceltype(oldtype, NULL);
	return (0);
}
Beispiel #2
0
int
_pthread_setcanceltype(int type, int *oldtype)
{
	struct pthread	*curthread = tls_get_curthread();
	int oldval;

	oldval = curthread->cancelflags;
	if (oldtype != NULL)
		*oldtype = ((oldval & THR_CANCEL_AT_POINT) ?
				 PTHREAD_CANCEL_ASYNCHRONOUS :
				 PTHREAD_CANCEL_DEFERRED);
	switch (type) {
	case PTHREAD_CANCEL_ASYNCHRONOUS:
		atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
		testcancel(curthread);
		break;
	case PTHREAD_CANCEL_DEFERRED:
		atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
		break;
	default:
		return (EINVAL);
	}

	return (0);
}
Beispiel #3
0
int
_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
{
	struct pthread *curthread = tls_get_curthread();
	int i;

	/* Lock the key table: */
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
	for (i = 0; i < PTHREAD_KEYS_MAX; i++) {

		if (_thread_keytable[i].allocated == 0) {
			_thread_keytable[i].allocated = 1;
			_thread_keytable[i].destructor = destructor;
			_thread_keytable[i].seqno++;

			/* Unlock the key table: */
			THR_LOCK_RELEASE(curthread, &_keytable_lock);
			*key = i;
			return (0);
		}

	}
	/* Unlock the key table: */
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
	return (EAGAIN);
}
Beispiel #4
0
void *
_pthread_getspecific(pthread_key_t key)
{
	struct pthread	*pthread;
	const void	*data;

	/* Point to the running thread: */
	pthread = tls_get_curthread();

	/* Check if there is specific data: */
	if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
		/* Check if this key has been used before: */
		if (_thread_keytable[key].allocated &&
		    (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
			/* Return the value: */
			data = pthread->specific[key].data;
		} else {
			/*
			 * This key has not been used before, so return NULL
			 * instead: 
			 */
			data = NULL;
		}
	} else
		/* No specific data has been created, so just return NULL: */
		data = NULL;
	return __DECONST(void *, data);
}
Beispiel #5
0
int 
_pthread_setspecific(pthread_key_t key, const void *value)
{
	struct pthread	*pthread;
	int		ret = 0;

	/* Point to the running thread: */
	pthread = tls_get_curthread();

	if ((pthread->specific) ||
	    (pthread->specific = pthread_key_allocate_data())) {
		if ((unsigned int)key < PTHREAD_KEYS_MAX) {
			if (_thread_keytable[key].allocated) {
				if (pthread->specific[key].data == NULL) {
					if (value != NULL)
						pthread->specific_data_count++;
				} else if (value == NULL)
					pthread->specific_data_count--;
				pthread->specific[key].data = value;
				pthread->specific[key].seqno =
				    _thread_keytable[key].seqno;
				ret = 0;
			} else
				ret = EINVAL;
		} else
			ret = EINVAL;
	} else
		ret = ENOMEM;
	return (ret);
}
Beispiel #6
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);
}
Beispiel #7
0
static void backout_join(void *arg)
{
	struct pthread *curthread = tls_get_curthread();
	struct pthread *pthread = (struct pthread *)arg;

	THREAD_LIST_LOCK(curthread);
	pthread->joiner = NULL;
	THREAD_LIST_UNLOCK(curthread);
}
Beispiel #8
0
void 
_thread_cleanupspecific(void)
{
	struct pthread	*curthread = tls_get_curthread();
	void		(*destructor)( void *);
	const void	*data = NULL;
	int		key;
	int		i;

	if (curthread->specific == NULL)
		return;

	/* Lock the key table: */
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
	for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
	    (curthread->specific_data_count > 0); i++) {
		for (key = 0; (key < PTHREAD_KEYS_MAX) &&
		    (curthread->specific_data_count > 0); key++) {
			destructor = NULL;

			if (_thread_keytable[key].allocated &&
			    (curthread->specific[key].data != NULL)) {
				if (curthread->specific[key].seqno ==
				    _thread_keytable[key].seqno) {
					data = 
					    curthread->specific[key].data;
					destructor = _thread_keytable[key].destructor;
				}
				curthread->specific[key].data = NULL;
				curthread->specific_data_count--;
			}

			/*
			 * If there is a destructore, call it
			 * with the key table entry unlocked:
			 */
			if (destructor != NULL) {
				/*
				 * Don't hold the lock while calling the
				 * destructor:
				 */
				THR_LOCK_RELEASE(curthread, &_keytable_lock);
				destructor(__DECONST(void *, data));
				THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
			}
		}
	}
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
	free(curthread->specific);
	curthread->specific = NULL;
	if (curthread->specific_data_count > 0)
		stderr_debug("Thread %p has exited with leftover "
		    "thread-specific data after %d destructor iterations\n",
		    curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
}
Beispiel #9
0
/* Set the thread name for debug. */
void
_pthread_set_name_np(pthread_t thread, const char *name)
{
	struct pthread *curthread = tls_get_curthread();

	if (curthread == thread) {
		lwp_setname(thread->tid, name);
	} else {
		if (_thr_ref_add(curthread, thread, 0) == 0) {
			THR_THREAD_LOCK(curthread, thread);
			if (thread->state != PS_DEAD)
				lwp_setname(thread->tid, name);
			THR_THREAD_UNLOCK(curthread, thread);
			_thr_ref_delete(curthread, thread);
		}
	}
}
Beispiel #10
0
int
_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
{
	struct pthread *curthread;
	struct pthread_attr attr;
	int	ret;

	if (pid == NULL || dst == NULL || *dst == NULL)
		return (EINVAL);

	curthread = tls_get_curthread();
	if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
		return (ret);
	attr = pid->attr;
	if (pid->tlflags & TLFLAGS_DETACHED)
		attr.flags |= PTHREAD_DETACHED;
	_thr_ref_delete(curthread, pid);
	memcpy(*dst, &attr, sizeof(struct pthread_attr));

	return (0);
}
Beispiel #11
0
int
_pthread_key_delete(pthread_key_t key)
{
	struct pthread *curthread = tls_get_curthread();
	int ret = 0;

	if ((unsigned int)key < PTHREAD_KEYS_MAX) {
		/* Lock the key table: */
		THR_LOCK_ACQUIRE(curthread, &_keytable_lock);

		if (_thread_keytable[key].allocated)
			_thread_keytable[key].allocated = 0;
		else
			ret = EINVAL;

		/* Unlock the key table: */
		THR_LOCK_RELEASE(curthread, &_keytable_lock);
	} else
		ret = EINVAL;
	return (ret);
}
Beispiel #12
0
int
_pthread_setcancelstate(int state, int *oldstate)
{
	struct pthread *curthread = tls_get_curthread();
	int oldval;

	oldval = curthread->cancelflags;
	if (oldstate != NULL)
		*oldstate = ((oldval & THR_CANCEL_DISABLE) ?
		    PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
	switch (state) {
	case PTHREAD_CANCEL_DISABLE:
		atomic_set_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
		break;
	case PTHREAD_CANCEL_ENABLE:
		atomic_clear_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
		testcancel(curthread);
		break;
	default:
		return (EINVAL);
	}

	return (0);
}
Beispiel #13
0
void
_pthread_testcancel(void)
{
	testcancel(tls_get_curthread());
}
Beispiel #14
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);
}
Beispiel #15
0
pthread_t
_pthread_self(void)
{
	/* Return the running thread pointer: */
	return (tls_get_curthread());
}
Beispiel #16
0
int
_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
    void *(*start_routine) (void *), void *arg)
{
	struct lwp_params create_params;
	void *stack;
	sigset_t sigmask, oldsigmask;
	struct pthread *curthread, *new_thread;
	int ret = 0, locked;

	_thr_check_init();

	/*
	 * Tell libc and others now they need lock to protect their data.
	 */
	if (_thr_isthreaded() == 0 && _thr_setthreaded(1))
		return (EAGAIN);

	curthread = tls_get_curthread();
	if ((new_thread = _thr_alloc(curthread)) == NULL)
		return (EAGAIN);

	if (attr == NULL || *attr == NULL) {
		/* Use the default thread attributes: */
		new_thread->attr = _pthread_attr_default;
	} else {
		new_thread->attr = *(*attr);
	}
	if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
		/* inherit scheduling contention scope */
		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
			new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
		else
			new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
		/*
		 * scheduling policy and scheduling parameters will be
		 * inherited in following code.
		 */
	}

	if (create_stack(&new_thread->attr) != 0) {
		/* Insufficient memory to create a stack: */
		new_thread->terminated = 1;
		_thr_free(curthread, new_thread);
		return (EAGAIN);
	}
	/*
	 * Write a magic value to the thread structure
	 * to help identify valid ones:
	 */
	new_thread->magic = THR_MAGIC;
	new_thread->start_routine = start_routine;
	new_thread->arg = arg;
	new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
	    PTHREAD_CANCEL_DEFERRED;
	/*
	 * Check if this thread is to inherit the scheduling
	 * attributes from its parent:
	 */
	if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
		/*
		 * Copy the scheduling attributes. Lock the scheduling
		 * lock to get consistent scheduling parameters.
		 */
		THR_LOCK(curthread);
		new_thread->base_priority = curthread->base_priority;
		new_thread->attr.prio = curthread->attr.prio;
		new_thread->attr.sched_policy = curthread->attr.sched_policy;
		THR_UNLOCK(curthread);
	} else {
		/*
		 * Use just the thread priority, leaving the
		 * other scheduling attributes as their
		 * default values:
		 */
		new_thread->base_priority = new_thread->attr.prio;
	}
	new_thread->active_priority = new_thread->base_priority;

	/* Initialize the mutex queue: */
	TAILQ_INIT(&new_thread->mutexq);

	/* Initialise hooks in the thread structure: */
	if (new_thread->attr.suspend == THR_CREATE_SUSPENDED)
		new_thread->flags = THR_FLAGS_NEED_SUSPEND;

	new_thread->state = PS_RUNNING;

	if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED)
		new_thread->tlflags |= TLFLAGS_DETACHED;

	/* Add the new thread. */
	new_thread->refcount = 1;
	_thr_link(curthread, new_thread);
	/* Return thread pointer eariler so that new thread can use it. */
	(*thread) = new_thread;
	if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) {
		THR_THREAD_LOCK(curthread, new_thread);
		locked = 1;
	} else
		locked = 0;
	/* Schedule the new thread. */
	stack = (char *)new_thread->attr.stackaddr_attr +
			new_thread->attr.stacksize_attr;
	bzero(&create_params, sizeof(create_params));
	create_params.lwp_func = thread_start;
	create_params.lwp_arg = new_thread;
	create_params.lwp_stack = stack;
	create_params.lwp_tid1 = &new_thread->tid;
	/*
	 * Thread created by thr_create() inherits currrent thread
	 * sigmask, however, before new thread setup itself correctly,
	 * it can not handle signal, so we should mask all signals here.
	 * We do this at the very last moment, so that we don't run
	 * into problems while we have all signals disabled.
	 */
	SIGFILLSET(sigmask);
	__sys_sigprocmask(SIG_SETMASK, &sigmask, &oldsigmask);
	new_thread->sigmask = oldsigmask;
	ret = lwp_create(&create_params);
	__sys_sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
	if (ret != 0) {
		if (!locked)
			THR_THREAD_LOCK(curthread, new_thread);
		new_thread->state = PS_DEAD;
		new_thread->terminated = 1;
		if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) {
			new_thread->cycle++;
			_thr_umtx_wake(&new_thread->cycle, INT_MAX);
		}
		THR_THREAD_UNLOCK(curthread, new_thread);
		THREAD_LIST_LOCK(curthread);
		_thread_active_threads--;
		new_thread->tlflags |= TLFLAGS_DETACHED;
		_thr_ref_delete_unlocked(curthread, new_thread);
		THREAD_LIST_UNLOCK(curthread);
		(*thread) = NULL;
		ret = EAGAIN;
	} else if (locked) {
		_thr_report_creation(curthread, new_thread);
		THR_THREAD_UNLOCK(curthread, new_thread);
	}
	return (ret);
}
Beispiel #17
0
#ifdef DEBUG_SIGNAL
#define DBG_MSG		stdout_debug
#else
#define DBG_MSG(x...)
#endif

int	__sigwait(const sigset_t *set, int *sig);
int	__sigwaitinfo(const sigset_t *set, siginfo_t *info);
int	__sigtimedwait(const sigset_t *set, siginfo_t *info,
		const struct timespec * timeout);

static void
sigcancel_handler(int sig __unused, siginfo_t *info __unused,
	ucontext_t *ucp __unused)
{
	struct pthread *curthread = tls_get_curthread();

	if (curthread->cancelflags & THR_CANCEL_AT_POINT)
		_pthread_testcancel();
	_thr_ast(curthread);
}

void
_thr_ast(struct pthread *curthread)
{
	if (!THR_IN_CRITICAL(curthread)) {
		if (__predict_false((curthread->flags &
		    (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
			== THR_FLAGS_NEED_SUSPEND))
			_thr_suspend_check(curthread);
	}