master
c 101 lines 3.12 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "rrdcollector.h"
4 #include "rrdcollector-internals.h"
5
6 // Each function points to this collector structure
7 // so that when the collector exits, all of them will
8 // be invalidated (running == false)
9 // The last function using this collector
10 // frees the structure too (or when the collector calls
11 // rrdset_collector_finished()).
12
13 struct rrd_collector {
14 REFCOUNT refcount;
15 REFCOUNT refcount_dispatcher;
16 pid_t tid;
17 bool running;
18 };
19
20 // Each thread that adds RRDSET functions has to call
21 // rrdset_collector_started() and rrdset_collector_finished()
22 // to create the collector structure.
23
24 __thread struct rrd_collector *thread_rrd_collector = NULL;
25
26 inline bool rrd_collector_running(struct rrd_collector *rdc) {
27 return __atomic_load_n(&rdc->running, __ATOMIC_RELAXED);
28 }
29
30 inline pid_t rrd_collector_tid(struct rrd_collector *rdc) {
31 return rdc->tid;
32 }
33
34 bool rrd_collector_dispatcher_acquire(struct rrd_collector *rdc) {
35 return refcount_acquire(&rdc->refcount_dispatcher);
36 }
37
38 void rrd_collector_dispatcher_release(struct rrd_collector *rdc) {
39 refcount_release(&rdc->refcount_dispatcher);
40 }
41
42 static void rrd_collector_free(struct rrd_collector *rdc) {
43 if(rrd_collector_running(rdc) || !refcount_acquire_for_deletion(&rdc->refcount))
44 // the collector is still referenced by charts.
45 // leave it hanging there, the last chart will actually free it.
46 return;
47
48 // we can free it now
49 freez(rdc);
50 }
51
52 // called once per collector
53 void rrd_collector_started(void) {
54 if(!thread_rrd_collector)
55 thread_rrd_collector = callocz(1, sizeof(struct rrd_collector));
56
57 thread_rrd_collector->tid = gettid_cached();
58 __atomic_store_n(&thread_rrd_collector->running, true, __ATOMIC_RELAXED);
59 }
60
61 // called once per collector
62 void rrd_collector_finished(void) {
63 if(!thread_rrd_collector)
64 return;
65
66 __atomic_store_n(&thread_rrd_collector->running, false, __ATOMIC_RELAXED);
67
68 // wait for any cancellation requests to be dispatched;
69 // the problem is that cancellation requests require a structure allocated by the collector,
70 // so, while cancellation requests are being dispatched, this structure is accessed.
71 // delaying the exit of the thread is required to avoid cleaning up this structure.
72
73 while(!refcount_acquire_for_deletion(&thread_rrd_collector->refcount_dispatcher))
74 sleep_usec(1 * USEC_PER_MS);
75
76 rrd_collector_free(thread_rrd_collector);
77 thread_rrd_collector = NULL;
78 }
79
80 static bool rrd_collector_acquire(struct rrd_collector *rdc) {
81 if(!rdc || !rrd_collector_running(rdc))
82 return false;
83
84 return refcount_acquire(&rdc->refcount);
85 }
86
87 struct rrd_collector *rrd_collector_acquire_current_thread(void) {
88 rrd_collector_started();
89
90 if(!rrd_collector_acquire(thread_rrd_collector))
91 internal_fatal(true, "FUNCTIONS: Trying to acquire a the current thread collector, that is currently exiting.");
92
93 return thread_rrd_collector;
94 }
95
96 void rrd_collector_release(struct rrd_collector *rdc) {
97 if(unlikely(!rdc)) return;
98
99 if(refcount_release(&rdc->refcount) == 0)
100 rrd_collector_free(rdc);
101 }