[M3devel] pthread/Interix
Jay K
jay.krell at cornell.edu
Wed Dec 16 18:40:52 CET 2009
There are no public suspend/resume primitives exposed.
You can see in the debugger what happens.
The signal handling thread calls NtSuspendThread/NtResumeThread.
I suppose there is a chance they use the target thread's stack to hold
the full previous context, I can dig in the debugger and see.
I don't think what I have is too awful though.
You see the test_interix.c file?
I believe Cygwin does similar, though in that case the thread
probably doesn't have the constrained access and you can use
the public Win32 GetCurrentThread/DuplicateHandle/SuspendThread/ResumeThread functions.
Remember how I had that turning of pthread_self into GetThreadForThis, GetThreadForThat?
e.g. one is pthread_self, the other is GetCurrentThread/DuplicateHandle.
That might come back.
- Jay
Subject: Re: pthread/Interix
From: hosking at cs.purdue.edu
Date: Wed, 16 Dec 2009 12:08:09 -0500
CC: m3devel at elegosoft.com
To: jay.krell at cornell.edu
On 16 Dec 2009, at 11:49, Jay K wrote:Signals are handled by a separate thread suspending the target thread and setting the context to run the signal handler. Therefore the state is on that thread's stack, not discoverable.
Interesting, this is exactly the way Mach does signals (which is why we use the Mach suspend/resume primitives for Darwin/OSX). If that is how they work, then can't you use the suspend/resume primitives directly?
There is only single parameter signal handlers.
Normally we could suspend/resume the thread "directly" but the thread is I think created by an outside process and we don't have sufficient access. There is a handle with sufficient access, used by that signal handling thread, but it isn't accessible either.
That is what is particularly unfortunate.
I think putting the two files in unconditionally and passing to the various functions, plus one other #ifdefed function "OpenInterixFiles" is a reasonable compromise. I've coded it up, haven't compiled/tested yet.
An improvement would be to use the (normally) zero sized record and pass that to the C code instead, not wasting the storage on othe platforms.
(A direct suspend/resume/getcontext solution will be good for Cygwin I'm sure.)
- Jay
Subject: Re: pthread/Interix
From: hosking at cs.purdue.edu
Date: Wed, 16 Dec 2009 11:40:56 -0500
CC: m3devel at elegosoft.com
To: jay.krell at cornell.edu
I really dislike this... just for a broken platform...
Is there really no way to know that the context on is not on the stack somewhere?
On 16 Dec 2009, at 10:36, Jay K wrote:[again, expect a bounce, but the mail does get through]
Tony, for Interix, suspend/resume thread can be achieved writing to a file.
Getting a suspended thread's registers can be gotten reading from a file.
(I believe the same thing works on Solaris.)
It appears to be intended for debuggers.
I can see that it works well.
I doubt that a thread's context is on a signal handler's stack.
I propose:
ActState = { Starting, Started, Stopping, Stopped };
REVEAL Activation = UNTRACED BRANDED REF RECORD
frame: ADDRESS := NIL; (* exception handling support *)
handle: pthread_t := NIL; (* LL = activeMu; thread handle *)
statusFile: int := -1; (* for Interix *)
controlFile: int := -1; (* for Interix *)
(* C code knows the structure above this point *)
...
END;
ThreadPThread.h:
typedef struct _Activation_t {
void* frame;
void* pthread;
int statusFile; /* for Interix */
int controlFile; /* for Interix */
} Activation_t;
and then whereever we pass act.handle off to C code, pass act instead.
frame is kept first so that it is offset 0 in case that gives codegen efficiencies
on the often used push/popframe.
The other three are moved up to the top to reduce maintainence of ThreadPThread.h.
I assume "branding" doesn't introduce data in the record.
I'd have to check the codegen to verify frame is at offset 0.
#ifdef code will open the files.
Modula-3 code can check if the files are >= 0 and close them,
or it can be a call out to #ifdefed C.
An alternative is that wherever we pass act.handle, also pass act.statusFile and act.controlFile.
(as VAR for initialization).
That is less fragile and less extensible.
I'm fine with that approach too.
As well though, I was wondering, maybe we should have:
common/InterixThreadState.i3
T = RECORD END; (* zero size? *)
interix/InterixThreadState.i3
T = RECORD statusFile, controlFile := -1; END;
and then put InterixThreadState.T in Activation.
That way saving the other platforms from spending the space.
Just two integers, not much, but in principle..
(We also sometimes use up 8 bytes for the pthread_t when 4 would suffice,
on 64bit platforms with pthread_t == int, I think HP-UX is like that at least.)
I could also open/close the files for every suspend/resume/processStopped,
though that seems too lame.
Another idea, that I don't really like, is to never optimize and
ignore the registers and just use the stack.
I rarely optimize, but depending on that seems bad.
Your "safe points" proposal would also make this work, though
I'd rather not wait for that.
?
Ok to add the two integers all the time?
Ok to either depend on the record layout in C, or to always pass the integers around?
Thanks,
- Jay
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20091216/49674a8c/attachment-0002.html>
More information about the M3devel
mailing list