cvs commit: src/lib Makefile src/lib/libpthread Makefile README dummy.c

Aggelos Economopoulos aoiko at cc.ece.ntua.gr
Mon Apr 30 05:45:07 PDT 2007


On Tuesday 17 April 2007 15:42, Simon 'corecode' Schubert wrote:
[...]
> Known issues (of libthread_xu/system):
> Mozilla stuff doesn't work.  they use sched_get_priority_min/max() and
> pthread_setsched_prio().  units disagree (former reporting -20/20, later
> expecting 0-32 or so).  this has to be streamlined somehow.
>
> Unfortunately I won't have time to do this in the next month because I am
> on tour, so I'd be grateful if somebody else could jump in.  It's not much
> work left!

The first attached patch (lwp_prio) adds a new syscall

int    lwp_rtprio (int, pid_t, lwpid_t, struct rtprio *);

that monkeys rtprio(2) and works on lwps. The other patch brings in code from 
freebsd (+ some small changes to /not/ silently accept any priority value for 
SCHED_OTHER) in libthread_xu, so that now my test program can only set 
priority values within sched_get_priority_{min,max} and smaller/larger values 
fail. The values are passed on to the kernel using lwp_rtprio() but the 
kernel side is not well tested.

Since, AFAICT lwpid can be zero lwp_rtprio() uses pid 0 for "current process" 
but lwpid -1 for "current thread", which IMO is ugly. Perhaps we should also 
reserve lwpid 0? Alternatively, I can change it to -1 for both. Then again, 
very few programs are ever going to use this. Opinions are welcome.

Don't know if this fixes thunderbird; can someone who has it linked against 
libpthread switch the symlink and test?

Aggelos
Index: kern/kern_resource.c
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.31
diff -u -u -r1.31 kern_resource.c
--- kern/kern_resource.c	3 Feb 2007 17:05:58 -0000	1.31
+++ kern/kern_resource.c	28 Apr 2007 20:24:55 -0000
@@ -261,6 +261,98 @@
 	return (0);
 }
 
+int
+sys_lwp_rtprio(struct lwp_rtprio_args *uap)
+{
+	struct proc *p = curproc;
+	struct lwp *lp;
+	struct rtprio rtp;
+	struct ucred *cr = p->p_ucred;
+	int error;
+
+	error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
+	if (error)
+		return error;
+
+	if (uap->pid < 0) {
+		return EINVAL;
+	} else if (uap->pid == 0) {
+		/* curproc already loaded on p */
+	} else {
+		p = pfind(uap->pid);
+	}
+
+	if (p == 0) {
+		return ESRCH;
+	}
+
+	if (uap->tid < -1) {
+		return EINVAL;
+	} else if (uap->tid == -1) {
+		/*
+		 * sadly, tid can be 0 so we can't use 0 here
+		 * like sys_rtprio()
+		 */
+		lp = curthread->td_lwp;
+	} else {
+		FOREACH_LWP_IN_PROC(lp, p) {
+			if (lp->lwp_tid == uap->tid) {
+				break;
+			}
+		}
+		if (!lp) {
+			return ESRCH;
+		}
+	}
+
+	switch (uap->function) {
+	case RTP_LOOKUP:
+		return (copyout(&lp->lwp_rtprio, uap->rtp,
+				sizeof(struct rtprio)));
+	case RTP_SET:
+		if (cr->cr_uid && cr->cr_ruid &&
+		    cr->cr_uid != p->p_ucred->cr_uid &&
+		    cr->cr_ruid != p->p_ucred->cr_uid) {
+			return EPERM;
+		}
+		/* disallow setting rtprio in most cases if not superuser */
+		if (suser_cred(cr, 0)) {
+			/* can't set someone else's */
+			if (uap->pid) { /* XXX */
+				return EPERM;
+			}
+			/* can't set realtime priority */
+/*
+ * Realtime priority has to be restricted for reasons which should be
+ * obvious. However, for idle priority, there is a potential for
+ * system deadlock if an idleprio process gains a lock on a resource
+ * that other processes need (and the idleprio process can't run
+ * due to a CPU-bound normal process). Fix me! XXX
+ */
+ 			if (RTP_PRIO_IS_REALTIME(rtp.type)) {
+				return EPERM;
+			}
+		}
+		switch (rtp.type) {
+#ifdef RTP_PRIO_FIFO
+		case RTP_PRIO_FIFO:
+#endif
+		case RTP_PRIO_REALTIME:
+		case RTP_PRIO_NORMAL:
+		case RTP_PRIO_IDLE:
+			if (rtp.prio > RTP_PRIO_MAX)
+				return EINVAL;
+			lp->lwp_rtprio = rtp;
+			return 0;
+		default:
+			return EINVAL;
+		}
+	default:
+		return EINVAL;
+	}
+	panic("can't get here");
+}
+
 /*
  * Set realtime priority
  */
Index: kern/syscalls.master
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/sys/kern/syscalls.master,v
retrieving revision 1.54
diff -u -u -r1.54 syscalls.master
--- kern/syscalls.master	22 Apr 2007 00:59:25 -0000	1.54
+++ kern/syscalls.master	28 Apr 2007 12:01:48 -0000
@@ -680,3 +680,4 @@
 495	STD	BSD	{ int lwp_create(struct lwp_params *params); }
 496	STD	BSD	{ lwpid_t lwp_gettid(void); }
 497	STD	BSD	{ int lwp_kill(pid_t pid, lwpid_t tid, int signum); }
+498	STD	BSD	{ int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); }
Index: sys/rtprio.h
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/sys/sys/rtprio.h,v
retrieving revision 1.5
diff -u -u -r1.5 rtprio.h
--- sys/rtprio.h	20 May 2006 02:42:13 -0000	1.5
+++ sys/rtprio.h	28 Apr 2007 17:38:22 -0000
@@ -81,6 +81,7 @@
 
 __BEGIN_DECLS
 int	rtprio (int, pid_t, struct rtprio *);
+int	lwp_rtprio (int, pid_t, lwpid_t, struct rtprio *);
 __END_DECLS
 #endif	/* !_KERNEL */
 #endif	/* !_SYS_RTPRIO_H_ */
Index: thread/thr_attr.c
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/lib/libthread_xu/thread/thr_attr.c,v
retrieving revision 1.7
diff -u -u -r1.7 thr_attr.c
--- thread/thr_attr.c	6 Apr 2006 13:03:09 -0000	1.7
+++ thread/thr_attr.c	27 Apr 2007 21:37:04 -0000
@@ -49,7 +49,6 @@
 struct pthread_attr _pthread_attr_default = {
 	.sched_policy = SCHED_OTHER,
 	.sched_inherit = 0,
-	.sched_interval = TIMESLICE_USEC,
 	.prio = THR_DEFAULT_PRIORITY,
 	.suspend = THR_CREATE_RUNNING,
 	.flags = 0,
Index: thread/thr_getschedparam.c
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/lib/libthread_xu/thread/thr_getschedparam.c,v
retrieving revision 1.4
diff -u -u -r1.4 thr_getschedparam.c
--- thread/thr_getschedparam.c	6 Apr 2006 13:03:09 -0000	1.4
+++ thread/thr_getschedparam.c	28 Apr 2007 09:46:01 -0000
@@ -46,34 +46,30 @@
 	struct sched_param *param)
 {
 	struct pthread *curthread = tls_get_curthread();
-	int ret, tmp;
+	int ret;
 
-	if ((param == NULL) || (policy == NULL))
-		/* Return an invalid argument error: */
-		ret = EINVAL;
-	else if (pthread == curthread) {
+	if (policy == NULL || param == NULL)
+		return (EINVAL);
+
+	if (pthread == curthread) {
 		/*
 		 * Avoid searching the thread list when it is the current
 		 * thread.
 		 */
-		THR_THREAD_LOCK(curthread, curthread);
-		param->sched_priority =
-		    THR_BASE_PRIORITY(pthread->base_priority);
-		tmp = pthread->attr.sched_policy;
-		THR_THREAD_UNLOCK(curthread, curthread);
-		*policy = tmp;
+		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);
-		param->sched_priority =
-		    THR_BASE_PRIORITY(pthread->base_priority);
-		tmp = pthread->attr.sched_policy;
+		*policy = pthread->attr.sched_policy;
+		param->sched_priority = pthread->attr.prio;
 		THR_THREAD_UNLOCK(curthread, pthread);
 		_thr_ref_delete(curthread, pthread);
-		*policy = tmp;
 	}
 	return (ret);
 }
Index: thread/thr_kern.c
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/lib/libthread_xu/thread/thr_kern.c,v
retrieving revision 1.2
diff -u -u -r1.2 thr_kern.c
--- thread/thr_kern.c	13 Mar 2007 00:19:29 -0000	1.2
+++ thread/thr_kern.c	30 Apr 2007 11:17:45 -0000
@@ -29,6 +29,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <sys/signalvar.h>
+#include <sys/rtprio.h>
 #include <pthread.h>
 #include "thr_private.h"
 
@@ -103,3 +104,114 @@
 {
 	return (lwp_gettid());
 }
+
+/*
+ * We don't use the priority for SCHED_OTHER, but
+ * some programs may depend on getting an error when
+ * setting a priority that is out of the range returned
+ * by sched_get_priority_{min,max}. Not sure if this
+ * falls into implementation defined behavior or not.
+ */
+int
+_thr_set_sched_other_prio(struct pthread *pth, int prio)
+{
+	static int max, min, init_status;
+
+	/*
+	 * switch (init_status) {
+	 * case 0: need initialization
+	 * case 1: initialization successful
+	 * case 2: initialization failed. can't happen, but if
+	 * 	   it does, accept all and hope for the best.
+	 * 	   It's not like we use it anyway.
+	 */
+	if (!init_status) {
+		int tmp = errno;
+
+		errno = 0;
+		init_status = 1;
+		if (((min = sched_get_priority_min(SCHED_OTHER)) == -1) &&
+								(errno != 0))
+			init_status = 2;
+		if (((max = sched_get_priority_max(SCHED_OTHER)) == -1) &&
+								(errno != 0))
+			init_status = 2;
+		errno = tmp;
+	}
+	if ((init_status == 2) || ((prio >= min) && (prio <= max))) {
+		return 0;
+	}
+	errno = EINVAL;
+	return -1;
+}
+
+int
+_rtp_to_schedparam(const struct rtprio *rtp, int *policy,
+	struct sched_param *param)
+{
+	switch(rtp->type) {
+	case RTP_PRIO_REALTIME:
+		*policy = SCHED_RR;
+		param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+		break;
+	case RTP_PRIO_FIFO:
+		*policy = SCHED_FIFO;
+		param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+		break;
+	default:
+		*policy = SCHED_OTHER;
+		param->sched_priority = 0;
+		break;
+	}
+	return (0);
+}
+
+int
+_schedparam_to_rtp(int policy, const struct sched_param *param,
+	struct rtprio *rtp)
+{
+	switch(policy) {
+	case SCHED_RR:
+		rtp->type = RTP_PRIO_REALTIME;
+		rtp->prio = RTP_PRIO_MAX - param->sched_priority;
+		break;
+	case SCHED_FIFO:
+		rtp->type = RTP_PRIO_FIFO;
+		rtp->prio = RTP_PRIO_MAX - param->sched_priority;
+		break;
+	case SCHED_OTHER:
+	default:
+		rtp->type = RTP_PRIO_NORMAL;
+		rtp->prio = 0;
+		break;
+	}
+	return (0);
+}
+
+int
+_thr_getscheduler(lwpid_t lwpid, int *policy, struct sched_param *param)
+{
+	struct pthread *curthread = tls_get_curthread();
+	struct rtprio rtp;
+	int ret;
+
+	if (lwpid == curthread->tid)
+		lwpid = -1;
+	ret = lwp_rtprio(RTP_LOOKUP, 0, lwpid, &rtp);
+	if (ret == -1)
+		return (ret);
+	_rtp_to_schedparam(&rtp, policy, param);
+	return (0);
+}
+
+int
+_thr_setscheduler(lwpid_t lwpid, int policy, const struct sched_param *param)
+{
+	struct pthread *curthread = tls_get_curthread();
+	struct rtprio rtp;
+
+	if (lwpid == curthread->tid)
+		lwpid = -1;
+	_schedparam_to_rtp(policy, param, &rtp);
+	return (lwp_rtprio(RTP_SET, 0, lwpid, &rtp));
+}
Index: thread/thr_private.h
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/lib/libthread_xu/thread/thr_private.h,v
retrieving revision 1.15
diff -u -u -r1.15 thr_private.h
--- thread/thr_private.h	13 Apr 2006 11:48:01 -0000	1.15
+++ thread/thr_private.h	30 Apr 2007 10:38:54 -0000
@@ -236,7 +236,6 @@
 struct pthread_attr {
 	int	sched_policy;
 	int	sched_inherit;
-	int	sched_interval;
 	int	prio;
 	int	suspend;
 #define	THR_STACK_USER		0x100	/* 0xFF reserved for <pthread.h> */
@@ -691,6 +690,9 @@
 void	_thr_report_death(struct pthread *curthread);
 void	_thread_bp_create(void);
 void	_thread_bp_death(void);
+int	_thr_getscheduler(lwpid_t, int *, struct sched_param *);
+int	_thr_setscheduler(lwpid_t, int, const struct sched_param *);
+int	_thr_set_sched_other_prio(struct pthread *, int);
 
 /* #include <sys/aio.h> */
 #ifdef _SYS_AIO_H_
Index: thread/thr_setschedparam.c
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/lib/libthread_xu/thread/thr_setschedparam.c,v
retrieving revision 1.5
diff -u -u -r1.5 thr_setschedparam.c
--- thread/thr_setschedparam.c	6 Apr 2006 13:03:09 -0000	1.5
+++ thread/thr_setschedparam.c	30 Apr 2007 10:40:46 -0000
@@ -49,49 +49,47 @@
 	struct pthread *curthread = tls_get_curthread();
 	int	ret = 0;
 
-	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;
-
-	/* Find the thread in the list of active threads: */
+	if (pthread == curthread) {
+		THR_LOCK(curthread);
+		if (curthread->attr.sched_policy == policy &&
+		     curthread->attr.prio == param->sched_priority) {
+			THR_UNLOCK(curthread);
+			return (0);
+		}
+		if (policy == SCHED_OTHER) {
+			ret = _thr_set_sched_other_prio(curthread,
+						param->sched_priority);
+		} else {
+			ret = _thr_setscheduler(curthread->tid, policy, param);
+		}
+		if (ret == -1)
+			ret = errno;
+		else {
+			curthread->attr.sched_policy = policy;
+			curthread->attr.prio = param->sched_priority;
+		}
+		THR_UNLOCK(curthread);
 	} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
-	    == 0) {
-		/*
-		 * Lock the threads scheduling queue while we change
-		 * its priority:
-		 */
+		== 0) {
 		THR_THREAD_LOCK(curthread, pthread);
-		if (pthread->state == PS_DEAD) {
+		if (pthread->attr.sched_policy == policy &&
+		     pthread->attr.prio == param->sched_priority) {
 			THR_THREAD_UNLOCK(curthread, pthread);
-			_thr_ref_delete(curthread, pthread);
-			return (ESRCH);
+			return (0);
 		}
-
-		/* 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);
+		if (policy == SCHED_OTHER) {
+			ret = _thr_set_sched_other_prio(curthread,
+						param->sched_priority);
+		} else {
+			ret = _thr_setscheduler(curthread->tid, policy, param);
+		}
+		if (ret == -1)
+			ret = errno;
 		else {
-			/* Set the thread base priority: */
-			pthread->base_priority = param->sched_priority;
-
-			/* Recalculate the active priority: */
-			pthread->active_priority = MAX(pthread->base_priority,
-			    pthread->inherited_priority);
-
-			/* Unlock the threads scheduling queue: */
-			THR_THREAD_UNLOCK(curthread, pthread);
+			pthread->attr.sched_policy = policy;
+			pthread->attr.prio = param->sched_priority;
 		}
+		THR_THREAD_UNLOCK(curthread, pthread);
 		_thr_ref_delete(curthread, pthread);
 	}
 	return (ret);




More information about the Submit mailing list