On Tue, Dec 01, 2020 at 10:46:00AM -0300, Martin Pieuchot wrote: > On 01/12/20(Tue) 21:47, Jonathan Matthew wrote: > > On Tue, Dec 01, 2020 at 10:31:43AM +0100, Claudio Jeker wrote: > > > On Mon, Nov 30, 2020 at 07:10:47PM -0300, Martin Pieuchot wrote: > > > > Every multi-threaded process keeps a list of threads in `ps_threads'. > > > > This list is iterated in interrupt and process context which makes it > > > > complicated to protect it with a rwlock. > > > > > > > > One of the places where such iteration is done is inside the tsleep(9) > > > > routines, directly in single_thread_check() or via CURSIG(). In order > > > > to take this code path out of the KERNEL_LOCK(), claudio@ proposed to > > > > use SMR_TAILQ. This has the advantage of not introducing lock > > > > dependencies and allow us to address every iteration one-by-one. > > > > > > > > Diff below is a first step into this direction, it replaces the existing > > > > TAILQ_* macros by the locked version of SMR_TAILQ*. This is mostly > > > > lifted > > > > from claudio@'s diff and should not introduce any side effect. > > > > > > > > ok? > > > > > > > > diff --git sys/uvm/uvm_glue.c sys/uvm/uvm_glue.c > > > > index 390307c4c81..40a10e4c1c5 100644 > > > > --- sys/uvm/uvm_glue.c > > > > +++ sys/uvm/uvm_glue.c > > > > @@ -369,7 +369,7 @@ uvm_swapout_threads(void) > > > > * the smallest p_slptime > > > > */ > > > > slpp = NULL; > > > > - TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) { > > > > + SMR_TAILQ_FOREACH_LOCKED(p, &pr->ps_threads, > > > > p_thr_link) { > > > > switch (p->p_stat) { > > > > case SRUN: > > > > case SONPROC: > > > > > > > > > > Why did you not include the smr_call() to safely free struct proc in this > > > diff? > > So we can discuss it separately, I'm happy to do it now :) > > > I was wondering about this too. Freeing the struct proc is already delayed > > by some amount since it happens in the reaper or in the parent process, does > > it make sense to combine that with the SMR wait? > > exit1() for a multi-threaded process does the following: > > atomic_setbits_int(&p->p_flag, P_WEXIT); > > single_thread_check(p, 0); // directly or via single_thread_set() > > SMR_TAILQ_REMOVE_LOCKED(&pr->ps_threads, p, p_thr_link); > > > Note that exit1() can't be called in parallel. > > If exit1() is called with EXIT_NORMAL, the current thread will start by > setting `ps_single' then iterate over `ps_thread'. This is done before > updating `ps_thread' so there's no race in that case. > > If exit1() is called with EXIT_THREAD, the current thread might end up > removing itself from `ps_thread' while another one is iterating over it. > Since we're currently concerned about the iteration in single_thread_set() > notice that `P_WEXIT' is checked first. So if my understanding is correct > is should be enough to do the following: > > SMR_TAILQ_REMOVE_LOCKED(&pr->ps_threads, p, p_thr_link); > smr_barrier(); > > That would delays exit1() a bit but doesn't involve callback which is > IMHO simpler. > > Did I miss anything?
Did you run a make build with that smr_barrier() in it and checked that it does not cause a slow down? I am sceptical, smr_barrier() is a very slow construct which introduces large delays and should be avoided whenever possible. -- :wq Claudio