master
c 394 lines 13.4 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4
5 #ifdef NETDATA_TRACE_RWLOCKS
6
7 #ifndef NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC
8 #define NETDATA_TRACE_RWLOCKS_WAIT_TIME_TO_IGNORE_USEC 10
9 #endif
10
11 #ifndef NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC
12 #define NETDATA_TRACE_RWLOCKS_HOLD_TIME_TO_IGNORE_USEC 10000
13 #endif
14
15 #ifndef NETDATA_THREAD_LOCKS_ARRAY_SIZE
16 #define NETDATA_THREAD_LOCKS_ARRAY_SIZE 10
17 #endif
18
19 #endif // NETDATA_TRACE_RWLOCKS
20
21 // ----------------------------------------------------------------------------
22 // mutex
23
24 ALWAYS_INLINE int __netdata_cond_init(netdata_cond_t *cond) {
25 int ret = uv_cond_init(cond);
26 if(unlikely(ret != 0))
27 netdata_log_error("COND: failed to initialize (code %d).", ret);
28 return ret;
29 }
30
31 ALWAYS_INLINE void __netdata_cond_destroy(netdata_cond_t *cond) {
32 uv_cond_destroy(cond);
33 }
34
35 ALWAYS_INLINE void __netdata_cond_signal(netdata_cond_t *cond) {
36 uv_cond_signal(cond);
37 }
38
39 ALWAYS_INLINE void __netdata_cond_broadcast(netdata_cond_t *cond) {
40 uv_cond_broadcast(cond);
41 }
42
43 ALWAYS_INLINE void __netdata_cond_wait(netdata_cond_t *cond, netdata_mutex_t *mutex)
44 {
45 uv_cond_wait(cond, mutex);
46 }
47
48 ALWAYS_INLINE int __netdata_cond_timedwait(netdata_cond_t *cond, netdata_mutex_t *mutex, uint64_t timeout_ns)
49 {
50 int ret = uv_cond_timedwait(cond, mutex, timeout_ns);
51 return ret;
52 }
53
54 ALWAYS_INLINE int __netdata_mutex_init(netdata_mutex_t *mutex) {
55 int ret = uv_mutex_init(mutex);
56 if(unlikely(ret != 0))
57 netdata_log_error("MUTEX_LOCK: failed to initialize (code %d).", ret);
58 return ret;
59 }
60
61 ALWAYS_INLINE void __netdata_mutex_destroy(netdata_mutex_t *mutex) {
62 uv_mutex_destroy(mutex);
63 }
64
65 ALWAYS_INLINE void __netdata_mutex_lock(netdata_mutex_t *mutex) {
66 uv_mutex_lock(mutex);
67 nd_thread_mutex_locked();
68 }
69
70 ALWAYS_INLINE int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
71 int ret = uv_mutex_trylock(mutex);
72 if(ret != 0)
73 ;
74 else
75 nd_thread_mutex_locked();
76
77 return ret;
78 }
79
80 ALWAYS_INLINE void __netdata_mutex_unlock(netdata_mutex_t *mutex) {
81 uv_mutex_unlock(mutex);
82 nd_thread_mutex_unlocked();
83 }
84
85 #ifdef NETDATA_TRACE_RWLOCKS
86
87 int netdata_mutex_init_debug(const char *file __maybe_unused, const char *function __maybe_unused,
88 const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
89 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(%p) from %lu@%s, %s()", mutex, line, file, function);
90
91 int ret = __netdata_mutex_init(mutex);
92
93 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(%p) = %d, from %lu@%s, %s()", mutex, ret, line, file, function);
94
95 return ret;
96 }
97
98 int netdata_mutex_destroy_debug(const char *file __maybe_unused, const char *function __maybe_unused,
99 const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
100 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_destroy(%p) from %lu@%s, %s()", mutex, line, file, function);
101
102 int ret = __netdata_mutex_destroy(mutex);
103
104 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_destroy(%p) = %d, from %lu@%s, %s()", mutex, ret, line, file, function);
105
106 return ret;
107 }
108
109 int netdata_mutex_lock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
110 const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
111 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(%p) from %lu@%s, %s()", mutex, line, file, function);
112
113 usec_t start_s = now_monotonic_high_precision_usec();
114 int ret = __netdata_mutex_lock(mutex);
115 usec_t end_s = now_monotonic_high_precision_usec();
116
117 // remove compiler unused variables warning
118 (void)start_s;
119 (void)end_s;
120
121 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, end_s - start_s, line, file, function);
122
123 return ret;
124 }
125
126 int netdata_mutex_trylock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
127 const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
128 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(%p) from %lu@%s, %s()", mutex, line, file, function);
129
130 usec_t start_s = now_monotonic_high_precision_usec();
131 int ret = __netdata_mutex_trylock(mutex);
132 usec_t end_s = now_monotonic_high_precision_usec();
133
134 // remove compiler unused variables warning
135 (void)start_s;
136 (void)end_s;
137
138 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, end_s - start_s, line, file, function);
139
140 return ret;
141 }
142
143 int netdata_mutex_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
144 const unsigned long line __maybe_unused, netdata_mutex_t *mutex) {
145 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(%p) from %lu@%s, %s()", mutex, line, file, function);
146
147 usec_t start_s = now_monotonic_high_precision_usec();
148 int ret = __netdata_mutex_unlock(mutex);
149 usec_t end_s = now_monotonic_high_precision_usec();
150
151 // remove compiler unused variables warning
152 (void)start_s;
153 (void)end_s;
154
155 netdata_log_debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, end_s - start_s, line, file, function);
156
157 return ret;
158 }
159
160 #endif // NETDATA_TRACE_RWLOCKS
161
162 // ----------------------------------------------------------------------------
163 // rwlock
164
165 ALWAYS_INLINE void __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
166 uv_rwlock_destroy(&rwlock->rwlock_t);
167 }
168
169 ALWAYS_INLINE int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
170 int ret = uv_rwlock_init(&rwlock->rwlock_t);
171 if(unlikely(ret != 0))
172 netdata_log_error("RW_LOCK: failed to initialize lock (code %d)", ret);
173 return ret;
174 }
175
176 ALWAYS_INLINE void __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
177 uv_rwlock_rdlock(&rwlock->rwlock_t);
178 nd_thread_rwlock_read_locked();
179 }
180
181 ALWAYS_INLINE void __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
182 uv_rwlock_wrlock(&rwlock->rwlock_t);
183 nd_thread_rwlock_write_locked();
184 }
185
186 ALWAYS_INLINE void __netdata_rwlock_rdunlock(netdata_rwlock_t *rwlock) {
187 uv_rwlock_rdunlock(&rwlock->rwlock_t);
188 nd_thread_rwlock_read_unlocked();
189 }
190
191 ALWAYS_INLINE void __netdata_rwlock_wrunlock(netdata_rwlock_t *rwlock) {
192 uv_rwlock_wrunlock(&rwlock->rwlock_t);
193 nd_thread_rwlock_write_unlocked();
194 }
195
196 ALWAYS_INLINE int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
197 int ret = uv_rwlock_tryrdlock(&rwlock->rwlock_t);
198 if(ret != 0)
199 ;
200 else
201 nd_thread_rwlock_read_locked();
202
203 return ret;
204 }
205
206 ALWAYS_INLINE int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
207 int ret = uv_rwlock_trywrlock(&rwlock->rwlock_t);
208 if(ret != 0)
209 ;
210 else
211 nd_thread_rwlock_write_locked();
212
213 return ret;
214 }
215
216 #ifdef NETDATA_TRACE_RWLOCKS
217
218 // ----------------------------------------------------------------------------
219 // lockers list
220
221 static netdata_rwlock_locker *find_rwlock_locker(const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
222 pid_t pid = gettid();
223 netdata_rwlock_locker *locker = NULL;
224
225 __netdata_mutex_lock(&rwlock->lockers_mutex);
226 Pvoid_t *PValue = JudyLGet(rwlock->lockers_pid_JudyL, pid, PJE0);
227 if(PValue && *PValue)
228 locker = *PValue;
229 __netdata_mutex_unlock(&rwlock->lockers_mutex);
230
231 return locker;
232 }
233
234 static netdata_rwlock_locker *add_rwlock_locker(const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock, LOCKER_REQUEST lock_type) {
235 netdata_rwlock_locker *locker;
236
237 locker = find_rwlock_locker(file, function, line, rwlock);
238 if(locker) {
239 locker->lock |= lock_type;
240 locker->refcount++;
241 }
242 else {
243 locker = mallocz(sizeof(netdata_rwlock_locker));
244 locker->pid = gettid();
245 locker->tag = netdata_thread_tag();
246 locker->refcount = 1;
247 locker->lock = lock_type;
248 locker->got_it = false;
249 locker->file = file;
250 locker->function = function;
251 locker->line = line;
252
253 __netdata_mutex_lock(&rwlock->lockers_mutex);
254 DOUBLE_LINKED_LIST_APPEND_UNSAFE(rwlock->lockers, locker, prev, next);
255 Pvoid_t *PValue = JudyLIns(&rwlock->lockers_pid_JudyL, locker->pid, PJE0);
256 *PValue = locker;
257 if (lock_type == RWLOCK_REQUEST_READ || lock_type == RWLOCK_REQUEST_TRYREAD) rwlock->readers++;
258 if (lock_type == RWLOCK_REQUEST_WRITE || lock_type == RWLOCK_REQUEST_TRYWRITE) rwlock->writers++;
259 __netdata_mutex_unlock(&rwlock->lockers_mutex);
260 }
261
262 return locker;
263 }
264
265 static void remove_rwlock_locker(const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock, netdata_rwlock_locker *locker) {
266 __netdata_mutex_lock(&rwlock->lockers_mutex);
267 locker->refcount--;
268 if(!locker->refcount) {
269 DOUBLE_LINKED_LIST_REMOVE_UNSAFE(rwlock->lockers, locker, prev, next);
270 JudyLDel(&rwlock->lockers_pid_JudyL, locker->pid, PJE0);
271 if (locker->lock == RWLOCK_REQUEST_READ || locker->lock == RWLOCK_REQUEST_TRYREAD) rwlock->readers--;
272 else if (locker->lock == RWLOCK_REQUEST_WRITE || locker->lock == RWLOCK_REQUEST_TRYWRITE) rwlock->writers--;
273 freez(locker);
274 }
275 __netdata_mutex_unlock(&rwlock->lockers_mutex);
276 }
277
278 // ----------------------------------------------------------------------------
279 // debug versions of rwlock
280
281 int netdata_rwlock_destroy_debug(const char *file __maybe_unused, const char *function __maybe_unused,
282 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
283
284 int ret = __netdata_rwlock_destroy(rwlock);
285 if(!ret) {
286 while (rwlock->lockers)
287 remove_rwlock_locker(file, function, line, rwlock, rwlock->lockers);
288 }
289
290 return ret;
291 }
292
293 int netdata_rwlock_init_debug(const char *file __maybe_unused, const char *function __maybe_unused,
294 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
295
296 int ret = __netdata_rwlock_init(rwlock);
297 if(!ret) {
298 __netdata_mutex_init(&rwlock->lockers_mutex);
299 rwlock->lockers_pid_JudyL = NULL;
300 rwlock->lockers = NULL;
301 rwlock->readers = 0;
302 rwlock->writers = 0;
303 }
304
305 return ret;
306 }
307
308 int netdata_rwlock_rdlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
309 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
310
311 netdata_rwlock_locker *locker = add_rwlock_locker(file, function, line, rwlock, RWLOCK_REQUEST_READ);
312
313 int ret = __netdata_rwlock_rdlock(rwlock);
314 if(!ret)
315 locker->got_it = true;
316 else
317 remove_rwlock_locker(file, function, line, rwlock, locker);
318
319 return ret;
320 }
321
322 int netdata_rwlock_wrlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
323 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
324
325 netdata_rwlock_locker *locker = add_rwlock_locker(file, function, line, rwlock, RWLOCK_REQUEST_WRITE);
326
327 int ret = __netdata_rwlock_wrlock(rwlock);
328 if(!ret)
329 locker->got_it = true;
330 else
331 remove_rwlock_locker(file, function, line, rwlock, locker);
332
333 return ret;
334 }
335
336 int netdata_rwlock_rdunlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
337 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
338
339 netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
340
341 if(unlikely(!locker))
342 fatal("UNLOCK WITHOUT LOCK");
343
344 int ret = __netdata_rwlock_rdunlock(rwlock);
345 if(likely(!ret))
346 remove_rwlock_locker(file, function, line, rwlock, locker);
347
348 return ret;
349 }
350
351 int netdata_rwlock_wrunlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
352 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
353
354 netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
355
356 if(unlikely(!locker))
357 fatal("UNLOCK WITHOUT LOCK");
358
359 int ret = __netdata_rwlock_wrunlock(rwlock);
360 if(likely(!ret))
361 remove_rwlock_locker(file, function, line, rwlock, locker);
362
363 return ret;
364 }
365
366 int netdata_rwlock_tryrdlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
367 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
368
369 netdata_rwlock_locker *locker = add_rwlock_locker(file, function, line, rwlock, RWLOCK_REQUEST_TRYREAD);
370
371 int ret = __netdata_rwlock_tryrdlock(rwlock);
372 if(!ret)
373 locker->got_it = true;
374 else
375 remove_rwlock_locker(file, function, line, rwlock, locker);
376
377 return ret;
378 }
379
380 int netdata_rwlock_trywrlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
381 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
382
383 netdata_rwlock_locker *locker = add_rwlock_locker(file, function, line, rwlock, RWLOCK_REQUEST_TRYWRITE);
384
385 int ret = __netdata_rwlock_trywrlock(rwlock);
386 if(!ret)
387 locker->got_it = true;
388 else
389 remove_rwlock_locker(file, function, line, rwlock, locker);
390
391 return ret;
392 }
393
394 #endif // NETDATA_TRACE_RWLOCKS