Semaphore.st
changeset 699 12f456343eea
parent 560 ecb5857b60cc
child 752 0259dd855289
equal deleted inserted replaced
698:04533375e12c 699:12f456343eea
    12 
    12 
    13 Object subclass:#Semaphore
    13 Object subclass:#Semaphore
    14 	 instanceVariableNames:'count waitingProcesses'
    14 	 instanceVariableNames:'count waitingProcesses'
    15 	 classVariableNames:''
    15 	 classVariableNames:''
    16 	 poolDictionaries:''
    16 	 poolDictionaries:''
    17 	 category:'Kernel-Processes'!
    17 	 category:'Kernel-Processes'
       
    18 !
    18 
    19 
    19 !Semaphore class methodsFor:'documentation'!
    20 !Semaphore class methodsFor:'documentation'!
    20 
    21 
    21 copyright
    22 copyright
    22 "
    23 "
    28  inclusion of the above copyright notice.   This software may not
    29  inclusion of the above copyright notice.   This software may not
    29  be provided or otherwise made available to, or used by, any
    30  be provided or otherwise made available to, or used by, any
    30  other person.  No title to or ownership of the software is
    31  other person.  No title to or ownership of the software is
    31  hereby transferred.
    32  hereby transferred.
    32 "
    33 "
    33 !
       
    34 
       
    35 version
       
    36     ^ '$Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.23 1995-11-15 14:22:56 werner Exp $'
       
    37 !
    34 !
    38 
    35 
    39 documentation
    36 documentation
    40 "
    37 "
    41     Semaphores are used to synchronize processes providing a nonBusy wait
    38     Semaphores are used to synchronize processes providing a nonBusy wait
    57 "
    54 "
    58 ! !
    55 ! !
    59 
    56 
    60 !Semaphore class methodsFor:'instance creation'!
    57 !Semaphore class methodsFor:'instance creation'!
    61 
    58 
       
    59 forMutualExclusion
       
    60     "create & return a new semaphore which allows exactly one process to
       
    61      wait on it without blocking"
       
    62 
       
    63     ^ super new setCount:1
       
    64 !
       
    65 
    62 new
    66 new
    63     "create & return a new semaphore which blocks until a signal is sent"
    67     "create & return a new semaphore which blocks until a signal is sent"
    64 
    68 
    65     ^ super new setCount:0
    69     ^ super new setCount:0
    66 !
    70 !
    68 new:n
    72 new:n
    69     "create & return a new semaphore which allows n waits before
    73     "create & return a new semaphore which allows n waits before
    70      blocking"
    74      blocking"
    71 
    75 
    72     ^ super new setCount:n
    76     ^ super new setCount:n
    73 !
    77 ! !
    74 
    78 
    75 forMutualExclusion
    79 !Semaphore methodsFor:'printing & storing'!
    76     "create & return a new semaphore which allows exactly one process to
    80 
    77      wait on it without blocking"
    81 displayString
    78 
    82     ^ self class name , '(' , count printString , ')'
    79     ^ super new setCount:1
       
    80 ! !
    83 ! !
    81 
    84 
    82 !Semaphore methodsFor:'private accessing'!
    85 !Semaphore methodsFor:'private accessing'!
    83 
    86 
    84 setCount:n
    87 setCount:n
    93      if a wait was performed. False otherwise."
    96      if a wait was performed. False otherwise."
    94 
    97 
    95     ^ count == 0
    98     ^ count == 0
    96 ! !
    99 ! !
    97 
   100 
    98 !Semaphore methodsFor:'printing & storing'!
       
    99 
       
   100 displayString
       
   101     ^ self class name , '(' , count printString , ')'
       
   102 ! !
       
   103 
       
   104 !Semaphore methodsFor:'wait & signal'!
   101 !Semaphore methodsFor:'wait & signal'!
   105 
       
   106 wait
       
   107     "wait for the semaphore"
       
   108 
       
   109     |current wasBlocked|
       
   110 
       
   111     "
       
   112      this works only since interrupts are only serviced at 
       
   113      message send and method-return time ....
       
   114      If you add a message send into the ifTrue:-block, things will
       
   115      go mad ... (especially be careful when adding a debugPrint-here)
       
   116     "
       
   117     count ~~ 0 ifTrue:[
       
   118 	count := count - 1.
       
   119 	^ self
       
   120     ].
       
   121 
       
   122     current := Processor activeProcess.
       
   123 
       
   124     wasBlocked := OperatingSystem blockInterrupts.
       
   125     "
       
   126      need a while-loop here, since more than one process may
       
   127      wait for it and another one may also wake up.
       
   128      Thus, the count is not always non-zero after returning from
       
   129      suspend.
       
   130     "
       
   131     [count == 0] whileTrue:[
       
   132 	waitingProcesses add:current.
       
   133 	"
       
   134 	 for some more descriptive info in processMonitor ...
       
   135 	 (notice that state could already be #ioWait, #timeWait or anything else)
       
   136 	"
       
   137 	current setStateTo:#wait if:#active.
       
   138 	Processor suspend:current
       
   139     ].
       
   140     count := count - 1.
       
   141     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   142 !
       
   143 
       
   144 waitUncounted
       
   145     "wait for the semaphore; do not consume the resource
       
   146      (i.e. do not count down)"
       
   147 
       
   148     |current wasBlocked|
       
   149 
       
   150     "
       
   151      this works only since interrupts are only serviced at 
       
   152      message send and method-return time ....
       
   153      If you add a message send into the ifTrue:-block, things will
       
   154      go mad ... (especially be careful when adding a debugPrint-here)
       
   155     "
       
   156     count ~~ 0 ifTrue:[
       
   157 	^ self
       
   158     ].
       
   159 
       
   160     current := Processor activeProcess.
       
   161 
       
   162     wasBlocked := OperatingSystem blockInterrupts.
       
   163     "
       
   164      need a while-loop here, since more than one process may
       
   165      wait for it and another one may also wake up.
       
   166      Thus, the count is not always non-zero after returning from
       
   167      suspend.
       
   168     "
       
   169     [count == 0] whileTrue:[
       
   170 	waitingProcesses add:current.
       
   171 	"
       
   172 	 for some more descriptive info in processMonitor ...
       
   173 	 (notice that state could already be #ioWait, #timeWait or anything else)
       
   174 	"
       
   175 	current setStateTo:#wait if:#active.
       
   176 	Processor suspend:current
       
   177     ].
       
   178     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   179 !
       
   180 
       
   181 waitWithTimeout:seconds
       
   182     "wait for the semaphore, but abort the wait after some time.
       
   183      return true if semaphore triggered normal, false if we return
       
   184      due to a timeout. With zero timeout, this can be used to poll
       
   185      a semaphore (which is not the intend of semaphores, though)."
       
   186 
       
   187     |current timeoutOccured wasBlocked unblock now endTime|
       
   188 
       
   189     "
       
   190      this works only since interrupts are only serviced at 
       
   191      message send and method-return time ....
       
   192      If you add a message send into the ifTrue:-block, things will
       
   193      go mad ... (especially be careful when adding a debugPrint-here)
       
   194     "
       
   195     count ~~ 0 ifTrue:[
       
   196 	count := count - 1.
       
   197 	^ true
       
   198     ].
       
   199 
       
   200     "
       
   201      with zero-timeout, this is a poll
       
   202     "
       
   203     seconds = 0 ifTrue:[
       
   204 	^ false
       
   205     ].
       
   206 
       
   207     current := Processor activeProcess.
       
   208 
       
   209     wasBlocked := OperatingSystem blockInterrupts.
       
   210 
       
   211     "
       
   212      calculate the end-time
       
   213     "
       
   214     now := OperatingSystem getMillisecondTime.
       
   215     endTime := OperatingSystem millisecondTimeAdd:now and:(seconds * 1000).
       
   216 
       
   217     unblock := [timeoutOccured := true. Processor resume:current].
       
   218     Processor addTimedBlock:unblock for:current atMilliseconds:endTime.
       
   219 
       
   220     "
       
   221      need a while-loop here, since more than one process may
       
   222      wait for it and another one may also wake up.
       
   223      Thus, the count is not always non-zero after returning from
       
   224      suspend.
       
   225     "
       
   226     [count == 0] whileTrue:[
       
   227 	waitingProcesses add:current.
       
   228 
       
   229 	"
       
   230 	 for some more descriptive info in processMonitor ...
       
   231 	 (notice that state could already be #ioWait or #timeWait)
       
   232 	"
       
   233 	current setStateTo:#wait if:#active.
       
   234 
       
   235 	timeoutOccured := false.
       
   236 	Processor suspend:current.
       
   237 
       
   238 	timeoutOccured ifTrue:[
       
   239 	    waitingProcesses remove:current ifAbsent:[].
       
   240 	    wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   241 	    ^ false
       
   242 	].
       
   243     ].
       
   244     Processor removeTimedBlock:unblock.
       
   245     count := count - 1.
       
   246     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   247     ^ true
       
   248 !
       
   249 
       
   250 signalOnce
       
   251     "wakeup waiters - but only once.
       
   252      I.e. if the semaphore has already been signalled, this
       
   253      is ignored."
       
   254 
       
   255     |wasBlocked|
       
   256 
       
   257     count == 0 ifTrue:[
       
   258 	wasBlocked := OperatingSystem blockInterrupts.
       
   259 	count == 0 ifTrue:[
       
   260 	    self signal
       
   261 	].
       
   262 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   263     ]
       
   264 !
       
   265 
       
   266 signal
       
   267     "waking up (first) waiter"
       
   268 
       
   269     |p wasBlocked|
       
   270 
       
   271     wasBlocked := OperatingSystem blockInterrupts.
       
   272     count := count + 1.
       
   273     waitingProcesses notEmpty ifTrue:[
       
   274 	p := waitingProcesses removeFirst.
       
   275 	p resume.
       
   276     ].
       
   277     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   278 !
       
   279 
       
   280 signalIf
       
   281     "signal the semaphore, but only if being waited upon.
       
   282      This can be used for one-shot semaphores (i.e. not remembering
       
   283      previous signals)"
       
   284 
       
   285     |wasBlocked|
       
   286 
       
   287     waitingProcesses notEmpty ifTrue:[
       
   288 	wasBlocked := OperatingSystem blockInterrupts.
       
   289 	waitingProcesses notEmpty ifTrue:[
       
   290 	    self signal
       
   291 	].
       
   292 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   293     ]
       
   294 !
       
   295 
       
   296 signalForAll
       
   297     "signal the semaphore for all waiters.
       
   298      This can be used for process synchronization, if multiple processes are
       
   299      waiting for a common event."
       
   300 
       
   301     |wasBlocked|
       
   302 
       
   303     [waitingProcesses notEmpty] whileTrue:[
       
   304 	wasBlocked := OperatingSystem blockInterrupts.
       
   305 	waitingProcesses notEmpty ifTrue:[
       
   306 	    self signal
       
   307 	].
       
   308 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   309     ]
       
   310 !
       
   311 
   102 
   312 critical:aBlock
   103 critical:aBlock
   313     "evaluate aBlock as a critical region; the receiver must be
   104     "evaluate aBlock as a critical region; the receiver must be
   314      created using Semaphore>>forMutualExclusion"
   105      created using Semaphore>>forMutualExclusion"
   315 
   106 
   343 		(Delay forSeconds:0.1) wait.
   134 		(Delay forSeconds:0.1) wait.
   344 	    ]
   135 	    ]
   345 	]
   136 	]
   346      ] forkAt:4.
   137      ] forkAt:4.
   347     "
   138     "
   348 ! !
   139 !
       
   140 
       
   141 signal
       
   142     "waking up (first) waiter"
       
   143 
       
   144     |p wasBlocked|
       
   145 
       
   146     wasBlocked := OperatingSystem blockInterrupts.
       
   147     count := count + 1.
       
   148     waitingProcesses notEmpty ifTrue:[
       
   149 	p := waitingProcesses removeFirst.
       
   150 	p resume.
       
   151     ].
       
   152     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   153 !
       
   154 
       
   155 signalForAll
       
   156     "signal the semaphore for all waiters.
       
   157      This can be used for process synchronization, if multiple processes are
       
   158      waiting for a common event."
       
   159 
       
   160     |wasBlocked|
       
   161 
       
   162     [waitingProcesses notEmpty] whileTrue:[
       
   163 	wasBlocked := OperatingSystem blockInterrupts.
       
   164 	waitingProcesses notEmpty ifTrue:[
       
   165 	    self signal
       
   166 	].
       
   167 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   168     ]
       
   169 !
       
   170 
       
   171 signalIf
       
   172     "signal the semaphore, but only if being waited upon.
       
   173      This can be used for one-shot semaphores (i.e. not remembering
       
   174      previous signals)"
       
   175 
       
   176     |wasBlocked|
       
   177 
       
   178     waitingProcesses notEmpty ifTrue:[
       
   179 	wasBlocked := OperatingSystem blockInterrupts.
       
   180 	waitingProcesses notEmpty ifTrue:[
       
   181 	    self signal
       
   182 	].
       
   183 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   184     ]
       
   185 !
       
   186 
       
   187 signalOnce
       
   188     "wakeup waiters - but only once.
       
   189      I.e. if the semaphore has already been signalled, this
       
   190      is ignored."
       
   191 
       
   192     |wasBlocked|
       
   193 
       
   194     count == 0 ifTrue:[
       
   195 	wasBlocked := OperatingSystem blockInterrupts.
       
   196 	count == 0 ifTrue:[
       
   197 	    self signal
       
   198 	].
       
   199 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   200     ]
       
   201 !
       
   202 
       
   203 wait
       
   204     "wait for the semaphore"
       
   205 
       
   206     |current wasBlocked|
       
   207 
       
   208     "
       
   209      this works only since interrupts are only serviced at 
       
   210      message send and method-return time ....
       
   211      If you add a message send into the ifTrue:-block, things will
       
   212      go mad ... (especially be careful when adding a debugPrint-here)
       
   213     "
       
   214     count ~~ 0 ifTrue:[
       
   215 	count := count - 1.
       
   216 	^ self
       
   217     ].
       
   218 
       
   219     current := Processor activeProcess.
       
   220 
       
   221     wasBlocked := OperatingSystem blockInterrupts.
       
   222     "
       
   223      need a while-loop here, since more than one process may
       
   224      wait for it and another one may also wake up.
       
   225      Thus, the count is not always non-zero after returning from
       
   226      suspend.
       
   227     "
       
   228     [count == 0] whileTrue:[
       
   229 	waitingProcesses add:current.
       
   230 	"
       
   231 	 for some more descriptive info in processMonitor ...
       
   232 	 (notice that state could already be #ioWait, #timeWait or anything else)
       
   233 	"
       
   234 	current setStateTo:#wait if:#active.
       
   235 	Processor suspend:current
       
   236     ].
       
   237     count := count - 1.
       
   238     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   239 !
       
   240 
       
   241 waitUncounted
       
   242     "wait for the semaphore; do not consume the resource
       
   243      (i.e. do not count down)"
       
   244 
       
   245     |current wasBlocked|
       
   246 
       
   247     "
       
   248      this works only since interrupts are only serviced at 
       
   249      message send and method-return time ....
       
   250      If you add a message send into the ifTrue:-block, things will
       
   251      go mad ... (especially be careful when adding a debugPrint-here)
       
   252     "
       
   253     count ~~ 0 ifTrue:[
       
   254 	^ self
       
   255     ].
       
   256 
       
   257     current := Processor activeProcess.
       
   258 
       
   259     wasBlocked := OperatingSystem blockInterrupts.
       
   260     "
       
   261      need a while-loop here, since more than one process may
       
   262      wait for it and another one may also wake up.
       
   263      Thus, the count is not always non-zero after returning from
       
   264      suspend.
       
   265     "
       
   266     [count == 0] whileTrue:[
       
   267 	waitingProcesses add:current.
       
   268 	"
       
   269 	 for some more descriptive info in processMonitor ...
       
   270 	 (notice that state could already be #ioWait, #timeWait or anything else)
       
   271 	"
       
   272 	current setStateTo:#wait if:#active.
       
   273 	Processor suspend:current
       
   274     ].
       
   275     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   276 !
       
   277 
       
   278 waitWithTimeout:seconds
       
   279     "wait for the semaphore, but abort the wait after some time.
       
   280      return true if semaphore triggered normal, false if we return
       
   281      due to a timeout. With zero timeout, this can be used to poll
       
   282      a semaphore (which is not the intend of semaphores, though)."
       
   283 
       
   284     |current timeoutOccured wasBlocked unblock now endTime|
       
   285 
       
   286     "
       
   287      this works only since interrupts are only serviced at 
       
   288      message send and method-return time ....
       
   289      If you add a message send into the ifTrue:-block, things will
       
   290      go mad ... (especially be careful when adding a debugPrint-here)
       
   291     "
       
   292     count ~~ 0 ifTrue:[
       
   293 	count := count - 1.
       
   294 	^ true
       
   295     ].
       
   296 
       
   297     "
       
   298      with zero-timeout, this is a poll
       
   299     "
       
   300     seconds = 0 ifTrue:[
       
   301 	^ false
       
   302     ].
       
   303 
       
   304     current := Processor activeProcess.
       
   305 
       
   306     wasBlocked := OperatingSystem blockInterrupts.
       
   307 
       
   308     "
       
   309      calculate the end-time
       
   310     "
       
   311     now := OperatingSystem getMillisecondTime.
       
   312     endTime := OperatingSystem millisecondTimeAdd:now and:(seconds * 1000).
       
   313 
       
   314     unblock := [timeoutOccured := true. Processor resume:current].
       
   315     Processor addTimedBlock:unblock for:current atMilliseconds:endTime.
       
   316 
       
   317     "
       
   318      need a while-loop here, since more than one process may
       
   319      wait for it and another one may also wake up.
       
   320      Thus, the count is not always non-zero after returning from
       
   321      suspend.
       
   322     "
       
   323     [count == 0] whileTrue:[
       
   324 	waitingProcesses add:current.
       
   325 
       
   326 	"
       
   327 	 for some more descriptive info in processMonitor ...
       
   328 	 (notice that state could already be #ioWait or #timeWait)
       
   329 	"
       
   330 	current setStateTo:#wait if:#active.
       
   331 
       
   332 	timeoutOccured := false.
       
   333 	Processor suspend:current.
       
   334 
       
   335 	timeoutOccured ifTrue:[
       
   336 	    waitingProcesses remove:current ifAbsent:[].
       
   337 	    wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   338 	    ^ false
       
   339 	].
       
   340     ].
       
   341     Processor removeTimedBlock:unblock.
       
   342     count := count - 1.
       
   343     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   344     ^ true
       
   345 ! !
       
   346 
       
   347 !Semaphore class methodsFor:'documentation'!
       
   348 
       
   349 version
       
   350     ^ '$Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.24 1995-12-07 21:30:36 cg Exp $'
       
   351 ! !