master
h 64 lines 2.06 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_WAITQ_H
4 #define NETDATA_WAITQ_H
5
6 #include "libnetdata/libnetdata.h"
7
8 /*
9 * WAITING QUEUE
10 * Like a spinlock, but:
11 *
12 * 1. Waiters get a sequence number (FIFO)
13 * 2. FIFO is respected within each priority
14 * 3. Higher priority threads get in first
15 *
16 * This is equivalent to 3 atomic operations for lock, and 1 for unlock.
17 *
18 * As lightweight and fast as it can be.
19 * About 3M thread switches/s per WAITING QUEUE, on modern hardware.
20 *
21 * Be careful: higher priority threads can starve the rest!
22 *
23 */
24
25 typedef enum __attribute__((packed)) {
26 WAITQ_PRIO_URGENT = 0, // will be first
27 WAITQ_PRIO_HIGH, // will be second
28 WAITQ_PRIO_NORMAL, // will be third
29 WAITQ_PRIO_LOW, // will be last
30
31 // terminator
32 WAITQ_PRIO_MAX,
33 } WAITQ_PRIORITY;
34
35 typedef struct waiting_queue {
36 SPINLOCK spinlock; // protects the actual resource
37 pid_t writer; // the pid the thread currently holding the lock
38 uint64_t current_priority; // current highest priority attempting to acquire
39 uint32_t last_seqno; // for FIFO ordering within same priority
40 } WAITQ;
41
42 #define WAITQ_INITIALIZER (WAITQ){ .spinlock = SPINLOCK_INITIALIZER, .current_priority = 0, .last_seqno = 0, }
43
44 // Initialize a waiting queue
45 void waitq_init(WAITQ *waitq);
46
47 // Destroy a waiting queue - must be empty
48 void waitq_destroy(WAITQ *wq);
49
50 // Returns true when the queue is acquired
51 bool waitq_try_acquire_with_trace(WAITQ *waitq, WAITQ_PRIORITY priority, const char *func);
52 #define waitq_try_acquire(waitq, priority) waitq_try_acquire_with_trace(waitq, priority, __FUNCTION__)
53
54 // Returns when it is our turn to run
55 // Returns time spent waiting in microseconds
56 void waitq_acquire_with_trace(WAITQ *waitq, WAITQ_PRIORITY priority, const char *func);
57 #define waitq_acquire(waitq, priority) waitq_acquire_with_trace(waitq, priority, __FUNCTION__)
58
59 // Mark that we are done - wakes up the next in line
60 void waitq_release(WAITQ *waitq);
61
62 int unittest_waiting_queue(void);
63
64 #endif // NETDATA_WAITQ_H