M:N threading
* add std.atomic.QueueMpsc.isEmpty * make std.debug.global_allocator thread-safe * std.event.Loop: now you have to choose between - initSingleThreaded - initMultiThreaded * std.event.Loop multiplexes coroutines onto kernel threads * Remove std.event.Loop.stop. Instead the event loop run() function returns once there are no pending coroutines. * fix crash in ir.cpp for calling methods under some conditions * small progress self-hosted compiler, analyzing top level declarations * Introduce std.event.Lock for synchronizing coroutines * introduce std.event.Locked(T) for data that only 1 coroutine should modify at once. * make the self hosted compiler use multi threaded event loop * make std.heap.DirectAllocator thread-safe See #174 TODO: * call sched_getaffinity instead of hard coding thread pool size 4 * support for Windows and MacOS * #1194 * #1197
This commit is contained in:
@@ -15,6 +15,8 @@ pub fn QueueMpsc(comptime T: type) type {
|
||||
|
||||
pub const Node = std.atomic.Stack(T).Node;
|
||||
|
||||
/// Not thread-safe. The call to init() must complete before any other functions are called.
|
||||
/// No deinitialization required.
|
||||
pub fn init() Self {
|
||||
return Self{
|
||||
.inboxes = []std.atomic.Stack(T){
|
||||
@@ -26,12 +28,15 @@ pub fn QueueMpsc(comptime T: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
/// Fully thread-safe. put() may be called from any thread at any time.
|
||||
pub fn put(self: *Self, node: *Node) void {
|
||||
const inbox_index = @atomicLoad(usize, &self.inbox_index, AtomicOrder.SeqCst);
|
||||
const inbox = &self.inboxes[inbox_index];
|
||||
inbox.push(node);
|
||||
}
|
||||
|
||||
/// Must be called by only 1 consumer at a time. Every call to get() and isEmpty() must complete before
|
||||
/// the next call to get().
|
||||
pub fn get(self: *Self) ?*Node {
|
||||
if (self.outbox.pop()) |node| {
|
||||
return node;
|
||||
@@ -43,6 +48,18 @@ pub fn QueueMpsc(comptime T: type) type {
|
||||
}
|
||||
return self.outbox.pop();
|
||||
}
|
||||
|
||||
/// Must be called by only 1 consumer at a time. Every call to get() and isEmpty() must complete before
|
||||
/// the next call to isEmpty().
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
if (!self.outbox.isEmpty()) return false;
|
||||
const prev_inbox_index = @atomicRmw(usize, &self.inbox_index, AtomicRmwOp.Xor, 0x1, AtomicOrder.SeqCst);
|
||||
const prev_inbox = &self.inboxes[prev_inbox_index];
|
||||
while (prev_inbox.pop()) |node| {
|
||||
self.outbox.push(node);
|
||||
}
|
||||
return self.outbox.isEmpty();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user