1
#include "internal.h"
2
3
u64 _pid_index_key(pid_t pid) {
4
return (u64)(u32)pid;
5
}6
7
sched_thread_t *pid_get(pid_t pid) {
8
if (!sched_state.procs.pid_index || pid <= 0) {
9
return NULL;
10
}11
12
u64 encoded = 0;
13
if (!hashmap_get(sched_state.procs.pid_index, _pid_index_key(pid), &encoded)) {
14
return NULL;
15
}16
17
sched_thread_t *thread = (sched_thread_t *)(uintptr_t)encoded;
18
if (thread && thread->in_all_list && thread->pid == pid) {
19
return thread;
20
}21
22
if (!hashmap_remove(sched_state.procs.pid_index, _pid_index_key(pid))) {
23
panic("scheduler pid index stale-entry cleanup failed");
24
}25
26
return NULL;
27
}28
29
void pid_set(sched_thread_t *thread) {
30
if (!sched_state.procs.pid_index || !thread || thread->pid <= 0) {
31
return;
32
}33
34
bool inserted = hashmap_set(sched_state.procs.pid_index, _pid_index_key(thread->pid), (u64)(uintptr_t)thread);
35
36
if (!inserted) {
37
panic("scheduler pid index insert failed");
38
}39
}40
41
void pid_remove(pid_t pid) {
42
if (!sched_state.procs.pid_index || pid <= 0) {
43
return;
44
}45
46
u64 encoded = 0;
47
if (!hashmap_get(sched_state.procs.pid_index, _pid_index_key(pid), &encoded)) {
48
return;
49
}50
51
if (!hashmap_remove(sched_state.procs.pid_index, _pid_index_key(pid))) {
52
panic("scheduler pid index remove failed");
53
}54
}55
56
void thread_add(sched_thread_t *thread) {
57
if (!thread || !sched_state.procs.all_list) {
58
return;
59
}60
61
unsigned long flags = sched_lock_save();
62
63
if (thread->in_all_list) {
64
sched_lock_restore(flags);
65
return;
66
}67
68
thread->all_node.data = thread;
69
list_append(sched_state.procs.all_list, &thread->all_node);
70
thread->in_all_list = true;
71
pid_set(thread);
72
sched_lock_restore(flags);
73
}74
75
bool sched_fd_refs_node(const vfs_node_t *node) {
76
if (!node || !sched_state.procs.all_list) {
77
return false;
78
}79
80
bool found = false;
81
unsigned long flags = sched_lock_save();
82
83
ll_foreach(entry, sched_state.procs.all_list) {
84
sched_thread_t *thread = entry->data;
85
86
if (!thread) {
87
continue;
88
}89
90
for (int fd = 0; fd < SCHED_FD_MAX; fd++) {
91
if (!thread->fd_used[fd]) {
92
continue;
93
}94
95
const sched_fd_t *slot = &thread->fds[fd];
96
if (slot->kind != SCHED_FD_VFS || slot->node != node) {
97
continue;
98
}99
100
found = true;
101
break;
102
}103
104
if (found) {
105
break;
106
}107
}108
109
sched_lock_restore(flags);
110
return found;
111
}112
113
void thread_set_name(sched_thread_t *thread, const char *name) {
114
if (!thread) {
115
return;
116
}117
118
const char *src = name ? name : "thread";
119
memset(thread->name, 0, sizeof(thread->name));
120
121
size_t len = strnlen(src, sizeof(thread->name) - 1);
122
123
memcpy(thread->name, src, len);
124
thread->name[len] = '\0';
125
}126
127
static void cleanup_thread(sched_thread_t *thread) {
128
if (!thread || !sched_state.procs.all_list || !thread->in_all_list) {
129
return;
130
}131
132
pid_remove(thread->pid);
133
list_remove(sched_state.procs.all_list, &thread->all_node);
134
thread->in_all_list = false;
135
}136
137
void thread_cleanup(sched_thread_t *thread) {
138
if (!thread || !sched_state.procs.all_list) {
139
return;
140
}141
142
unsigned long flags = sched_lock_save();
143
cleanup_thread(thread);
144
sched_lock_restore(flags);
145
}146
147
sched_thread_t *find_thread(pid_t pid) {
148
if (!sched_state.procs.all_list) {
149
return NULL;
150
}151
152
sched_thread_t *thread = pid_get(pid);
153
if (thread) {
154
return thread;
155
}156
157
ll_foreach(node, sched_state.procs.all_list) {
158
thread = node->data;
159
160
if (thread && thread->pid == pid) {
161
pid_set(thread);
162
return thread;
163
}164
}165
166
return NULL;
167
}168
169
NORETURN void thread_trampoline(void) {
170
sched_thread_t *thread = sched_current();
171
172
if (thread && thread->entry) {
173
thread->entry(thread->arg);
174
}175
176
sched_exit();
177
__builtin_unreachable();
178
}179
180
void thread_get(sched_thread_t *thread) {
181
if (!thread) {
182
return;
183
}184
185
__atomic_fetch_add(&thread->refcount, 1, __ATOMIC_RELAXED);
186
}187
188
void thread_put(sched_thread_t *thread) {
189
if (!thread) {
190
return;
191
}192
193
u32 prev = __atomic_fetch_sub(&thread->refcount, 1, __ATOMIC_ACQ_REL);
194
if (!prev) {
195
__atomic_fetch_add(&thread->refcount, 1, __ATOMIC_RELAXED);
196
return;
197
}198
199
if (prev != 1) {
200
return;
201
}202
203
u32 prior_lifecycle = __atomic_fetch_or(&thread->lifecycle_flags, SCHED_DEFER_QUEUED, __ATOMIC_ACQ_REL);
204
205
if (prior_lifecycle & SCHED_DEFER_QUEUED) {
206
return;
207
}208
209
unsigned long flags = sched_lock_save();
210
211
if (sched_state.procs.deferred_destroy_list && !thread->in_deferred_list) {
212
thread->deferred_node.data = thread;
213
list_append(sched_state.procs.deferred_destroy_list, &thread->deferred_node);
214
thread->in_deferred_list = true;
215
}216
217
sched_lock_restore(flags);
218
}219
220
void thread_destroy(sched_thread_t *thread) {
221
if (!thread) {
222
return;
223
}224
225
thread->magic = 0;
226
227
__atomic_fetch_or(&thread->lifecycle_flags, SCHED_DESTROYING, __ATOMIC_ACQ_REL);
228
229
if (thread->pid > 0) {
230
procfs_unregister_pid(thread->pid);
231
}232
233
sched_fd_close_all(thread);
234
235
sched_clear_user_regions(thread);
236
237
if (thread->vm_space && thread->vm_space != sched_state.core.kernel_vm) {
238
arch_vm_destroy(thread->vm_space);
239
}240
241
sched_wait_queue_destroy(&thread->wait_queue);
242
243
arch_kernel_stack_free(thread);
244
245
free(thread);
246
}247
248
static bool thread_destroy_ready_locked(sched_thread_t *thread) {
249
if (!thread) {
250
return false;
251
}252
253
if (thread->in_all_list || thread->in_zombie_list || thread->in_wait_queue || thread->sleep_queued ||
254
thread->blocked_on) {
255
return false;
256
}257
258
if (thread_is_owned(thread)) {
259
return false;
260
}261
262
if (thread->on_rq || thread->in_run_queue) {
263
rq_remove_thread(thread);
264
}265
266
return !thread->on_rq && !thread->in_run_queue && thread->rq_index == UINT32_MAX;
267
}268
269
void sched_reap_deferred(void) {
270
if (!sched_state.procs.deferred_destroy_list) {
271
return;
272
}273
274
for (;;) {
275
unsigned long flags = sched_lock_save();
276
277
list_node_t *node = list_pop_front(sched_state.procs.deferred_destroy_list);
278
sched_thread_t *thread = node ? node->data : NULL;
279
280
if (thread) {
281
thread->in_deferred_list = false;
282
}283
284
if (thread && !thread_destroy_ready_locked(thread)) {
285
thread->deferred_node.data = thread;
286
list_append(sched_state.procs.deferred_destroy_list, &thread->deferred_node);
287
thread->in_deferred_list = true;
288
sched_lock_restore(flags);
289
break;
290
}291
292
sched_lock_restore(flags);
293
294
if (!thread) {
295
break;
296
}297
298
thread_destroy(thread);
299
}300
}301
302
void sched_reap(void) {
303
if (!sched_state.procs.zombie_list) {
304
sched_reap_deferred();
305
return;
306
}307
308
sched_reap_deferred();
309
310
unsigned long flags = sched_lock_save();
311
list_node_t *node = sched_state.procs.zombie_list->head;
312
313
while (node) {
314
list_node_t *next = node->next;
315
sched_thread_t *thread = node->data;
316
317
if (thread && thread != sched_local_current() && thread != sched_local_idle()) {
318
if (thread->user_thread) {
319
node = next;
320
continue;
321
}322
323
if (thread_cpu(thread) >= 0) {
324
node = next;
325
continue;
326
}327
328
list_remove(sched_state.procs.zombie_list, node);
329
thread->in_zombie_list = false;
330
cleanup_thread(thread);
331
thread_put(thread);
332
}333
334
node = next;
335
}336
337
sched_lock_restore(flags);
338
}