Skip to content

Commit

Permalink
Merge pull request #255 from swiftwasm/yt/tls-eventloop
Browse files Browse the repository at this point in the history
Allocate JavaScriptEventLoop per thread in multi-threaded environment
  • Loading branch information
kateinoigakukun committed Jun 27, 2024
2 parents 2bb0694 + eb47bcb commit 0d39aa7
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 8 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ jobs:
- { os: ubuntu-22.04, toolchain: wasm-5.10.0-RELEASE, wasi-backend: Node }

# Ensure that test succeeds with all toolchains and wasi backend combinations
- { os: ubuntu-20.04, toolchain: wasm-5.7.3-RELEASE, wasi-backend: Node }
- { os: ubuntu-20.04, toolchain: wasm-5.8.0-RELEASE, wasi-backend: Node }
- { os: ubuntu-20.04, toolchain: wasm-5.7.3-RELEASE, wasi-backend: MicroWASI }
- { os: ubuntu-20.04, toolchain: wasm-5.10.0-RELEASE, wasi-backend: Node }
- { os: ubuntu-20.04, toolchain: wasm-5.8.0-RELEASE, wasi-backend: MicroWASI }
- { os: ubuntu-20.04, toolchain: wasm-5.9.1-RELEASE, wasi-backend: MicroWASI }
- { os: ubuntu-20.04, toolchain: wasm-5.10.0-RELEASE, wasi-backend: MicroWASI }
- os: ubuntu-22.04
toolchain: DEVELOPMENT-SNAPSHOT-2024-05-01-a
swift-sdk:
Expand Down Expand Up @@ -76,8 +76,6 @@ jobs:
strategy:
matrix:
include:
- os: macos-12
xcode: Xcode_14.0
- os: macos-13
xcode: Xcode_14.3
- os: macos-14
Expand Down
27 changes: 24 additions & 3 deletions Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,28 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable {
}

/// A singleton instance of the Executor
public static let shared: JavaScriptEventLoop = {
public static var shared: JavaScriptEventLoop {
return _shared
}

#if compiler(>=6.0) && _runtime(_multithreaded)
// In multi-threaded environment, we have an event loop executor per
// thread (per Web Worker). A job enqueued in one thread should be
// executed in the same thread under this global executor.
private static var _shared: JavaScriptEventLoop {
if let tls = swjs_thread_local_event_loop {
let eventLoop = Unmanaged<JavaScriptEventLoop>.fromOpaque(tls).takeUnretainedValue()
return eventLoop
}
let eventLoop = create()
swjs_thread_local_event_loop = Unmanaged.passRetained(eventLoop).toOpaque()
return eventLoop
}
#else
private static let _shared: JavaScriptEventLoop = create()
#endif

private static func create() -> JavaScriptEventLoop {
let promise = JSPromise(resolver: { resolver -> Void in
resolver(.success(.undefined))
})
Expand All @@ -79,7 +100,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable {
}
)
return eventLoop
}()
}

private static var didInstallGlobalExecutor = false

Expand Down Expand Up @@ -124,7 +145,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable {
JavaScriptEventLoop.shared.unsafeEnqueue(job)
}
swift_task_enqueueMainExecutor_hook = unsafeBitCast(swift_task_enqueueMainExecutor_hook_impl, to: UnsafeMutableRawPointer?.self)

didInstallGlobalExecutor = true
}

Expand Down
11 changes: 10 additions & 1 deletion Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,16 @@ public class JSObject: Equatable {

/// A `JSObject` of the global scope object.
/// This allows access to the global properties and global names by accessing the `JSObject` returned.
public static let global = JSObject(id: _JS_Predef_Value_Global)
public static var global: JSObject { return _global }

// `JSObject` storage itself is immutable, and use of `JSObject.global` from other
// threads maintains the same semantics as `globalThis` in JavaScript.
#if compiler(>=5.10)
nonisolated(unsafe)
static let _global = JSObject(id: _JS_Predef_Value_Global)
#else
static let _global = JSObject(id: _JS_Predef_Value_Global)
#endif

deinit { swjs_release(id) }

Expand Down
3 changes: 3 additions & 0 deletions Sources/_CJavaScriptEventLoop/_CJavaScriptEventLoop.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "_CJavaScriptEventLoop.h"

_Thread_local void *swjs_thread_local_event_loop;
5 changes: 5 additions & 0 deletions Sources/_CJavaScriptEventLoop/include/_CJavaScriptEventLoop.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ typedef SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_override)(
SWIFT_EXPORT_FROM(swift_Concurrency)
extern void *_Nullable swift_task_asyncMainDrainQueue_hook;


/// MARK: - thread local storage

extern _Thread_local void * _Nullable swjs_thread_local_event_loop;

#endif

0 comments on commit 0d39aa7

Please sign in to comment.