Skip to content

Commit

Permalink
Fix nested callbacks deadlock
Browse files Browse the repository at this point in the history
  • Loading branch information
SavchenkoValeriy committed Aug 7, 2022
1 parent ccaaf46 commit 864eb4d
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 5 deletions.
12 changes: 7 additions & 5 deletions Source/Swift/Channel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ fileprivate struct CallbackStack {
return elements.count - 1
}

mutating func pop(at index: Index, with env: Environment) throws {
mutating func pop(at index: Index) -> Element? {
os_unfair_lock_lock(&lock)
defer { os_unfair_lock_unlock(&lock) }

guard let element = elements[index] else {
print("Tried to call already called element!")
return
return nil
}

try element.callback.call(env, with: element.args)

elements[index] = nil
if elements.allSatisfy({ $0 == nil }) {
elements.removeAll()
}

return element
}
}

Expand Down Expand Up @@ -105,7 +105,9 @@ public class Channel {
/// Call the callback stored under the given index.
private func call(_ index: CallbackStack.Index, with env: Environment) throws
{
try stack.pop(at: index, with: env)
if let element = stack.pop(at: index) {
try element.callback.call(env, with: element.args)
}
}

/// Register a callback to be called with the given arguments.
Expand Down
14 changes: 14 additions & 0 deletions Test/TestModule/Test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ public func Init(_ runtimePtr: RuntimePointer) -> Int32 {
})
}
}
try env.defun("swift-async-channel-with-result") {
(callback: PersistentEmacsValue) in
Task {
try await someAsyncTaskWithResult(completion: channel.callback(callback))
}
}
try env.defun("swift-nested-async-with-result") {
(callback: PersistentEmacsValue) in
Task {
try await someAsyncTaskWithResult(completion: channel.callback {
(_, x) in channel.callback(callback)(x)
})
}
}
try env.defun("swift-async-lisp-callback") {
(callback: PersistentEmacsValue) in
Task {
Expand Down
14 changes: 14 additions & 0 deletions Test/swift-module-test.el
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
;; -*- lexical-binding: t; -*-
(require 'ert-async)

(intern "swift-error")
Expand Down Expand Up @@ -99,3 +100,16 @@
(ert-deftest swift-module:check-alist-conversion ()
(let ((result (swift-alist '((10 . "a") (42 . "matters") (43 . "b")))))
(should (equal (length result) 1))))

(ert-deftest-async swift-module:check-async-nested-1 (done1 done2)
(swift-async-channel-with-result
(lambda (x)
(swift-async-channel-with-result
(lambda (y) (should (equal x y)) (funcall done1)))
(swift-async-channel done2))))

(ert-deftest-async swift-module:check-async-nested-2 (done1)
(swift-nested-async-with-result
(lambda (x)
(should (equal x 42))
(funcall done1))))

0 comments on commit 864eb4d

Please # to comment.