From 356845ba1ea5f062f21ecb8bf3f6d395e085f00e Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Sun, 10 Jan 2010 11:04:05 +0000 Subject: [PATCH] * 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 - --- rtl/inc/thread.inc | 62 ++++++++++++-- rtl/objpas/sysutils/sysuthrd.inc | 138 ++++++++++++++++++------------- 2 files changed, 132 insertions(+), 68 deletions(-) diff --git a/rtl/inc/thread.inc b/rtl/inc/thread.inc index 5f05c69d3a..e883967b5f 100644 --- a/rtl/inc/thread.inc +++ b/rtl/inc/thread.inc @@ -334,6 +334,7 @@ function NoBeginThread(sa : Pointer;stacksize : PtrUInt; creationFlags : dword; var ThreadId : TThreadID) : TThreadID; begin NoThreadError; + result:=tthreadid(-1); end; procedure NoEndThread(ExitCode : DWord); @@ -344,6 +345,7 @@ end; function NoThreadHandler (threadHandle : TThreadID) : dword; begin NoThreadError; + result:=dword(-1); end; procedure NoThreadSwitch; {give time to other threads} @@ -354,16 +356,19 @@ end; function NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword; {0=no timeout} begin NoThreadError; + result:=dword(-1); end; function NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal} begin NoThreadError; + result:=false; end; function NoThreadGetPriority (threadHandle : TThreadID): longint; begin NoThreadError; + result:=-1; end; function NoGetCurrentThreadId : TThreadID; @@ -394,6 +399,7 @@ function NoRelocateThreadvar(offset : dword) : pointer; begin NoThreadError; + result:=nil; end; @@ -412,31 +418,45 @@ end; function noBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState; begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; + result:=nil; end; procedure nobasiceventdestroy(state:peventstate); begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; end; procedure nobasiceventResetEvent(state:peventstate); begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; end; procedure nobasiceventSetEvent(state:peventstate); begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; end; function nobasiceventWaitFor(Timeout : Cardinal;state:peventstate) : longint; begin NoThreadError; + result:=-1; end; function NORTLEventCreate :PRTLEvent; @@ -445,7 +465,8 @@ begin if IsMultiThread then NoThreadError else - ThreadingAlreadyUsed:=true + ThreadingAlreadyUsed:=true; + result:=nil; end; procedure NORTLeventdestroy(state:pRTLEvent); @@ -460,7 +481,19 @@ end; procedure NORTLeventSetEvent(state:pRTLEvent); begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; +end; + +procedure NORTLeventResetEvent(state:pRTLEvent); + +begin + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; end; procedure NORTLeventWaitFor(state:pRTLEvent); @@ -482,7 +515,11 @@ procedure NORTLeventsync(m:trtlmethod;p:tprocedure); function NoSemaphoreInit: Pointer; begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; + result:=nil; end; procedure NoSemaphoreWait(const FSem: Pointer); @@ -492,12 +529,18 @@ end; procedure NoSemaphorePost(const FSem: Pointer); begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; end; procedure NoSemaphoreDestroy(const FSem: Pointer); begin - NoThreadError; + if IsMultiThread then + NoThreadError + else + ThreadingAlreadyUsed:=true; end; Var @@ -536,6 +579,7 @@ begin rtlEventCreate :=@NortlEventCreate; rtleventdestroy :=@Nortleventdestroy; rtleventSetEvent :=@NortleventSetEvent; + rtleventResetEvent :=@NortleventResetEvent; rtleventWaitFor :=@NortleventWaitFor; rtleventsync :=@Nortleventsync; rtleventwaitfortimeout :=@NortleventWaitForTimeout; diff --git a/rtl/objpas/sysutils/sysuthrd.inc b/rtl/objpas/sysutils/sysuthrd.inc index e666db8e3a..8a69f5dea3 100644 --- a/rtl/objpas/sysutils/sysuthrd.inc +++ b/rtl/objpas/sysutils/sysuthrd.inc @@ -68,28 +68,33 @@ end; function TMultiReadExclusiveWriteSynchronizer.Beginwrite : boolean; begin - { wait for any other writers that may be in progress } - RTLEventWaitFor(fwritelock); - { it is possible that we earlier on missed waiting on the - fwaitingwriterlock and that it's still set (must be done - after aquiring the fwritelock, because otherwise one - writer could reset the fwaitingwriterlock of another one - that's about to wait on it) } - RTLeventResetEvent(fwaitingwriterlock); - { new readers have to block from now on; writers get priority to avoid - writer starvation (since they have to compete with potentially many - concurrent readers) } - BasicEventResetEvent(freaderqueue); - { for quick checking by candidate-readers } - System.InterlockedExchange(fwritelocked,1); - - { wait until all readers are gone -- freadercount and fwritelocked are only - accessed using atomic operations (that's why we use - 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); + { if IsMultiThread is false, no thread manager may be installed + under unix and hence the event routines may throw an error } + if IsMultiThread then + begin + { wait for any other writers that may be in progress } + RTLEventWaitFor(fwritelock); + { it is possible that we earlier on missed waiting on the + fwaitingwriterlock and that it's still set (must be done + after aquiring the fwritelock, because otherwise one + writer could reset the fwaitingwriterlock of another one + that's about to wait on it) } + RTLeventResetEvent(fwaitingwriterlock); + { new readers have to block from now on; writers get priority to avoid + writer starvation (since they have to compete with potentially many + concurrent readers) } + BasicEventResetEvent(freaderqueue); + { for quick checking by candidate-readers } + System.InterlockedExchange(fwritelocked,1); + + { wait until all readers are gone -- freadercount and fwritelocked are only + accessed using atomic operations (that's why we use + 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 } result:=true; @@ -98,20 +103,25 @@ end; procedure TMultiReadExclusiveWriteSynchronizer.Endwrite; begin - { Finish all writes inside the section so that everything executing - afterwards will certainly see these results } - WriteBarrier; + { if IsMultiThread is false, no thread manager may be installed + under unix and hence the event routines may throw an error } + 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 } - System.InterlockedExchange(fwritelocked,0); - { wake up waiting readers (if any); do not check first whether freadercount - 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 - freaderqueue even though freadercount=0. Setting an event multiple times - is no problem. } - BasicEventSetEvent(freaderqueue); - { free the writer lock so another writer can become active } - RTLeventSetEvent(fwritelock); + { signal potential readers that the coast is clear } + System.InterlockedExchange(fwritelocked,0); + { wake up waiting readers (if any); do not check first whether freadercount + 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 + freaderqueue even though freadercount=0. Setting an event multiple times + is no problem. } + BasicEventSetEvent(freaderqueue); + { free the writer lock so another writer can become active } + RTLeventSetEvent(fwritelock); + end; end; @@ -122,37 +132,47 @@ Const wrAbandoned= 2; wrError = 3; begin - System.InterlockedIncrement(freadercount); - { wait until there is no more writer } - while System.InterLockedExchangeAdd(fwritelocked,0)<>0 do + { if IsMultiThread is false, no thread manager may be installed + under unix and hence the event routines may throw an error } + if IsMultiThread then 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); + { 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; procedure TMultiReadExclusiveWriteSynchronizer.Endread; 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 IsMultiThread is false, no thread manager may be installed + under unix and hence the event routines may throw an error } + if IsMultiThread then + 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 - always first atomically sets the fwritelocked and then atomically checks - the freadercount, first modifying freadercount and then checking fwritelock - ensures that we cannot miss one of the events regardless of execution - order. } - if (System.InterlockedDecrement(freadercount)=0) and - (System.InterLockedExchangeAdd(fwritelocked,0)<>0) then - RTLEventSetEvent(fwaitingwriterlock); + { 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 + the freadercount, first modifying freadercount and then checking fwritelock + ensures that we cannot miss one of the events regardless of execution + order. } + if (System.InterlockedDecrement(freadercount)=0) and + (System.InterLockedExchangeAdd(fwritelocked,0)<>0) then + RTLEventSetEvent(fwaitingwriterlock); + end; end;