/usr/share/gnu-smalltalk/kernel/Semaphore.st is in gnu-smalltalk-common 3.2.5-1build2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | "======================================================================
|
| Semaphore Method Definitions
|
|
======================================================================"
"======================================================================
|
| Copyright 1988,92,94,95,99,2000,2001,2002,2008,2009
| Free Software Foundation, Inc.
| Written by Steve Byrne.
|
| This file is part of the GNU Smalltalk class library.
|
| The GNU Smalltalk class library is free software; you can redistribute it
| and/or modify it under the terms of the GNU Lesser General Public License
| as published by the Free Software Foundation; either version 2.1, or (at
| your option) any later version.
|
| The GNU Smalltalk class library is distributed in the hope that it will be
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
| General Public License for more details.
|
| You should have received a copy of the GNU Lesser General Public License
| along with the GNU Smalltalk class library; see the file COPYING.LIB.
| If not, write to the Free Software Foundation, 59 Temple Place - Suite
| 330, Boston, MA 02110-1301, USA.
|
======================================================================"
LinkedList subclass: Semaphore [
| signals name |
<category: 'Language-Processes'>
<comment: 'My instances represent counting semaphores. I provide methods for signalling
the semaphore''s availability, and methods for waiting for its availability.
I also provide some methods for implementing critical sections.'>
Semaphore class >> new [
"Answer a new semaphore"
<category: 'instance creation'>
^self basicNew initialize
]
Semaphore class >> forMutualExclusion [
"Answer a new semaphore with a signal on it. These semaphores are a useful
shortcut when you use semaphores as critical sections."
<category: 'instance creation'>
^(self new)
signal;
yourself
]
critical: aBlock [
"Wait for the receiver to be free, execute aBlock and signal the receiver
again. Return the result of evaluating aBlock."
"Look out for race conditions!"
<category: 'mutual exclusion'>
| ownedSem c |
^[
"With a little help from the VM we can easily ascertain
whether we did get a signal. It is still necessary to
trap process termination however, because if we did
simply `ownedSem := self wait' we might be terminated
after the wait has ended, and yet before the variable
is assigned. Pushing self and sending #wait is atomic
thanks to superoperators."
c := #(nil).
ownedSem := [c := thisContext. self wait]
on: ProcessBeingTerminated
do: [:ex | ownedSem := c at: 1. ex pass].
ownedSem == self ifTrue: [aBlock value]]
ensure: [ownedSem == self ifTrue: [self signal]]
]
name [
"Answer a user-friendly name for the receiver"
<category: 'accessing'>
^name
]
name: aString [
"Answer a user-friendly name for the receiver"
<category: 'accessing'>
name := aString
]
waitingProcesses [
"Answer an Array of processes currently waiting on the receiver."
<category: 'accessing'>
^self asArray
]
wouldBlock [
"Answer whether waiting on the receiver would suspend the current process."
<category: 'accessing'>
^signals <= 0
]
printOn: aStream [
"Print a human-readable represention of the receiver on aStream."
<category: 'printing'>
aStream
nextPutAll: self class name;
nextPutAll: '(%1: %<free|held>2, %3 %<available signals|waiting processes>2)'
%
{self name printString.
self signals > 0.
self signals abs}
]
initialize [
<category: 'private'>
signals := 0
]
signals [
"Answer the number of processes that can be accomodated or (if negative
the number of waiting processes."
"If <= 0 the value of signals does not have a relationship to the number
of waiting processes (currently it never goes at all below zero). So
- if 0 and 0 processes are waiting, the signal count is 0
- if 0 and k processes are waiting, the signal count is -k
- if >0, no processes must be waiting and the signal count is signals"
<category: 'private'>
^(signals max: 0) - self size
]
notify [
"Resume one of the processes that were waiting on the semaphore if
there were any. Do not leave a signal on the semaphore if no
process is waiting."
<category: 'builtins'>
<primitive: VMpr_Semaphore_notify>
^self primitiveFailed
]
notifyAll [
"Resume all the processes that were waiting on the semaphore if there
were any. Do not leave a signal on the semaphore if no process is
waiting."
<category: 'builtins'>
<primitive: VMpr_Semaphore_notifyAll>
^self primitiveFailed
]
signal [
"Signal the receiver, resuming a waiting process' if there is one"
<category: 'builtins'>
<primitive: VMpr_Semaphore_signal>
^self primitiveFailed
]
wait [
"Wait for the receiver to be signalled, suspending the executing process
if it is not yet. Return nil if the wait was interrupted, the
receiver otherwise."
<category: 'builtins'>
<primitive: VMpr_Semaphore_wait>
^self primitiveFailed
]
waitAfterSignalling: aSemaphore [
"Signal aSemaphore then, atomically, wait for the receiver to be
signalled, suspending the executing process if it is not yet. This
is needed to avoid race conditions when the #notify and #notifyAll
are used before waiting on receiver: otherwise, if a process sends
any of the two between the time aSemaphore is signaled and the time
the process starts waiting on the receiver, the notification is lost."
<category: 'builtins'>
<primitive: VMpr_Semaphore_waitAfterSignalling>
^self primitiveFailed
]
lock [
"Without putting the receiver to sleep, force processes that try to wait
on the semaphore to block. Answer whether this was the case even before."
<category: 'builtins'>
<primitive: VMpr_Semaphore_lock>
^self primitiveFailed
]
]
|