summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2000-04-19 09:58:21 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2000-04-19 09:58:21 +0000
commit1eb85a579a0d9030c50d66f0327dee8387ccf303 (patch)
treede76153b3fd63ba73b6b358f5ff3f88c5deda1c2
parentc5af69f27d7fb2fb195805f354bb466926706ff7 (diff)
Remove the roundrobin_attempts hack and replace it with per-process scheduling
flags (much nicer for future smp work). Add two generic functions yield() and preempt(). Use preepmt() in uio when we are told to yield. Based on my idea, code written by Jason Thorpe from NetBSD.
-rw-r--r--sys/kern/kern_subr.c24
-rw-r--r--sys/kern/kern_synch.c86
-rw-r--r--sys/sys/proc.h14
3 files changed, 85 insertions, 39 deletions
diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c
index 7c7550b9861..59a1ebc0d06 100644
--- a/sys/kern/kern_subr.c
+++ b/sys/kern/kern_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_subr.c,v 1.11 2000/03/03 16:58:49 art Exp $ */
+/* $OpenBSD: kern_subr.c,v 1.12 2000/04/19 09:58:20 art Exp $ */
/* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */
/*
@@ -49,10 +49,6 @@
#include <sys/kernel.h>
#include <sys/resourcevar.h>
-void uio_yield __P((struct proc *));
-
-#define UIO_NEED_YIELD (roundrobin_attempts >= 2)
-
int
uiomove(cp, n, uio)
register caddr_t cp;
@@ -85,8 +81,8 @@ uiomove(cp, n, uio)
switch (uio->uio_segflg) {
case UIO_USERSPACE:
- if (UIO_NEED_YIELD)
- uio_yield(p);
+ if (p->p_schedflags & PSCHED_SHOULDYIELD)
+ preempt(NULL);
if (uio->uio_rw == UIO_READ)
error = copyout(cp, iov->iov_base, cnt);
else
@@ -168,20 +164,6 @@ again:
return (0);
}
-void
-uio_yield(p)
- struct proc *p;
-{
- int s;
-
- p->p_priority = p->p_usrpri;
- s = splstatclock();
- setrunqueue(p);
- p->p_stats->p_ru.ru_nivcsw++;
- mi_switch();
- splx(s);
-}
-
/*
* General routine to allocate a hash table.
*/
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 804e830e8bf..59b50786171 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_synch.c,v 1.23 2000/03/23 16:54:43 art Exp $ */
+/* $OpenBSD: kern_synch.c,v 1.24 2000/04/19 09:58:20 art Exp $ */
/* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
/*-
@@ -93,14 +93,6 @@ scheduler_start()
}
/*
- * We need to keep track on how many times we call roundrobin before we
- * actually attempt a switch (that is when we call mi_switch()).
- * This is done so that some slow kernel subsystems can yield instead of
- * blocking the scheduling.
- */
-int roundrobin_attempts;
-
-/*
* Force switch among equal priority processes every 100ms.
*/
/* ARGSUSED */
@@ -109,9 +101,23 @@ roundrobin(arg)
void *arg;
{
struct timeout *to = (struct timeout *)arg;
+ int s;
+ if (curproc != NULL) {
+ s = splstatclock();
+ if (curproc->p_schedflags & PSCHED_SEENRR) {
+ /*
+ * The process has already been through a roundrobin
+ * without switching and may be hogging the CPU.
+ * Indicate that the process should yield.
+ */
+ curproc->p_schedflags |= PSCHED_SHOULDYIELD;
+ } else {
+ curproc->p_schedflags |= PSCHED_SEENRR;
+ }
+ splx(s);
+ }
need_resched();
- roundrobin_attempts++;
timeout_add(to, hz / 10);
}
@@ -606,6 +612,52 @@ restart:
}
/*
+ * General yield call. Puts the current process back on its run queue and
+ * performs a voluntary context switch.
+ */
+void
+yield()
+{
+ struct proc *p = curproc;
+ int s;
+
+ p->p_priority = p->p_usrpri;
+ s = splstatclock();
+ setrunqueue(p);
+ p->p_stats->p_ru.ru_nvcsw++;
+ mi_switch();
+ splx(s);
+}
+
+/*
+ * General preemption call. Puts the current process back on its run queue
+ * and performs an involuntary context switch. If a process is supplied,
+ * we switch to that process. Otherwise, we use the normal process selection
+ * criteria.
+ */
+void
+preempt(newp)
+ struct proc *newp;
+{
+ struct proc *p = curproc;
+ int s;
+
+ /*
+ * XXX Switching to a specific process is not supported yet.
+ */
+ if (newp != NULL)
+ panic("preempt: cpu_preempt not yet implemented");
+
+ p->p_priority = p->p_usrpri;
+ s = splstatclock();
+ setrunqueue(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ mi_switch();
+ splx(s);
+}
+
+
+/*
* The machine independent parts of mi_switch().
* Must be called at splstatclock() or higher.
*/
@@ -654,6 +706,13 @@ mi_switch()
resetpriority(p);
}
+
+ /*
+ * Process is about to yield the CPU; clear the appropriate
+ * scheduling flags.
+ */
+ p->p_schedflags &= ~PSCHED_SWITCHCLEAR;
+
/*
* Pick a new current process and record its start time.
*/
@@ -664,13 +723,6 @@ mi_switch()
#endif
cpu_switch(p);
microtime(&runtime);
-
- /*
- * We reset roundrobin_attempts at exit, because cpu_switch could
- * have looped in the idle loop and the attempts would increase
- * leading to unjust punishment of an innocent process.
- */
- roundrobin_attempts = 0;
}
/*
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index d77872cb261..9ddd84f1a93 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.29 2000/03/23 14:43:47 art Exp $ */
+/* $OpenBSD: proc.h,v 1.30 2000/04/19 09:58:19 art Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -154,6 +154,7 @@ struct proc {
char *p_wmesg; /* Reason for sleep. */
u_int p_swtime; /* Time swapped in or out. */
u_int p_slptime; /* Time since last blocked. */
+ int p_schedflags; /* PSCHED_* flags */
struct itimerval p_realtimer; /* Alarm timer. */
struct timeout p_realit_to; /* Alarm timeout. */
@@ -243,6 +244,15 @@ struct proc {
#define P_NOZOMBIE 0x100000 /* Pid 1 waits for me instead of dad */
/*
+ * These flags are kept in p_schedflags. p_schedflags may be modified
+ * only at splstatclock().
+ */
+#define PSCHED_SEENRR 0x0001 /* process has been in roundrobin() */
+#define PSCHED_SHOULDYIELD 0x0002 /* process should yield */
+
+#define PSCHED_SWITCHCLEAR (PSCHED_SEENRR|PSCHED_SHOULDYIELD)
+
+/*
* MOVE TO ucred.h?
*
* Shareable process credentials (always resident). This includes a reference
@@ -332,6 +342,8 @@ int enterpgrp __P((struct proc *p, pid_t pgid, int mksess));
void fixjobc __P((struct proc *p, struct pgrp *pgrp, int entering));
int inferior __P((struct proc *p));
int leavepgrp __P((struct proc *p));
+void yield __P((void));
+void preempt __P((struct proc *));
void mi_switch __P((void));
void pgdelete __P((struct pgrp *pgrp));
void procinit __P((void));