Package init
This commit is contained in:
commit
92e17ba381
58
cleanup-workqueue-update-comments-referring-to-call-.patch
Normal file
58
cleanup-workqueue-update-comments-referring-to-call-.patch
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
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
|
||||||
|
|
||||||
48
fix-compat_futex_noasync-on-Cygwin.patch
Normal file
48
fix-compat_futex_noasync-on-Cygwin.patch
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
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
|
||||||
|
|
||||||
49
fix-don-t-wait-after-completion-of-a-work-queue-job-.patch
Normal file
49
fix-don-t-wait-after-completion-of-a-work-queue-job-.patch
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
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
|
||||||
|
|
||||||
56
fix-don-t-wait-after-completion-of-job-batch-if-work.patch
Normal file
56
fix-don-t-wait-after-completion-of-job-batch-if-work.patch
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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
|
||||||
|
|
||||||
45
fix-mixup-between-URCU_WORKQUEUE_RT-and-URCU_CALL_RC.patch
Normal file
45
fix-mixup-between-URCU_WORKQUEUE_RT-and-URCU_CALL_RC.patch
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
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
|
||||||
|
|
||||||
48
fix-only-wait-if-work-queue-is-empty-in-real-time-mo.patch
Normal file
48
fix-only-wait-if-work-queue-is-empty-in-real-time-mo.patch
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
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
|
||||||
|
|
||||||
224
fix-pthread_rwlock-initialization-on-Cygwin.patch
Normal file
224
fix-pthread_rwlock-initialization-on-Cygwin.patch
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
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
|
||||||
|
|
||||||
42
fix-workqueue-struct-urcu_work-vs-rcu_head-mixup.patch
Normal file
42
fix-workqueue-struct-urcu_work-vs-rcu_head-mixup.patch
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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
|
||||||
|
|
||||||
26
regtest-without-bench.patch
Normal file
26
regtest-without-bench.patch
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Remove the benchmarks from the regtest target, they timeout on the buildds.
|
||||||
|
|
||||||
|
--- a/tests/benchmark/Makefile.am
|
||||||
|
+++ b/tests/benchmark/Makefile.am
|
||||||
|
@@ -229,13 +229,10 @@
|
||||||
|
done; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
-.PHONY: short_bench long_bench regtest
|
||||||
|
+.PHONY: short_bench long_bench
|
||||||
|
|
||||||
|
short_bench:
|
||||||
|
./run.sh short_bench_tests
|
||||||
|
|
||||||
|
long_bench:
|
||||||
|
./run.sh long_bench_tests
|
||||||
|
-
|
||||||
|
-regtest:
|
||||||
|
- ./run.sh regression_tests
|
||||||
|
--- a/tests/Makefile.am
|
||||||
|
+++ b/tests/Makefile.am
|
||||||
|
@@ -8,4 +8,3 @@
|
||||||
|
cd benchmark && $(MAKE) $(AM_MAKEFLAGS) long_bench
|
||||||
|
regtest:
|
||||||
|
cd regression && $(MAKE) $(AM_MAKEFLAGS) regtest
|
||||||
|
- cd benchmark && $(MAKE) $(AM_MAKEFLAGS) regtest
|
||||||
52
test_rwlock-Add-per-thread-count-to-verbose-output.patch
Normal file
52
test_rwlock-Add-per-thread-count-to-verbose-output.patch
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
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
|
||||||
|
|
||||||
57
urcu-fix-deadlock-issue-using-SIG_RCU.patch
Normal file
57
urcu-fix-deadlock-issue-using-SIG_RCU.patch
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
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
|
||||||
|
|
||||||
BIN
userspace-rcu-0.10.1.tar.bz2
Normal file
BIN
userspace-rcu-0.10.1.tar.bz2
Normal file
Binary file not shown.
87
userspace-rcu.spec
Normal file
87
userspace-rcu.spec
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
Name: userspace-rcu
|
||||||
|
Version: 0.10.1
|
||||||
|
Release: 6
|
||||||
|
Summary: Userspace read-copy-update library
|
||||||
|
License: LGPLv2+
|
||||||
|
URL: http://liburcu.org
|
||||||
|
Source0: http://lttng.org/files/urcu/%{name}-%{version}.tar.bz2
|
||||||
|
|
||||||
|
Patch0: regtest-without-bench.patch
|
||||||
|
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
|
||||||
|
|
||||||
|
Patch9000: urcu-fix-deadlock-issue-using-SIG_RCU.patch
|
||||||
|
|
||||||
|
BuildRequires: pkgconfig perl-Test-Harness autoconf automake libtool
|
||||||
|
|
||||||
|
%description
|
||||||
|
liburcu is a LGPLv2.1 userspace RCU (read-copy-update) library. This data
|
||||||
|
synchronization library provides read-side access which scales linearly with
|
||||||
|
the number of cores. It does so by allowing multiples copies of a given data
|
||||||
|
structure to live at the same time, and by monitoring the data structure
|
||||||
|
accesses to detect grace periods after which memory reclamation is possible.
|
||||||
|
|
||||||
|
%package devel
|
||||||
|
Summary: The devel for %{name}
|
||||||
|
Requires: %{name} = %{version}-%{release}
|
||||||
|
|
||||||
|
%description devel
|
||||||
|
Development files for %{name}
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -n %{name}-%{version} -p1
|
||||||
|
|
||||||
|
%build
|
||||||
|
autoreconf -vif
|
||||||
|
|
||||||
|
%configure
|
||||||
|
|
||||||
|
make %{?_smp_mflags} V=1
|
||||||
|
|
||||||
|
|
||||||
|
%install
|
||||||
|
%make_install
|
||||||
|
|
||||||
|
%check
|
||||||
|
make check
|
||||||
|
make regtest
|
||||||
|
|
||||||
|
%post -p /sbin/ldconfig
|
||||||
|
%postun -p /sbin/ldconfig
|
||||||
|
|
||||||
|
|
||||||
|
%files
|
||||||
|
%license LICENSE gpl-2.0.txt lgpl-relicensing.txt lgpl-2.1.txt
|
||||||
|
%doc ChangeLog README.md
|
||||||
|
%{_libdir}/*.so.*
|
||||||
|
%exclude %{_libdir}/*.a
|
||||||
|
%exclude %{_libdir}/*.la
|
||||||
|
%exclude %{_docdir}/%{name}/LICENSE
|
||||||
|
|
||||||
|
%files devel
|
||||||
|
%doc %{_pkgdocdir}/examples
|
||||||
|
%{_includedir}/*
|
||||||
|
%{_libdir}/*.so
|
||||||
|
%{_libdir}/pkgconfig/liburcu*.pc
|
||||||
|
%{_docdir}/%{name}/cds-api.md
|
||||||
|
%{_docdir}/%{name}/rcu-api.md
|
||||||
|
%{_docdir}/%{name}/solaris-build.md
|
||||||
|
%{_docdir}/%{name}/uatomic-api.md
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Mon Aug 12 2019 hewenliang<hewenliang4@huawei.com> - 0.10.1-6
|
||||||
|
- Type:bugfix
|
||||||
|
- ID:NA
|
||||||
|
- SUG:restart
|
||||||
|
- DESC: fix performance issue of the urcu.
|
||||||
|
|
||||||
|
* Mon Aug 12 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.10.1-5
|
||||||
|
- Package init
|
||||||
Loading…
x
Reference in New Issue
Block a user