xref: /plan9-contrib/sys/src/9/port/pgrp.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 enum {
9 	Whinesecs = 10,		/* frequency of out-of-resources printing */
10 };
11 
12 static Ref pgrpid;
13 static Ref mountid;
14 
15 void
pgrpnote(ulong noteid,char * a,long n,int flag)16 pgrpnote(ulong noteid, char *a, long n, int flag)
17 {
18 	Proc *p, *ep;
19 	char buf[ERRMAX];
20 
21 	if(n >= ERRMAX-1)
22 		error(Etoobig);
23 
24 	memmove(buf, a, n);
25 	buf[n] = 0;
26 	p = proctab(0);
27 	ep = p+conf.nproc;
28 	for(; p < ep; p++) {
29 		if(p->state == Dead)
30 			continue;
31 		if(up != p && p->noteid == noteid && p->kp == 0) {
32 			qlock(&p->debug);
33 			if(p->pid == 0 || p->noteid != noteid){
34 				qunlock(&p->debug);
35 				continue;
36 			}
37 			if(!waserror()) {
38 				postnote(p, 0, buf, flag);
39 				poperror();
40 			}
41 			qunlock(&p->debug);
42 		}
43 	}
44 }
45 
46 Pgrp*
newpgrp(void)47 newpgrp(void)
48 {
49 	Pgrp *p;
50 
51 	p = smalloc(sizeof(Pgrp));
52 	p->ref = 1;
53 	p->pgrpid = incref(&pgrpid);
54 	return p;
55 }
56 
57 Rgrp*
newrgrp(void)58 newrgrp(void)
59 {
60 	Rgrp *r;
61 
62 	r = smalloc(sizeof(Rgrp));
63 	r->ref = 1;
64 	return r;
65 }
66 
67 void
closergrp(Rgrp * r)68 closergrp(Rgrp *r)
69 {
70 	if(decref(r) == 0)
71 		free(r);
72 }
73 
74 void
closepgrp(Pgrp * p)75 closepgrp(Pgrp *p)
76 {
77 	Mhead **h, **e, *f, *next;
78 
79 	if(decref(p) != 0)
80 		return;
81 
82 	qlock(&p->debug);
83 	wlock(&p->ns);
84 	p->pgrpid = -1;
85 
86 	e = &p->mnthash[MNTHASH];
87 	for(h = p->mnthash; h < e; h++) {
88 		for(f = *h; f; f = next) {
89 			wlock(&f->lock);
90 			cclose(f->from);
91 			mountfree(f->mount);
92 			f->mount = nil;
93 			next = f->hash;
94 			wunlock(&f->lock);
95 			putmhead(f);
96 		}
97 	}
98 	wunlock(&p->ns);
99 	qunlock(&p->debug);
100 	free(p);
101 }
102 
103 void
pgrpinsert(Mount ** order,Mount * m)104 pgrpinsert(Mount **order, Mount *m)
105 {
106 	Mount *f;
107 
108 	m->order = 0;
109 	if(*order == 0) {
110 		*order = m;
111 		return;
112 	}
113 	for(f = *order; f; f = f->order) {
114 		if(m->mountid < f->mountid) {
115 			m->order = f;
116 			*order = m;
117 			return;
118 		}
119 		order = &f->order;
120 	}
121 	*order = m;
122 }
123 
124 /*
125  * pgrpcpy MUST preserve the mountid allocation order of the parent group
126  */
127 void
pgrpcpy(Pgrp * to,Pgrp * from)128 pgrpcpy(Pgrp *to, Pgrp *from)
129 {
130 	int i;
131 	Mount *n, *m, **link, *order;
132 	Mhead *f, **tom, **l, *mh;
133 
134 	wlock(&from->ns);
135 	order = 0;
136 	tom = to->mnthash;
137 	for(i = 0; i < MNTHASH; i++) {
138 		l = tom++;
139 		for(f = from->mnthash[i]; f; f = f->hash) {
140 			rlock(&f->lock);
141 			mh = newmhead(f->from);
142 			*l = mh;
143 			l = &mh->hash;
144 			link = &mh->mount;
145 			for(m = f->mount; m; m = m->next) {
146 				n = newmount(mh, m->to, m->mflag, m->spec);
147 				m->copy = n;
148 				pgrpinsert(&order, m);
149 				*link = n;
150 				link = &n->next;
151 			}
152 			runlock(&f->lock);
153 		}
154 	}
155 	/*
156 	 * Allocate mount ids in the same sequence as the parent group
157 	 */
158 	lock(&mountid);
159 	for(m = order; m; m = m->order)
160 		m->copy->mountid = mountid.ref++;
161 	unlock(&mountid);
162 	wunlock(&from->ns);
163 }
164 
165 Fgrp*
dupfgrp(Fgrp * f)166 dupfgrp(Fgrp *f)
167 {
168 	Fgrp *new;
169 	Chan *c;
170 	int i;
171 
172 	new = smalloc(sizeof(Fgrp));
173 	if(f == nil){
174 		new->fd = smalloc(DELTAFD*sizeof(Chan*));
175 		new->nfd = DELTAFD;
176 		new->ref = 1;
177 		return new;
178 	}
179 
180 	lock(f);
181 	/* Make new fd list shorter if possible, preserving quantization */
182 	new->nfd = f->maxfd+1;
183 	i = new->nfd%DELTAFD;
184 	if(i != 0)
185 		new->nfd += DELTAFD - i;
186 	new->fd = malloc(new->nfd*sizeof(Chan*));
187 	if(new->fd == nil){
188 		unlock(f);
189 		free(new);
190 		error("no memory for fgrp");
191 	}
192 	new->ref = 1;
193 
194 	new->maxfd = f->maxfd;
195 	for(i = 0; i <= f->maxfd; i++) {
196 		if(c = f->fd[i]){
197 			incref(c);
198 			new->fd[i] = c;
199 		}
200 	}
201 	unlock(f);
202 
203 	return new;
204 }
205 
206 void
closefgrp(Fgrp * f)207 closefgrp(Fgrp *f)
208 {
209 	int i;
210 	Chan *c;
211 
212 	if(f == 0)
213 		return;
214 
215 	if(decref(f) != 0)
216 		return;
217 
218 	/*
219 	 * If we get into trouble, forceclosefgrp
220 	 * will bail us out.
221 	 */
222 	up->closingfgrp = f;
223 	for(i = 0; i <= f->maxfd; i++)
224 		if(c = f->fd[i]){
225 			f->fd[i] = nil;
226 			cclose(c);
227 		}
228 	up->closingfgrp = nil;
229 
230 	free(f->fd);
231 	free(f);
232 }
233 
234 /*
235  * Called from sleep because up is in the middle
236  * of closefgrp and just got a kill ctl message.
237  * This usually means that up has wedged because
238  * of some kind of deadly embrace with mntclose
239  * trying to talk to itself.  To break free, hand the
240  * unclosed channels to the close queue.  Once they
241  * are finished, the blocked cclose that we've
242  * interrupted will finish by itself.
243  */
244 void
forceclosefgrp(void)245 forceclosefgrp(void)
246 {
247 	int i;
248 	Chan *c;
249 	Fgrp *f;
250 
251 	if(up->procctl != Proc_exitme || up->closingfgrp == nil){
252 		print("bad forceclosefgrp call");
253 		return;
254 	}
255 
256 	f = up->closingfgrp;
257 	for(i = 0; i <= f->maxfd; i++)
258 		if(c = f->fd[i]){
259 			f->fd[i] = nil;
260 			ccloseq(c);
261 		}
262 }
263 
264 
265 Mount*
newmount(Mhead * mh,Chan * to,int flag,char * spec)266 newmount(Mhead *mh, Chan *to, int flag, char *spec)
267 {
268 	Mount *m;
269 
270 	m = smalloc(sizeof(Mount));
271 	m->to = to;
272 	m->head = mh;
273 	incref(to);
274 	m->mountid = incref(&mountid);
275 	m->mflag = flag;
276 	if(spec != 0)
277 		kstrdup(&m->spec, spec);
278 
279 	return m;
280 }
281 
282 void
mountfree(Mount * m)283 mountfree(Mount *m)
284 {
285 	Mount *f;
286 
287 	while(m) {
288 		f = m->next;
289 		cclose(m->to);
290 		m->mountid = 0;
291 		free(m->spec);
292 		free(m);
293 		m = f;
294 	}
295 }
296 
297 void
resrcwait(char * reason)298 resrcwait(char *reason)
299 {
300 	ulong now;
301 	char *p;
302 	static ulong lastwhine;
303 
304 	if(up == 0)
305 		panic("resrcwait");
306 
307 	p = up->psstate;
308 	if(reason) {
309 		up->psstate = reason;
310 		now = seconds();
311 		/* don't tie up the console with complaints */
312 		if(now - lastwhine > Whinesecs) {
313 			lastwhine = now;
314 			print("%s\n", reason);
315 		}
316 	}
317 
318 	tsleep(&up->sleep, return0, 0, 300);
319 	up->psstate = p;
320 }
321