mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-19 16:09:16 +02:00
* set function results for unimplemented generic thread manager routines
(to remove warnings) * don't give a thread error for basicevent and threadevent routines if isMultiThreaded is false, except for the waiting routines (the new TMultiReadExclusiveWriteSynchronizer creates/sets such events in the constructor, which caused thread manager errors in case cthreads was not used under unix) * don't perform any actual locking in TMultiReadExclusiveWriteSynchronizer routines if isMultiThreaded is false (in order to avoid the errors described above) + added generic RTLeventResetEvent stub git-svn-id: trunk@14592 -
This commit is contained in:
parent
9bad162368
commit
356845ba1e
@ -334,6 +334,7 @@ function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
|
|||||||
creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
|
creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=tthreadid(-1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure NoEndThread(ExitCode : DWord);
|
procedure NoEndThread(ExitCode : DWord);
|
||||||
@ -344,6 +345,7 @@ end;
|
|||||||
function NoThreadHandler (threadHandle : TThreadID) : dword;
|
function NoThreadHandler (threadHandle : TThreadID) : dword;
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=dword(-1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure NoThreadSwitch; {give time to other threads}
|
procedure NoThreadSwitch; {give time to other threads}
|
||||||
@ -354,16 +356,19 @@ end;
|
|||||||
function NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout}
|
function NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout}
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=dword(-1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
|
function NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NoThreadGetPriority (threadHandle : TThreadID): longint;
|
function NoThreadGetPriority (threadHandle : TThreadID): longint;
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=-1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NoGetCurrentThreadId : TThreadID;
|
function NoGetCurrentThreadId : TThreadID;
|
||||||
@ -394,6 +399,7 @@ function NoRelocateThreadvar(offset : dword) : pointer;
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -412,31 +418,45 @@ end;
|
|||||||
function noBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
|
function noBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
|
result:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure nobasiceventdestroy(state:peventstate);
|
procedure nobasiceventdestroy(state:peventstate);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure nobasiceventResetEvent(state:peventstate);
|
procedure nobasiceventResetEvent(state:peventstate);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure nobasiceventSetEvent(state:peventstate);
|
procedure nobasiceventSetEvent(state:peventstate);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function nobasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
|
function nobasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
NoThreadError;
|
||||||
|
result:=-1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NORTLEventCreate :PRTLEvent;
|
function NORTLEventCreate :PRTLEvent;
|
||||||
@ -445,7 +465,8 @@ begin
|
|||||||
if IsMultiThread then
|
if IsMultiThread then
|
||||||
NoThreadError
|
NoThreadError
|
||||||
else
|
else
|
||||||
ThreadingAlreadyUsed:=true
|
ThreadingAlreadyUsed:=true;
|
||||||
|
result:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure NORTLeventdestroy(state:pRTLEvent);
|
procedure NORTLeventdestroy(state:pRTLEvent);
|
||||||
@ -460,7 +481,19 @@ end;
|
|||||||
procedure NORTLeventSetEvent(state:pRTLEvent);
|
procedure NORTLeventSetEvent(state:pRTLEvent);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure NORTLeventResetEvent(state:pRTLEvent);
|
||||||
|
|
||||||
|
begin
|
||||||
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure NORTLeventWaitFor(state:pRTLEvent);
|
procedure NORTLeventWaitFor(state:pRTLEvent);
|
||||||
@ -482,7 +515,11 @@ procedure NORTLeventsync(m:trtlmethod;p:tprocedure);
|
|||||||
|
|
||||||
function NoSemaphoreInit: Pointer;
|
function NoSemaphoreInit: Pointer;
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
|
result:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure NoSemaphoreWait(const FSem: Pointer);
|
procedure NoSemaphoreWait(const FSem: Pointer);
|
||||||
@ -492,12 +529,18 @@ end;
|
|||||||
|
|
||||||
procedure NoSemaphorePost(const FSem: Pointer);
|
procedure NoSemaphorePost(const FSem: Pointer);
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure NoSemaphoreDestroy(const FSem: Pointer);
|
procedure NoSemaphoreDestroy(const FSem: Pointer);
|
||||||
begin
|
begin
|
||||||
NoThreadError;
|
if IsMultiThread then
|
||||||
|
NoThreadError
|
||||||
|
else
|
||||||
|
ThreadingAlreadyUsed:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
@ -536,6 +579,7 @@ begin
|
|||||||
rtlEventCreate :=@NortlEventCreate;
|
rtlEventCreate :=@NortlEventCreate;
|
||||||
rtleventdestroy :=@Nortleventdestroy;
|
rtleventdestroy :=@Nortleventdestroy;
|
||||||
rtleventSetEvent :=@NortleventSetEvent;
|
rtleventSetEvent :=@NortleventSetEvent;
|
||||||
|
rtleventResetEvent :=@NortleventResetEvent;
|
||||||
rtleventWaitFor :=@NortleventWaitFor;
|
rtleventWaitFor :=@NortleventWaitFor;
|
||||||
rtleventsync :=@Nortleventsync;
|
rtleventsync :=@Nortleventsync;
|
||||||
rtleventwaitfortimeout :=@NortleventWaitForTimeout;
|
rtleventwaitfortimeout :=@NortleventWaitForTimeout;
|
||||||
|
@ -68,28 +68,33 @@ end;
|
|||||||
|
|
||||||
function TMultiReadExclusiveWriteSynchronizer.Beginwrite : boolean;
|
function TMultiReadExclusiveWriteSynchronizer.Beginwrite : boolean;
|
||||||
begin
|
begin
|
||||||
{ wait for any other writers that may be in progress }
|
{ if IsMultiThread is false, no thread manager may be installed
|
||||||
RTLEventWaitFor(fwritelock);
|
under unix and hence the event routines may throw an error }
|
||||||
{ it is possible that we earlier on missed waiting on the
|
if IsMultiThread then
|
||||||
fwaitingwriterlock and that it's still set (must be done
|
begin
|
||||||
after aquiring the fwritelock, because otherwise one
|
{ wait for any other writers that may be in progress }
|
||||||
writer could reset the fwaitingwriterlock of another one
|
RTLEventWaitFor(fwritelock);
|
||||||
that's about to wait on it) }
|
{ it is possible that we earlier on missed waiting on the
|
||||||
RTLeventResetEvent(fwaitingwriterlock);
|
fwaitingwriterlock and that it's still set (must be done
|
||||||
{ new readers have to block from now on; writers get priority to avoid
|
after aquiring the fwritelock, because otherwise one
|
||||||
writer starvation (since they have to compete with potentially many
|
writer could reset the fwaitingwriterlock of another one
|
||||||
concurrent readers) }
|
that's about to wait on it) }
|
||||||
BasicEventResetEvent(freaderqueue);
|
RTLeventResetEvent(fwaitingwriterlock);
|
||||||
{ for quick checking by candidate-readers }
|
{ new readers have to block from now on; writers get priority to avoid
|
||||||
System.InterlockedExchange(fwritelocked,1);
|
writer starvation (since they have to compete with potentially many
|
||||||
|
concurrent readers) }
|
||||||
{ wait until all readers are gone -- freadercount and fwritelocked are only
|
BasicEventResetEvent(freaderqueue);
|
||||||
accessed using atomic operations (that's why we use
|
{ for quick checking by candidate-readers }
|
||||||
InterLockedExchangeAdd(x,0) below) -> always in-order. The writer always
|
System.InterlockedExchange(fwritelocked,1);
|
||||||
first sets fwritelocked and then checks freadercount, while the readers
|
|
||||||
always first increase freadercount and then check fwritelocked }
|
{ wait until all readers are gone -- freadercount and fwritelocked are only
|
||||||
while (System.InterLockedExchangeAdd(freadercount,0)<>0) do
|
accessed using atomic operations (that's why we use
|
||||||
RTLEventWaitFor(fwaitingwriterlock);
|
InterLockedExchangeAdd(x,0) below) -> always in-order. The writer always
|
||||||
|
first sets fwritelocked and then checks freadercount, while the readers
|
||||||
|
always first increase freadercount and then check fwritelocked }
|
||||||
|
while (System.InterLockedExchangeAdd(freadercount,0)<>0) do
|
||||||
|
RTLEventWaitFor(fwaitingwriterlock);
|
||||||
|
end;
|
||||||
|
|
||||||
{ we have the writer lock, and all readers are gone }
|
{ we have the writer lock, and all readers are gone }
|
||||||
result:=true;
|
result:=true;
|
||||||
@ -98,20 +103,25 @@ end;
|
|||||||
|
|
||||||
procedure TMultiReadExclusiveWriteSynchronizer.Endwrite;
|
procedure TMultiReadExclusiveWriteSynchronizer.Endwrite;
|
||||||
begin
|
begin
|
||||||
{ Finish all writes inside the section so that everything executing
|
{ if IsMultiThread is false, no thread manager may be installed
|
||||||
afterwards will certainly see these results }
|
under unix and hence the event routines may throw an error }
|
||||||
WriteBarrier;
|
if IsMultiThread then
|
||||||
|
begin
|
||||||
|
{ Finish all writes inside the section so that everything executing
|
||||||
|
afterwards will certainly see these results }
|
||||||
|
WriteBarrier;
|
||||||
|
|
||||||
{ signal potential readers that the coast is clear }
|
{ signal potential readers that the coast is clear }
|
||||||
System.InterlockedExchange(fwritelocked,0);
|
System.InterlockedExchange(fwritelocked,0);
|
||||||
{ wake up waiting readers (if any); do not check first whether freadercount
|
{ wake up waiting readers (if any); do not check first whether freadercount
|
||||||
is <> 0, because the InterlockedDecrement in the while loop of BeginRead
|
is <> 0, because the InterlockedDecrement in the while loop of BeginRead
|
||||||
can have already occurred, so a single reader may be about to wait on
|
can have already occurred, so a single reader may be about to wait on
|
||||||
freaderqueue even though freadercount=0. Setting an event multiple times
|
freaderqueue even though freadercount=0. Setting an event multiple times
|
||||||
is no problem. }
|
is no problem. }
|
||||||
BasicEventSetEvent(freaderqueue);
|
BasicEventSetEvent(freaderqueue);
|
||||||
{ free the writer lock so another writer can become active }
|
{ free the writer lock so another writer can become active }
|
||||||
RTLeventSetEvent(fwritelock);
|
RTLeventSetEvent(fwritelock);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -122,37 +132,47 @@ Const
|
|||||||
wrAbandoned= 2;
|
wrAbandoned= 2;
|
||||||
wrError = 3;
|
wrError = 3;
|
||||||
begin
|
begin
|
||||||
System.InterlockedIncrement(freadercount);
|
{ if IsMultiThread is false, no thread manager may be installed
|
||||||
{ wait until there is no more writer }
|
under unix and hence the event routines may throw an error }
|
||||||
while System.InterLockedExchangeAdd(fwritelocked,0)<>0 do
|
if IsMultiThread then
|
||||||
begin
|
begin
|
||||||
{ there's a writer busy or wanting to start -> wait until it's
|
|
||||||
finished; a writer may already be blocked in the mean time, so
|
|
||||||
wake it up if we're the last to go to sleep }
|
|
||||||
if System.InterlockedDecrement(freadercount)=0 then
|
|
||||||
RTLEventSetEvent(fwaitingwriterlock);
|
|
||||||
if (BasicEventWaitFor(high(cardinal),freaderqueue) in [wrAbandoned,wrError]) then
|
|
||||||
raise Exception.create('BasicEventWaitFor failed in TMultiReadExclusiveWriteSynchronizer.Beginread');
|
|
||||||
{ and try again: first increase freadercount, only then check
|
|
||||||
fwritelocked }
|
|
||||||
System.InterlockedIncrement(freadercount);
|
System.InterlockedIncrement(freadercount);
|
||||||
|
{ wait until there is no more writer }
|
||||||
|
while System.InterLockedExchangeAdd(fwritelocked,0)<>0 do
|
||||||
|
begin
|
||||||
|
{ there's a writer busy or wanting to start -> wait until it's
|
||||||
|
finished; a writer may already be blocked in the mean time, so
|
||||||
|
wake it up if we're the last to go to sleep }
|
||||||
|
if System.InterlockedDecrement(freadercount)=0 then
|
||||||
|
RTLEventSetEvent(fwaitingwriterlock);
|
||||||
|
if (BasicEventWaitFor(high(cardinal),freaderqueue) in [wrAbandoned,wrError]) then
|
||||||
|
raise Exception.create('BasicEventWaitFor failed in TMultiReadExclusiveWriteSynchronizer.Beginread');
|
||||||
|
{ and try again: first increase freadercount, only then check
|
||||||
|
fwritelocked }
|
||||||
|
System.InterlockedIncrement(freadercount);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMultiReadExclusiveWriteSynchronizer.Endread;
|
procedure TMultiReadExclusiveWriteSynchronizer.Endread;
|
||||||
begin
|
begin
|
||||||
{ Make sure that all read operations have finished, so that none of those
|
{ if IsMultiThread is false, no thread manager may be installed
|
||||||
can still be executed after a writer starts working and changes some
|
under unix and hence the event routines may throw an error }
|
||||||
things }
|
if IsMultiThread then
|
||||||
ReadBarrier;
|
begin
|
||||||
|
{ Make sure that all read operations have finished, so that none of those
|
||||||
|
can still be executed after a writer starts working and changes some
|
||||||
|
things }
|
||||||
|
ReadBarrier;
|
||||||
|
|
||||||
{ If no more readers, wake writer in the ready-queue if any. Since a writer
|
{ If no more readers, wake writer in the ready-queue if any. Since a writer
|
||||||
always first atomically sets the fwritelocked and then atomically checks
|
always first atomically sets the fwritelocked and then atomically checks
|
||||||
the freadercount, first modifying freadercount and then checking fwritelock
|
the freadercount, first modifying freadercount and then checking fwritelock
|
||||||
ensures that we cannot miss one of the events regardless of execution
|
ensures that we cannot miss one of the events regardless of execution
|
||||||
order. }
|
order. }
|
||||||
if (System.InterlockedDecrement(freadercount)=0) and
|
if (System.InterlockedDecrement(freadercount)=0) and
|
||||||
(System.InterLockedExchangeAdd(fwritelocked,0)<>0) then
|
(System.InterLockedExchangeAdd(fwritelocked,0)<>0) then
|
||||||
RTLEventSetEvent(fwaitingwriterlock);
|
RTLEventSetEvent(fwaitingwriterlock);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user