1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
/*
* KPL specific objects
*/
#pragma once
// for atomic linked list queue
// size in bytes, index on the kpl_threads array
#define KPL_OBJECT_HEADER(STRUCT_NAME) \
struct STRUCT_NAME *_Atomic queue_next; \
int32_t object_size, thread_id
typedef struct _kpl_object {
KPL_OBJECT_HEADER(_kpl_object);
} kpl_object; // all kpl objects allocated by the kpl memory allocator extend this header
/*
* Atomic linked list queue any thread can add, only owner thread can remove
*/
typedef struct {
kpl_object *_Atomic head, *tail; // head is modified with atomic exchange
struct {
kpl_object *_Atomic queue_next;
} dummy; // head and tail are never null will always point to this
} kpl_object_queue;
/*
* Only owner thread can call this
*/
inline void kpl_object_queue_init(kpl_object_queue *object_queue) {
__atomic_store_n(&object_queue->dummy.queue_next, NULL, __ATOMIC_RELAXED);
__atomic_store_n(&object_queue->head, &object_queue->dummy, __ATOMIC_RELAXED);
object_queue->tail = (kpl_object*) &object_queue->dummy;
}
/*
* Always succeeds, any thread can call this
*/
inline void kpl_object_queue_enqueue(kpl_object_queue *object_queue, void *object) {
kpl_object *obj = object;
__atomic_store_n(&obj->queue_next, NULL, __ATOMIC_RELAXED);
kpl_object *head = __atomic_exchange_n(&object_queue->head, obj, __ATOMIC_SEQ_CST);
__atomic_store_n(&head->queue_next, obj, __ATOMIC_RELEASE);
}
/*
* Null for not found, only owner thread can call this
*/
void *kpl_object_queue_dequeue(kpl_object_queue *object_queue);
typedef void kpl_task_fn(kpl_task *task, kpl_env *env);
typedef struct _kpl_task {
KPL_OBJECT_HEADER(_kpl_task);
// TODO
} kpl_task;
|