this started as just using struct cond to handle the sleep and
wakeups for sched_barrier, but it got a bit bigger.

the biggest semantic change is that it gets rid of the sbar taskq
and uses systqmp instead. a whole thread (which is what is underneath
a taskq) is a very big hammer for solving this problem. the task
the sched barrier wants to run is short, so it wont be a burden for
systqmp.

the other big change is the use of a variable on the stack as the
wait channel for sleeping in the caller and waking up in the task,
instead of a variable in struct schedstate_percpu. the latter is
effectively a shared global. if (and this is a big if) two different
threads are running sched_barrier, this could lead to unwanted
races. putting this on the stack (via struct cond) means each thread
gets its own condition to sleep on and use as a wait channel.

ok?

Index: sys/sched.h
===================================================================
RCS file: /cvs/src/sys/sys/sched.h,v
retrieving revision 1.43
diff -u -p -r1.43 sched.h
--- sys/sched.h 4 Dec 2017 09:51:03 -0000       1.43
+++ sys/sched.h 14 Dec 2017 01:14:47 -0000
@@ -114,8 +114,6 @@ struct schedstate_percpu {
        struct proc *spc_reaper;        /* dead proc reaper */
 #endif
        LIST_HEAD(,proc) spc_deadproc;
-
-       volatile int spc_barrier;       /* for sched_barrier() */
 };
 
 #ifdef _KERNEL
Index: kern/kern_sched.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sched.c,v
retrieving revision 1.46
diff -u -p -r1.46 kern_sched.c
--- kern/kern_sched.c   28 Nov 2017 16:22:27 -0000      1.46
+++ kern/kern_sched.c   14 Dec 2017 01:14:48 -0000
@@ -227,12 +227,6 @@ sched_exit(struct proc *p)
 void
 sched_init_runqueues(void)
 {
-#ifdef MULTIPROCESSOR
-       sbartq = taskq_create("sbar", 1, IPL_VM,
-           TASKQ_MPSAFE | TASKQ_CANTSLEEP);
-       if (sbartq == NULL)
-               panic("unable to create sbar taskq");
-#endif
 }
 
 void
@@ -658,24 +652,28 @@ sched_stop_secondary_cpus(void)
        }
 }
 
+struct sched_barrier_state {
+       struct cpu_info *ci;
+       struct cond cond;
+};
+
 void
 sched_barrier_task(void *arg)
 {
-       struct cpu_info *ci = arg;
+       struct sched_barrier_state *sb = arg;
+       struct cpu_info *ci = sb->ci;
 
        sched_peg_curproc(ci);
-       ci->ci_schedstate.spc_barrier = 1;
-       wakeup(&ci->ci_schedstate.spc_barrier);
+       cond_signal(&sb->cond);
        atomic_clearbits_int(&curproc->p_flag, P_CPUPEG);
 }
 
 void
 sched_barrier(struct cpu_info *ci)
 {
-       struct sleep_state sls;
+       struct sched_barrier_state sb;
        struct task task;
        CPU_INFO_ITERATOR cii;
-       struct schedstate_percpu *spc;
 
        if (ci == NULL) {
                CPU_INFO_FOREACH(cii, ci) {
@@ -688,14 +686,12 @@ sched_barrier(struct cpu_info *ci)
        if (ci == curcpu())
                return;
 
-       task_set(&task, sched_barrier_task, ci);
-       spc = &ci->ci_schedstate;
-       spc->spc_barrier = 0;
-       task_add(sbartq, &task);
-       while (!spc->spc_barrier) {
-               sleep_setup(&sls, &spc->spc_barrier, PWAIT, "sbar");
-               sleep_finish(&sls, !spc->spc_barrier);
-       }
+       sb.ci = ci;
+       cond_init(&sb.cond);
+       task_set(&task, sched_barrier_task, &sb);
+
+       task_add(systqmp, &task);
+       cond_wait(&sb.cond, "sbar");
 }
 
 #else

Reply via email to