Commit bfc1772d8e

Andrew Kelley <andrew@ziglang.org>
2019-02-01 18:22:21
fixups
1 parent 8d3eb25
std/fmt/index.zig
@@ -982,13 +982,11 @@ test "fmt.format" {
         context = BufPrintContext{ .remaining = buf1[0..] };
         try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
         res = buf1[0 .. buf1.len - context.remaining.len];
-        debug.warn("{}\n", res);
         assert(mem.eql(u8, res, "a"));
 
         context = BufPrintContext{ .remaining = buf1[0..] };
         try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
         res = buf1[0 .. buf1.len - context.remaining.len];
-        debug.warn("{}\n", res);
         assert(mem.eql(u8, res, "1100"));
     }
     {
std/os/windows/kernel32.zig
@@ -253,15 +253,17 @@ pub const RTL_CRITICAL_SECTION = extern struct {
 };
 
 pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
+pub const INIT_ONCE = RTL_RUN_ONCE;
+pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
 
-pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *RTL_RUN_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?LPVOID) BOOL;
+pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;
 
-pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *RTL_RUN_ONCE, Parameter: ?PVOID, Context: ?PVOID) BOOL;
+pub const INIT_ONCE_FN = extern fn(InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
 
 pub const RTL_RUN_ONCE = extern struct {
-    Ptr: ?PVOID,
+    Ptr: ?*c_void,
 };
 
-pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE {
-  .Ptr = null,
-};
\ No newline at end of file
+pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE {
+    .Ptr = null,
+};
std/index.zig
@@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
 pub const HashMap = @import("hash_map.zig").HashMap;
 pub const LinkedList = @import("linked_list.zig").LinkedList;
 pub const Mutex = @import("mutex.zig").Mutex;
+pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
 pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
 pub const SpinLock = @import("spinlock.zig").SpinLock;
 
@@ -55,6 +56,7 @@ test "std" {
     _ = @import("hash_map.zig");
     _ = @import("linked_list.zig");
     _ = @import("mutex.zig");
+    _ = @import("statically_initialized_mutex.zig");
     _ = @import("segmented_list.zig");
     _ = @import("spinlock.zig");
     
std/mutex.zig
@@ -9,6 +9,9 @@ const windows = std.os.windows;
 
 /// Lock may be held only once. If the same thread
 /// tries to acquire the same mutex twice, it deadlocks.
+/// This type must be initialized at runtime, and then deinitialized when no
+/// longer needed, to free resources.
+/// If you need static initialization, use std.StaticallyInitializedMutex.
 /// The Linux implementation is based on mutex3 from
 /// https://www.akkadia.org/drepper/futex.pdf
 pub const Mutex = switch(builtin.os) {
@@ -60,57 +63,15 @@ pub const Mutex = switch(builtin.os) {
             return Held { .mutex = self };
         }
     },
-    builtin.Os.windows => struct {
-
-        lock: windows.CRITICAL_SECTION,
-        init_once: windows.RTL_RUN_ONCE,
-
-        pub const Held = struct {
-            mutex: *Mutex,
-
-            pub fn release(self: Held) void {
-                windows.LeaveCriticalSection(&self.mutex.lock);
-            }
-        };
-
-        pub fn init() Mutex {
-            return Mutex {
-                .lock = undefined,
-                .init_once = windows.INIT_ONCE_STATIC_INIT,
-            };
-        }
-
-        extern fn initCriticalSection(
-            InitOnce: *windows.RTL_RUN_ONCE,
-            Parameter: ?windows.PVOID,
-            Context: ?windows.PVOID
-        ) windows.BOOL {
-            var lock = @ptrCast(
-                *windows.CRITICAL_SECTION,
-                @alignCast(@alignOf(*windows.CRITICAL_SECTION), Context.?)
-            );
-            windows.InitializeCriticalSection(lock);
-            return windows.TRUE;
-        }
-
-        pub fn deinit(self: *Mutex) void {
-            windows.DeleteCriticalSection(&self.lock);
-        }
-
-        pub fn acquire(self: *Mutex) Held {
-            if (windows.InitOnceExecuteOnce(
-                &self.init_once,
-                initCriticalSection,
-                null, @ptrCast(?windows.PVOID, self)
-            ) == windows.FALSE) {
-                unreachable;
-            }
-            windows.EnterCriticalSection(&self.lock);
-            return Held { .mutex = self };
-        }
-    },
+    // TODO once https://github.com/ziglang/zig/issues/287 (copy elision) is solved, we can make a
+    // better implementation of this. The problem is we need the init() function to have access to
+    // the address of the CRITICAL_SECTION, and then have it not move.
+    builtin.Os.windows => std.StaticallyInitializedMutex,
     else => struct {
-        /// TODO better implementation than spin lock
+        /// TODO better implementation than spin lock.
+        /// When changing this, one must also change the corresponding
+        /// std.StaticallyInitializedMutex code, since it aliases this type,
+        /// under the assumption that it works both statically and at runtime.
         lock: SpinLock,
 
         pub const Held = struct {
std/statically_initialized_mutex.zig
@@ -0,0 +1,105 @@
+const std = @import("index.zig");
+const builtin = @import("builtin");
+const AtomicOrder = builtin.AtomicOrder;
+const AtomicRmwOp = builtin.AtomicRmwOp;
+const assert = std.debug.assert;
+const windows = std.os.windows;
+
+/// Lock may be held only once. If the same thread
+/// tries to acquire the same mutex twice, it deadlocks.
+/// This type is intended to be initialized statically. If you don't
+/// require static initialization, use std.Mutex.
+/// On Windows, this mutex allocates resources when it is
+/// first used, and the resources cannot be freed.
+/// On Linux, this is an alias of std.Mutex.
+pub const StaticallyInitializedMutex = switch(builtin.os) {
+    builtin.Os.linux => std.Mutex,
+    builtin.Os.windows => struct {
+        lock: windows.CRITICAL_SECTION,
+        init_once: windows.RTL_RUN_ONCE,
+
+        pub const Held = struct {
+            mutex: *StaticallyInitializedMutex,
+
+            pub fn release(self: Held) void {
+                windows.LeaveCriticalSection(&self.mutex.lock);
+            }
+        };
+
+        pub fn init() StaticallyInitializedMutex {
+            return StaticallyInitializedMutex {
+                .lock = undefined,
+                .init_once = windows.INIT_ONCE_STATIC_INIT,
+            };
+        }
+
+        extern fn initCriticalSection(
+            InitOnce: *windows.RTL_RUN_ONCE,
+            Parameter: ?*c_void,
+            Context: ?*c_void,
+        ) windows.BOOL {
+            const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter));
+            windows.InitializeCriticalSection(lock);
+            return windows.TRUE;
+        }
+
+        /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better
+        /// implementation of a runtime initialized mutex, remove this function.
+        pub fn deinit(self: *StaticallyInitializedMutex) void {
+            assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
+            windows.DeleteCriticalSection(&self.lock);
+        }
+
+        pub fn acquire(self: *StaticallyInitializedMutex) Held {
+            assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
+            windows.EnterCriticalSection(&self.lock);
+            return Held { .mutex = self };
+        }
+    },
+    else => std.Mutex,
+};
+
+test "std.StaticallyInitializedMutex" {
+    const TestContext = struct {
+        data: i128,
+
+        const TestContext = @This();
+        const incr_count = 10000;
+
+        var mutex = StaticallyInitializedMutex.init();
+
+        fn worker(ctx: *TestContext) void {
+            var i: usize = 0;
+            while (i != TestContext.incr_count) : (i += 1) {
+                const held = mutex.acquire();
+                defer held.release();
+
+                ctx.data += 1;
+            }
+        }
+    };
+
+    var direct_allocator = std.heap.DirectAllocator.init();
+    defer direct_allocator.deinit();
+
+    var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
+    defer direct_allocator.allocator.free(plenty_of_memory);
+
+    var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
+    var a = &fixed_buffer_allocator.allocator;
+
+
+    var context = TestContext{
+        .data = 0,
+    };
+
+    const thread_count = 10;
+    var threads: [thread_count]*std.os.Thread = undefined;
+    for (threads) |*t| {
+        t.* = try std.os.spawnThread(&context, TestContext.worker);
+    }
+    for (threads) |t|
+        t.wait();
+
+    std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count);
+}
CMakeLists.txt
@@ -454,10 +454,10 @@ set(ZIG_STD_FILES
     "crypto/hmac.zig"
     "crypto/index.zig"
     "crypto/md5.zig"
+    "crypto/poly1305.zig"
     "crypto/sha1.zig"
     "crypto/sha2.zig"
     "crypto/sha3.zig"
-    "crypto/poly1305.zig"
     "crypto/x25519.zig"
     "cstr.zig"
     "debug/failing_allocator.zig"
@@ -566,9 +566,9 @@ set(ZIG_STD_FILES
     "math/tan.zig"
     "math/tanh.zig"
     "math/trunc.zig"
+    "mem.zig"
     "meta/index.zig"
     "meta/trait.zig"
-    "mem.zig"
     "mutex.zig"
     "net.zig"
     "os/child_process.zig"
@@ -576,16 +576,16 @@ set(ZIG_STD_FILES
     "os/darwin/errno.zig"
     "os/epoch.zig"
     "os/file.zig"
+    "os/freebsd/errno.zig"
+    "os/freebsd/index.zig"
     "os/get_app_data_dir.zig"
     "os/get_user_id.zig"
     "os/index.zig"
+    "os/linux/arm64.zig"
     "os/linux/errno.zig"
     "os/linux/index.zig"
     "os/linux/vdso.zig"
     "os/linux/x86_64.zig"
-    "os/linux/arm64.zig"
-    "os/freebsd/errno.zig"
-    "os/freebsd/index.zig"
     "os/path.zig"
     "os/time.zig"
     "os/uefi.zig"
@@ -612,6 +612,16 @@ set(ZIG_STD_FILES
     "special/compiler_rt/comparetf2.zig"
     "special/compiler_rt/divti3.zig"
     "special/compiler_rt/extendXfYf2.zig"
+    "special/compiler_rt/fixdfdi.zig"
+    "special/compiler_rt/fixdfsi.zig"
+    "special/compiler_rt/fixdfti.zig"
+    "special/compiler_rt/fixint.zig"
+    "special/compiler_rt/fixsfdi.zig"
+    "special/compiler_rt/fixsfsi.zig"
+    "special/compiler_rt/fixsfti.zig"
+    "special/compiler_rt/fixtfdi.zig"
+    "special/compiler_rt/fixtfsi.zig"
+    "special/compiler_rt/fixtfti.zig"
     "special/compiler_rt/fixuint.zig"
     "special/compiler_rt/fixunsdfdi.zig"
     "special/compiler_rt/fixunsdfsi.zig"
@@ -622,16 +632,6 @@ set(ZIG_STD_FILES
     "special/compiler_rt/fixunstfdi.zig"
     "special/compiler_rt/fixunstfsi.zig"
     "special/compiler_rt/fixunstfti.zig"
-    "special/compiler_rt/fixint.zig"
-    "special/compiler_rt/fixdfdi.zig"
-    "special/compiler_rt/fixdfsi.zig"
-    "special/compiler_rt/fixdfti.zig"
-    "special/compiler_rt/fixsfdi.zig"
-    "special/compiler_rt/fixsfsi.zig"
-    "special/compiler_rt/fixsfti.zig"
-    "special/compiler_rt/fixtfdi.zig"
-    "special/compiler_rt/fixtfsi.zig"
-    "special/compiler_rt/fixtfti.zig"
     "special/compiler_rt/floattidf.zig"
     "special/compiler_rt/floattisf.zig"
     "special/compiler_rt/floattitf.zig"
@@ -656,6 +656,7 @@ set(ZIG_STD_FILES
     "special/panic.zig"
     "special/test_runner.zig"
     "spinlock.zig"
+    "statically_initialized_mutex.zig"
     "unicode.zig"
     "zig/ast.zig"
     "zig/index.zig"