1/* @title: Daemons */
2#pragma once
3#include <structures/list.h>
4#include <sync/semaphore.h>
5#include <thread/thread.h>
6#include <thread/workqueue.h>
7
8/* These commands are sent back up to the daemon
9 * thread executing a daemon work and are operated
10 * upon the completion of the daemon work */
11enum daemon_thread_command {
12 DAEMON_THREAD_COMMAND_NONE,
13 DAEMON_THREAD_COMMAND_EXIT, /* Daemon thread exit */
14 DAEMON_THREAD_COMMAND_RESTART, /* Restart the function */
15 DAEMON_THREAD_COMMAND_SLEEP, /* Go to sleep */
16 DAEMON_THREAD_COMMAND_DEFAULT =
17 DAEMON_THREAD_COMMAND_SLEEP, /* By default we sleep after
18 * the daemon work returns */
19};
20
21struct daemon_thread {
22 struct list_head list_node;
23 bool background;
24 struct thread *thread;
25 struct daemon *daemon; /* What daemon are we attached to? */
26
27 atomic_bool executing_work;
28 enum daemon_thread_command command;
29};
30
31struct daemon_work;
32
33typedef enum daemon_thread_command (*daemon_fn)(
34 void *arg, /* Daemon work provided arg1 */
35 void *arg2 /* Daemon work provided arg2 */
36);
37
38struct daemon_work {
39 daemon_fn function;
40 struct work_args args;
41 struct daemon *daemon;
42 void *private; /* Whatever anything wants */
43};
44#define DAEMON_WORK_FROM(fn, a) \
45 ((struct daemon_work) {.function = fn, .args = a})
46
47enum daemon_flags {
48 DAEMON_FLAG_HAS_WORKQUEUE = 1,
49 DAEMON_FLAG_HAS_NAME = 1 << 1,
50 DAEMON_FLAG_AUTO_SPAWN = 1 << 2,
51 DAEMON_FLAG_NO_TS_THREADS = 1 << 3,
52 DAEMON_FLAG_NONE = 0,
53};
54
55struct daemon_attributes {
56 size_t max_timesharing_threads;
57 size_t min_timesharing_threads;
58
59 atomic_size_t timesharing_threads; /* Internal */
60 atomic_size_t idle_timesharing_threads; /* Internal */
61 atomic_bool background_thread_present; /* Internal */
62
63 struct cpu_mask thread_cpu_mask;
64
65 enum daemon_flags flags;
66};
67
68enum daemon_state {
69 DAEMON_STATE_ACTIVE,
70 DAEMON_STATE_DESTROYING,
71 DAEMON_STATE_DEAD,
72};
73
74static inline const char *daemon_state_str(enum daemon_state s) {
75 switch (s) {
76 case DAEMON_STATE_ACTIVE: return "ACTIVE";
77 case DAEMON_STATE_DESTROYING: return "DESTROYING";
78 case DAEMON_STATE_DEAD: return "DEAD";
79 }
80 return "UNKNOWN";
81}
82
83struct daemon {
84 char *name;
85 struct semaphore ts_sem;
86 struct semaphore bg_sem;
87
88 struct list_head timesharing_threads;
89 struct daemon_work *timesharing_work;
90
91 struct daemon_thread *background_thread;
92 struct daemon_work *background_work;
93
94 struct workqueue *workqueue;
95
96 struct daemon_attributes attrs;
97
98 struct spinlock lock;
99 enum daemon_state state;
100};
101
102#define daemon_thread_from_list_node(ln) \
103 container_of(ln, struct daemon_thread, list_node)
104
105struct daemon *daemon_create(const char *fmt, struct daemon_attributes *attrs,
106 struct daemon_work *timesharing_work,
107 struct daemon_work *background_work,
108 struct workqueue_attributes *wq_attrs, ...);
109
110void daemon_destroy(struct daemon *daemon);
111
112struct daemon_thread *daemon_spawn_worker(struct daemon *daemon);
113
114enum workqueue_error daemon_submit_oneshot_work(struct daemon *daemon,
115 work_function func,
116 struct work_args args);
117
118enum workqueue_error daemon_submit_work(struct daemon *daemon,
119 struct work *work);
120
121void daemon_print(struct daemon *daemon);
122void daemon_wake_background_worker(struct daemon *daemon);
123void daemon_wake_timesharing_worker(struct daemon *daemon);
124void daemon_wake_all_idle_timesharing_workers(struct daemon *daemon);
125
126#define DAEMON_FLAG_TEST(daemon, flag) (daemon->attrs.flags & flag)
127