Semaphore.st
changeset 8569 657853ae04cd
parent 7718 657b832f54a3
child 8617 5fb5a717deff
--- a/Semaphore.st	Tue Sep 21 20:00:49 2004 +0200
+++ b/Semaphore.st	Tue Sep 21 20:06:25 2004 +0200
@@ -318,45 +318,6 @@
     ^ super new setCount:n
 ! !
 
-!Semaphore methodsFor:'friend-class interface'!
-
-checkAndRegisterProcess:process
-    "interface for SemaphoreSet.
-     If the semaphore is available, decrement it and return true.
-     Otherwise register our process to be wakened up once the semaphore is available
-     and return false.
-     ATTENTION: this must be invoked with OperatingSystem-interrupts-blocked.
-    "
-
-    count > 0 ifTrue:[
-        count := count - 1.
-        count == 0 ifTrue:[
-            lastOwnerID := Processor activeProcessId.
-        ].
-        ^ true
-    ].
-    (waitingProcesses isNil or:[(waitingProcesses includesIdentical:process) not]) ifTrue:[
-        self addWaitingProcess:process.
-    ].
-    ^ false
-
-    "Modified: 14.12.1995 / 10:32:17 / stefan"
-    "Modified: 10.1.1997 / 21:42:18 / cg"
-!
-
-unregisterProcess:aProcess
-    "interface for SemaphoreSet.
-     Unregister our process from the Semaphore.
-     ATTENTION: this must be invoked with OperatingSystem-interrupts-blocked."
-
-    waitingProcesses notNil ifTrue:[
-        self removeWaitingProcess:aProcess
-    ].
-
-    "Created: 14.12.1995 / 10:31:50 / stefan"
-    "Modified: 1.2.1997 / 12:11:22 / cg"
-! !
-
 !Semaphore methodsFor:'printing & storing'!
 
 displayString
@@ -454,6 +415,12 @@
 
 !Semaphore methodsFor:'private-accessing'!
 
+clear
+    "clear the semaphores count"
+
+    count := 0
+!
+
 initSignals
     "set the count of the semaphore to zero.
      provided for ST-80 compatibility."
@@ -508,6 +475,152 @@
     ^ waitingProcesses ? #()
 
     "Created: 18.7.1996 / 20:53:33 / cg"
+! !
+
+!Semaphore methodsFor:'semaphoreSet interface'!
+
+checkAndAddWaitingProcess:process
+    "interface for SemaphoreSet.
+     If the semaphore is available, decrement it and return true.
+     Otherwise register our process to be wakened up once the semaphore is available
+     and return false.
+     ATTENTION: this must be invoked with OperatingSystem-interrupts-blocked.
+    "
+
+    count > 0 ifTrue:[
+        count := count - 1.
+        count == 0 ifTrue:[
+            lastOwnerID := Processor activeProcessId.
+        ].
+        ^ true
+    ].
+    (waitingProcesses notNil and:[(waitingProcesses includesIdentical:process)]) ifFalse:[
+        self addWaitingProcess:process.
+    ].
+    ^ false
+
+    "Modified: 14.12.1995 / 10:32:17 / stefan"
+    "Modified: 10.1.1997 / 21:42:18 / cg"
+! !
+
+!Semaphore methodsFor:'signaling'!
+
+signal
+    "waking up (the first) waiter.
+     Q: should this be the highest prio waiter ?"
+
+    |wasBlocked|
+
+    wasBlocked := OperatingSystem blockInterrupts.
+    [
+        |p|
+
+        count := count + 1.
+        waitingProcesses notNil ifTrue:[
+            p := self removeFirstWaitingProcess.
+            p notNil ifTrue:[
+                Processor resume:p.
+            ].
+        ].
+    ] ensure:[
+        wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+    ]
+
+    "Modified: / 4.2.1998 / 21:01:07 / cg"
+!
+
+signalForAll
+    "signal the semaphore for all waiters.
+     This can be used for process synchronization, if multiple processes are
+     waiting for a common event."
+
+    |wasBlocked|
+
+    waitingProcesses size ~~ 0 ifTrue:[
+        wasBlocked := OperatingSystem blockInterrupts.
+        [
+            |processes|
+
+            "first, make them all runnable, but do not schedule
+             (in case one has higher prio and goes into a wait immediately again.)"
+
+            processes := waitingProcesses.
+            waitingProcesses := nil.
+            processes do:[:eachWaitingProcess|
+                count := count + 1.
+                Processor makeRunnable:eachWaitingProcess.
+            ].    
+        ] ensure:[
+            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+        ].
+        "now, schedule the highest priority process"
+        Processor reschedule
+    ]
+
+    "Modified: / 5.2.1998 / 10:40:26 / cg"
+!
+
+signalIf
+    "signal the semaphore, but only if being waited upon.
+     This can be used for one-shot semaphores (i.e. not remembering
+     previous signals)"
+
+    |wasBlocked|
+
+    waitingProcesses notNil ifTrue:[
+        wasBlocked := OperatingSystem blockInterrupts.
+        [
+            waitingProcesses size ~~ 0 ifTrue:[
+                self signal
+            ].
+        ] ensure:[
+            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+        ]
+    ]
+
+    "Modified: 28.2.1996 / 21:23:57 / cg"
+!
+
+signalOnce
+    "wakeup waiters - but only once.
+     I.e. if the semaphore has already been signalled, this is ignored."
+
+    |wasBlocked|
+
+    count <= 0 ifTrue:[
+        wasBlocked := OperatingSystem blockInterrupts.
+        "/ check again - now interrupts are blocked.
+        [
+            |p|
+
+            count <= 0 ifTrue:[
+                count := count + 1.
+                count == 1 ifTrue:[
+                    waitingProcesses notNil ifTrue:[
+                        p := self removeFirstWaitingProcess.
+                        p notNil ifTrue:[
+                            Processor resume:p.
+                        ].
+                    ].
+                ].
+            ].
+        ] ensure:[
+            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+        ]
+    ]
+
+    "Modified: 28.2.1996 / 21:24:08 / cg"
+! !
+
+!Semaphore methodsFor:'testing'!
+
+isEmpty
+    "ST80 compatibility - return true if there are no waiters"
+
+    ^ waitingProcesses size == 0
+
+    "Created: / 3.5.1996 / 18:06:27 / cg"
+    "Modified: / 18.6.1998 / 16:07:38 / cg"
 !
 
 wouldBlock
@@ -519,24 +632,7 @@
     ^ count <= 0
 ! !
 
-!Semaphore methodsFor:'testing'!
-
-isEmpty
-    "ST80 compatibility - return true if there are no waiters"
-
-    ^ waitingProcesses size == 0
-
-    "Created: / 3.5.1996 / 18:06:27 / cg"
-    "Modified: / 18.6.1998 / 16:07:38 / cg"
-! !
-
-!Semaphore methodsFor:'wait & signal'!
-
-clear
-    "clear the semaphores count"
-
-    count := 0
-!
+!Semaphore methodsFor:'waiting'!
 
 critical:aBlock
     "evaluate aBlock as a critical region; the receiver must be
@@ -618,117 +714,6 @@
     "Modified: / 21.7.1998 / 17:45:26 / cg"
 !
 
-signal
-    "waking up (the first) waiter.
-     Q: should this be the highest prio waiter ?"
-
-    |wasBlocked|
-
-    wasBlocked := OperatingSystem blockInterrupts.
-    [
-        |p|
-
-        count := count + 1.
-        waitingProcesses notNil ifTrue:[
-            p := self removeFirstWaitingProcess.
-            p notNil ifTrue:[
-                Processor resume:p.
-            ].
-        ].
-    ] ensure:[
-        wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-    ]
-
-    "Modified: / 4.2.1998 / 21:01:07 / cg"
-!
-
-signalForAll
-    "signal the semaphore for all waiters.
-     This can be used for process synchronization, if multiple processes are
-     waiting for a common event."
-
-    |wasBlocked|
-
-    waitingProcesses size > 0 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.)
-
-            [(nWaiting := waitingProcesses size) > 0] whileTrue:[
-                |p|
-
-                p := self removeFirstWaitingProcess.
-                count := count + 1.
-                Processor makeRunnable:p.
-            ].
-        ] ensure:[
-            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-        ].
-        "/
-        "/ now, reschedule
-        "/
-        Processor reschedule
-    ]
-
-    "Modified: / 5.2.1998 / 10:40:26 / cg"
-!
-
-signalIf
-    "signal the semaphore, but only if being waited upon.
-     This can be used for one-shot semaphores (i.e. not remembering
-     previous signals)"
-
-    |wasBlocked|
-
-    (waitingProcesses size > 0) ifTrue:[
-        wasBlocked := OperatingSystem blockInterrupts.
-        [
-            (waitingProcesses size > 0) ifTrue:[
-                self signal
-            ].
-        ] ensure:[
-            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-        ]
-    ]
-
-    "Modified: 28.2.1996 / 21:23:57 / cg"
-!
-
-signalOnce
-    "wakeup waiters - but only once.
-     I.e. if the semaphore has already been signalled, this is ignored."
-
-    |wasBlocked|
-
-    count <= 0 ifTrue:[
-        wasBlocked := OperatingSystem blockInterrupts.
-        "/ check again - now interrupts are blocked.
-        [
-            |p|
-
-            count <= 0 ifTrue:[
-                count := count + 1.
-                count == 1 ifTrue:[
-                    waitingProcesses notNil ifTrue:[
-                        p := self removeFirstWaitingProcess.
-                        p notNil ifTrue:[
-                            Processor resume:p.
-                        ].
-                    ].
-                ].
-            ].
-        ] ensure:[
-            wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-        ]
-    ]
-
-    "Modified: 28.2.1996 / 21:24:08 / cg"
-!
-
 wait
     "wait for the semaphore"
 
@@ -745,7 +730,7 @@
          Thus, the count is not always non-zero after returning from
          suspend.
         "
-        [count <= 0] whileTrue:[
+        [
             self addWaitingProcess:activeProcess.
             "
              for some more descriptive info in processMonitor ...
@@ -757,13 +742,8 @@
                 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
-                self removeWaitingProcess:activeProcess.
-            ]
-        ].
+            self removeWaitingProcess:activeProcess.
+        ] doUntil:[count > 0].
     ].
 
     count := count - 1.
@@ -807,11 +787,7 @@
             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
-            self removeWaitingProcess:activeProcess.
-        ]
+        self removeWaitingProcess:activeProcess.
     ].
     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
 
@@ -846,30 +822,27 @@
      However, polling is not the intended use of semaphores, though.
      If milliSeconds is nil, wait without timeout."
 
-    |activeProcess timeoutOccured wasBlocked unblock now endTime|
+    |activeProcess timeoutOccured wasBlocked timeoutBlock now endTime|
 
     wasBlocked := OperatingSystem blockInterrupts.
 
     count <= 0 ifTrue:[
-        "
-         with zero-timeout, this is a poll
-        "
-        milliSeconds = 0 ifTrue:[
+        "with zero-timeout, this is a poll"
+        milliSeconds == 0 ifTrue:[
             wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
             ^ nil
         ].
 
         activeProcess := Processor activeProcess.
+        timeoutOccured := false.
 
-        "
-         calculate the end-time
-        "
         milliSeconds notNil ifTrue:[
+            "Wait with timeout: calculate the end-time"
             now := OperatingSystem getMillisecondTime.
             endTime := OperatingSystem millisecondTimeAdd:now and:milliSeconds.
 
-            unblock := [timeoutOccured := true. Processor resume:activeProcess].
-            Processor addTimedBlock:unblock for:activeProcess atMilliseconds:endTime.
+            timeoutBlock := [timeoutOccured := true. timeoutBlock:= nil. Processor resume:activeProcess].
+            Processor addTimedBlock:timeoutBlock for:activeProcess atMilliseconds:endTime.
         ].
 
         "
@@ -878,19 +851,21 @@
          Thus, the count is not always non-zero after returning from
          suspend.
         "
-        [count <= 0] whileTrue:[
+        [
             self addWaitingProcess:activeProcess.
 
-            timeoutOccured := false.
             "
              for some more descriptive info in processMonitor ...
              ... set the state to #wait (instead of #suspend)
             "
             [
+                "sleep until resumed..."
                 activeProcess suspendWithState:#wait.
             ] ifCurtailed:[
-                Processor removeTimedBlock:unblock.
-                unblock := nil.
+                timeoutBlock notNil ifTrue:[
+                    Processor removeTimedBlock:timeoutBlock.
+                    timeoutBlock := nil.
+                ].
                 self removeWaitingProcess:activeProcess.
                 wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
             ].
@@ -898,17 +873,17 @@
             self removeWaitingProcess:activeProcess.
             timeoutOccured ifTrue:[
                 wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-                unblock := nil.
                 ^ nil
             ].
-        ].
+        ] doUntil:[count > 0].
 
-        unblock notNil ifTrue:[
-            Processor removeTimedBlock:unblock.
-            unblock := nil.
+        timeoutBlock notNil ifTrue:[
+            Processor removeTimedBlock:timeoutBlock.
+            timeoutBlock := nil.
         ].
     ].
 
+    "if we come here, we have accquired the semaphore"
     count := count - 1.
     count == 0 ifTrue:[
         lastOwnerID := Processor activeProcessId.
@@ -923,5 +898,5 @@
 !Semaphore class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.71 2003-10-28 21:16:45 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.72 2004-09-21 18:06:07 stefan Exp $'
 ! !