4 * Userspace RCU library
6 * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
8 * Distributed under GPLv2
20 pthread_mutex_t urcu_mutex
= PTHREAD_MUTEX_INITIALIZER
;
22 /* Global grace period counter */
25 int __thread urcu_active_readers
;
27 /* Thread IDs of registered readers */
28 #define INIT_NUM_THREADS 4
32 int *urcu_active_readers
;
36 unsigned int yield_active
;
37 unsigned int __thread rand_yield
;
40 static struct reader_data
*reader_data
;
41 static int num_readers
, alloc_readers
;
44 void internal_urcu_lock(void)
47 ret
= pthread_mutex_lock(&urcu_mutex
);
49 perror("Error in pthread mutex lock");
54 void internal_urcu_unlock(void)
58 ret
= pthread_mutex_unlock(&urcu_mutex
);
60 perror("Error in pthread mutex unlock");
66 * called with urcu_mutex held.
68 static void switch_next_urcu_qparity(void)
70 urcu_gp_ctr
^= RCU_GP_CTR_BIT
;
73 static void force_mb_all_threads(void)
75 struct reader_data
*index
;
77 * Ask for each threads to execute a mb() so we can consider the
78 * compiler barriers around rcu read lock as real memory barriers.
85 mb(); /* write sig_done before sending the signals */
87 for (index
= reader_data
; index
< reader_data
+ num_readers
; index
++) {
88 pthread_kill(index
->tid
, SIGURCU
);
92 * Wait for sighandler (and thus mb()) to execute on every thread.
95 while (sig_done
< num_readers
)
98 mb(); /* read sig_done before ending the barrier */
102 void wait_for_quiescent_state(void)
104 struct reader_data
*index
;
108 /* Wait for each thread urcu_active_readers count to become 0.
110 for (index
= reader_data
; index
< reader_data
+ num_readers
; index
++) {
114 while (rcu_old_gp_ongoing(index
->urcu_active_readers
))
118 * Locally : read *index->urcu_active_readers before freeing old
120 * Remote (reader threads) : Order urcu_qparity update and other
121 * thread's quiescent state counter read.
123 force_mb_all_threads();
126 static void switch_qparity(void)
128 /* All threads should read qparity before accessing data structure. */
129 /* Write ptr before changing the qparity */
130 force_mb_all_threads();
132 switch_next_urcu_qparity();
136 * Wait for previous parity to be empty of readers.
138 wait_for_quiescent_state();
141 void synchronize_rcu(void)
144 internal_urcu_lock();
150 internal_urcu_lock();
154 void urcu_add_reader(pthread_t id
)
156 struct reader_data
*oldarray
;
159 alloc_readers
= INIT_NUM_THREADS
;
162 malloc(sizeof(struct reader_data
) * alloc_readers
);
164 if (alloc_readers
< num_readers
+ 1) {
165 oldarray
= reader_data
;
166 reader_data
= malloc(sizeof(struct reader_data
)
167 * (alloc_readers
<< 1));
168 memcpy(reader_data
, oldarray
,
169 sizeof(struct reader_data
) * alloc_readers
);
173 reader_data
[num_readers
].tid
= id
;
174 /* reference to the TLS of _this_ reader thread. */
175 reader_data
[num_readers
].urcu_active_readers
= &urcu_active_readers
;
180 * Never shrink (implementation limitation).
181 * This is O(nb threads). Eventually use a hash table.
183 void urcu_remove_reader(pthread_t id
)
185 struct reader_data
*index
;
187 assert(reader_data
!= NULL
);
188 for (index
= reader_data
; index
< reader_data
+ num_readers
; index
++) {
189 if (pthread_equal(index
->tid
, id
)) {
190 memcpy(index
, &reader_data
[num_readers
- 1],
191 sizeof(struct reader_data
));
192 reader_data
[num_readers
- 1].tid
= 0;
193 reader_data
[num_readers
- 1].urcu_active_readers
= NULL
;
198 /* Hrm not found, forgot to register ? */
202 void urcu_register_thread(void)
204 internal_urcu_lock();
205 urcu_add_reader(pthread_self());
206 internal_urcu_unlock();
209 void urcu_unregister_thread(void)
211 internal_urcu_lock();
212 urcu_remove_reader(pthread_self());
213 internal_urcu_unlock();
216 void sigurcu_handler(int signo
, siginfo_t
*siginfo
, void *context
)
219 atomic_inc(&sig_done
);
222 void __attribute__((constructor
)) urcu_init(void)
224 struct sigaction act
;
227 act
.sa_sigaction
= sigurcu_handler
;
228 ret
= sigaction(SIGURCU
, &act
, NULL
);
230 perror("Error in sigaction");
235 void __attribute__((destructor
)) urcu_exit(void)
237 struct sigaction act
;
240 ret
= sigaction(SIGURCU
, NULL
, &act
);
242 perror("Error in sigaction");
245 assert(act
.sa_sigaction
== sigurcu_handler
);