]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/lwp.c
[BOUNDS_CHECK]: Defunct, remove.
[empserver] / src / lib / lwp / lwp.c
1 /*
2  * lwp.c -- lightweight process creation, destruction and manipulation.
3  * Copyright (C) 1991-3 Stephen Crane.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  * 
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  * 
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
20  * Imperial College of Science, Technology and Medicine, 180 Queen's
21  * Gate, London SW7 2BZ, England.
22  */
23
24 #include <stdio.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "lwp.h"
29 #include "lwpint.h"
30 #include "prototypes.h"
31
32 #if defined(_EMPTH_LWP)
33
34 struct lwpQueue LwpSchedQ[LWP_MAX_PRIO], LwpDeadQ;
35
36 struct lwpProc *LwpCurrent = NULL;
37 char **LwpContextPtr;
38 int LwpMaxpri = 0;              /* maximum priority so far */
39
40 static sigset_t oldmask;
41
42 static void lwpStackCheckInit(struct lwpProc *newp);
43 static void lwpStackCheck(struct lwpProc *newp);
44 static void lwpStackCheckUsed(struct lwpProc *newp);
45
46 /* check stack direction */
47 static int
48 growsdown(void *x)
49 {
50     int y;
51     y = (x > (void *)&y);
52     return y;
53 }
54
55 /*
56  * lwpReschedule -- schedule another process.  we also check for dead
57  * processes here and free them.
58  */
59 void
60 lwpReschedule(void)
61 {
62     static int lcount = LCOUNT;
63     static struct lwpProc *nextp;
64     static int i;
65     static sigset_t tmask;
66
67     if (LwpCurrent && (LwpCurrent->flags & LWP_STACKCHECK)) {
68         lwpStackCheck(LwpCurrent);
69     }
70     if (!--lcount) {
71         int p = lwpSetPriority(LWP_MAX_PRIO - 1);
72         lcount = LCOUNT;
73         sigprocmask(SIG_SETMASK, &oldmask, &tmask);
74         sigprocmask(SIG_SETMASK, &tmask, &oldmask);
75         LwpCurrent->pri = p;
76     }
77
78     /* destroy dead threads */
79     lwpStatus(LwpCurrent, "Cleaning dead queue");
80     while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
81         if (nextp == LwpCurrent) {
82             lwpStatus(nextp, "OOOPS, we are running already dead thread");
83             exit(1);
84         }
85         lwpDestroy(nextp);
86         lwpStatus(LwpCurrent, "Destroying done");
87     }
88
89     for (i = LwpMaxpri + 1; i--;) {
90         while (NULL != (nextp = lwpGetFirst(&LwpSchedQ[i]))) {
91             if (!nextp->dead)
92                 break;
93             /* clean up after dead bodies */
94             lwpStatus(nextp, "got a dead body");
95             if (nextp == LwpCurrent) {
96                 lwpStatus(nextp, "we are in it -- will bury later");
97                 lwpAddTail(&LwpDeadQ, nextp);
98             } else {
99                 lwpDestroy(nextp);
100             }
101             nextp = 0;
102         }
103         if (nextp)
104             break;
105     }
106     if (LwpCurrent == 0 && nextp == 0) {
107         fprintf(stderr, "No processes to run!\n");
108         exit(1);
109     }
110     if (LwpCurrent)
111         lwpStatus(LwpCurrent, "switch out");
112     /* do context switch */
113     if (LwpCurrent != nextp && !(LwpCurrent && lwpSave(LwpCurrent->context))) {
114         /* restore previous context */
115         lwpStatus(nextp, "switch in %d", nextp->pri);
116         LwpCurrent = nextp;
117         *LwpContextPtr = LwpCurrent->ud;
118         lwpRestore(LwpCurrent->context);
119     }
120 }
121
122 /*
123  * lwpEntryPoint -- process entry point.
124  */
125 void
126 lwpEntryPoint(void)
127 {
128     sigset_t set;
129
130     sigemptyset(&set);
131     sigaddset(&set, SIGALRM);
132     sigprocmask(SIG_SETMASK, &set, &oldmask);
133     *LwpContextPtr = LwpCurrent->ud;
134
135     lwpStatus(LwpCurrent, "starting at entry point");
136     (*LwpCurrent->entry)(LwpCurrent->ud);
137     lwpExit();
138 }
139
140 /*
141  * lwpCreate -- create a process.
142  */
143 struct lwpProc *
144 lwpCreate(int priority, void (*entry)(void *), int size, int flags, char *name, char *desc, int argc, char **argv, void *ud)
145 {
146     struct lwpProc *newp;
147     char *s, *sp;
148     int redsize, x;
149 #ifdef UCONTEXT
150     stack_t usp;
151 #endif /* UCONTEXT */
152
153     if (!(newp = malloc(sizeof(struct lwpProc))))
154         return 0;
155     /* Add a 1K buffer on each side of the stack */
156     redsize = flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
157     size += 2 * redsize;
158     size += LWP_EXTRASTACK;
159     size += sizeof(stkalign_t);
160     if (!(s = malloc(size)))
161         return 0;
162     newp->flags = flags;
163     newp->name = strdup(name);
164     newp->desc = strdup(desc);
165     newp->entry = entry;
166     newp->argc = argc;
167     newp->argv = argv;
168     newp->ud = ud;
169     if (growsdown(&x)) {
170         sp = s + size - sizeof(stkalign_t) - LWP_EXTRASTACK - redsize;
171         sp = (char *)0 + ((sp - (char *)0) & -sizeof(stkalign_t));
172         newp->lowmark = sp + LWP_EXTRASTACK;
173         newp->himark = s;
174     } else {
175         sp = s + LWP_EXTRASTACK + redsize;
176         sp = (char *)0 + ((sp - (char *)0) & -sizeof(stkalign_t));
177         newp->lowmark = s;
178         newp->himark = s + size - LWP_REDZONE;
179     }
180     if (LWP_MAX_PRIO <= priority)
181         priority = LWP_MAX_PRIO - 1;
182     if (LwpMaxpri < (newp->pri = priority))
183         LwpMaxpri = priority;
184     newp->sbtm = s;
185     newp->size = size;
186     newp->dead = 0;
187     if (flags & LWP_STACKCHECK)
188         lwpStackCheckInit(newp);
189     lwpStatus(newp, "creating process structure sbtm: %p",
190               newp->sbtm);
191     lwpReady(newp);
192     lwpReady(LwpCurrent);
193 #ifdef UCONTEXT
194     usp.ss_sp = sp;
195     usp.ss_size = size;
196     usp.ss_flags = 0;
197     lwpInitContext(newp, &usp); /* architecture-dependent: from arch.c */
198 #else  /* UCONTEXT */
199     lwpInitContext(newp, sp);   /* architecture-dependent: from arch.c */
200 #endif /* UCONTEXT */
201     lwpReschedule();
202     return newp;
203 }
204
205 void
206 lwpDestroy(struct lwpProc *proc)
207 {
208     if (proc->flags & LWP_STACKCHECK) {
209         lwpStackCheckUsed(proc);
210         lwpStackCheck(proc);
211     }
212     lwpStatus(proc, "destroying sbtm: %p", proc->sbtm);
213     proc->entry = 0;
214     proc->ud = 0;
215     proc->argv = 0;
216     free(proc->sbtm);
217     free(proc->name);
218     free(proc->desc);
219     proc->name = 0;
220     proc->desc = 0;
221     proc->sbtm = 0;
222     proc->lowmark = 0;
223     proc->himark = 0;
224     free(proc);
225 }
226
227 /*
228  * lwpReady -- put process on ready queue.  if null, assume current.
229  */
230 void
231 lwpReady(struct lwpProc *p)
232 {
233     if (!p)
234         p = LwpCurrent;
235     lwpStatus(p, "added to run queue");
236     lwpAddTail(&LwpSchedQ[p->pri], p);
237 }
238
239 /*
240  * return user's data
241  */
242 void *
243 lwpGetUD(struct lwpProc *p)
244 {
245     if (!p)
246         p = LwpCurrent;
247     return p->ud;
248 }
249
250 /*
251  * set user's data
252  */
253 void
254 lwpSetUD(struct lwpProc *p, char *ud)
255 {
256     if (!p)
257         p = LwpCurrent;
258     p->ud = ud;
259 }
260
261 /*
262  * set name & desc
263  */
264 void
265 lwpSetDesc(struct lwpProc *p, char *name, char *desc)
266 {
267     if (!p)
268         p = LwpCurrent;
269     free(p->name);
270     free(p->desc);
271     p->name = strdup(name);
272     p->desc = strdup(desc);
273 }
274
275 /*
276  * lwpYield -- yield the processor to another thread.
277  */
278 void
279 lwpYield(void)
280 {
281     lwpStatus(LwpCurrent, "yielding control");
282     lwpReady(LwpCurrent);
283     lwpReschedule();
284 }
285
286 /*
287  * cause the current process to be scheduled for deletion.
288  */
289 void
290 lwpExit(void)
291 {
292     lwpStatus(LwpCurrent, "marking self as dead");
293     LwpCurrent->dead = 1;
294     lwpYield();
295 }
296
297 /*
298  * mark another process as dead, so it will never be rescheduled.
299  * remove any lingering FD action
300  */
301 void
302 lwpTerminate(struct lwpProc *p)
303 {
304     lwpStatus(p, "terminating process");
305     p->dead = 1;
306     if (p->fd >= 0)
307         lwpWakeupFd(p);
308 }
309
310 /*
311  * set the thread's priority, returning the old.
312  * if the new priority is lower than the old, we reschedule.
313  */
314 int
315 lwpSetPriority(int new)
316 {
317     int old = LwpCurrent->pri;
318
319     if (LWP_MAX_PRIO <= new)
320         new = LWP_MAX_PRIO - 1;
321     if (LwpMaxpri < new)
322         LwpMaxpri = new;
323     LwpCurrent->pri = new;
324     lwpStatus(LwpCurrent, "resetting priority (%d -> %d)", old, new);
325     if (new < old)
326         lwpYield();
327     return old;
328 }
329
330 /*
331  * initialise the coroutine structures
332  */
333 struct lwpProc *
334 lwpInitSystem(int pri, char **ctxptr, int flags)
335 {
336     struct lwpQueue *q;
337     int i, *stack;
338     struct lwpProc *sel;
339
340     LwpContextPtr = ctxptr;
341     if (pri < 1)
342         pri = 1;
343     /* *LwpContextPtr = 0; */
344     if (!(LwpCurrent = calloc(1, sizeof(struct lwpProc))))
345         return 0;
346     if (!(stack = malloc(64)))
347         return 0;
348     if (LWP_MAX_PRIO <= pri)
349         pri = LWP_MAX_PRIO - 1;
350     if (LwpMaxpri < pri)
351         LwpMaxpri = pri;
352     LwpCurrent->next = 0;
353     LwpCurrent->sbtm = stack;   /* dummy stack for "main" */
354     LwpCurrent->pri = pri;
355     LwpCurrent->dead = 0;
356     LwpCurrent->flags = flags & ~LWP_STACKCHECK;
357     LwpCurrent->name = "Main";
358     for (i = LWP_MAX_PRIO, q = LwpSchedQ; i--; q++)
359         q->head = q->tail = 0;
360     LwpDeadQ.head = LwpDeadQ.tail = 0;
361     /* must be lower in priority than us for this to work right */
362     sel = lwpCreate(0, lwpSelect, 16384, flags, "EventHandler",
363                     "Select (main loop) Event Handler", 0, 0, 0);
364     lwpInitSelect(sel);
365     return LwpCurrent;
366 }
367
368 /* lwpStackCheckInit
369  *
370  * Initialize the entire stack (including both redzones) with the stack
371  * check mark.  Thus, we can get some indication of how much stack was
372  * used.
373  */
374 static void
375 lwpStackCheckInit(struct lwpProc *newp)
376 {
377     register int i;
378     register long *lp;
379
380     int lim = newp->size / sizeof(long);
381     if (!newp || !newp->sbtm)
382         return;
383     for (lp = newp->sbtm, i = 0; i < lim; i++, lp++) {
384         *lp = LWP_CHECKMARK;
385     }
386 }
387
388 /* lwpStackCheck
389  *
390  * Check if the thread has overflowed/underflowed its stack.
391  * Should that happen, abort the process, as we cannot recover.
392  */
393 static void
394 lwpStackCheck(struct lwpProc *newp)
395 {
396     register int end, amt;
397     register unsigned int i;
398     register long *lp;
399     register int growsDown;
400     int marker;
401
402     if (CANT_HAPPEN(!newp || !newp->himark || !newp->lowmark))
403         return;
404     growsDown = growsdown(&marker);
405     for (lp = newp->himark, i = 0; i < LWP_REDZONE / sizeof(long);
406          i++, lp++) {
407         if (*lp == LWP_CHECKMARK)
408             continue;
409         /* Stack overflow. */
410         if (growsDown) {
411             end = i;
412             while (i < LWP_REDZONE / sizeof(long)) {
413                 if (*lp++ != LWP_CHECKMARK)
414                     end = i;
415                 i++;
416             }
417             amt = (end + 1) * sizeof(long);
418         } else {
419             amt = (i + 1) * sizeof(long);
420         }
421         logerror("Thread %s stack overflow %d bytes (of %u)",
422                  newp->name, amt,
423                  newp->size - 2 * LWP_REDZONE - (int)sizeof(stkalign_t));
424         abort();
425     }
426     for (lp = newp->lowmark, i = 0; i < LWP_REDZONE / sizeof(long);
427          i++, lp++) {
428         if (*lp == LWP_CHECKMARK)
429             continue;
430         /* Stack underflow. */
431         if (growsDown) {
432             end = i;
433             while (i < LWP_REDZONE / sizeof(long)) {
434                 if (*lp++ != LWP_CHECKMARK)
435                     end = i;
436                 i++;
437             }
438             amt = (end + 1) * sizeof(long);
439         } else {
440             amt = (LWP_REDZONE - i + 1) * sizeof(long);
441         }
442         logerror("Thread %s stack underflow %d bytes (of %u)",
443                   newp->name, amt,
444                  newp->size - 2 * LWP_REDZONE - (int)sizeof(stkalign_t));
445         abort();
446     }
447 }
448
449 /* lwpStackCheckUsed
450  *
451  * Figure out how much stack was used by this thread.
452  */
453 static void
454 lwpStackCheckUsed(struct lwpProc *newp)
455 {
456     register int i;
457     register long *lp;
458     register int lim;
459     int marker;
460
461     if (!newp || !newp->sbtm)
462         return;
463     lim = newp->size / sizeof(long);
464     if (growsdown(&marker)) {
465         /* Start at the bottom and find first non checkmark. */
466         for (lp = newp->sbtm, i = 0; i < lim; i++, lp++) {
467             if (*lp != LWP_CHECKMARK) {
468                 break;
469             }
470         }
471     } else {
472         /* Start at the top and find first non checkmark. */
473         lp = newp->sbtm;
474         lp += newp->size / sizeof(long);
475         lp--;
476         for (i = 0; i < lim; i++, lp--) {
477             if (*lp != LWP_CHECKMARK) {
478                 break;
479             }
480         }
481     }
482     lwpStatus(newp, "Thread stack %lu used %lu left %lu total",
483               labs((char *)lp - (char *)newp->lowmark) - LWP_REDZONE,
484               labs((char *)newp->himark - (char *)lp) - LWP_REDZONE,
485               labs((char *)newp->himark - (char *)newp->lowmark) - LWP_REDZONE);
486 }
487
488 #endif