git.cappig.dev / apheleiaOS.git master

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
}