144963Sjb/*
244963Sjb * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>.
344963Sjb * All rights reserved.
444963Sjb *
544963Sjb * Redistribution and use in source and binary forms, with or without
644963Sjb * modification, are permitted provided that the following conditions
744963Sjb * are met:
844963Sjb * 1. Redistributions of source code must retain the above copyright
944963Sjb *    notice, this list of conditions and the following disclaimer.
1044963Sjb * 2. Redistributions in binary form must reproduce the above copyright
1144963Sjb *    notice, this list of conditions and the following disclaimer in the
1244963Sjb *    documentation and/or other materials provided with the distribution.
1344963Sjb * 3. All advertising materials mentioning features or use of this software
1444963Sjb *    must display the following acknowledgement:
1544963Sjb *	This product includes software developed by Daniel Eischen.
1644963Sjb * 4. Neither the name of the author nor the names of any co-contributors
1744963Sjb *    may be used to endorse or promote products derived from this software
1844963Sjb *    without specific prior written permission.
1944963Sjb *
2044963Sjb * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
2144963Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2244963Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2344963Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2444963Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2544963Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2644963Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2744963Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2844963Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2944963Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3044963Sjb * SUCH DAMAGE.
3144963Sjb *
3250476Speter * $FreeBSD$
3344963Sjb */
34174112Sdeischen
35174112Sdeischen#include "namespace.h"
3644963Sjb#include <errno.h>
3744963Sjb#include <sys/param.h>
3844963Sjb#include <pthread.h>
39174112Sdeischen#include "un-namespace.h"
40103388Smini#include "thr_private.h"
4144963Sjb
4275369Sdeischen__weak_reference(_pthread_setschedparam, pthread_setschedparam);
4371581Sdeischen
4444963Sjbint
4571581Sdeischen_pthread_setschedparam(pthread_t pthread, int policy,
4653812Salfred	const struct sched_param *param)
4744963Sjb{
48113658Sdeischen	struct pthread *curthread = _get_curthread();
49113658Sdeischen	int	in_syncq;
50113658Sdeischen	int	in_readyq = 0;
51113658Sdeischen	int	old_prio;
52113658Sdeischen	int	ret = 0;
5344963Sjb
5459892Sjasone	if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
5544963Sjb		/* Return an invalid argument error: */
5644963Sjb		ret = EINVAL;
57113658Sdeischen	} else if ((param->sched_priority < THR_MIN_PRIORITY) ||
58113658Sdeischen	    (param->sched_priority > THR_MAX_PRIORITY)) {
5959892Sjasone		/* Return an unsupported value error. */
6059892Sjasone		ret = ENOTSUP;
6144963Sjb
6244963Sjb	/* Find the thread in the list of active threads: */
63113658Sdeischen	} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
64113658Sdeischen	    == 0) {
6544963Sjb		/*
66113658Sdeischen		 * Lock the threads scheduling queue while we change
67113658Sdeischen		 * its priority:
6844963Sjb		 */
69113658Sdeischen		THR_SCHED_LOCK(curthread, pthread);
70113661Sdeischen		if ((pthread->state == PS_DEAD) ||
71113661Sdeischen		    (pthread->state == PS_DEADLOCK) ||
72113661Sdeischen		    ((pthread->flags & THR_FLAGS_EXITING) != 0)) {
73113661Sdeischen			THR_SCHED_UNLOCK(curthread, pthread);
74113661Sdeischen			_thr_ref_delete(curthread, pthread);
75113661Sdeischen			return (ESRCH);
76113661Sdeischen		}
77113786Sdeischen		in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ;
7844963Sjb
79113658Sdeischen		/* Set the scheduling policy: */
80113658Sdeischen		pthread->attr.sched_policy = policy;
81113658Sdeischen
82113658Sdeischen		if (param->sched_priority ==
83113658Sdeischen		    THR_BASE_PRIORITY(pthread->base_priority))
8444963Sjb			/*
85113658Sdeischen			 * There is nothing to do; unlock the threads
86113658Sdeischen			 * scheduling queue.
87113658Sdeischen			 */
88113658Sdeischen			THR_SCHED_UNLOCK(curthread, pthread);
89113658Sdeischen		else {
90113658Sdeischen			/*
9144963Sjb			 * Remove the thread from its current priority
9244963Sjb			 * queue before any adjustments are made to its
9344963Sjb			 * active priority:
9444963Sjb			 */
9555194Sdeischen			old_prio = pthread->active_priority;
96113658Sdeischen			if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) {
9744963Sjb				in_readyq = 1;
98113658Sdeischen				THR_RUNQ_REMOVE(pthread);
9944963Sjb			}
10044963Sjb
10144963Sjb			/* Set the thread base priority: */
10267097Sdeischen			pthread->base_priority &=
103113658Sdeischen			    (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY);
10444963Sjb			pthread->base_priority = param->sched_priority;
10544963Sjb
10644963Sjb			/* Recalculate the active priority: */
10744963Sjb			pthread->active_priority = MAX(pthread->base_priority,
10844963Sjb			    pthread->inherited_priority);
10944963Sjb
11044963Sjb			if (in_readyq) {
11144963Sjb				if ((pthread->priority_mutex_count > 0) &&
11244963Sjb				    (old_prio > pthread->active_priority)) {
11344963Sjb					/*
11444963Sjb					 * POSIX states that if the priority is
11544963Sjb					 * being lowered, the thread must be
11644963Sjb					 * inserted at the head of the queue for
11744963Sjb					 * its priority if it owns any priority
11844963Sjb					 * protection or inheritence mutexes.
11944963Sjb					 */
120113658Sdeischen					THR_RUNQ_INSERT_HEAD(pthread);
12144963Sjb				}
12244963Sjb				else
123113658Sdeischen					THR_RUNQ_INSERT_TAIL(pthread);
12444963Sjb			}
12544963Sjb
126113658Sdeischen			/* Unlock the threads scheduling queue: */
127113658Sdeischen			THR_SCHED_UNLOCK(curthread, pthread);
128113658Sdeischen
12944963Sjb			/*
13044963Sjb			 * Check for any mutex priority adjustments.  This
13144963Sjb			 * includes checking for a priority mutex on which
13244963Sjb			 * this thread is waiting.
13344963Sjb			 */
134113658Sdeischen			_mutex_notify_priochange(curthread, pthread, in_syncq);
13544963Sjb		}
136113658Sdeischen		_thr_ref_delete(curthread, pthread);
13744963Sjb	}
138113658Sdeischen	return (ret);
13944963Sjb}
140