Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!mcsun!ukc!edcastle!aiai!richard From: richard@aiai.ed.ac.uk (Richard Tobin) Newsgroups: comp.unix.internals Subject: Re: threads without kernel mods Message-ID: <4815@skye.ed.ac.uk> Date: 27 May 91 16:45:27 GMT References: <213@titccy.cc.titech.ac.jp> <1991May20.123423.10388@linus.mitre.org> Reply-To: richard@aiai.UUCP (Richard Tobin) Organization: AIAI, University of Edinburgh, Scotland Lines: 82 In article <1991May20.123423.10388@linus.mitre.org> jfjr@mbunix.mitre.org (Freedman) writes: > I need to know about implementing threads or lightweight processes >without modifying kernel - ie strictly user level implementations. >How is this accomplished? Some variant on setjmp/longjmp? Setjmp() and longjmp() may do the trick, but it's extremely unportable. Once you have n stacks, you may be able to longjmp() between them. If this works, you still have the problem of getting onto a new stack in the first place. Under BSD-like systems you may be able to use a completely disgusting hack due I think to Simon Brown, which involves using sigstack() to set up an alternative stack for signal handlers, and then sending yourself a signal. Here's some code from a Lisp system: #include "defs.h" #include "structs.h" #include #include #include typedef void Sigtype; static jmp_buf newenv, oldenv; static LispObject *(*threadfunction)(); static Sigtype threadstart() { if(_setjmp(newenv) == 0) longjmp(oldenv, 1); (void)(*threadfunction)(); /* If we get here, the thread has returned too far. */ fprintf(stderr, "Panic! Thread returned too far!\n"); exit(1); } void create_thread(thread, fn) struct thread_structure *thread; LispObject *(*fn)(); { struct sigstack stack, ostack; struct sigvec vec, ovec; stack.ss_sp = (char *)(((int)thread->stack + thread->size - 1) & ~7); stack.ss_onstack = 0; sigstack(&stack, &ostack); vec.sv_handler = threadstart; vec.sv_mask = 0; vec.sv_flags = SV_ONSTACK; sigvec(SIGUSR1, &vec, &ovec); if(setjmp(oldenv) == 0) { kill(getpid(), SIGUSR1); /* We never get here, because threadstart longjmps */ } /* * At this point, threadstart has done a setjmp(newenv). When * we jump to it, it will call the function in threadfunction. */ sigvec(SIGUSR1, &ovec, (struct sigvec *)0); sigstack(&ostack, (struct sigstack *)0); threadfunction = fn; _longjmp(newenv, 1); } -- Richard -- Richard Tobin, JANET: R.Tobin@uk.ac.ed AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin