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