[M3devel] using *context functions for user threading?

Jay jay.krell at cornell.edu
Sat Jan 31 04:46:53 CET 2009


I think setjmp/longjmp would continue to be ok.
It has very little machine dependency, and I /guess/ works and is portable.
I guess. We are both leary, but it's been there a while.
It is InitContext imho that could be "better" --  more portable, remove all the
mucking around with frames and stack pointers.
I was late to see this because it is in the machine-independent chunk of code.
 
 
What does swapcontext buy over setjmp/longjmp, once a thread is "already started"?
I can see there is a "unifying" reason.
If makecontext is used to InitContext, then swapcontext is needed to "start" a thread.
setjmp/longjmp could be used to suspend/resume, but if you phrase "start" and "resume" as the same thing, then "stuck" with swapcontext.
 
 
For some time I was under the impression that Modula-3 repeatedly longjmped to a buffer that only had setjmp called once, or where the function that setjmp was called from had returned, but I'm not sure of that now. It seems viable to "follow the rules" wrt setjmp/longjmp, other than the "escaping from a signal handler" aspect.
 
 
> The safest solution for all of this is to have the timer signal 
> handler set a flag and for the M3 compiler to inject a test of the 
> flag at calls/backward branches, and explicitly yield if the flag is 
> set. 

 
Yes that makes me much more comfortable as well.
 
 
Is it cut & dry agreed to and such?
 
 
Someone should just do it?
 
 
 Or there are concerns that: 
  - it might not be often enough? 
    There are no "forward" or "backward" branches at the Modula-3 level, are there?
    It is at the whim of the backend, right? I guess you might be able to
    conceptually label branches as forward or backward, even if the backend "rotates" things or
     adds  more branches (you know, like loops often starting with a forward branch).
  - it might be too often? 
  - it might be too code bloating? Or too slow when "checks" greatly outweight actual switches? 
  - a call out to a function or a check of a variable? 
  - only do it if a compiler command line switch is given? Or for platforms known to support user threads? (given the design though..it could be every platform)
 
 
 Though I raise the issues, it still seems the right thing, vs. longjmping out of a signal handler.
 
 
The OpenBSD sigaction manpage does seem to have in mind an ability to "switch threads" in a signal handler:
 
 
     "When a caught
     signal is delivered, the current state of the process is saved, a new
     signal mask is calculated (as described below), and the signal handler is
     invoked.  The call to the handler is arranged so that if the signal han-
     dling routine returns normally the process will resume execution in the
     context from before the signal's delivery.  If the process wishes to re-
     sume in a different context, then it must arrange to restore the previous
     context itself.
     "
 
 but the idea here is not longjmp or I think exactly swapcontext, but manually swapping a context with the third parameter to the signal handler.
 
 
> single-threaded process, but I don't know if that really prevents a 
> timer signal arriving inside the signal handler, and what impact that 
> might have. 

 
Right. I don't see that control-c can't come in at about the same time as timer.
Though I think sigaction allows for fixing this -- block all signals during the signal handler.
I'll reread some manpages.
 
 
 - Jay



----------------------------------------
> From: hosking at cs.purdue.edu
> To: jay.krell at cornell.edu
> Date: Sat, 31 Jan 2009 14:09:23 +1100
> CC: m3devel at elegosoft.com
> Subject: Re: [M3devel] using *context functions for user threading?
>
> On 31 Jan 2009, at 09:49, Jay wrote:
>
>> Tony, can you tell me more of what you have in mind here?
>
> I didn't plan anything other than using swapcontext instead of longjmp
> in switch_thread, and using makecontext instead of InitContext to get
> a forked thread's context.
>
>> In particular...I /think/ it goes like:
>>
>>
>> use getcontext + makecontext to "create a thread"
>> use simple struct copying/memcpy of the third parameter to the
>> signal handler for context switching
>
> No, swapcontext.
>
>> in particular -- setcontext/makecontext never used -- except to
>> start a thread, but not to switch to/from already started threads.
>
> Right.
>
>> ?
>>
>>
>> Implication here is that even on systems without context APIs, our
>> ucontext_t needs to match what the signal handler gets. That isn't
>> the case for what I just got "working" (prototype, proof of concept,
>> whatever) on OpenBSD, but easy enough.
>
> I don't know what you are saying here. swapcontext should be enough.
>
>> An alternative is to call setcontext in the signal handler, but that
>> makes me nervous.
>> It seems best to exit "cleanly" out of a signal handler?
>
> You're right, but this is probably broken for the current longjmp-
> based implementation too.
>
>> And then I get to seeing very murky things, like, can a system call
>> be interrupted by an alarm signal? If so, switching threads
>> then...what would that do? Seems bad.
>
> Yes, I was never convinced that the longjmp-based implementation was
> safe either. I figured that it probably worked only because it was a
> single-threaded process, but I don't know if that really prevents a
> timer signal arriving inside the signal handler, and what impact that
> might have.
>
>> So then I guess I see the origin of all the original system call
>> wrappers -- to turn of thread switching during system calls.
>
> No, those were only for GC.
>
>> ?
>>
>> The current code does appear to longjmp out of a system call -- or
>> rather, to longjmp from one alarm signal to another. Again this
>> seems confusing if alarm signals can interrupt system calls.
>
> Right...
>
>> Some abstraction that encompasses Win32 fibers might be nice, though
>> there would remain the question of how to preempt.
>
> The safest solution for all of this is to have the timer signal
> handler set a flag and for the M3 compiler to inject a test of the
> flag at calls/backward branches, and explicitly yield if the flag is
> set.
>
>>
>>
>> - Jay
>


More information about the M3devel mailing list