-
Notifications
You must be signed in to change notification settings - Fork 2
fix: remove mutex/io dependency from the dsl #20
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,8 +67,8 @@ pub fn defaultFinalize(comptime T: type) napi.FinalizeCallback(T) { | |
| pub fn registerClass(comptime T: type, env: napi.Env, ctor: napi.Value) !void { | ||
| const State = state(T); | ||
|
|
||
| State.mutex.lock(); | ||
| defer State.mutex.unlock(); | ||
| State.lock(); | ||
| defer State.unlock(); | ||
|
|
||
| if (State.find(env.env) != null) return; | ||
|
|
||
|
|
@@ -113,8 +113,8 @@ pub fn materializeClassInstance(comptime T: type, env: napi.Env, instance: T, pr | |
| fn getConstructor(comptime T: type, env: napi.Env) !napi.Value { | ||
| const State = state(T); | ||
|
|
||
| State.mutex.lock(); | ||
| defer State.mutex.unlock(); | ||
| State.lock(); | ||
| defer State.unlock(); | ||
|
|
||
| const entry = State.find(env.env) orelse return error.ClassNotRegistered; | ||
| return try entry.ctor_ref.getValue(); | ||
|
|
@@ -147,7 +147,17 @@ fn state(comptime T: type) type { | |
| }; | ||
|
|
||
| var head: ?*Entry = null; | ||
| var mutex: std.Thread.Mutex = .{}; | ||
| var locked: std.atomic.Value(bool) = std.atomic.Value(bool).init(false); | ||
|
|
||
| fn lock() void { | ||
| while (locked.cmpxchgWeak(false, true, .acquire, .monotonic) != null) { | ||
| std.atomic.spinLoopHint(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can add
|
||
| } | ||
| } | ||
|
|
||
| fn unlock() void { | ||
| locked.store(false, .release); | ||
| } | ||
|
|
||
| fn find(env_ptr: napi.c.napi_env) ?*Entry { | ||
| var current = head; | ||
|
|
@@ -158,8 +168,8 @@ fn state(comptime T: type) type { | |
| } | ||
|
|
||
| fn cleanupHook(entry: *Entry) void { | ||
| mutex.lock(); | ||
| defer mutex.unlock(); | ||
| lock(); | ||
| defer unlock(); | ||
|
|
||
| var cursor = &head; | ||
| while (cursor.*) |current| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For someone curiosity how this code works, here is some explanation.
CPUs provide a single hardware instruction that does two things atomically (cannot be interrupted):
▎ "Read the value. If it equals X, replace it with Y. Tell me if it worked."
This is
cmpxchg— it's a single CPU instruction, not two separate operations. The CPU's cache coherency protocol guarantees that only one core can win the race.The signature is:
So as per call we instruct
lockedvalue isfalse, set it totrue- means mark the resource locked.lockedvalue is notfalse, keep trying in the loop.success_caseinstruct atomic state to beacquire, so no CPU instruction is allowed to re-ordered in memory.fail_caseinstruct atomic state to bemonotonic, that suggest to perform any atomic operation afterwards.