* 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:
Jonas Maebe 2010-01-10 11:04:05 +00:00
parent 9bad162368
commit 356845ba1e
2 changed files with 132 additions and 68 deletions

View File

@ -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;

View File

@ -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;