var data = {lines:[ {"lineNum":" 1","line":"const std = @import(\"std.zig\");"}, {"lineNum":" 2","line":"const builtin = @import(\"builtin\");"}, {"lineNum":" 3","line":"const os = std.os;"}, {"lineNum":" 4","line":"const assert = std.debug.assert;"}, {"lineNum":" 5","line":"const windows = os.windows;"}, {"lineNum":" 6","line":"const testing = std.testing;"}, {"lineNum":" 7","line":"const SpinLock = std.SpinLock;"}, {"lineNum":" 8","line":"const ResetEvent = std.ResetEvent;"}, {"lineNum":" 9","line":""}, {"lineNum":" 10","line":"/// Lock may be held only once. If the same thread tries to acquire"}, {"lineNum":" 11","line":"/// the same mutex twice, it deadlocks. This type supports static"}, {"lineNum":" 12","line":"/// initialization and is at most `@sizeOf(usize)` in size. When an"}, {"lineNum":" 13","line":"/// application is built in single threaded release mode, all the"}, {"lineNum":" 14","line":"/// functions are no-ops. In single threaded debug mode, there is"}, {"lineNum":" 15","line":"/// deadlock detection."}, {"lineNum":" 16","line":"///"}, {"lineNum":" 17","line":"/// Example usage:"}, {"lineNum":" 18","line":"/// var m = Mutex.init();"}, {"lineNum":" 19","line":"/// defer m.deinit();"}, {"lineNum":" 20","line":"///"}, {"lineNum":" 21","line":"/// const lock = m.acquire();"}, {"lineNum":" 22","line":"/// defer lock.release();"}, {"lineNum":" 23","line":"/// ... critical code"}, {"lineNum":" 24","line":"///"}, {"lineNum":" 25","line":"/// Non-blocking:"}, {"lineNum":" 26","line":"/// if (m.tryAcquire) |lock| {"}, {"lineNum":" 27","line":"/// defer lock.release();"}, {"lineNum":" 28","line":"/// // ... critical section"}, {"lineNum":" 29","line":"/// } else {"}, {"lineNum":" 30","line":"/// // ... lock not acquired"}, {"lineNum":" 31","line":"/// }"}, {"lineNum":" 32","line":"pub const Mutex = if (builtin.single_threaded)"}, {"lineNum":" 33","line":" struct {"}, {"lineNum":" 34","line":" lock: @TypeOf(lock_init),"}, {"lineNum":" 35","line":""}, {"lineNum":" 36","line":" const lock_init = if (std.debug.runtime_safety) false else {};"}, {"lineNum":" 37","line":""}, {"lineNum":" 38","line":" pub const Held = struct {"}, {"lineNum":" 39","line":" mutex: *Mutex,"}, {"lineNum":" 40","line":""}, {"lineNum":" 41","line":" pub fn release(self: Held) void {"}, {"lineNum":" 42","line":" if (std.debug.runtime_safety) {"}, {"lineNum":" 43","line":" self.mutex.lock = false;"}, {"lineNum":" 44","line":" }"}, {"lineNum":" 45","line":" }"}, {"lineNum":" 46","line":" };"}, {"lineNum":" 47","line":""}, {"lineNum":" 48","line":" /// Create a new mutex in unlocked state."}, {"lineNum":" 49","line":" pub fn init() Mutex {"}, {"lineNum":" 50","line":" return Mutex{ .lock = lock_init };"}, {"lineNum":" 51","line":" }"}, {"lineNum":" 52","line":""}, {"lineNum":" 53","line":" /// Free a mutex created with init. Calling this while the"}, {"lineNum":" 54","line":" /// mutex is held is illegal behavior."}, {"lineNum":" 55","line":" pub fn deinit(self: *Mutex) void {"}, {"lineNum":" 56","line":" self.* = undefined;"}, {"lineNum":" 57","line":" }"}, {"lineNum":" 58","line":""}, {"lineNum":" 59","line":" /// Try to acquire the mutex without blocking. Returns null if"}, {"lineNum":" 60","line":" /// the mutex is unavailable. Otherwise returns Held. Call"}, {"lineNum":" 61","line":" /// release on Held."}, {"lineNum":" 62","line":" pub fn tryAcquire(self: *Mutex) ?Held {"}, {"lineNum":" 63","line":" if (std.debug.runtime_safety) {"}, {"lineNum":" 64","line":" if (self.lock) return null;"}, {"lineNum":" 65","line":" self.lock = true;"}, {"lineNum":" 66","line":" }"}, {"lineNum":" 67","line":" return Held{ .mutex = self };"}, {"lineNum":" 68","line":" }"}, {"lineNum":" 69","line":""}, {"lineNum":" 70","line":" /// Acquire the mutex. Will deadlock if the mutex is already"}, {"lineNum":" 71","line":" /// held by the calling thread."}, {"lineNum":" 72","line":" pub fn acquire(self: *Mutex) Held {"}, {"lineNum":" 73","line":" return self.tryAcquire() orelse @panic(\"deadlock detected\");"}, {"lineNum":" 74","line":" }"}, {"lineNum":" 75","line":" }"}, {"lineNum":" 76","line":"else if (builtin.os.tag == .windows)"}, {"lineNum":" 77","line":"// https://locklessinc.com/articles/keyed_events/"}, {"lineNum":" 78","line":" extern union {"}, {"lineNum":" 79","line":" locked: u8,"}, {"lineNum":" 80","line":" waiters: u32,"}, {"lineNum":" 81","line":""}, {"lineNum":" 82","line":" const WAKE = 1 << 8;"}, {"lineNum":" 83","line":" const WAIT = 1 << 9;"}, {"lineNum":" 84","line":""}, {"lineNum":" 85","line":" pub fn init() Mutex {"}, {"lineNum":" 86","line":" return Mutex{ .waiters = 0 };"}, {"lineNum":" 87","line":" }"}, {"lineNum":" 88","line":""}, {"lineNum":" 89","line":" pub fn deinit(self: *Mutex) void {"}, {"lineNum":" 90","line":" self.* = undefined;"}, {"lineNum":" 91","line":" }"}, {"lineNum":" 92","line":""}, {"lineNum":" 93","line":" pub fn tryAcquire(self: *Mutex) ?Held {"}, {"lineNum":" 94","line":" if (@atomicRmw(u8, &self.locked, .Xchg, 1, .Acquire) != 0)"}, {"lineNum":" 95","line":" return null;"}, {"lineNum":" 96","line":" return Held{ .mutex = self };"}, {"lineNum":" 97","line":" }"}, {"lineNum":" 98","line":""}, {"lineNum":" 99","line":" pub fn acquire(self: *Mutex) Held {"}, {"lineNum":" 100","line":" return self.tryAcquire() orelse self.acquireSlow();"}, {"lineNum":" 101","line":" }"}, {"lineNum":" 102","line":""}, {"lineNum":" 103","line":" fn acquireSpinning(self: *Mutex) Held {"}, {"lineNum":" 104","line":" @setCold(true);"}, {"lineNum":" 105","line":" while (true) : (SpinLock.yield()) {"}, {"lineNum":" 106","line":" return self.tryAcquire() orelse continue;"}, {"lineNum":" 107","line":" }"}, {"lineNum":" 108","line":" }"}, {"lineNum":" 109","line":""}, {"lineNum":" 110","line":" fn acquireSlow(self: *Mutex) Held {"}, {"lineNum":" 111","line":" // try to use NT keyed events for blocking, falling back to spinlock if unavailable"}, {"lineNum":" 112","line":" @setCold(true);"}, {"lineNum":" 113","line":" const handle = ResetEvent.OsEvent.Futex.getEventHandle() orelse return self.acquireSpinning();"}, {"lineNum":" 114","line":" const key = @ptrCast(*const c_void, &self.waiters);"}, {"lineNum":" 115","line":""}, {"lineNum":" 116","line":" while (true) : (SpinLock.loopHint(1)) {"}, {"lineNum":" 117","line":" const waiters = @atomicLoad(u32, &self.waiters, .Monotonic);"}, {"lineNum":" 118","line":""}, {"lineNum":" 119","line":" // try and take lock if unlocked"}, {"lineNum":" 120","line":" if ((waiters & 1) == 0) {"}, {"lineNum":" 121","line":" if (@atomicRmw(u8, &self.locked, .Xchg, 1, .Acquire) == 0) {"}, {"lineNum":" 122","line":" return Held{ .mutex = self };"}, {"lineNum":" 123","line":" }"}, {"lineNum":" 124","line":""}, {"lineNum":" 125","line":" // otherwise, try and update the waiting count."}, {"lineNum":" 126","line":" // then unset the WAKE bit so that another unlocker can wake up a thread."}, {"lineNum":" 127","line":" } else if (@cmpxchgWeak(u32, &self.waiters, waiters, (waiters + WAIT) | 1, .Monotonic, .Monotonic) == null) {"}, {"lineNum":" 128","line":" const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null);"}, {"lineNum":" 129","line":" assert(rc == .SUCCESS);"}, {"lineNum":" 130","line":" _ = @atomicRmw(u32, &self.waiters, .Sub, WAKE, .Monotonic);"}, {"lineNum":" 131","line":" }"}, {"lineNum":" 132","line":" }"}, {"lineNum":" 133","line":" }"}, {"lineNum":" 134","line":""}, {"lineNum":" 135","line":" pub const Held = struct {"}, {"lineNum":" 136","line":" mutex: *Mutex,"}, {"lineNum":" 137","line":""}, {"lineNum":" 138","line":" pub fn release(self: Held) void {"}, {"lineNum":" 139","line":" // unlock without a rmw/cmpxchg instruction"}, {"lineNum":" 140","line":" @atomicStore(u8, @ptrCast(*u8, &self.mutex.locked), 0, .Release);"}, {"lineNum":" 141","line":" const handle = ResetEvent.OsEvent.Futex.getEventHandle() orelse return;"}, {"lineNum":" 142","line":" const key = @ptrCast(*const c_void, &self.mutex.waiters);"}, {"lineNum":" 143","line":""}, {"lineNum":" 144","line":" while (true) : (SpinLock.loopHint(1)) {"}, {"lineNum":" 145","line":" const waiters = @atomicLoad(u32, &self.mutex.waiters, .Monotonic);"}, {"lineNum":" 146","line":""}, {"lineNum":" 147","line":" // no one is waiting"}, {"lineNum":" 148","line":" if (waiters < WAIT) return;"}, {"lineNum":" 149","line":" // someone grabbed the lock and will do the wake instead"}, {"lineNum":" 150","line":" if (waiters & 1 != 0) return;"}, {"lineNum":" 151","line":" // someone else is currently waking up"}, {"lineNum":" 152","line":" if (waiters & WAKE != 0) return;"}, {"lineNum":" 153","line":""}, {"lineNum":" 154","line":" // try to decrease the waiter count & set the WAKE bit meaning a thread is waking up"}, {"lineNum":" 155","line":" if (@cmpxchgWeak(u32, &self.mutex.waiters, waiters, waiters - WAIT + WAKE, .Release, .Monotonic) == null) {"}, {"lineNum":" 156","line":" const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null);"}, {"lineNum":" 157","line":" assert(rc == .SUCCESS);"}, {"lineNum":" 158","line":" return;"}, {"lineNum":" 159","line":" }"}, {"lineNum":" 160","line":" }"}, {"lineNum":" 161","line":" }"}, {"lineNum":" 162","line":" };"}, {"lineNum":" 163","line":" }"}, {"lineNum":" 164","line":"else if (builtin.link_libc or builtin.os.tag == .linux)"}, {"lineNum":" 165","line":"// stack-based version of https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs"}, {"lineNum":" 166","line":" struct {"}, {"lineNum":" 167","line":" state: usize,"}, {"lineNum":" 168","line":""}, {"lineNum":" 169","line":" /// number of times to spin trying to acquire the lock."}, {"lineNum":" 170","line":" /// https://webkit.org/blog/6161/locking-in-webkit/"}, {"lineNum":" 171","line":" const SPIN_COUNT = 40;"}, {"lineNum":" 172","line":""}, {"lineNum":" 173","line":" const MUTEX_LOCK: usize = 1 << 0;"}, {"lineNum":" 174","line":" const QUEUE_LOCK: usize = 1 << 1;"}, {"lineNum":" 175","line":" const QUEUE_MASK: usize = ~(MUTEX_LOCK | QUEUE_LOCK);"}, {"lineNum":" 176","line":""}, {"lineNum":" 177","line":" const Node = struct {"}, {"lineNum":" 178","line":" next: ?*Node,"}, {"lineNum":" 179","line":" event: ResetEvent,"}, {"lineNum":" 180","line":" };"}, {"lineNum":" 181","line":""}, {"lineNum":" 182","line":" pub fn init() Mutex {","class":"lineCov","hits":"1","order":"2225","possible_hits":"1",}, {"lineNum":" 183","line":" return Mutex{ .state = 0 };","class":"lineCov","hits":"1","order":"2226","possible_hits":"1",}, {"lineNum":" 184","line":" }"}, {"lineNum":" 185","line":""}, {"lineNum":" 186","line":" pub fn deinit(self: *Mutex) void {","class":"lineCov","hits":"2","order":"2433","possible_hits":"2",}, {"lineNum":" 187","line":" self.* = undefined;","class":"lineCov","hits":"1","order":"2434","possible_hits":"1",}, {"lineNum":" 188","line":" }"}, {"lineNum":" 189","line":""}, {"lineNum":" 190","line":" pub fn tryAcquire(self: *Mutex) ?Held {","class":"lineCov","hits":"1","order":"2322","possible_hits":"1",}, {"lineNum":" 191","line":" if (@cmpxchgWeak(usize, &self.state, 0, MUTEX_LOCK, .Acquire, .Monotonic) != null)","class":"lineCov","hits":"2","order":"2323","possible_hits":"2",}, {"lineNum":" 192","line":" return null;","class":"lineCov","hits":"1","order":"2324","possible_hits":"1",}, {"lineNum":" 193","line":" return Held{ .mutex = self };","class":"lineCov","hits":"1","order":"2327","possible_hits":"1",}, {"lineNum":" 194","line":" }"}, {"lineNum":" 195","line":""}, {"lineNum":" 196","line":" pub fn acquire(self: *Mutex) Held {","class":"lineCov","hits":"1","order":"2320","possible_hits":"1",}, {"lineNum":" 197","line":" return self.tryAcquire() orelse {","class":"lineCov","hits":"2","order":"2321","possible_hits":"2",}, {"lineNum":" 198","line":" self.acquireSlow();","class":"lineCov","hits":"1","order":"2325","possible_hits":"1",}, {"lineNum":" 199","line":" return Held{ .mutex = self };","class":"lineCov","hits":"1","order":"2386","possible_hits":"1",}, {"lineNum":" 200","line":" };"}, {"lineNum":" 201","line":" }"}, {"lineNum":" 202","line":""}, {"lineNum":" 203","line":" fn acquireSlow(self: *Mutex) void {","class":"lineCov","hits":"1","order":"2326","possible_hits":"1",}, {"lineNum":" 204","line":" // inlining the fast path and hiding *Slow()"}, {"lineNum":" 205","line":" // calls behind a @setCold(true) appears to"}, {"lineNum":" 206","line":" // improve performance in release builds."}, {"lineNum":" 207","line":" @setCold(true);"}, {"lineNum":" 208","line":" while (true) {","class":"lineCov","hits":"1","order":"2421","possible_hits":"1",}, {"lineNum":" 209","line":""}, {"lineNum":" 210","line":" // try and spin for a bit to acquire the mutex if theres currently no queue"}, {"lineNum":" 211","line":" var spin_count: u32 = SPIN_COUNT;","class":"lineCov","hits":"1","order":"2328","possible_hits":"1",}, {"lineNum":" 212","line":" var state = @atomicLoad(usize, &self.state, .Monotonic);","class":"lineCov","hits":"1","order":"2329","possible_hits":"1",}, {"lineNum":" 213","line":" while (spin_count != 0) : (spin_count -= 1) {","class":"linePartCov","hits":"2","order":"2330","possible_hits":"3",}, {"lineNum":" 214","line":" if (state & MUTEX_LOCK == 0) {","class":"linePartCov","hits":"2","order":"2331","possible_hits":"3",}, {"lineNum":" 215","line":" _ = @cmpxchgWeak(usize, &self.state, state, state | MUTEX_LOCK, .Acquire, .Monotonic) orelse return;","class":"lineCov","hits":"1","order":"2391","possible_hits":"1",}, {"lineNum":" 216","line":" } else if (state & QUEUE_MASK == 0) {","class":"lineCov","hits":"2","order":"2332","possible_hits":"2",}, {"lineNum":" 217","line":" break;","class":"lineCov","hits":"1","order":"2333","possible_hits":"1",}, {"lineNum":" 218","line":" }"}, {"lineNum":" 219","line":" SpinLock.yield();","class":"lineCov","hits":"1","order":"7411","possible_hits":"1",}, {"lineNum":" 220","line":" state = @atomicLoad(usize, &self.state, .Monotonic);","class":"lineCov","hits":"1","order":"7413","possible_hits":"1",}, {"lineNum":" 221","line":" }"}, {"lineNum":" 222","line":""}, {"lineNum":" 223","line":" // create the ResetEvent node on the stack"}, {"lineNum":" 224","line":" // (faster than threadlocal on platforms like OSX)"}, {"lineNum":" 225","line":" var node: Node = undefined;","class":"lineCov","hits":"1","order":"2334","possible_hits":"1",}, {"lineNum":" 226","line":" node.event = ResetEvent.init();","class":"lineCov","hits":"1","order":"2336","possible_hits":"1",}, {"lineNum":" 227","line":" defer node.event.deinit();","class":"lineCov","hits":"2","order":"2376","possible_hits":"2",}, {"lineNum":" 228","line":""}, {"lineNum":" 229","line":" // we\'ve spun too long, try and add our node to the LIFO queue."}, {"lineNum":" 230","line":" // if the mutex becomes available in the process, try and grab it instead."}, {"lineNum":" 231","line":" while (true) {","class":"lineCov","hits":"2","order":"2342","possible_hits":"2",}, {"lineNum":" 232","line":" if (state & MUTEX_LOCK == 0) {","class":"linePartCov","hits":"1","order":"2343","possible_hits":"2",}, {"lineNum":" 233","line":" _ = @cmpxchgWeak(usize, &self.state, state, state | MUTEX_LOCK, .Acquire, .Monotonic) orelse return;","class":"lineCov","hits":"2","order":"2375","possible_hits":"2",}, {"lineNum":" 234","line":" } else {"}, {"lineNum":" 235","line":" node.next = @intToPtr(?*Node, state & QUEUE_MASK);","class":"linePartCov","hits":"1","order":"2344","possible_hits":"2",}, {"lineNum":" 236","line":" const new_state = @ptrToInt(&node) | (state & ~QUEUE_MASK);","class":"lineCov","hits":"1","order":"2345","possible_hits":"1",}, {"lineNum":" 237","line":" _ = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Monotonic) orelse {","class":"lineCov","hits":"2","order":"2347","possible_hits":"2",}, {"lineNum":" 238","line":" node.event.wait();","class":"lineCov","hits":"1","order":"2348","possible_hits":"1",}, {"lineNum":" 239","line":" break;","class":"lineCov","hits":"1","order":"2420","possible_hits":"1",}, {"lineNum":" 240","line":" };"}, {"lineNum":" 241","line":" }"}, {"lineNum":" 242","line":" SpinLock.yield();","class":"lineCov","hits":"1","order":"2349","possible_hits":"1",}, {"lineNum":" 243","line":" state = @atomicLoad(usize, &self.state, .Monotonic);","class":"lineCov","hits":"1","order":"2370","possible_hits":"1",}, {"lineNum":" 244","line":" }"}, {"lineNum":" 245","line":" }"}, {"lineNum":" 246","line":" }"}, {"lineNum":" 247","line":""}, {"lineNum":" 248","line":" /// Returned when the lock is acquired. Call release to"}, {"lineNum":" 249","line":" /// release."}, {"lineNum":" 250","line":" pub const Held = struct {"}, {"lineNum":" 251","line":" mutex: *Mutex,"}, {"lineNum":" 252","line":""}, {"lineNum":" 253","line":" /// Release the held lock."}, {"lineNum":" 254","line":" pub fn release(self: Held) void {","class":"lineCov","hits":"2","order":"2346","possible_hits":"2",}, {"lineNum":" 255","line":" // first, remove the lock bit so another possibly parallel acquire() can succeed."}, {"lineNum":" 256","line":" // use .Sub since it can be usually compiled down more efficiency"}, {"lineNum":" 257","line":" // (`lock sub` on x86) vs .And ~MUTEX_LOCK (`lock cmpxchg` loop on x86)"}, {"lineNum":" 258","line":" const state = @atomicRmw(usize, &self.mutex.state, .Sub, MUTEX_LOCK, .Release);","class":"lineCov","hits":"1","order":"2350","possible_hits":"1",}, {"lineNum":" 259","line":""}, {"lineNum":" 260","line":" // if the LIFO queue isnt locked and it has a node, try and wake up the node."}, {"lineNum":" 261","line":" if ((state & QUEUE_LOCK) == 0 and (state & QUEUE_MASK) != 0)","class":"lineCov","hits":"2","order":"2354","possible_hits":"2",}, {"lineNum":" 262","line":" self.mutex.releaseSlow();","class":"lineCov","hits":"1","order":"2359","possible_hits":"1",}, {"lineNum":" 263","line":" }"}, {"lineNum":" 264","line":" };"}, {"lineNum":" 265","line":""}, {"lineNum":" 266","line":" fn releaseSlow(self: *Mutex) void {","class":"lineCov","hits":"1","order":"2365","possible_hits":"1",}, {"lineNum":" 267","line":" @setCold(true);"}, {"lineNum":" 268","line":""}, {"lineNum":" 269","line":" // try and lock the LFIO queue to pop a node off,"}, {"lineNum":" 270","line":" // stopping altogether if its already locked or the queue is empty"}, {"lineNum":" 271","line":" var state = @atomicLoad(usize, &self.state, .Monotonic);","class":"lineCov","hits":"1","order":"2368","possible_hits":"1",}, {"lineNum":" 272","line":" while (true) : (SpinLock.loopHint(1)) {","class":"lineCov","hits":"2","order":"2371","possible_hits":"2",}, {"lineNum":" 273","line":" if (state & QUEUE_LOCK != 0 or state & QUEUE_MASK == 0)","class":"lineCov","hits":"2","order":"2373","possible_hits":"2",}, {"lineNum":" 274","line":" return;","class":"lineNoCov","hits":"0","possible_hits":"1",}, {"lineNum":" 275","line":" state = @cmpxchgWeak(usize, &self.state, state, state | QUEUE_LOCK, .Acquire, .Monotonic) orelse break;","class":"lineCov","hits":"1","order":"2377","possible_hits":"1",}, {"lineNum":" 276","line":" }"}, {"lineNum":" 277","line":""}, {"lineNum":" 278","line":" // acquired the QUEUE_LOCK, try and pop a node to wake it."}, {"lineNum":" 279","line":" // if the mutex is locked, then unset QUEUE_LOCK and let"}, {"lineNum":" 280","line":" // the thread who holds the mutex do the wake-up on unlock()"}, {"lineNum":" 281","line":" while (true) : (SpinLock.loopHint(1)) {","class":"lineCov","hits":"2","order":"2387","possible_hits":"2",}, {"lineNum":" 282","line":" if ((state & MUTEX_LOCK) != 0) {","class":"lineCov","hits":"2","order":"2388","possible_hits":"2",}, {"lineNum":" 283","line":" state = @cmpxchgWeak(usize, &self.state, state, state & ~QUEUE_LOCK, .Release, .Acquire) orelse return;","class":"lineCov","hits":"1","order":"2390","possible_hits":"1",}, {"lineNum":" 284","line":" } else {"}, {"lineNum":" 285","line":" const node = @intToPtr(*Node, state & QUEUE_MASK);","class":"linePartCov","hits":"1","order":"2395","possible_hits":"2",}, {"lineNum":" 286","line":" const new_state = @ptrToInt(node.next);","class":"lineCov","hits":"1","order":"2397","possible_hits":"1",}, {"lineNum":" 287","line":" state = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Acquire) orelse {","class":"lineCov","hits":"2","order":"2399","possible_hits":"2",}, {"lineNum":" 288","line":" node.event.set();","class":"lineCov","hits":"1","order":"2401","possible_hits":"1",}, {"lineNum":" 289","line":" return;","class":"lineCov","hits":"1","order":"2422","possible_hits":"1",}, {"lineNum":" 290","line":" };"}, {"lineNum":" 291","line":" }"}, {"lineNum":" 292","line":" }"}, {"lineNum":" 293","line":" }"}, {"lineNum":" 294","line":" }"}, {"lineNum":" 295","line":""}, {"lineNum":" 296","line":" // for platforms without a known OS blocking"}, {"lineNum":" 297","line":" // primitive, default to SpinLock for correctness"}, {"lineNum":" 298","line":"else"}, {"lineNum":" 299","line":" SpinLock;"}, {"lineNum":" 300","line":""}, {"lineNum":" 301","line":"const TestContext = struct {"}, {"lineNum":" 302","line":" mutex: *Mutex,"}, {"lineNum":" 303","line":" data: i128,"}, {"lineNum":" 304","line":""}, {"lineNum":" 305","line":" const incr_count = 10000;"}, {"lineNum":" 306","line":"};"}, {"lineNum":" 307","line":""}, {"lineNum":" 308","line":"test \"std.Mutex\" {","class":"lineCov","hits":"3","order":"2223","possible_hits":"3",}, {"lineNum":" 309","line":" var mutex = Mutex.init();","class":"lineCov","hits":"1","order":"2224","possible_hits":"1",}, {"lineNum":" 310","line":" defer mutex.deinit();","class":"linePartCov","hits":"1","order":"2432","possible_hits":"2",}, {"lineNum":" 311","line":""}, {"lineNum":" 312","line":" var context = TestContext{"}, {"lineNum":" 313","line":" .mutex = &mutex,","class":"lineCov","hits":"1","order":"2227","possible_hits":"1",}, {"lineNum":" 314","line":" .data = 0,","class":"lineCov","hits":"1","order":"2228","possible_hits":"1",}, {"lineNum":" 315","line":" };"}, {"lineNum":" 316","line":""}, {"lineNum":" 317","line":" if (builtin.single_threaded) {"}, {"lineNum":" 318","line":" worker(&context);"}, {"lineNum":" 319","line":" testing.expect(context.data == TestContext.incr_count);"}, {"lineNum":" 320","line":" } else {"}, {"lineNum":" 321","line":" const thread_count = 10;"}, {"lineNum":" 322","line":" var threads: [thread_count]*std.Thread = undefined;","class":"lineCov","hits":"1","order":"2229","possible_hits":"1",}, {"lineNum":" 323","line":" for (threads) |*t| {","class":"lineCov","hits":"2","order":"2230","possible_hits":"2",}, {"lineNum":" 324","line":" t.* = try std.Thread.spawn(&context, worker);","class":"linePartCov","hits":"1","order":"2231","possible_hits":"2",}, {"lineNum":" 325","line":" }"}, {"lineNum":" 326","line":" for (threads) |t|","class":"lineCov","hits":"2","order":"2304","possible_hits":"2",}, {"lineNum":" 327","line":" t.wait();","class":"lineCov","hits":"1","order":"2305","possible_hits":"1",}, {"lineNum":" 328","line":""}, {"lineNum":" 329","line":" testing.expect(context.data == thread_count * TestContext.incr_count);","class":"lineCov","hits":"1","order":"2431","possible_hits":"1",}, {"lineNum":" 330","line":" }"}, {"lineNum":" 331","line":"}"}, {"lineNum":" 332","line":""}, {"lineNum":" 333","line":"fn worker(ctx: *TestContext) void {","class":"lineCov","hits":"2","order":"2316","possible_hits":"2",}, {"lineNum":" 334","line":" var i: usize = 0;","class":"lineCov","hits":"1","order":"2317","possible_hits":"1",}, {"lineNum":" 335","line":" while (i != TestContext.incr_count) : (i += 1) {","class":"lineCov","hits":"2","order":"2318","possible_hits":"2",}, {"lineNum":" 336","line":" const held = ctx.mutex.acquire();","class":"lineCov","hits":"1","order":"2319","possible_hits":"1",}, {"lineNum":" 337","line":" defer held.release();","class":"lineCov","hits":"1","order":"2340","possible_hits":"1",}, {"lineNum":" 338","line":""}, {"lineNum":" 339","line":" ctx.data += 1;","class":"linePartCov","hits":"1","order":"2335","possible_hits":"2",}, {"lineNum":" 340","line":" }"}, {"lineNum":" 341","line":"}"}, ]}; var percent_low = 25;var percent_high = 75; var header = { "command" : "test", "date" : "2020-05-19 01:29:25", "instrumented" : 71, "covered" : 70,}; var merged_data = [];