Hi, Has anyone ever tested threads on linux? A dead simple test program (attached) didn't work for me. It always just got "killed".
After recompiling the RTL with debugging and using ddd, I was able to figure out what the problem is: Line 80 of tthread.inc in linux says: FpSigAction(SIGCHLD, @Act, @OldAct); and really should be FpSigAction(SIGCHLD, Act, OldAct); or maybe even better FpSigAction(SIGCHLD, Act, nil); Noting that it still doesn't work correctly (the thread executes even though I create it suspended!), I went on. Further debugging reveals that the thread executes before the constructor is able to stop the new thread. I got around this by doing while Thread.FHandle = 0 do fpsleep(1); // necessary to avoid race if Thread.FSuspended then Thread.suspend(); in ThreadProc() as the first thing and removing the suspend() call in TThread.Create. Note however, that this still doesn't work as expected with the test program. Another thing to note is that the flags to clone() should probably include CLONE_PARENT if threads are created from within threads. Another problem I noticed is that IsMultiThread is set to true _very_ late, even after the thread is really created. This can possibly lead to heap corruption, because the thread could start another thread and then execute memory management routines in those 2 threads before IsMultiThread is set to true. It is highly unlikely though. And, something I have to take blame for, FFatalException shouldn't be set to nil after the clone() call, but rather before it, because the thread could already have executed, gotten an exception, and set FFatalException by the time FFatalException is set to nil again. TThread.Suspend should also be rewritten to procedure TThread.Suspend; begin FSuspended := true; // put before Kill() call Kill(FHandle, SIGSTOP); end; so that a thread can suspend itself properly. Since suspending threads is non-portable (afaik the current implementation actually violates posix because if a thread is sent SIGSTOP then the whole process should be suspended), I think it would be better to change the implementation as follows: - if CreateSuspended is true, do not actually clone() - in resume, clone() if the thread was created suspended [if you do this, implementing above change with calling suspend in ThreadProc is meaningless and should not be done] One could also add in a portable way threads suspending themselves, by having them wait for an event in suspend() and signalling that event in resume(). This would be done if FThreadID = CurrentThreadID, otherwise try the non-portable way of sending SIGSTOP. In resume, check a flag (how the thread was suspended) and then either signal the event or sent SIGCONT. Then at least suspending from inside the thread would be posix-safe. Maybe suspend() should be marked as deprecated. This way at least the semantics of CreateSuspended could be kept, while using suspend() itself would be rather dangerous for portable code. But I do think that using BeginThread and such functions would be far better. I'd be willing to implement this, but I only have access to a Linux 2.6 (with NPTL) system (my own) and some Linux 2.4 (with LinuxThreads) systems (at university). johannes -- http://www.sipsolutions.de/ GnuPG key: http://www.sipsolutions.de/keys/JohannesBerg.asc Key-ID: 9AB78CA5 Johannes Berg <[EMAIL PROTECTED]> Fingerprint = AD02 0176 4E29 C137 1DF6 08D2 FC44 CF86 9AB7 8CA5
program thread;
{$IFDEF FPC}
{$THREADING ON}
{$MODE OBJFPC}
uses
Unix,BaseUnix,
{$ELSE}
uses
{$ENDIF}
SysUtils, Classes;
{$IFNDEF FPC}
procedure fpsleep(const atime: longint);
begin
sleep(atime);
end;
{$ENDIF}
type
TMyThread = class(TThread)
procedure Execute; override;
end;
procedure TMyThread.Execute;
begin
while not terminated do begin
writeln('hallo');
fpsleep(1);
end;
end;
var
m: TMyThread;
begin
writeln('starting');
// fpkill(fpgetpid(),SIGSTOP);
m := TMyThread.Create(true);
fpsleep(1000);
m.terminate;
m.free;
end.
signature.asc
Description: This is a digitally signed message part
