Changeset: 99c9270bd729 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/99c9270bd729
Branch: properties
Log Message:
Merged with default
diffs (truncated from 446 to 300 lines):
diff --git a/MonetDB.spec b/MonetDB.spec
--- a/MonetDB.spec
+++ b/MonetDB.spec
@@ -365,6 +365,7 @@ developer.
%{_bindir}/smack00
%{_bindir}/smack01
%{_bindir}/streamcat
+%{_bindir}/testcondvar
%{_bindir}/testgetinfo
%{_bindir}/testStmtAttr
%{_bindir}/malsample.pl
diff --git a/clients/Tests/All b/clients/Tests/All
--- a/clients/Tests/All
+++ b/clients/Tests/All
@@ -3,3 +3,4 @@ HAVE_HGE&HAVE_FITS&HAVE_GEOM&HAVE_LIBR&H
!HAVE_HGE&HAVE_FITS&HAVE_GEOM&HAVE_LIBR&HAVE_LIBPY3&HAVE_NETCDF&HAVE_SHP&NOT_WIN32?MAL-signatures
NOT_WIN32&MERCURIAL?melcheck
mclient-uri
+testcondvar
diff --git a/clients/Tests/testcondvar.py b/clients/Tests/testcondvar.py
new file mode 100644
--- /dev/null
+++ b/clients/Tests/testcondvar.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+
+try:
+ subprocess.check_output("testcondvar", stderr=subprocess.STDOUT)
+except subprocess.CalledProcessError as e:
+ output = str(e.stdout, 'utf-8')
+ if not output.endswith('\n'):
+ output += '\n'
+ print(f"Test program failed with the following output:\n------",
file=sys.stderr)
+ print(f"{output}-----", file=sys.stderr)
+ sys.exit('TEST FAILED')
diff --git a/clients/examples/C/CMakeLists.txt
b/clients/examples/C/CMakeLists.txt
--- a/clients/examples/C/CMakeLists.txt
+++ b/clients/examples/C/CMakeLists.txt
@@ -45,6 +45,16 @@ if(TESTING)
monetdb_config_header
stream)
+ add_executable(testcondvar
+ testcondvar.c)
+
+ target_link_libraries(testcondvar
+ PRIVATE
+ monetdb_config_header
+ bat
+ Threads::Threads
+ )
+
add_executable(bincopydata
bincopydata.c
bincopydata.h
@@ -75,6 +85,7 @@ if(TESTING)
smack00
smack01
streamcat
+ testcondvar
bincopydata
RUNTIME
DESTINATION
@@ -89,6 +100,7 @@ if(TESTING)
$<TARGET_PDB_FILE:smack00>
$<TARGET_PDB_FILE:smack01>
$<TARGET_PDB_FILE:streamcat>
+ $<TARGET_PDB_FILE:testcondvar>
$<TARGET_PDB_FILE:bincopydata>
$<TARGET_PDB_FILE:bincopyloops>
DESTINATION ${CMAKE_INSTALL_BINDIR}
diff --git a/clients/examples/C/testcondvar.c b/clients/examples/C/testcondvar.c
new file mode 100644
--- /dev/null
+++ b/clients/examples/C/testcondvar.c
@@ -0,0 +1,183 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 1997 - July 2008 CWI, August 2008 - 2022 MonetDB B.V.
+ */
+
+#include "monetdb_config.h"
+#include "gdk.h"
+#include "gdk_system.h"
+
+#include <assert.h>
+
+#define NN (3)
+
+volatile int timeout = 100; // set this to 0 during interactive debugging
+
+/* global state protected by a lock: */
+
+MT_Lock lock = MT_LOCK_INITIALIZER(lock);
+MT_Cond condvar = MT_COND_INITIALIZER(the_condvar);
+struct state {
+ MT_Id id;
+ int ticks;
+ int permits;
+ bool terminate;
+ bool terminated;
+} states[NN] = { {0} };
+
+
+static void
+let_run(void)
+{
+ MT_lock_unset(&lock);
+
+ MT_sleep_ms(100);
+
+ int attempts = 0;
+ while (!MT_lock_try(&lock)) {
+ if (timeout > 0 && ++attempts > timeout) {
+ fprintf(stderr, "Can't get hold of the lock after %d
attempts\n", attempts);
+ abort();
+ }
+ MT_sleep_ms(10);
+ }
+
+ fprintf(stderr, "\n");
+}
+
+
+static void
+worker(void *arg)
+{
+ struct state *st = arg;
+ int id = (int)(st - &states[0]);
+ fprintf(stderr, "worker %d starting\n", id);
+
+ MT_lock_set(&lock);
+ while (1) {
+ if (st->terminate) {
+ fprintf(stderr, "worker %d terminating\n", id);
+ break;
+ }
+ if (st->permits > 0) {
+ fprintf(stderr, "worker %d ticking\n", id);
+ st->ticks++;
+ st->permits--;
+ }
+ fprintf(stderr, "worker %d waiting\n", id);
+ MT_cond_wait(&condvar, &lock);
+ fprintf(stderr, "worker %d woke up\n", id);
+ }
+ st->terminated = true;
+ MT_lock_unset(&lock);
+}
+
+
+static void clear(void)
+{
+ for (int i = 0; i < NN; i++) {
+ struct state *st = &states[i];
+ st->permits = 0;
+ st->ticks = 0;
+ }
+}
+
+
+static void
+check_impl(int line, int expected_sum_ticks, int expected_max_ticks, int
expected_sum_permits)
+{
+ int sum_ticks = 0;
+ int max_ticks = -1;
+ int sum_permits = 0;
+
+ for (int i = 0; i < NN; i++) {
+ sum_permits += states[i].permits;
+ int ticks = states[i].ticks;
+ sum_ticks += ticks;
+ if (ticks > max_ticks)
+ max_ticks = ticks;
+ }
+
+ bool good = true;
+ good &= (sum_ticks == expected_sum_ticks);
+ good &= (max_ticks == expected_max_ticks);
+ good &= (sum_permits == expected_sum_permits);
+ if (good)
+ return;
+
+ fprintf(stderr, "\nOn line %d:\n", line);
+ fprintf(stderr, "Expect sum ticks to be %d, is %d\n",
expected_sum_ticks, sum_ticks);
+ fprintf(stderr, "Expect max ticks to be %d, is %d\n",
expected_max_ticks, max_ticks);
+ fprintf(stderr, "Expect sum permits to be %d, is %d\n",
expected_sum_permits, sum_permits);
+ for (int i = 0; i < NN; i++) {
+ fprintf(stderr, "worker %d: ticks=%d permits=%d\n", i,
states[i].ticks, states[i].permits);
+ }
+ abort();
+}
+
+#define check(expected_sum, expected_max, expected_permits)
check_impl(__LINE__, expected_sum, expected_max, expected_permits)
+
+int
+main(void)
+{
+ MT_thread_init();
+
+ MT_lock_set(&lock);
+ check(0, 0, 0);
+
+ for (int i = 0; i < NN; i++) {
+ struct state *st = &states[i];
+ char name[MT_NAME_LEN];
+ snprintf(name, sizeof(name), "worker%d", i);
+ MT_create_thread(&st->id, worker, st, MT_THR_JOINABLE, name);
+ }
+ check(0, 0, 0);
+
+ let_run();
+ check(0, 0, 0);
+
+ // give them all a permit and broadcast on the condvar. they should all
run
+ for (int i = 0; i < NN; i++)
+ states[i].permits = 1;
+ let_run();
+ // haven't notified them yet:
+ check(0, 0, 3);
+ MT_cond_broadcast(&condvar);
+ let_run();
+ check(3, 1, 0);
+
+ // when using signal, we need to trigger them three times
+ clear();
+ for (int i = 0; i < NN; i++)
+ states[i].permits = 1;
+ let_run();
+ check(0, 0, 3);
+ MT_cond_signal(&condvar);
+ let_run();
+ check(1, 1, 2);
+ MT_cond_signal(&condvar);
+ let_run();
+ check(2, 1, 1);
+ MT_cond_signal(&condvar);
+ let_run();
+ check(3, 1, 0);
+
+ for (int i = 0; i < NN; i++) {
+ states[i].terminate = true;
+ }
+ MT_cond_broadcast(&condvar);
+ let_run();
+
+ for (int i = 0; i < NN; i++) {
+ fprintf(stderr, "joining worker %d\n", i);
+ MT_join_thread(states[i].id);
+ }
+ fprintf(stderr, "joined all, exiting\n");
+
+ (void)worker;
+ (void)let_run;
+ return 0;
+}
diff --git a/gdk/gdk_system.c b/gdk/gdk_system.c
--- a/gdk/gdk_system.c
+++ b/gdk/gdk_system.c
@@ -177,6 +177,8 @@ GDKlockstatistics(int what)
#endif /* LOCK_STATS */
+static void MT_thread_setcondwait(MT_Cond *cond);
+
#if !defined(HAVE_PTHREAD_H) && defined(WIN32)
static struct winthread {
struct winthread *next;
@@ -186,6 +188,7 @@ static struct winthread {
void *data;
MT_Lock *lockwait; /* lock we're waiting for */
MT_Sema *semawait; /* semaphore we're waiting for */
+ MT_Cond *condwait; /* condition variable we're waiting for */
struct winthread *joinwait; /* process we are joining with */
const char *working; /* what we're currently doing */
char algorithm[512]; /* the algorithm used in the last operation */
@@ -213,6 +216,7 @@ dump_threads(void)
w->threadname,
w->lockwait ? w->lockwait->name :
w->semawait ? w->semawait->name :
+ w->condwait ? w->condwait->name :
w->joinwait ? w->joinwait->threadname :
"nothing",
ATOMIC_GET(&w->exited) ? "exiting" :
@@ -328,6 +332,17 @@ MT_thread_setsemawait(MT_Sema *sema)
w->semawait = sema;
}
+static void
+MT_thread_setcondwait(MT_Cond *cond)
+{
+ if (threadslot == TLS_OUT_OF_INDEXES)
+ return;
+ struct winthread *w = TlsGetValue(threadslot);
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]