aboutsummaryrefslogtreecommitdiff
path: root/include/kpl/object.h
blob: 1f3ec0432cb768418b9be6e4812fd8c6797388da (plain)
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
57
58
59
60
61
62
63
64
65
/*
 * 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_object_task *task, kpl_env *env);

/*
 * Coroutine state object
 */
typedef struct _kpl_object_task {
    KPL_OBJECT_HEADER(_kpl_object_task);
    _Atomic bool join_ready __attribute__((aligned(4))); // shares cache line with variables_size
    int32_t variables_size, io_res; // variables_size is set once then only read
    uint32_t io_flags; // io_res and io_flags are set by io_uring complete
    kpl_object_task *join;
    kpl_task_fn *task_fn;
    kpl_result result;
    kpl_class variables[]; // a task has no distinction between an argument or a local, both live here
} kpl_object_task;