tuning - although ugly, the speedup of critical: is > 30%
authorClaus Gittinger <cg@exept.de>
Tue, 28 Oct 2003 22:12:54 +0100
changeset 7717 ac9f01ef7157
parent 7716 41535a2538c9
child 7718 657b832f54a3
tuning - although ugly, the speedup of critical: is > 30%
Semaphore.st
--- a/Semaphore.st	Tue Oct 28 21:40:03 2003 +0100
+++ b/Semaphore.st	Tue Oct 28 22:12:54 2003 +0100
@@ -335,7 +335,7 @@
         ].
         ^ true
     ].
-    (waitingProcesses identityIndexOf:process) == 0 ifTrue:[
+    (waitingProcesses isNil or:[(waitingProcesses includesIdentical:process) not]) ifTrue:[
         self addWaitingProcess:process.
     ].
     ^ false
@@ -344,11 +344,14 @@
     "Modified: 10.1.1997 / 21:42:18 / cg"
 !
 
-unregisterProcess:process
+unregisterProcess:aProcess
     "interface for SemaphoreSet.
-     Unregister our process from the Semaphore"
+     Unregister our process from the Semaphore.
+     ATTENTION: this must be invoked with OperatingSystem-interrupts-blocked."
 
-    waitingProcesses removeIdentical:process ifAbsent:[].
+    waitingProcesses notNil ifTrue:[
+        self removeWaitingProcess:aProcess
+    ].
 
     "Created: 14.12.1995 / 10:31:50 / stefan"
     "Modified: 1.2.1997 / 12:11:22 / cg"
@@ -381,14 +384,23 @@
 
 addWaitingProcess:aProcess
     "add aProcess to the list of waiting processes.
-     Sort, so that higher priority process are resumed first.
-     Processes having the same priority are ordered first-come-first-serve.
+     all processes are ordered first-come-first-serve.
 
      NOTE: must be called with blocked interrupts"
 
     "for now"
-    waitingProcesses add:aProcess.
+    waitingProcesses isNil ifTrue:[
+        waitingProcesses := Array with:aProcess
+    ] ifFalse:[
+        waitingProcesses class == Array ifTrue:[
+            waitingProcesses := OrderedCollection withAll:waitingProcesses.
+        ].
+        waitingProcesses add:aProcess.
+    ].
 
+"/    "Sort, so that higher priority process are resumed first.
+"/    Processes having the same priority are ordered first-come-first-serve."
+"/
 "/    |priority insertIndex|
 "/
 "/    (waitingProcesses size == 0 
@@ -399,6 +411,45 @@
 "/
 "/    insertIndex := waitingProcesses findFirst:[:process| process priority < priority].
 "/    waitingProcesses add:aProcess beforeIndex:insertIndex.
+!
+
+removeFirstWaitingProcess
+    "remove the first waiting process from the list of waiting processes
+     and return it; Nil if there is none.
+
+     NOTE: must be called with blocked interrupts"
+
+    |nWaiting p|
+
+    nWaiting := waitingProcesses size.
+    nWaiting == 0 ifTrue:[^ nil].
+
+    nWaiting == 1 ifTrue:[
+        p := waitingProcesses at:1.
+        waitingProcesses := nil.
+        ^ p.
+    ].
+    ^ waitingProcesses removeFirst.
+!
+
+removeWaitingProcess:aProcess
+    "remove aProcess from the list of waiting processes
+     NO action if it is not in the list.
+
+     NOTE: must be called with blocked interrupts"
+
+    |nWaiting|
+
+    nWaiting := waitingProcesses size.
+    nWaiting == 0 ifTrue:[^ self].
+
+    nWaiting == 1 ifTrue:[
+        (waitingProcesses at:1) == aProcess ifTrue:[
+            waitingProcesses := nil.
+        ].
+        ^ self.
+    ].
+   waitingProcesses removeIdentical:aProcess ifAbsent:[].
 ! !
 
 !Semaphore methodsFor:'private-accessing'!
@@ -416,7 +467,7 @@
     "set the count of the semaphore;
      thats the number of possible waits, without blocking"
 
-    waitingProcesses := OrderedCollection new:2.
+    waitingProcesses := nil.
     count := n
 
     "Modified: 17.2.1997 / 11:36:40 / cg"
@@ -454,7 +505,7 @@
 waitingProcesses
     "return the processes waiting on the receiver"
 
-    ^ waitingProcesses
+    ^ waitingProcesses ? #()
 
     "Created: 18.7.1996 / 20:53:33 / cg"
 !
@@ -473,7 +524,7 @@
 isEmpty
     "ST80 compatibility - return true if there are no waiters"
 
-    ^ waitingProcesses isEmpty
+    ^ waitingProcesses size == 0
 
     "Created: / 3.5.1996 / 18:06:27 / cg"
     "Modified: / 18.6.1998 / 16:07:38 / cg"
@@ -491,7 +542,36 @@
     "evaluate aBlock as a critical region; the receiver must be
      created using Semaphore>>forMutualExclusion"
 
-    |retVal gotSema|
+    |retVal gotSema wasBlocked|
+
+    "/ inlined common case - ugly kludge but helpful
+    wasBlocked := OperatingSystem blockInterrupts.
+    count > 0 ifTrue:[
+        count := count - 1.
+        count == 0 ifTrue:[
+            lastOwnerID := Processor activeProcessId.
+        ].
+        wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+
+        retVal := aBlock ifCurtailed:[ self signal ].
+
+        OperatingSystem blockInterrupts.
+        [
+            |p|
+
+            count := count + 1.
+            waitingProcesses notNil ifTrue:[
+                p := self removeFirstWaitingProcess.
+                p notNil ifTrue:[
+                    Processor resume:p.
+                ].
+            ].
+        ] ensure:[
+            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+        ].
+        ^ retVal.
+    ].
+    wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
 
     [
         gotSema := self wait.
@@ -549,9 +629,11 @@
         |p|
 
         count := count + 1.
-        p := waitingProcesses removeFirstIfAbsent:nil.
-        p notNil ifTrue:[
-            Processor resume:p.
+        waitingProcesses notNil ifTrue:[
+            p := self removeFirstWaitingProcess.
+            p notNil ifTrue:[
+                Processor resume:p.
+            ].
         ].
     ] ensure:[
         wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
@@ -570,14 +652,16 @@
     waitingProcesses notEmpty ifTrue:[
         wasBlocked := OperatingSystem blockInterrupts.
         [
+            |nWaiting|
+
             "/ first, make them all runnable, but do not schedule
             "/ (in case one has higher prio and goes into a wait
             "/  immediately again.)
 
-            [waitingProcesses notEmpty] whileTrue:[
+            [(nWaiting := waitingProcesses size) > 0] whileTrue:[
                 |p|
 
-                p := waitingProcesses removeFirst.
+                p := self removeFirstWaitingProcess.
                 count := count + 1.
                 Processor makeRunnable:p.
             ].
@@ -600,10 +684,10 @@
 
     |wasBlocked|
 
-    waitingProcesses notEmpty ifTrue:[
+    (waitingProcesses size > 0) ifTrue:[
         wasBlocked := OperatingSystem blockInterrupts.
         [
-            waitingProcesses notEmpty ifTrue:[
+            (waitingProcesses size > 0) ifTrue:[
                 self signal
             ].
         ] ensure:[
@@ -624,12 +708,16 @@
         wasBlocked := OperatingSystem blockInterrupts.
         "/ check again - now interrupts are blocked.
         [
+            |p|
+
             count <= 0 ifTrue:[
                 count := count + 1.
-                count == 1 ifTrue:[ |p|
-                    p := waitingProcesses removeFirstIfAbsent:nil.
-                    p notNil ifTrue:[
-                        Processor resume:p.
+                count == 1 ifTrue:[
+                    waitingProcesses notNil ifTrue:[
+                        p := self removeFirstWaitingProcess.
+                        p notNil ifTrue:[
+                            Processor resume:p.
+                        ].
                     ].
                 ].
             ].
@@ -666,14 +754,14 @@
             [
                 activeProcess suspendWithState:#wait
             ] ifCurtailed:[
-                waitingProcesses removeIdentical:activeProcess ifAbsent:[].
+                self removeWaitingProcess:activeProcess.
                 wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
             ].
             
             count <= 0 ifTrue:[
                 "/ care for someone manually resuming me (i.e. semaphore still not avail)...
                 "/ being multiple times on waitingProcesses
-                waitingProcesses removeIdentical:activeProcess ifAbsent:[].
+                self removeWaitingProcess:activeProcess.
             ]
         ].
     ].
@@ -716,13 +804,13 @@
         [
             activeProcess suspendWithState:#wait
         ] ifCurtailed:[
-            waitingProcesses removeIdentical:activeProcess ifAbsent:[].
+            self removeWaitingProcess:activeProcess.
             wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
         ].
         count <= 0 ifTrue:[
             "/ care for someone manually resuming me (i.e. semaphore still not avail)...
             "/ being multiple times on waitingProcesses
-            waitingProcesses removeIdentical:activeProcess ifAbsent:[].
+            self removeWaitingProcess:activeProcess.
         ]
     ].
     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
@@ -803,11 +891,11 @@
             ] ifCurtailed:[
                 Processor removeTimedBlock:unblock.
                 unblock := nil.
-                waitingProcesses removeIdentical:activeProcess ifAbsent:[].
+                self removeWaitingProcess:activeProcess.
                 wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
             ].
 
-            waitingProcesses removeIdentical:activeProcess ifAbsent:[].
+            self removeWaitingProcess:activeProcess.
             timeoutOccured ifTrue:[
                 wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
                 unblock := nil.
@@ -835,5 +923,5 @@
 !Semaphore class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.69 2003-05-07 14:11:01 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.70 2003-10-28 21:12:54 cg Exp $'
 ! !