master
c 92 lines 2.91 KB
Raw
1 #include "object-state.h"
2
3 OBJECT_STATE_ID object_state_id(OBJECT_STATE *os) {
4 return __atomic_load_n(&os->state_id, __ATOMIC_ACQUIRE);
5 }
6
7 void object_state_activate(OBJECT_STATE *os) {
8 __atomic_add_fetch(&os->state_id, 1, __ATOMIC_RELAXED);
9
10 REFCOUNT expected = __atomic_load_n(&os->state_refcount, __ATOMIC_RELAXED);
11 REFCOUNT desired;
12
13 do {
14 if(expected != OBJECT_STATE_DEACTIVATED) {
15 fatal("OBJECT_STATE: attempt to activate already activated object (state refcount is %d)", expected);
16 return;
17 }
18
19 desired = 0;
20
21 } while(!__atomic_compare_exchange_n(
22 &os->state_refcount, &expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED));
23 }
24
25 void object_state_activate_if_not_activated(OBJECT_STATE *os) {
26 __atomic_add_fetch(&os->state_id, 1, __ATOMIC_RELAXED);
27
28 REFCOUNT expected = __atomic_load_n(&os->state_refcount, __ATOMIC_RELAXED);
29 REFCOUNT desired;
30
31 do {
32 if(expected != OBJECT_STATE_DEACTIVATED)
33 return;
34
35 desired = 0;
36
37 } while(!__atomic_compare_exchange_n(
38 &os->state_refcount, &expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED));
39 }
40
41 void object_state_deactivate(OBJECT_STATE *os) {
42 __atomic_add_fetch(&os->state_id, 1, __ATOMIC_RELAXED);
43
44 REFCOUNT expected = __atomic_load_n(&os->state_refcount, __ATOMIC_RELAXED);
45 REFCOUNT desired;
46
47 do {
48 if(expected == OBJECT_STATE_DEACTIVATED) {
49 fatal("OBJECT_STATE: attempt to deactivate object that is already deactivated (state refcount %d)", expected);
50 return;
51 }
52 else if(expected < 0) {
53 fatal("OBJECT_STATE: attempt to deactivate object that is already deactivating (state refcount %d)", expected);
54 return;
55 }
56
57 // Current (-INT32_MAX) + holders
58 desired = OBJECT_STATE_DEACTIVATED + expected;
59
60 } while(!__atomic_compare_exchange_n(
61 &os->state_refcount, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED));
62
63 // Now wait for all holders to release
64 while(__atomic_load_n(&os->state_refcount, __ATOMIC_ACQUIRE) != OBJECT_STATE_DEACTIVATED)
65 tinysleep(); // Busy wait until all holders are gone
66 }
67
68 bool object_state_acquire(OBJECT_STATE *os, OBJECT_STATE_ID wanted_state_id) {
69 REFCOUNT expected = __atomic_load_n(&os->state_refcount, __ATOMIC_RELAXED);
70 REFCOUNT desired;
71
72 do {
73 // If refcount is negative, it means deactivation is in progress or complete
74 if(expected < 0)
75 return false;
76
77 desired = expected + 1;
78
79 } while(!__atomic_compare_exchange_n(
80 &os->state_refcount, &expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED));
81
82 if(object_state_id(os) != wanted_state_id) {
83 object_state_release(os);
84 return false;
85 }
86
87 return true;
88 }
89
90 void object_state_release(OBJECT_STATE *os) {
91 __atomic_sub_fetch(&os->state_refcount, 1, __ATOMIC_RELEASE);
92 }