123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- {
- This file is part of the Free Component Library (FCL)
- Copyright (c) 1999-2000 by the Free Pascal development team
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {****************************************************************************}
- {* TThread *}
- {****************************************************************************}
- {$ifdef FPC_WASM_THREADS}
- procedure TThread.CallOnTerminate;
- begin
- FOnTerminate(self);
- end;
- function TThread.GetPriority: TThreadPriority;
- begin
- GetPriority:=tpNormal;
- end;
- procedure TThread.SetPriority(Value: TThreadPriority);
- begin
- // Not supported
- end;
- procedure TThread.SetSuspended(Value: Boolean);
- begin
- if Value <> FSuspended then
- if Value then
- Suspend
- else
- Resume;
- end;
- procedure TThread.DoTerminate;
- begin
- if Assigned(FOnTerminate) then
- Synchronize(@CallOnTerminate);
- end;
- function ThreadFunc(parameter: Pointer): ptrint;
- Var
- LThread : TThread Absolute parameter;
- LFreeOnTerminate : Boolean;
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('In threadfunc. Thread object: '+IntToStr(PTrUint(LThread)));{$ENDIF}
- try
- if LThread.FInitialSuspended then
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('thread '+IntToStr(ptruint(LThread))+' waiting for RTLEvent '+IntToStr(ptruint(LThread.FSuspendEvent)));{$ENDIF}
- RtlEventWaitFor(LThread.FSuspendEvent);
- if (LThread.FTerminated) then
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('initially created suspended, but already terminated'){$ENDIF}
- else if LThread.FSuspended then
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('thread '+IntToStr(PtrUint(LThread))+' initially created suspended, resumed, but still suspended?!'){$ENDIF}
- else
- begin
- LThread.FInitialSuspended := false;
- CurrentThreadVar := LThread;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('going into LThread.Execute (1)');{$ENDIF}
- LThread.Execute;
- end
- end
- else
- begin
- // The suspend internal is needed due to bug 16884
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Suspending internally');{$ENDIF}
- LThread.FSuspendedInternal:=True;
- RtlEventWaitFor(LThread.FSuspendEvent);
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Internal suspend done.');{$ENDIF}
- CurrentThreadVar := LThread;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('going into LThread.Execute (2)');{$ENDIF}
- LThread.Execute;
- end;
- except
- on e: exception do
- begin
- LThread.FFatalException := TObject(AcquireExceptionObject);
- if e is EThreadDestroyCalled then
- LThread.FFreeOnTerminate := true;
- end;
- end;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('thread done running');{$ENDIF}
- Result := LThread.FReturnValue;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Result is '+IntToStr(Result));{$ENDIF}
- LFreeOnTerminate := LThread.FreeOnTerminate;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Calling doterminate');{$ENDIF}
- LThread.DoTerminate;
- LThread.FFinished := True;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread Set to finished');{$ENDIF}
- if LFreeOnTerminate then
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread '+IntToStr(ptruint(lthread))+' should be freed');{$ENDIF}
- LThread.Free;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread freed');{$ENDIF}
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Thread func calling EndThread');{$ENDIF}
- EndThread(Result);
- end;
- end;
- procedure TThread.SysCreate(CreateSuspended: Boolean; const StackSize: SizeUInt);
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('In TThread.SysCreate');{$ENDIF}
- FSuspendEvent := RtlEventCreate;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TThread.SysCreate: Created suspend event');{$ENDIF}
- FSuspended := CreateSuspended;
- FThreadReaped := false;
- FInitialSuspended := CreateSuspended;
- FSuspendedInternal := not CreateSuspended;
- FFatalException := nil;
- FHandle:=BeginThread(@ThreadFunc, Pointer(Self), FThreadID, StackSize);
- if FHandle = TThreadID(0) then
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TThread.SysCreate: Failed to create thread');{$ENDIF}
- raise EThread.create('Failed to create new thread');
- end;
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('TThread.SysCreate: thread created');{$ENDIF}
- end;
- procedure TThread.SysDestroy;
- begin
- { exception in constructor }
- if not assigned(FSuspendEvent) then
- exit;
- { exception in constructor }
- if (FHandle = TThreadID(0)) then
- begin
- RtlEventDestroy(FSuspendEvent);
- exit;
- end;
- { Thread itself called destroy ? }
- if (FThreadID = GetCurrentThreadID) then
- begin
- if not(FFreeOnTerminate) and not FFinished then
- raise EThreadDestroyCalled.Create('A thread cannot destroy itself except by setting FreeOnTerminate and leaving!');
- FFreeOnTerminate := false;
- end
- else
- begin
- { avoid recursion}
- FFreeOnTerminate := false;
- { you can't join yourself, so only for FThreadID<>GetCurrentThreadID }
- { and you can't join twice -> make sure we didn't join already }
- if not FThreadReaped then
- begin
- Terminate;
- if (FSuspendedInternal or FInitialSuspended) then
- Resume;
- WaitFor;
- end;
- end;
- RtlEventDestroy(FSuspendEvent);
- FFatalException.Free;
- FFatalException := nil;
- end;
- procedure TThread.Resume;
- begin
- if FSuspendedInternal and (InterLockedExchange(longint(FSuspendedInternal),ord(false)) = longint(longbool(true))) then
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('resuming thread after TThread construction '+IntToStr(ptruint(self)));{$ENDIF}
- RtlEventSetEvent(FSuspendEvent);
- end
- else
- begin
- { don't compare with ord(true) or ord(longbool(true)), }
- { becaue a longbool's "true" value is anyting <> false }
- if FSuspended and
- (InterLockedExchange(longint(FSuspended),longint(false)) <> longint(longbool(false))) then
- begin
- {$IFDEF DEBUGWASMTHREADS}DebugWriteln('resuming '+IntToStr(ptruint(self)));{$ENDIF}
- RtlEventSetEvent(FSuspendEvent);
- end
- end
- end;
- procedure TThread.Suspend;
- begin
- if FThreadID<>GetCurrentThreadID then
- Raise EThread.create('Suspending one thread from inside another one is unsupported (because it is unsafe and deadlock prone) by *nix and posix operating systems');
- { don't compare with ord(true) or ord(longbool(true)), }
- { becaue a longbool's "true" value is anyting <> false }
- if not FSuspended and
- (InterLockedExchange(longint(FSuspended),longint(longbool(true))) = longint(longbool(false))) then
- RtlEventWaitFor(FSuspendEvent)
- end;
- function TThread.WaitFor: Integer;
- begin
- WaitFor:=WaitForThreadTerminate(FThreadID,-1);
- end;
- {$else FPC_WASM_THREADS}
- procedure TThread.CallOnTerminate;
- begin
- end;
- function TThread.GetPriority: TThreadPriority;
- begin
- GetPriority:=tpNormal;
- end;
- procedure TThread.SetPriority(Value: TThreadPriority);
- begin
- end;
- procedure TThread.SetSuspended(Value: Boolean);
- begin
- end;
- procedure TThread.DoTerminate;
- begin
- end;
- procedure TThread.SysCreate(CreateSuspended: Boolean; const StackSize: SizeUInt);
- begin
- {IsMultiThread := TRUE; }
- end;
- procedure TThread.SysDestroy;
- begin
- end;
- procedure TThread.Resume;
- begin
- end;
- procedure TThread.Suspend;
- begin
- end;
- function TThread.WaitFor: Integer;
- begin
- WaitFor:=0;
- end;
- {$endif FPC_WASM_THREADS}
|