Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate unused and not-recommended Threads.Mutex #32875

Merged
merged 1 commit into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,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