Skip to content

Commit c5eaee3

Browse files
committed
rcu-list: Fix the data-race
Instead of using the old implementation of thread-rcu [1], let's use the newest and correct one, thread-rcu/rcu.h. And, to avoid the data race while we traverse the linked list, introduce the for loop API, list_for_each_entry_rcu. After we changed the implementation and used the new for loop API, it doesn't report the data race: $ make cc -o test test.c -g -Wall -std=c99 -fsanitize=thread -D'READER_NUM=10' -D'UPDATER_NUM=1' -D'TRACE_LOOP=1000' -D'CONFIG_TRACE_TIME' -lpthread $ ./test [tracer] loop 1000 : 2367069575.000000 ns [1] https://github.com/linD026/parallel-programs/blob/main/rcu/thrd-based-rcu/thrd_rcu.h
1 parent c5596e2 commit c5eaee3

File tree

4 files changed

+18
-224
lines changed

4 files changed

+18
-224
lines changed

rcu-list/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CFLAGS = -g
33
CFLAGS += -Wall
44
LDFLAGS += -lpthread
55
CFLAGS += -std=c99
6-
# CFLAGS += -fsanitize=thread
6+
CFLAGS += -fsanitize=thread
77

88
READER_NUM = 10
99
UPDATER_NUM = 1

rcu-list/rculist.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
#include <stddef.h>
66

7-
#include "thread-rcu.h"
7+
/* Reuse the RCU from thread-rcu */
8+
#include "../thread-rcu/rcu.h"
9+
10+
#define __allow_unused __attribute__((unused))
811

912
#define container_of(ptr, type, member) \
1013
__extension__({ \
@@ -63,10 +66,22 @@ static inline void list_del_rcu(struct list_head *node)
6366
list_init_rcu(node);
6467
}
6568

69+
/*
70+
* For the write side only (i.e., it should hold the lock when we use the
71+
* non-rcu postfix for loop API).
72+
*/
73+
6674
#define list_for_each(n, head) for (n = (head)->next; n != (head); n = n->next)
6775

6876
#define list_for_each_from(pos, head) for (; pos != (head); pos = pos->next)
6977

7078
#define list_for_each_safe(pos, n, head) \
7179
for (pos = (head)->next, n = pos->next; pos != (head); \
7280
pos = n, n = pos->next)
81+
82+
/* The read side should only use the following API. */
83+
84+
#define list_for_each_entry_rcu(pos, head, member) \
85+
for (pos = list_entry_rcu((head)->next, __typeof__(*pos), member); \
86+
&pos->member != (head); \
87+
pos = list_entry_rcu(pos->member.next, __typeof__(*pos), member))

rcu-list/test.c

+1-4
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,12 @@ static struct test *test_alloc(int val)
3333
static void *reader_side(void *argv)
3434
{
3535
struct test __allow_unused *tmp;
36-
struct list_head *node;
3736

3837
rcu_init();
3938

4039
rcu_read_lock();
4140

42-
list_for_each (node, &head) {
43-
tmp = list_entry_rcu(node, struct test, node);
44-
}
41+
list_for_each_entry_rcu(tmp, &head, node) {}
4542

4643
rcu_read_unlock();
4744

rcu-list/thread-rcu.h

-218
This file was deleted.

0 commit comments

Comments
 (0)