Lock: guarantee crash instead of undefined behaviour (#1131)
Motivation: NIO's Lock currently just deadlocks if a thread which already holds a lock tries to reacquire it. This however isn't even really defined behaviour. Modifications: Switch us to a guaranteed crash from a unguarnateed hang. Result: Easier to debug deadlocks with NIO's lock.
This commit is contained in:
parent
b6067bd531
commit
cee3db7072
|
@ -0,0 +1,47 @@
|
|||
#!/bin/bash
|
||||
##===----------------------------------------------------------------------===##
|
||||
##
|
||||
## This source file is part of the SwiftNIO open source project
|
||||
##
|
||||
## Copyright (c) 2019 Apple Inc. and the SwiftNIO project authors
|
||||
## Licensed under Apache License v2.0
|
||||
##
|
||||
## See LICENSE.txt for license information
|
||||
## See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
##
|
||||
## SPDX-License-Identifier: Apache-2.0
|
||||
##
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
set -eu
|
||||
|
||||
function make_package() {
|
||||
cat > "$tmpdir/syscallwrapper/Package.swift" <<"EOF"
|
||||
// swift-tools-version:5.0
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "syscallwrapper",
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "syscallwrapper",
|
||||
dependencies: ["CNIOLinux", "CNIODarwin"]),
|
||||
.target(
|
||||
name: "CNIOLinux",
|
||||
dependencies: []),
|
||||
.target(
|
||||
name: "CNIODarwin",
|
||||
dependencies: []),
|
||||
]
|
||||
)
|
||||
EOF
|
||||
cp "$here/../../Tests/NIOTests/SystemCallWrapperHelpers.swift" \
|
||||
"$here/../../Sources/NIO/System.swift" \
|
||||
"$here/../../Sources/NIO/IO.swift" \
|
||||
"$tmpdir/syscallwrapper/Sources/syscallwrapper"
|
||||
ln -s "$here/../../Sources/CNIOLinux" "$tmpdir/syscallwrapper/Sources"
|
||||
ln -s "$here/../../Sources/CNIODarwin" "$tmpdir/syscallwrapper/Sources"
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
##===----------------------------------------------------------------------===##
|
||||
##
|
||||
## This source file is part of the SwiftNIO open source project
|
||||
##
|
||||
## Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
|
||||
## Licensed under Apache License v2.0
|
||||
##
|
||||
## See LICENSE.txt for license information
|
||||
## See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
##
|
||||
## SPDX-License-Identifier: Apache-2.0
|
||||
##
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
set -eu
|
||||
|
||||
source defines.sh
|
||||
|
||||
swift_binary=swiftc
|
||||
here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
if [[ ! -z "${SWIFT_EXEC-}" ]]; then
|
||||
swift_binary="$(dirname "$SWIFT_EXEC")/swiftc"
|
||||
elif [[ "$(uname -s)" == "Linux" ]]; then
|
||||
swift_binary=$(which swiftc)
|
||||
fi
|
||||
|
||||
cp "$here/../../Sources/NIOConcurrencyHelpers/lock.swift" "$tmp"
|
||||
cat > "$tmp/main.swift" <<"EOF"
|
||||
let l = Lock()
|
||||
l.lock()
|
||||
l.lock()
|
||||
EOF
|
||||
|
||||
"$swift_binary" -o "$tmp/test" "$tmp/main.swift" "$tmp/lock.swift"
|
||||
if "$tmp/test"; then
|
||||
fail "should have crashed"
|
||||
else
|
||||
exit_code=$?
|
||||
assert_equal $(( 128 + 4 )) $exit_code # 4 == SIGILL
|
||||
fi
|
|
@ -28,13 +28,17 @@ public final class Lock {
|
|||
|
||||
/// Create a new lock.
|
||||
public init() {
|
||||
let err = pthread_mutex_init(self.mutex, nil)
|
||||
precondition(err == 0)
|
||||
var attr = pthread_mutexattr_t()
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, .init(PTHREAD_MUTEX_ERRORCHECK));
|
||||
|
||||
let err = pthread_mutex_init(self.mutex, &attr)
|
||||
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
|
||||
}
|
||||
|
||||
deinit {
|
||||
let err = pthread_mutex_destroy(self.mutex)
|
||||
precondition(err == 0)
|
||||
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
|
||||
mutex.deallocate()
|
||||
}
|
||||
|
||||
|
@ -44,7 +48,7 @@ public final class Lock {
|
|||
/// `unlock`, to simplify lock handling.
|
||||
public func lock() {
|
||||
let err = pthread_mutex_lock(self.mutex)
|
||||
precondition(err == 0)
|
||||
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
|
||||
}
|
||||
|
||||
/// Release the lock.
|
||||
|
@ -53,7 +57,7 @@ public final class Lock {
|
|||
/// `lock`, to simplify lock handling.
|
||||
public func unlock() {
|
||||
let err = pthread_mutex_unlock(self.mutex)
|
||||
precondition(err == 0)
|
||||
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,12 +102,12 @@ public final class ConditionLock<T: Equatable> {
|
|||
self._value = value
|
||||
self.mutex = Lock()
|
||||
let err = pthread_cond_init(self.cond, nil)
|
||||
precondition(err == 0)
|
||||
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
|
||||
}
|
||||
|
||||
deinit {
|
||||
let err = pthread_cond_destroy(self.cond)
|
||||
precondition(err == 0)
|
||||
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
|
||||
self.cond.deallocate()
|
||||
}
|
||||
|
||||
|
@ -141,7 +145,7 @@ public final class ConditionLock<T: Equatable> {
|
|||
break
|
||||
}
|
||||
let err = pthread_cond_wait(self.cond, self.mutex.mutex)
|
||||
precondition(err == 0, "pthread_cond_wait error \(err)")
|
||||
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +196,7 @@ public final class ConditionLock<T: Equatable> {
|
|||
public func unlock(withValue newValue: T) {
|
||||
self._value = newValue
|
||||
self.unlock()
|
||||
let r = pthread_cond_broadcast(self.cond)
|
||||
precondition(r == 0)
|
||||
let err = pthread_cond_broadcast(self.cond)
|
||||
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue