diff options
Diffstat (limited to 'lib/libthr/thread/thr_setschedparam.c')
| -rw-r--r-- | lib/libthr/thread/thr_setschedparam.c | 153 | 
1 files changed, 83 insertions, 70 deletions
diff --git a/lib/libthr/thread/thr_setschedparam.c b/lib/libthr/thread/thr_setschedparam.c index fff1abf05370..4f0a60d3ef5e 100644 --- a/lib/libthr/thread/thr_setschedparam.c +++ b/lib/libthr/thread/thr_setschedparam.c @@ -31,93 +31,106 @@   *   * $FreeBSD$   */ +  #include <errno.h>  #include <sys/param.h>  #include <pthread.h> -#include <stdlib.h> +  #include "thr_private.h" -__weak_reference(_pthread_getschedparam, pthread_getschedparam);  __weak_reference(_pthread_setschedparam, pthread_setschedparam);  int -_pthread_getschedparam(pthread_t pthread, int *policy,  -    struct sched_param *param) -{ -	if (param == NULL || policy == NULL) -		return (EINVAL); -	if (_find_thread(pthread) == ESRCH) -		return (ESRCH); -	param->sched_priority = pthread->base_priority; -	*policy = pthread->attr.sched_policy; -	return(0); -} - -int  _pthread_setschedparam(pthread_t pthread, int policy,   	const struct sched_param *param)  { -	struct pthread_mutex *mtx; -	int old_prio; +	struct pthread *curthread = _get_curthread(); +	int	in_syncq; +	int	in_readyq = 0; +	int	old_prio; +	int	ret = 0; -	mtx = NULL; -	old_prio = 0; -	if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) -		return (EINVAL); -	if ((param->sched_priority < PTHREAD_MIN_PRIORITY) || -	    (param->sched_priority > PTHREAD_MAX_PRIORITY)) -		return (ENOTSUP); -	if (_find_thread(pthread) != 0) -		return (ESRCH); - -	/* -	 * If the pthread is waiting on a mutex grab it now. Doing it now -	 * even though we do not need it immediately greatly simplifies the -	 * LOR avoidance code. -	 */ -	do { -		PTHREAD_LOCK(pthread); -		if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) { -			mtx = pthread->data.mutex; -			if (_spintrylock(&mtx->lock) == EBUSY) -				PTHREAD_UNLOCK(pthread); -			else -				break; -		} else { -			mtx = NULL; -			break; -		} -	} while (1); +	if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) { +		/* Return an invalid argument error: */ +		ret = EINVAL; +	} else if ((param->sched_priority < THR_MIN_PRIORITY) || +	    (param->sched_priority > THR_MAX_PRIORITY)) { +		/* Return an unsupported value error. */ +		ret = ENOTSUP; -	PTHREAD_ASSERT(pthread->active_priority >= pthread->inherited_priority, -	    "active priority cannot be less than inherited priority"); -	old_prio = pthread->base_priority; -	pthread->base_priority = param->sched_priority; -	if (param->sched_priority <= pthread->active_priority) { +	/* Find the thread in the list of active threads: */ +	} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) +	    == 0) {  		/* -		 * Active priority is affected only if it was the -		 * base priority and the new base priority is lower. +		 * Lock the threads scheduling queue while we change +		 * its priority:  		 */ -		if (pthread->active_priority == old_prio && -		    pthread->active_priority != pthread->inherited_priority) { -			pthread->active_priority = param->sched_priority; -			readjust_priorities(pthread, mtx); +		THR_THREAD_LOCK(curthread, pthread); +		if (pthread->state == PS_DEAD) { +			THR_THREAD_UNLOCK(curthread, pthread); +			_thr_ref_delete(curthread, pthread); +			return (ESRCH);  		} +		in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ; -	} else { -		/* -		 * New base priority is greater than active priority. This -		 * only affects threads that are holding priority inheritance -		 * mutexes this thread is waiting on and its position in the -		 * queue. -		 */ -		pthread->active_priority = param->sched_priority; -		readjust_priorities(pthread, mtx); +		/* Set the scheduling policy: */ +		pthread->attr.sched_policy = policy; + +		if (param->sched_priority == +		    THR_BASE_PRIORITY(pthread->base_priority)) +			/* +			 * There is nothing to do; unlock the threads +			 * scheduling queue. +			 */ +			THR_THREAD_UNLOCK(curthread, pthread); +		else { +			/* +			 * Remove the thread from its current priority +			 * queue before any adjustments are made to its +			 * active priority: +			 */ +			old_prio = pthread->active_priority; +			/* if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) */ { +				in_readyq = 1; +				/* THR_RUNQ_REMOVE(pthread); */ +			} + +			/* Set the thread base priority: */ +			pthread->base_priority &= +			    (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY); +			pthread->base_priority = param->sched_priority; +			/* Recalculate the active priority: */ +			pthread->active_priority = MAX(pthread->base_priority, +			    pthread->inherited_priority); + +			if (in_readyq) { +				if ((pthread->priority_mutex_count > 0) && +				    (old_prio > pthread->active_priority)) { +					/* +					 * POSIX states that if the priority is +					 * being lowered, the thread must be +					 * inserted at the head of the queue for +					 * its priority if it owns any priority +					 * protection or inheritence mutexes. +					 */ +					/* THR_RUNQ_INSERT_HEAD(pthread); */ +				} +				else +					/* THR_RUNQ_INSERT_TAIL(pthread)*/ ; +			} + +			/* Unlock the threads scheduling queue: */ +			THR_THREAD_UNLOCK(curthread, pthread); + +			/* +			 * Check for any mutex priority adjustments.  This +			 * includes checking for a priority mutex on which +			 * this thread is waiting. +			 */ +			_mutex_notify_priochange(curthread, pthread, in_syncq); +		} +		_thr_ref_delete(curthread, pthread);  	} -	pthread->attr.sched_policy = policy; -	PTHREAD_UNLOCK(pthread); -	if (mtx != NULL) -		_SPINUNLOCK(&mtx->lock); -	return(0); +	return (ret);  }  | 
