8 pthread_mutex_t urcu_mutex
= PTHREAD_MUTEX_INITIALIZER
;
10 /* Global quiescent period parity */
13 int __thread urcu_active_readers
[2];
15 /* Thread IDs of registered readers */
16 #define INIT_NUM_THREADS 4
20 int **urcu_active_readers
;
23 static struct reader_data
*reader_data
;
24 static int num_readers
, alloc_readers
;
28 * called with urcu_mutex held.
30 static int switch_next_urcu_qparity(void)
32 int old_parity
= urcu_qparity
;
33 urcu_qparity
= 1 - old_parity
;
37 static void force_mb_all_threads(void)
41 * Ask for each threads to execute a mb() so we can consider the
42 * compiler barriers around rcu read lock as real memory barriers.
46 sigtask
= TASK_FORCE_MB
;
48 mb(); /* write sig_done and sigtask before sending the signals */
49 for (index
= reader_data
; index
< reader_data
+ num_readers
; index
++)
50 pthread_kill(*index
, SIGURCU
);
52 * Wait for sighandler (and thus mb()) to execute on every thread.
55 while (sig_done
< num_readers
)
57 mb(); /* read sig_done before writing sigtask */
61 void wait_for_quiescent_state(int parity
)
66 /* Wait for each thread urcu_active_readers count to become 0.
68 for (index
= readers_data
; index
< reader_data
+ num_readers
; index
++) {
72 while (*index
->urcu_active_readers
!= 0)
76 * Locally : read *index->urcu_active_readers before freeing old
78 * Remote (reader threads) : Order urcu_qparity update and other
79 * thread's quiescent state counter read.
81 force_mb_all_threads();
85 * Return old pointer, OK to free, no more reference exist.
87 void *urcu_publish_content(void **ptr
, void *new)
92 ret
= pthread_mutex_lock(&urcu_mutex
);
94 perror("Error in %s pthread mutex lock", __func__
);
99 * We can publish the new pointer before we change the current qparity.
100 * Readers seeing the new pointer while being in the previous qparity
101 * window will make us wait until the end of the quiescent state before
102 * we release the unrelated memory area. However, given we hold the
103 * urcu_mutex, we are making sure that no further garbage collection can
104 * occur until we release the mutex, therefore we guarantee that this
105 * given reader will have completed its execution using the new pointer
106 * when the next quiescent state window will be over.
110 wmb(); /* Write ptr before changing the qparity */
111 /* All threads should read qparity before ptr */
112 force_rmb_all_threads();
113 prev_parity
= switch_next_urcu_qparity();
116 * Wait for previous parity to be empty of readers.
118 wait_for_quiescent_state(prev_parity
);
120 * Deleting old data is ok !
123 ret
= pthread_mutex_unlock(&urcu_mutex
);
125 perror("Error in %s pthread mutex lock", __func__
);
131 void urcu_add_reader(pthread_t id
)
134 alloc_readers
= INIT_NUM_THREADS
;
137 malloc(sizeof(struct reader_data
) * alloc_readers
);
140 if (alloc_readers
< num_readers
+ 1) {
142 oldarray
= reader_data
;
143 reader_data
= malloc(sizeof(struct reader_data
)
144 * (alloc_readers
<< 1));
145 memcpy(reader_data
, oldarray
,
146 sizeof(struct reader_data
) * alloc_readers
);
150 reader_data
[num_readers
].tid
= id
;
151 /* reference to the TLS of _this_ reader thread. */
152 reader_data
[num_readers
].urcu_active_readers
= urcu_active_readers
;
157 * Never shrink (implementation limitation).
158 * This is O(nb threads). Eventually use a hash table.
160 void urcu_remove_reader(pthread_t id
)
162 struct reader_data
*index
;
164 assert(reader_data
!= NULL
);
165 for (index
= reader_data
; index
< reader_data
+ num_readers
; index
++) {
166 if (index
->tid
== id
) {
167 memcpy(index
, &reader_data
[num_readers
- 1],
168 sizeof(struct reader_data
));
169 reader_data
[num_readers
- 1].tid
= 0;
170 reader_data
[num_readers
- 1].urcu_active_readers
= NULL
;
175 /* Hrm not found, forgot to register ? */
179 void urcu_register_thread(void)
181 pthread_t self
= pthread_self();
183 ret
= pthread_mutex_lock(&urcu_mutex
);
185 perror("Error in %s pthread mutex lock", __func__
);
189 urcu_add_reader(self
);
192 ret
= pthread_mutex_unlock(&urcu_mutex
);
194 perror("Error in %s pthread mutex unlock", __func__
);
199 void urcu_register_thread(void)
201 pthread_t self
= pthread_self();
203 ret
= pthread_mutex_lock(&urcu_mutex
);
205 perror("Error in %s pthread mutex lock", __func__
);
209 urcu_remove_reader(self
);
211 ret
= pthread_mutex_unlock(&urcu_mutex
);
213 perror("Error in %s pthread mutex unlock", __func__
);
219 void handler(int signo
, siginfo_t
*siginfo
, void *context
)
222 atomic_inc(&sig_done
);
225 void __attribute__((constructor
)) urcu_init(void)
227 struct sigaction act
;
230 act
.sa_sigaction
= sigurcu_handler
;
231 ret
= sigaction(SIGURCU
, &act
, NULL
);
233 perror("Error in %s sigaction", __func__
);
238 void __attribute__((destructor
)) urcu_exit(void)
240 struct sigaction act
;
243 ret
= sigaction(SIGURCU
, NULL
, &act
);
245 perror("Error in %s sigaction", __func__
);
248 assert(act
.sa_sigaction
== sigurcu_handler
);