Пример #1
0
int
_pthread_getschedparam(pthread_t pthread, int *policy, 
	struct sched_param *param)
{
	struct pthread *curthread = _get_curthread();
	int ret;

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

	if (pthread == curthread) {
		/*
		 * Avoid searching the thread list when it is the current
		 * thread.
		 */
		THR_LOCK(curthread);
		*policy = curthread->attr.sched_policy;
		param->sched_priority = curthread->attr.prio;
		THR_UNLOCK(curthread);
		ret = 0;
	}
	/* Find the thread in the list of active threads. */
	else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
	    == 0) {
		THR_THREAD_LOCK(curthread, pthread);
		*policy = pthread->attr.sched_policy;
		param->sched_priority = pthread->attr.prio;
		THR_THREAD_UNLOCK(curthread, pthread);
		_thr_ref_delete(curthread, pthread);
	}
	return (ret);
}
Пример #2
0
void
_thr_cancel_enter(struct pthread *thread)
{
	/* Look for a cancellation before we block: */
	THR_THREAD_LOCK(thread, thread);
	testcancel(thread);
	thread->cancelflags |= THR_AT_CANCEL_POINT;
	THR_THREAD_UNLOCK(thread, thread);
}
Пример #3
0
void
_pthread_testcancel(void)
{
	struct pthread	*curthread = _get_curthread();

	THR_THREAD_LOCK(curthread, curthread);
	testcancel(curthread);
	THR_THREAD_UNLOCK(curthread, curthread);
}
Пример #4
0
static void backout_join(void *arg)
{
	struct pthread *pthread = (struct pthread *)arg;
	struct pthread *curthread = _get_curthread();

	THR_THREAD_LOCK(curthread, pthread);
	pthread->joiner = NULL;
	THR_THREAD_UNLOCK(curthread, pthread);
}
Пример #5
0
void
_thr_cancel_leave(struct pthread *thread, int check)
{
	THR_THREAD_LOCK(thread, thread);
	thread->cancelflags &= ~THR_AT_CANCEL_POINT;
	/* Look for a cancellation after we unblock: */
	if (check)
		testcancel(thread);
	THR_THREAD_UNLOCK(thread, thread);
}
Пример #6
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);
		}
	}
}
Пример #7
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);
}
Пример #8
0
int
_pthread_cancel(pthread_t pthread)
{
	struct pthread *curthread = _get_curthread();
	struct pthread *joinee = NULL;
	struct kse_mailbox *kmbx = NULL;
	int ret;

	if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) {
		/*
		 * Take the thread's lock while we change the cancel flags.
		 */
		THR_THREAD_LOCK(curthread, pthread);
		THR_SCHED_LOCK(curthread, pthread);
		if (pthread->flags & THR_FLAGS_EXITING) {
			THR_SCHED_UNLOCK(curthread, pthread);
			THR_THREAD_UNLOCK(curthread, pthread);
			_thr_ref_delete(curthread, pthread);
			return (ESRCH);
		}
		if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
		    (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
		    ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)))
			/* Just mark it for cancellation: */
			pthread->cancelflags |= THR_CANCELLING;
		else {
			/*
			 * Check if we need to kick it back into the
			 * run queue:
			 */
			switch (pthread->state) {
			case PS_RUNNING:
				/* No need to resume: */
				pthread->cancelflags |= THR_CANCELLING;
				break;

			case PS_LOCKWAIT:
				/*
				 * These can't be removed from the queue.
				 * Just mark it as cancelling and tell it
				 * to yield once it leaves the critical
				 * region.
				 */
				pthread->cancelflags |= THR_CANCELLING;
				pthread->critical_yield = 1;
				break;

			case PS_SLEEP_WAIT:
			case PS_SIGSUSPEND:
			case PS_SIGWAIT:
				/* Interrupt and resume: */
				pthread->interrupted = 1;
				pthread->cancelflags |= THR_CANCELLING;
				kmbx = _thr_setrunnable_unlocked(pthread);
				break;

			case PS_JOIN:
				/* Disconnect the thread from the joinee: */
				joinee = pthread->join_status.thread;
				pthread->join_status.thread = NULL;
				pthread->cancelflags |= THR_CANCELLING;
				kmbx = _thr_setrunnable_unlocked(pthread);
				if ((joinee != NULL) &&
				    (pthread->kseg == joinee->kseg)) {
					/* Remove the joiner from the joinee. */
					joinee->joiner = NULL;
					joinee = NULL;
				}
				break;

			case PS_SUSPENDED:
			case PS_MUTEX_WAIT:
			case PS_COND_WAIT:
				/*
				 * Threads in these states may be in queues.
				 * In order to preserve queue integrity, the
				 * cancelled thread must remove itself from the
				 * queue.  Mark the thread as interrupted and
				 * needing cancellation, and set the state to
				 * running.  When the thread resumes, it will
				 * remove itself from the queue and call the
				 * cancellation completion routine.
				 */
				pthread->interrupted = 1;
				pthread->cancelflags |= THR_CANCEL_NEEDED;
				kmbx = _thr_setrunnable_unlocked(pthread);
				pthread->continuation =
					_thr_finish_cancellation;
				break;

			case PS_DEAD:
			case PS_DEADLOCK:
			case PS_STATE_MAX:
				/* Ignore - only here to silence -Wall: */
				break;
			}
			if ((pthread->cancelflags & THR_AT_CANCEL_POINT) &&
			    (pthread->blocked != 0 ||
			     pthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
				kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
					KSE_INTR_INTERRUPT, 0);
		}

		/*
		 * Release the thread's lock and remove the
		 * reference:
		 */
		THR_SCHED_UNLOCK(curthread, pthread);
		THR_THREAD_UNLOCK(curthread, pthread);
		_thr_ref_delete(curthread, pthread);
		if (kmbx != NULL)
			kse_wakeup(kmbx);

		if ((joinee != NULL) &&
		    (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) {
			/* Remove the joiner from the joinee. */
			THR_SCHED_LOCK(curthread, joinee);
			joinee->joiner = NULL;
			THR_SCHED_UNLOCK(curthread, joinee);
			_thr_ref_delete(curthread, joinee);
		}
	}
	return (ret);
}
Пример #9
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);
}
Пример #10
0
int
_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
	       void *(*start_routine) (void *), void *arg)
{
	struct pthread *curthread, *new_thread;
	struct thr_param param;
	struct sched_param sched_param;
	struct rtprio rtp;
	sigset_t set, oset;
	cpuset_t *cpusetp;
	int i, cpusetsize, create_suspended, locked, old_stack_prot, ret;

	cpusetp = NULL;
	ret = cpusetsize = 0;
	_thr_check_init();

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

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

	memset(&param, 0, sizeof(param));

	if (attr == NULL || *attr == NULL)
		/* Use the default thread attributes: */
		new_thread->attr = _pthread_attr_default;
	else {
		new_thread->attr = *(*attr);
		cpusetp = new_thread->attr.cpuset;
		cpusetsize = new_thread->attr.cpusetsize;
		new_thread->attr.cpuset = NULL;
		new_thread->attr.cpusetsize = 0;
	}
	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;

		new_thread->attr.prio = curthread->attr.prio;
		new_thread->attr.sched_policy = curthread->attr.sched_policy;
	}

	new_thread->tid = TID_TERMINATED;

	old_stack_prot = _rtld_get_stack_prot();
	if (create_stack(&new_thread->attr) != 0) {
		/* Insufficient memory to create a stack: */
		_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->cancel_enable = 1;
	new_thread->cancel_async = 0;
	/* Initialize the mutex queue: */
	for (i = 0; i < TMQ_NITEMS; i++)
		TAILQ_INIT(&new_thread->mq[i]);

	/* Initialise hooks in the thread structure: */
	if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
		new_thread->flags = THR_FLAGS_NEED_SUSPEND;
		create_suspended = 1;
	} else {
		create_suspended = 0;
	}

	new_thread->state = PS_RUNNING;

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

	/* Add the new thread. */
	new_thread->refcount = 1;
	_thr_link(curthread, new_thread);

	/*
	 * Handle the race between __pthread_map_stacks_exec and
	 * thread linkage.
	 */
	if (old_stack_prot != _rtld_get_stack_prot())
		_thr_stack_fix_protection(new_thread);

	/* Return thread pointer eariler so that new thread can use it. */
	(*thread) = new_thread;
	if (SHOULD_REPORT_EVENT(curthread, TD_CREATE) || cpusetp != NULL) {
		THR_THREAD_LOCK(curthread, new_thread);
		locked = 1;
	} else
		locked = 0;
	param.start_func = (void (*)(void *)) thread_start;
	param.arg = new_thread;
	param.stack_base = new_thread->attr.stackaddr_attr;
	param.stack_size = new_thread->attr.stacksize_attr;
	param.tls_base = (char *)new_thread->tcb;
	param.tls_size = sizeof(struct tcb);
	param.child_tid = &new_thread->tid;
	param.parent_tid = &new_thread->tid;
	param.flags = 0;
	if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM)
		param.flags |= THR_SYSTEM_SCOPE;
	if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED)
		param.rtp = NULL;
	else {
		sched_param.sched_priority = new_thread->attr.prio;
		_schedparam_to_rtp(new_thread->attr.sched_policy,
			&sched_param, &rtp);
		param.rtp = &rtp;
	}

	/* Schedule the new thread. */
	if (create_suspended) {
		SIGFILLSET(set);
		SIGDELSET(set, SIGTRAP);
		__sys_sigprocmask(SIG_SETMASK, &set, &oset);
		new_thread->sigmask = oset;
		SIGDELSET(new_thread->sigmask, SIGCANCEL);
	}

	ret = thr_new(&param, sizeof(param));

	if (ret != 0) {
		ret = errno;
		/*
		 * Translate EPROCLIM into well-known POSIX code EAGAIN.
		 */
		if (ret == EPROCLIM)
			ret = EAGAIN;
	}

	if (create_suspended)
		__sys_sigprocmask(SIG_SETMASK, &oset, NULL);

	if (ret != 0) {
		if (!locked)
			THR_THREAD_LOCK(curthread, new_thread);
		new_thread->state = PS_DEAD;
		new_thread->tid = TID_TERMINATED;
		new_thread->flags |= THR_FLAGS_DETACHED;
		new_thread->refcount--;
		if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) {
			new_thread->cycle++;
			_thr_umtx_wake(&new_thread->cycle, INT_MAX, 0);
		}
		_thr_try_gc(curthread, new_thread); /* thread lock released */
		atomic_add_int(&_thread_active_threads, -1);
	} else if (locked) {
		if (cpusetp != NULL) {
			if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
				TID(new_thread), cpusetsize, cpusetp)) {
				ret = errno;
				/* kill the new thread */
				new_thread->force_exit = 1;
				new_thread->flags |= THR_FLAGS_DETACHED;
				_thr_try_gc(curthread, new_thread);
				 /* thread lock released */
				goto out;
			}
		}

		_thr_report_creation(curthread, new_thread);
		THR_THREAD_UNLOCK(curthread, new_thread);
	}
out:
	if (ret)
		(*thread) = 0;
	return (ret);
}
Пример #11
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);
}