On Wed, 2010-10-27 at 16:25 +0300, Nikodemus Siivola wrote:
> On 26 October 2010 22:28, Kalyanov Dmitry <kalyanov.dmitry@...> wrote:
> > I'd like to get review of support for Windows threads.
> I gave the lisp-half of the "Condensed thread changes" commit a quick
> read. My comments (or at least most of them) linked below for
> Overall the lisp-side of that commit at least looks quite good -- the
> comments are mostly on stylistic issues. I'll read more and more
> in-depth later.
> The C-side I started to look at, but didn't get very far into -- and
> the other commits not at all yet.
> Some meta-commetary
> > 1) Subset of pthreads is implemented using win32 API.
> If there is someone with both pthread and Win32 thread API chops here,
> please raise your hand and go take a look at this. I can review it,
> but my Win32 API knowledge isn't all that hot.
> > 2) Thread-local storage is implemented using an "Arbitrary data slot" in
> > Thread Information Block (which is specific for a thread and is
> > accessible via the FS register).
> A quick glance at the code didn't show me any big comments about this.
> I there is one, I just missed it and apologize.
> I'll leave it for others (Alistair?) to comment on the strategy
> itself, but a big descriptive comment about this would be in order,
> preferably with a link to appropriate Win32 docs.
TLS strategy is the hard part of Windows threads; I'll write review of
implementation strategies that I've tried.
Unfortunately, I can't now find a normative reference that would
describe this (however I've seen references that say the Windows NT
Driver Development Kit includes one). There are numerous descriptions
http://en.wikipedia.org/wiki/Win32_Thread_Information_Block ). In
particular, field at offset 0x14 is described as "The 14h DWORD
pvArbitrary field is theoretically available for applications to use
however they want. It's almost like an extra thread local storage slot
for you to use, although I've never seen an application use it."
> > 3) Instead of using signals to stop threads for GC and to interrupt
> > threads, 'safepoints' and 'safe regions' are used. Safepoint is a
> > place in a code when threads checks if it should do something unusual:
> > suspend for GC or handle an interruption.
> > Safepoints are placed at heads of functions and loops (I'm not very
> > proficient with SBCL compiler internals so I took Paul Khuong's
> > code for placement of safepoints). Safe region is a region of code
> > when Lisp code is not running for a long period of time (safe regions
> > are placed around foreign calls and possibly blocking code in C
> > runtime).
> I wonder if safepoints should be decoupled from Win32 threads. Dunno. *shrug*
I agree - safepoints are platform-agnostic per se, it's just that on
Windows they seem to be the only way to implement
suspension/interruption. As for decoupling, I'm not too well proficient
with SBCL code and with signals; also I'm not sure how safepoints would
interact with signals.
Also, as safepoints are implemented right now, compatibility is
maintained with signal-related thread state tracking via signal masks.
This makes implementation somewhat more complex than neccessary.
Safepoints for thread suspension might be better than signals (P.Khuong
mentions this in hist post
http://www.pvk.ca/Blog/LowLevel/VM_tricks_safepoints.html ) including
being more portable. Also safepoints might open possibility for precise
> > 4) Changed thread state transitions and thread state invariants. New
> > thread state variables are added:
> > * *disable-safepoints* is bound to T when thread can not be interrupted
> > * *in-safepoint* is bound to T when thread executes the 'safepoint'
> > routine to prevent infinite recursion
> > * *gc-safe* is bound to T when thread leaves lisp code (it's safe not to
> > wait for such thread to suspend for gc - it won't touch the memory)
> Can interrupts via safepoints nest?
Interrupts are running 'outside' of safepoints; so interrupt code may
have its own safepoints but they will not be nested.
The real reason for this is the GC code that is called 'inside' a
1) thread hits a safepoint
2) thread notices that *gc-pending* is T and calls the GC (by calling
maybe_gc which calls SUB-GC)
3) SUB-GC hits a safepoint. <- this one is nested
> > 5) GC gets thread context directly with
> > SuspensThread/GetThreadContext/ResumeThread - not from saved interrupt
> > context.
> ...and if they can, does sufficient context end up on stack for
> regular stack scavenging to deal with nested interrupts?
As far as I know, all context ends up on stack in Win32; all
'interrupts' are just regular function calls. Windows does provide
limited form of asynchronous interrupts via APC (Asynchronous Procedure
Calls which are called only during calls to specific Win32 functions) -
I don't know how APCs store context; but we don't need to deal with them
as they are not used anywhere in SBCL.