2 * lwp.c -- lightweight process creation, destruction and manipulation.
3 * Copyright (C) 1991-3 Stephen Crane.
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.
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.
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.
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.
30 #include "prototypes.h"
32 #if defined(_EMPTH_LWP)
35 #include <bounds/fix-args.h>
36 #include <bounds/unchecked.h>
40 extern struct lwpProc *initcontext;
41 extern int startpoint;
44 struct lwpQueue LwpSchedQ[LWP_MAX_PRIO], LwpDeadQ;
46 struct lwpProc *LwpCurrent = NULL;
48 int LwpMaxpri=0; /* maximum priority so far */
51 static sigset_t oldmask;
52 #else /* POSIXSIGNALS */
54 #endif /* POSIXSIGNALS */
56 /* for systems without strdup */
58 extern char *strdup();
61 static void lwpStackCheckInit();
62 static int lwpStackCheck();
63 static void lwpStackCheckUsed();
65 /* check stack direction */
66 static int growsdown (x)
84 * lwpReschedule -- schedule another process. we also check for dead
85 * processes here and free them.
89 extern struct lwpQueue LwpSchedQ[];
90 static int lcount = LCOUNT;
91 static struct lwpProc *nextp;
94 static sigset_t tmask;
95 #endif /* POSIXSIGNALS */
97 if (LwpCurrent && (LwpCurrent->flags & LWP_STACKCHECK)) {
98 lwpStackCheck(LwpCurrent);
101 int p = lwpSetPriority(LWP_MAX_PRIO-1);
104 sigprocmask (SIG_SETMASK, &oldmask, &tmask);
105 sigprocmask (SIG_SETMASK, &tmask, &oldmask);
106 #else /* POSIXSIGNALS */
107 sigsetmask(sigsetmask(oldmask));
108 #endif /* POSIXSIGNALS */
112 /* destroy dead threads */
113 lwpStatus(LwpCurrent, "Cleaning dead queue");
114 while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
115 if (nextp == LwpCurrent) {
117 "OOOPS, we are running already dead thread");
121 lwpStatus(LwpCurrent, "Destroying done");
124 for (i=LwpMaxpri+1; i--; ) {
125 while (NULL != (nextp = lwpGetFirst(&LwpSchedQ[i]))) {
128 /* clean up after dead bodies */
129 lwpStatus(nextp, "got a dead body");
130 if (nextp == LwpCurrent) {
132 "we are in it -- will bury later");
133 lwpAddTail(&LwpDeadQ, nextp);
137 /* fprintf(stderr, "Destroying done\n"); */
144 if (LwpCurrent == 0 && nextp == 0) {
145 fprintf(stderr, "No processes to run!\n");
149 lwpStatus(LwpCurrent, "switch out");
150 /* do context switch */
159 endpoint = &endpoint;
160 if (initcontext == NULL || endpoint < startpoint) {
161 i = lwpSave(LwpCurrent->context);
163 LwpCurrent->size = endpoint - startpoint;
164 LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
165 memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
166 if (i = lwpSave(LwpCurrent->context)) {
167 memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
173 i = lwpSave(LwpCurrent->context);
179 if (LwpCurrent != nextp &&
180 !(LwpCurrent && i)) {
181 /* restore previous context */
182 lwpStatus(nextp, "switch in", nextp->pri);
184 *LwpContextPtr = LwpCurrent->ud;
188 lwpRestore(LwpCurrent->context);
197 * lwpEntryPoint -- process entry point.
201 extern struct lwpProc *LwpCurrent;
204 #endif /* POSIXSIGNALS */
211 sigaddset (&set, SIGALRM);
212 sigprocmask (SIG_SETMASK, &set, &oldmask);
213 #else /* POSIXSIGNALS */
215 #endif /* POSIXSIGNALS */
216 *LwpContextPtr = LwpCurrent->ud;
218 lwpStatus(LwpCurrent, "starting at entry point");
219 (*LwpCurrent->entry)(LwpCurrent->argc, LwpCurrent->argv,
230 * lwpCreate -- create a process.
233 lwpCreate(priority, entry, size, flags, name, desc, argc, argv, ud)
244 extern struct lwpProc *LwpCurrent;
245 struct lwpProc *newp;
251 #endif /* UCONTEXT */
252 unsigned long stackp;
254 if (!(newp = (struct lwpProc *)malloc(sizeof(struct lwpProc))))
256 if (flags & LWP_STACKCHECK) {
257 /* Add a 1K buffer on each side of the stack */
258 size += 2 * LWP_REDZONE;
260 size += LWP_EXTRASTACK;
261 size += sizeof(stkalign_t);
262 if (!(s = (int *)malloc(size)))
265 newp->name = strdup(name);
266 newp->desc = strdup(desc);
271 if ((newp->flags & LWP_STACKCHECK) == 0) {
272 stackp = growsdown((void *)&x) ?
273 (((long)s) + size - sizeof(stkalign_t) - LWP_EXTRASTACK) :
274 (long) s + LWP_EXTRASTACK;
276 sp.ss_sp = (void *)(stackp & -sizeof(stkalign_t));
280 sp = (void *)(stackp & -sizeof(stkalign_t));
281 #endif /* UCONTEXT */
284 /* round address off to stkalign_t */
285 stackp = ((long)s) + size - LWP_REDZONE -
286 LWP_EXTRASTACK - sizeof(stkalign_t);
288 sp.ss_sp = (void *)(stackp & -sizeof(stkalign_t));
291 newp->lowmark = (void *)(((long) sp.ss_sp) + LWP_EXTRASTACK);
293 sp = (void *)(stackp & -sizeof(stkalign_t));
294 newp->lowmark = (void *)(((long) sp) + LWP_EXTRASTACK);
295 #endif /* UCONTEXT */
298 stackp = ((long)s) + LWP_REDZONE + LWP_EXTRASTACK;
300 sp.ss_sp = (void *)(((long)stackp) &
301 -sizeof(stkalign_t));
305 sp = (void *)(((long)stackp) & -sizeof(stkalign_t));
306 #endif /* UCONTEXT */
307 newp->lowmark = (void *)s;
308 newp->himark = (void *)(((long)s) + size - LWP_REDZONE);
311 if (LWP_MAX_PRIO <= priority)
312 priority = LWP_MAX_PRIO-1;
313 if (LwpMaxpri < (newp->pri = priority))
314 LwpMaxpri = priority;
315 newp->sbtm = (void *)s;
318 if (flags & LWP_STACKCHECK)
319 lwpStackCheckInit(newp);
320 lwpStatus(newp, "creating process structure sbtm: %d",
323 lwpReady(LwpCurrent);
325 lwpInitContext(newp, &sp); /* architecture-dependent: from arch.c */
327 lwpInitContext(newp, sp); /* architecture-dependent: from arch.c */
328 #endif /* UCONTEXT */
333 void lwpDestroy(proc)
334 struct lwpProc *proc;
336 if (proc->flags & LWP_STACKCHECK){
337 lwpStackCheckUsed(proc);
340 lwpStatus(proc, "destroying sbtm: %d", (int)proc->sbtm);
344 free((char *)proc->sbtm);
356 * lwpReady -- put process on ready queue. if null, assume current.
361 extern struct lwpProc *LwpCurrent;
362 extern struct lwpQueue LwpSchedQ[];
366 lwpStatus(p, "added to run queue");
367 lwpAddTail(&LwpSchedQ[p->pri], p);
396 void lwpSetDesc(p, name, desc)
405 p->name = strdup(name);
406 p->desc = strdup(desc);
410 * lwpYield -- yield the processor to another thread.
414 lwpStatus(LwpCurrent, "yielding control");
415 lwpReady(LwpCurrent);
420 * cause the current process to be scheduled for deletion.
424 lwpStatus(LwpCurrent, "marking self as dead");
425 LwpCurrent->dead = 1;
430 * mark another process as dead, so it will never be rescheduled.
431 * remove any lingering FD action
436 lwpStatus(p, "terminating process");
443 * set the thread's priority, returning the old.
444 * if the new priority is lower than the old, we reschedule.
446 int lwpSetPriority(new)
449 int old = LwpCurrent->pri;
451 if (LWP_MAX_PRIO <= new)
452 new = LWP_MAX_PRIO-1;
455 LwpCurrent->pri = new;
456 lwpStatus(LwpCurrent, "resetting priority (%d -> %d)", old, new);
463 * initialise the coroutine structures
465 struct lwpProc *lwpInitSystem(pri, ctxptr, flags)
470 extern struct lwpQueue LwpSchedQ[];
471 extern struct lwpProc *LwpCurrent;
476 LwpContextPtr = ctxptr;
479 /* *LwpContextPtr = 0; */
480 if (!(LwpCurrent = (struct lwpProc *)calloc (1, sizeof(struct lwpProc))))
482 if (!(stack = (int *)malloc(64)))
484 if (LWP_MAX_PRIO <= pri)
485 pri = LWP_MAX_PRIO-1;
488 LwpCurrent->next = 0;
489 LwpCurrent->sbtm = stack; /* dummy stack for "main" */
490 LwpCurrent->pri = pri;
491 LwpCurrent->dead = 0;
492 LwpCurrent->flags = flags;
493 LwpCurrent->name = "Main";
494 for (i=LWP_MAX_PRIO, q=LwpSchedQ; i--; q++)
495 q->head = q->tail = 0;
496 LwpDeadQ.head = LwpDeadQ.tail = 0;
497 /* must be lower in priority than us for this to work right */
498 sel = lwpCreate(0, lwpSelect, 16384, flags, "EventHandler",
499 "Select (main loop) Event Handler", 0, 0, 0);
506 * Initialize the entire stack (including both redzones) with the stack
507 * check mark. Thus, we can get some indication of how much stack was
510 static void lwpStackCheckInit(newp)
511 struct lwpProc *newp;
516 int lim = newp->size/sizeof(long);
517 if (!newp || !newp->sbtm)
519 for (lp=newp->sbtm,i=0; i < lim; i++,lp++) {
526 * Check if the thread has overflowed/underflowed its stack.
528 * If an problem occurs, it is not corrected.
529 * The buffer is not cleaned up, nor is the thread terminated.
530 * Cleaning up the buffer would be a mistake, and terminating
531 * the thread, well, could be done. Should more like take
532 * down the entire process.
534 static int lwpStackCheck(newp)
535 struct lwpProc *newp;
537 register int end, amt;
538 register unsigned int i;
540 register int growsDown;
543 if (!newp || !newp->himark || !newp->lowmark)
545 growsDown = growsdown(&marker);
546 for (lp=newp->himark,i=0; i < LWP_REDZONE/sizeof(long); i++,lp++) {
547 if (*lp == LWP_CHECKMARK)
549 /* Stack overflow. */
552 while (i < LWP_REDZONE/sizeof(long)) {
553 if (*lp++ != LWP_CHECKMARK)
557 amt = (end+1) * sizeof(long);
559 amt = (i+1) * sizeof(long);
561 lwpStatus(newp, "Thread stack overflowed %d bytes (of %u)",
562 amt, newp->size - 2*LWP_REDZONE - sizeof(stkalign_t));
565 for (lp=newp->lowmark,i=0; i < LWP_REDZONE/sizeof(long); i++,lp++) {
566 if (*lp == LWP_CHECKMARK)
568 /* Stack underflow. */
571 while (i < LWP_REDZONE/sizeof(long)) {
572 if (*lp++ != LWP_CHECKMARK)
576 amt = (end+1) * sizeof(long);
578 amt = (LWP_REDZONE - i+1) * sizeof(long);
580 lwpStatus(newp, "Thread stack underflow %d bytes (of %u)",
581 amt, newp->size - 2*LWP_REDZONE - sizeof(stkalign_t));
589 * Figure out how much stack was used by this thread.
591 static void lwpStackCheckUsed(newp)
592 struct lwpProc *newp;
599 if (!newp || !newp->sbtm)
601 lim = newp->size/sizeof(long);
602 if (growsdown(&marker)) {
603 /* Start at the bottom and find first non checkmark. */
604 for (lp=newp->sbtm,i=0; i < lim; i++,lp++) {
605 if (*lp != LWP_CHECKMARK) {
610 /* Start at the top and find first non checkmark. */
612 lp += newp->size/sizeof(long);
614 for (i=0; i < lim; i++, lp--) {
615 if (*lp != LWP_CHECKMARK) {
620 lwpStatus(newp, "stack use: %u bytes (of %u total)",
621 (i * sizeof(long)) - LWP_REDZONE,
622 newp->size - 2*LWP_REDZONE - sizeof(stkalign_t));