]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/lwp.c
Remove some redundant parenthesis; no functional change.
[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 #ifdef BOUNDS_CHECK
35 #include <bounds/fix-args.h>
36 #include <bounds/unchecked.h>
37 #endif
38
39 struct lwpQueue LwpSchedQ[LWP_MAX_PRIO], LwpDeadQ;
40
41 struct lwpProc *LwpCurrent = NULL;
42 char **LwpContextPtr;
43 int LwpMaxpri = 0;              /* maximum priority so far */
44
45 static sigset_t oldmask;
46
47 /* for systems without strdup  */
48 #ifdef NOSTRDUP
49 extern char *strdup();
50 #endif /* NOSTRDUP */
51
52 static void lwpStackCheckInit(struct lwpProc *newp);
53 static void lwpStackCheck(struct lwpProc *newp);
54 static void lwpStackCheckUsed(struct lwpProc *newp);
55
56 /* check stack direction */
57 static int
58 growsdown(void *x)
59 {
60     int y;
61
62 #ifdef BOUNDS_CHECK
63     BOUNDS_CHECKING_OFF;
64 #endif
65     y = (x > (void *)&y);
66
67 #ifdef BOUNDS_CHECK
68     BOUNDS_CHECKING_ON;
69 #endif
70
71     return y;
72 }
73
74 /*
75  * lwpReschedule -- schedule another process.  we also check for dead
76  * processes here and free them.
77  */
78 void
79 lwpReschedule(void)
80 {
81     static int lcount = LCOUNT;
82     static struct lwpProc *nextp;
83     static int i;
84     static sigset_t tmask;
85
86     if (LwpCurrent && (LwpCurrent->flags & LWP_STACKCHECK)) {
87         lwpStackCheck(LwpCurrent);
88     }
89     if (!--lcount) {
90         int p = lwpSetPriority(LWP_MAX_PRIO - 1);
91         lcount = LCOUNT;
92         sigprocmask(SIG_SETMASK, &oldmask, &tmask);
93         sigprocmask(SIG_SETMASK, &tmask, &oldmask);
94         LwpCurrent->pri = p;
95     }
96
97     /* destroy dead threads */
98     lwpStatus(LwpCurrent, "Cleaning dead queue");
99     while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
100         if (nextp == LwpCurrent) {
101             lwpStatus(nextp, "OOOPS, we are running already dead thread");
102             exit(1);
103         }
104         lwpDestroy(nextp);
105         lwpStatus(LwpCurrent, "Destroying done");
106     }
107
108     for (i = LwpMaxpri + 1; i--;) {
109         while (NULL != (nextp = lwpGetFirst(&LwpSchedQ[i]))) {
110             if (!nextp->dead)
111                 break;
112             /* clean up after dead bodies */
113             lwpStatus(nextp, "got a dead body");
114             if (nextp == LwpCurrent) {
115                 lwpStatus(nextp, "we are in it -- will bury later");
116                 lwpAddTail(&LwpDeadQ, nextp);
117             } else {
118                 lwpDestroy(nextp);
119 /*                              fprintf(stderr,  "Destroying done\n"); */
120             }
121             nextp = 0;
122         }
123         if (nextp)
124             break;
125     }
126     if (LwpCurrent == 0 && nextp == 0) {
127         fprintf(stderr, "No processes to run!\n");
128         exit(1);
129     }
130     if (LwpCurrent)
131         lwpStatus(LwpCurrent, "switch out");
132     /* do context switch */
133 #ifdef BOUNDS_CHECK
134     BOUNDS_CHECKING_OFF;
135 #endif
136
137 #if defined(hpc)
138     {
139         int endpoint;
140
141         endpoint = &endpoint;
142         if (initcontext == NULL || endpoint < startpoint) {
143             i = lwpSave(LwpCurrent->context);
144         } else {
145             LwpCurrent->size = endpoint - startpoint;
146             LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
147             memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
148             if (i = lwpSave(LwpCurrent->context)) {
149                 memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
150                 i = 1;
151             }
152         }
153     }
154 #else
155     i = lwpSave(LwpCurrent->context);
156 #endif
157 #ifdef BOUNDS_CHECK
158     BOUNDS_CHECKING_ON;
159 #endif
160
161     if (LwpCurrent != nextp && !(LwpCurrent && i)) {
162         /* restore previous context */
163         lwpStatus(nextp, "switch in %d", nextp->pri);
164         LwpCurrent = nextp;
165         *LwpContextPtr = LwpCurrent->ud;
166 #ifdef BOUNDS_CHECK
167         BOUNDS_CHECKING_OFF;
168 #endif
169         lwpRestore(LwpCurrent->context);
170
171 #ifdef BOUNDS_CHECK
172         BOUNDS_CHECKING_ON;
173 #endif
174     }
175 }
176
177 /*
178  * lwpEntryPoint -- process entry point.
179  */
180 void
181 lwpEntryPoint(void)
182 {
183     sigset_t set;
184
185 #ifdef BOUNDS_CHECK
186     BOUNDS_CHECKING_OFF;
187 #endif
188     sigemptyset(&set);
189     sigaddset(&set, SIGALRM);
190     sigprocmask(SIG_SETMASK, &set, &oldmask);
191     *LwpContextPtr = LwpCurrent->ud;
192
193     lwpStatus(LwpCurrent, "starting at entry point");
194     (*LwpCurrent->entry)(LwpCurrent->ud);
195     lwpExit();
196 #ifdef BOUNDS_CHECK
197     BOUNDS_CHECKING_ON;
198 #endif
199
200
201 }
202
203 /*
204  * lwpCreate -- create a process.
205  */
206 struct lwpProc *
207 lwpCreate(int priority, void (*entry)(void *), int size, int flags, char *name, char *desc, int argc, char **argv, void *ud)
208 {
209     struct lwpProc *newp;
210     int *s, x;
211 #ifdef UCONTEXT
212     stack_t sp;
213 #else  /* UCONTEXT */
214     void *sp;
215 #endif /* UCONTEXT */
216     unsigned long stackp;
217
218     if (!(newp = malloc(sizeof(struct lwpProc))))
219         return 0;
220     if (flags & LWP_STACKCHECK) {
221         /* Add a 1K buffer on each side of the stack */
222         size += 2 * LWP_REDZONE;
223     }
224     size += LWP_EXTRASTACK;
225     size += sizeof(stkalign_t);
226     if (!(s = malloc(size)))
227         return 0;
228     newp->flags = flags;
229     newp->name = strdup(name);
230     newp->desc = strdup(desc);
231     newp->entry = entry;
232     newp->argc = argc;
233     newp->argv = argv;
234     newp->ud = ud;
235     if ((newp->flags & LWP_STACKCHECK) == 0) {
236         stackp = growsdown((void *)&x)
237             ? (unsigned long)s + size - sizeof(stkalign_t) - LWP_EXTRASTACK
238             : (unsigned long)s + LWP_EXTRASTACK;
239 #ifdef UCONTEXT
240         sp.ss_sp = (void *)(stackp & -sizeof(stkalign_t));
241         sp.ss_size = size;
242         sp.ss_flags = 0;
243 #else  /* UCONTEXT */
244         sp = (void *)(stackp & -sizeof(stkalign_t));
245 #endif /* UCONTEXT */
246     } else {
247         if (growsdown(&x)) {
248             /* round address off to stkalign_t */
249             stackp = ((long)s) + size - LWP_REDZONE -
250                 LWP_EXTRASTACK - sizeof(stkalign_t);
251 #ifdef UCONTEXT
252             sp.ss_sp = (void *)(stackp & -sizeof(stkalign_t));
253             sp.ss_size = size;
254             sp.ss_flags = 0;
255             newp->lowmark = (void *)(((long)sp.ss_sp) + LWP_EXTRASTACK);
256 #else  /* UCONTEXT */
257             sp = (void *)(stackp & -sizeof(stkalign_t));
258             newp->lowmark = (void *)(((long)sp) + LWP_EXTRASTACK);
259 #endif /* UCONTEXT */
260             newp->himark = s;
261         } else {
262             stackp = ((long)s) + LWP_REDZONE + LWP_EXTRASTACK;
263 #ifdef UCONTEXT
264             sp.ss_sp = (void *)(((long)stackp) & -sizeof(stkalign_t));
265             sp.ss_size = size;
266             sp.ss_flags = 0;
267 #else  /* UCONTEXT */
268             sp = (void *)(((long)stackp) & -sizeof(stkalign_t));
269 #endif /* UCONTEXT */
270             newp->lowmark = (void *)s;
271             newp->himark = (void *)(((long)s) + size - LWP_REDZONE);
272         }
273     }
274     if (LWP_MAX_PRIO <= priority)
275         priority = LWP_MAX_PRIO - 1;
276     if (LwpMaxpri < (newp->pri = priority))
277         LwpMaxpri = priority;
278     newp->sbtm = (void *)s;
279     newp->size = size;
280     newp->dead = 0;
281     if (flags & LWP_STACKCHECK)
282         lwpStackCheckInit(newp);
283     lwpStatus(newp, "creating process structure sbtm: %p",
284               newp->sbtm);
285     lwpReady(newp);
286     lwpReady(LwpCurrent);
287 #ifdef UCONTEXT
288     lwpInitContext(newp, &sp);  /* architecture-dependent: from arch.c */
289 #else  /* UCONTEXT */
290     lwpInitContext(newp, sp);   /* architecture-dependent: from arch.c */
291 #endif /* UCONTEXT */
292     lwpReschedule();
293     return newp;
294 }
295
296 void
297 lwpDestroy(struct lwpProc *proc)
298 {
299     if (proc->flags & LWP_STACKCHECK) {
300         lwpStackCheckUsed(proc);
301         lwpStackCheck(proc);
302     }
303     lwpStatus(proc, "destroying sbtm: %p", proc->sbtm);
304     proc->entry = 0;
305     proc->ud = 0;
306     proc->argv = 0;
307     free(proc->sbtm);
308     free(proc->name);
309     free(proc->desc);
310     proc->name = 0;
311     proc->desc = 0;
312     proc->sbtm = 0;
313     proc->lowmark = 0;
314     proc->himark = 0;
315     free(proc);
316 }
317
318 /*
319  * lwpReady -- put process on ready queue.  if null, assume current.
320  */
321 void
322 lwpReady(struct lwpProc *p)
323 {
324     if (!p)
325         p = LwpCurrent;
326     lwpStatus(p, "added to run queue");
327     lwpAddTail(&LwpSchedQ[p->pri], p);
328 }
329
330 /*
331  * return user's data
332  */
333 void *
334 lwpGetUD(struct lwpProc *p)
335 {
336     if (!p)
337         p = LwpCurrent;
338     return p->ud;
339 }
340
341 /*
342  * set user's data
343  */
344 void
345 lwpSetUD(struct lwpProc *p, char *ud)
346 {
347     if (!p)
348         p = LwpCurrent;
349     p->ud = ud;
350 }
351
352 /*
353  * set name & desc
354  */
355 void
356 lwpSetDesc(struct lwpProc *p, char *name, char *desc)
357 {
358     if (!p)
359         p = LwpCurrent;
360     free(p->name);
361     free(p->desc);
362     p->name = strdup(name);
363     p->desc = strdup(desc);
364 }
365
366 /*
367  * lwpYield -- yield the processor to another thread.
368  */
369 void
370 lwpYield(void)
371 {
372     lwpStatus(LwpCurrent, "yielding control");
373     lwpReady(LwpCurrent);
374     lwpReschedule();
375 }
376
377 /*
378  * cause the current process to be scheduled for deletion.
379  */
380 void
381 lwpExit(void)
382 {
383     lwpStatus(LwpCurrent, "marking self as dead");
384     LwpCurrent->dead = 1;
385     lwpYield();
386 }
387
388 /*
389  * mark another process as dead, so it will never be rescheduled.
390  * remove any lingering FD action
391  */
392 void
393 lwpTerminate(struct lwpProc *p)
394 {
395     lwpStatus(p, "terminating process");
396     p->dead = 1;
397     if (p->fd >= 0)
398         lwpWakeupFd(p);
399 }
400
401 /*
402  * set the thread's priority, returning the old.
403  * if the new priority is lower than the old, we reschedule.
404  */
405 int
406 lwpSetPriority(int new)
407 {
408     int old = LwpCurrent->pri;
409
410     if (LWP_MAX_PRIO <= new)
411         new = LWP_MAX_PRIO - 1;
412     if (LwpMaxpri < new)
413         LwpMaxpri = new;
414     LwpCurrent->pri = new;
415     lwpStatus(LwpCurrent, "resetting priority (%d -> %d)", old, new);
416     if (new < old)
417         lwpYield();
418     return old;
419 }
420
421 /*
422  * initialise the coroutine structures
423  */
424 struct lwpProc *
425 lwpInitSystem(int pri, char **ctxptr, int flags)
426 {
427     struct lwpQueue *q;
428     int i, *stack;
429     struct lwpProc *sel;
430
431     LwpContextPtr = ctxptr;
432     if (pri < 1)
433         pri = 1;
434     /* *LwpContextPtr = 0; */
435     if (!(LwpCurrent = calloc(1, sizeof(struct lwpProc))))
436         return 0;
437     if (!(stack = malloc(64)))
438         return 0;
439     if (LWP_MAX_PRIO <= pri)
440         pri = LWP_MAX_PRIO - 1;
441     if (LwpMaxpri < pri)
442         LwpMaxpri = pri;
443     LwpCurrent->next = 0;
444     LwpCurrent->sbtm = stack;   /* dummy stack for "main" */
445     LwpCurrent->pri = pri;
446     LwpCurrent->dead = 0;
447     LwpCurrent->flags = flags & ~LWP_STACKCHECK;
448     LwpCurrent->name = "Main";
449     for (i = LWP_MAX_PRIO, q = LwpSchedQ; i--; q++)
450         q->head = q->tail = 0;
451     LwpDeadQ.head = LwpDeadQ.tail = 0;
452     /* must be lower in priority than us for this to work right */
453     sel = lwpCreate(0, lwpSelect, 16384, flags, "EventHandler",
454                     "Select (main loop) Event Handler", 0, 0, 0);
455     lwpInitSelect(sel);
456     return LwpCurrent;
457 }
458
459 /* lwpStackCheckInit
460  *
461  * Initialize the entire stack (including both redzones) with the stack
462  * check mark.  Thus, we can get some indication of how much stack was
463  * used.
464  */
465 static void
466 lwpStackCheckInit(struct lwpProc *newp)
467 {
468     register int i;
469     register long *lp;
470
471     int lim = newp->size / sizeof(long);
472     if (!newp || !newp->sbtm)
473         return;
474     for (lp = newp->sbtm, i = 0; i < lim; i++, lp++) {
475         *lp = LWP_CHECKMARK;
476     }
477 }
478
479 /* lwpStackCheck
480  *
481  * Check if the thread has overflowed/underflowed its stack.
482  * Should that happen, abort the process, as we cannot recover.
483  */
484 static void
485 lwpStackCheck(struct lwpProc *newp)
486 {
487     register int end, amt;
488     register unsigned int i;
489     register long *lp;
490     register int growsDown;
491     int marker;
492
493     if (CANT_HAPPEN(!newp || !newp->himark || !newp->lowmark))
494         return;
495     growsDown = growsdown(&marker);
496     for (lp = newp->himark, i = 0; i < LWP_REDZONE / sizeof(long);
497          i++, lp++) {
498         if (*lp == LWP_CHECKMARK)
499             continue;
500         /* Stack overflow. */
501         if (growsDown) {
502             end = i;
503             while (i < LWP_REDZONE / sizeof(long)) {
504                 if (*lp++ != LWP_CHECKMARK)
505                     end = i;
506                 i++;
507             }
508             amt = (end + 1) * sizeof(long);
509         } else {
510             amt = (i + 1) * sizeof(long);
511         }
512         logerror("Thread %s stack overflow %d bytes (of %u)",
513                  newp->name, amt,
514                  newp->size - 2 * LWP_REDZONE - (int)sizeof(stkalign_t));
515         abort();
516     }
517     for (lp = newp->lowmark, i = 0; i < LWP_REDZONE / sizeof(long);
518          i++, lp++) {
519         if (*lp == LWP_CHECKMARK)
520             continue;
521         /* Stack underflow. */
522         if (growsDown) {
523             end = i;
524             while (i < LWP_REDZONE / sizeof(long)) {
525                 if (*lp++ != LWP_CHECKMARK)
526                     end = i;
527                 i++;
528             }
529             amt = (end + 1) * sizeof(long);
530         } else {
531             amt = (LWP_REDZONE - i + 1) * sizeof(long);
532         }
533         logerror("Thread %s stack underflow %d bytes (of %u)",
534                   newp->name, amt,
535                  newp->size - 2 * LWP_REDZONE - (int)sizeof(stkalign_t));
536         abort();
537     }
538 }
539
540 /* lwpStackCheckUsed
541  *
542  * Figure out how much stack was used by this thread.
543  */
544 static void
545 lwpStackCheckUsed(struct lwpProc *newp)
546 {
547     register int i;
548     register long *lp;
549     register int lim;
550     int marker;
551
552     if (!newp || !newp->sbtm)
553         return;
554     lim = newp->size / sizeof(long);
555     if (growsdown(&marker)) {
556         /* Start at the bottom and find first non checkmark. */
557         for (lp = newp->sbtm, i = 0; i < lim; i++, lp++) {
558             if (*lp != LWP_CHECKMARK) {
559                 break;
560             }
561         }
562     } else {
563         /* Start at the top and find first non checkmark. */
564         lp = newp->sbtm;
565         lp += newp->size / sizeof(long);
566         lp--;
567         for (i = 0; i < lim; i++, lp--) {
568             if (*lp != LWP_CHECKMARK) {
569                 break;
570             }
571         }
572     }
573     lwpStatus(newp, "Thread stack %lu used %lu left %lu total",
574               labs((char *)lp - (char *)newp->lowmark) - LWP_REDZONE,
575               labs((char *)newp->himark - (char *)lp) - LWP_REDZONE,
576               labs((char *)newp->himark - (char *)newp->lowmark) - LWP_REDZONE);
577 }
578
579 #endif