Skip to content

Commit

Permalink
remove unused and not-recommended Threads.Mutex (JuliaLang#32875)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson committed Aug 15, 2019
1 parent b451d55 commit 0eabe22
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 148 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Deprecated or removed
---------------------

* `@spawn expr` from the `Distributed` standard library should be replaced with `@spawnat :any expr` ([#32600]).
* `Threads.Mutex` and `Threads.RecursiveSpinLock` have been removed; use `ReentrantLock` (preferred) or
`Threads.SpinLock` instead ([#32875]).

External dependencies
---------------------
Expand Down
9 changes: 9 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,12 @@ MPFR.BigFloat(x::Real, prec::Int) = BigFloat(x; precision=prec)
MPFR.BigFloat(x::Real, prec::Int, rounding::RoundingMode) = BigFloat(x, rounding; precision=prec)

# END 1.0 deprecations

# BEGIN 1.3 deprecations

@eval Threads begin
Base.@deprecate_binding RecursiveSpinLock ReentrantLock
Base.@deprecate_binding Mutex ReentrantLock
end

# END 1.3 deprecations
144 changes: 1 addition & 143 deletions base/locks-mt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import .Base: unsafe_convert, lock, trylock, unlock, islocked, wait, notify, AbstractLock

export SpinLock, RecursiveSpinLock, Mutex
export SpinLock

# Important Note: these low-level primitives defined here
# are typically not for general usage
Expand All @@ -24,9 +24,6 @@ Each [`lock`](@ref) must be matched with an [`unlock`](@ref).
Test-and-test-and-set spin locks are quickest up to about 30ish
contending threads. If you have more contention than that, perhaps
a lock is the wrong way to synchronize.
See also [`Mutex`](@ref) for a more efficient version on one core or if the
lock may be held for a considerable length of time.
"""
struct SpinLock <: AbstractLock
handle::Atomic{Int}
Expand Down Expand Up @@ -63,142 +60,3 @@ end
function islocked(l::SpinLock)
return l.handle[] != 0
end

"""
RecursiveSpinLock()
Creates a reentrant lock.
The same thread can acquire the lock as many times as required.
Each [`lock`](@ref) must be matched with an [`unlock`](@ref).
See also [`SpinLock`](@ref) for a slightly faster version.
See also [`Mutex`](@ref) for a more efficient version on one core or if the lock
may be held for a considerable length of time.
"""
struct RecursiveSpinLock <: AbstractLock
ownertid::Atomic{Int16}
handle::Atomic{Int}
RecursiveSpinLock() = new(Atomic{Int16}(0), Atomic{Int}(0))
end

function lock(l::RecursiveSpinLock)
if l.ownertid[] == threadid()
l.handle[] += 1
return
end
while true
if l.handle[] == 0
if atomic_cas!(l.handle, 0, 1) == 0
l.ownertid[] = threadid()
return
end
end
ccall(:jl_cpu_pause, Cvoid, ())
# Temporary solution before we have gc transition support in codegen.
ccall(:jl_gc_safepoint, Cvoid, ())
end
end

function trylock(l::RecursiveSpinLock)
if l.ownertid[] == threadid()
l.handle[] += 1
return true
end
if l.handle[] == 0
if atomic_cas!(l.handle, 0, 1) == 0
l.ownertid[] = threadid()
return true
end
return false
end
return false
end

function unlock(l::RecursiveSpinLock)
@assert(l.ownertid[] == threadid(), "unlock from wrong thread")
@assert(l.handle[] != 0, "unlock count must match lock count")
if l.handle[] == 1
l.ownertid[] = 0
l.handle[] = 0
ccall(:jl_cpu_wake, Cvoid, ())
else
l.handle[] -= 1
end
return
end

function islocked(l::RecursiveSpinLock)
return l.handle[] != 0
end

##########################################
# System Mutexes
##########################################

# These are mutexes from libuv.
const UV_MUTEX_SIZE = ccall(:jl_sizeof_uv_mutex, Cint, ())

"""
Mutex()
These are standard system mutexes for locking critical sections of logic.
On Windows, this is a critical section object,
on pthreads, this is a `pthread_mutex_t`.
See also [`SpinLock`](@ref) for a lighter-weight lock.
"""
mutable struct Mutex <: AbstractLock
ownertid::Int16
handle::Ptr{Cvoid}
function Mutex()
m = new(zero(Int16), Libc.malloc(UV_MUTEX_SIZE))
ccall(:uv_mutex_init, Cvoid, (Ptr{Cvoid},), m.handle)
finalizer(mutex_destroy, m)
return m
end
end

unsafe_convert(::Type{Ptr{Cvoid}}, m::Mutex) = m.handle

function mutex_destroy(x::Mutex)
h = x.handle
if h != C_NULL
x.handle = C_NULL
ccall(:uv_mutex_destroy, Cvoid, (Ptr{Cvoid},), h)
Libc.free(h)
nothing
end
end

function lock(m::Mutex)
m.ownertid == threadid() && concurrency_violation() # deadlock
# Temporary solution before we have gc transition support in codegen.
# This could mess up gc state when we add codegen support.
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
ccall(:uv_mutex_lock, Cvoid, (Ptr{Cvoid},), m)
ccall(:jl_gc_safe_leave, Cvoid, (Int8,), gc_state)
m.ownertid = threadid()
return
end

function trylock(m::Mutex)
m.ownertid == threadid() && concurrency_violation() # deadlock
r = ccall(:uv_mutex_trylock, Cint, (Ptr{Cvoid},), m)
if r == 0
m.ownertid = threadid()
end
return r == 0
end

function unlock(m::Mutex)
m.ownertid == threadid() || concurrency_violation()
m.ownertid = 0
ccall(:uv_mutex_unlock, Cvoid, (Ptr{Cvoid},), m)
return
end

function islocked(m::Mutex)
return m.ownertid != 0
end
1 change: 0 additions & 1 deletion doc/src/base/multi-threading.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ Base.@threadcall
These building blocks are used to create the regular synchronization objects.

```@docs
Base.Threads.Mutex
Base.Threads.SpinLock
```
1 change: 0 additions & 1 deletion src/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ JL_DLLEXPORT uint32_t jl_getutf8(ios_t *s)
return wc;
}

JL_DLLEXPORT int jl_sizeof_uv_mutex(void) { return sizeof(uv_mutex_t); }
JL_DLLEXPORT int jl_sizeof_off_t(void) { return sizeof(off_t); }
#ifndef _OS_WINDOWS_
JL_DLLEXPORT int jl_sizeof_mode_t(void) { return sizeof(mode_t); }
Expand Down
4 changes: 1 addition & 3 deletions test/threads_exec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Test
using Base.Threads
using Base.Threads: SpinLock, Mutex
using Base.Threads: SpinLock

# threading constructs

Expand Down Expand Up @@ -110,7 +110,6 @@ end

@test threaded_add_locked(SpinLock, 0, 10000) == 10000
@test threaded_add_locked(ReentrantLock, 0, 10000) == 10000
@test threaded_add_locked(Mutex, 0, 10000) == 10000

# Check if the recursive lock can be locked and unlocked correctly.
let critical = ReentrantLock()
Expand Down Expand Up @@ -151,7 +150,6 @@ end

threaded_gc_locked(SpinLock)
threaded_gc_locked(Threads.ReentrantLock)
threaded_gc_locked(Mutex)

# Issue 14726
# Make sure that eval'ing in a different module doesn't mess up other threads
Expand Down

0 comments on commit 0eabe22

Please sign in to comment.