From cbe3791b422728b3ae692009b32836e30c37c9d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Jan 2023 13:11:17 +0000 Subject: [PATCH] Replace all queues with MPSCQueue where possible --- src/check_decl.cpp | 2 +- src/checker.cpp | 14 +++++++------- src/checker.hpp | 5 ++--- src/parser.hpp | 1 + src/queue.cpp | 24 +++++++++++++++--------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index a21461454..f0059424e 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1010,7 +1010,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (ac.deferred_procedure.entity != nullptr) { e->Procedure.deferred_procedure = ac.deferred_procedure; - mpmc_enqueue(&ctx->checker->procs_with_deferred_to_check, e); + mpsc_enqueue(&ctx->checker->procs_with_deferred_to_check, e); } if (is_foreign) { diff --git a/src/checker.cpp b/src/checker.cpp index 354e033aa..8d6462f8b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1254,12 +1254,12 @@ gb_internal void init_checker(Checker *c) { c->info.checker = c; TIME_SECTION("init proc queues"); - mpmc_init(&c->procs_with_deferred_to_check, a, 1<<10); + mpsc_init(&c->procs_with_deferred_to_check, a); //, 1<<10); // NOTE(bill): 1 Mi elements should be enough on average array_init(&c->procs_to_check, heap_allocator(), 0, 1<<20); - mpmc_init(&c->global_untyped_queue, a, 1<<20); + mpsc_init(&c->global_untyped_queue, a); // , 1<<20); c->builtin_ctx = make_checker_context(c); } @@ -1270,7 +1270,7 @@ gb_internal void destroy_checker(Checker *c) { destroy_checker_context(&c->builtin_ctx); array_free(&c->procs_to_check); - mpmc_destroy(&c->global_untyped_queue); + mpsc_destroy(&c->global_untyped_queue); } @@ -4647,10 +4647,10 @@ gb_internal GB_COMPARE_PROC(sort_file_by_name) { gb_internal void check_create_file_scopes(Checker *c) { for_array(i, c->parser->packages) { AstPackage *pkg = c->parser->packages[i]; - isize total_pkg_decl_count = 0; gb_sort_array(pkg->files.data, pkg->files.count, sort_file_by_name); + isize total_pkg_decl_count = 0; for_array(j, pkg->files) { AstFile *f = pkg->files[j]; string_map_set(&c->info.files, f->fullpath, f); @@ -5382,14 +5382,14 @@ gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap Ast *expr = entry.key; ExprInfo *info = entry.value; if (expr != nullptr && info != nullptr) { - mpmc_enqueue(&cinfo->checker->global_untyped_queue, UntypedExprInfo{expr, info}); + mpsc_enqueue(&cinfo->checker->global_untyped_queue, UntypedExprInfo{expr, info}); } } map_clear(untyped); } gb_internal void check_deferred_procedures(Checker *c) { - for (Entity *src = nullptr; mpmc_dequeue(&c->procs_with_deferred_to_check, &src); /**/) { + for (Entity *src = nullptr; mpsc_dequeue(&c->procs_with_deferred_to_check, &src); /**/) { GB_ASSERT(src->kind == Entity_Procedure); DeferredProcedureKind dst_kind = src->Procedure.deferred_procedure.kind; @@ -5831,7 +5831,7 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("add untyped expression values"); // Add untyped expression values - for (UntypedExprInfo u = {}; mpmc_dequeue(&c->global_untyped_queue, &u); /**/) { + for (UntypedExprInfo u = {}; mpsc_dequeue(&c->global_untyped_queue, &u); /**/) { GB_ASSERT(u.expr != nullptr && u.info != nullptr); if (is_type_typed(u.info->type)) { compiler_error("%s (type %s) is typed!", expr_to_string(u.expr), type_to_string(u.info->type)); diff --git a/src/checker.hpp b/src/checker.hpp index 7c545a716..595618e1d 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -446,11 +446,10 @@ struct Checker { CheckerContext builtin_ctx; - MPMCQueue procs_with_deferred_to_check; + MPSCQueue procs_with_deferred_to_check; Array procs_to_check; - // TODO(bill): Technically MPSC queue - MPMCQueue global_untyped_queue; + MPSCQueue global_untyped_queue; }; diff --git a/src/parser.hpp b/src/parser.hpp index d81194831..6782a9248 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -176,6 +176,7 @@ struct AstPackage { BlockingMutex foreign_files_mutex; BlockingMutex type_and_value_mutex; + // NOTE(bill): This must be a MPMCQueue MPMCQueue exported_entity_queue; // NOTE(bill): Created/set in checker diff --git a/src/queue.cpp b/src/queue.cpp index d3fd69c52..5585b772f 100644 --- a/src/queue.cpp +++ b/src/queue.cpp @@ -10,11 +10,12 @@ struct MPSCNode { // template struct MPSCQueue { + gbAllocator allocator; + std::atomic count; + std::atomic *> head; std::atomic *> tail; - std::atomic count; MPSCNode sentinel; - gbAllocator allocator; }; template gb_internal void mpsc_init (MPSCQueue *q, gbAllocator const &allocator); @@ -29,6 +30,7 @@ gb_internal void mpsc_init(MPSCQueue *q, gbAllocator const &allocator) { q->count.store(0, std::memory_order_relaxed); q->head.store(&q->sentinel, std::memory_order_relaxed); q->tail.store(&q->sentinel, std::memory_order_relaxed); + q->sentinel.next.store(nullptr, std::memory_order_relaxed); } @@ -36,14 +38,20 @@ template gb_internal void mpsc_destroy(MPSCQueue *q) { while (mpsc_dequeue(q, (T *)nullptr)) {} // DO NOTHING for the time being + // free the nodes later } template gb_internal MPSCNode *mpsc_alloc_node(MPSCQueue *q, T const &value) { - auto node = gb_alloc_item(q->allocator, MPSCNode); - node->value = value; - return node; + auto new_node = gb_alloc_item(q->allocator, MPSCNode); + new_node->value = value; + return new_node; +} + +template +gb_internal void mpsc_free_node(MPSCQueue *q, MPSCNode *node) { + // TODO(bill): reuse the free nodes } template @@ -68,10 +76,8 @@ gb_internal bool mpsc_dequeue(MPSCQueue *q, T *value_) { auto next = tail->next.load(std::memory_order_relaxed); if (next) { q->tail.store(next, std::memory_order_relaxed); - // `tail` is now "dead" and needs to be "freed" - tail->value = next->value; - T value = tail->value; - if (value_) *value_ = value; + if (value_) *value_ = next->value; + mpsc_free_node(q, tail); q->count.fetch_sub(1, std::memory_order_acq_rel); return true; }