| /* |
| * This needs to be callable from a signal handler, so it has been |
| * written to avoid locks. The only lock is the one used to acquire |
| * an entry in the table, and we make sure that acquiring is done |
| * when not in a handler. Lookup and delete do not need locks. |
| * It's a scan-forward hash table. To avoid breaking chains, |
| * T ((void*)-1) is used as a non-breaking nil. |
| */ |
| |
| #include <u.h> |
| #include <libc.h> |
| #include "9proc.h" |
| |
| enum { PIDHASH = 1021 }; |
| |
| #define T ((void*)-1) |
| static Uproc *alluproc[PIDHASH]; |
| static int allupid[PIDHASH]; |
| static Lock uproclock; |
| |
| void |
| _clearuproc(void) |
| { |
| int i; |
| |
| /* called right after fork - no locking needed */ |
| for(i=0; i<PIDHASH; i++) |
| if(alluproc[i] != T && alluproc[i] != 0) |
| free(alluproc[i]); |
| memset(alluproc, 0, sizeof alluproc); |
| memset(allupid, 0, sizeof allupid); |
| } |
| |
| Uproc* |
| _p9uproc(int inhandler) |
| { |
| int i, h, pid; |
| Uproc *up; |
| |
| /* for now, assume getpid is fast or cached */ |
| pid = getpid(); |
| |
| /* |
| * this part - the lookup - needs to run without locks |
| * so that it can safely be called from within the notify handler. |
| * notify calls _p9uproc, and fork and rfork call _p9uproc |
| * in both parent and child, so if we're in a signal handler, |
| * we should find something in the table. |
| */ |
| h = pid%PIDHASH; |
| for(i=0; i<PIDHASH; i++){ |
| up = alluproc[h]; |
| if(up == nil) |
| break; |
| if(allupid[h] == pid) |
| return up; |
| if(++h == PIDHASH) |
| h = 0; |
| } |
| |
| if(inhandler){ |
| fprint(2, "%s: did not find uproc for pid %d in signal handler\n", argv0, pid); |
| abort(); |
| } |
| |
| /* need to allocate */ |
| while((up = mallocz(sizeof(Uproc), 1)) == nil) |
| sleep(1000); |
| |
| /* fprint(2, "alloc uproc for pid %d\n", pid); */ |
| up->pid = pid; |
| lock(&uproclock); |
| h = pid%PIDHASH; |
| for(i=0; i<PIDHASH; i++){ |
| if(alluproc[h]==T || alluproc[h]==nil){ |
| alluproc[h] = up; |
| allupid[h] = pid; |
| unlock(&uproclock); |
| return up; |
| } |
| if(++h == PIDHASH) |
| h = 0; |
| } |
| unlock(&uproclock); |
| |
| /* out of pids! */ |
| sysfatal("too many processes in uproc table"); |
| return nil; |
| } |
| |
| void |
| _p9uprocdie(void) |
| { |
| Uproc *up; |
| int pid, i, h; |
| |
| pid = getpid(); |
| /* fprint(2, "reap uproc for pid %d\n", pid); */ |
| h = pid%PIDHASH; |
| for(i=0; i<PIDHASH; i++){ |
| up = alluproc[h]; |
| if(up == nil) |
| break; |
| if(up == T) |
| continue; |
| if(allupid[h] == pid){ |
| up = alluproc[h]; |
| alluproc[h] = T; |
| free(up); |
| allupid[h] = 0; |
| } |
| } |
| } |