commit 92e17ba381e5d45b2c5ff06590d3ed8e018bcd6d Author: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon Sep 30 11:19:12 2019 -0400 Package init diff --git a/cleanup-workqueue-update-comments-referring-to-call-.patch b/cleanup-workqueue-update-comments-referring-to-call-.patch new file mode 100644 index 0000000..b62ce67 --- /dev/null +++ b/cleanup-workqueue-update-comments-referring-to-call-.patch @@ -0,0 +1,58 @@ +From 136211f67b5ba804fd0e02603bcef61ac47dbc16 Mon Sep 17 00:00:00 2001 +From: Mathieu Desnoyers +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 +--- + 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 + diff --git a/fix-compat_futex_noasync-on-Cygwin.patch b/fix-compat_futex_noasync-on-Cygwin.patch new file mode 100644 index 0000000..5ffc5a5 --- /dev/null +++ b/fix-compat_futex_noasync-on-Cygwin.patch @@ -0,0 +1,48 @@ +From b197ce865b0de8c475f3ddeadeae3a66b15ace21 Mon Sep 17 00:00:00 2001 +From: Michael Jeanson +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/fix-don-t-wait-after-completion-of-a-work-queue-job-.patch b/fix-don-t-wait-after-completion-of-a-work-queue-job-.patch new file mode 100644 index 0000000..f422f54 --- /dev/null +++ b/fix-don-t-wait-after-completion-of-a-work-queue-job-.patch @@ -0,0 +1,49 @@ +From 79eca0929fc50a668a15937b5bf4d1cb97049de8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= + +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/fix-don-t-wait-after-completion-of-job-batch-if-work.patch b/fix-don-t-wait-after-completion-of-job-batch-if-work.patch new file mode 100644 index 0000000..86e8cf9 --- /dev/null +++ b/fix-don-t-wait-after-completion-of-job-batch-if-work.patch @@ -0,0 +1,56 @@ +From d3e42beb106479eae7c234bb0aeacce92661ca7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= + +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/fix-mixup-between-URCU_WORKQUEUE_RT-and-URCU_CALL_RC.patch b/fix-mixup-between-URCU_WORKQUEUE_RT-and-URCU_CALL_RC.patch new file mode 100644 index 0000000..c827f8b --- /dev/null +++ b/fix-mixup-between-URCU_WORKQUEUE_RT-and-URCU_CALL_RC.patch @@ -0,0 +1,45 @@ +From 0aa1fccd3aff5f5a7717c166f7bfbe864d041f23 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= + +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/fix-only-wait-if-work-queue-is-empty-in-real-time-mo.patch b/fix-only-wait-if-work-queue-is-empty-in-real-time-mo.patch new file mode 100644 index 0000000..d098bce --- /dev/null +++ b/fix-only-wait-if-work-queue-is-empty-in-real-time-mo.patch @@ -0,0 +1,48 @@ +From 803e59362b6d94edff3a36f47a9da3e8dca4bde2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Galarneau?= + +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/fix-pthread_rwlock-initialization-on-Cygwin.patch b/fix-pthread_rwlock-initialization-on-Cygwin.patch new file mode 100644 index 0000000..c7bc16a --- /dev/null +++ b/fix-pthread_rwlock-initialization-on-Cygwin.patch @@ -0,0 +1,224 @@ +From eec2f6a5c353f28bb74e4a3f96a3da5a50f25574 Mon Sep 17 00:00:00 2001 +From: Michael Jeanson +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/fix-workqueue-struct-urcu_work-vs-rcu_head-mixup.patch b/fix-workqueue-struct-urcu_work-vs-rcu_head-mixup.patch new file mode 100644 index 0000000..6e64605 --- /dev/null +++ b/fix-workqueue-struct-urcu_work-vs-rcu_head-mixup.patch @@ -0,0 +1,42 @@ +From 9e19a6b0d350ffb70e9f29d8eea371c6b7ffad72 Mon Sep 17 00:00:00 2001 +From: Mathieu Desnoyers +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 +--- + 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 + diff --git a/regtest-without-bench.patch b/regtest-without-bench.patch new file mode 100644 index 0000000..8c29b9d --- /dev/null +++ b/regtest-without-bench.patch @@ -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 diff --git a/test_rwlock-Add-per-thread-count-to-verbose-output.patch b/test_rwlock-Add-per-thread-count-to-verbose-output.patch new file mode 100644 index 0000000..becab4b --- /dev/null +++ b/test_rwlock-Add-per-thread-count-to-verbose-output.patch @@ -0,0 +1,52 @@ +From 6c249cd8c0a48370bac8511216c166e98104d699 Mon Sep 17 00:00:00 2001 +From: Michael Jeanson +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 +Signed-off-by: Mathieu Desnoyers +--- + 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 + diff --git a/urcu-fix-deadlock-issue-using-SIG_RCU.patch b/urcu-fix-deadlock-issue-using-SIG_RCU.patch new file mode 100644 index 0000000..6d46afc --- /dev/null +++ b/urcu-fix-deadlock-issue-using-SIG_RCU.patch @@ -0,0 +1,57 @@ +From 11dcfc5e044f55941ffd3f1155bbda51ed05aff7 Mon Sep 17 00:00:00 2001 +From: hewenliang +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 +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/userspace-rcu-0.10.1.tar.bz2 b/userspace-rcu-0.10.1.tar.bz2 new file mode 100644 index 0000000..78f84a6 Binary files /dev/null and b/userspace-rcu-0.10.1.tar.bz2 differ diff --git a/userspace-rcu.spec b/userspace-rcu.spec new file mode 100644 index 0000000..97a8d0c --- /dev/null +++ b/userspace-rcu.spec @@ -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 - 0.10.1-6 +- Type:bugfix +- ID:NA +- SUG:restart +- DESC: fix performance issue of the urcu. + +* Mon Aug 12 2019 openEuler Buildteam - 0.10.1-5 +- Package init