Semaphore.st
changeset 159 514c749165c3
parent 93 e31220cb391f
child 183 7899f380e77d
equal deleted inserted replaced
158:be947d4e7fb2 159:514c749165c3
     1 "
     1 "
     2  COPYRIGHT (c) 1993 by Claus Gittinger
     2  COPYRIGHT (c) 1993 by Claus Gittinger
     3               All Rights Reserved
     3 	      All Rights Reserved
     4 
     4 
     5  This software is furnished under a license and may be used
     5  This software is furnished under a license and may be used
     6  only in accordance with the terms of that license and with the
     6  only in accordance with the terms of that license and with the
     7  inclusion of the above copyright notice.   This software may not
     7  inclusion of the above copyright notice.   This software may not
     8  be provided or otherwise made available to, or used by, any
     8  be provided or otherwise made available to, or used by, any
     9  other person.  No title to or ownership of the software is
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 
    12 
    13 LinkedList subclass:#Semaphore
    13 LinkedList subclass:#Semaphore
    14          instanceVariableNames:'count waitingProcesses'
    14 	 instanceVariableNames:'count waitingProcesses'
    15 "/         instanceVariableNames:'count'
    15 "/         instanceVariableNames:'count'
    16          classVariableNames:''
    16 	 classVariableNames:''
    17          poolDictionaries:''
    17 	 poolDictionaries:''
    18          category:'Kernel-Processes'!
    18 	 category:'Kernel-Processes'!
    19 
    19 
    20 Semaphore comment:'
    20 Semaphore comment:'
    21 COPYRIGHT (c) 1993 by Claus Gittinger
    21 COPYRIGHT (c) 1993 by Claus Gittinger
    22               All Rights Reserved
    22 	      All Rights Reserved
    23 
    23 
    24 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.11 1994-08-05 00:59:40 claus Exp $
    24 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.12 1994-10-10 00:28:02 claus Exp $
    25 '!
    25 '!
    26 
    26 
    27 !Semaphore class methodsFor:'documentation'!
    27 !Semaphore class methodsFor:'documentation'!
    28 
    28 
    29 copyright
    29 copyright
    30 "
    30 "
    31  COPYRIGHT (c) 1993 by Claus Gittinger
    31  COPYRIGHT (c) 1993 by Claus Gittinger
    32               All Rights Reserved
    32 	      All Rights Reserved
    33 
    33 
    34  This software is furnished under a license and may be used
    34  This software is furnished under a license and may be used
    35  only in accordance with the terms of that license and with the
    35  only in accordance with the terms of that license and with the
    36  inclusion of the above copyright notice.   This software may not
    36  inclusion of the above copyright notice.   This software may not
    37  be provided or otherwise made available to, or used by, any
    37  be provided or otherwise made available to, or used by, any
    40 "
    40 "
    41 !
    41 !
    42 
    42 
    43 version
    43 version
    44 "
    44 "
    45 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.11 1994-08-05 00:59:40 claus Exp $
    45 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.12 1994-10-10 00:28:02 claus Exp $
    46 "
    46 "
    47 !
    47 !
    48 
    48 
    49 documentation
    49 documentation
    50 "
    50 "
    51     Semaphores are used to synchronize processes providing a nonBusy wait
    51     Semaphores are used to synchronize processes providing a nonBusy wait
    52     mechanism. A process can wait for the availability of some resource by
    52     mechanism. A process can wait for the availability of some resource by
    53     performing a Semaphore>>wait, which will suspend the process until the
    53     performing a Semaphore>>wait, which will suspend the process until the
    54     resource becomes available. Signalling is done by (another process performing) 
    54     resource becomes available. Signalling is done by (another process performing) 
    55     Semaphore>>signal.
    55     Semaphore>>signal.
    56     If the resource has been alrady available before the wait, no suspending is
    56     If the resource has been already available before the wait, no suspending is
    57     done, but the resource immediately allocated.
    57     done, but the resource immediately allocated.
    58     There are also semaphores for mutual access to a critical region
    58     There are also semaphores for mutual access to a critical region
    59     (Semaphore>>forMutualExclusion and Semaphore>>critical:).
    59     (Semaphore>>forMutualExclusion and Semaphore>>critical:).
    60 
    60 
       
    61     You can also attach semaphores to external events (such as I/O arrival or
       
    62     timer events. This is done by telling the Processor to signal the semaphore.
       
    63     See 'Processor>>signal:afterSeconds:', 'Processor>>signal:onInput:' etc.
       
    64 
    61     See examples in doc/coding.
    65     See examples in doc/coding.
    62 "
    66 "
    63 ! !
    67 ! !
    64 
    68 
    65 !Semaphore class methodsFor:'instance creation'!
    69 !Semaphore class methodsFor:'instance creation'!
    94 
    98 
    95 wait
    99 wait
    96     "wait for the semaphore"
   100     "wait for the semaphore"
    97 
   101 
    98     |current wasBlocked|
   102     |current wasBlocked|
       
   103 
       
   104     "
       
   105      this works only since interrupts are only serviced at 
       
   106      message send and method-return time ....
       
   107      If you add a message send into the ifTrue:-block, things will
       
   108      go mad ... (especially be careful when adding a debugPrint-here)
       
   109     "
       
   110     count ~~ 0 ifTrue:[
       
   111 	count := count - 1.
       
   112 	^ self
       
   113     ].
       
   114 
       
   115     wasBlocked := OperatingSystem blockInterrupts.
       
   116 
       
   117     current := Processor activeProcess.
       
   118     waitingProcesses isNil ifTrue:[
       
   119 	waitingProcesses := OrderedCollection with:current
       
   120     ] ifFalse:[
       
   121 	waitingProcesses add:current
       
   122     ].
       
   123 "/        self add:current.
    99 
   124 
   100     "
   125     "
   101      need a while-loop here, since more than one process may
   126      need a while-loop here, since more than one process may
   102      wait for it and another one may also wake up.
   127      wait for it and another one may also wake up.
   103      Thus, the count is not always non-zero after returning from
   128      Thus, the count is not always non-zero after returning from
   104      suspend.
   129      suspend.
   105     "
   130     "
   106 
   131     [count == 0] whileTrue:[
   107     "
   132 	"
   108      this works only due to interrupts being serviced at message send
   133 	 for some more descriptive info in processMonitor ...
   109      and method-return time only ....
   134 	 (notice that state could already be #ioWait or #timeWait)
       
   135 	"
       
   136 	current setStateTo:#wait if:#active.
       
   137 	Processor suspend:current
       
   138     ].
       
   139     count := count - 1.
       
   140     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   141 !
       
   142 
       
   143 waitWithTimeout:seconds
       
   144     "wait for the semaphore, but abort the wait after some time.
       
   145      return true if semaphore triggered normal, false if we return
       
   146      due to a timeout. With zero timeout, this can be used to poll
       
   147      a semaphore (which is not the intend of semaphores, though)."
       
   148 
       
   149     |current timeoutOccured wasBlocked unblock now endTime|
       
   150 
       
   151     "
       
   152      this works only since interrupts are only serviced at 
       
   153      message send and method-return time ....
       
   154      If you add a message send into the ifTrue:-block, things will
       
   155      go mad ... (especially be careful when adding a debugPrint-here)
   110     "
   156     "
   111     count ~~ 0 ifTrue:[
   157     count ~~ 0 ifTrue:[
   112 	count := count - 1.
   158 	count := count - 1.
   113 	^ self
   159 	^ true
       
   160     ].
       
   161 
       
   162     "
       
   163      with zero-timeout, this is a poll
       
   164     "
       
   165     seconds = 0 ifTrue:[
       
   166 	^ false
   114     ].
   167     ].
   115 
   168 
   116     wasBlocked := OperatingSystem blockInterrupts.
   169     wasBlocked := OperatingSystem blockInterrupts.
       
   170 
       
   171     "
       
   172      calculate the end-time
       
   173     "
       
   174     now := OperatingSystem getMillisecondTime.
       
   175     endTime := OperatingSystem millisecondTimeAdd:now and:(seconds * 1000).
       
   176 
       
   177     current := Processor activeProcess.
       
   178     waitingProcesses isNil ifTrue:[
       
   179 	waitingProcesses := OrderedCollection with:current
       
   180     ] ifFalse:[
       
   181 	waitingProcesses add:current
       
   182     ].
       
   183 "/    self add:current.
       
   184 
       
   185     unblock := [timeoutOccured := true. Processor resume:current].
       
   186     Processor addTimedBlock:unblock for:current atMilliseconds:endTime.
       
   187 
       
   188     "
       
   189      need a while-loop here, since more than one process may
       
   190      wait for it and another one may also wake up.
       
   191      Thus, the count is not always non-zero after returning from
       
   192      suspend.
       
   193     "
   117     [count == 0] whileTrue:[
   194     [count == 0] whileTrue:[
   118 "/        (count == 0) ifTrue:[
   195 	"
   119             current := Processor activeProcess.
   196 	 for some more descriptive info in processMonitor ...
   120             waitingProcesses isNil ifTrue:[
   197 	 (notice that state could already be #ioWait or #timeWait)
   121                 waitingProcesses := OrderedCollection with:current
   198 	"
   122             ] ifFalse:[
   199 	current setStateTo:#wait if:#active.
   123                 waitingProcesses add:current
   200 
   124             ].
   201 	timeoutOccured := false.
   125 "/            self add:current.
   202 	Processor suspend:current.
   126 	    "
   203 
   127 	     for some more info in processMonitor ...
   204 	timeoutOccured ifTrue:[
   128 	    "
   205 	    waitingProcesses remove:current ifAbsent:[].
   129             current state == #active ifTrue:[
   206 	    wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   130                 current state:#wait.
   207 	    ^ false
   131             ].
   208 	].
   132             Processor suspend:current
   209     ].
   133 "/        ].
   210     Processor removeTimedBlock:unblock.
   134     ].
       
   135     count := count - 1.
   211     count := count - 1.
   136     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   212     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   213     ^ true
   137 !
   214 !
   138 
   215 
   139 signalOnce
   216 signalOnce
   140     "wakeup waiters - but only once.
   217     "wakeup waiters - but only once.
   141      I.e. if the receiver has already been signalled, this
   218      I.e. if the semaphore has already been signalled, this
   142      is ignored."
   219      is ignored."
   143 
   220 
   144     |wasBlocked|
   221     |wasBlocked|
   145 
   222 
   146     wasBlocked := OperatingSystem blockInterrupts.
       
   147     count == 0 ifTrue:[
   223     count == 0 ifTrue:[
   148         self signal
   224 	wasBlocked := OperatingSystem blockInterrupts.
   149     ].
   225 	count == 0 ifTrue:[
   150     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   226 	    self signal
       
   227 	].
       
   228 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
       
   229     ]
   151 !
   230 !
   152 
   231 
   153 signal
   232 signal
   154     "waking up (first) waiter"
   233     "waking up (first) waiter"
   155 
   234 
   156     |p wasBlocked|
   235     |p wasBlocked|
   157 
   236 
   158     wasBlocked := OperatingSystem blockInterrupts.
   237     wasBlocked := OperatingSystem blockInterrupts.
   159     count := count + 1.
   238     count := count + 1.
   160     (waitingProcesses notNil and:[waitingProcesses notEmpty]) ifTrue:[
   239     (waitingProcesses notNil and:[waitingProcesses notEmpty]) ifTrue:[
   161         p := waitingProcesses removeFirst.
   240 	p := waitingProcesses removeFirst.
   162 "/    self isEmpty ifFalse:[
   241 "/    self isEmpty ifFalse:[
   163 "/        p := self removeFirst.
   242 "/        p := self removeFirst.
   164 
   243 
   165         wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   244 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   166         p resume.
   245 	p resume.
   167         ^ self
   246 	^ self
   168     ].
   247     ].
   169     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   248     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   170 !
   249 !
   171 
   250 
   172 critical:aBlock
   251 critical:aBlock