Import of Empire 4.2.12
This commit is contained in:
commit
d8b7fdfae1
817 changed files with 126589 additions and 0 deletions
64
src/lib/lwp/Makefile
Normal file
64
src/lib/lwp/Makefile
Normal file
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
# Empire - A multi-player, client/server Internet based war game.
|
||||
# Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
# Ken Stevens, Steve McClure
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
|
||||
# related information and legal notices. It is expected that any future
|
||||
# projects/authors will amend these files as needed.
|
||||
#
|
||||
# Makefile - Wolfpack, 1996
|
||||
|
||||
# Note that these could have been listed 1 per line, but I chose to just
|
||||
# stick them all together this way to shorten the file.
|
||||
|
||||
include ../../../build.conf
|
||||
include ../../make.src
|
||||
include ../../make.defs
|
||||
|
||||
LIB = $(SRCDIR)/lib/liblwp.a
|
||||
|
||||
OBJS = arch.o lwp.o queue.o sel.o sem.o status.o
|
||||
|
||||
MIPSOBJS = mipsarch.o
|
||||
|
||||
AIXOBJS = lwpInit.o lwpRestore.o lwpSave.o
|
||||
|
||||
GENMASTER = GLOBALCFLAGS="$(GLOBALCFLAGS)" GLOBALLFLAGS="$(GLOBALLFLAGS)"
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(OBJS) $(EXTRAOBJS)
|
||||
rm -f $(LIB)
|
||||
ar cq $(LIB) $(OBJS) $(EXTRAOBJS)
|
||||
$(RANLIB) $(LIB)
|
||||
|
||||
nt:
|
||||
|
||||
mipsultrix:
|
||||
make EXTRAOBJS="$(MIPSOBJS)" $(GENMASTER)
|
||||
|
||||
aix:
|
||||
make EXTRAOBJS="$(AIXOBJS)" $(GENMASTER)
|
||||
|
||||
clean:
|
||||
-(rm -f $(OBJS) $(AIXOBJS) $(MIPSOBJS))
|
||||
|
||||
include ../../make.rules
|
||||
include Makedepend
|
428
src/lib/lwp/arch.c
Normal file
428
src/lib/lwp/arch.c
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
|
||||
* related information and legal notices. It is expected that any future
|
||||
* projects/authors will amend these files as needed.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* arch.c: architecture-dependant process context code
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Dave Pare, 1994
|
||||
* Steve McClure, 1994-2000
|
||||
*/
|
||||
|
||||
#include "prototypes.h"
|
||||
|
||||
#if defined(_EMPTH_LWP)
|
||||
|
||||
#if (!defined(AIX32))
|
||||
|
||||
#include "lwp.h"
|
||||
|
||||
#include "lwpint.h"
|
||||
|
||||
#if defined(hpc)
|
||||
|
||||
static struct lwpProc *tempcontext;
|
||||
struct lwpProc *initcontext=NULL;
|
||||
int startpoint;
|
||||
|
||||
startcontext()
|
||||
{
|
||||
int space[10000];
|
||||
int x;
|
||||
|
||||
startpoint = (void *) &x;
|
||||
if (!setjmp(initcontext->context)) longjmp(tempcontext->context,1);
|
||||
|
||||
if (!setjmp(tempcontext->context)) longjmp(LwpCurrent->context,1);
|
||||
|
||||
lwpEntryPoint();
|
||||
}
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
struct lwpProc holder;
|
||||
int endpoint;
|
||||
|
||||
if (initcontext == NULL) {
|
||||
initcontext = (struct lwpProc *) malloc (sizeof(struct lwpProc));
|
||||
tempcontext = &holder;
|
||||
if (!setjmp(tempcontext->context)) startcontext();
|
||||
}
|
||||
|
||||
tempcontext = newp;
|
||||
endpoint = &endpoint;
|
||||
if (endpoint < startpoint) {
|
||||
if (!setjmp(LwpCurrent->context)) longjmp(initcontext->context,1);
|
||||
} else {
|
||||
LwpCurrent->size = endpoint - startpoint;
|
||||
LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
|
||||
memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
|
||||
if (!setjmp(LwpCurrent->context)) longjmp(initcontext->context,1);
|
||||
memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(hpux)
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
volatile struct lwpProc *volatile newp;
|
||||
void *sp;
|
||||
{
|
||||
static jmp_buf *cpp;
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
if (!lwpSave(LwpCurrent->context)) {
|
||||
cpp = (jmp_buf *)&newp->context;
|
||||
asm volatile ("ldw %0, %%sp": : "o" (sp));
|
||||
if (!lwpSave(*cpp))
|
||||
lwpRestore(LwpCurrent->context);
|
||||
lwpEntryPoint();
|
||||
}
|
||||
}
|
||||
|
||||
int lwpSave(jb)
|
||||
jmp_buf jb;
|
||||
{
|
||||
/* save stack pointer and return program counter */
|
||||
asm ("stw %sp, 4(%arg0)");
|
||||
asm ("stw %rp, 8(%arg0)");
|
||||
|
||||
/* save "callee save" registers */
|
||||
asm ("stw %r3, 12(%arg0)");
|
||||
asm ("stw %r4, 16(%arg0)");
|
||||
asm ("stw %r5, 20(%arg0)");
|
||||
asm ("stw %r6, 24(%arg0)");
|
||||
asm ("stw %r7, 28(%arg0)");
|
||||
asm ("stw %r8, 32(%arg0)");
|
||||
asm ("stw %r9, 36(%arg0)");
|
||||
asm ("stw %r10, 40(%arg0)");
|
||||
asm ("stw %r11, 44(%arg0)");
|
||||
asm ("stw %r12, 48(%arg0)");
|
||||
asm ("stw %r13, 52(%arg0)");
|
||||
asm ("stw %r14, 56(%arg0)");
|
||||
asm ("stw %r15, 60(%arg0)");
|
||||
asm ("stw %r16, 64(%arg0)");
|
||||
asm ("stw %r17, 68(%arg0)");
|
||||
asm ("stw %r18, 72(%arg0)");
|
||||
|
||||
/* save "callee save" space register */
|
||||
asm volatile ("mfsp %sr3, %r1");
|
||||
asm ("stw %r1, 0(%arg0)");
|
||||
|
||||
/* indicate "true return" from saved() */
|
||||
asm ("ldi 0, %ret0");
|
||||
|
||||
asm (".LABEL _comefrom_");
|
||||
}
|
||||
|
||||
void
|
||||
lwpRestore(jb)
|
||||
jmp_buf jb;
|
||||
{
|
||||
/* restore stack pointer and program counter */
|
||||
asm volatile ("ldw 4(%arg0), %sp");
|
||||
asm volatile ("ldw 8(%arg0), %rp");
|
||||
|
||||
/* restore "callee save" space register */
|
||||
asm volatile ("ldw 0(%arg0), %r1");
|
||||
asm volatile ("mtsp %r1, %sr3");
|
||||
|
||||
/* restore "callee save" registers */
|
||||
asm volatile ("ldw 12(%arg0), %r3");
|
||||
asm volatile ("ldw 16(%arg0), %r4");
|
||||
asm volatile ("ldw 20(%arg0), %r5");
|
||||
asm volatile ("ldw 24(%arg0), %r6");
|
||||
asm volatile ("ldw 28(%arg0), %r7");
|
||||
asm volatile ("ldw 32(%arg0), %r8");
|
||||
asm volatile ("ldw 36(%arg0), %r9");
|
||||
asm volatile ("ldw 40(%arg0), %r10");
|
||||
asm volatile ("ldw 44(%arg0), %r11");
|
||||
asm volatile ("ldw 48(%arg0), %r12");
|
||||
asm volatile ("ldw 52(%arg0), %r13");
|
||||
asm volatile ("ldw 56(%arg0), %r14");
|
||||
asm volatile ("ldw 60(%arg0), %r15");
|
||||
asm volatile ("ldw 64(%arg0), %r16");
|
||||
asm volatile ("ldw 68(%arg0), %r17");
|
||||
asm volatile ("ldw 72(%arg0), %r18");
|
||||
|
||||
/* warp to saved() to unwind the frame correctly */
|
||||
asm volatile ("bl _comefrom_, %r0");
|
||||
asm volatile ("ldi 1, %ret0");
|
||||
}
|
||||
|
||||
#elif defined(BSD386)
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
newp->context[2] = (int)sp;
|
||||
newp->context[0] = (int)lwpEntryPoint;
|
||||
}
|
||||
|
||||
#elif defined(FBSD)
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
setjmp (newp->context);
|
||||
newp->context->_jb[2] = (int)sp;
|
||||
newp->context->_jb[3] = (int)sp;
|
||||
newp->context->_jb[0] = (int)lwpEntryPoint;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||||
#if defined(__PPC__)
|
||||
newp->context->__jmpbuf[JB_GPR1] = (int) sp;
|
||||
newp->context->__jmpbuf[JB_LR] = (int) lwpEntryPoint;
|
||||
#else
|
||||
newp->context->__jmpbuf[JB_SP] = (int) sp;
|
||||
newp->context->__jmpbuf[JB_BP] = (int) sp;
|
||||
newp->context->__jmpbuf[JB_PC] = (int) lwpEntryPoint;
|
||||
#endif
|
||||
#else
|
||||
newp->context->__sp = sp;
|
||||
newp->context->__bp = sp;
|
||||
newp->context->__pc = (void *)lwpEntryPoint;
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(SUN3)
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
newp->context[2] = (int)sp;
|
||||
newp->context[3] = (int)lwpEntryPoint;
|
||||
}
|
||||
|
||||
#elif defined(__vax)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void lwpInitContext(newp, stack)
|
||||
struct lwpProc *newp;
|
||||
void *stack;
|
||||
{
|
||||
int *sp = (int*)stack;
|
||||
int *fp = 0;
|
||||
|
||||
/* Build root frame on new stack for lwpEntryPoint */
|
||||
*--sp = 0; /* pc */
|
||||
*--sp = (int)fp; /* fp */
|
||||
*--sp = 0; /* ap */
|
||||
*--sp = 0; /* psw */
|
||||
*--sp = 0; /* condition handler */
|
||||
fp = sp;
|
||||
|
||||
/* Build stack frame to return from. */
|
||||
*--sp = (int)lwpEntryPoint+2;/* pc */
|
||||
*--sp = (int)fp; /* fp */
|
||||
*--sp = 0; /* ap */
|
||||
*--sp = 0; /* psw */
|
||||
*--sp = 0; /* condition handler */
|
||||
fp = sp;
|
||||
|
||||
/* Fill in the context */
|
||||
/* Note: This is *not* how libc fills out jump buffers. */
|
||||
newp->context[0] = 0; /* r6 */
|
||||
newp->context[1] = 0;
|
||||
newp->context[2] = 0;
|
||||
newp->context[3] = 0;
|
||||
newp->context[4] = 0;
|
||||
newp->context[5] = 0; /* r11 */
|
||||
newp->context[6] = 0; /* ap */
|
||||
newp->context[7] = (int)fp; /* fp */
|
||||
return;
|
||||
}
|
||||
|
||||
int lwpSave(jb)
|
||||
jmp_buf jb;
|
||||
{
|
||||
asm("movl 4(ap), r0"); /* r0 = &jb */
|
||||
asm("movl r6, (r0)"); /* jb[0] = r6 */
|
||||
asm("movl r7, 4(r0)");
|
||||
asm("movl r8, 8(r0)");
|
||||
asm("movl r9, 12(r0)");
|
||||
asm("movl r10, 16(r0)");
|
||||
asm("movl r11, 20(r0)");
|
||||
asm("movl ap, 24(r0)");
|
||||
asm("movl fp, 28(r0)"); /* jb[7] = fp */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lwpRestore(jb)
|
||||
jmp_buf jb;
|
||||
{
|
||||
asm("movl 4(ap), r0"); /* r0 = &jb */
|
||||
asm("movl (r0), r6"); /* r6 = jb[0] */
|
||||
asm("movl 4(r0), r7");
|
||||
asm("movl 8(r0), r8");
|
||||
asm("movl 12(r0), r9");
|
||||
asm("movl 16(r0), r10");
|
||||
asm("movl 20(r0), r11");
|
||||
asm("movl 24(r0), ap");
|
||||
asm("movl 28(r0), fp"); /* fp = jb[7] */
|
||||
asm("movl $1, r0"); /* faked return 1 from lwpSave() */
|
||||
asm("ret");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(SUN4)
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
static jmp_buf *cpp;
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
bzero(newp->context, sizeof(newp->context));
|
||||
newp->context[0] = (int)sp;
|
||||
/* preserve cpp for new context */
|
||||
cpp = (jmp_buf *)&newp->context;
|
||||
if (!_setjmp(LwpCurrent->context)) {
|
||||
/* create new context */
|
||||
/* flush registers */
|
||||
asm ("ta 0x03");
|
||||
/* %o0 <- newp */
|
||||
asm ("ld [%fp+0x44], %o0");
|
||||
/* %o1 <- newp->context[0] */
|
||||
asm ("ld [%o0], %o1");
|
||||
/* create min frame on new stack */
|
||||
asm ("save %o1,-96, %sp");
|
||||
if (!_setjmp(*cpp))
|
||||
_longjmp(LwpCurrent->context, 1);
|
||||
lwpEntryPoint();
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__USLC__) && defined(i386)
|
||||
|
||||
/* USL/Unixware on an Intel 386/486/... processor.
|
||||
* Tested on Unixware v1.1.2, based on SYSV R4.2
|
||||
*/
|
||||
|
||||
/* As per normal empire documentation, there is none.
|
||||
*
|
||||
* But, what we are attempting to do here is set up a longjump
|
||||
* context buffer so that the lwpEntryPoint is called when
|
||||
* the thread starts.
|
||||
*
|
||||
* I.E., what a setjmp/longjmp call set would do.
|
||||
*
|
||||
* How to figure this out? Well, without the setjmp code, you
|
||||
* need to reverse engineer it by printing out the context buffer
|
||||
* and the processor registers, and mapping which ones need
|
||||
* to be set.
|
||||
*
|
||||
* Alternatively, you can single instruction step through the longjmp
|
||||
* function, and figure out the offsets that it uses.
|
||||
*
|
||||
* Using offsets in bytes,
|
||||
* context + 0x04 [1] -> esi (general purpose reg)
|
||||
* context + 0x08 [2] -> edi (general purpose reg)
|
||||
* context + 0x0C [3] -> ebp (general purpose or parameter passing)
|
||||
* context + 0x10 [4] -> esp (stack)
|
||||
* context + 0x14 [5] -> jump location for return
|
||||
*/
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
newp->context[4] = (int)sp;
|
||||
newp->context[5] = (int)lwpEntryPoint;
|
||||
}
|
||||
|
||||
#elif defined UCONTEXT
|
||||
|
||||
/*
|
||||
* Alternate aproach using setcontext en getcontext in stead of setjmp and
|
||||
* longjump. This should work on any SVr4 machine independant of
|
||||
* architecture. Unfortunaltely some changes are still nessesary in lwp.c.
|
||||
* Tested on IRIX 5.3
|
||||
*/
|
||||
|
||||
void lwpInitContext(newp, spp)
|
||||
struct lwpProc *newp;
|
||||
stack_t *spp;
|
||||
{
|
||||
getcontext (&(newp->context));
|
||||
newp->context.uc_stack.ss_sp = spp->ss_sp;
|
||||
newp->context.uc_stack.ss_size = spp->ss_size;
|
||||
makecontext (&(newp->context), lwpEntryPoint, 0);
|
||||
}
|
||||
|
||||
#elif defined(ALPHA)
|
||||
|
||||
#include <c_asm.h>
|
||||
|
||||
void lwpInitContext(newp, sp)
|
||||
struct lwpProc *newp;
|
||||
void *sp;
|
||||
{
|
||||
extern long *_gp;
|
||||
|
||||
/* register values obtained from setjmp.h */
|
||||
_setjmp(newp->context);
|
||||
newp->context[2] = (long)lwpEntryPoint; /* program counter */
|
||||
newp->context[30] = (long)lwpEntryPoint; /* return address */
|
||||
newp->context[31] = (long)lwpEntryPoint; /* fake program value (!) */
|
||||
newp->context[34] = (long)sp; /* stack pointer */
|
||||
}
|
||||
|
||||
int lwpSave(jb)
|
||||
jmp_buf jb;
|
||||
{
|
||||
return _setjmp(jb);
|
||||
}
|
||||
|
||||
void lwpRestore(jb)
|
||||
jmp_buf jb;
|
||||
{
|
||||
/* resume, but get the pv from the jmp_buf */
|
||||
asm("ldq %pv, 248(%a0)");
|
||||
asm("stq %a0, 16(%sp)");
|
||||
/* generates a warning, but functions just fine */
|
||||
asm("bsr %ra, __longjump_resume");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
625
src/lib/lwp/lwp.c
Normal file
625
src/lib/lwp/lwp.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* lwp.c -- lightweight process creation, destruction and manipulation.
|
||||
* Copyright (C) 1991-3 Stephen Crane.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
|
||||
* Imperial College of Science, Technology and Medicine, 180 Queen's
|
||||
* Gate, London SW7 2BZ, England.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lwp.h"
|
||||
#include "lwpint.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#if defined(_EMPTH_LWP)
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
#include <bounds/fix-args.h>
|
||||
#include <bounds/unchecked.h>
|
||||
#endif
|
||||
|
||||
#ifdef hpc
|
||||
extern struct lwpProc *initcontext;
|
||||
extern int startpoint;
|
||||
#endif
|
||||
|
||||
struct lwpQueue LwpSchedQ[LWP_MAX_PRIO], LwpDeadQ;
|
||||
|
||||
struct lwpProc *LwpCurrent = NULL;
|
||||
char **LwpContextPtr;
|
||||
int LwpMaxpri=0; /* maximum priority so far */
|
||||
|
||||
#ifdef POSIXSIGNALS
|
||||
static sigset_t oldmask;
|
||||
#else /* POSIXSIGNALS */
|
||||
static int oldmask;
|
||||
#endif /* POSIXSIGNALS */
|
||||
|
||||
/* for systems without strdup */
|
||||
#ifdef NOSTRDUP
|
||||
extern char *strdup();
|
||||
#endif /* NOSTRDUP */
|
||||
|
||||
static void lwpStackCheckInit();
|
||||
static int lwpStackCheck();
|
||||
static void lwpStackCheckUsed();
|
||||
|
||||
/* check stack direction */
|
||||
static int growsdown (x)
|
||||
void *x;
|
||||
{
|
||||
int y;
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_OFF;
|
||||
#endif
|
||||
y = (x > (void *)&y);
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_ON;
|
||||
#endif
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/*
|
||||
* lwpReschedule -- schedule another process. we also check for dead
|
||||
* processes here and free them.
|
||||
*/
|
||||
void lwpReschedule()
|
||||
{
|
||||
extern struct lwpQueue LwpSchedQ[];
|
||||
static int lcount = LCOUNT;
|
||||
static struct lwpProc *nextp;
|
||||
static int i;
|
||||
#ifdef POSIXSIGNALS
|
||||
static sigset_t tmask;
|
||||
#endif /* POSIXSIGNALS */
|
||||
|
||||
if (LwpCurrent && (LwpCurrent->flags & LWP_STACKCHECK)) {
|
||||
lwpStackCheck(LwpCurrent);
|
||||
}
|
||||
if (!--lcount) {
|
||||
int p = lwpSetPriority(LWP_MAX_PRIO-1);
|
||||
lcount = LCOUNT;
|
||||
#ifdef POSIXSIGNALS
|
||||
sigprocmask (SIG_SETMASK, &oldmask, &tmask);
|
||||
sigprocmask (SIG_SETMASK, &tmask, &oldmask);
|
||||
#else /* POSIXSIGNALS */
|
||||
sigsetmask(sigsetmask(oldmask));
|
||||
#endif /* POSIXSIGNALS */
|
||||
LwpCurrent->pri = p;
|
||||
}
|
||||
|
||||
/* destroy dead threads */
|
||||
lwpStatus(LwpCurrent, "Cleaning dead queue");
|
||||
while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
|
||||
if (nextp == LwpCurrent) {
|
||||
lwpStatus(nextp,
|
||||
"OOOPS, we are running already dead thread");
|
||||
exit(1);
|
||||
}
|
||||
lwpDestroy(nextp);
|
||||
lwpStatus(LwpCurrent, "Destroying done");
|
||||
}
|
||||
|
||||
for (i=LwpMaxpri+1; i--; ) {
|
||||
while (NULL != (nextp = lwpGetFirst(&LwpSchedQ[i]))) {
|
||||
if (!nextp->dead)
|
||||
break;
|
||||
/* clean up after dead bodies */
|
||||
lwpStatus(nextp, "got a dead body");
|
||||
if (nextp == LwpCurrent) {
|
||||
lwpStatus(nextp,
|
||||
"we are in it -- will bury later");
|
||||
lwpAddTail(&LwpDeadQ, nextp);
|
||||
}
|
||||
else{
|
||||
lwpDestroy(nextp);
|
||||
/* fprintf(stderr, "Destroying done\n"); */
|
||||
}
|
||||
nextp = 0;
|
||||
}
|
||||
if (nextp)
|
||||
break;
|
||||
}
|
||||
if (LwpCurrent == 0 && nextp == 0) {
|
||||
fprintf(stderr, "No processes to run!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (LwpCurrent)
|
||||
lwpStatus(LwpCurrent, "switch out");
|
||||
/* do context switch */
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_OFF;
|
||||
#endif
|
||||
|
||||
#if defined(hpc)
|
||||
{
|
||||
int endpoint;
|
||||
|
||||
endpoint = &endpoint;
|
||||
if (initcontext == NULL || endpoint < startpoint) {
|
||||
i = lwpSave(LwpCurrent->context);
|
||||
} else {
|
||||
LwpCurrent->size = endpoint - startpoint;
|
||||
LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
|
||||
memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
|
||||
if (i = lwpSave(LwpCurrent->context)) {
|
||||
memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
i = lwpSave(LwpCurrent->context);
|
||||
#endif
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_ON;
|
||||
#endif
|
||||
|
||||
if (LwpCurrent != nextp &&
|
||||
!(LwpCurrent && i)) {
|
||||
/* restore previous context */
|
||||
lwpStatus(nextp, "switch in", nextp->pri);
|
||||
LwpCurrent = nextp;
|
||||
*LwpContextPtr = LwpCurrent->ud;
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_OFF;
|
||||
#endif
|
||||
lwpRestore(LwpCurrent->context);
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_ON;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lwpEntryPoint -- process entry point.
|
||||
*/
|
||||
void lwpEntryPoint()
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
#ifdef POSIXSIGNALS
|
||||
sigset_t set;
|
||||
#endif /* POSIXSIGNALS */
|
||||
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_OFF;
|
||||
#endif
|
||||
#ifdef POSIXSIGNALS
|
||||
sigemptyset (&set);
|
||||
sigaddset (&set, SIGALRM);
|
||||
sigprocmask (SIG_SETMASK, &set, &oldmask);
|
||||
#else /* POSIXSIGNALS */
|
||||
sigsetmask(SIGNALS);
|
||||
#endif /* POSIXSIGNALS */
|
||||
*LwpContextPtr = LwpCurrent->ud;
|
||||
|
||||
lwpStatus(LwpCurrent, "starting at entry point");
|
||||
(*LwpCurrent->entry)(LwpCurrent->argc, LwpCurrent->argv,
|
||||
LwpCurrent->ud);
|
||||
lwpExit();
|
||||
#ifdef BOUNDS_CHECK
|
||||
BOUNDS_CHECKING_ON;
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* lwpCreate -- create a process.
|
||||
*/
|
||||
struct lwpProc *
|
||||
lwpCreate(priority, entry, size, flags, name, desc, argc, argv, ud)
|
||||
int priority;
|
||||
void (*entry)();
|
||||
int size;
|
||||
int flags;
|
||||
char *name;
|
||||
char *desc;
|
||||
int argc;
|
||||
char *argv[];
|
||||
void *ud;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
struct lwpProc *newp;
|
||||
int *s, x;
|
||||
#ifdef UCONTEXT
|
||||
stack_t sp;
|
||||
#else /* UCONTEXT */
|
||||
void *sp;
|
||||
#endif /* UCONTEXT */
|
||||
unsigned long stackp;
|
||||
|
||||
if (!(newp = (struct lwpProc *)malloc(sizeof(struct lwpProc))))
|
||||
return (0);
|
||||
if (flags & LWP_STACKCHECK) {
|
||||
/* Add a 1K buffer on each side of the stack */
|
||||
size += 2 * LWP_REDZONE;
|
||||
}
|
||||
size += LWP_EXTRASTACK;
|
||||
size += sizeof(stkalign_t);
|
||||
if (!(s = (int *)malloc(size)))
|
||||
return (0);
|
||||
newp->flags = flags;
|
||||
newp->name = strdup(name);
|
||||
newp->desc = strdup(desc);
|
||||
newp->entry = entry;
|
||||
newp->argc = argc;
|
||||
newp->argv = argv;
|
||||
newp->ud = ud;
|
||||
if ((newp->flags & LWP_STACKCHECK) == 0) {
|
||||
stackp = growsdown((void *)&x) ?
|
||||
(((long)s) + size - sizeof(stkalign_t) - LWP_EXTRASTACK) :
|
||||
(long) s + LWP_EXTRASTACK;
|
||||
#ifdef UCONTEXT
|
||||
sp.ss_sp = (void *)(stackp & -sizeof(stkalign_t));
|
||||
sp.ss_size = size;
|
||||
sp.ss_flags = 0;
|
||||
#else /* UCONTEXT */
|
||||
sp = (void *)(stackp & -sizeof(stkalign_t));
|
||||
#endif /* UCONTEXT */
|
||||
} else {
|
||||
if (growsdown(&x)) {
|
||||
/* round address off to stkalign_t */
|
||||
stackp = ((long)s) + size - LWP_REDZONE -
|
||||
LWP_EXTRASTACK - sizeof(stkalign_t);
|
||||
#ifdef UCONTEXT
|
||||
sp.ss_sp = (void *)(stackp & -sizeof(stkalign_t));
|
||||
sp.ss_size = size;
|
||||
sp.ss_flags = 0;
|
||||
newp->lowmark = (void *)(((long) sp.ss_sp) + LWP_EXTRASTACK);
|
||||
#else /* UCONTEXT */
|
||||
sp = (void *)(stackp & -sizeof(stkalign_t));
|
||||
newp->lowmark = (void *)(((long) sp) + LWP_EXTRASTACK);
|
||||
#endif /* UCONTEXT */
|
||||
newp->himark = s;
|
||||
} else {
|
||||
stackp = ((long)s) + LWP_REDZONE + LWP_EXTRASTACK;
|
||||
#ifdef UCONTEXT
|
||||
sp.ss_sp = (void *)(((long)stackp) &
|
||||
-sizeof(stkalign_t));
|
||||
sp.ss_size = size;
|
||||
sp.ss_flags = 0;
|
||||
#else /* UCONTEXT */
|
||||
sp = (void *)(((long)stackp) & -sizeof(stkalign_t));
|
||||
#endif /* UCONTEXT */
|
||||
newp->lowmark = (void *)s;
|
||||
newp->himark = (void *)(((long)s) + size - LWP_REDZONE);
|
||||
}
|
||||
}
|
||||
if (LWP_MAX_PRIO <= priority)
|
||||
priority = LWP_MAX_PRIO-1;
|
||||
if (LwpMaxpri < (newp->pri = priority))
|
||||
LwpMaxpri = priority;
|
||||
newp->sbtm = (void *)s;
|
||||
newp->size = size;
|
||||
newp->dead = 0;
|
||||
if (flags & LWP_STACKCHECK)
|
||||
lwpStackCheckInit(newp);
|
||||
lwpStatus(newp, "creating process structure sbtm: %d",
|
||||
(int)newp->sbtm);
|
||||
lwpReady(newp);
|
||||
lwpReady(LwpCurrent);
|
||||
#ifdef UCONTEXT
|
||||
lwpInitContext(newp, &sp); /* architecture-dependent: from arch.c */
|
||||
#else /* UCONTEXT */
|
||||
lwpInitContext(newp, sp); /* architecture-dependent: from arch.c */
|
||||
#endif /* UCONTEXT */
|
||||
lwpReschedule();
|
||||
return (newp);
|
||||
}
|
||||
|
||||
void lwpDestroy(proc)
|
||||
struct lwpProc *proc;
|
||||
{
|
||||
if (proc->flags & LWP_STACKCHECK){
|
||||
lwpStackCheckUsed(proc);
|
||||
lwpStackCheck(proc);
|
||||
}
|
||||
lwpStatus(proc, "destroying sbtm: %d", (int)proc->sbtm);
|
||||
proc->entry = 0;
|
||||
proc->ud = 0;
|
||||
proc->argv = 0;
|
||||
free((char *)proc->sbtm);
|
||||
free(proc->name);
|
||||
free(proc->desc);
|
||||
proc->name = 0;
|
||||
proc->desc = 0;
|
||||
proc->sbtm = 0;
|
||||
proc->lowmark = 0;
|
||||
proc->himark = 0;
|
||||
free((char *)proc);
|
||||
}
|
||||
|
||||
/*
|
||||
* lwpReady -- put process on ready queue. if null, assume current.
|
||||
*/
|
||||
void lwpReady(p)
|
||||
struct lwpProc *p;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
extern struct lwpQueue LwpSchedQ[];
|
||||
|
||||
if (!p)
|
||||
p = LwpCurrent;
|
||||
lwpStatus(p, "added to run queue");
|
||||
lwpAddTail(&LwpSchedQ[p->pri], p);
|
||||
}
|
||||
|
||||
/*
|
||||
* return user's data
|
||||
*/
|
||||
void *lwpGetUD(p)
|
||||
struct lwpProc *p;
|
||||
{
|
||||
if (!p)
|
||||
p = LwpCurrent;
|
||||
return (p->ud);
|
||||
}
|
||||
|
||||
/*
|
||||
* set user's data
|
||||
*/
|
||||
void lwpSetUD(p, ud)
|
||||
struct lwpProc *p;
|
||||
char *ud;
|
||||
{
|
||||
if (!p)
|
||||
p = LwpCurrent;
|
||||
p->ud = ud;
|
||||
}
|
||||
|
||||
/*
|
||||
* set name & desc
|
||||
*/
|
||||
void lwpSetDesc(p, name, desc)
|
||||
struct lwpProc *p;
|
||||
char *name;
|
||||
char *desc;
|
||||
{
|
||||
if (!p)
|
||||
p = LwpCurrent;
|
||||
free(p->name);
|
||||
free(p->desc);
|
||||
p->name = strdup(name);
|
||||
p->desc = strdup(desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* lwpYield -- yield the processor to another thread.
|
||||
*/
|
||||
void lwpYield()
|
||||
{
|
||||
lwpStatus(LwpCurrent, "yielding control");
|
||||
lwpReady(LwpCurrent);
|
||||
lwpReschedule();
|
||||
}
|
||||
|
||||
/*
|
||||
* cause the current process to be scheduled for deletion.
|
||||
*/
|
||||
void lwpExit()
|
||||
{
|
||||
lwpStatus(LwpCurrent, "marking self as dead");
|
||||
LwpCurrent->dead = 1;
|
||||
lwpYield();
|
||||
}
|
||||
|
||||
/*
|
||||
* mark another process as dead, so it will never be rescheduled.
|
||||
* remove any lingering FD action
|
||||
*/
|
||||
void lwpTerminate(p)
|
||||
struct lwpProc *p;
|
||||
{
|
||||
lwpStatus(p, "terminating process");
|
||||
p->dead = 1;
|
||||
if (p->fd >= 0)
|
||||
lwpWakeupFd(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* set the thread's priority, returning the old.
|
||||
* if the new priority is lower than the old, we reschedule.
|
||||
*/
|
||||
int lwpSetPriority(new)
|
||||
int new;
|
||||
{
|
||||
int old = LwpCurrent->pri;
|
||||
|
||||
if (LWP_MAX_PRIO <= new)
|
||||
new = LWP_MAX_PRIO-1;
|
||||
if (LwpMaxpri < new)
|
||||
LwpMaxpri = new;
|
||||
LwpCurrent->pri = new;
|
||||
lwpStatus(LwpCurrent, "resetting priority (%d -> %d)", old, new);
|
||||
if (new < old)
|
||||
lwpYield();
|
||||
return (old);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the coroutine structures
|
||||
*/
|
||||
struct lwpProc *lwpInitSystem(pri, ctxptr, flags)
|
||||
int pri;
|
||||
char **ctxptr;
|
||||
int flags;
|
||||
{
|
||||
extern struct lwpQueue LwpSchedQ[];
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
struct lwpQueue *q;
|
||||
int i, *stack;
|
||||
struct lwpProc *sel;
|
||||
|
||||
LwpContextPtr = ctxptr;
|
||||
if (pri < 1)
|
||||
pri = 1;
|
||||
/* *LwpContextPtr = 0; */
|
||||
if (!(LwpCurrent = (struct lwpProc *)calloc (1, sizeof(struct lwpProc))))
|
||||
return (0);
|
||||
if (!(stack = (int *)malloc(64)))
|
||||
return (0);
|
||||
if (LWP_MAX_PRIO <= pri)
|
||||
pri = LWP_MAX_PRIO-1;
|
||||
if (LwpMaxpri < pri)
|
||||
LwpMaxpri = pri;
|
||||
LwpCurrent->next = 0;
|
||||
LwpCurrent->sbtm = stack; /* dummy stack for "main" */
|
||||
LwpCurrent->pri = pri;
|
||||
LwpCurrent->dead = 0;
|
||||
LwpCurrent->flags = flags;
|
||||
LwpCurrent->name = "Main";
|
||||
for (i=LWP_MAX_PRIO, q=LwpSchedQ; i--; q++)
|
||||
q->head = q->tail = 0;
|
||||
LwpDeadQ.head = LwpDeadQ.tail = 0;
|
||||
/* must be lower in priority than us for this to work right */
|
||||
sel = lwpCreate(0, lwpSelect, 16384, flags, "EventHandler",
|
||||
"Select (main loop) Event Handler", 0, 0, 0);
|
||||
lwpInitSelect(sel);
|
||||
return (LwpCurrent);
|
||||
}
|
||||
|
||||
/* lwpStackCheckInit
|
||||
*
|
||||
* Initialize the entire stack (including both redzones) with the stack
|
||||
* check mark. Thus, we can get some indication of how much stack was
|
||||
* used.
|
||||
*/
|
||||
static void lwpStackCheckInit(newp)
|
||||
struct lwpProc *newp;
|
||||
{
|
||||
register int i;
|
||||
register long *lp;
|
||||
|
||||
int lim = newp->size/sizeof(long);
|
||||
if (!newp || !newp->sbtm)
|
||||
return;
|
||||
for (lp=newp->sbtm,i=0; i < lim; i++,lp++) {
|
||||
*lp = LWP_CHECKMARK;
|
||||
}
|
||||
}
|
||||
|
||||
/* lwpStackCheck
|
||||
*
|
||||
* Check if the thread has overflowed/underflowed its stack.
|
||||
* NOTE:
|
||||
* If an problem occurs, it is not corrected.
|
||||
* The buffer is not cleaned up, nor is the thread terminated.
|
||||
* Cleaning up the buffer would be a mistake, and terminating
|
||||
* the thread, well, could be done. Should more like take
|
||||
* down the entire process.
|
||||
*/
|
||||
static int lwpStackCheck(newp)
|
||||
struct lwpProc *newp;
|
||||
{
|
||||
register int end, amt;
|
||||
register unsigned int i;
|
||||
register long *lp;
|
||||
register int growsDown;
|
||||
int marker;
|
||||
|
||||
if (!newp || !newp->himark || !newp->lowmark)
|
||||
return(1);
|
||||
growsDown = growsdown(&marker);
|
||||
for (lp=newp->himark,i=0; i < LWP_REDZONE/sizeof(long); i++,lp++) {
|
||||
if (*lp == LWP_CHECKMARK)
|
||||
continue;
|
||||
/* Stack overflow. */
|
||||
if (growsDown) {
|
||||
end = i;
|
||||
while (i < LWP_REDZONE/sizeof(long)) {
|
||||
if (*lp++ != LWP_CHECKMARK)
|
||||
end = i;
|
||||
i++;
|
||||
}
|
||||
amt = (end+1) * sizeof(long);
|
||||
} else {
|
||||
amt = (i+1) * sizeof(long);
|
||||
}
|
||||
lwpStatus(newp, "Thread stack overflowed %d bytes (of %u)",
|
||||
amt, newp->size - 2*LWP_REDZONE - sizeof(stkalign_t));
|
||||
return(0);
|
||||
}
|
||||
for (lp=newp->lowmark,i=0; i < LWP_REDZONE/sizeof(long); i++,lp++) {
|
||||
if (*lp == LWP_CHECKMARK)
|
||||
continue;
|
||||
/* Stack underflow. */
|
||||
if (growsDown) {
|
||||
end = i;
|
||||
while (i < LWP_REDZONE/sizeof(long)) {
|
||||
if (*lp++ != LWP_CHECKMARK)
|
||||
end = i;
|
||||
i++;
|
||||
}
|
||||
amt = (end+1) * sizeof(long);
|
||||
} else {
|
||||
amt = (LWP_REDZONE - i+1) * sizeof(long);
|
||||
}
|
||||
lwpStatus(newp, "Thread stack underflow %d bytes (of %u)",
|
||||
amt, newp->size - 2*LWP_REDZONE - sizeof(stkalign_t));
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* lwpStackCheckUsed
|
||||
*
|
||||
* Figure out how much stack was used by this thread.
|
||||
*/
|
||||
static void lwpStackCheckUsed(newp)
|
||||
struct lwpProc *newp;
|
||||
{
|
||||
register int i;
|
||||
register long *lp;
|
||||
register int lim;
|
||||
int marker;
|
||||
|
||||
if (!newp || !newp->sbtm)
|
||||
return;
|
||||
lim = newp->size/sizeof(long);
|
||||
if (growsdown(&marker)) {
|
||||
/* Start at the bottom and find first non checkmark. */
|
||||
for (lp=newp->sbtm,i=0; i < lim; i++,lp++) {
|
||||
if (*lp != LWP_CHECKMARK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Start at the top and find first non checkmark. */
|
||||
lp = newp->sbtm;
|
||||
lp += newp->size/sizeof(long);
|
||||
lp--;
|
||||
for (i=0; i < lim; i++, lp--) {
|
||||
if (*lp != LWP_CHECKMARK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lwpStatus(newp, "stack use: %u bytes (of %u total)",
|
||||
(i * sizeof(long)) - LWP_REDZONE,
|
||||
newp->size - 2*LWP_REDZONE - sizeof(stkalign_t));
|
||||
}
|
||||
|
||||
#endif
|
76
src/lib/lwp/lwpInit.s
Normal file
76
src/lib/lwp/lwpInit.s
Normal file
|
@ -0,0 +1,76 @@
|
|||
.set r0,0; .set SP,1; .set RTOC,2; .set r3,3; .set r4,4
|
||||
.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9
|
||||
.set LR,8
|
||||
|
||||
.rename LwpInitContext{PR},""
|
||||
.rename LwpInitContext{TC},"lwpInitContext"
|
||||
.rename LwpEntryPoint{TC},"lwpEntryPoint"
|
||||
|
||||
.lglobl LwpInitContext{PR}
|
||||
.globl .lwpInitContext
|
||||
.globl lwpInitContext{DS}
|
||||
.extern lwpEntryPoint{DS}
|
||||
|
||||
|
||||
# .text section
|
||||
|
||||
|
||||
.csect LwpInitContext{PR}
|
||||
.function .lwpInitContext{PR},.lwpInitContext,2,0
|
||||
.lwpInitContext: # 0x00000000 (LwpInitContext)
|
||||
stu SP,-0x40(SP)
|
||||
st r3,0x58(SP) # r3 = newp pointer
|
||||
st r4,0x5c(SP) # r4 = sp pointer
|
||||
.bf 234
|
||||
st SP,0x0(r4)
|
||||
st SP,0xf8(r3) # store prev SP
|
||||
st r4,0xc(r3) # store entrypoint at newp[3]
|
||||
l r3,LWPEntryPoint(RTOC)
|
||||
l r4,0x0(r3)
|
||||
l r3,0x58(SP) # load newp into r3
|
||||
st r4,0x8(r3) # store sp at newp[2]
|
||||
st RTOC,0x10(r3) # store RTOC at newp[4]
|
||||
ai SP,SP,0x40
|
||||
br
|
||||
.ef 236
|
||||
# traceback table
|
||||
.long 0x00000000
|
||||
.byte 0x00 # VERSION=0
|
||||
.byte 0x00 # LANG=TB_C
|
||||
.byte 0x20 # IS_GL=0,IS_EPROL=0,HAS_TBOFF=1
|
||||
# INT_PROC=0,HAS_CTL=0,TOCLESS=0
|
||||
# FP_PRESENT=0,LOG_ABORT=0
|
||||
.byte 0x40 # INT_HNDL=0,NAME_PRESENT=1
|
||||
# USES_ALLOCA=0,CL_DIS_INV=WALK_ONCOND
|
||||
# SAVES_CR=0,SAVES_LR=0
|
||||
.byte 0x80 # STORES_BC=1,FPR_SAVED=0
|
||||
.byte 0x00 # GPR_SAVED=0
|
||||
.byte 0x02 # FIXEDPARMS=2
|
||||
.byte 0x01 # FLOATPARMS=0,PARMSONSTK=1
|
||||
.long 0x00000000 #
|
||||
.long 0x0000002c # TB_OFFSET
|
||||
.short 14 # NAME_LEN
|
||||
.byte "lwpInitContext"
|
||||
# End of traceback table
|
||||
# End csect LwpInitContext{PR}
|
||||
|
||||
# .data section
|
||||
|
||||
|
||||
.toc # 0x00000050
|
||||
LWPInitContext:
|
||||
.tc LwpInitContext{TC},lwpInitContext{DS}
|
||||
LWPEntryPoint:
|
||||
.tc LwpEntryPoint{TC},lwpEntryPoint{DS}
|
||||
|
||||
|
||||
.csect lwpInitContext{DS}
|
||||
.long .lwpInitContext # "\0\0\0\0"
|
||||
.long TOC{TC0} # "\0\0\0P"
|
||||
.long 0x00000000 # "\0\0\0\0"
|
||||
# End csect lwpInitContext{DS}
|
||||
|
||||
|
||||
|
||||
# .bss section
|
||||
|
62
src/lib/lwp/lwpRestore.s
Normal file
62
src/lib/lwp/lwpRestore.s
Normal file
|
@ -0,0 +1,62 @@
|
|||
.set r0,0; .set SP,1; .set RTOC,2; .set r3,3; .set r4,4
|
||||
.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9
|
||||
.set LR,8
|
||||
|
||||
.rename lwpRestore{PR},""
|
||||
.rename lwpRestore{TC},"lwpRestore"
|
||||
|
||||
.lglobl lwpRestore{PR}
|
||||
.globl .lwpRestore
|
||||
.globl lwpRestore{DS}
|
||||
|
||||
|
||||
# .text section
|
||||
|
||||
|
||||
.csect lwpRestore{PR}
|
||||
.lwpRestore: # 0x00000000 (lwpRestore)
|
||||
l r5,0x8(r3)
|
||||
l SP,0xc(r3)
|
||||
l RTOC,0x10(r3)
|
||||
mtlr r5
|
||||
lil r3,0x1
|
||||
br
|
||||
# traceback table
|
||||
.long 0x00000000
|
||||
.byte 0x00 # VERSION=0
|
||||
.byte 0x00 # LANG=TB_C
|
||||
.byte 0x20 # IS_GL=0,IS_EPROL=0,HAS_TBOFF=1
|
||||
# INT_PROC=0,HAS_CTL=0,TOCLESS=0
|
||||
# FP_PRESENT=0,LOG_ABORT=0
|
||||
.byte 0x40 # INT_HNDL=0,NAME_PRESENT=1
|
||||
# USES_ALLOCA=0,CL_DIS_INV=WALK_ONCOND
|
||||
# SAVES_CR=0,SAVES_LR=0
|
||||
.byte 0x80 # STORES_BC=1,FPR_SAVED=0
|
||||
.byte 0x00 # GPR_SAVED=0
|
||||
.byte 0x01 # FIXEDPARMS=1
|
||||
.byte 0x01 # FLOATPARMS=0,PARMSONSTK=1
|
||||
.long 0x00000000 #
|
||||
.long 0x00000010 # TB_OFFSET
|
||||
.short 10 # NAME_LEN
|
||||
.byte "lwpRestore"
|
||||
# End of traceback table
|
||||
# End csect lwpRestore{PR}
|
||||
|
||||
# .data section
|
||||
|
||||
|
||||
.toc # 0x00000030
|
||||
LWPRestore:
|
||||
.tc lwpRestore{TC},lwpRestore{DS}
|
||||
|
||||
|
||||
.csect lwpRestore{DS}
|
||||
.long .lwpRestore # "\0\0\0\0"
|
||||
.long TOC{TC0} # "\0\0\0000"
|
||||
.long 0x00000000 # "\0\0\0\0"
|
||||
# End csect lwpRestore{DS}
|
||||
|
||||
|
||||
|
||||
# .bss section
|
||||
|
66
src/lib/lwp/lwpSave.s
Normal file
66
src/lib/lwp/lwpSave.s
Normal file
|
@ -0,0 +1,66 @@
|
|||
.set r0,0; .set SP,1; .set RTOC,2; .set r3,3; .set r4,4
|
||||
.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9
|
||||
.set LR,8
|
||||
|
||||
.rename lwpSave{PR},""
|
||||
.rename lwpSave{TC},"lwpSave"
|
||||
|
||||
.lglobl lwpSave{PR}
|
||||
.globl .lwpSave
|
||||
.globl lwpSave{DS}
|
||||
|
||||
|
||||
# .text section
|
||||
|
||||
|
||||
.csect lwpSave{PR}
|
||||
.lwpSave: # 0x00000000 (lwpSave)
|
||||
st SP,0xc(r3)
|
||||
st RTOC,0x10(r3)
|
||||
mflr r4
|
||||
st r4,0x8(r3)
|
||||
lil r3,0x0
|
||||
br
|
||||
# traceback table
|
||||
.long 0x00000000
|
||||
.byte 0x00 # VERSION=0
|
||||
.byte 0x00 # LANG=TB_C
|
||||
.byte 0x20 # IS_GL=0,IS_EPROL=0,HAS_TBOFF=1
|
||||
# INT_PROC=0,HAS_CTL=0,TOCLESS=0
|
||||
# FP_PRESENT=0,LOG_ABORT=0
|
||||
.byte 0x40 # INT_HNDL=0,NAME_PRESENT=1
|
||||
# USES_ALLOCA=0,CL_DIS_INV=WALK_ONCOND
|
||||
# SAVES_CR=0,SAVES_LR=0
|
||||
.byte 0x80 # STORES_BC=1,FPR_SAVED=0
|
||||
.byte 0x00 # GPR_SAVED=0
|
||||
.byte 0x01 # FIXEDPARMS=1
|
||||
.byte 0x01 # FLOATPARMS=0,PARMSONSTK=1
|
||||
.long 0x00000000 #
|
||||
.long 0x00000014 # TB_OFFSET
|
||||
.short 7 # NAME_LEN
|
||||
.byte "lwpSave"
|
||||
.byte 0 # padding
|
||||
.byte 0 # padding
|
||||
.byte 0 # padding
|
||||
# End of traceback table
|
||||
.long 0x00000000 # "\0\0\0\0"
|
||||
# End csect lwpSave{PR}
|
||||
|
||||
# .data section
|
||||
|
||||
|
||||
.toc # 0x00000038
|
||||
LWPSave:
|
||||
.tc lwpSave{TC},lwpSave{DS}
|
||||
|
||||
|
||||
.csect lwpSave{DS}
|
||||
.long .lwpSave # "\0\0\0\0"
|
||||
.long TOC{TC0} # "\0\0\0008"
|
||||
.long 0x00000000 # "\0\0\0\0"
|
||||
# End csect lwpSave{DS}
|
||||
|
||||
|
||||
|
||||
# .bss section
|
||||
|
105
src/lib/lwp/lwpint.h
Normal file
105
src/lib/lwp/lwpint.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* lwpint.h -- lwp internal structures
|
||||
*
|
||||
* Copyright (C) 1991-3 Stephen Crane.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
|
||||
* Imperial College of Science, Technology and Medicine, 180 Queen's
|
||||
* Gate, London SW7 2BZ, England.
|
||||
*/
|
||||
#ifndef _LWPINT_H
|
||||
#define _LWPINT_H
|
||||
|
||||
/* `liveness' counter: check signals every `n' visits to the scheduler */
|
||||
/* note: the lower this value, the more responsive the system but the */
|
||||
/* more inefficient the context switch time */
|
||||
#define LCOUNT -1
|
||||
|
||||
#ifdef hpux
|
||||
int lwpSave _PROTO((jmp_buf));
|
||||
void lwpRestore _PROTO((jmp_buf));
|
||||
#endif
|
||||
|
||||
#if defined(MIPS) || defined(AIX32) || defined(ALPHA) || defined(__vax)
|
||||
int lwpSave _PROTO((jmp_buf));
|
||||
void lwpRestore _PROTO((jmp_buf));
|
||||
#elif defined(SUN4)
|
||||
#define lwpSave(x) _setjmp(x)
|
||||
#define lwpRestore(x) _longjmp(x, 1)
|
||||
#elif defined (UCONTEXT)
|
||||
#define lwpSave(x) getcontext(&(x))
|
||||
#define lwpRestore(x) setcontext(&(x))
|
||||
#else
|
||||
#ifdef hpc
|
||||
#define lwpSave(x) setjmp(x)
|
||||
#define lwpRestore(x) longjmp(x, 1)
|
||||
#else
|
||||
#ifndef hpux
|
||||
#define lwpSave(x) setjmp(x)
|
||||
#define lwpRestore(x) longjmp(x, 1)
|
||||
#endif /* hpux */
|
||||
#endif /* hpc */
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#define SIGNALS sigmask(SIGALRM)
|
||||
|
||||
#ifndef hpux
|
||||
typedef double stkalign_t;
|
||||
#else
|
||||
typedef struct {
|
||||
char x[64];
|
||||
} stkalign_t;
|
||||
#endif
|
||||
|
||||
/* internal routines */
|
||||
void lwpAddTail _PROTO((struct lwpQueue *, struct lwpProc *));
|
||||
struct lwpProc *lwpGetFirst _PROTO((struct lwpQueue *));
|
||||
void lwpReschedule _PROTO((void));
|
||||
void lwpReady _PROTO((struct lwpProc *));
|
||||
void lwpOnalarm _PROTO((void));
|
||||
|
||||
#ifdef UCONTEXT
|
||||
void lwpInitContext _PROTO((struct lwpProc *, stack_t *));
|
||||
#else /* GETCONTEXT */
|
||||
#ifdef hpc
|
||||
void lwpInitContext _PROTO((struct lwpProc *, void *));
|
||||
#else
|
||||
#ifdef hpux
|
||||
void lwpInitContext _PROTO((volatile struct lwpProc *volatile, void *));
|
||||
#else
|
||||
void lwpInitContext _PROTO((struct lwpProc *, void *));
|
||||
#endif /* hpux */
|
||||
#endif /* hpc */
|
||||
#endif /* GETCONTEXT */
|
||||
void lwpEntryPoint _PROTO((void));
|
||||
void lwpInitSelect _PROTO((struct lwpProc *self));
|
||||
void lwpDestroy _PROTO((struct lwpProc *proc));
|
||||
|
||||
#endif /* _LWP_H */
|
||||
|
71
src/lib/lwp/mipsarch.s
Normal file
71
src/lib/lwp/mipsarch.s
Normal file
|
@ -0,0 +1,71 @@
|
|||
.verstamp 3 0
|
||||
.extern tzname 0
|
||||
.extern LwpCurrent 4
|
||||
.lcomm $$9 4
|
||||
.text
|
||||
.align 2
|
||||
.file 2 "arch.new.c"
|
||||
.globl lwpSave
|
||||
.ent lwpSave 2
|
||||
lwpSave:
|
||||
.option O1
|
||||
subu $sp, 32
|
||||
sw $31, 28($sp)
|
||||
sw $4, 32($sp)
|
||||
.mask 0x80000000, -4
|
||||
.frame $sp, 32, $31
|
||||
sw $0, $$9
|
||||
sw $30, 0($4)
|
||||
sw $sp, 4($4)
|
||||
sw $31, 8($4)
|
||||
sd $16, 12($4)
|
||||
sd $18, 20($4)
|
||||
sd $20, 28($4)
|
||||
sd $22, 36($4)
|
||||
lw $2, $$9
|
||||
.livereg 0x2000FF0E,0x00000FFF
|
||||
lw $31, 28($sp)
|
||||
addu $sp, 32
|
||||
j $31
|
||||
.end lwpSave
|
||||
.text
|
||||
.align 2
|
||||
.file 2 "arch.new.c"
|
||||
.globl lwpRestore
|
||||
.ent lwpRestore 2
|
||||
lwpRestore:
|
||||
.option O1
|
||||
subu $sp, 32
|
||||
sw $31, 28($sp)
|
||||
sw $4, 32($sp)
|
||||
.mask 0x80000000, -4
|
||||
.frame $sp, 32, $31
|
||||
li $14, 1
|
||||
sw $14, $$9
|
||||
lw $30, 0($4)
|
||||
lw $sp, 4($4)
|
||||
lw $31, 8($4)
|
||||
ld $16, 12($4)
|
||||
ld $18, 20($4)
|
||||
ld $20, 28($4)
|
||||
ld $22, 36($4)
|
||||
lw $2, $$9
|
||||
.livereg 0x0000FF0E,0x00000FFF
|
||||
addu $sp, 32
|
||||
j $31
|
||||
.end lwpRestore
|
||||
.text
|
||||
.align 2
|
||||
.file 2 "arch.new.c"
|
||||
.globl lwpInitContext
|
||||
.ent lwpInitContext 2
|
||||
lwpInitContext:
|
||||
.option O1
|
||||
.frame $sp, 0, $31
|
||||
sw $5, 4($4)
|
||||
la $14, lwpEntryPoint
|
||||
sw $14, 8($4)
|
||||
.livereg 0x0000FF0E,0x00000FFF
|
||||
j $31
|
||||
.end lwpInitContext
|
||||
|
115
src/lib/lwp/misc/echo.c
Normal file
115
src/lib/lwp/misc/echo.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* server.c
|
||||
*
|
||||
* lwp (echo) connection handler server
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define SP_ACCEPT 3
|
||||
#define SP_READER 3
|
||||
|
||||
#include "lwp.h"
|
||||
|
||||
struct context {
|
||||
struct lwpProc *us;
|
||||
struct sockaddr_in addr;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*ARGSUSED*/
|
||||
int readConn(argc, argv, ud)
|
||||
int argc;
|
||||
char **argv;
|
||||
void *ud;
|
||||
{
|
||||
struct context *ctx = (struct context *) ud;
|
||||
char buf[1024];
|
||||
int n;
|
||||
|
||||
while (1) {
|
||||
printf("sleeping\n");
|
||||
lwpSleepFd(ctx->fd, LWP_FD_READ);
|
||||
printf("waiting to read\n");
|
||||
if ((n = read(ctx->fd, buf, sizeof(buf))) <= 0)
|
||||
break;
|
||||
printf("got %d char\n", n);
|
||||
lwpSleepFd(ctx->fd, LWP_FD_WRITE);
|
||||
printf("waiting to write\n");
|
||||
if (write(ctx->fd, buf, n) < 0)
|
||||
break;
|
||||
printf("wrote %d char\n", n);
|
||||
}
|
||||
printf("process/fd %d exiting\n", ctx->fd);
|
||||
close(ctx->fd);
|
||||
lwpExit();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
int acceptConn(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int s;
|
||||
int ns;
|
||||
int len;
|
||||
int maxfd;
|
||||
struct context *ctx;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s port\n", *argv);
|
||||
exit(-1);
|
||||
}
|
||||
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("inet socket");
|
||||
exit(-1);
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(atoi(argv[1]));
|
||||
sin.sin_addr.s_addr = 0;
|
||||
if (bind(s, &sin, sizeof(sin)) < 0) {
|
||||
perror("inet socket bind");
|
||||
exit(-1);
|
||||
}
|
||||
if (listen(s, LISTENMAXCONN) < 0) {
|
||||
perror("inet socket listen");
|
||||
exit(-1);
|
||||
}
|
||||
maxfd = getdtablesize() - 1;
|
||||
while (1) {
|
||||
lwpSleepFd(s, LWP_FD_READ);
|
||||
len = sizeof(sin);
|
||||
ns = accept(s, &sin, &len);
|
||||
if (ns < 0) {
|
||||
perror("accept");
|
||||
exit(-1);
|
||||
}
|
||||
if (ns == maxfd) {
|
||||
fprintf(stderr, "no more connections");
|
||||
close(ns);
|
||||
}
|
||||
printf("got connection from %s\n", inet_ntoa(sin.sin_addr));
|
||||
ctx = (struct context *) malloc(sizeof(*ctx));
|
||||
ctx->addr = sin;
|
||||
ctx->fd = ns;
|
||||
ctx->us = lwpCreate(SP_READER, readConn, 8192, 0, 0, ctx);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
lwpInitSystem(1);
|
||||
lwpCreate(SP_ACCEPT, acceptConn, 8192, argc, argv, 0);
|
||||
lwpReschedule();
|
||||
/*NOTREACHED*/
|
||||
}
|
90
src/lib/lwp/misc/lwp.h
Normal file
90
src/lib/lwp/misc/lwp.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* lwp.h -- prototypes and structures for lightweight processes
|
||||
* Copyright (C) 1991-3 Stephen Crane.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
|
||||
* Imperial College of Science, Technology and Medicine, 180 Queen's
|
||||
* Gate, London SW7 2BZ, England.
|
||||
*/
|
||||
#ifndef _LWP_H
|
||||
#define _LWP_H
|
||||
|
||||
#ifndef _PROTO
|
||||
#ifdef __cplusplus
|
||||
#define _PROTO(x) x
|
||||
#else
|
||||
#define _PROTO(x) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* process control block. do *not* change the position of context */
|
||||
struct lwpProc {
|
||||
jmp_buf context; /* processor context area */
|
||||
void *sbtm; /* bottom of stack attached to it */
|
||||
int size; /* size of stack */
|
||||
void (*entry)(); /* entry point */
|
||||
int dead; /* whether the process can be rescheduled */
|
||||
int pri; /* which scheduling queue we're on */
|
||||
long runtime; /* time at which process is restarted */
|
||||
int fd; /* fd we're blocking on */
|
||||
int argc; /* initial arguments */
|
||||
char **argv;
|
||||
void *ud; /* user data */
|
||||
struct lwpProc *next;
|
||||
};
|
||||
|
||||
/* queue */
|
||||
struct lwpQueue {
|
||||
struct lwpProc *head;
|
||||
struct lwpProc *tail;
|
||||
};
|
||||
|
||||
/* semaphore */
|
||||
struct lwpSem {
|
||||
int count;
|
||||
struct lwpQueue q;
|
||||
};
|
||||
|
||||
#define LWP_FD_READ 0x1
|
||||
#define LWP_FD_WRITE 0x2
|
||||
|
||||
#define LWP_MAX_PRIO 8
|
||||
|
||||
struct lwpProc *lwpInitSystem _PROTO((int));
|
||||
struct lwpProc *lwpCreate _PROTO((int, void (*)(), int, int, char **, void *));
|
||||
void lwpExit _PROTO((void));
|
||||
void lwpTerminate _PROTO((struct lwpProc *));
|
||||
void lwpYield _PROTO((void));
|
||||
void lwpSleepFd _PROTO((int fd, int flags));
|
||||
void lwpSleepUntil _PROTO((long until));
|
||||
void lwpWakeupFd _PROTO((struct lwpProc *));
|
||||
void *lwpGetUD _PROTO((struct lwpProc *));
|
||||
void lwpSetUD _PROTO((struct lwpProc *, char *));
|
||||
int lwpSetPriority _PROTO((int));
|
||||
void lwpReschedule _PROTO(());
|
||||
|
||||
struct lwpSem *lwpCreateSem _PROTO((int));
|
||||
void lwpSignal _PROTO((struct lwpSem *));
|
||||
void lwpWait _PROTO((struct lwpSem *));
|
||||
void lwpSelect _PROTO((int argc, char **argv));
|
||||
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
#endif /* _LWP_H */
|
BIN
src/lib/lwp/misc/lwp.tar.gz
Normal file
BIN
src/lib/lwp/misc/lwp.tar.gz
Normal file
Binary file not shown.
189
src/lib/lwp/misc/lwp.tex
Normal file
189
src/lib/lwp/misc/lwp.tex
Normal file
|
@ -0,0 +1,189 @@
|
|||
\documentstyle[tgrind, a4]{article}
|
||||
\title{The {\sc Rex} lightweight process library}
|
||||
\author{Stephen Crane\\ (jsc@doc.ic.ac.uk)\thanks{Thanks to Mark Little
|
||||
(m.c.little@ncl.ac.uk) for the Linux port}}
|
||||
\begin{document}
|
||||
\maketitle
|
||||
This document describes the interface to and the behaviour underlying
|
||||
my threads library for Rex.\footnote{Available as lwp.tar.gz by anonymous
|
||||
ftp from gummo.doc.ic.ac.uk:/rex. Rex (Esprit project 2080) was
|
||||
axed by Men in Suits.} It has been tested on Sun-3, Sun-4,
|
||||
Mips, 386-BSD and Linux systems. Counting semi-colons, it is
|
||||
260 lines long, including support for the different architectures (this
|
||||
figure includes variable- but not function-declarations).
|
||||
|
||||
A word from our sponsor:
|
||||
\begin{quote}
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but {\sc WITHOUT ANY WARRANTY}; without even the implied warranty of
|
||||
{\sc MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE}. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
\end{quote}
|
||||
|
||||
(Note that while this library is protected by the GNU copyleft, it is not
|
||||
supported by the Free Software Foundation.)
|
||||
|
||||
\section{Threads}
|
||||
Threads are prioritised and
|
||||
non-preemptive. Operations supported on threads are:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{struct} pcb *initlp (\K{int} priority)}}
|
||||
\L{\LB{}\Tab{8}{\K{struct} pcb *creatp (priority, entry, size, argc, argv, envp)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} readyp (\K{struct} pcb *p)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} yieldp (\K{void})}}
|
||||
\L{\LB{}\Tab{8}{\K{void} *getenvp (\K{struct} pcb *p)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} setenvp (\K{struct} pcb *p, \K{void} *)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} suicidep (\K{void})}}
|
||||
\L{\LB{}\Tab{8}{\K{void} destroyp (\K{struct} pcb *p)}}
|
||||
\end{tgrind}
|
||||
\begin{description}
|
||||
\item[initlp] initialises the threads runtime, creating a thread with
|
||||
specified priority for the invoker.
|
||||
\item[creatp] creates a new thread with specified {\em priority}, {\em
|
||||
entry} point, with a stack of {\em size}, {\em argc} arguments in {\em
|
||||
argv} and a user-defined environment pointer.
|
||||
\item[getenvp] returns the environment pointer associated with the given
|
||||
thread. If the thread is null, the current thread is assumed.
|
||||
\item[setenvp] reassigns the environment pointer associated with the
|
||||
given thread.
|
||||
\item[readyp] makes the specified thread ready to run, or the current
|
||||
thread if null.
|
||||
\item[yieldp] makes the current thread ready to run. If no thread of
|
||||
higher priority is runnable, the current thread will run.
|
||||
\item[suicidep] marks the invoking thread as dead. It will never be
|
||||
rescheduled.
|
||||
\item[destroyp] marks the specified thread as dead. It will be removed
|
||||
at the next reschedule. If it is currently running, it will be
|
||||
unaffected until the next reschedule.
|
||||
\end{description}
|
||||
|
||||
\section{Semaphores}
|
||||
For synchronisation, counting semaphores are provided. Available
|
||||
operations are:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{struct} sem *creats (\K{int} count)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} signals (\K{struct} sem *s)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} waits (\K{struct} sem *s)}}
|
||||
\end{tgrind}
|
||||
\begin{description}
|
||||
\item[creats] allocates a new semaphore from the heap and initialises its
|
||||
count.
|
||||
\item[signals] increments the semaphore's count, makes a waiting process
|
||||
ready if there is one. If the readied process's priority is greater than
|
||||
that of the signaller, a reschedule is done.
|
||||
\item[waits] decrements the semaphore's count. If it becomes negative,
|
||||
the current process is suspended and a reschedule is done.
|
||||
\end{description}
|
||||
|
||||
\section{Signals}
|
||||
The library is concerned with two types of signal, {\sc sigio} and {\sc
|
||||
sigalrm}. These signals are normally blocked until the null process is
|
||||
scheduled. It uses {\tt sigpause()} to reenable them and wait for one
|
||||
to arrive. While awaiting a signal, the null process `runs' at maximum
|
||||
priority. Thus users will not be able to cause a reschedule from
|
||||
their handlers. When {\tt sigpause()} returns, the signal will have
|
||||
been handled and the null process drops back down to the lowest priority
|
||||
and yields to any thread which has been made ready to run from the
|
||||
user-level handler.
|
||||
|
||||
These semantics make the library rather unresponsive to signals in the
|
||||
presence of busy processes. If a more responsive system is required,
|
||||
the constant {\sc LCOUNT} may be changed. This value determines the
|
||||
number of times the {\tt reschedp ()} function must be called before
|
||||
signals are re-enabled. If given a value of {\tt 1}, it will affect
|
||||
context-switching time by about 50\%. Its default value is {\tt -1}.
|
||||
|
||||
\subsection{Input and output}
|
||||
Input and output present a problem to threads, because they require
|
||||
calls to the underlying {\sc Unix} system, which will block not only
|
||||
the invoking thread, but also all others in the process. Thus, in
|
||||
general, a thread must wait until the descriptor on which I/O is to
|
||||
be done becomes ready for the operation. This is done by trapping
|
||||
{\sc sigio}. Two routines are provided:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{int} sigioset (\K{int} fd, \K{void} (*han) (\K{void}
|
||||
*, \K{int}), \K{void} *ctx)}}
|
||||
\L{\LB{}\Tab{8}{\K{int} sigioclr (\K{int} fd)}}
|
||||
\end{tgrind}
|
||||
The general model adopted for processing {\sc sigio} is to install a
|
||||
{\em handler} routine for the I/O descriptor using {\em sigioset} and
|
||||
remove it using {\em sigioclr}. The user is responsible for setting up
|
||||
the device correctly to generate {\sc sigio}. When {\sc sigio} arrives
|
||||
for the descriptor, the handler will be called with a context pointer
|
||||
as its argument. (In C++, this context is the instance pointer of the
|
||||
invoking thread.)
|
||||
|
||||
\subsection{The timer}
|
||||
A single routine is provided to block the invoking thread for the
|
||||
specified time:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{void} delayp (\K{int} n)}}
|
||||
\end{tgrind}
|
||||
This routine blocks the invoker for {\em at least\/} the time specified.
|
||||
If this is zero, a reschedule is done. Delays are implemented as a
|
||||
delta queue, using {\sc sigalrm}. $n$ specifies a microsecond delay
|
||||
which is of limited utility in practice.
|
||||
|
||||
\section{Performance}
|
||||
\begin{figure}[htb]
|
||||
\begin{center}
|
||||
\begin{tabular}{||l|c|c|c||} \hline
|
||||
Arch & ctxsw & creat & comment \\ \hline
|
||||
sun3 & 308 & 778 & 3/240 \\ \hline
|
||||
386bsd & 186 & 464 & 486/33 \\ \hline
|
||||
sun4 & 96 & 436 & IPX \\ \hline
|
||||
sun4 & 59 & 212 & Sparc-10 \\ \hline
|
||||
linux & 56 & 382 & 486-DX2/50 \\ \hline
|
||||
mips & 17 & 85 & Decstation \\ \hline
|
||||
\end{tabular}
|
||||
\caption{Performance with architecture (times in microseconds).}
|
||||
\end{center}
|
||||
\end{figure}
|
||||
\begin{description}
|
||||
\item[sun3] has very lightweight process initialisation, compared with
|
||||
context switching.
|
||||
\item[sun4] has a high context switch time as a result of {\tt setjmp ()} and
|
||||
{\tt longjmp ()} implementations. Process initialisation is also relatively
|
||||
heavyweight: it requires two calls to {\tt setjmp ()} and one to {\tt longjmp
|
||||
()}.
|
||||
\item[mips] provides its own context switching in assembly language.
|
||||
\end{description}
|
||||
|
||||
\section{Porting to another architecture}
|
||||
Although the threads library is quite portable, a few guidelines should
|
||||
be observed when moving to a new architecture.
|
||||
|
||||
\begin{itemize}
|
||||
\item Create two new files for your architecture/kernel (e.g. {\tt sun4.c}
|
||||
and {\tt sun4.h}).
|
||||
The `.c' file should contain any routines which your version of {\sc Unix} is
|
||||
missing and a thread initialisation routine:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{void} initp (\K{struct} pcb *, \K{void} *)}}
|
||||
\end{tgrind}
|
||||
The `.h' file contains any machine-specific definitions.
|
||||
\item If {\tt setjmp ()} and {\tt longjmp ()} don't work on your machine
|
||||
(for example the {\sc Ultrix} {\tt longjmp ()} implementation checks that
|
||||
the frame being jumped to is an ancestor of the current one), you will
|
||||
have to write {\tt savep ()} and {\tt restorep ()} and put the following
|
||||
define into your machine-specific header file:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{\#define} OWN\_CONTEXT\_SWITCH}}
|
||||
\end{tgrind}
|
||||
\item Compile and run the three test programs: {\tt producer.c}, {\tt
|
||||
timer.c} and {\tt bm.c}.
|
||||
\item Add the name of the architecture to `config'.
|
||||
\item Send {\tt new-arch.[ch]}, any context diffs for the rest of the
|
||||
library and the output of {\tt bm.c} to {\tt jsc@doc.ic.ac.uk}. Also
|
||||
please let me know where you got the library from.
|
||||
\end{itemize}
|
||||
\end{document}
|
51
src/lib/lwp/queue.c
Normal file
51
src/lib/lwp/queue.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* queue.c -- queue manipulation routines.
|
||||
* Copyright (C) 1991-3 Stephen Crane.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
|
||||
* Imperial College of Science, Technology and Medicine, 180 Queen's
|
||||
* Gate, London SW7 2BZ, England.
|
||||
*/
|
||||
#include "lwp.h"
|
||||
#include "lwpint.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#if defined(_EMPTH_LWP)
|
||||
|
||||
struct lwpProc *lwpGetFirst(q)
|
||||
struct lwpQueue *q;
|
||||
{
|
||||
struct lwpProc *head;
|
||||
|
||||
if ((head = q->head) && !(q->head = head->next))
|
||||
q->tail = 0;
|
||||
return (head);
|
||||
}
|
||||
|
||||
void lwpAddTail(q, p)
|
||||
register struct lwpQueue *q;
|
||||
register struct lwpProc *p;
|
||||
{
|
||||
if (!q->tail)
|
||||
q->head = p;
|
||||
else
|
||||
q->tail->next = p;
|
||||
q->tail = p;
|
||||
p->next = 0;
|
||||
}
|
||||
|
||||
#endif
|
250
src/lib/lwp/sel.c
Normal file
250
src/lib/lwp/sel.c
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
|
||||
* related information and legal notices. It is expected that any future
|
||||
* projects/authors will amend these files as needed.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* sel.c: arrange to block on read/write file descriptors using lwp
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Dave Pare, 1994
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef hpux
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "bit.h"
|
||||
#include "lwp.h"
|
||||
#include "lwpint.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#if defined(_EMPTH_LWP)
|
||||
|
||||
struct lwpSelect {
|
||||
int maxfd;
|
||||
int nfds;
|
||||
int nfile;
|
||||
fd_set readmask;
|
||||
fd_set writemask;
|
||||
struct lwpProc **wait;
|
||||
struct lwpQueue delayq;
|
||||
struct lwpProc *proc;
|
||||
};
|
||||
|
||||
struct lwpSelect LwpSelect;
|
||||
|
||||
void lwpInitSelect(proc)
|
||||
struct lwpProc *proc;
|
||||
{
|
||||
LwpSelect.maxfd = 0;
|
||||
LwpSelect.nfds = 0;
|
||||
#ifdef hpux
|
||||
LwpSelect.nfile = _NFILE;
|
||||
#else
|
||||
LwpSelect.nfile = getdtablesize();
|
||||
#endif
|
||||
FD_ZERO(&LwpSelect.readmask);
|
||||
FD_ZERO(&LwpSelect.writemask);
|
||||
LwpSelect.wait = (struct lwpProc **)
|
||||
calloc(LwpSelect.nfile, sizeof(char *));
|
||||
LwpSelect.delayq.head = 0;
|
||||
LwpSelect.delayq.tail = 0;
|
||||
LwpSelect.proc = proc;
|
||||
}
|
||||
|
||||
void lwpSleepFd(fd, mask)
|
||||
int fd;
|
||||
int mask;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
lwpStatus(LwpCurrent, "sleeping on fd %d", fd);
|
||||
|
||||
if (LwpSelect.wait[fd] != 0) {
|
||||
lwpStatus(LwpCurrent,
|
||||
"multiple sleeps attempted on file descriptor %d", fd);
|
||||
return;
|
||||
}
|
||||
if (mask & LWP_FD_READ)
|
||||
FD_SET(fd, &LwpSelect.readmask);
|
||||
if (mask & LWP_FD_WRITE)
|
||||
FD_SET(fd, &LwpSelect.writemask);
|
||||
|
||||
LwpSelect.nfds++;
|
||||
|
||||
if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
|
||||
/* select process is sleeping until first waiter arrives */
|
||||
lwpStatus(LwpCurrent, "going to resched fd %d", fd);
|
||||
lwpReady(LwpSelect.proc);
|
||||
}
|
||||
lwpStatus(LwpCurrent, "going to wait on fd %d", fd);
|
||||
if (fd > LwpSelect.maxfd)
|
||||
LwpSelect.maxfd = fd;
|
||||
LwpSelect.wait[fd] = LwpCurrent;
|
||||
LwpCurrent->fd = fd;
|
||||
lwpReschedule();
|
||||
}
|
||||
|
||||
void lwpWakeupFd(proc)
|
||||
struct lwpProc *proc;
|
||||
{
|
||||
if (proc->fd < 0)
|
||||
return;
|
||||
|
||||
lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd);
|
||||
FD_CLR(proc->fd, &LwpSelect.readmask);
|
||||
FD_CLR(proc->fd, &LwpSelect.writemask);
|
||||
LwpSelect.nfds--;
|
||||
LwpSelect.wait[proc->fd] = 0;
|
||||
proc->fd = -1;
|
||||
lwpReady(proc);
|
||||
}
|
||||
|
||||
void lwpSleepUntil(until)
|
||||
long until;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
lwpStatus(LwpCurrent, "sleeping for %d sec", until - time(0));
|
||||
LwpCurrent->runtime = until;
|
||||
if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
|
||||
/* select process is sleeping until first waiter arrives */
|
||||
lwpReady(LwpSelect.proc);
|
||||
}
|
||||
lwpAddTail(&LwpSelect.delayq, LwpCurrent);
|
||||
lwpReschedule();
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
lwpSelect(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
struct lwpProc *us = LwpCurrent;
|
||||
fd_set readmask;
|
||||
fd_set writemask;
|
||||
int n;
|
||||
int fd;
|
||||
time_t now;
|
||||
time_t delta;
|
||||
struct lwpProc *proc;
|
||||
struct timeval tv;
|
||||
struct lwpQueue save;
|
||||
|
||||
lwpStatus(us, "starting select loop");
|
||||
FD_ZERO(&readmask);
|
||||
FD_ZERO(&writemask);
|
||||
while (1) {
|
||||
while (1) {
|
||||
if (LwpSelect.nfds)
|
||||
break;
|
||||
if (LwpSelect.delayq.head)
|
||||
break;
|
||||
/* wait for someone to lwpSleepFd or lwpSleepUntil */
|
||||
LwpSelect.maxfd = 0;
|
||||
lwpStatus(us, "no fds or sleepers, waiting");
|
||||
lwpReschedule();
|
||||
}
|
||||
tv.tv_sec = 1000000;
|
||||
tv.tv_usec = 0;
|
||||
if (LwpSelect.delayq.head) {
|
||||
time(&now);
|
||||
proc = LwpSelect.delayq.head;
|
||||
for ( ; proc != 0; proc = proc->next) {
|
||||
delta = proc->runtime - now;
|
||||
if (delta < tv.tv_sec)
|
||||
tv.tv_sec = delta;
|
||||
}
|
||||
if (tv.tv_sec < 0)
|
||||
tv.tv_sec = 0;
|
||||
}
|
||||
lwpStatus(us, "selecting; sleep %ld secs", (long)delta);
|
||||
|
||||
bcopy((s_char *)&LwpSelect.readmask, (s_char *)&readmask, sizeof(fd_set));
|
||||
bcopy((s_char *)&LwpSelect.writemask, (s_char *)&writemask, sizeof(fd_set));
|
||||
n = select(LwpSelect.maxfd + 1, &readmask, &writemask,
|
||||
(fd_set *)0, &tv);
|
||||
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
/* go handle the signal */
|
||||
lwpReady(us);
|
||||
lwpReschedule();
|
||||
continue;
|
||||
}
|
||||
lwpStatus(us,
|
||||
"select failed (bad file descriptor?)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (LwpSelect.delayq.head) {
|
||||
/* sleeping proecss activity */
|
||||
time(&now);
|
||||
save.tail = save.head = 0;
|
||||
while (NULL != (proc = lwpGetFirst(&LwpSelect.delayq))) {
|
||||
if (now >= proc->runtime) {
|
||||
lwpStatus(proc, "sleep done");
|
||||
lwpReady(proc);
|
||||
} else {
|
||||
lwpAddTail(&save, proc);
|
||||
}
|
||||
}
|
||||
LwpSelect.delayq = save;
|
||||
}
|
||||
if (n > 0) {
|
||||
/* file descriptor activity */
|
||||
for(fd = 0; fd <= LwpSelect.maxfd; fd++) {
|
||||
if (LwpSelect.wait[fd] == 0)
|
||||
continue;
|
||||
if (FD_ISSET(fd, &readmask)) {
|
||||
lwpStatus(LwpSelect.wait[fd],
|
||||
"input ready");
|
||||
lwpWakeupFd(LwpSelect.wait[fd]);
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(fd, &writemask)) {
|
||||
lwpStatus(LwpSelect.wait[fd],
|
||||
"output ready");
|
||||
lwpWakeupFd(LwpSelect.wait[fd]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
lwpStatus(us, "fd dispatch completed");
|
||||
lwpReady(LwpCurrent);
|
||||
lwpReschedule();
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif
|
90
src/lib/lwp/sem.c
Normal file
90
src/lib/lwp/sem.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* lwpSem.c -- lwpSemaphore manipulation.
|
||||
* Copyright (C) 1991-3 Stephen Crane.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
|
||||
* Imperial College of Science, Technology and Medicine, 180 Queen's
|
||||
* Gate, London SW7 2BZ, England.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lwp.h"
|
||||
#include "lwpint.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#if defined(_EMPTH_LWP)
|
||||
|
||||
/* for systems without strdup */
|
||||
#ifdef NOSTRDUP
|
||||
extern char *strdup();
|
||||
#endif /* NOSTRDUP */
|
||||
|
||||
/*
|
||||
* create a lwpSemaphore.
|
||||
*/
|
||||
struct lwpSem *lwpCreateSem(name, count)
|
||||
char *name;
|
||||
int count;
|
||||
{
|
||||
struct lwpSem *new;
|
||||
|
||||
if (!(new = (struct lwpSem *)malloc(sizeof(struct lwpSem))))
|
||||
return (0);
|
||||
new->name = strdup(name);
|
||||
new->count = count;
|
||||
new->q.head = new->q.tail = 0;
|
||||
return (new);
|
||||
}
|
||||
|
||||
/*
|
||||
* signal a lwpSemaphore. We only yield here if
|
||||
* the blocked process has a higher priority than ours'.
|
||||
*/
|
||||
void lwpSignal(s)
|
||||
struct lwpSem *s;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
lwpStatus(LwpCurrent, "done with semaphore %s", s->name);
|
||||
if (s->count++ < 0) {
|
||||
struct lwpProc *p = lwpGetFirst(&s->q);
|
||||
lwpStatus(LwpCurrent, "activating first waiter");
|
||||
lwpReady(p);
|
||||
if (LwpCurrent->pri < p->pri) {
|
||||
lwpStatus(p, "priority is higher");
|
||||
lwpYield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* wait on a lwpSemaphore
|
||||
*/
|
||||
void lwpWait(s)
|
||||
struct lwpSem *s;
|
||||
{
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
lwpStatus(LwpCurrent, "checking semaphore %s", s->name);
|
||||
if (--s->count < 0) {
|
||||
lwpStatus(LwpCurrent, "blocking");
|
||||
lwpAddTail(&s->q, LwpCurrent);
|
||||
lwpReschedule();
|
||||
}
|
||||
}
|
||||
#endif
|
69
src/lib/lwp/status.c
Normal file
69
src/lib/lwp/status.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
|
||||
* related information and legal notices. It is expected that any future
|
||||
* projects/authors will amend these files as needed.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* status.c: Process and perhaps display status messages
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Dave Pare, 1994
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifdef BOUNDS_CHECK
|
||||
#include <bounds/fix-args.h>
|
||||
#endif
|
||||
#include "lwp.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#if defined(_EMPTH_LWP)
|
||||
|
||||
void lwpStatus(struct lwpProc *proc, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static struct timeval startTime;
|
||||
struct timeval tv;
|
||||
char buf[1024];
|
||||
int sec, msec;
|
||||
|
||||
va_start(ap,format);
|
||||
if (proc->flags & LWP_PRINT) {
|
||||
if (startTime.tv_sec == 0)
|
||||
gettimeofday(&startTime, 0);
|
||||
gettimeofday(&tv, 0);
|
||||
sec = tv.tv_sec - startTime.tv_sec;
|
||||
msec = (tv.tv_usec - startTime.tv_usec) / 1000;
|
||||
if (msec < 0) {
|
||||
sec++;
|
||||
msec += 1000;
|
||||
}
|
||||
vsprintf(buf, format, ap);
|
||||
printf("%d:%02d.%03d %17s[%d]: %s\n", sec/60, sec%60, msec/10,
|
||||
proc->name, proc->pri, buf);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue