From 4ac36d094c06b04c1c71d972d3f3e1187bccea95 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 27 Apr 2018 19:27:58 -0400 Subject: add std.atomic.Stack and std.atomic.Queue --- std/atomic/queue.zig | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 std/atomic/queue.zig (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig new file mode 100644 index 0000000000..54981d4a61 --- /dev/null +++ b/std/atomic/queue.zig @@ -0,0 +1,37 @@ +/// Many reader, many writer, non-allocating, thread-safe, lock-free +pub fn Queue(comptime T: type) type { + return struct { + head: &Node, + tail: &Node, + root: Node, + + pub const Self = this; + + pub const Node = struct { + next: ?&Node, + data: T, + }; + + // TODO: well defined copy elision + pub fn init(self: &Self) void { + self.root.next = null; + self.head = &self.root; + self.tail = &self.root; + } + + pub fn put(self: &Self, node: &Node) void { + node.next = null; + + const tail = @atomicRmw(&Node, &self.tail, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst); + _ = @atomicRmw(?&Node, &tail.next, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst); + } + + pub fn get(self: &Self) ?&Node { + var head = @atomicLoad(&Node, &self.head, AtomicOrder.Acquire); + while (true) { + const node = head.next ?? return null; + head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? return node; + } + } + }; +} -- cgit v1.2.3 From 5d6e44b3f2bf37deaf09ce4a473fa5b52a6fb760 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 28 Apr 2018 18:00:51 -0400 Subject: add tests for std.atomic Queue and Stack --- std/atomic/queue.zig | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++- std/atomic/stack.zig | 4 +++ 2 files changed, 88 insertions(+), 1 deletion(-) (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 54981d4a61..c7ce00d6cf 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -1,3 +1,7 @@ +const builtin = @import("builtin"); +const AtomicOrder = builtin.AtomicOrder; +const AtomicRmwOp = builtin.AtomicRmwOp; + /// Many reader, many writer, non-allocating, thread-safe, lock-free pub fn Queue(comptime T: type) type { return struct { @@ -12,7 +16,7 @@ pub fn Queue(comptime T: type) type { data: T, }; - // TODO: well defined copy elision + // TODO: well defined copy elision: https://github.com/zig-lang/zig/issues/287 pub fn init(self: &Self) void { self.root.next = null; self.head = &self.root; @@ -35,3 +39,82 @@ pub fn Queue(comptime T: type) type { } }; } + +const std = @import("std"); +const Context = struct { + allocator: &std.mem.Allocator, + queue: &Queue(i32), + put_sum: isize, + get_sum: isize, + get_count: usize, + puts_done: u8, // TODO make this a bool +}; +const puts_per_thread = 10000; +const put_thread_count = 3; + +test "std.atomic.queue" { + var direct_allocator = std.heap.DirectAllocator.init(); + defer direct_allocator.deinit(); + + var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 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 queue: Queue(i32) = undefined; + queue.init(); + var context = Context { + .allocator = a, + .queue = &queue, + .put_sum = 0, + .get_sum = 0, + .puts_done = 0, + .get_count = 0, + }; + + var putters: [put_thread_count]&std.os.Thread = undefined; + for (putters) |*t| { + *t = try std.os.spawnThreadAllocator(a, &context, startPuts); + } + var getters: [put_thread_count]&std.os.Thread = undefined; + for (getters) |*t| { + *t = try std.os.spawnThreadAllocator(a, &context, startGets); + } + + for (putters) |t| t.wait(); + _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); + for (getters) |t| t.wait(); + + std.debug.assert(context.put_sum == context.get_sum); + std.debug.assert(context.get_count == puts_per_thread * put_thread_count); +} + +fn startPuts(ctx: &Context) u8 { + var put_count: usize = puts_per_thread; + var r = std.rand.DefaultPrng.init(0xdeadbeef); + while (put_count != 0) : (put_count -= 1) { + std.os.time.sleep(0, 1); // let the os scheduler be our fuzz + const x = @bitCast(i32, r.random.scalar(u32)); + const node = ctx.allocator.create(Queue(i32).Node) catch unreachable; + node.data = x; + ctx.queue.put(node); + _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); + } + return 0; +} + +fn startGets(ctx: &Context) u8 { + while (true) { + while (ctx.queue.get()) |node| { + std.os.time.sleep(0, 1); // let the os scheduler be our fuzz + _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst); + _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst); + } + + if (@atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1) { + break; + } + } + return 0; +} diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index a1e686155c..a53f7682b0 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -53,6 +53,7 @@ const Context = struct { stack: &Stack(i32), put_sum: isize, get_sum: isize, + get_count: usize, puts_done: u8, // TODO make this a bool }; const puts_per_thread = 1000; @@ -75,6 +76,7 @@ test "std.atomic.stack" { .put_sum = 0, .get_sum = 0, .puts_done = 0, + .get_count = 0, }; var putters: [put_thread_count]&std.os.Thread = undefined; @@ -91,6 +93,7 @@ test "std.atomic.stack" { for (getters) |t| t.wait(); std.debug.assert(context.put_sum == context.get_sum); + std.debug.assert(context.get_count == puts_per_thread * put_thread_count); } fn startPuts(ctx: &Context) u8 { @@ -112,6 +115,7 @@ fn startGets(ctx: &Context) u8 { while (ctx.stack.pop()) |node| { std.os.time.sleep(0, 1); // let the os scheduler be our fuzz _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst); + _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst); } if (@atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1) { -- cgit v1.2.3 From a10351b439769c57454e19915365b21e43f408bc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 28 Apr 2018 18:19:00 -0400 Subject: disable atomic stack and queue tests for non-linux --- std/atomic/queue.zig | 4 ++++ std/atomic/stack.zig | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index c7ce00d6cf..3866bad7ce 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -53,6 +53,10 @@ const puts_per_thread = 10000; const put_thread_count = 3; test "std.atomic.queue" { + if (builtin.os != builtin.Os.linux) { + // TODO implement kernel threads for windows and macos + return; + } var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index a53f7682b0..12de2edaaa 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -60,6 +60,10 @@ const puts_per_thread = 1000; const put_thread_count = 3; test "std.atomic.stack" { + if (builtin.os != builtin.Os.linux) { + // TODO implement kernel threads for windows and macos + return; + } var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); -- cgit v1.2.3 From abf90eaa674782e092e49bb23c4c7da0f581f604 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 29 Apr 2018 00:09:18 -0400 Subject: enable atomic queue and stack tests for macos --- std/atomic/queue.zig | 4 ++-- std/atomic/stack.zig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 3866bad7ce..dd9b869f02 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -53,8 +53,8 @@ const puts_per_thread = 10000; const put_thread_count = 3; test "std.atomic.queue" { - if (builtin.os != builtin.Os.linux) { - // TODO implement kernel threads for windows and macos + if (builtin.os == builtin.Os.windows) { + // TODO implement kernel threads for windows return; } var direct_allocator = std.heap.DirectAllocator.init(); diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 12de2edaaa..9f2ceacfa3 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -60,8 +60,8 @@ const puts_per_thread = 1000; const put_thread_count = 3; test "std.atomic.stack" { - if (builtin.os != builtin.Os.linux) { - // TODO implement kernel threads for windows and macos + if (builtin.os == builtin.Os.windows) { + // TODO implement kernel threads for windows return; } var direct_allocator = std.heap.DirectAllocator.init(); -- cgit v1.2.3 From 6376d96824c5205ecc02b2c621bcef5dc78f1a81 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 29 Apr 2018 02:40:22 -0400 Subject: support kernel threads for windows * remove std.os.spawnThreadAllocator - windows does not support an explicit stack, so using an allocator for a thread stack space does not work. * std.os.spawnThread - instead of accepting a stack argument, the implementation will directly allocate using OS-specific APIs. --- std/atomic/queue.zig | 8 +-- std/atomic/stack.zig | 8 +-- std/mem.zig | 1 + std/os/index.zig | 165 ++++++++++++++++++++++++++++++----------------- std/os/test.zig | 20 ++---- std/os/windows/index.zig | 6 ++ 6 files changed, 120 insertions(+), 88 deletions(-) (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index dd9b869f02..1acecbab2c 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -53,10 +53,6 @@ const puts_per_thread = 10000; const put_thread_count = 3; test "std.atomic.queue" { - if (builtin.os == builtin.Os.windows) { - // TODO implement kernel threads for windows - return; - } var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); @@ -79,11 +75,11 @@ test "std.atomic.queue" { var putters: [put_thread_count]&std.os.Thread = undefined; for (putters) |*t| { - *t = try std.os.spawnThreadAllocator(a, &context, startPuts); + *t = try std.os.spawnThread(&context, startPuts); } var getters: [put_thread_count]&std.os.Thread = undefined; for (getters) |*t| { - *t = try std.os.spawnThreadAllocator(a, &context, startGets); + *t = try std.os.spawnThread(&context, startGets); } for (putters) |t| t.wait(); diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 9f2ceacfa3..accbcc942a 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -60,10 +60,6 @@ const puts_per_thread = 1000; const put_thread_count = 3; test "std.atomic.stack" { - if (builtin.os == builtin.Os.windows) { - // TODO implement kernel threads for windows - return; - } var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); @@ -85,11 +81,11 @@ test "std.atomic.stack" { var putters: [put_thread_count]&std.os.Thread = undefined; for (putters) |*t| { - *t = try std.os.spawnThreadAllocator(a, &context, startPuts); + *t = try std.os.spawnThread(&context, startPuts); } var getters: [put_thread_count]&std.os.Thread = undefined; for (getters) |*t| { - *t = try std.os.spawnThreadAllocator(a, &context, startGets); + *t = try std.os.spawnThread(&context, startGets); } for (putters) |t| t.wait(); diff --git a/std/mem.zig b/std/mem.zig index cc3161cddd..0f66f549cc 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -32,6 +32,7 @@ pub const Allocator = struct { freeFn: fn (self: &Allocator, old_mem: []u8) void, fn create(self: &Allocator, comptime T: type) !&T { + if (@sizeOf(T) == 0) return &{}; const slice = try self.alloc(T, 1); return &slice[0]; } diff --git a/std/os/index.zig b/std/os/index.zig index 85e46a1bf9..6842fd0fb3 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -2347,18 +2347,30 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void { } pub const Thread = struct { - pid: pid_t, - allocator: ?&mem.Allocator, - stack: []u8, - pthread_handle: pthread_t, + data: Data, pub const use_pthreads = is_posix and builtin.link_libc; - const pthread_t = if (use_pthreads) c.pthread_t else void; - const pid_t = if (!use_pthreads) i32 else void; + const Data = if (use_pthreads) struct { + handle: c.pthread_t, + stack_addr: usize, + stack_len: usize, + } else switch (builtin.os) { + builtin.Os.linux => struct { + pid: i32, + stack_addr: usize, + stack_len: usize, + }, + builtin.Os.windows => struct { + handle: windows.HANDLE, + alloc_start: &c_void, + heap_handle: windows.HANDLE, + }, + else => @compileError("Unsupported OS"), + }; pub fn wait(self: &const Thread) void { if (use_pthreads) { - const err = c.pthread_join(self.pthread_handle, null); + const err = c.pthread_join(self.data.handle, null); switch (err) { 0 => {}, posix.EINVAL => unreachable, @@ -2366,23 +2378,27 @@ pub const Thread = struct { posix.EDEADLK => unreachable, else => unreachable, } - } else if (builtin.os == builtin.Os.linux) { - while (true) { - const pid_value = @atomicLoad(i32, &self.pid, builtin.AtomicOrder.SeqCst); - if (pid_value == 0) break; - const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null); - switch (linux.getErrno(rc)) { - 0 => continue, - posix.EINTR => continue, - posix.EAGAIN => continue, - else => unreachable, + assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0); + } else switch (builtin.os) { + builtin.Os.linux => { + while (true) { + const pid_value = @atomicLoad(i32, &self.data.pid, builtin.AtomicOrder.SeqCst); + if (pid_value == 0) break; + const rc = linux.futex_wait(@ptrToInt(&self.data.pid), linux.FUTEX_WAIT, pid_value, null); + switch (linux.getErrno(rc)) { + 0 => continue, + posix.EINTR => continue, + posix.EAGAIN => continue, + else => unreachable, + } } - } - } else { - @compileError("Unsupported OS"); - } - if (self.allocator) |a| { - a.free(self.stack); + assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0); + }, + builtin.Os.windows => { + assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0); + assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0); + }, + else => @compileError("Unsupported OS"), } } }; @@ -2407,52 +2423,60 @@ pub const SpawnThreadError = error { /// be copied. SystemResources, - /// pthreads requires at least 16384 bytes of stack space - StackTooSmall, + /// Not enough userland memory to spawn the thread. + OutOfMemory, Unexpected, }; -pub const SpawnThreadAllocatorError = SpawnThreadError || error{OutOfMemory}; - /// caller must call wait on the returned thread /// fn startFn(@typeOf(context)) T /// where T is u8, noreturn, void, or !void -pub fn spawnThreadAllocator(allocator: &mem.Allocator, context: var, comptime startFn: var) SpawnThreadAllocatorError!&Thread { +/// caller must call wait on the returned thread +pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!&Thread { // TODO compile-time call graph analysis to determine stack upper bound // https://github.com/zig-lang/zig/issues/157 const default_stack_size = 8 * 1024 * 1024; - const stack_bytes = try allocator.alignedAlloc(u8, os.page_size, default_stack_size); - const thread = try spawnThread(stack_bytes, context, startFn); - thread.allocator = allocator; - return thread; -} -/// stack must be big enough to store one Thread and one @typeOf(context), each with default alignment, at the end -/// fn startFn(@typeOf(context)) T -/// where T is u8, noreturn, void, or !void -/// caller must call wait on the returned thread -pub fn spawnThread(stack: []align(os.page_size) u8, context: var, comptime startFn: var) SpawnThreadError!&Thread { const Context = @typeOf(context); comptime assert(@ArgType(@typeOf(startFn), 0) == Context); - var stack_end: usize = @ptrToInt(stack.ptr) + stack.len; - var arg: usize = undefined; - if (@sizeOf(Context) != 0) { - stack_end -= @sizeOf(Context); - stack_end -= stack_end % @alignOf(Context); - assert(stack_end >= @ptrToInt(stack.ptr)); - const context_ptr = @alignCast(@alignOf(Context), @intToPtr(&Context, stack_end)); - *context_ptr = context; - arg = stack_end; - } + if (builtin.os == builtin.Os.windows) { + const WinThread = struct { + const OuterContext = struct { + thread: Thread, + inner: Context, + }; + extern fn threadMain(arg: windows.LPVOID) windows.DWORD { + if (@sizeOf(Context) == 0) { + return startFn({}); + } else { + return startFn(*@ptrCast(&Context, @alignCast(@alignOf(Context), arg))); + } + } + }; - stack_end -= @sizeOf(Thread); - stack_end -= stack_end % @alignOf(Thread); - assert(stack_end >= @ptrToInt(stack.ptr)); - const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(&Thread, stack_end)); - thread_ptr.stack = stack; - thread_ptr.allocator = null; + const heap_handle = windows.GetProcessHeap() ?? return SpawnThreadError.OutOfMemory; + const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext); + const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) ?? return SpawnThreadError.OutOfMemory; + errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0); + const bytes = @ptrCast(&u8, bytes_ptr)[0..byte_count]; + const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable; + outer_context.inner = context; + outer_context.thread.data.heap_handle = heap_handle; + outer_context.thread.data.alloc_start = bytes_ptr; + + const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(&c_void, &outer_context.inner); + outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, + parameter, 0, null) ?? + { + const err = windows.GetLastError(); + return switch (err) { + else => os.unexpectedErrorWindows(err), + }; + }; + return &outer_context.thread; + } const MainFuncs = struct { extern fn linuxThreadMain(ctx_addr: usize) u8 { @@ -2473,6 +2497,29 @@ pub fn spawnThread(stack: []align(os.page_size) u8, context: var, comptime start } }; + const stack_len = default_stack_size; + const stack_addr = posix.mmap(null, stack_len, posix.PROT_READ|posix.PROT_WRITE, + posix.MAP_PRIVATE|posix.MAP_ANONYMOUS|posix.MAP_GROWSDOWN, -1, 0); + if (stack_addr == posix.MAP_FAILED) return error.OutOfMemory; + errdefer _ = posix.munmap(stack_addr, stack_len); + + var stack_end: usize = stack_addr + stack_len; + var arg: usize = undefined; + if (@sizeOf(Context) != 0) { + stack_end -= @sizeOf(Context); + stack_end -= stack_end % @alignOf(Context); + assert(stack_end >= stack_addr); + const context_ptr = @alignCast(@alignOf(Context), @intToPtr(&Context, stack_end)); + *context_ptr = context; + arg = stack_end; + } + + stack_end -= @sizeOf(Thread); + stack_end -= stack_end % @alignOf(Thread); + assert(stack_end >= stack_addr); + const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(&Thread, stack_end)); + + if (builtin.os == builtin.Os.windows) { // use windows API directly @compileError("TODO support spawnThread for Windows"); @@ -2484,14 +2531,12 @@ pub fn spawnThread(stack: []align(os.page_size) u8, context: var, comptime start // align to page stack_end -= stack_end % os.page_size; + assert(c.pthread_attr_setstack(&attr, @intToPtr(&c_void, stack_addr), stack_len) == 0); - const stack_size = stack_end - @ptrToInt(stack.ptr); - const setstack_err = c.pthread_attr_setstack(&attr, @ptrCast(&c_void, stack.ptr), stack_size); - if (setstack_err != 0) { - return SpawnThreadError.StackTooSmall; // pthreads requires at least 16384 bytes - } + thread_ptr.data.stack_addr = stack_addr; + thread_ptr.data.stack_len = stack_len; - const err = c.pthread_create(&thread_ptr.pthread_handle, &attr, MainFuncs.posixThreadMain, @intToPtr(&c_void, arg)); + const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(&c_void, arg)); switch (err) { 0 => return thread_ptr, posix.EAGAIN => return SpawnThreadError.SystemResources, diff --git a/std/os/test.zig b/std/os/test.zig index 37e5bf4bb8..56d6e8b309 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -44,24 +44,12 @@ test "access file" { } test "spawn threads" { - if (builtin.os == builtin.Os.windows) { - // TODO implement threads on windows - return; - } - - var direct_allocator = std.heap.DirectAllocator.init(); - defer direct_allocator.deinit(); - var shared_ctx: i32 = 1; - const thread1 = try std.os.spawnThreadAllocator(&direct_allocator.allocator, {}, start1); - const thread4 = try std.os.spawnThreadAllocator(&direct_allocator.allocator, &shared_ctx, start2); - - var stack1: [20 * 1024]u8 align(os.page_size) = undefined; - var stack2: [20 * 1024]u8 align(os.page_size) = undefined; - - const thread2 = try std.os.spawnThread(stack1[0..], &shared_ctx, start2); - const thread3 = try std.os.spawnThread(stack2[0..], &shared_ctx, start2); + const thread1 = try std.os.spawnThread({}, start1); + const thread2 = try std.os.spawnThread(&shared_ctx, start2); + const thread3 = try std.os.spawnThread(&shared_ctx, start2); + const thread4 = try std.os.spawnThread(&shared_ctx, start2); thread1.wait(); thread2.wait(); diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index d6ef7205e8..e13ed0f131 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -28,6 +28,9 @@ pub extern "kernel32" stdcallcc fn CreateProcessA(lpApplicationName: ?LPCSTR, lp pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(lpSymlinkFileName: LPCSTR, lpTargetFileName: LPCSTR, dwFlags: DWORD) BOOLEAN; + +pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE; + pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL; pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn; @@ -318,6 +321,9 @@ pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000; pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004; pub const HEAP_NO_SERIALIZE = 0x00000001; +pub const PTHREAD_START_ROUTINE = extern fn(LPVOID) DWORD; +pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; + test "import" { _ = @import("util.zig"); } -- cgit v1.2.3 From c186cd187e9b75ee1514a5f3371abeffb36d871a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 2 May 2018 20:19:26 -0400 Subject: std.atomic - use AtomicOrder.SeqCst for everything also use less memory for the tests --- std/atomic/queue.zig | 6 +++--- std/atomic/stack.zig | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 1acecbab2c..69c82236d1 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -31,10 +31,10 @@ pub fn Queue(comptime T: type) type { } pub fn get(self: &Self) ?&Node { - var head = @atomicLoad(&Node, &self.head, AtomicOrder.Acquire); + var head = @atomicLoad(&Node, &self.head, AtomicOrder.SeqCst); while (true) { const node = head.next ?? return null; - head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? return node; + head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return node; } } }; @@ -56,7 +56,7 @@ test "std.atomic.queue" { var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); - var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024); + var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 600 * 1024); defer direct_allocator.allocator.free(plenty_of_memory); var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory); diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index accbcc942a..96185d308b 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -35,7 +35,7 @@ pub fn Stack(comptime T: type) type { } pub fn pop(self: &Self) ?&Node { - var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire); + var root = @atomicLoad(?&Node, &self.root, AtomicOrder.SeqCst); while (true) { root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root; } @@ -63,7 +63,7 @@ test "std.atomic.stack" { var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); - var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024); + var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 600 * 1024); defer direct_allocator.allocator.free(plenty_of_memory); var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory); -- cgit v1.2.3 From 02c1b9df3bcf2e0324adf02fd6c0ed56fe58c6d3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 2 May 2018 21:34:34 -0400 Subject: fix compiler-rt tests accidentally running std tests also reduce the aggressiveness of std.atomic.stack and std.atomic.queue fuzz testing. appveyor has 1 core and 10,000 iterations is too much for 6 threads to thrash over --- std/atomic/queue.zig | 10 +++++-- std/atomic/stack.zig | 9 ++++-- std/special/compiler_rt/fixuint.zig | 2 +- std/special/compiler_rt/fixunsdfdi_test.zig | 2 +- std/special/compiler_rt/fixunsdfsi_test.zig | 2 +- std/special/compiler_rt/fixunsdfti_test.zig | 2 +- std/special/compiler_rt/fixunssfdi_test.zig | 2 +- std/special/compiler_rt/fixunssfsi_test.zig | 2 +- std/special/compiler_rt/fixunssfti_test.zig | 2 +- std/special/compiler_rt/fixunstfdi_test.zig | 2 +- std/special/compiler_rt/fixunstfsi_test.zig | 2 +- std/special/compiler_rt/fixunstfti_test.zig | 2 +- std/special/compiler_rt/index.zig | 5 ++-- std/special/compiler_rt/udivmod.zig | 2 +- std/zig/parser_test.zig | 46 +++++++++++++++++------------ 15 files changed, 56 insertions(+), 36 deletions(-) (limited to 'std/atomic/queue.zig') diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 69c82236d1..e25c8e6b17 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -49,14 +49,20 @@ const Context = struct { get_count: usize, puts_done: u8, // TODO make this a bool }; -const puts_per_thread = 10000; + +// TODO add lazy evaluated build options and then put puts_per_thread behind +// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor +// CI we would use a less aggressive setting since at 1 core, while we still +// want this test to pass, we need a smaller value since there is so much thrashing +// we would also use a less aggressive setting when running in valgrind +const puts_per_thread = 500; const put_thread_count = 3; test "std.atomic.queue" { var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); - var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 600 * 1024); + 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); diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 96185d308b..4a3dbef32b 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -56,14 +56,19 @@ const Context = struct { get_count: usize, puts_done: u8, // TODO make this a bool }; -const puts_per_thread = 1000; +// TODO add lazy evaluated build options and then put puts_per_thread behind +// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor +// CI we would use a less aggressive setting since at 1 core, while we still +// want this test to pass, we need a smaller value since there is so much thrashing +// we would also use a less aggressive setting when running in valgrind +const puts_per_thread = 500; const put_thread_count = 3; test "std.atomic.stack" { var direct_allocator = std.heap.DirectAllocator.init(); defer direct_allocator.deinit(); - var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 600 * 1024); + 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); diff --git a/std/special/compiler_rt/fixuint.zig b/std/special/compiler_rt/fixuint.zig index b01bc48118..37cec446bc 100644 --- a/std/special/compiler_rt/fixuint.zig +++ b/std/special/compiler_rt/fixuint.zig @@ -1,5 +1,5 @@ const is_test = @import("builtin").is_test; -const Log2Int = @import("../../math/index.zig").Log2Int; +const Log2Int = @import("std").math.Log2Int; pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t { @setRuntimeSafety(is_test); diff --git a/std/special/compiler_rt/fixunsdfdi_test.zig b/std/special/compiler_rt/fixunsdfdi_test.zig index 3443a4938e..e59d09f8de 100644 --- a/std/special/compiler_rt/fixunsdfdi_test.zig +++ b/std/special/compiler_rt/fixunsdfdi_test.zig @@ -1,5 +1,5 @@ const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunsdfdi(a: f64, expected: u64) void { const x = __fixunsdfdi(a); diff --git a/std/special/compiler_rt/fixunsdfsi_test.zig b/std/special/compiler_rt/fixunsdfsi_test.zig index 3c74bc5f4c..db6e32e23d 100644 --- a/std/special/compiler_rt/fixunsdfsi_test.zig +++ b/std/special/compiler_rt/fixunsdfsi_test.zig @@ -1,5 +1,5 @@ const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunsdfsi(a: f64, expected: u32) void { const x = __fixunsdfsi(a); diff --git a/std/special/compiler_rt/fixunsdfti_test.zig b/std/special/compiler_rt/fixunsdfti_test.zig index 3cb7687887..7283b35c0e 100644 --- a/std/special/compiler_rt/fixunsdfti_test.zig +++ b/std/special/compiler_rt/fixunsdfti_test.zig @@ -1,5 +1,5 @@ const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunsdfti(a: f64, expected: u128) void { const x = __fixunsdfti(a); diff --git a/std/special/compiler_rt/fixunssfdi_test.zig b/std/special/compiler_rt/fixunssfdi_test.zig index de27323777..e4e6c1736d 100644 --- a/std/special/compiler_rt/fixunssfdi_test.zig +++ b/std/special/compiler_rt/fixunssfdi_test.zig @@ -1,5 +1,5 @@ const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunssfdi(a: f32, expected: u64) void { const x = __fixunssfdi(a); diff --git a/std/special/compiler_rt/fixunssfsi_test.zig b/std/special/compiler_rt/fixunssfsi_test.zig index 47ed21d4f4..614c648dfe 100644 --- a/std/special/compiler_rt/fixunssfsi_test.zig +++ b/std/special/compiler_rt/fixunssfsi_test.zig @@ -1,5 +1,5 @@ const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunssfsi(a: f32, expected: u32) void { const x = __fixunssfsi(a); diff --git a/std/special/compiler_rt/fixunssfti_test.zig b/std/special/compiler_rt/fixunssfti_test.zig index 3033eb0def..43ad527f53 100644 --- a/std/special/compiler_rt/fixunssfti_test.zig +++ b/std/special/compiler_rt/fixunssfti_test.zig @@ -1,5 +1,5 @@ const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunssfti(a: f32, expected: u128) void { const x = __fixunssfti(a); diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/std/special/compiler_rt/fixunstfdi_test.zig index d1f5f6496a..dd0869195a 100644 --- a/std/special/compiler_rt/fixunstfdi_test.zig +++ b/std/special/compiler_rt/fixunstfdi_test.zig @@ -1,5 +1,5 @@ const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunstfdi(a: f128, expected: u64) void { const x = __fixunstfdi(a); diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/std/special/compiler_rt/fixunstfsi_test.zig index 8bdf36d9d4..f682191994 100644 --- a/std/special/compiler_rt/fixunstfsi_test.zig +++ b/std/special/compiler_rt/fixunstfsi_test.zig @@ -1,5 +1,5 @@ const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunstfsi(a: f128, expected: u32) void { const x = __fixunstfsi(a); diff --git a/std/special/compiler_rt/fixunstfti_test.zig b/std/special/compiler_rt/fixunstfti_test.zig index d9eb60e59b..9128ac6c08 100644 --- a/std/special/compiler_rt/fixunstfti_test.zig +++ b/std/special/compiler_rt/fixunstfti_test.zig @@ -1,5 +1,5 @@ const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; -const assert = @import("../../index.zig").debug.assert; +const assert = @import("std").debug.assert; fn test__fixunstfti(a: f128, expected: u128) void { const x = __fixunstfti(a); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 6ef43c4fed..9da9c3f083 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -71,7 +71,8 @@ comptime { } } -const assert = @import("../../index.zig").debug.assert; +const std = @import("std"); +const assert = std.debug.assert; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; @@ -80,7 +81,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn { @setCold(true); if (is_test) { - @import("std").debug.panic("{}", msg); + std.debug.panic("{}", msg); } else { unreachable; } diff --git a/std/special/compiler_rt/udivmod.zig b/std/special/compiler_rt/udivmod.zig index 07eaef583c..7820c7beb0 100644 --- a/std/special/compiler_rt/udivmod.zig +++ b/std/special/compiler_rt/udivmod.zig @@ -9,7 +9,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2)); const SignedDoubleInt = @IntType(true, DoubleInt.bit_count); - const Log2SingleInt = @import("../../math/index.zig").Log2Int(SingleInt); + const Log2SingleInt = @import("std").math.Log2Int(SingleInt); const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #421 const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #421 diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 4688939485..beb3a4e0c3 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,3 +1,30 @@ +// TODO +//if (sr > n_uword_bits - 1) // d > r +// return 0; + +// TODO switch with no body +// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {}; + + +//TODO +//test "zig fmt: same-line comptime" { +// try testCanonical( +// \\test "" { +// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt +// \\} +// \\ +// ); +//} + + +//TODO +//test "zig fmt: number literals" { +// try testCanonical( +// \\pub const f64_true_min = 4.94065645841246544177e-324; +// \\ +// ); +//} + test "zig fmt: line comments in struct initializer" { try testCanonical( \\fn foo() void { @@ -20,25 +47,6 @@ test "zig fmt: line comments in struct initializer" { ); } -//TODO -//test "zig fmt: same-line comptime" { -// try testCanonical( -// \\test "" { -// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt -// \\} -// \\ -// ); -//} - - -//TODO -//test "zig fmt: number literals" { -// try testCanonical( -// \\pub const f64_true_min = 4.94065645841246544177e-324; -// \\ -// ); -//} - test "zig fmt: doc comments before struct field" { try testCanonical( \\pub const Allocator = struct { -- cgit v1.2.3