commit
686ce7ab03
@ -1,58 +0,0 @@
|
|||||||
From 136211f67b5ba804fd0e02603bcef61ac47dbc16 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
Date: Sun, 9 Dec 2018 06:31:57 -0500
|
|
||||||
Subject: [PATCH 06/15] Cleanup: workqueue: update comments referring to
|
|
||||||
call-rcu
|
|
||||||
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
src/workqueue.c | 12 +++++-------
|
|
||||||
1 file changed, 5 insertions(+), 7 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/workqueue.c b/src/workqueue.c
|
|
||||||
index 8561a7a..db0c63a 100644
|
|
||||||
--- a/src/workqueue.c
|
|
||||||
+++ b/src/workqueue.c
|
|
||||||
@@ -37,7 +37,6 @@
|
|
||||||
|
|
||||||
#include "compat-getcpu.h"
|
|
||||||
#include "urcu/wfcqueue.h"
|
|
||||||
-#include "urcu-call-rcu.h"
|
|
||||||
#include "urcu-pointer.h"
|
|
||||||
#include "urcu/list.h"
|
|
||||||
#include "urcu/futex.h"
|
|
||||||
@@ -55,10 +54,9 @@
|
|
||||||
struct urcu_workqueue {
|
|
||||||
/*
|
|
||||||
* We do not align head on a different cache-line than tail
|
|
||||||
- * mainly because call_rcu callback-invocation threads use
|
|
||||||
- * batching ("splice") to get an entire list of callbacks, which
|
|
||||||
- * effectively empties the queue, and requires to touch the tail
|
|
||||||
- * anyway.
|
|
||||||
+ * mainly because workqueue threads use batching ("splice") to
|
|
||||||
+ * get an entire list of callbacks, which effectively empties
|
|
||||||
+ * the queue, and requires to touch the tail anyway.
|
|
||||||
*/
|
|
||||||
struct cds_wfcq_tail cbs_tail;
|
|
||||||
struct cds_wfcq_head cbs_head;
|
|
||||||
@@ -244,7 +242,7 @@ static void *workqueue_thread(void *arg)
|
|
||||||
uatomic_dec(&workqueue->futex);
|
|
||||||
/*
|
|
||||||
* Decrement futex before reading
|
|
||||||
- * call_rcu list.
|
|
||||||
+ * urcu_work list.
|
|
||||||
*/
|
|
||||||
cmm_smp_mb();
|
|
||||||
} else {
|
|
||||||
@@ -258,7 +256,7 @@ static void *workqueue_thread(void *arg)
|
|
||||||
}
|
|
||||||
if (!rt) {
|
|
||||||
/*
|
|
||||||
- * Read call_rcu list before write futex.
|
|
||||||
+ * Read urcu_work list before write futex.
|
|
||||||
*/
|
|
||||||
cmm_smp_mb();
|
|
||||||
uatomic_set(&workqueue->futex, 0);
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
From b197ce865b0de8c475f3ddeadeae3a66b15ace21 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Michael Jeanson <mjeanson@efficios.com>
|
|
||||||
Date: Fri, 23 Nov 2018 15:27:04 -0500
|
|
||||||
Subject: [PATCH 01/15] Fix: compat_futex_noasync on Cygwin
|
|
||||||
|
|
||||||
The futex_noasync compat code uses a weak symbol to share state across
|
|
||||||
different shared object which is not possible on Windows with the
|
|
||||||
Portable Executable format. Use the async compat code for both cases.
|
|
||||||
|
|
||||||
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
include/urcu/futex.h | 19 +++++++++++++++++++
|
|
||||||
1 file changed, 19 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/include/urcu/futex.h b/include/urcu/futex.h
|
|
||||||
index 0486ff6..753df62 100644
|
|
||||||
--- a/include/urcu/futex.h
|
|
||||||
+++ b/include/urcu/futex.h
|
|
||||||
@@ -102,6 +102,25 @@ static inline int futex_async(int32_t *uaddr, int op, int32_t val,
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+#elif defined(__CYGWIN__)
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * The futex_noasync compat code uses a weak symbol to share state across
|
|
||||||
+ * different shared object which is not possible on Windows with the
|
|
||||||
+ * Portable Executable format. Use the async compat code for both cases.
|
|
||||||
+ */
|
|
||||||
+static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
|
|
||||||
+ const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
|
|
||||||
+{
|
|
||||||
+ return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline int futex_async(int32_t *uaddr, int op, int32_t val,
|
|
||||||
+ const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
|
|
||||||
+{
|
|
||||||
+ return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
From 79eca0929fc50a668a15937b5bf4d1cb97049de8 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?=
|
|
||||||
<jeremie.galarneau@efficios.com>
|
|
||||||
Date: Fri, 7 Dec 2018 17:06:38 -0500
|
|
||||||
Subject: [PATCH 09/15] Fix: don't wait after completion of a work queue job
|
|
||||||
batch
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
As indicated in the previous patch of this series, waiting on
|
|
||||||
completion of a job batch from the work queue artificially increases
|
|
||||||
the latency of the work queue.
|
|
||||||
|
|
||||||
The previous patch removed the wait that is performed when the
|
|
||||||
work queue is observed to be empty and was observed as the cause of a
|
|
||||||
performance problem.
|
|
||||||
|
|
||||||
It is likely that waiting when the queue is observed to be non-empty
|
|
||||||
is similarly unintended. Note that I have not observed such a problem
|
|
||||||
myself.
|
|
||||||
|
|
||||||
If a workqueue user even need the explicit delay for batching (e.g. if
|
|
||||||
a call-rcu implementation would ever use the workqueue worker thread),
|
|
||||||
it can add it within the worker_before_wait_fct callback received as
|
|
||||||
argument from workqueue creation.
|
|
||||||
|
|
||||||
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
src/workqueue.c | 2 --
|
|
||||||
1 file changed, 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/workqueue.c b/src/workqueue.c
|
|
||||||
index 0b1a9ea..39d0e07 100644
|
|
||||||
--- a/src/workqueue.c
|
|
||||||
+++ b/src/workqueue.c
|
|
||||||
@@ -244,8 +244,6 @@ static void *workqueue_thread(void *arg)
|
|
||||||
* urcu_work list.
|
|
||||||
*/
|
|
||||||
cmm_smp_mb();
|
|
||||||
- } else {
|
|
||||||
- (void) poll(NULL, 0, 10);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(void) poll(NULL, 0, 10);
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
From d3e42beb106479eae7c234bb0aeacce92661ca7a Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?=
|
|
||||||
<jeremie.galarneau@efficios.com>
|
|
||||||
Date: Fri, 7 Dec 2018 17:06:37 -0500
|
|
||||||
Subject: [PATCH 08/15] Fix: don't wait after completion of job batch if work
|
|
||||||
queue is empty
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
On completion of a batch of jobs from the work queue, a wait of 10
|
|
||||||
ms (using poll()) is performed if there is no work present in the
|
|
||||||
work queue before waiting on its futex.
|
|
||||||
|
|
||||||
The work queue thread's structure is inspired by the call-rcu thread.
|
|
||||||
In the context of the call-rcu thread, my understanding is that the
|
|
||||||
intention is to ensure that the thread does not continuously wake-up
|
|
||||||
to process a single queued item. This is fine as an application should
|
|
||||||
not wait for a call-rcu job to be executed (or at least I don't see a
|
|
||||||
use-case for that).
|
|
||||||
|
|
||||||
In the context of the work queue, waiting for more work to be available
|
|
||||||
artificially slows down the execution of work on which an application
|
|
||||||
may wait.
|
|
||||||
|
|
||||||
I have observed a case where LTTng's session daemon's shutdown is
|
|
||||||
takes around 4 seconds as a large number of cds_lfht objects are
|
|
||||||
destroyed. Removing the wait reduces the duration of this phase of the
|
|
||||||
shut-down to almost ~10ms.
|
|
||||||
|
|
||||||
If a workqueue user even need the explicit delay for batching (e.g. if
|
|
||||||
a call-rcu implementation would ever use the workqueue worker thread),
|
|
||||||
it can add it within the worker_before_wait_fct callback received as
|
|
||||||
argument from workqueue creation.
|
|
||||||
|
|
||||||
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
src/workqueue.c | 1 -
|
|
||||||
1 file changed, 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/workqueue.c b/src/workqueue.c
|
|
||||||
index 6707ffe..0b1a9ea 100644
|
|
||||||
--- a/src/workqueue.c
|
|
||||||
+++ b/src/workqueue.c
|
|
||||||
@@ -238,7 +238,6 @@ static void *workqueue_thread(void *arg)
|
|
||||||
if (cds_wfcq_empty(&workqueue->cbs_head,
|
|
||||||
&workqueue->cbs_tail)) {
|
|
||||||
futex_wait(&workqueue->futex);
|
|
||||||
- (void) poll(NULL, 0, 10);
|
|
||||||
uatomic_dec(&workqueue->futex);
|
|
||||||
/*
|
|
||||||
* Decrement futex before reading
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
From 0aa1fccd3aff5f5a7717c166f7bfbe864d041f23 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?=
|
|
||||||
<jeremie.galarneau@efficios.com>
|
|
||||||
Date: Fri, 7 Dec 2018 17:06:36 -0500
|
|
||||||
Subject: [PATCH 05/15] Fix: mixup between URCU_WORKQUEUE_RT and
|
|
||||||
URCU_CALL_RCU_RT
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
The work queue implementation is derived from the call-rcu thread. A
|
|
||||||
number of references seem to have been left in place when adapting the
|
|
||||||
code for its new purpose.
|
|
||||||
|
|
||||||
The URCU_CALL_RCU_RT flag is used by wake_worker_thread() while the
|
|
||||||
rest of the workqueue.c code uses URCU_WORKQUEUE_RT to determine if
|
|
||||||
the work queue was configured in real-time mode. Both flags are defined
|
|
||||||
to the same value (0x1) and the current internal user of the
|
|
||||||
work queue (lfht) never specifies any flags.
|
|
||||||
|
|
||||||
In practice, this does not cause any problem, but this mixup should
|
|
||||||
be fixed nevertheless.
|
|
||||||
|
|
||||||
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
src/workqueue.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/workqueue.c b/src/workqueue.c
|
|
||||||
index 17ea835..8561a7a 100644
|
|
||||||
--- a/src/workqueue.c
|
|
||||||
+++ b/src/workqueue.c
|
|
||||||
@@ -309,7 +309,7 @@ struct urcu_workqueue *urcu_workqueue_create(unsigned long flags,
|
|
||||||
|
|
||||||
static void wake_worker_thread(struct urcu_workqueue *workqueue)
|
|
||||||
{
|
|
||||||
- if (!(_CMM_LOAD_SHARED(workqueue->flags) & URCU_CALL_RCU_RT))
|
|
||||||
+ if (!(_CMM_LOAD_SHARED(workqueue->flags) & URCU_WORKQUEUE_RT))
|
|
||||||
futex_wake_up(&workqueue->futex);
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
From 803e59362b6d94edff3a36f47a9da3e8dca4bde2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?=
|
|
||||||
<jeremie.galarneau@efficios.com>
|
|
||||||
Date: Fri, 7 Dec 2018 17:06:39 -0500
|
|
||||||
Subject: [PATCH 10/15] Fix: only wait if work queue is empty in real-time mode
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Unconditionally waiting for 10 ms after the completion of every batch
|
|
||||||
of jobs of the work queue in real-time mode appears to be a behaviour
|
|
||||||
inherited from the call-rcu thread.
|
|
||||||
|
|
||||||
While this is a fair trade-off in the context of call-rcu, it is less
|
|
||||||
evident that it is desirable in the context of a general-purpose
|
|
||||||
work queue. Waiting when work is available artificially degrades the
|
|
||||||
latency characteristics of the work queue.
|
|
||||||
|
|
||||||
If a workqueue user even need the explicit delay for batching (e.g. if
|
|
||||||
a call-rcu implementation would ever use the workqueue worker thread),
|
|
||||||
it can add it within the worker_before_wait_fct callback received as
|
|
||||||
argument from workqueue creation.
|
|
||||||
|
|
||||||
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
src/workqueue.c | 5 ++++-
|
|
||||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/workqueue.c b/src/workqueue.c
|
|
||||||
index 39d0e07..14957a0 100644
|
|
||||||
--- a/src/workqueue.c
|
|
||||||
+++ b/src/workqueue.c
|
|
||||||
@@ -246,7 +246,10 @@ static void *workqueue_thread(void *arg)
|
|
||||||
cmm_smp_mb();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
- (void) poll(NULL, 0, 10);
|
|
||||||
+ if (cds_wfcq_empty(&workqueue->cbs_head,
|
|
||||||
+ &workqueue->cbs_tail)) {
|
|
||||||
+ (void) poll(NULL, 0, 10);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
if (workqueue->worker_after_wake_up_fct)
|
|
||||||
workqueue->worker_after_wake_up_fct(workqueue, workqueue->priv);
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,224 +0,0 @@
|
|||||||
From eec2f6a5c353f28bb74e4a3f96a3da5a50f25574 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Michael Jeanson <mjeanson@efficios.com>
|
|
||||||
Date: Fri, 23 Nov 2018 16:47:18 -0500
|
|
||||||
Subject: [PATCH 02/15] Fix: pthread_rwlock initialization on Cygwin
|
|
||||||
|
|
||||||
On Cygwin the PTHREAD_RWLOCK_INITIALIZER macro is not
|
|
||||||
sufficient to get a properly initialized pthread_rwlock_t
|
|
||||||
struct. Use the pthread_rwlock_init function instead which
|
|
||||||
should work on all platforms.
|
|
||||||
|
|
||||||
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
tests/benchmark/test_rwlock.c | 51 ++++++++++++++++++++++++----
|
|
||||||
tests/benchmark/test_rwlock_timing.c | 50 +++++++++++++++++++++++----
|
|
||||||
2 files changed, 88 insertions(+), 13 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/tests/benchmark/test_rwlock.c b/tests/benchmark/test_rwlock.c
|
|
||||||
index 4448597..f95e4e1 100644
|
|
||||||
--- a/tests/benchmark/test_rwlock.c
|
|
||||||
+++ b/tests/benchmark/test_rwlock.c
|
|
||||||
@@ -48,7 +48,11 @@ struct test_array {
|
|
||||||
int a;
|
|
||||||
};
|
|
||||||
|
|
||||||
-pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
|
|
||||||
+/*
|
|
||||||
+ * static rwlock initializer is broken on Cygwin. Use runtime
|
|
||||||
+ * initialization.
|
|
||||||
+ */
|
|
||||||
+pthread_rwlock_t lock;
|
|
||||||
|
|
||||||
static volatile int test_go, test_stop;
|
|
||||||
|
|
||||||
@@ -173,14 +177,25 @@ void *thr_reader(void *_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
- int a;
|
|
||||||
+ int a, ret;
|
|
||||||
+
|
|
||||||
+ ret = pthread_rwlock_rdlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "reader pthread_rwlock_rdlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- pthread_rwlock_rdlock(&lock);
|
|
||||||
a = test_array.a;
|
|
||||||
assert(a == 8);
|
|
||||||
if (caa_unlikely(rduration))
|
|
||||||
loop_sleep(rduration);
|
|
||||||
- pthread_rwlock_unlock(&lock);
|
|
||||||
+
|
|
||||||
+ ret = pthread_rwlock_unlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "reader pthread_rwlock_unlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
URCU_TLS(nr_reads)++;
|
|
||||||
if (caa_unlikely(!test_duration_read()))
|
|
||||||
break;
|
|
||||||
@@ -208,12 +223,25 @@ void *thr_writer(void *_count)
|
|
||||||
cmm_smp_mb();
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
- pthread_rwlock_wrlock(&lock);
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = pthread_rwlock_wrlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "writer pthread_rwlock_wrlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
test_array.a = 0;
|
|
||||||
test_array.a = 8;
|
|
||||||
if (caa_unlikely(wduration))
|
|
||||||
loop_sleep(wduration);
|
|
||||||
- pthread_rwlock_unlock(&lock);
|
|
||||||
+
|
|
||||||
+ ret = pthread_rwlock_unlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "writer pthread_rwlock_unlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
URCU_TLS(nr_writes)++;
|
|
||||||
if (caa_unlikely(!test_duration_write()))
|
|
||||||
break;
|
|
||||||
@@ -321,6 +349,12 @@ int main(int argc, char **argv)
|
|
||||||
printf_verbose("thread %-6s, tid %lu\n",
|
|
||||||
"main", urcu_get_thread_id());
|
|
||||||
|
|
||||||
+ err = pthread_rwlock_init(&lock, NULL);
|
|
||||||
+ if (err != 0) {
|
|
||||||
+ fprintf(stderr, "pthread_rwlock_init: (%d) %s\n", err, strerror(err));
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
tid_reader = calloc(nr_readers, sizeof(*tid_reader));
|
|
||||||
tid_writer = calloc(nr_writers, sizeof(*tid_writer));
|
|
||||||
count_reader = calloc(nr_readers, sizeof(*count_reader));
|
|
||||||
@@ -371,6 +405,11 @@ int main(int argc, char **argv)
|
|
||||||
nr_writers, wdelay, tot_reads, tot_writes,
|
|
||||||
tot_reads + tot_writes);
|
|
||||||
|
|
||||||
+ err = pthread_rwlock_destroy(&lock);
|
|
||||||
+ if (err != 0) {
|
|
||||||
+ fprintf(stderr, "pthread_rwlock_destroy: (%d) %s\n", err, strerror(err));
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
free(tid_reader);
|
|
||||||
free(tid_writer);
|
|
||||||
free(count_reader);
|
|
||||||
diff --git a/tests/benchmark/test_rwlock_timing.c b/tests/benchmark/test_rwlock_timing.c
|
|
||||||
index a52da38..bc51c45 100644
|
|
||||||
--- a/tests/benchmark/test_rwlock_timing.c
|
|
||||||
+++ b/tests/benchmark/test_rwlock_timing.c
|
|
||||||
@@ -42,7 +42,11 @@ struct test_array {
|
|
||||||
int a;
|
|
||||||
};
|
|
||||||
|
|
||||||
-pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
|
|
||||||
+/*
|
|
||||||
+ * static rwlock initializer is broken on Cygwin. Use runtime
|
|
||||||
+ * initialization.
|
|
||||||
+ */
|
|
||||||
+pthread_rwlock_t lock;
|
|
||||||
|
|
||||||
static struct test_array test_array = { 8 };
|
|
||||||
|
|
||||||
@@ -65,7 +69,7 @@ static caa_cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
|
|
||||||
|
|
||||||
void *thr_reader(void *arg)
|
|
||||||
{
|
|
||||||
- int i, j;
|
|
||||||
+ int i, j, ret;
|
|
||||||
caa_cycles_t time1, time2;
|
|
||||||
|
|
||||||
printf("thread_begin %s, tid %lu\n",
|
|
||||||
@@ -75,9 +79,19 @@ void *thr_reader(void *arg)
|
|
||||||
time1 = caa_get_cycles();
|
|
||||||
for (i = 0; i < OUTER_READ_LOOP; i++) {
|
|
||||||
for (j = 0; j < INNER_READ_LOOP; j++) {
|
|
||||||
- pthread_rwlock_rdlock(&lock);
|
|
||||||
+ ret = pthread_rwlock_rdlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "reader pthread_rwlock_rdlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
assert(test_array.a == 8);
|
|
||||||
- pthread_rwlock_unlock(&lock);
|
|
||||||
+
|
|
||||||
+ ret = pthread_rwlock_unlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "reader pthread_rwlock_unlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time2 = caa_get_cycles();
|
|
||||||
@@ -93,7 +107,7 @@ void *thr_reader(void *arg)
|
|
||||||
|
|
||||||
void *thr_writer(void *arg)
|
|
||||||
{
|
|
||||||
- int i, j;
|
|
||||||
+ int i, j, ret;
|
|
||||||
caa_cycles_t time1, time2;
|
|
||||||
|
|
||||||
printf("thread_begin %s, tid %lu\n",
|
|
||||||
@@ -103,9 +117,20 @@ void *thr_writer(void *arg)
|
|
||||||
for (i = 0; i < OUTER_WRITE_LOOP; i++) {
|
|
||||||
for (j = 0; j < INNER_WRITE_LOOP; j++) {
|
|
||||||
time1 = caa_get_cycles();
|
|
||||||
- pthread_rwlock_wrlock(&lock);
|
|
||||||
+ ret = pthread_rwlock_wrlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "writer pthread_rwlock_wrlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
test_array.a = 8;
|
|
||||||
- pthread_rwlock_unlock(&lock);
|
|
||||||
+
|
|
||||||
+ ret = pthread_rwlock_unlock(&lock);
|
|
||||||
+ if (ret) {
|
|
||||||
+ fprintf(stderr, "writer pthread_rwlock_unlock: %s\n", strerror(ret));
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
time2 = caa_get_cycles();
|
|
||||||
writer_time[(unsigned long)arg] += time2 - time1;
|
|
||||||
usleep(1);
|
|
||||||
@@ -133,6 +158,12 @@ int main(int argc, char **argv)
|
|
||||||
num_read = atoi(argv[1]);
|
|
||||||
num_write = atoi(argv[2]);
|
|
||||||
|
|
||||||
+ err = pthread_rwlock_init(&lock, NULL);
|
|
||||||
+ if (err != 0) {
|
|
||||||
+ fprintf(stderr, "pthread_rwlock_init: (%d) %s\n", err, strerror(err));
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
reader_time = calloc(num_read, sizeof(*reader_time));
|
|
||||||
writer_time = calloc(num_write, sizeof(*writer_time));
|
|
||||||
tid_reader = calloc(num_read, sizeof(*tid_reader));
|
|
||||||
@@ -173,6 +204,11 @@ int main(int argc, char **argv)
|
|
||||||
printf("Time per write : %g cycles\n",
|
|
||||||
(double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
|
|
||||||
|
|
||||||
+ err = pthread_rwlock_destroy(&lock);
|
|
||||||
+ if (err != 0) {
|
|
||||||
+ fprintf(stderr, "pthread_rwlock_destroy: (%d) %s\n", err, strerror(err));
|
|
||||||
+ exit(1);
|
|
||||||
+ }
|
|
||||||
free(reader_time);
|
|
||||||
free(writer_time);
|
|
||||||
free(tid_reader);
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
From f3a942e30e3a217cfbf987d5e6bec1d89c394963 Mon Sep 17 00:00:00 2001
|
|
||||||
From: root <root@localhost.localdomain>
|
|
||||||
Date: Thu, 25 Jun 2020 07:20:38 +0800
|
|
||||||
Subject: [PATCH] fix-make-test-error
|
|
||||||
|
|
||||||
---
|
|
||||||
tests/Makefile.am | 1 -
|
|
||||||
tests/benchmark/Makefile.am | 4 +---
|
|
||||||
2 files changed, 1 insertion(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
|
||||||
index 03f3f29..7e91a71 100644
|
|
||||||
--- a/tests/Makefile.am
|
|
||||||
+++ b/tests/Makefile.am
|
|
||||||
@@ -8,4 +8,3 @@ long_bench:
|
|
||||||
cd benchmark && $(MAKE) $(AM_MAKEFLAGS) long_bench
|
|
||||||
regtest:
|
|
||||||
cd regression && $(MAKE) $(AM_MAKEFLAGS) regtest
|
|
||||||
- cd benchmark && $(MAKE) $(AM_MAKEFLAGS) regtest
|
|
||||||
diff --git a/tests/benchmark/Makefile.am b/tests/benchmark/Makefile.am
|
|
||||||
index 216d013..35e2db6 100644
|
|
||||||
--- a/tests/benchmark/Makefile.am
|
|
||||||
+++ b/tests/benchmark/Makefile.am
|
|
||||||
@@ -226,7 +226,7 @@ clean-local:
|
|
||||||
done; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
-.PHONY: short_bench long_bench regtest
|
|
||||||
+.PHONY: short_bench long_bench
|
|
||||||
|
|
||||||
short_bench:
|
|
||||||
./run.sh short_bench_tests
|
|
||||||
@@ -234,5 +234,3 @@ short_bench:
|
|
||||||
long_bench:
|
|
||||||
./run.sh long_bench_tests
|
|
||||||
|
|
||||||
-regtest:
|
|
||||||
- ./run.sh regression_tests
|
|
||||||
--
|
|
||||||
2.23.0
|
|
||||||
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
From 9e19a6b0d350ffb70e9f29d8eea371c6b7ffad72 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
Date: Sun, 9 Dec 2018 06:37:09 -0500
|
|
||||||
Subject: [PATCH 07/15] Fix: workqueue: struct urcu_work vs rcu_head mixup
|
|
||||||
|
|
||||||
The workqueue code was derived from call-rcu, and its API
|
|
||||||
expects a struct urcu_work for work items, but it internally iterates
|
|
||||||
over struct rcu_head.
|
|
||||||
|
|
||||||
This is not an issue at runtime because both structures have the
|
|
||||||
exact same layout and content, but it is a type mixup nevertheless.
|
|
||||||
|
|
||||||
Use the right type in the implementation.
|
|
||||||
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
src/workqueue.c | 8 ++++----
|
|
||||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/workqueue.c b/src/workqueue.c
|
|
||||||
index db0c63a..6707ffe 100644
|
|
||||||
--- a/src/workqueue.c
|
|
||||||
+++ b/src/workqueue.c
|
|
||||||
@@ -221,11 +221,11 @@ static void *workqueue_thread(void *arg)
|
|
||||||
cbcount = 0;
|
|
||||||
__cds_wfcq_for_each_blocking_safe(&cbs_tmp_head,
|
|
||||||
&cbs_tmp_tail, cbs, cbs_tmp_n) {
|
|
||||||
- struct rcu_head *rhp;
|
|
||||||
+ struct urcu_work *uwp;
|
|
||||||
|
|
||||||
- rhp = caa_container_of(cbs,
|
|
||||||
- struct rcu_head, next);
|
|
||||||
- rhp->func(rhp);
|
|
||||||
+ uwp = caa_container_of(cbs,
|
|
||||||
+ struct urcu_work, next);
|
|
||||||
+ uwp->func(uwp);
|
|
||||||
cbcount++;
|
|
||||||
}
|
|
||||||
uatomic_sub(&workqueue->qlen, cbcount);
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
From 6c249cd8c0a48370bac8511216c166e98104d699 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Michael Jeanson <mjeanson@efficios.com>
|
|
||||||
Date: Fri, 23 Nov 2018 15:27:07 -0500
|
|
||||||
Subject: [PATCH 04/15] test_rwlock: Add per-thread count to verbose output
|
|
||||||
|
|
||||||
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
|
|
||||||
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
||||||
---
|
|
||||||
tests/benchmark/test_rwlock.c | 12 +++++++-----
|
|
||||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/tests/benchmark/test_rwlock.c b/tests/benchmark/test_rwlock.c
|
|
||||||
index f95e4e1..827c117 100644
|
|
||||||
--- a/tests/benchmark/test_rwlock.c
|
|
||||||
+++ b/tests/benchmark/test_rwlock.c
|
|
||||||
@@ -202,8 +202,9 @@ void *thr_reader(void *_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
*count = URCU_TLS(nr_reads);
|
|
||||||
- printf_verbose("thread_end %s, tid %lu\n",
|
|
||||||
- "reader", urcu_get_thread_id());
|
|
||||||
+
|
|
||||||
+ printf_verbose("thread_end %s, tid %lu, count %llu\n",
|
|
||||||
+ "reader", urcu_get_thread_id(), *count);
|
|
||||||
return ((void*)1);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -248,10 +249,10 @@ void *thr_writer(void *_count)
|
|
||||||
if (caa_unlikely(wdelay))
|
|
||||||
loop_sleep(wdelay);
|
|
||||||
}
|
|
||||||
-
|
|
||||||
- printf_verbose("thread_end %s, tid %lu\n",
|
|
||||||
- "writer", urcu_get_thread_id());
|
|
||||||
*count = URCU_TLS(nr_writes);
|
|
||||||
+
|
|
||||||
+ printf_verbose("thread_end %s, tid %lu, count %llu\n",
|
|
||||||
+ "writer", urcu_get_thread_id(), *count);
|
|
||||||
return ((void*)2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -345,6 +346,7 @@ int main(int argc, char **argv)
|
|
||||||
printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
|
|
||||||
duration, nr_readers, nr_writers);
|
|
||||||
printf_verbose("Writer delay : %lu loops.\n", wdelay);
|
|
||||||
+ printf_verbose("Writer duration : %lu loops.\n", wduration);
|
|
||||||
printf_verbose("Reader duration : %lu loops.\n", rduration);
|
|
||||||
printf_verbose("thread %-6s, tid %lu\n",
|
|
||||||
"main", urcu_get_thread_id());
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
From 11dcfc5e044f55941ffd3f1155bbda51ed05aff7 Mon Sep 17 00:00:00 2001
|
|
||||||
From: hewenliang <hewenliang4@huawei.com>
|
|
||||||
Date: Mon, 12 Aug 2019 22:30:20 +0000
|
|
||||||
Subject: [PATCH] urcu: fix deadlock issue using SIG_RCU
|
|
||||||
|
|
||||||
reason:
|
|
||||||
1.use a seperate thread(cds_lfht_workqueue) to handle hash table auto resize,
|
|
||||||
and this thread block all signal at initialization.
|
|
||||||
2.While in urcu-signal flavor, call_rcu_thread will send SIGRCU signal to all
|
|
||||||
the registed thread to make them do cmm_smp_mb.
|
|
||||||
3.Based on above, call_rcu_thread and workqueue thread will trapped into a dead
|
|
||||||
loop: where call_rcu_thread hold the rcu_registry_lock to waiting all the registed
|
|
||||||
thread to do cmm_smp_mb, while workqueue thread nerver do cmm_smp_mb and waiting to
|
|
||||||
get rcu_registry_lock to unregiter from rcu.
|
|
||||||
so we should not block SIGRCU in workqueue thread to avoid the dead lock.
|
|
||||||
|
|
||||||
Signed-off-by: hewenliang <hewenliang4@huawei.com>
|
|
||||||
---
|
|
||||||
src/rculfhash.c | 8 +++++++-
|
|
||||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/rculfhash.c b/src/rculfhash.c
|
|
||||||
index fed33e4..fc3d610 100644
|
|
||||||
--- a/src/rculfhash.c
|
|
||||||
+++ b/src/rculfhash.c
|
|
||||||
@@ -273,6 +273,7 @@
|
|
||||||
#include <urcu/uatomic.h>
|
|
||||||
#include <urcu/compiler.h>
|
|
||||||
#include <urcu/rculfhash.h>
|
|
||||||
+#include <urcu.h>
|
|
||||||
#include <rculfhash-internal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
@@ -2112,7 +2113,7 @@ static void cds_lfht_worker_init(struct urcu_workqueue *workqueue,
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
sigset_t mask;
|
|
||||||
-
|
|
||||||
+ sigset_t set;
|
|
||||||
/* Block signal for entire process, so only our thread processes it. */
|
|
||||||
ret = sigfillset(&mask);
|
|
||||||
if (ret)
|
|
||||||
@@ -2120,6 +2121,11 @@ static void cds_lfht_worker_init(struct urcu_workqueue *workqueue,
|
|
||||||
ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
|
||||||
if (ret)
|
|
||||||
urcu_die(ret);
|
|
||||||
+ sigemptyset(&set);
|
|
||||||
+ sigaddset(&set, SIGRCU);
|
|
||||||
+ ret = pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
|
||||||
+ if (ret)
|
|
||||||
+ urcu_die(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cds_lfht_init_worker(const struct rcu_flavor_struct *flavor)
|
|
||||||
--
|
|
||||||
2.19.1
|
|
||||||
|
|
||||||
Binary file not shown.
BIN
userspace-rcu-0.12.1.tar.bz2
Normal file
BIN
userspace-rcu-0.12.1.tar.bz2
Normal file
Binary file not shown.
@ -1,24 +1,11 @@
|
|||||||
Name: userspace-rcu
|
Name: userspace-rcu
|
||||||
Version: 0.10.1
|
Version: 0.12.1
|
||||||
Release: 10
|
Release: 1
|
||||||
Summary: Userspace read-copy-update library
|
Summary: Userspace read-copy-update library
|
||||||
License: LGPLv2+
|
License: LGPLv2+
|
||||||
URL: http://liburcu.org
|
URL: http://liburcu.org
|
||||||
Source0: http://lttng.org/files/urcu/%{name}-%{version}.tar.bz2
|
Source0: http://lttng.org/files/urcu/%{name}-%{version}.tar.bz2
|
||||||
|
|
||||||
Patch6000: fix-compat_futex_noasync-on-Cygwin.patch
|
|
||||||
Patch6001: fix-pthread_rwlock-initialization-on-Cygwin.patch
|
|
||||||
Patch6002: test_rwlock-Add-per-thread-count-to-verbose-output.patch
|
|
||||||
Patch6003: fix-mixup-between-URCU_WORKQUEUE_RT-and-URCU_CALL_RC.patch
|
|
||||||
Patch6004: cleanup-workqueue-update-comments-referring-to-call-.patch
|
|
||||||
Patch6005: fix-workqueue-struct-urcu_work-vs-rcu_head-mixup.patch
|
|
||||||
Patch6006: fix-don-t-wait-after-completion-of-job-batch-if-work.patch
|
|
||||||
Patch6007: fix-don-t-wait-after-completion-of-a-work-queue-job-.patch
|
|
||||||
Patch6008: fix-only-wait-if-work-queue-is-empty-in-real-time-mo.patch
|
|
||||||
Patch6009: fix-regtest-without-bench.patch
|
|
||||||
|
|
||||||
Patch9000: urcu-fix-deadlock-issue-using-SIG_RCU.patch
|
|
||||||
|
|
||||||
BuildRequires: pkgconfig perl-Test-Harness autoconf automake libtool
|
BuildRequires: pkgconfig perl-Test-Harness autoconf automake libtool
|
||||||
|
|
||||||
%description
|
%description
|
||||||
@ -77,6 +64,9 @@ make check
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Jul 21 2020 jinzhimin <jinzhimin2@huawei.com> - 0.12.1-1
|
||||||
|
- upgrade to 0.12.1
|
||||||
|
|
||||||
* Thu Jun 29 2020 xinghe <xinghe1@huawei.com> - 0.10.1-10
|
* Thu Jun 29 2020 xinghe <xinghe1@huawei.com> - 0.10.1-10
|
||||||
- Type:bugfix
|
- Type:bugfix
|
||||||
- ID:NA
|
- ID:NA
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user