1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* 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;
}
}
}
|