2
2
3
3
import . Base: unsafe_convert, lock, trylock, unlock, islocked, wait, notify, AbstractLock
4
4
5
- export SpinLock, RecursiveSpinLock, Mutex
5
+ export SpinLock
6
6
7
7
# Important Note: these low-level primitives defined here
8
8
# are typically not for general usage
@@ -24,9 +24,6 @@ Each [`lock`](@ref) must be matched with an [`unlock`](@ref).
24
24
Test-and-test-and-set spin locks are quickest up to about 30ish
25
25
contending threads. If you have more contention than that, perhaps
26
26
a lock is the wrong way to synchronize.
27
-
28
- See also [`Mutex`](@ref) for a more efficient version on one core or if the
29
- lock may be held for a considerable length of time.
30
27
"""
31
28
struct SpinLock <: AbstractLock
32
29
handle:: Atomic{Int}
63
60
function islocked (l:: SpinLock )
64
61
return l. handle[] != 0
65
62
end
66
-
67
- """
68
- RecursiveSpinLock()
69
-
70
- Creates a reentrant lock.
71
- The same thread can acquire the lock as many times as required.
72
- Each [`lock`](@ref) must be matched with an [`unlock`](@ref).
73
-
74
- See also [`SpinLock`](@ref) for a slightly faster version.
75
-
76
- See also [`Mutex`](@ref) for a more efficient version on one core or if the lock
77
- may be held for a considerable length of time.
78
- """
79
- struct RecursiveSpinLock <: AbstractLock
80
- ownertid:: Atomic{Int16}
81
- handle:: Atomic{Int}
82
- RecursiveSpinLock () = new (Atomic {Int16} (0 ), Atomic {Int} (0 ))
83
- end
84
-
85
- function lock (l:: RecursiveSpinLock )
86
- if l. ownertid[] == threadid ()
87
- l. handle[] += 1
88
- return
89
- end
90
- while true
91
- if l. handle[] == 0
92
- if atomic_cas! (l. handle, 0 , 1 ) == 0
93
- l. ownertid[] = threadid ()
94
- return
95
- end
96
- end
97
- ccall (:jl_cpu_pause , Cvoid, ())
98
- # Temporary solution before we have gc transition support in codegen.
99
- ccall (:jl_gc_safepoint , Cvoid, ())
100
- end
101
- end
102
-
103
- function trylock (l:: RecursiveSpinLock )
104
- if l. ownertid[] == threadid ()
105
- l. handle[] += 1
106
- return true
107
- end
108
- if l. handle[] == 0
109
- if atomic_cas! (l. handle, 0 , 1 ) == 0
110
- l. ownertid[] = threadid ()
111
- return true
112
- end
113
- return false
114
- end
115
- return false
116
- end
117
-
118
- function unlock (l:: RecursiveSpinLock )
119
- @assert (l. ownertid[] == threadid (), " unlock from wrong thread" )
120
- @assert (l. handle[] != 0 , " unlock count must match lock count" )
121
- if l. handle[] == 1
122
- l. ownertid[] = 0
123
- l. handle[] = 0
124
- ccall (:jl_cpu_wake , Cvoid, ())
125
- else
126
- l. handle[] -= 1
127
- end
128
- return
129
- end
130
-
131
- function islocked (l:: RecursiveSpinLock )
132
- return l. handle[] != 0
133
- end
134
-
135
- # #########################################
136
- # System Mutexes
137
- # #########################################
138
-
139
- # These are mutexes from libuv.
140
- const UV_MUTEX_SIZE = ccall (:jl_sizeof_uv_mutex , Cint, ())
141
-
142
- """
143
- Mutex()
144
-
145
- These are standard system mutexes for locking critical sections of logic.
146
-
147
- On Windows, this is a critical section object,
148
- on pthreads, this is a `pthread_mutex_t`.
149
-
150
- See also [`SpinLock`](@ref) for a lighter-weight lock.
151
- """
152
- mutable struct Mutex <: AbstractLock
153
- ownertid:: Int16
154
- handle:: Ptr{Cvoid}
155
- function Mutex ()
156
- m = new (zero (Int16), Libc. malloc (UV_MUTEX_SIZE))
157
- ccall (:uv_mutex_init , Cvoid, (Ptr{Cvoid},), m. handle)
158
- finalizer (mutex_destroy, m)
159
- return m
160
- end
161
- end
162
-
163
- unsafe_convert (:: Type{Ptr{Cvoid}} , m:: Mutex ) = m. handle
164
-
165
- function mutex_destroy (x:: Mutex )
166
- h = x. handle
167
- if h != C_NULL
168
- x. handle = C_NULL
169
- ccall (:uv_mutex_destroy , Cvoid, (Ptr{Cvoid},), h)
170
- Libc. free (h)
171
- nothing
172
- end
173
- end
174
-
175
- function lock (m:: Mutex )
176
- m. ownertid == threadid () && concurrency_violation () # deadlock
177
- # Temporary solution before we have gc transition support in codegen.
178
- # This could mess up gc state when we add codegen support.
179
- gc_state = ccall (:jl_gc_safe_enter , Int8, ())
180
- ccall (:uv_mutex_lock , Cvoid, (Ptr{Cvoid},), m)
181
- ccall (:jl_gc_safe_leave , Cvoid, (Int8,), gc_state)
182
- m. ownertid = threadid ()
183
- return
184
- end
185
-
186
- function trylock (m:: Mutex )
187
- m. ownertid == threadid () && concurrency_violation () # deadlock
188
- r = ccall (:uv_mutex_trylock , Cint, (Ptr{Cvoid},), m)
189
- if r == 0
190
- m. ownertid = threadid ()
191
- end
192
- return r == 0
193
- end
194
-
195
- function unlock (m:: Mutex )
196
- m. ownertid == threadid () || concurrency_violation ()
197
- m. ownertid = 0
198
- ccall (:uv_mutex_unlock , Cvoid, (Ptr{Cvoid},), m)
199
- return
200
- end
201
-
202
- function islocked (m:: Mutex )
203
- return m. ownertid != 0
204
- end
0 commit comments