From bb31695fbfbf7c808dc3fd8c3cfc0b654ed15e5e Mon Sep 17 00:00:00 2001 From: emekoi Date: Mon, 26 Nov 2018 21:07:01 -0600 Subject: fixed mutex on windows --- std/mutex.zig | 54 +++++++++++++++++++++++++++++++++------------ std/os/windows/index.zig | 1 + std/os/windows/kernel32.zig | 24 +++++++++++++++----- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 9307637253..45336f353e 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -61,31 +61,57 @@ pub const Mutex = switch(builtin.os) { } }, builtin.Os.windows => struct { - lock: ?*windows.RTL_CRITICAL_SECTION, + + lock: ?windows.CRITICAL_SECTION, + init_once: windows.PINIT_ONCE, pub const Held = struct { mutex: *Mutex, pub fn release(self: Held) void { - windows.LeaveCriticalSection(self.mutex.lock); + if (self.mutex.lock) |*lock| { + windows.LeaveCriticalSection(lock); + } } }; pub fn init() Mutex { - var lock: ?*windows.RTL_CRITICAL_SECTION = null; - windows.InitializeCriticalSection(lock); - return Mutex { .lock = lock }; + return Mutex { + .lock = null, + .init_once = undefined, + }; + } + + extern fn initCriticalSection(InitOnce: *windows.PINIT_ONCE, Parameter: ?windows.PVOID, Context: ?*windows.PVOID) windows.BOOL { + if (Context) |ctx| { + var mutex = @ptrCast(*?windows.CRITICAL_SECTION, ctx); + if (mutex.* == null) { + var lock: windows.CRITICAL_SECTION = undefined; + windows.InitializeCriticalSection(&lock); + mutex.* = lock; + } + return windows.TRUE; + } + return windows.FALSE; } pub fn deinit(self: *Mutex) void { - if (self.lock != null) { - windows.DeleteCriticalSection(self.lock); - self.lock = null; + if (self.lock) |*lock| { + windows.DeleteCriticalSection(lock); } } pub fn acquire(self: *Mutex) Held { - windows.EnterCriticalSection(self.lock); + if (self.lock) |*lock| { + windows.EnterCriticalSection(lock); + } else { + if (windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, null, @ptrCast(?*windows.PVOID, self)) == windows.TRUE) { + windows.EnterCriticalSection(&self.lock.?); + } else { + @panic("unable to initialize Mutex"); + } + } + return Held { .mutex = self }; } }, @@ -116,7 +142,7 @@ pub const Mutex = switch(builtin.os) { }, }; -const Context = struct { +const TestContext = struct { mutex: *Mutex, data: i128, @@ -136,7 +162,7 @@ test "std.Mutex" { var mutex = Mutex.init(); defer mutex.deinit(); - var context = Context{ + var context = TestContext{ .mutex = &mutex, .data = 0, }; @@ -149,12 +175,12 @@ test "std.Mutex" { for (threads) |t| t.wait(); - std.debug.assertOrPanic(context.data == thread_count * Context.incr_count); + std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); } -fn worker(ctx: *Context) void { +fn worker(ctx: *TestContext) void { var i: usize = 0; - while (i != Context.incr_count) : (i += 1) { + while (i != TestContext.incr_count) : (i += 1) { const held = ctx.mutex.acquire(); defer held.release(); diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index 3d6ee67113..3f19905835 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -49,6 +49,7 @@ pub const UNICODE = false; pub const WCHAR = u16; pub const WORD = u16; pub const LARGE_INTEGER = i64; +pub const LONG = c_long; pub const TRUE = 1; pub const FALSE = 0; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index e34092ad51..07d6cd80a2 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -221,10 +221,10 @@ pub const FOREGROUND_GREEN = 2; pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; -pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; pub const LIST_ENTRY = extern struct { Flink: *LIST_ENTRY, @@ -245,9 +245,21 @@ pub const RTL_CRITICAL_SECTION_DEBUG = extern struct { pub const RTL_CRITICAL_SECTION = extern struct { DebugInfo: *RTL_CRITICAL_SECTION_DEBUG, - LockCount: i32, - RecursionCount: i32, + LockCount: LONG, + RecursionCount: LONG, OwningThread: HANDLE, LockSemaphore: HANDLE, SpinCount: ULONG_PTR, }; + +pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; + +pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *PINIT_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?*LPVOID) BOOL; + +pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *PINIT_ONCE, Parameter: ?PVOID, Context: ?*PVOID) BOOL; + +pub const RTL_RUN_ONCE = extern struct { + Ptr: PVOID, +}; + +pub const PINIT_ONCE = RTL_RUN_ONCE; -- cgit v1.2.3