#include <9pm/u.h> #include <9pm/libc.h> #include <9pm/ns.h> #include <9pm/thread.h> #include <9pm/threadimpl.h> int _threadnonotes; /* * Threadkillgrp arranges the death of a particular thread group. * On Plan 9 we used to send the note kilgrp%d to the entire process group, * but we don't have that much flexibility in the signals on other systems. * Instead, we iterate over all threads and mark the ones that are to die. */ void threadkillgrp(int grp) { Tproc *p; Thread *t; lock(&_threadpq.lk); for(p=_threadpq.head; p; p=p->next){ lock(&p->threadlk); for(t=p->threads.head; t; t=t->nextt) if(t->grp == grp) t->exiting = 1; unlock(&p->threadlk); } unlock(&_threadpq.lk); _threadsignal(); } /* * On Plan 9 we used to send kilthr%d to the entire process group. * See comment for threadkillgrp. */ void threadkill(int id) { Tproc *p; Thread *t; int selfthread, selfproc; lock(&_threadpq.lk); for(p=_threadpq.head; p; p=p->next){ lock(&p->threadlk); for(t=p->threads.head; t; t=t->nextt) if(t->id == id) goto Found; unlock(&p->threadlk); } unlock(&_threadpq.lk); _threaddebug(DBGNOTE, "Can't find thread to kill"); return; Found: lock(&_threndezlock); if(t->state == Rendezvous){ _threaddebug(DBGNOTE, "Thread was in rendezvous"); assert(_threadgetqbytag(&_threndez, t->tag) == t); } t->exiting = 1; selfproc = p == _threadgetproc(); selfthread = t == _threadgetthr(); unlock(&_threndezlock); unlock(&p->threadlk); unlock(&_threadpq.lk); if(selfproc){ _threaddebug(DBGNOTE, "Thread in same proc"); if(selfthread){ _threaddebug(DBGNOTE, "Threadkill: killing self"); threadexits("threadicide"); } _freethread(t); return; } /* * We could signal just the relevant process here, but * that would require holding p->threadlock or _threadpq.lock * until after sending the signal, so that the p structure doesn't * get freed out from under us. Just signal everyone instead. */ _threadsignal(); } /* * Isolate ourselves from outside notes by killing off the passer. */ void threadnonotes(void) { _threadnonotes = 1; _threadsignalpasser(); }