Forwarding the reply from Jonas Mabe to the MacPascal mailing list:
a) first an index into some structure which contains the value of this variable in case of a multi-threaded program
How are these indices allocated? AFAICS, they must be globally unique, even across units. Do you do something like a base-index per unit, and running indices within unit? Or an extra pass in the main program to sort all indices in the units used?
All threadvars in a compilation unit are collected in a threadvarlist, e.g. in case of the example program it becomes:
.globl THREADVARLIST_P$PROGRAM THREADVARLIST_P$PROGRAM: .long U_P$PROGRAM_A .long 4,0
As you can see, it consists of "address of variable" followed by the size of the variable. A zero marks the end of the threadvarlist.
The threadvarlists of all compilation units are collected when compiling a main program or library (similar to how the initialisation routines of all used units are collected, I guess GPC also already contains some mechanism for this). We then generate a threadvartable from this in the program/library:
.globl FPC_THREADVARTABLES FPC_THREADVARTABLES: .long 2 .long THREADVARLIST_SYSTEM .long THREADVARLIST_P$PROGRAM
(format: nr of entries followed by the addresses of the threadvarlists)
When the first thread is started (via BeginThread(), we don't detect if someone uses pthread_create or so), the thread manager walks the threadvartable and the referenced lists and fills in all indexes. This thread manager is fully pluggable, so everyone is free to use his own (e.g. if you implement some user space fibers or so).
My speaking of PPC assembler is not really good, but I read it as something like this, right?
if FPC_THREADVAR_RELOCATE <> nil then r3 := FPC_THREADVAR_RELOCATE^ (a) else r3 := Pointer (@a) + 4; LongInt (r3^) := 5;
Correct.
Of course, such a solution for ioresult is slower than returning an error from a function,
Sure, the function call is expensive. Of course, it's only needed when actually multi-threaded which is a plus as far as I'm concerned. Still, it would be good if it could be avoided. One way might be to store offsets instead of indices, but computing globally-contiguous offsets is even harder than globally-unique indices. AFAICS, it could be done in an extra pass in the compiler or perhaps easier by automatically "registering" all thread variables at runtime.)
At least FPC's pthread-based thread manager, it is an offset. But this offset is still relative to something thread-unique, which you have to lookup each time the variable is accessed. That's what FPC_RELOCATE_THREADVAR does:
function CRelocateThreadvar(offset : dword) : pointer; begin CRelocateThreadvar:=pthread_getspecific(tlskey)+Offset; end;
Hmm, I guess this dword should be replaced by a ptruint :) (although someone allocating more than 4GB of threadvars possibly deserves to crash ;)
So this might be an option. (But again, first I'd like to see which variables are actually affected and thus how big the effects would actually be. InOutRes might well be the worst, because most-often used one, but not the only one, of course.)
These are the threadvars in FPC's system unit:
ThreadVar ThreadID : TThreadID; { Standard In- and Output } ErrOutput, Output, Input, StdOut, StdErr : Text; InOutRes : Word; { Stack checking } StackBottom : Pointer; StackLength : SizeUInt;
There's a few more in TP-compatibility units (like doserror in the Dos unit and some crt things) and some for Delphi-style exception handling, but that's about it. Of course, users can also declare their own threadvars in their programs and units.
You can download our rtl via svn (http://www.freepascal.org/ develop.html#svn) and have a look how it's done. The support routines are in rtl/inc/threadvr.inc, rtl/unix/cthreads.pp (pthreads-based thread manager, in a separate unit because this is dependent on libc and most of our targets do not require/depend on libc by default) and rtl/win32systhrd.inc, rtl/emx/systhrd.inc, rtl/netware/systhrd.inc, rtl/os2/systhrd.inc (but the pthreads-based one can be used for all targets which have a libpthread, so I guess that's enough for GPC).
Since our RTL is under a slightly modified LGPL (allows static linking as long as you make the modifications to the FPC-RTL-licensed code available), license-wise I don't think there is any problem for you to reuse things. If there is, we could dual-license it under the regular LGPL as well I suppose (the main reason for the static linking exception is that some OS'es, like Dos, simply do not support dynamic linking, and support for creating dynamic libraries was not available for all OS'es in our compiler from the start either).
Jonas
_______________________________________________ MacPascal mailing list http://lists.sonic.net/mailman/listinfo/mac-pascal