* Steve McClure, 1994-2000
*/
+#include <stdlib.h>
#include "lwp.h"
#include "lwpint.h"
#if defined(_EMPTH_LWP)
/*
- * Implement machine-dependent functions lwpInitContext(), lwpSave(),
- * lwpRestore().
- *
- * If lwpSave() and lwpRestore() are #def'd to setjmp() and longjmp(),
- * then lwpInitContext() needs to set up the jmp_buf for a longjmp(),
- * similar to setjmp(). To figure that out for another machine, check
- * their source or reverse engineer.
+ * Implement machine-dependent functions lwpNewContext(),
+ * lwpSwitchContext().
*/
#if defined UCONTEXT
+
/*
- * Alternate aproach using setcontext and getcontext instead of setjmp and
- * longjump. This should work on any SVr4 machine independant of
- * architecture. Unfortunately some changes are still nessesary in lwp.c.
- * Tested on IRIX 5.3
+ * Alternate aproach using setcontext and getcontext instead of setjmp
+ * and longjump. This should work on any SVr4 machine independant of
+ * architecture.
*/
-void
-lwpInitContext(struct lwpProc *newp, stack_t *spp)
+int
+lwpNewContext(struct lwpProc *newp, int stacksz)
{
- getcontext(&newp->context);
- newp->context.uc_stack = *spp;
+ char *s;
+ int size, redsize;
+
+ /* Make size a multiple of sizeof(long) to keep things aligned */
+ stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
+ /* Add a red zone on each side of the stack for LWP_STACKCHECK */
+ redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
+ size = stacksz + 2 * redsize;
+
+ s = malloc(size);
+ if (!s)
+ return -1;
+
+ newp->sbtm = s;
+ newp->size = size;
+ newp->ustack = s + redsize;
+ newp->usize = stacksz;
+
+ if (getcontext(&newp->context) < 0)
+ return -1;
+ newp->context.uc_stack.ss_sp = newp->ustack;
+ newp->context.uc_stack.ss_size = newp->usize;
+ newp->context.uc_stack.ss_flags = 0;
newp->context.uc_link = NULL;
makecontext(&newp->context, lwpEntryPoint, 0);
+ return 0;
}
-#elif defined(hpc)
+void
+lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
+{
+ if (!oldp) {
+ setcontext(&nextp->context);
+ abort();
+ } else {
+ if (swapcontext(&oldp->context, &nextp->context) < 0)
+ abort();
+ }
+}
+
+#else /* !UCONTEXT */
+
+/*
+ * If lwpSave() and lwpRestore() are #def'd to setjmp() and longjmp(),
+ * then lwpInitContext() needs to set up the jmp_buf for a longjmp(),
+ * similar to setjmp(). To figure that out for another machine, check
+ * their source or reverse engineer.
+ */
+
+#if defined(hpc)
+
+#define STKALIGN 64
static struct lwpProc *tempcontext;
static struct lwpProc *initcontext = NULL;
lwpEntryPoint();
}
-void
+static void
lwpInitContext(struct lwpProc *newp, void *sp)
{
struct lwpProc holder;
}
}
-int
+static int
lwpSave(jmp_buf jb)
{
int endpoint;
#elif defined(hpux)
-void
+#define STKALIGN 64
+
+static void
lwpInitContext(volatile struct lwpProc *volatile newp, void *sp)
{
static jmp_buf *cpp;
if (!lwpSave(LwpCurrent->context)) {
- cpp = (jmp_buf *) & newp->context;
+ cpp = (jmp_buf *)&newp->context;
asm volatile ("ldw %0, %%sp"::"o" (sp));
if (!lwpSave(*cpp))
lwpRestore(LwpCurrent->context);
}
}
-int
+static int
lwpSave(jmp_buf jb)
{
/* save stack pointer and return program counter */
asm(".LABEL _comefrom_");
}
-void
+static void
lwpRestore(jmp_buf jb)
{
/* restore stack pointer and program counter */
#elif defined(FBSD)
-void
+static void
lwpInitContext(struct lwpProc *newp, void *sp)
{
setjmp(newp->context);
#elif defined(__linux__)
-void
+static void
lwpInitContext(struct lwpProc *newp, void *sp)
{
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
#elif defined(SUN3)
-void
+static void
lwpInitContext(struct lwpProc *newp, void *sp)
{
newp->context[2] = (int)sp;
#elif defined(SUN4)
-void
+static void
lwpInitContext(struct lwpProc *newp, void *sp)
{
static jmp_buf *cpp;
}
}
+#define lwpSave(x) _setjmp(x)
+#define lwpRestore(x) _longjmp(x, 1)
+
#elif defined(ALPHA)
#include <c_asm.h>
-void
+static void
lwpInitContext(struct lwpProc *newp, void *sp)
{
extern long *_gp;
newp->context[34] = (long)sp; /* stack pointer */
}
-int
+static int
lwpSave(jmp_buf jb)
{
return _setjmp(jb);
}
-void
+static void
lwpRestore(jmp_buf jb)
{
/* resume, but get the pv from the jmp_buf */
}
#elif defined(AIX32)
+
+#define LWP_EXTRASTACK 12
+
/* Code is in .s files, as compiler doesn't grok asm */
+extern int lwpSave(jmp_buf);
+extern void lwpRestore(jmp_buf);
+extern void lwpInitContext(struct lwpProc *);
+
#endif
+#ifndef LWP_EXTRASTACK
+#define LWP_EXTRASTACK 0
+#endif
+#ifndef STKALIGN
+#define STKALIGN sizeof(double)
+#endif
+#ifndef lwpSave
+#define lwpSave(x) setjmp(x)
+#endif
+#ifndef lwpRestore
+#define lwpRestore(x) longjmp(x, 1)
+#endif
+
+int
+lwpNewContext(struct lwpProc *newp, int stacksz)
+{
+ char *s, *sp;
+ int size, redsize;
+
+ if (CANT_HAPPEN(STKALIGN == 0|| (STKALIGN & (STKALIGN - 1))))
+ return -1; /* STKALIGN not power of 2 */
+
+ /* Make size a multiple of sizeof(long) to keep things aligned */
+ stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
+ /* Add a red zone on each side of the stack for LWP_STACKCHECK */
+ redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
+ size = stacksz + 2 * redsize + LWP_EXTRASTACK + STKALIGN - 1;
+
+ s = malloc(size);
+ if (!s)
+ return -1;
+
+ if (LwpStackGrowsDown) {
+ /*
+ * Stack layout for stack growing downward:
+ * ptr block size
+ * --------------------------------------
+ * red zone LWP_REDZONE
+ * sp -> extra LWP_EXTRASTACK
+ * ustack -> stack stacksz
+ * red zone LWP_REDZONE
+ * waste STKALIGN - 1 - x
+ * sp is aligned to a multiple of STKALIGN.
+ */
+ sp = s + redsize + stacksz;
+ sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
+ newp->ustack = sp - stacksz;
+ } else {
+ /*
+ * Stack layout for stack growing upward:
+ * ptr block size
+ * --------------------------------------
+ * waste x
+ * red zone LWP_REDZONE
+ * sp -> stack stacksz
+ * ustack -> extra LWP_EXTRASTACK
+ * red zone LWP_REDZONE
+ * waste STKALIGN - 1 - x
+ * sp is aligned to a multiple of STKALIGN.
+ */
+ sp = s + redsize + LWP_EXTRASTACK;
+ sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
+ newp->ustack = sp - LWP_EXTRASTACK;
+ }
+ newp->sbtm = s;
+ newp->size = size;
+ newp->usize = stacksz + LWP_EXTRASTACK;
+ lwpInitContext(newp, sp);
+ return 0;
+}
+
+void
+lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
+{
+ if (!(oldp && lwpSave(oldp->context)))
+ lwpRestore(nextp->context);
+}
+
+#endif /* !UCONTEXT */
+
#endif
struct lwpProc *LwpCurrent = NULL;
char **LwpContextPtr;
int LwpMaxpri = 0; /* maximum priority so far */
+int LwpStackGrowsDown;
static sigset_t oldmask;
fprintf(stderr, "No processes to run!\n");
exit(1);
}
- if (LwpCurrent)
- lwpStatus(LwpCurrent, "switch out");
- /* do context switch */
- i = LwpCurrent && lwpSave(LwpCurrent->context);
- if (LwpCurrent != nextp && !i) {
- /* restore previous context */
- lwpStatus(nextp, "switch in %d", nextp->pri);
+ if (LwpCurrent != nextp) {
+ struct lwpProc *oldp = LwpCurrent;
+ if (oldp)
+ lwpStatus(oldp, "switch out");
LwpCurrent = nextp;
- *LwpContextPtr = LwpCurrent->ud;
- lwpRestore(LwpCurrent->context);
+ *LwpContextPtr = nextp->ud;
+ lwpSwitchContext(oldp, nextp);
+ lwpStatus(nextp, "switch in %d", nextp->pri);
}
}
lwpCreate(int priority, void (*entry)(void *), int stacksz, int flags, char *name, char *desc, int argc, char **argv, void *ud)
{
struct lwpProc *newp;
- char *s, *sp;
- int size, redsize, x;
-#ifdef UCONTEXT
- stack_t usp;
-#endif /* UCONTEXT */
-
- if (CANT_HAPPEN(STKALIGN == 0|| (STKALIGN & (STKALIGN - 1))))
- return NULL; /* STKALIGN not power of 2 */
+
if (!(newp = malloc(sizeof(struct lwpProc))))
return 0;
- /* Make size a multiple of sizeof(long) to keep things aligned */
- stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
- /* Add a red zone on each side of the stack for LWP_STACKCHECK */
- redsize = flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
- size = stacksz + 2 * redsize + LWP_EXTRASTACK + STKALIGN - 1;
- if (!(s = malloc(size)))
- return 0;
newp->flags = flags;
newp->name = strdup(name);
newp->desc = strdup(desc);
newp->argc = argc;
newp->argv = argv;
newp->ud = ud;
- if (growsdown(&x)) {
- /*
- * Stack layout for stack growing downward:
- * ptr block size
- * --------------------------------------
- * waste x
- * red zone LWP_REDZONE
- * sp -> extra LWP_EXTRASTACK
- * ustack -> stack stacksz
- * red zone LWP_REDZONE
- * waste STKALIGN - 1 - x
- * sp is aligned to a multiple of STKALIGN.
- */
- sp = s + redsize + stacksz;
- sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
- newp->ustack = sp - stacksz;
- } else {
- /*
- * Stack layout for stack growing upward:
- * ptr block size
- * --------------------------------------
- * waste x
- * red zone LWP_REDZONE
- * sp -> stack stacksz
- * ustack -> extra LWP_EXTRASTACK
- * red zone LWP_REDZONE
- * waste STKALIGN - 1 - x
- * sp is aligned to a multiple of STKALIGN.
- */
- sp = s + redsize + LWP_EXTRASTACK;
- sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
- newp->ustack = sp - LWP_EXTRASTACK;
- }
- newp->usize = stacksz + LWP_EXTRASTACK;
+ newp->dead = 0;
if (LWP_MAX_PRIO <= priority)
priority = LWP_MAX_PRIO - 1;
if (LwpMaxpri < (newp->pri = priority))
LwpMaxpri = priority;
- newp->sbtm = s;
- newp->size = size;
- newp->dead = 0;
- if (flags & LWP_STACKCHECK)
- lwpStackCheckInit(newp);
+ lwpNewContext(newp, stacksz);
lwpStatus(newp, "creating process structure %p (sbtm %p)",
newp, newp->sbtm);
+ if (flags & LWP_STACKCHECK)
+ lwpStackCheckInit(newp);
lwpReady(newp);
lwpReady(LwpCurrent);
-#ifdef UCONTEXT
- usp.ss_sp = s + redsize;
- usp.ss_size = stacksz;
- usp.ss_flags = 0;
- lwpInitContext(newp, &usp); /* architecture-dependent: from arch.c */
-#else /* UCONTEXT */
- lwpInitContext(newp, sp); /* architecture-dependent: from arch.c */
-#endif /* UCONTEXT */
lwpReschedule();
return newp;
}
lwpInitSystem(int pri, char **ctxptr, int flags)
{
struct lwpQueue *q;
- int i, *stack;
+ int i, *stack, marker;
struct lwpProc *sel;
LwpContextPtr = ctxptr;
if (pri < 1)
pri = 1;
/* *LwpContextPtr = 0; */
+ LwpStackGrowsDown = growsdown(&marker);
if (!(LwpCurrent = calloc(1, sizeof(struct lwpProc))))
return 0;
if (!(stack = malloc(64)))
int *btm = (int *)(newp->ustack - LWP_REDZONE);
int *top = (int *)(newp->ustack + newp->usize + LWP_REDZONE);
int n = LWP_REDZONE / sizeof(int);
- int i, lo_clean, hi_clean, marker, overflow, underflow;
+ int i, lo_clean, hi_clean, overflow, underflow;
for (i = 0; i < n && btm[i] == LWP_CHECKMARK; i++) ;
lo_clean = i;
for (i = 1; i <= n && top[-i] == LWP_CHECKMARK; i++) ;
hi_clean = i - 1;
- if (growsdown(&marker)) {
+ if (LwpStackGrowsDown) {
overflow = n - lo_clean;
underflow = n - hi_clean;
} else {
int *base = (int *)newp->ustack;
int *lim = (int *)(newp->ustack + newp->usize);
int total = (lim + 1 - base) * sizeof(int);
- int marker, used, *p;
+ int used, *p;
- if (growsdown(&marker)) {
+ if (LwpStackGrowsDown) {
for (p = base; p < lim && *p == LWP_CHECKMARK; ++p) ;
used = (lim - p) * sizeof(int);
} else {
char *name;
};
-#ifdef UCONTEXT
-void lwpInitContext(struct lwpProc *, stack_t *);
-#define lwpSave(x) getcontext(&(x))
-#define lwpRestore(x) setcontext(&(x))
-#else /* !UCONTEXT */
-#if defined(hpux) && !defined(hpc)
-void lwpInitContext(volatile struct lwpProc * volatile, void *);
-#else
-void lwpInitContext(struct lwpProc *, void *);
-#endif
-#if defined(hpc)
-int lwpSave(jmp_buf);
-#define lwpRestore(x) longjmp(x, 1)
-#elif defined(hpux) || defined(AIX32) || defined(ALPHA)
-int lwpSave(jmp_buf);
-void lwpRestore(jmp_buf);
-#elif defined(SUN4)
-#define lwpSave(x) _setjmp(x)
-#define lwpRestore(x) _longjmp(x, 1)
-#else
-#define lwpSave(x) setjmp(x)
-#define lwpRestore(x) longjmp(x, 1)
-#endif
-#endif /* !UCONTEXT */
-
-#ifdef AIX32
-/* AIX needs 12 extra bytes above the stack; we add it here */
-#define LWP_EXTRASTACK 3*sizeof(long)
-#else
-#define LWP_EXTRASTACK 0
-#endif
-
#define LWP_REDZONE 1024 /* make this a multiple of 1024 */
/* XXX Note that this assumes sizeof(long) == 4 */
#define LWP_CHECKMARK 0x5a5a5a5aL
-#ifdef hpux
-#define STKALIGN 64
-#else
-#define STKALIGN sizeof(double)
-#endif
+extern int LwpStackGrowsDown;
-/* internal routines */
+int lwpNewContext(struct lwpProc *, int);
+void lwpSwitchContext(struct lwpProc *, struct lwpProc *);
void lwpAddTail(struct lwpQueue *, struct lwpProc *);
struct lwpProc *lwpGetFirst(struct lwpQueue *);
void lwpReady(struct lwpProc *);