From cfa4a289ec506dab1aac53cef1dd79806dbfd595 Mon Sep 17 00:00:00 2001 From: Gianluca Martino Date: Wed, 19 Feb 2025 10:39:40 +0100 Subject: [PATCH 1/4] Adding missing include. --- vpi/vcd_priv2.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/vpi/vcd_priv2.cc b/vpi/vcd_priv2.cc index a41c5b5a41..dd74ba7234 100644 --- a/vpi/vcd_priv2.cc +++ b/vpi/vcd_priv2.cc @@ -23,6 +23,7 @@ # include # include # include +# include # include # include From 9afaf6f136d9d1149ad4a11aa0d58d39342b2328 Mon Sep 17 00:00:00 2001 From: Gianluca Martino Date: Wed, 19 Feb 2025 11:10:23 +0100 Subject: [PATCH 2/4] Removed pthread dependency in vcd_priv2.cc --- vpi/vcd_priv2.cc | 73 +++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/vpi/vcd_priv2.cc b/vpi/vcd_priv2.cc index dd74ba7234..f812cec789 100644 --- a/vpi/vcd_priv2.cc +++ b/vpi/vcd_priv2.cc @@ -21,11 +21,13 @@ # include # include # include -# include # include # include # include # include +# include +# include +# include /* Nexus Id cache @@ -84,7 +86,7 @@ extern "C" void vcd_scope_names_delete(void) vcd_scope_names_set.clear(); } -static pthread_t work_thread; +static std::thread work_thread; static const unsigned WORK_QUEUE_SIZE = 128*1024; static const unsigned WORK_QUEUE_BATCH_MIN = 4*1024; @@ -94,10 +96,10 @@ static struct vcd_work_item_s work_queue[WORK_QUEUE_SIZE]; static volatile unsigned work_queue_next = 0; static volatile unsigned work_queue_fill = 0; -static pthread_mutex_t work_queue_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t work_queue_is_empty_sig = PTHREAD_COND_INITIALIZER; -static pthread_cond_t work_queue_notempty_sig = PTHREAD_COND_INITIALIZER; -static pthread_cond_t work_queue_minfree_sig = PTHREAD_COND_INITIALIZER; +static std::mutex work_queue_mutex; +static std::condition_variable work_queue_is_empty_sig; +static std::condition_variable work_queue_notempty_sig; +static std::condition_variable work_queue_minfree_sig; extern "C" struct vcd_work_item_s* vcd_work_thread_peek(void) @@ -108,10 +110,8 @@ extern "C" struct vcd_work_item_s* vcd_work_thread_peek(void) // one item that I can peek at. I only need to lock if I must // wait for the work_queue_fill to become non-zero. if (work_queue_fill == 0) { - pthread_mutex_lock(&work_queue_mutex); - while (work_queue_fill == 0) - pthread_cond_wait(&work_queue_notempty_sig, &work_queue_mutex); - pthread_mutex_unlock(&work_queue_mutex); + std::unique_lock lock(work_queue_mutex); + work_queue_notempty_sig.wait(lock, []{ return work_queue_fill != 0; }); } return work_queue + work_queue_next; @@ -119,7 +119,7 @@ extern "C" struct vcd_work_item_s* vcd_work_thread_peek(void) extern "C" void vcd_work_thread_pop(void) { - pthread_mutex_lock(&work_queue_mutex); + std::lock_guard lock(work_queue_mutex); unsigned use_fill = work_queue_fill - 1; work_queue_fill = use_fill; @@ -137,11 +137,10 @@ extern "C" void vcd_work_thread_pop(void) work_queue_next = use_next; if (use_fill == WORK_QUEUE_SIZE-WORK_QUEUE_BATCH_MIN) - pthread_cond_signal(&work_queue_minfree_sig); + work_queue_minfree_sig.notify_one(); else if (use_fill == 0) - pthread_cond_signal(&work_queue_is_empty_sig); + work_queue_is_empty_sig.notify_one(); - pthread_mutex_unlock(&work_queue_mutex); } /* @@ -158,33 +157,34 @@ static unsigned current_batch_base = 0; extern "C" void vcd_work_start( void* (*fun) (void*), void*arg ) { - pthread_create(&work_thread, 0, fun, arg); + work_thread = std::thread(fun, arg); } static struct vcd_work_item_s* grab_item(void) { if (current_batch_alloc == 0) { - pthread_mutex_lock(&work_queue_mutex); - while ((WORK_QUEUE_SIZE-work_queue_fill) < WORK_QUEUE_BATCH_MIN) - pthread_cond_wait(&work_queue_minfree_sig, &work_queue_mutex); - - current_batch_base = work_queue_next + work_queue_fill; - current_batch_alloc = WORK_QUEUE_SIZE - work_queue_fill; - - pthread_mutex_unlock(&work_queue_mutex); - - if (current_batch_base >= WORK_QUEUE_SIZE) - current_batch_base -= WORK_QUEUE_SIZE; - if (current_batch_alloc > WORK_QUEUE_BATCH_MAX) - current_batch_alloc = WORK_QUEUE_BATCH_MAX; - current_batch_cnt = 0; + { + std::unique_lock lock(work_queue_mutex); + work_queue_minfree_sig.wait(lock, [] { + return (WORK_QUEUE_SIZE - work_queue_fill) >= WORK_QUEUE_BATCH_MIN; + }); + + current_batch_base = work_queue_next + work_queue_fill; + current_batch_alloc = WORK_QUEUE_SIZE - work_queue_fill; + } + + if (current_batch_base >= WORK_QUEUE_SIZE) + current_batch_base -= WORK_QUEUE_SIZE; + if (current_batch_alloc > WORK_QUEUE_BATCH_MAX) + current_batch_alloc = WORK_QUEUE_BATCH_MAX; + current_batch_cnt = 0; } assert(current_batch_cnt < current_batch_alloc); unsigned cur = current_batch_base + current_batch_cnt; if (cur >= WORK_QUEUE_SIZE) - cur -= WORK_QUEUE_SIZE; + cur -= WORK_QUEUE_SIZE; // Write the new timestamp into the work item. struct vcd_work_item_s*cell = work_queue + cur; @@ -194,7 +194,7 @@ static struct vcd_work_item_s* grab_item(void) static void end_batch(void) { - pthread_mutex_lock(&work_queue_mutex); + std::lock_guard lock(work_queue_mutex); unsigned use_fill = work_queue_fill; bool was_empty_flag = (use_fill==0) && (current_batch_cnt > 0); @@ -206,9 +206,8 @@ static void end_batch(void) current_batch_cnt = 0; if (was_empty_flag) - pthread_cond_signal(&work_queue_notempty_sig); + work_queue_notempty_sig.notify_one(); - pthread_mutex_unlock(&work_queue_mutex); } static inline void unlock_item(bool flush_batch =false) @@ -224,10 +223,8 @@ extern "C" void vcd_work_sync(void) end_batch(); if (work_queue_fill > 0) { - pthread_mutex_lock(&work_queue_mutex); - while (work_queue_fill > 0) - pthread_cond_wait(&work_queue_is_empty_sig, &work_queue_mutex); - pthread_mutex_unlock(&work_queue_mutex); + std::unique_lock lock(work_queue_mutex); + work_queue_is_empty_sig.wait(lock, []{ return !(work_queue_fill > 0); }); } } @@ -282,5 +279,5 @@ extern "C" void vcd_work_terminate(void) struct vcd_work_item_s*cell = grab_item(); cell->type = WT_TERMINATE; unlock_item(true); - pthread_join(work_thread, 0); + work_thread.join(); } From 25104ca2a80852c32ba213b23ecf0442af682ced Mon Sep 17 00:00:00 2001 From: Gianluca Martino Date: Tue, 25 Feb 2025 12:54:59 +0100 Subject: [PATCH 3/4] work_queue_fill is an unsigned so we can simplify the condition variable predicate. Co-authored-by: Lars-Peter Clausen --- vpi/vcd_priv2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpi/vcd_priv2.cc b/vpi/vcd_priv2.cc index f812cec789..80e122b0d9 100644 --- a/vpi/vcd_priv2.cc +++ b/vpi/vcd_priv2.cc @@ -224,7 +224,7 @@ extern "C" void vcd_work_sync(void) if (work_queue_fill > 0) { std::unique_lock lock(work_queue_mutex); - work_queue_is_empty_sig.wait(lock, []{ return !(work_queue_fill > 0); }); + work_queue_is_empty_sig.wait(lock, []{ return work_queue_fill == 0; }); } } From 60f5026ae42b2ec3085a08bca25a0465046181a5 Mon Sep 17 00:00:00 2001 From: Gianluca Martino Date: Tue, 25 Feb 2025 16:06:32 +0100 Subject: [PATCH 4/4] Fixed double join in lxt2 writer. --- vpi/sys_lxt2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index ce68387ec9..7a27083708 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -467,7 +467,6 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static void *close_dumpfile(void) { - vcd_work_terminate(); lxt2_wr_close(dump_file); dump_file = NULL; return NULL;