Implementation of processor-sets, affinity and POSIX real-time extensions.
Add schedctl(8) - a program to control scheduling of processes and threads. Notes: - This is supported only by SCHED_M2; - Migration of LWP mechanism will be revisited; Proposed on: <tech-kern>. Reviewed by: <ad>.
This commit is contained in:
parent
cdd511a2fb
commit
5c71a4d49f
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: mi,v 1.737 2008/01/09 11:25:59 simonb Exp $
|
||||
# $NetBSD: mi,v 1.738 2008/01/15 03:37:12 rmind Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
|
@ -1270,6 +1270,7 @@
|
|||
./usr/sbin/setencstat base-sysutil-bin
|
||||
./usr/sbin/setkey base-obsolete obsolete
|
||||
./usr/sbin/setobjstat base-sysutil-bin
|
||||
./usr/sbin/schedctl base-sysutil-bin
|
||||
./usr/sbin/sliplogin base-slip-bin
|
||||
./usr/sbin/slstats base-slip-bin
|
||||
./usr/sbin/smrsh base-obsolete obsolete
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: mi,v 1.1108 2008/01/03 20:47:58 jdc Exp $
|
||||
# $NetBSD: mi,v 1.1109 2008/01/15 03:37:13 rmind Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
|
@ -1893,6 +1893,7 @@
|
|||
./usr/include/sys/proc.h comp-c-include
|
||||
./usr/include/sys/properties.h comp-obsolete obsolete
|
||||
./usr/include/sys/protosw.h comp-c-include
|
||||
./usr/include/sys/pset.h comp-c-include
|
||||
./usr/include/sys/ptrace.h comp-c-include
|
||||
./usr/include/sys/queue.h comp-c-include
|
||||
./usr/include/sys/radioio.h comp-c-include
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sysconf.c,v 1.25 2007/10/15 14:12:56 ad Exp $ */
|
||||
/* $NetBSD: sysconf.c,v 1.26 2008/01/15 03:37:14 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)sysconf.c 8.2 (Berkeley) 3/20/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: sysconf.c,v 1.25 2007/10/15 14:12:56 ad Exp $");
|
||||
__RCSID("$NetBSD: sysconf.c,v 1.26 2008/01/15 03:37:14 rmind Exp $");
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
|
@ -321,6 +321,11 @@ sysconf(int name)
|
|||
NULL, NULL, NULL, SYSCTL_VERSION))
|
||||
return -1;
|
||||
break;
|
||||
case _SC_PRIORITY_SCHEDULING:
|
||||
if (sysctlgetmibinfo("kern.posix_sched", &mib[0], &mib_len,
|
||||
NULL, NULL, NULL, SYSCTL_VERSION))
|
||||
return -1;
|
||||
goto yesno;
|
||||
case _SC_ATEXIT_MAX:
|
||||
mib[0] = CTL_USER;
|
||||
mib[1] = USER_ATEXIT_MAX;
|
||||
|
@ -350,6 +355,23 @@ yesno: if (sysctl(mib, mib_len, &value, &len, NULL, 0) == -1)
|
|||
mib[1] = HW_NCPUONLINE;
|
||||
break;
|
||||
|
||||
/* Native */
|
||||
case _SC_SCHED_RT_TS:
|
||||
if (sysctlgetmibinfo("kern.sched.rt_ts", &mib[0], &mib_len,
|
||||
NULL, NULL, NULL, SYSCTL_VERSION))
|
||||
return -1;
|
||||
break;
|
||||
case _SC_SCHED_PRI_MIN:
|
||||
if (sysctlgetmibinfo("kern.sched.pri_min", &mib[0], &mib_len,
|
||||
NULL, NULL, NULL, SYSCTL_VERSION))
|
||||
return -1;
|
||||
break;
|
||||
case _SC_SCHED_PRI_MAX:
|
||||
if (sysctlgetmibinfo("kern.sched.pri_max", &mib[0], &mib_len,
|
||||
NULL, NULL, NULL, SYSCTL_VERSION))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile.inc,v 1.182 2007/12/14 21:52:17 yamt Exp $
|
||||
# $NetBSD: Makefile.inc,v 1.183 2008/01/15 03:37:14 rmind Exp $
|
||||
# @(#)Makefile.inc 8.3 (Berkeley) 10/24/94
|
||||
|
||||
# sys sources
|
||||
|
@ -113,7 +113,9 @@ WEAKASM= accept.S aio_suspend.S close.S connect.S execve.S \
|
|||
kill.S mq_receive.S mq_send.S mq_timedreceive.S mq_timedsend.S \
|
||||
msgrcv.S msgsnd.S __msync13.S \
|
||||
nanosleep.S open.S poll.S pollts.S pselect.S read.S readlink.S readv.S \
|
||||
sched_yield.S select.S __sigprocmask14.S __sigsuspend14.S sysarch.S \
|
||||
_sched_setparam.S _sched_getparam.S _sched_setaffinity.S \
|
||||
_sched_getaffinity.S sched_yield.S \
|
||||
select.S __sigprocmask14.S __sigsuspend14.S sysarch.S \
|
||||
wait4.S write.S writev.S
|
||||
|
||||
NOERR= getegid.S geteuid.S getgid.S getpid.S getppid.S getuid.S \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh -
|
||||
# $NetBSD: makelintstub,v 1.20 2007/11/13 09:07:33 he Exp $
|
||||
# $NetBSD: makelintstub,v 1.21 2008/01/15 03:37:14 rmind Exp $
|
||||
#
|
||||
# Copyright (c) 1996, 1997 Christopher G. Demetriou
|
||||
# All rights reserved.
|
||||
|
@ -68,6 +68,7 @@ header()
|
|||
#include <sys/msg.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/event.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile,v 1.48 2007/12/14 21:51:21 yamt Exp $
|
||||
# $NetBSD: Makefile,v 1.49 2008/01/15 03:37:14 rmind Exp $
|
||||
#
|
||||
|
||||
WARNS= 4
|
||||
|
@ -61,7 +61,6 @@ SRCS+= pthread_specific.c
|
|||
SRCS+= pthread_spin.c
|
||||
SRCS+= pthread_tsd.c
|
||||
SRCS+= res_state.c
|
||||
SRCS+= sched.c
|
||||
SRCS+= sem.c
|
||||
# Architecture-dependent files
|
||||
SRCS+= _context_u.S
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: pthread.h,v 1.24 2007/12/24 14:46:28 ad Exp $ */
|
||||
/* $NetBSD: pthread.h,v 1.25 2008/01/15 03:37:14 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include <time.h> /* For timespec */
|
||||
#include <sched.h>
|
||||
#include <sys/pset.h>
|
||||
|
||||
#include <pthread_types.h>
|
||||
|
||||
|
@ -186,6 +187,9 @@ int pthread_barrierattr_destroy(pthread_barrierattr_t *);
|
|||
int pthread_getschedparam(pthread_t, int * __restrict,
|
||||
struct sched_param * __restrict);
|
||||
int pthread_setschedparam(pthread_t, int, const struct sched_param *);
|
||||
int pthread_getaffinity_np(pthread_t, size_t, cpuset_t *);
|
||||
int pthread_setaffinity_np(pthread_t, size_t, cpuset_t *);
|
||||
int pthread_setschedprio(pthread_t, int);
|
||||
|
||||
int *pthread__errno(void);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: pthread_misc.c,v 1.3 2007/11/13 17:20:09 ad Exp $ */
|
||||
/* $NetBSD: pthread_misc.c,v 1.4 2008/01/15 03:37:14 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
|
@ -37,14 +37,19 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: pthread_misc.c,v 1.3 2007/11/13 17:20:09 ad Exp $");
|
||||
__RCSID("$NetBSD: pthread_misc.c,v 1.4 2008/01/15 03:37:14 rmind Exp $");
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <lwp.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "pthread.h"
|
||||
#include "pthread_int.h"
|
||||
|
@ -60,27 +65,65 @@ __strong_alias(__libc_thr_sigsetmask,pthread_sigmask)
|
|||
__strong_alias(__sigprocmask14,pthread_sigmask)
|
||||
__strong_alias(__libc_thr_yield,pthread__sched_yield)
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
|
||||
{
|
||||
if (param == NULL || policy == NULL)
|
||||
return EINVAL;
|
||||
param->sched_priority = 0;
|
||||
*policy = SCHED_RR;
|
||||
return 0;
|
||||
int error;
|
||||
|
||||
if (pthread__find(thread) != 0)
|
||||
return ESRCH;
|
||||
|
||||
error = _sched_getparam(getpid(), thread->pt_lid, param);
|
||||
if (error == 0)
|
||||
*policy = param->sched_class;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
pthread_setschedparam(pthread_t thread, int policy,
|
||||
const struct sched_param *param)
|
||||
{
|
||||
if (param == NULL || policy < SCHED_FIFO || policy > SCHED_RR)
|
||||
return EINVAL;
|
||||
if (param->sched_priority > 0 || policy != SCHED_RR)
|
||||
return ENOTSUP;
|
||||
return 0;
|
||||
struct sched_param sp;
|
||||
|
||||
if (pthread__find(thread) != 0)
|
||||
return ESRCH;
|
||||
|
||||
memcpy(&sp, param, sizeof(struct sched_param));
|
||||
sp.sched_class = policy;
|
||||
return _sched_setparam(getpid(), thread->pt_lid, &sp);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_getaffinity_np(pthread_t thread, size_t size, cpuset_t *cpuset)
|
||||
{
|
||||
|
||||
if (pthread__find(thread) != 0)
|
||||
return ESRCH;
|
||||
|
||||
return _sched_getaffinity(getpid(), thread->pt_lid, size, cpuset);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_setaffinity_np(pthread_t thread, size_t size, cpuset_t *cpuset)
|
||||
{
|
||||
|
||||
if (pthread__find(thread) != 0)
|
||||
return ESRCH;
|
||||
|
||||
return _sched_setaffinity(getpid(), thread->pt_lid, size, cpuset);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_setschedprio(pthread_t thread, int prio)
|
||||
{
|
||||
struct sched_param sp;
|
||||
|
||||
if (pthread__find(thread) != 0)
|
||||
return ESRCH;
|
||||
|
||||
sp.sched_class = SCHED_NONE;
|
||||
sp.sched_priority = prio;
|
||||
return _sched_setparam(getpid(), thread->pt_lid, &sp);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.4 2007/06/17 12:47:41 rmind Exp $
|
||||
# $NetBSD: Makefile,v 1.5 2008/01/15 03:37:15 rmind Exp $
|
||||
#
|
||||
|
||||
WARNS= 2
|
||||
|
||||
LIB= rt
|
||||
SRCS= sem.c
|
||||
SRCS+= sched.c
|
||||
|
||||
MAN+= aio_cancel.3 aio_error.3 aio_fsync.3 aio_read.3 aio_return.3 \
|
||||
aio_suspend.3 aio_write.3 lio_listio.3 \
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
/* $NetBSD: sched.c,v 1.4 2005/10/09 11:17:28 kleink Exp $ */
|
||||
/* $NetBSD: sched.c,v 1.1 2008/01/15 03:37:15 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
/*
|
||||
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Nathan J. Williams.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
|
@ -15,15 +12,8 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
|
@ -37,73 +27,91 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: sched.c,v 1.4 2005/10/09 11:17:28 kleink Exp $");
|
||||
__RCSID("$NetBSD: sched.c,v 1.1 2008/01/15 03:37:15 rmind Exp $");
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int pthread__sched_binder;
|
||||
/*
|
||||
* Scheduling parameters.
|
||||
*/
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sched_setparam(pid_t pid, const struct sched_param *param)
|
||||
{
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return _sched_setparam(pid, 0, param);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sched_getparam(pid_t pid, struct sched_param *param)
|
||||
{
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return _sched_getparam(pid, 0, param);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sched_setscheduler(pid_t pid, int policy,
|
||||
const struct sched_param *param)
|
||||
sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)
|
||||
{
|
||||
struct sched_param sp;
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
memcpy(&sp, param, sizeof(struct sched_param));
|
||||
sp.sched_class = policy;
|
||||
return _sched_setparam(pid, 0, &sp);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sched_getscheduler(pid_t pid)
|
||||
{
|
||||
struct sched_param sp;
|
||||
int error;
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
error = _sched_getparam(pid, 0, &sp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return sp.sched_class;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
/*
|
||||
* Scheduling priorities.
|
||||
*/
|
||||
|
||||
int
|
||||
sched_get_priority_max(int policy)
|
||||
{
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return sysconf(_SC_SCHED_PRI_MAX);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sched_get_priority_min(int policy)
|
||||
{
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return sysconf(_SC_SCHED_PRI_MIN);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sched_rr_get_interval(pid_t pid, struct timespec *interval)
|
||||
{
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
interval->tv_sec = 0;
|
||||
interval->tv_nsec = sysconf(_SC_SCHED_RT_TS) * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Processor-sets.
|
||||
*/
|
||||
|
||||
int
|
||||
pset_bind(psetid_t psid, idtype_t idtype, id_t id, psetid_t *opsid)
|
||||
{
|
||||
|
||||
return _pset_bind(idtype, id, 0, psid, opsid);
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
# $NetBSD: Makefile.inc,v 1.4 2007/10/09 18:18:33 rmind Exp $
|
||||
# $NetBSD: Makefile.inc,v 1.5 2008/01/15 03:37:15 rmind Exp $
|
||||
|
||||
.PATH: ${.CURDIR}/sys
|
||||
|
||||
ASM= aio_cancel.S aio_error.S aio_fsync.S aio_read.S aio_return.S \
|
||||
aio_write.S lio_listio.S \
|
||||
mq_close.S mq_getattr.S mq_notify.S mq_open.S \
|
||||
mq_setattr.S mq_unlink.S
|
||||
mq_setattr.S mq_unlink.S \
|
||||
pset_create.S pset_destroy.S pset_assign.S _pset_bind.S
|
||||
|
||||
SRCS+= ${ASM}
|
||||
CLEANFILES+= ${ASM}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files,v 1.884 2008/01/14 12:40:04 yamt Exp $
|
||||
# $NetBSD: files,v 1.885 2008/01/15 03:37:10 rmind Exp $
|
||||
|
||||
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
|
||||
|
||||
|
@ -1421,6 +1421,7 @@ file kern/sys_lwp.c
|
|||
file kern/sys_pipe.c !pipe_socketpair
|
||||
file kern/sys_pmc.c
|
||||
file kern/sys_process.c ptrace | ktrace
|
||||
file kern/sys_pset.c
|
||||
file kern/sys_sig.c
|
||||
file kern/sys_sched.c
|
||||
file kern/sys_socket.c
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: init_main.c,v 1.338 2008/01/14 12:40:03 yamt Exp $ */
|
||||
/* $NetBSD: init_main.c,v 1.339 2008/01/15 03:37:10 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
|
||||
|
@ -71,7 +71,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.338 2008/01/14 12:40:03 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.339 2008/01/15 03:37:10 rmind Exp $");
|
||||
|
||||
#include "opt_ipsec.h"
|
||||
#include "opt_ntp.h"
|
||||
|
@ -339,6 +339,9 @@ main(void)
|
|||
turnstile_init();
|
||||
sleeptab_init(&sleeptab);
|
||||
|
||||
/* Initialize processor-sets */
|
||||
psets_init();
|
||||
|
||||
/* MI initialization of the boot cpu */
|
||||
error = mi_cpu_attach(curcpu());
|
||||
KASSERT(error == 0);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_cpu.c,v 1.17 2008/01/14 12:40:03 yamt Exp $ */
|
||||
/* $NetBSD: kern_cpu.c,v 1.18 2008/01/15 03:37:10 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -64,7 +64,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.17 2008/01/14 12:40:03 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.18 2008/01/15 03:37:10 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -284,19 +284,8 @@ cpu_xc_offline(struct cpu_info *ci)
|
|||
lwp_unlock(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Runqueues are locked with the global lock if pointers match,
|
||||
* thus hold only one. Otherwise, double-lock the runqueues.
|
||||
*/
|
||||
if (spc->spc_mutex == mspc->spc_mutex) {
|
||||
spc_lock(ci);
|
||||
} else if (ci < mci) {
|
||||
spc_lock(ci);
|
||||
spc_lock(mci);
|
||||
} else {
|
||||
spc_lock(mci);
|
||||
spc_lock(ci);
|
||||
}
|
||||
/* Double-lock the run-queues */
|
||||
spc_dlock(ci, mci);
|
||||
|
||||
/* Handle LSRUN and LSIDL cases */
|
||||
LIST_FOREACH(l, &alllwp, l_list) {
|
||||
|
@ -312,13 +301,7 @@ cpu_xc_offline(struct cpu_info *ci)
|
|||
lwp_setlock(l, mspc->spc_mutex);
|
||||
}
|
||||
}
|
||||
if (spc->spc_mutex == mspc->spc_mutex) {
|
||||
spc_unlock(ci);
|
||||
} else {
|
||||
spc_unlock(ci);
|
||||
spc_unlock(mci);
|
||||
}
|
||||
|
||||
spc_dunlock(ci, mci);
|
||||
mutex_exit(&proclist_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_lwp.c,v 1.90 2008/01/12 18:06:40 ad Exp $ */
|
||||
/* $NetBSD: kern_lwp.c,v 1.91 2008/01/15 03:37:11 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -205,7 +205,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.90 2008/01/12 18:06:40 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.91 2008/01/15 03:37:11 rmind Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_multiprocessor.h"
|
||||
|
@ -225,6 +225,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.90 2008/01/12 18:06:40 ad Exp $");
|
|||
#include <sys/user.h>
|
||||
#include <sys/lockdebug.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/intr.h>
|
||||
#include <sys/lwpctl.h>
|
||||
#include <sys/atomic.h>
|
||||
|
@ -584,15 +585,8 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_t uaddr, bool inmem, int flags,
|
|||
l2->l_pflag = LP_MPSAFE;
|
||||
|
||||
if (p2->p_flag & PK_SYSTEM) {
|
||||
/*
|
||||
* Mark it as a system process and not a candidate for
|
||||
* swapping.
|
||||
*/
|
||||
/* Mark it as a system LWP and not a candidate for swapping */
|
||||
l2->l_flag |= LW_SYSTEM;
|
||||
} else {
|
||||
/* Look for a CPU to start */
|
||||
l2->l_cpu = sched_takecpu(l2);
|
||||
l2->l_mutex = l2->l_cpu->ci_schedstate.spc_mutex;
|
||||
}
|
||||
|
||||
lwp_initspecific(l2);
|
||||
|
@ -636,6 +630,18 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_t uaddr, bool inmem, int flags,
|
|||
LIST_INSERT_HEAD(&alllwp, l2, l_list);
|
||||
mutex_exit(&proclist_lock);
|
||||
|
||||
if ((p2->p_flag & PK_SYSTEM) == 0) {
|
||||
/* Locking is needed, since LWP is in the list of all LWPs */
|
||||
lwp_lock(l2);
|
||||
/* Inherit a processor-set */
|
||||
l2->l_psid = l1->l_psid;
|
||||
/* Inherit an affinity */
|
||||
memcpy(&l2->l_affinity, &l1->l_affinity, sizeof(cpuset_t));
|
||||
/* Look for a CPU to start */
|
||||
l2->l_cpu = sched_takecpu(l2);
|
||||
lwp_unlock_to(l2, l2->l_cpu->ci_schedstate.spc_mutex);
|
||||
}
|
||||
|
||||
SYSCALL_TIME_LWP_INIT(l2);
|
||||
|
||||
if (p2->p_emul->e_lwp_fork)
|
||||
|
@ -1044,6 +1050,74 @@ proc_representative_lwp(struct proc *p, int *nrlwps, int locking)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Migrate the LWP to the another CPU. Unlocks the LWP.
|
||||
*/
|
||||
void
|
||||
lwp_migrate(lwp_t *l, struct cpu_info *ci)
|
||||
{
|
||||
struct schedstate_percpu *spc;
|
||||
KASSERT(lwp_locked(l, NULL));
|
||||
|
||||
if (l->l_cpu == ci) {
|
||||
lwp_unlock(l);
|
||||
return;
|
||||
}
|
||||
|
||||
spc = &ci->ci_schedstate;
|
||||
switch (l->l_stat) {
|
||||
case LSRUN:
|
||||
if (l->l_flag & LW_INMEM) {
|
||||
l->l_target_cpu = ci;
|
||||
break;
|
||||
}
|
||||
case LSIDL:
|
||||
l->l_cpu = ci;
|
||||
lwp_unlock_to(l, spc->spc_mutex);
|
||||
KASSERT(!mutex_owned(spc->spc_mutex));
|
||||
return;
|
||||
case LSSLEEP:
|
||||
l->l_cpu = ci;
|
||||
break;
|
||||
case LSSTOP:
|
||||
case LSSUSPENDED:
|
||||
if (l->l_wchan != NULL) {
|
||||
l->l_cpu = ci;
|
||||
break;
|
||||
}
|
||||
case LSONPROC:
|
||||
l->l_target_cpu = ci;
|
||||
break;
|
||||
}
|
||||
lwp_unlock(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the LWP in the process.
|
||||
* On success - returns LWP locked.
|
||||
*/
|
||||
struct lwp *
|
||||
lwp_find2(pid_t pid, lwpid_t lid)
|
||||
{
|
||||
proc_t *p;
|
||||
lwp_t *l;
|
||||
|
||||
/* Find the process */
|
||||
p = p_find(pid, PFIND_UNLOCK_FAIL);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
mutex_enter(&p->p_smutex);
|
||||
mutex_exit(&proclist_lock);
|
||||
|
||||
/* Find the thread */
|
||||
l = lwp_find(p, lid);
|
||||
if (l != NULL)
|
||||
lwp_lock(l);
|
||||
mutex_exit(&p->p_smutex);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up a live LWP within the speicifed process, and return it locked.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_synch.c,v 1.215 2008/01/04 21:18:10 ad Exp $ */
|
||||
/* $NetBSD: kern_synch.c,v 1.216 2008/01/15 03:37:11 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2004, 2006, 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -75,7 +75,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.215 2008/01/04 21:18:10 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.216 2008/01/15 03:37:11 rmind Exp $");
|
||||
|
||||
#include "opt_kstack.h"
|
||||
#include "opt_lockdebug.h"
|
||||
|
@ -354,10 +354,10 @@ updatertime(lwp_t *l, const struct bintime *now)
|
|||
int
|
||||
mi_switch(lwp_t *l)
|
||||
{
|
||||
struct cpu_info *ci, *tci = NULL;
|
||||
struct schedstate_percpu *spc;
|
||||
struct lwp *newl;
|
||||
int retval, oldspl;
|
||||
struct cpu_info *ci;
|
||||
struct bintime bt;
|
||||
bool returning;
|
||||
|
||||
|
@ -421,16 +421,41 @@ mi_switch(lwp_t *l)
|
|||
/*
|
||||
* If on the CPU and we have gotten this far, then we must yield.
|
||||
*/
|
||||
mutex_spin_enter(spc->spc_mutex);
|
||||
KASSERT(l->l_stat != LSRUN);
|
||||
if (l->l_stat == LSONPROC && l != newl) {
|
||||
if (l->l_stat == LSONPROC && (l->l_target_cpu || l != newl)) {
|
||||
KASSERT(lwp_locked(l, &spc->spc_lwplock));
|
||||
|
||||
tci = l->l_target_cpu;
|
||||
if (__predict_false(tci != NULL)) {
|
||||
/* Double-lock the runqueues */
|
||||
spc_dlock(ci, tci);
|
||||
} else {
|
||||
/* Lock the runqueue */
|
||||
spc_lock(ci);
|
||||
}
|
||||
|
||||
if ((l->l_flag & LW_IDLE) == 0) {
|
||||
l->l_stat = LSRUN;
|
||||
lwp_setlock(l, spc->spc_mutex);
|
||||
if (__predict_false(tci != NULL)) {
|
||||
/*
|
||||
* Set the new CPU, lock and unset the
|
||||
* l_target_cpu - thread will be enqueued
|
||||
* to the runqueue of target CPU.
|
||||
*/
|
||||
l->l_cpu = tci;
|
||||
lwp_setlock(l, tci->ci_schedstate.spc_mutex);
|
||||
l->l_target_cpu = NULL;
|
||||
} else {
|
||||
lwp_setlock(l, spc->spc_mutex);
|
||||
}
|
||||
sched_enqueue(l, true);
|
||||
} else
|
||||
} else {
|
||||
KASSERT(tci == NULL);
|
||||
l->l_stat = LSIDL;
|
||||
}
|
||||
} else {
|
||||
/* Lock the runqueue */
|
||||
spc_lock(ci);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -482,7 +507,13 @@ mi_switch(lwp_t *l)
|
|||
struct lwp *prevlwp;
|
||||
|
||||
/* Release all locks, but leave the current LWP locked */
|
||||
if (l->l_mutex == spc->spc_mutex) {
|
||||
if (l->l_mutex == l->l_cpu->ci_schedstate.spc_mutex) {
|
||||
/*
|
||||
* In case of migration, drop the local runqueue
|
||||
* lock, thread is on other runqueue now.
|
||||
*/
|
||||
if (__predict_false(tci != NULL))
|
||||
spc_unlock(ci);
|
||||
/*
|
||||
* Drop spc_lwplock, if the current LWP has been moved
|
||||
* to the run queue (it is now locked by spc_mutex).
|
||||
|
@ -494,6 +525,7 @@ mi_switch(lwp_t *l)
|
|||
* run queues.
|
||||
*/
|
||||
mutex_spin_exit(spc->spc_mutex);
|
||||
KASSERT(tci == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -565,7 +597,8 @@ mi_switch(lwp_t *l)
|
|||
retval = 1;
|
||||
} else {
|
||||
/* Nothing to do - just unlock and return. */
|
||||
mutex_spin_exit(spc->spc_mutex);
|
||||
KASSERT(tci == NULL);
|
||||
spc_unlock(ci);
|
||||
lwp_unlock(l);
|
||||
retval = 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sched_4bsd.c,v 1.11 2007/12/21 12:05:39 ad Exp $ */
|
||||
/* $NetBSD: sched_4bsd.c,v 1.12 2008/01/15 03:37:11 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2004, 2006, 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -75,7 +75,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sched_4bsd.c,v 1.11 2007/12/21 12:05:39 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sched_4bsd.c,v 1.12 2008/01/15 03:37:11 rmind Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_lockdebug.h"
|
||||
|
@ -136,7 +136,7 @@ extern unsigned int sched_pstats_ticks; /* defined in kern_synch.c */
|
|||
kmutex_t runqueue_lock;
|
||||
|
||||
/* Number of hardclock ticks per sched_tick() */
|
||||
int rrticks;
|
||||
static int rrticks;
|
||||
|
||||
const int schedppq = 1;
|
||||
|
||||
|
@ -642,6 +642,12 @@ void
|
|||
sched_enqueue(struct lwp *l, bool ctxswitch)
|
||||
{
|
||||
|
||||
if (__predict_false(l->l_target_cpu != NULL)) {
|
||||
/* Global mutex is used - just change the CPU */
|
||||
l->l_cpu = l->l_target_cpu;
|
||||
l->l_target_cpu = NULL;
|
||||
}
|
||||
|
||||
if ((l->l_flag & LW_BOUND) != 0)
|
||||
runqueue_enqueue(l->l_cpu->ci_schedstate.spc_sched_info, l);
|
||||
else
|
||||
|
@ -740,8 +746,20 @@ sched_lwp_collect(struct lwp *t)
|
|||
}
|
||||
|
||||
/*
|
||||
* sysctl setup. XXX This should be split with kern_synch.c.
|
||||
* Sysctl nodes and initialization.
|
||||
*/
|
||||
|
||||
static int
|
||||
sysctl_sched_rtts(SYSCTLFN_ARGS)
|
||||
{
|
||||
struct sysctlnode node;
|
||||
int rttsms = hztoms(rrticks);
|
||||
|
||||
node = *rnode;
|
||||
node.sysctl_data = &rttsms;
|
||||
return sysctl_lookup(SYSCTLFN_CALL(&node));
|
||||
}
|
||||
|
||||
SYSCTL_SETUP(sysctl_sched_setup, "sysctl kern.sched subtree setup")
|
||||
{
|
||||
const struct sysctlnode *node = NULL;
|
||||
|
@ -765,6 +783,12 @@ SYSCTL_SETUP(sysctl_sched_setup, "sysctl kern.sched subtree setup")
|
|||
CTLTYPE_STRING, "name", NULL,
|
||||
NULL, 0, __UNCONST("4.4BSD"), 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_INT, "rtts",
|
||||
SYSCTL_DESCR("Round-robin time quantum (in miliseconds)"),
|
||||
sysctl_sched_rtts, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "timesoftints",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: sched_m2.c,v 1.14 2007/12/21 12:05:39 ad Exp $ */
|
||||
/* $NetBSD: sched_m2.c,v 1.15 2008/01/15 03:37:11 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007, Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sched_m2.c,v 1.14 2007/12/21 12:05:39 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sched_m2.c,v 1.15 2008/01/15 03:37:11 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
|
@ -47,6 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: sched_m2.c,v 1.14 2007/12/21 12:05:39 ad Exp $");
|
|||
#include <sys/mutex.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/sched.h>
|
||||
|
@ -87,6 +88,7 @@ static pri_t high_pri[PRI_COUNT]; /* Map for priority increase */
|
|||
* Migration and balancing.
|
||||
*/
|
||||
#ifdef MULTIPROCESSOR
|
||||
|
||||
static u_int cacheht_time; /* Cache hotness time */
|
||||
static u_int min_catch; /* Minimal LWP count for catching */
|
||||
|
||||
|
@ -420,6 +422,7 @@ sched_dequeue(struct lwp *l)
|
|||
|
||||
ci_rq = l->l_cpu->ci_schedstate.spc_sched_info;
|
||||
KASSERT(lwp_locked(l, l->l_cpu->ci_schedstate.spc_mutex));
|
||||
|
||||
KASSERT(eprio <= ci_rq->r_highest_pri);
|
||||
KASSERT(ci_rq->r_bitmap[eprio >> BITMAP_SHIFT] != 0);
|
||||
KASSERT(ci_rq->r_count > 0);
|
||||
|
@ -554,19 +557,20 @@ sched_pstats_hook(struct lwp *l)
|
|||
|
||||
/* Check if LWP can migrate to the chosen CPU */
|
||||
static inline bool
|
||||
sched_migratable(const struct lwp *l, const struct cpu_info *ci)
|
||||
sched_migratable(const struct lwp *l, struct cpu_info *ci)
|
||||
{
|
||||
const struct schedstate_percpu *spc = &ci->ci_schedstate;
|
||||
|
||||
if (ci->ci_schedstate.spc_flags & SPCF_OFFLINE)
|
||||
/* CPU is offline */
|
||||
if (__predict_false(spc->spc_flags & SPCF_OFFLINE))
|
||||
return false;
|
||||
|
||||
if ((l->l_flag & LW_BOUND) == 0)
|
||||
return true;
|
||||
#if 0
|
||||
return cpu_in_pset(ci, l->l_psid);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
/* Affinity bind */
|
||||
if (__predict_false(l->l_flag & LW_AFFINITY))
|
||||
return CPU_ISSET(cpu_index(ci), &l->l_affinity);
|
||||
|
||||
/* Processor-set */
|
||||
return (spc->spc_psid == l->l_psid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -576,17 +580,23 @@ sched_migratable(const struct lwp *l, const struct cpu_info *ci)
|
|||
struct cpu_info *
|
||||
sched_takecpu(struct lwp *l)
|
||||
{
|
||||
struct cpu_info *ci, *tci = NULL;
|
||||
struct cpu_info *ci, *tci;
|
||||
struct schedstate_percpu *spc;
|
||||
runqueue_t *ci_rq;
|
||||
sched_info_lwp_t *sil;
|
||||
CPU_INFO_ITERATOR cii;
|
||||
pri_t eprio, lpri;
|
||||
|
||||
KASSERT(lwp_locked(l, NULL));
|
||||
|
||||
ci = l->l_cpu;
|
||||
spc = &ci->ci_schedstate;
|
||||
ci_rq = spc->spc_sched_info;
|
||||
|
||||
/* If thread is strictly bound, do not estimate other CPUs */
|
||||
if (l->l_flag & LW_BOUND)
|
||||
return ci;
|
||||
|
||||
/* CPU of this thread is idling - run there */
|
||||
if (ci_rq->r_count == 0)
|
||||
return ci;
|
||||
|
@ -609,6 +619,7 @@ sched_takecpu(struct lwp *l)
|
|||
* Look for the CPU with the lowest priority thread. In case of
|
||||
* equal the priority - check the lower count of the threads.
|
||||
*/
|
||||
tci = l->l_cpu;
|
||||
lpri = PRI_COUNT;
|
||||
for (CPU_INFO_FOREACH(cii, ci)) {
|
||||
runqueue_t *ici_rq;
|
||||
|
@ -620,18 +631,16 @@ sched_takecpu(struct lwp *l)
|
|||
if (pri > lpri)
|
||||
continue;
|
||||
|
||||
if (pri == lpri && tci && ci_rq->r_count < ici_rq->r_count)
|
||||
if (pri == lpri && ci_rq->r_count < ici_rq->r_count)
|
||||
continue;
|
||||
|
||||
if (sched_migratable(l, ci) == false)
|
||||
if (!sched_migratable(l, ci))
|
||||
continue;
|
||||
|
||||
lpri = pri;
|
||||
tci = ci;
|
||||
ci_rq = ici_rq;
|
||||
}
|
||||
|
||||
KASSERT(tci != NULL);
|
||||
return tci;
|
||||
}
|
||||
|
||||
|
@ -691,7 +700,7 @@ sched_catchlwp(void)
|
|||
/* Look for threads, whose are allowed to migrate */
|
||||
sil = l->l_sched_info;
|
||||
if ((l->l_flag & LW_SYSTEM) || CACHE_HOT(sil) ||
|
||||
sched_migratable(l, curci) == false) {
|
||||
!sched_migratable(l, curci)) {
|
||||
l = TAILQ_NEXT(l, l_runq);
|
||||
continue;
|
||||
}
|
||||
|
@ -866,7 +875,7 @@ sched_tick(struct cpu_info *ci)
|
|||
* If there are higher priority threads or threads in the same queue,
|
||||
* mark that thread should yield, otherwise, continue running.
|
||||
*/
|
||||
if (lwp_eprio(l) <= ci_rq->r_highest_pri) {
|
||||
if (lwp_eprio(l) <= ci_rq->r_highest_pri || l->l_target_cpu) {
|
||||
spc->spc_flags |= SPCF_SHOULDYIELD;
|
||||
cpu_need_resched(ci, 0);
|
||||
} else
|
||||
|
@ -877,6 +886,17 @@ sched_tick(struct cpu_info *ci)
|
|||
* Sysctl nodes and initialization.
|
||||
*/
|
||||
|
||||
static int
|
||||
sysctl_sched_rtts(SYSCTLFN_ARGS)
|
||||
{
|
||||
struct sysctlnode node;
|
||||
int rttsms = hztoms(rt_ts);
|
||||
|
||||
node = *rnode;
|
||||
node.sysctl_data = &rttsms;
|
||||
return sysctl_lookup(SYSCTLFN_CALL(&node));
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_sched_mints(SYSCTLFN_ARGS)
|
||||
{
|
||||
|
@ -967,6 +987,12 @@ SYSCTL_SETUP(sysctl_sched_setup, "sysctl kern.sched subtree setup")
|
|||
CTLTYPE_STRING, "name", NULL,
|
||||
NULL, 0, __UNCONST("M2"), 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_INT, "rtts",
|
||||
SYSCTL_DESCR("Round-robin time quantum (in miliseconds)"),
|
||||
sysctl_sched_rtts, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "maxts",
|
||||
|
|
|
@ -0,0 +1,503 @@
|
|||
/* $NetBSD: sys_pset.c,v 1.1 2008/01/15 03:41:49 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of the Processor Sets.
|
||||
*
|
||||
* Locking
|
||||
* The array of the processor-set structures and its members are protected
|
||||
* by the global psets_lock. Note that in scheduler, the very l_psid value
|
||||
* might be used without lock held.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sys_pset.c,v 1.1 2008/01/15 03:41:49 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/kauth.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/lwp.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/syscallargs.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static pset_info_t ** psets;
|
||||
static kmutex_t psets_lock;
|
||||
static u_int psets_max;
|
||||
static u_int psets_count;
|
||||
|
||||
static int psets_realloc(int);
|
||||
static int psid_validate(psetid_t, bool);
|
||||
static int kern_pset_create(psetid_t *);
|
||||
static int kern_pset_destroy(psetid_t);
|
||||
|
||||
/*
|
||||
* Initialization of the processor-sets.
|
||||
*/
|
||||
void
|
||||
psets_init(void)
|
||||
{
|
||||
|
||||
psets_max = max(MAXCPUS, 32);
|
||||
psets = kmem_zalloc(psets_max * sizeof(void *), KM_SLEEP);
|
||||
mutex_init(&psets_lock, MUTEX_DEFAULT, IPL_NONE);
|
||||
psets_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reallocate the array of the processor-set structures.
|
||||
*/
|
||||
static int
|
||||
psets_realloc(int new_psets_max)
|
||||
{
|
||||
pset_info_t **new_psets, **old_psets;
|
||||
const u_int newsize = new_psets_max * sizeof(void *);
|
||||
u_int i, oldsize;
|
||||
|
||||
if (new_psets_max < 1)
|
||||
return EINVAL;
|
||||
|
||||
new_psets = kmem_zalloc(newsize, KM_SLEEP);
|
||||
mutex_enter(&psets_lock);
|
||||
old_psets = psets;
|
||||
oldsize = psets_max * sizeof(void *);
|
||||
|
||||
/* Check if we can lower the size of the array */
|
||||
if (new_psets_max < psets_max) {
|
||||
for (i = new_psets_max; i < psets_max; i++) {
|
||||
if (psets[i] == NULL)
|
||||
continue;
|
||||
mutex_exit(&psets_lock);
|
||||
kmem_free(new_psets, newsize);
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy all pointers to the new array */
|
||||
memcpy(new_psets, psets, newsize);
|
||||
psets_max = new_psets_max;
|
||||
psets = new_psets;
|
||||
mutex_exit(&psets_lock);
|
||||
|
||||
kmem_free(old_psets, oldsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate processor-set ID.
|
||||
*/
|
||||
static int
|
||||
psid_validate(psetid_t psid, bool chkps)
|
||||
{
|
||||
|
||||
KASSERT(mutex_owned(&psets_lock));
|
||||
|
||||
if (chkps && (psid == PS_NONE || psid == PS_QUERY || psid == PS_MYID))
|
||||
return 0;
|
||||
if (psid <= 0 || psid > psets_max)
|
||||
return EINVAL;
|
||||
if (psets[psid - 1] == NULL)
|
||||
return EINVAL;
|
||||
if (psets[psid - 1]->ps_flags & PSET_BUSY)
|
||||
return EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a processor-set.
|
||||
*/
|
||||
static int
|
||||
kern_pset_create(psetid_t *psid)
|
||||
{
|
||||
pset_info_t *pi;
|
||||
u_int i;
|
||||
|
||||
if (psets_count == psets_max)
|
||||
return ENOMEM;
|
||||
|
||||
pi = kmem_zalloc(sizeof(pset_info_t), KM_SLEEP);
|
||||
|
||||
mutex_enter(&psets_lock);
|
||||
if (psets_count == psets_max) {
|
||||
mutex_exit(&psets_lock);
|
||||
kmem_free(pi, sizeof(pset_info_t));
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* Find a free entry in the array */
|
||||
for (i = 0; i < psets_max; i++)
|
||||
if (psets[i] == NULL)
|
||||
break;
|
||||
KASSERT(i != psets_max);
|
||||
|
||||
psets[i] = pi;
|
||||
psets_count++;
|
||||
mutex_exit(&psets_lock);
|
||||
|
||||
*psid = i + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a processor-set.
|
||||
*/
|
||||
static int
|
||||
kern_pset_destroy(psetid_t psid)
|
||||
{
|
||||
struct cpu_info *ci;
|
||||
pset_info_t *pi;
|
||||
struct lwp *l;
|
||||
CPU_INFO_ITERATOR cii;
|
||||
int error;
|
||||
|
||||
mutex_enter(&psets_lock);
|
||||
if (psid == PS_MYID) {
|
||||
/* Use caller's processor-set ID */
|
||||
psid = curlwp->l_psid;
|
||||
}
|
||||
error = psid_validate(psid, false);
|
||||
if (error) {
|
||||
mutex_exit(&psets_lock);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Release the processor-set from all CPUs */
|
||||
for (CPU_INFO_FOREACH(cii, ci)) {
|
||||
struct schedstate_percpu *spc;
|
||||
|
||||
spc = &ci->ci_schedstate;
|
||||
if (spc->spc_psid != psid)
|
||||
continue;
|
||||
spc->spc_psid = PS_NONE;
|
||||
}
|
||||
/* Mark that processor-set is going to be destroyed */
|
||||
pi = psets[psid - 1];
|
||||
pi->ps_flags |= PSET_BUSY;
|
||||
mutex_exit(&psets_lock);
|
||||
|
||||
/* Unmark the processor-set ID from each thread */
|
||||
mutex_enter(&proclist_lock);
|
||||
LIST_FOREACH(l, &alllwp, l_list) {
|
||||
/* Safe to check and set without lock held */
|
||||
if (l->l_psid != psid)
|
||||
continue;
|
||||
l->l_psid = PS_NONE;
|
||||
}
|
||||
mutex_exit(&proclist_lock);
|
||||
|
||||
/* Destroy the processor-set */
|
||||
mutex_enter(&psets_lock);
|
||||
psets[psid - 1] = NULL;
|
||||
psets_count--;
|
||||
mutex_exit(&psets_lock);
|
||||
|
||||
kmem_free(pi, sizeof(pset_info_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* General system calls for the processor-sets.
|
||||
*/
|
||||
|
||||
int
|
||||
sys_pset_create(struct lwp *l, const struct sys_pset_create_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(psetid_t) *psid;
|
||||
} */
|
||||
psetid_t psid;
|
||||
int error;
|
||||
|
||||
/* Available only for super-user */
|
||||
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL))
|
||||
return EPERM;
|
||||
|
||||
error = kern_pset_create(&psid);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = copyout(&psid, SCARG(uap, psid), sizeof(psetid_t));
|
||||
if (error)
|
||||
(void)kern_pset_destroy(psid);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
sys_pset_destroy(struct lwp *l, const struct sys_pset_destroy_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(psetid_t) psid;
|
||||
} */
|
||||
|
||||
/* Available only for super-user */
|
||||
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL))
|
||||
return EPERM;
|
||||
|
||||
return kern_pset_destroy(SCARG(uap, psid));
|
||||
}
|
||||
|
||||
int
|
||||
sys_pset_assign(struct lwp *l, const struct sys_pset_assign_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(psetid_t) psid;
|
||||
syscallarg(cpuid_t) cpuid;
|
||||
syscallarg(psetid_t) *opsid;
|
||||
} */
|
||||
struct cpu_info *ci;
|
||||
struct schedstate_percpu *spc;
|
||||
psetid_t psid = SCARG(uap, psid), opsid = 0;
|
||||
CPU_INFO_ITERATOR cii;
|
||||
int error = 0;
|
||||
|
||||
/* Available only for super-user, except the case of PS_QUERY */
|
||||
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL) &&
|
||||
psid != PS_QUERY)
|
||||
return EPERM;
|
||||
|
||||
/* Find the target CPU */
|
||||
for (CPU_INFO_FOREACH(cii, ci))
|
||||
if (cpu_index(ci) == SCARG(uap, cpuid))
|
||||
break;
|
||||
if (ci == NULL)
|
||||
return EINVAL;
|
||||
spc = &ci->ci_schedstate;
|
||||
|
||||
mutex_enter(&psets_lock);
|
||||
error = psid_validate(psid, true);
|
||||
if (error) {
|
||||
mutex_exit(&psets_lock);
|
||||
return error;
|
||||
}
|
||||
opsid = spc->spc_psid;
|
||||
switch (psid) {
|
||||
case PS_QUERY:
|
||||
break;
|
||||
case PS_MYID:
|
||||
psid = curlwp->l_psid;
|
||||
default:
|
||||
spc->spc_psid = psid;
|
||||
}
|
||||
mutex_exit(&psets_lock);
|
||||
|
||||
if (SCARG(uap, opsid) != NULL)
|
||||
error = copyout(&opsid, SCARG(uap, opsid), sizeof(psetid_t));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
sys__pset_bind(struct lwp *l, const struct sys__pset_bind_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(idtype_t) idtype;
|
||||
syscallarg(id_t) first_id;
|
||||
syscallarg(id_t) second_id;
|
||||
syscallarg(psetid_t) psid;
|
||||
syscallarg(psetid_t) *opsid;
|
||||
} */
|
||||
struct cpu_info *ci;
|
||||
struct proc *p;
|
||||
struct lwp *t;
|
||||
id_t id1, id2;
|
||||
pid_t pid = 0;
|
||||
lwpid_t lid = 0;
|
||||
psetid_t psid, opsid;
|
||||
int error = 0, lcnt;
|
||||
|
||||
psid = SCARG(uap, psid);
|
||||
|
||||
/* Available only for super-user, except the case of PS_QUERY */
|
||||
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL) &&
|
||||
psid != PS_QUERY)
|
||||
return EPERM;
|
||||
|
||||
mutex_enter(&psets_lock);
|
||||
error = psid_validate(psid, true);
|
||||
if (error) {
|
||||
mutex_exit(&psets_lock);
|
||||
return error;
|
||||
}
|
||||
if (psid == PS_MYID)
|
||||
psid = curlwp->l_psid;
|
||||
if (psid != PS_QUERY && psid != PS_NONE)
|
||||
psets[psid - 1]->ps_flags |= PSET_BUSY;
|
||||
mutex_exit(&psets_lock);
|
||||
|
||||
/*
|
||||
* Get PID and LID from the ID.
|
||||
*/
|
||||
p = l->l_proc;
|
||||
id1 = SCARG(uap, first_id);
|
||||
id2 = SCARG(uap, second_id);
|
||||
|
||||
switch (SCARG(uap, idtype)) {
|
||||
case P_PID:
|
||||
/*
|
||||
* Process:
|
||||
* First ID - PID;
|
||||
* Second ID - ignored;
|
||||
*/
|
||||
pid = (id1 == P_MYID) ? p->p_pid : id1;
|
||||
lid = 0;
|
||||
break;
|
||||
case P_LWPID:
|
||||
/*
|
||||
* Thread (LWP):
|
||||
* First ID - LID;
|
||||
* Second ID - PID;
|
||||
*/
|
||||
if (id1 == P_MYID) {
|
||||
pid = p->p_pid;
|
||||
lid = l->l_lid;
|
||||
break;
|
||||
}
|
||||
lid = id1;
|
||||
pid = (id2 == P_MYID) ? p->p_pid : id2;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Find the process */
|
||||
p = p_find(pid, PFIND_UNLOCK_FAIL);
|
||||
if (p == NULL) {
|
||||
error = ESRCH;
|
||||
goto error;
|
||||
}
|
||||
mutex_enter(&p->p_smutex);
|
||||
mutex_exit(&proclist_lock);
|
||||
|
||||
/* Disallow modification of the system processes */
|
||||
if (p->p_flag & PK_SYSTEM) {
|
||||
mutex_exit(&p->p_smutex);
|
||||
error = EPERM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Find the LWP(s) */
|
||||
lcnt = 0;
|
||||
ci = NULL;
|
||||
LIST_FOREACH(t, &p->p_lwps, l_sibling) {
|
||||
if (lid && lid != t->l_lid)
|
||||
continue;
|
||||
/*
|
||||
* Bind the thread to the processor-set,
|
||||
* take some CPU and migrate.
|
||||
*/
|
||||
lwp_lock(t);
|
||||
opsid = t->l_psid;
|
||||
t->l_psid = psid;
|
||||
ci = sched_takecpu(l);
|
||||
/* Unlocks LWP */
|
||||
lwp_migrate(t, ci);
|
||||
lcnt++;
|
||||
}
|
||||
mutex_exit(&p->p_smutex);
|
||||
if (lcnt == 0) {
|
||||
error = ESRCH;
|
||||
goto error;
|
||||
}
|
||||
*retval = lcnt;
|
||||
if (SCARG(uap, opsid))
|
||||
error = copyout(&opsid, SCARG(uap, opsid), sizeof(psetid_t));
|
||||
error:
|
||||
if (psid != PS_QUERY && psid != PS_NONE) {
|
||||
mutex_enter(&psets_lock);
|
||||
psets[psid - 1]->ps_flags &= ~PSET_BUSY;
|
||||
mutex_exit(&psets_lock);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysctl nodes and initialization.
|
||||
*/
|
||||
|
||||
static int
|
||||
sysctl_psets_max(SYSCTLFN_ARGS)
|
||||
{
|
||||
struct sysctlnode node;
|
||||
int error, newsize;
|
||||
|
||||
node = *rnode;
|
||||
node.sysctl_data = &newsize;
|
||||
|
||||
newsize = psets_max;
|
||||
error = sysctl_lookup(SYSCTLFN_CALL(&node));
|
||||
if (error || newp == NULL)
|
||||
return error;
|
||||
|
||||
if (newsize <= 0)
|
||||
return EINVAL;
|
||||
|
||||
sysctl_unlock();
|
||||
error = psets_realloc(newsize);
|
||||
sysctl_relock();
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCTL_SETUP(sysctl_pset_setup, "sysctl kern.pset subtree setup")
|
||||
{
|
||||
const struct sysctlnode *node = NULL;
|
||||
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "kern", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_KERN, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, &node,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "pset",
|
||||
SYSCTL_DESCR("Processor-set options"),
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_KERN, CTL_CREATE, CTL_EOL);
|
||||
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "psets_max",
|
||||
SYSCTL_DESCR("Maximal count of the processor-sets"),
|
||||
sysctl_psets_max, 0, &psets_max, 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
/* $NetBSD: sys_sched.c,v 1.4 2007/12/20 23:03:11 dsl Exp $ */
|
||||
/* $NetBSD: sys_sched.c,v 1.5 2008/01/15 03:37:11 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
/*
|
||||
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
|
@ -12,15 +12,8 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
|
@ -33,14 +26,324 @@
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Handle pthread_setschedprio() as defined by POSIX;
|
||||
* - Handle sched_yield() case for SCHED_FIFO as defined by POSIX;
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sys_sched.c,v 1.4 2007/12/20 23:03:11 dsl Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sys_sched.c,v 1.5 2008/01/15 03:37:11 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/syscallargs.h>
|
||||
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/kauth.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/lwp.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/syscallargs.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
/*
|
||||
* Set scheduling parameters.
|
||||
*/
|
||||
int
|
||||
sys__sched_setparam(struct lwp *l, const struct sys__sched_setparam_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(pid_t) pid;
|
||||
syscallarg(lwpid_t) lid;
|
||||
syscallarg(const struct sched_param *) params;
|
||||
} */
|
||||
struct sched_param *sp;
|
||||
struct proc *p;
|
||||
struct lwp *t;
|
||||
pid_t pid;
|
||||
lwpid_t lid;
|
||||
u_int lcnt;
|
||||
pri_t pri;
|
||||
int error;
|
||||
|
||||
/* Available only for super-user */
|
||||
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL))
|
||||
return EACCES;
|
||||
|
||||
/* Get the parameters from the user-space */
|
||||
sp = kmem_zalloc(sizeof(struct sched_param), KM_SLEEP);
|
||||
error = copyin(SCARG(uap, params), sp, sizeof(struct sched_param));
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Validate scheduling class and priority.
|
||||
* Convert the user priority to the in-kernel value.
|
||||
*/
|
||||
pri = sp->sched_priority;
|
||||
if (pri != PRI_NONE && (pri < SCHED_PRI_MIN || pri > SCHED_PRI_MAX)) {
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
switch (sp->sched_class) {
|
||||
case SCHED_OTHER:
|
||||
if (pri == PRI_NONE)
|
||||
pri = PRI_USER;
|
||||
else
|
||||
pri += PRI_USER;
|
||||
break;
|
||||
case SCHED_RR:
|
||||
case SCHED_FIFO:
|
||||
if (pri == PRI_NONE)
|
||||
pri = PRI_USER_RT;
|
||||
else
|
||||
pri += PRI_USER_RT;
|
||||
break;
|
||||
case SCHED_NONE:
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Find the process */
|
||||
pid = SCARG(uap, pid);
|
||||
p = p_find(pid, PFIND_UNLOCK_FAIL);
|
||||
if (p == NULL) {
|
||||
error = ESRCH;
|
||||
goto error;
|
||||
}
|
||||
mutex_enter(&p->p_smutex);
|
||||
mutex_exit(&proclist_lock);
|
||||
|
||||
/* Disallow modification of system processes */
|
||||
if (p->p_flag & PK_SYSTEM) {
|
||||
mutex_exit(&p->p_smutex);
|
||||
error = EACCES;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Find the LWP(s) */
|
||||
lcnt = 0;
|
||||
lid = SCARG(uap, lid);
|
||||
LIST_FOREACH(t, &p->p_lwps, l_sibling) {
|
||||
bool chpri;
|
||||
|
||||
if (lid && lid != t->l_lid)
|
||||
continue;
|
||||
|
||||
/* Set the scheduling class */
|
||||
lwp_lock(t);
|
||||
if (sp->sched_class != SCHED_NONE) {
|
||||
/*
|
||||
* Priority must be changed to get into the correct
|
||||
* priority range of the new scheduling class.
|
||||
*/
|
||||
chpri = (t->l_class != sp->sched_class);
|
||||
t->l_class = sp->sched_class;
|
||||
} else
|
||||
chpri = false;
|
||||
|
||||
/* Change the priority */
|
||||
if (sp->sched_priority != PRI_NONE || chpri)
|
||||
lwp_changepri(t, pri);
|
||||
|
||||
lwp_unlock(t);
|
||||
lcnt++;
|
||||
}
|
||||
mutex_exit(&p->p_smutex);
|
||||
if (lcnt != 0)
|
||||
*retval = lcnt;
|
||||
else
|
||||
error = ESRCH;
|
||||
error:
|
||||
kmem_free(sp, sizeof(struct sched_param));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get scheduling parameters.
|
||||
*/
|
||||
int
|
||||
sys__sched_getparam(struct lwp *l, const struct sys__sched_getparam_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(pid_t) pid;
|
||||
syscallarg(lwpid_t) lid;
|
||||
syscallarg(struct sched_param *) params;
|
||||
} */
|
||||
struct sched_param *sp;
|
||||
struct lwp *t;
|
||||
int error;
|
||||
|
||||
sp = kmem_zalloc(sizeof(struct sched_param), KM_SLEEP);
|
||||
|
||||
/* Locks the LWP */
|
||||
t = lwp_find2(SCARG(uap, pid), SCARG(uap, lid));
|
||||
if (t == NULL) {
|
||||
kmem_free(sp, sizeof(struct sched_param));
|
||||
return ESRCH;
|
||||
}
|
||||
sp->sched_priority = t->l_priority;
|
||||
sp->sched_class = t->l_class;
|
||||
lwp_unlock(t);
|
||||
|
||||
switch (sp->sched_class) {
|
||||
case SCHED_OTHER:
|
||||
sp->sched_priority -= PRI_USER;
|
||||
break;
|
||||
case SCHED_RR:
|
||||
case SCHED_FIFO:
|
||||
sp->sched_priority -= PRI_USER_RT;
|
||||
break;
|
||||
}
|
||||
error = copyout(sp, SCARG(uap, params), sizeof(struct sched_param));
|
||||
kmem_free(sp, sizeof(struct sched_param));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set affinity.
|
||||
*/
|
||||
int
|
||||
sys__sched_setaffinity(struct lwp *l,
|
||||
const struct sys__sched_setaffinity_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(pid_t) pid;
|
||||
syscallarg(lwpid_t) lid;
|
||||
syscallarg(size_t) size;
|
||||
syscallarg(void *) cpuset;
|
||||
} */
|
||||
cpuset_t *cpuset;
|
||||
struct cpu_info *ci = NULL;
|
||||
struct proc *p;
|
||||
struct lwp *t;
|
||||
CPU_INFO_ITERATOR cii;
|
||||
lwpid_t lid;
|
||||
u_int lcnt;
|
||||
int error;
|
||||
|
||||
/* Available only for super-user */
|
||||
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL))
|
||||
return EACCES;
|
||||
|
||||
if (SCARG(uap, size) <= 0)
|
||||
return EINVAL;
|
||||
|
||||
/* Allocate the CPU set, and get it from userspace */
|
||||
cpuset = kmem_zalloc(sizeof(cpuset_t), KM_SLEEP);
|
||||
error = copyin(SCARG(uap, cpuset), cpuset,
|
||||
min(SCARG(uap, size), sizeof(cpuset_t)));
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
/* Look for a CPU in the set */
|
||||
for (CPU_INFO_FOREACH(cii, ci))
|
||||
if (CPU_ISSET(cpu_index(ci), cpuset))
|
||||
break;
|
||||
if (ci == NULL) {
|
||||
/* Empty set */
|
||||
kmem_free(cpuset, sizeof(cpuset_t));
|
||||
cpuset = NULL;
|
||||
}
|
||||
|
||||
/* Find the process */
|
||||
p = p_find(SCARG(uap, pid), PFIND_UNLOCK_FAIL);
|
||||
if (p == NULL) {
|
||||
error = ESRCH;
|
||||
goto error;
|
||||
}
|
||||
mutex_enter(&p->p_smutex);
|
||||
mutex_exit(&proclist_lock);
|
||||
|
||||
/* Disallow modification of system processes */
|
||||
if (p->p_flag & PK_SYSTEM) {
|
||||
mutex_exit(&p->p_smutex);
|
||||
error = EACCES;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Find the LWP(s) */
|
||||
lcnt = 0;
|
||||
lid = SCARG(uap, lid);
|
||||
LIST_FOREACH(t, &p->p_lwps, l_sibling) {
|
||||
if (lid && lid != t->l_lid)
|
||||
continue;
|
||||
lwp_lock(t);
|
||||
if (cpuset) {
|
||||
/* Set the affinity flag and new CPU set */
|
||||
t->l_flag |= LW_AFFINITY;
|
||||
memcpy(&t->l_affinity, cpuset, sizeof(cpuset_t));
|
||||
/* Migrate to another CPU, unlocks LWP */
|
||||
lwp_migrate(t, ci);
|
||||
} else {
|
||||
/* Unset the affinity flag */
|
||||
t->l_flag &= ~LW_AFFINITY;
|
||||
lwp_unlock(t);
|
||||
}
|
||||
lcnt++;
|
||||
}
|
||||
mutex_exit(&p->p_smutex);
|
||||
if (lcnt == 0)
|
||||
error = ESRCH;
|
||||
else
|
||||
*retval = lcnt;
|
||||
error:
|
||||
if (cpuset != NULL)
|
||||
kmem_free(cpuset, sizeof(cpuset_t));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get affinity.
|
||||
*/
|
||||
int
|
||||
sys__sched_getaffinity(struct lwp *l,
|
||||
const struct sys__sched_getaffinity_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(pid_t) pid;
|
||||
syscallarg(lwpid_t) lid;
|
||||
syscallarg(size_t) size;
|
||||
syscallarg(void *) cpuset;
|
||||
} */
|
||||
struct lwp *t;
|
||||
void *cpuset;
|
||||
int error;
|
||||
|
||||
if (SCARG(uap, size) <= 0)
|
||||
return EINVAL;
|
||||
|
||||
cpuset = kmem_zalloc(sizeof(cpuset_t), KM_SLEEP);
|
||||
|
||||
/* Locks the LWP */
|
||||
t = lwp_find2(SCARG(uap, pid), SCARG(uap, lid));
|
||||
if (t == NULL) {
|
||||
kmem_free(cpuset, sizeof(cpuset_t));
|
||||
return ESRCH;
|
||||
}
|
||||
if (t->l_flag & LW_AFFINITY)
|
||||
memcpy(cpuset, &t->l_affinity, sizeof(cpuset_t));
|
||||
lwp_unlock(t);
|
||||
|
||||
error = copyout(cpuset, SCARG(uap, cpuset),
|
||||
min(SCARG(uap, size), sizeof(cpuset_t)));
|
||||
|
||||
kmem_free(cpuset, sizeof(cpuset_t));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Yield.
|
||||
*/
|
||||
int
|
||||
sys_sched_yield(struct lwp *l, const void *v, register_t *retval)
|
||||
{
|
||||
|
@ -48,3 +351,47 @@ sys_sched_yield(struct lwp *l, const void *v, register_t *retval)
|
|||
yield();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysctl nodes and initialization.
|
||||
*/
|
||||
SYSCTL_SETUP(sysctl_sched_setup, "sysctl sched setup")
|
||||
{
|
||||
const struct sysctlnode *node = NULL;
|
||||
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "kern", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_KERN, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
|
||||
CTLTYPE_INT, "posix_sched",
|
||||
SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
|
||||
"Process Scheduling option to which the "
|
||||
"system attempts to conform"),
|
||||
NULL, _POSIX_PRIORITY_SCHEDULING, NULL, 0,
|
||||
CTL_KERN, CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, &node,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "sched",
|
||||
SYSCTL_DESCR("Scheduler options"),
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_KERN, CTL_CREATE, CTL_EOL);
|
||||
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_PERMANENT | CTLFLAG_IMMEDIATE,
|
||||
CTLTYPE_INT, "pri_min",
|
||||
SYSCTL_DESCR("Minimal POSIX real-time priority"),
|
||||
NULL, SCHED_PRI_MIN, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, &node, NULL,
|
||||
CTLFLAG_PERMANENT | CTLFLAG_IMMEDIATE,
|
||||
CTLTYPE_INT, "pri_max",
|
||||
SYSCTL_DESCR("Minimal POSIX real-time priority"),
|
||||
NULL, SCHED_PRI_MAX, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$NetBSD: syscalls.master,v 1.183 2008/01/07 16:15:36 ad Exp $
|
||||
$NetBSD: syscalls.master,v 1.184 2008/01/15 03:37:11 rmind Exp $
|
||||
|
||||
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
|
||||
|
||||
|
@ -696,17 +696,20 @@
|
|||
const struct kevent *changelist, size_t nchanges, \
|
||||
struct kevent *eventlist, size_t nevents, \
|
||||
const struct timespec *timeout); }
|
||||
;
|
||||
; Syscalls 346-353 are reserved for the IEEE Std1003.1b scheduling syscalls
|
||||
;
|
||||
346 UNIMPL sys_sched_setparam
|
||||
347 UNIMPL sys_sched_getparam
|
||||
348 UNIMPL sys_sched_setscheduler
|
||||
349 UNIMPL sys_sched_getscheduler
|
||||
|
||||
; Scheduling system calls.
|
||||
346 STD MPSAFE { int sys__sched_setparam(pid_t pid, lwpid_t lid, \
|
||||
const struct sched_param *params); }
|
||||
347 STD MPSAFE { int sys__sched_getparam(pid_t pid, lwpid_t lid, \
|
||||
struct sched_param *params); }
|
||||
348 STD MPSAFE { int sys__sched_setaffinity(pid_t pid, lwpid_t lid, \
|
||||
size_t size, void *cpuset); }
|
||||
349 STD MPSAFE { int sys__sched_getaffinity(pid_t pid, lwpid_t lid, \
|
||||
size_t size, void *cpuset); }
|
||||
350 STD MPSAFE { int sys_sched_yield(void); }
|
||||
351 UNIMPL sys_sched_get_priority_max
|
||||
352 UNIMPL sys_sched_get_priority_min
|
||||
353 UNIMPL sys_sched_rr_get_interval
|
||||
351 UNIMPL
|
||||
352 UNIMPL
|
||||
353 UNIMPL
|
||||
|
||||
354 STD MPSAFE { int sys_fsync_range(int fd, int flags, off_t start, \
|
||||
off_t length); }
|
||||
|
@ -824,3 +827,11 @@
|
|||
size_t data_len); }
|
||||
411 STD MPSAFE { void *sys_mremap(void *old_address, size_t old_size, \
|
||||
void *new_address, size_t new_size, int flags); }
|
||||
|
||||
; Processor-sets system calls
|
||||
412 STD MPSAFE { int sys_pset_create(psetid_t *psid); }
|
||||
413 STD MPSAFE { int sys_pset_destroy(psetid_t psid); }
|
||||
414 STD MPSAFE { int sys_pset_assign(psetid_t psid, cpuid_t cpuid, \
|
||||
psetid_t *opsid); }
|
||||
415 STD MPSAFE { int sys__pset_bind(idtype_t idtype, id_t first_id, \
|
||||
id_t second_id, psetid_t psid, psetid_t *opsid); }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile,v 1.106 2007/12/31 15:32:14 ad Exp $
|
||||
# $NetBSD: Makefile,v 1.107 2008/01/15 03:37:12 rmind Exp $
|
||||
|
||||
.include <bsd.sys.mk>
|
||||
|
||||
|
@ -23,7 +23,7 @@ INCS= acct.h agpio.h aio.h ansi.h ataio.h atomic.h audioio.h \
|
|||
md5.h midiio.h mman.h mount.h mqueue.h msg.h msgbuf.h mtio.h mutex.h \
|
||||
namei.h null.h \
|
||||
param.h pipe.h pmc.h poll.h pool.h power.h proc.h \
|
||||
protosw.h ptrace.h queue.h \
|
||||
protosw.h pset.h ptrace.h queue.h \
|
||||
ras.h reboot.h radioio.h resource.h resourcevar.h rmd160.h rnd.h rwlock.h \
|
||||
scanio.h sched.h scsiio.h select.h selinfo.h sem.h sha1.h sha2.h \
|
||||
shm.h siginfo.h signal.h signalvar.h sigtypes.h simplelock.h \
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lwp.h,v 1.76 2008/01/07 16:12:56 ad Exp $ */
|
||||
/* $NetBSD: lwp.h,v 1.77 2008/01/15 03:37:12 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -44,6 +44,7 @@
|
|||
#include <sys/callout.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/specificdata.h>
|
||||
#include <sys/syncobj.h>
|
||||
|
@ -98,9 +99,12 @@ struct lwp {
|
|||
int l_cpticks; /* t: Ticks of CPU time */
|
||||
fixpt_t l_pctcpu; /* t: %cpu during l_swtime */
|
||||
fixpt_t l_estcpu; /* l: cpu time for SCHED_4BSD */
|
||||
psetid_t l_psid; /* l: assigned processor-set ID */
|
||||
struct cpu_info *l_target_cpu; /* l: target CPU to migrate */
|
||||
kmutex_t l_swaplock; /* l: lock to prevent swapping */
|
||||
struct lwpctl *l_lwpctl; /* p: lwpctl block kernel address */
|
||||
struct lcpage *l_lcpage; /* p: lwpctl containing page */
|
||||
cpuset_t l_affinity; /* l: CPU set for affinity */
|
||||
|
||||
/* Synchronisation */
|
||||
struct turnstile *l_ts; /* l: current turnstile */
|
||||
|
@ -191,6 +195,7 @@ extern lwp_t lwp0; /* LWP for proc0 */
|
|||
#define LW_WSUSPEND 0x00020000 /* Suspend before return to user */
|
||||
#define LW_WCORE 0x00080000 /* Stop for core dump on return to user */
|
||||
#define LW_WEXIT 0x00100000 /* Exit before return to user */
|
||||
#define LW_AFFINITY 0x00200000 /* Affinity is assigned to the thread */
|
||||
#define LW_PENDSIG 0x01000000 /* Pending signal for us */
|
||||
#define LW_CANCELLED 0x02000000 /* tsleep should not sleep */
|
||||
#define LW_WUSERRET 0x04000000 /* Call proc::p_userret on return to user */
|
||||
|
@ -270,7 +275,9 @@ lwp_t *proc_representative_lwp(struct proc *, int *, int);
|
|||
int lwp_suspend(lwp_t *, lwp_t *);
|
||||
int lwp_create1(lwp_t *, const void *, size_t, u_long, lwpid_t *);
|
||||
void lwp_update_creds(lwp_t *);
|
||||
lwp_t *lwp_find(struct proc *, int);
|
||||
void lwp_migrate(lwp_t *, struct cpu_info *);
|
||||
lwp_t *lwp_find2(pid_t, lwpid_t);
|
||||
lwp_t *lwp_find(proc_t *, int);
|
||||
void lwp_userret(lwp_t *);
|
||||
void lwp_need_userret(lwp_t *);
|
||||
void lwp_free(lwp_t *, bool, bool);
|
||||
|
@ -382,6 +389,39 @@ spc_unlock(struct cpu_info *ci)
|
|||
mutex_spin_exit(ci->ci_schedstate.spc_mutex);
|
||||
}
|
||||
|
||||
static inline void
|
||||
spc_dlock(struct cpu_info *ci1, struct cpu_info *ci2)
|
||||
{
|
||||
struct schedstate_percpu *spc1 = &ci1->ci_schedstate;
|
||||
struct schedstate_percpu *spc2 = &ci2->ci_schedstate;
|
||||
|
||||
KASSERT(ci1 != ci2);
|
||||
if (spc1->spc_mutex == spc2->spc_mutex) {
|
||||
mutex_spin_enter(spc1->spc_mutex);
|
||||
} else if (ci1 < ci2) {
|
||||
mutex_spin_enter(spc1->spc_mutex);
|
||||
mutex_spin_enter(spc2->spc_mutex);
|
||||
} else {
|
||||
mutex_spin_enter(spc2->spc_mutex);
|
||||
mutex_spin_enter(spc1->spc_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
spc_dunlock(struct cpu_info *ci1, struct cpu_info *ci2)
|
||||
{
|
||||
struct schedstate_percpu *spc1 = &ci1->ci_schedstate;
|
||||
struct schedstate_percpu *spc2 = &ci2->ci_schedstate;
|
||||
|
||||
KASSERT(ci1 != ci2);
|
||||
if (spc1->spc_mutex == spc2->spc_mutex) {
|
||||
mutex_spin_exit(spc1->spc_mutex);
|
||||
} else {
|
||||
mutex_spin_exit(spc1->spc_mutex);
|
||||
mutex_spin_exit(spc2->spc_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/* Flags for _lwp_create(), as per Solaris. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: param.h,v 1.299 2008/01/09 16:16:27 ad Exp $ */
|
||||
/* $NetBSD: param.h,v 1.300 2008/01/15 03:37:12 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
|
@ -244,6 +244,10 @@
|
|||
#define NPRI_USER 64
|
||||
#define MAXPRI_USER (PRI_USER + NPRI_USER - 1)
|
||||
|
||||
/* Priority range used by POSIX real-time features */
|
||||
#define SCHED_PRI_MIN 0
|
||||
#define SCHED_PRI_MAX 63
|
||||
|
||||
/*
|
||||
* Kernel thread priorities.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* $NetBSD: pset.h,v 1.1 2008/01/15 03:41:50 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_PSET_H_
|
||||
#define _SYS_PSET_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Types of processor-sets */
|
||||
#define PS_NONE 0
|
||||
#define PS_MYID -1
|
||||
#define PS_QUERY -2
|
||||
|
||||
/* ID types for processor-set calls */
|
||||
#define P_MYID -1
|
||||
#define P_PID 1
|
||||
#define P_LWPID 2
|
||||
|
||||
/* For compatibility only */
|
||||
typedef cpuid_t processorid_t;
|
||||
|
||||
__BEGIN_DECLS
|
||||
int pset_assign(psetid_t, cpuid_t, psetid_t *);
|
||||
int pset_bind(psetid_t, idtype_t, id_t, psetid_t *);
|
||||
int pset_create(psetid_t *);
|
||||
int pset_destroy(psetid_t);
|
||||
__END_DECLS
|
||||
|
||||
/* Size of the CPU set bitmap */
|
||||
#define CPUSET_SHIFT 5
|
||||
#define CPUSET_MASK 31
|
||||
#if MAXCPUS > 32
|
||||
#define CPUSET_SIZE (MAXCPUS >> CPUSET_SHIFT)
|
||||
#else
|
||||
#define CPUSET_SIZE 1
|
||||
#endif
|
||||
|
||||
/* Bitmap of the CPUs */
|
||||
typedef struct {
|
||||
uint32_t bits[CPUSET_SIZE];
|
||||
} cpuset_t;
|
||||
|
||||
#define CPU_ZERO(c) \
|
||||
(memset(c, 0, sizeof(cpuset_t)))
|
||||
|
||||
#define CPU_ISSET(i, c) \
|
||||
((1 << (i & CPUSET_MASK)) & (c)->bits[i >> CPUSET_SHIFT])
|
||||
|
||||
#define CPU_SET(i, c) \
|
||||
((c)->bits[i >> CPUSET_SHIFT] |= 1 << (i & CPUSET_MASK))
|
||||
|
||||
#define CPU_CLR(i, c) \
|
||||
((c)->bits[i >> CPUSET_SHIFT] &= ~(1 << (i & CPUSET_MASK)))
|
||||
|
||||
#ifdef _NETBSD_SOURCE
|
||||
int _pset_bind(idtype_t, id_t, id_t, psetid_t, psetid_t *);
|
||||
#endif /* _NETBSD_SOURCE */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
/* Processor-set structure */
|
||||
typedef struct {
|
||||
int ps_flags;
|
||||
} pset_info_t;
|
||||
|
||||
/* Flags */
|
||||
#define PSET_BUSY 0x01
|
||||
|
||||
void psets_init(void);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _SYS_PSET_H_ */
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sched.h,v 1.44 2007/12/22 01:14:53 yamt Exp $ */
|
||||
/* $NetBSD: sched.h,v 1.45 2008/01/15 03:37:12 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -77,6 +77,7 @@
|
|||
#define _SYS_SCHED_H_
|
||||
|
||||
#include <sys/featuretest.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_multiprocessor.h"
|
||||
|
@ -84,20 +85,27 @@
|
|||
#endif
|
||||
|
||||
struct sched_param {
|
||||
int sched_class;
|
||||
int sched_priority;
|
||||
int _reserved1;
|
||||
int _reserved2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Scheduling policies required by IEEE Std 1003.1-2001
|
||||
*/
|
||||
#define SCHED_OTHER 0 /* Behavior can be FIFO or RR, or not */
|
||||
#define SCHED_NONE -1
|
||||
#define SCHED_OTHER 0
|
||||
#define SCHED_FIFO 1
|
||||
#define SCHED_RR 2
|
||||
|
||||
/* Other nonstandard policies: */
|
||||
|
||||
#if defined(_NETBSD_SOURCE)
|
||||
|
||||
int _sched_getaffinity(pid_t, lwpid_t, size_t, void *);
|
||||
int _sched_setaffinity(pid_t, lwpid_t, size_t, void *);
|
||||
int _sched_getparam(pid_t, lwpid_t, struct sched_param *);
|
||||
int _sched_setparam(pid_t, lwpid_t, const struct sched_param *);
|
||||
|
||||
/*
|
||||
* CPU states.
|
||||
* XXX Not really scheduler state, but no other good place to put
|
||||
|
@ -128,6 +136,7 @@ struct schedstate_percpu {
|
|||
kmutex_t *spc_mutex; /* (: lock on below, runnable LWPs */
|
||||
kmutex_t spc_lwplock; /* (: general purpose lock for LWPs */
|
||||
pri_t spc_curpriority;/* m: usrpri of curlwp */
|
||||
psetid_t spc_psid; /* (: processor-set ID */
|
||||
time_t spc_lastmod; /* c: time of last cpu state change */
|
||||
|
||||
/* For the most part, this set of data is CPU-private. */
|
||||
|
@ -163,7 +172,7 @@ struct schedstate_percpu {
|
|||
#define CLONE_VFORK 0x00004000 /* parent blocks until child
|
||||
exits */
|
||||
|
||||
#endif /* !_POSIX_SOURCE && !_XOPEN_SOURCE && !_ANSI_SOURCE */
|
||||
#endif /* _NETBSD_SOURCE */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: types.h,v 1.77 2007/09/07 18:56:13 rmind Exp $ */
|
||||
/* $NetBSD: types.h,v 1.78 2008/01/15 03:37:12 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1991, 1993, 1994
|
||||
|
@ -164,6 +164,7 @@ typedef __gid_t gid_t; /* group id */
|
|||
#define gid_t __gid_t
|
||||
#endif
|
||||
|
||||
typedef int idtype_t; /* type of the id */
|
||||
typedef uint32_t id_t; /* group id, process id or user id */
|
||||
typedef uint64_t ino_t; /* inode number */
|
||||
typedef long key_t; /* IPC key (for Sys V IPC) */
|
||||
|
@ -198,6 +199,8 @@ typedef int32_t dtime_t; /* on-disk time_t */
|
|||
|
||||
typedef int mqd_t;
|
||||
|
||||
typedef int psetid_t;
|
||||
|
||||
#if defined(_KERNEL) || defined(_STANDALONE)
|
||||
/*
|
||||
* Boolean type definitions for the kernel environment. User-space
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: unistd.h,v 1.39 2007/10/15 14:12:55 ad Exp $ */
|
||||
/* $NetBSD: unistd.h,v 1.40 2008/01/15 03:37:12 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
|
@ -87,6 +87,8 @@
|
|||
#define _POSIX_MESSAGE_PASSING 200112L
|
||||
/* monotonic clock */
|
||||
#define _POSIX_MONOTONIC_CLOCK 200112L
|
||||
/* priority scheduling */
|
||||
#define _POSIX_PRIORITY_SCHEDULING 200112L
|
||||
/* threads */
|
||||
#define _POSIX_THREADS 200112L
|
||||
/* semaphores */
|
||||
|
@ -206,11 +208,16 @@
|
|||
#define _SC_MESSAGE_PASSING 53
|
||||
#define _SC_MQ_OPEN_MAX 54
|
||||
#define _SC_MQ_PRIO_MAX 55
|
||||
#define _SC_PRIORITY_SCHEDULING 56
|
||||
|
||||
#ifdef _NETBSD_SOURCE
|
||||
/* Commonly provided sysconf() extensions */
|
||||
#define _SC_NPROCESSORS_CONF 1001
|
||||
#define _SC_NPROCESSORS_ONLN 1002
|
||||
/* Native variables */
|
||||
#define _SC_SCHED_RT_TS 2001
|
||||
#define _SC_SCHED_PRI_MIN 2002
|
||||
#define _SC_SCHED_PRI_MAX 2003
|
||||
#endif /* _NETBSD_SOURCE */
|
||||
|
||||
/* configurable system strings */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: getconf.c,v 1.30 2007/12/15 19:44:50 perry Exp $ */
|
||||
/* $NetBSD: getconf.c,v 1.31 2008/01/15 03:37:12 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: getconf.c,v 1.30 2007/12/15 19:44:50 perry Exp $");
|
||||
__RCSID("$NetBSD: getconf.c,v 1.31 2008/01/15 03:37:12 rmind Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <err.h>
|
||||
|
@ -152,6 +152,7 @@ static const struct conf_variable conf_table[] =
|
|||
{ "_POSIX_MEMORY_PROTECTION", SYSCONF, _SC_MEMORY_PROTECTION },
|
||||
{ "_POSIX_MESSAGE_PASSING", SYSCONF, _POSIX_MESSAGE_PASSING },
|
||||
{ "_POSIX_MONOTONIC_CLOCK", SYSCONF, _SC_MONOTONIC_CLOCK },
|
||||
{ "_POSIX_PRIORITY_SCHEDULING", SYSCONF, _SC_PRIORITY_SCHEDULING },
|
||||
{ "_POSIX_SEMAPHORES", SYSCONF, _SC_SEMAPHORES },
|
||||
{ "_POSIX_SYNCHRONIZED_IO", SYSCONF, _SC_SYNCHRONIZED_IO },
|
||||
{ "_POSIX_TIMERS", SYSCONF, _SC_TIMERS },
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile,v 1.229 2007/08/04 11:03:03 ad Exp $
|
||||
# $NetBSD: Makefile,v 1.230 2008/01/15 03:37:15 rmind Exp $
|
||||
# from: @(#)Makefile 5.20 (Berkeley) 6/12/93
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
@ -19,7 +19,7 @@ SUBDIR= ac accton acpitools altq amd apm apmd arp bad144 bind bootp \
|
|||
rarpd rbootd rdate \
|
||||
repquota rmt rpc.bootparamd rpc.lockd rpc.pcnfsd \
|
||||
rpc.statd rpcbind rwhod sa screenblank sdpd services_mkdb sesd \
|
||||
sliplogin sntp \
|
||||
schedctl sliplogin sntp \
|
||||
spray srtconfig sti sunlabel sup syslogd tadpolectl tcpdchk \
|
||||
tcpdmatch tcpdump tcpdrop timed tpctl traceroute trpt unlink \
|
||||
usbdevs user videomode vipw veriexecgen vnconfig wiconfig wlanctl wpa \
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# $NetBSD: Makefile,v 1.1 2008/01/15 03:37:15 rmind Exp $
|
||||
|
||||
PROG= schedctl
|
||||
MAN=
|
||||
|
||||
LDADD+= -lrt -lkvm
|
||||
|
||||
WARNS= 4
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -0,0 +1,298 @@
|
|||
/* $NetBSD: schedctl.c,v 1.1 2008/01/15 03:37:15 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* schedctl(8) - a program to control scheduling of processes and threads.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: schedctl.c,v 1.1 2008/01/15 03:37:15 rmind Exp $");
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/pset.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static const char *class_str[] = {
|
||||
"SCHED_OTHER",
|
||||
"SCHED_FIFO",
|
||||
"SCHED_RR"
|
||||
};
|
||||
|
||||
static void sched_set(pid_t, lwpid_t, struct sched_param *, cpuset_t *);
|
||||
static void thread_info(pid_t, lwpid_t);
|
||||
static cpuset_t *makecpuset(char *);
|
||||
static char *showcpuset(cpuset_t *);
|
||||
static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
kvm_t *kd;
|
||||
struct kinfo_lwp *lwp_list, *lwp;
|
||||
struct sched_param *sp;
|
||||
cpuset_t *cpuset;
|
||||
int i, count, ch;
|
||||
pid_t pid;
|
||||
lwpid_t lid;
|
||||
bool set;
|
||||
|
||||
pid = lid = 0;
|
||||
cpuset = NULL;
|
||||
set = false;
|
||||
|
||||
sp = malloc(sizeof(struct sched_param));
|
||||
if (sp == NULL)
|
||||
err(EXIT_FAILURE, "malloc");
|
||||
|
||||
memset(sp, 0, sizeof(struct sched_param));
|
||||
sp->sched_class = SCHED_NONE;
|
||||
sp->sched_priority = PRI_NONE;
|
||||
|
||||
while ((ch = getopt(argc, argv, "A:C:P:p:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
/* PID */
|
||||
pid = atoi(optarg);
|
||||
break;
|
||||
case 't':
|
||||
/* Thread (LWP) ID */
|
||||
lid = atoi(optarg);
|
||||
break;
|
||||
case 'A':
|
||||
/* Affinity */
|
||||
cpuset = makecpuset(optarg);
|
||||
if (cpuset == NULL) {
|
||||
fprintf(stderr, "%s: invalid CPU value\n",
|
||||
getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
/* Scheduling class */
|
||||
sp->sched_class = atoi(optarg);
|
||||
if (sp->sched_class < SCHED_OTHER ||
|
||||
sp->sched_class > SCHED_RR) {
|
||||
fprintf(stderr,
|
||||
"%s: invalid scheduling class\n",
|
||||
getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
set = true;
|
||||
break;
|
||||
case 'P':
|
||||
/* Priority */
|
||||
sp->sched_priority = atoi(optarg);
|
||||
if (sp->sched_priority < sysconf(_SC_SCHED_PRI_MIN) ||
|
||||
sp->sched_priority > sysconf(_SC_SCHED_PRI_MAX)) {
|
||||
fprintf(stderr, "%s: invalid priority\n",
|
||||
getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
set = true;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/* At least PID must be specified */
|
||||
if (pid == 0)
|
||||
usage();
|
||||
|
||||
/* Set the scheduling information for thread/process */
|
||||
sched_set(pid, lid, set ? sp : NULL, cpuset);
|
||||
|
||||
/* Show information about each thread */
|
||||
kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
|
||||
if (kd == NULL)
|
||||
err(EXIT_FAILURE, "kvm_open");
|
||||
lwp_list = kvm_getlwps(kd, pid, 0, sizeof(struct kinfo_lwp), &count);
|
||||
if (lwp_list == NULL)
|
||||
err(EXIT_FAILURE, "kvm_getlwps");
|
||||
for (lwp = lwp_list, i = 0; i < count; lwp++, i++) {
|
||||
if (lid && lid != lwp->l_lid)
|
||||
continue;
|
||||
thread_info(pid, lwp->l_lid);
|
||||
}
|
||||
kvm_close(kd);
|
||||
|
||||
free(sp);
|
||||
free(cpuset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sched_set(pid_t pid, lwpid_t lid, struct sched_param *sp, cpuset_t *cpuset)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (sp) {
|
||||
/* Set the scheduling parameters for the thread */
|
||||
error = _sched_setparam(pid, lid, sp);
|
||||
if (error < 0)
|
||||
err(EXIT_FAILURE, "_sched_setparam");
|
||||
}
|
||||
if (cpuset) {
|
||||
/* Set the CPU-set for affinity */
|
||||
error = _sched_setaffinity(pid, lid,
|
||||
sizeof(cpuset_t), cpuset);
|
||||
if (error < 0)
|
||||
err(EXIT_FAILURE, "_sched_setaffinity");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
thread_info(pid_t pid, lwpid_t lid)
|
||||
{
|
||||
struct sched_param sp;
|
||||
cpuset_t *cpuset;
|
||||
char *cpus;
|
||||
int error;
|
||||
|
||||
cpuset = malloc(sizeof(cpuset_t));
|
||||
if (cpuset == NULL)
|
||||
err(EXIT_FAILURE, "malloc");
|
||||
|
||||
error = _sched_getparam(pid, lid, &sp);
|
||||
if (error < 0)
|
||||
err(EXIT_FAILURE, "_sched_getparam");
|
||||
|
||||
error = _sched_getaffinity(pid, lid, sizeof(cpuset_t), cpuset);
|
||||
if (error < 0)
|
||||
err(EXIT_FAILURE, "_sched_getaffinity");
|
||||
|
||||
printf(" LID: %d\n", lid);
|
||||
printf(" Priority: %d\n", sp.sched_priority);
|
||||
printf(" Class: %s\n", class_str[sp.sched_class]);
|
||||
|
||||
cpus = showcpuset(cpuset);
|
||||
printf(" Affinity (CPUs): %s\n", cpus);
|
||||
free(cpus);
|
||||
|
||||
free(cpuset);
|
||||
}
|
||||
|
||||
static cpuset_t *
|
||||
makecpuset(char *str)
|
||||
{
|
||||
cpuset_t *cpuset;
|
||||
char *cpustr, *s;
|
||||
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
cpuset = malloc(sizeof(cpuset_t));
|
||||
if (cpuset == NULL)
|
||||
err(EXIT_FAILURE, "malloc");
|
||||
memset(cpuset, 0, sizeof(cpuset_t));
|
||||
|
||||
cpustr = strdup(str);
|
||||
if (cpustr == NULL)
|
||||
err(EXIT_FAILURE, "strdup");
|
||||
s = cpustr;
|
||||
|
||||
while (s != NULL) {
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
/* Get the CPU number and validate the range */
|
||||
p = strsep(&s, ",");
|
||||
if (p == NULL) {
|
||||
free(cpuset);
|
||||
cpuset = NULL;
|
||||
break;
|
||||
}
|
||||
i = atoi(p);
|
||||
if (i == -1) {
|
||||
memset(cpuset, 0, sizeof(cpuset_t));
|
||||
break;
|
||||
}
|
||||
if ((unsigned int)i > MAXCPUS) {
|
||||
free(cpuset);
|
||||
cpuset = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the bit */
|
||||
CPU_SET(i, cpuset);
|
||||
}
|
||||
|
||||
free(cpustr);
|
||||
return cpuset;
|
||||
}
|
||||
|
||||
static char *
|
||||
showcpuset(cpuset_t *cpuset)
|
||||
{
|
||||
char *buf;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
size = 3 * MAXCPUS; /* XXX */
|
||||
buf = malloc(size + 1);
|
||||
if (cpuset == NULL)
|
||||
err(EXIT_FAILURE, "malloc");
|
||||
memset(buf, '\0', size + 1);
|
||||
|
||||
for (i = 0; i < MAXCPUS; i++)
|
||||
if (CPU_ISSET(i, cpuset))
|
||||
snprintf(buf, size, "%s%d,", buf, i);
|
||||
|
||||
i = strlen(buf);
|
||||
if (i != 0) {
|
||||
buf[i - 1] = '\0';
|
||||
} else {
|
||||
strncpy(buf, "<none>", size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
const char *progname = getprogname();
|
||||
|
||||
fprintf(stderr, "usage: %s -p pid [ -t lid ] [ -A processor ]\n"
|
||||
"\t [ -C class ] [ -P priority ]\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
Loading…
Reference in New Issue