master
c 137 lines 3.71 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "completion.h"
4
5 ALWAYS_INLINE void completion_reset(struct completion *p)
6 {
7 if (!p)
8 return;
9 p->completed = 0;
10 p->completed_jobs = 0;
11 }
12
13 ALWAYS_INLINE void completion_init(struct completion *p)
14 {
15 p->completed = 0;
16 p->completed_jobs = 0;
17 fatal_assert(0 == netdata_cond_init(&p->cond));
18 fatal_assert(0 == netdata_mutex_init(&p->mutex));
19 }
20
21 ALWAYS_INLINE void completion_destroy(struct completion *p)
22 {
23 netdata_cond_destroy(&p->cond);
24 netdata_mutex_destroy(&p->mutex);
25 }
26
27 ALWAYS_INLINE void completion_wait_for(struct completion *p)
28 {
29 netdata_mutex_lock(&p->mutex);
30 while (0 == p->completed) {
31 netdata_cond_wait(&p->cond, &p->mutex);
32 }
33 fatal_assert(1 == p->completed);
34 netdata_mutex_unlock(&p->mutex);
35 }
36
37 ALWAYS_INLINE bool completion_timedwait_for(struct completion *p, uint64_t timeout_s)
38 {
39 uint64_t timeout_ns = timeout_s * NSEC_PER_SEC;
40 if (timeout_ns == 0) timeout_ns = 1;
41
42 uint64_t deadline_ns = uv_hrtime() + timeout_ns;
43 bool result = true;
44
45 netdata_mutex_lock(&p->mutex);
46 while (!p->completed && result) {
47 uint64_t current_time_ns = uv_hrtime();
48
49 // Check if we've already exceeded the deadline
50 if (current_time_ns >= deadline_ns) {
51 result = false;
52 break;
53 }
54
55 uint64_t remaining_timeout_ns = deadline_ns - current_time_ns;
56
57 int rc = netdata_cond_timedwait(&p->cond, &p->mutex, remaining_timeout_ns);
58
59 if (rc == UV_ETIMEDOUT)
60 result = false;
61
62 // Condition was signaled (or spurious wakeup).
63 // The loop condition `!p->completed` will be re-evaluated.
64 // If p->completed is true, the loop exits.
65 // If p->completed is false (spurious wakeup), the loop continues with a new remaining_timeout_ns.
66 }
67 netdata_mutex_unlock(&p->mutex);
68
69 return result;
70 }
71
72 ALWAYS_INLINE void completion_mark_complete(struct completion *p)
73 {
74 netdata_mutex_lock(&p->mutex);
75 p->completed = 1;
76 netdata_cond_broadcast(&p->cond);
77 netdata_mutex_unlock(&p->mutex);
78 }
79
80 ALWAYS_INLINE unsigned completion_wait_for_a_job(struct completion *p, unsigned completed_jobs)
81 {
82 netdata_mutex_lock(&p->mutex);
83 while (0 == p->completed && p->completed_jobs <= completed_jobs) {
84 netdata_cond_wait(&p->cond, &p->mutex);
85 }
86 completed_jobs = p->completed_jobs;
87 netdata_mutex_unlock(&p->mutex);
88
89 return completed_jobs;
90 }
91
92 ALWAYS_INLINE unsigned completion_wait_for_a_job_with_timeout(struct completion *p, unsigned completed_jobs, uint64_t timeout_ms)
93 {
94 uint64_t timeout_ns = timeout_ms * NSEC_PER_MSEC;
95 if (timeout_ns == 0) timeout_ns = 1;
96
97 uint64_t deadline_ns = uv_hrtime() + timeout_ns;
98
99 netdata_mutex_lock(&p->mutex);
100
101 while (p->completed == 0 && p->completed_jobs <= completed_jobs) {
102 uint64_t current_time_ns = uv_hrtime();
103
104 // Check if we've already exceeded the deadline
105 if (current_time_ns >= deadline_ns) {
106 break;
107 }
108
109 uint64_t remaining_timeout_ns = deadline_ns - current_time_ns;
110
111 int rc = netdata_cond_timedwait(&p->cond, &p->mutex, remaining_timeout_ns);
112 if (rc == UV_ETIMEDOUT)
113 break;
114 }
115
116 completed_jobs = p->completed_jobs;
117 netdata_mutex_unlock(&p->mutex);
118
119 return completed_jobs;
120 }
121
122 ALWAYS_INLINE void completion_mark_complete_a_job(struct completion *p)
123 {
124 netdata_mutex_lock(&p->mutex);
125 p->completed_jobs++;
126 netdata_cond_broadcast(&p->cond);
127 netdata_mutex_unlock(&p->mutex);
128 }
129
130 ALWAYS_INLINE bool completion_is_done(struct completion *p)
131 {
132 bool ret;
133 netdata_mutex_lock(&p->mutex);
134 ret = p->completed;
135 netdata_mutex_unlock(&p->mutex);
136 return ret;
137 }