O2 2.0
A communication protocol for interactive music and media applications.
o2atomic.h
1// atomic.h -- atomic list functions for O2
2//
3// Roger B. Dannenberg
4// Oct, 2020
5
6#ifndef __cplusplus
7# include <stdatomic.h>
8#else
9# include <atomic>
10# define _Atomic(X) std::atomic< X >
11#endif
12
13// O2list_elem is a generic linked list element. Although we could use
14// templates to make a generic atomic list, the "C++" way would
15// require either separate list elements that point to objects, or all
16// list elements would have to subclass List_elem and add the overhead
17// of a "next" pointer.
18//
19// Instead, we just cast memory blocks to O2list_elem and overwrite the
20// first 8 bytes with the "next" pointer. This works for freed objects
21// because, well, they are free memory, and because they have a length
22// count stored in the previous 8 bytes before the object (the standard
23// trick used by malloc()), so we don't lose size information when we
24// cast to a different type.
25//
26// Some objects, notably O2message objects, use atomic lists for
27// shared memory, inter-thread communication. These objects have a
28// "next" pointer allocated as their first member variable so that
29// using them in an atomic list does not overwrite anything. In this
30// case, it might make sense to subclass O2list_elem to form O2message,
31// but that would require introducing C++ into the O2 API, which is
32// simpler and more portable if we keep it in C.
33//
34typedef struct O2list_elem {
35 union {
36 struct O2list_elem *next;
37 char data[8];
38 };
40
41
42typedef struct O2queue_na {
43 uintptr_t aba;
44 O2list_elem_ptr first;
46
47typedef _Atomic(O2queue_na) o2_queue;
48typedef _Atomic(O2queue_na) *o2_queue_ptr;
49
50#define O2_QUEUE_INIT {0, NULL}
51
52#if defined(__clang__)
53 #pragma clang diagnostic push
54 #pragma clang diagnostic ignored "-Wunused-private-field"
55#endif
56
57// An atomic queue must be 16-byte aligned, but malloc and O2MALLOC (new)
58// only align to 8 bytes, so the atomic queue here has some padding and
59// we treat it as being whereever the 16-byte boundary occurs. We use a
60// method to find it.
61class O2queue {
62 private:
63 int64_t padding;
64 o2_queue space_for_queue_head;
65 public:
66 o2_queue *queue() {
67 return ((o2_queue *) (((intptr_t) &space_for_queue_head) & ~0xF)); }
68
69 O2queue() { clear(); }
70
71 void clear() {
72 O2queue_na init = O2_QUEUE_INIT;
73 atomic_init(queue(), init);
74 }
75
76 O2list_elem *pop();
77
78 void push(O2list_elem *elem);
79
80 O2list_elem *grab();
81};
82
83#if defined(__clang__)
84 #pragma clang diagnostic pop
85#endif
Definition: o2atomic.h:61
Definition: o2atomic.h:34
Definition: o2atomic.h:42