1/* @title: APCs */
2#pragma once
3#include <atomic.h>
4#include <compiler/core.h>
5#include <irq/irq.h>
6#include <sch/sched.h>
7#include <smp/core.h>
8#include <stdbool.h>
9#include <stddef.h>
10#include <stdint.h>
11#include <structures/list.h>
12#include <thread/apc_types.h>
13#include <thread/thread.h>
14#include <types/refcount.h>
15
16enum apc_state : uint8_t {
17 APC_STATE_IDLE = 0,
18 APC_STATE_QUEUED,
19 APC_STATE_EXECUTING,
20};
21
22struct apc;
23typedef void (*apc_destroy_t)(struct apc *apc);
24
25struct apc_context {
26 struct apc *apc;
27};
28
29struct apc {
30 apc_func_t func;
31 void *ctx;
32 struct thread *owner;
33 struct apc *next;
34 refcount_t refcount;
35 atomic(enum apc_state) state;
36 apc_destroy_t destroy;
37};
38
39struct apc *apc_create(void);
40void apc_init(struct apc *cc_nonnull_ptr a, apc_func_t cc_nonnull_ptr fn,
41 void *arg1, apc_destroy_t destroy);
42bool apc_getref(struct apc *a);
43void apc_putref(struct apc *cc_nonnull_ptr a);
44void apc_destroy_free(struct apc *a);
45void apc_event_signal(struct apc_event_desc *desc);
46
47/* The caller must hold a reference to both t and a. */
48bool apc_enqueue(struct thread *t, struct apc *a, enum apc_type type);
49/* The caller must hold a reference to both t and a. */
50bool apc_cancel(struct thread *t, struct apc *a);
51
52void apc_check_and_deliver(struct thread *t);
53
54void apc_enable_special(void);
55void apc_disable_special(void);
56
57void apc_enable_kernel(void);
58void apc_disable_kernel(void);
59
60void apc_rundown_thread(struct thread *t);
61
62static inline bool apc_enqueue_on_curr(struct apc *a, enum apc_type type) {
63 return apc_enqueue(t: thread_get_current(), a, type);
64}
65
66static inline void apc_queue_init(struct apc_queue *q) {
67 q->head = q->tail = NULL;
68}
69
70static inline cc_always_inline cc_unused void
71apc_kernel_guard_exit(int *unused) {
72 cc_ignore(unused);
73 apc_enable_kernel();
74}
75
76static inline cc_always_inline cc_unused int apc_kernel_guard_enter(void) {
77 apc_disable_kernel();
78 return 0;
79}
80
81static inline cc_always_inline cc_unused void
82apc_special_guard_exit(int *unused) {
83 cc_ignore(unused);
84 apc_enable_special();
85}
86
87static inline cc_always_inline cc_unused int apc_special_guard_enter(void) {
88 apc_disable_special();
89 return 0;
90}
91
92#define apc_kernel_guard() \
93 cc_cleanup(apc_kernel_guard_exit) int PP_CONCAT( \
94 apc_kernel_guard_, __COUNTER__) = apc_kernel_guard_enter()
95
96#define apc_guard() apc_kernel_guard()
97
98#define apc_special_guard() \
99 cc_cleanup(apc_special_guard_exit) int PP_CONCAT( \
100 apc_special_guard_, __COUNTER__) = apc_special_guard_enter()
101