소스 검색

* 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 -

Jonas Maebe 15 년 전
부모
커밋
356845ba1e
2개의 변경된 파일134개의 추가작업 그리고 70개의 파일을 삭제
  1. 53 9
      rtl/inc/thread.inc
  2. 81 61
      rtl/objpas/sysutils/sysuthrd.inc

+ 53 - 9
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;

+ 81 - 61
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;
-
-  { 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);
+  { 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);
+    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 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 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);
+    end;
 end;