taskfs fix up, minor refactoring
[lunaix-os.git] / lunaix-os / kernel / process / sched.c
1 #include <asm/abi.h>
2 #include <asm/mempart.h>
3
4 #include <asm/cpu.h>
5
6 #include <lunaix/fs/taskfs.h>
7 #include <lunaix/mm/cake.h>
8 #include <lunaix/mm/mmap.h>
9 #include <lunaix/mm/pmm.h>
10 #include <lunaix/mm/valloc.h>
11 #include <lunaix/mm/vmm.h>
12 #include <lunaix/mm/procvm.h>
13 #include <lunaix/process.h>
14 #include <lunaix/sched.h>
15 #include <lunaix/signal.h>
16 #include <lunaix/spike.h>
17 #include <lunaix/status.h>
18 #include <lunaix/syscall.h>
19 #include <lunaix/syslog.h>
20 #include <lunaix/hart_state.h>
21 #include <lunaix/kpreempt.h>
22
23 #include <klibc/string.h>
24
25 struct thread empty_thread_obj;
26
27 volatile struct proc_info* __current;
28 volatile struct thread* current_thread = &empty_thread_obj;
29
30 struct scheduler sched_ctx;
31
32 struct cake_pile *proc_pile ,*thread_pile;
33
34 #define root_process   (sched_ctx.procs[1])
35
36 LOG_MODULE("SCHED")
37
38 void
39 sched_init()
40 {
41     proc_pile = cake_new_pile("proc", sizeof(struct proc_info), 1, 0);
42     thread_pile = cake_new_pile("thread", sizeof(struct thread), 1, 0);
43     cake_set_constructor(proc_pile, cake_ctor_zeroing);
44     cake_set_constructor(thread_pile, cake_ctor_zeroing);
45
46     sched_ctx = (struct scheduler){
47         .procs = vzalloc(PROC_TABLE_SIZE), .ptable_len = 0, .procs_index = 0};
48     
49     llist_init_head(&sched_ctx.sleepers);
50 }
51
52 void
53 run(struct thread* thread)
54 {
55     thread->state = PS_RUNNING;
56     thread->process->state = PS_RUNNING;
57     thread->process->th_active = thread;
58
59     procvm_mount_self(vmspace(thread->process));
60     set_current_executing(thread);
61
62     switch_context();
63
64     fail("unexpected return from switching");
65 }
66
67 /*
68     Currently, we do not allow self-destorying thread, doing
69     so will eliminate current kernel stack which is disaster.
70     A compromise solution is to perform a regular scan and 
71     clean-up on these thread, in the preemptible kernel thread.
72 */
73
74 void
75 cleanup_detached_threads() 
76 {
77     // XXX may be a lock on sched_context will ben the most appropriate?
78     cpu_disable_interrupt();
79
80     int i = 0;
81     struct thread *pos, *n;
82     llist_for_each(pos, n, sched_ctx.threads, sched_sibs) {
83         if (likely(!proc_terminated(pos) || !thread_detached(pos))) {
84             continue;
85         }
86
87         struct proc_mm* mm = vmspace(pos->process);
88
89         procvm_mount(mm);
90         destory_thread(pos);
91         procvm_unmount(mm);
92         
93         i++;
94     }
95
96     if (i) {
97         INFO("cleaned %d terminated detached thread(s)", i);
98     }
99
100     cpu_enable_interrupt();
101 }
102
103 bool
104 can_schedule(struct thread* thread)
105 {
106     if (!thread) {
107         return 0;
108     }
109
110     if (proc_terminated(thread)) {
111         return false;
112     }
113
114     if (preempt_check_stalled(thread)) {
115         thread_flags_set(thread, TH_STALLED);
116         return true;
117     }
118
119     if (unlikely(kernel_process(thread->process))) {
120         // a kernel process is always runnable
121         return thread->state == PS_READY;
122     }
123
124     struct sigctx* sh = &thread->sigctx;
125
126     if ((thread->state & PS_PAUSED)) {
127         return !!(sh->sig_pending & ~1);
128     }
129
130     if ((thread->state & PS_BLOCKED)) {
131         return sigset_test(sh->sig_pending, _SIGINT);
132     }
133
134     if (sigset_test(sh->sig_pending, _SIGSTOP)) {
135         // If one thread is experiencing SIGSTOP, then we know
136         // all other threads are also SIGSTOP (as per POSIX-2008.1)
137         // In which case, the entire process is stopped.
138         thread->state = PS_STOPPED;
139         return false;
140     }
141     
142     if (sigset_test(sh->sig_pending, _SIGCONT)) {
143         thread->state = PS_READY;
144     }
145
146     return (thread->state == PS_READY) \
147             && proc_runnable(thread->process);
148 }
149
150 void
151 check_sleepers()
152 {
153     struct thread *pos, *n;
154     time_t now = clock_systime() / 1000;
155
156     llist_for_each(pos, n, &sched_ctx.sleepers, sleep.sleepers)
157     {
158         if (proc_terminated(pos)) {
159             goto del;
160         }
161
162         time_t wtime = pos->sleep.wakeup_time;
163         time_t atime = pos->sleep.alarm_time;
164
165         if (wtime && now >= wtime) {
166             pos->sleep.wakeup_time = 0;
167             pos->state = PS_READY;
168         }
169
170         if (atime && now >= atime) {
171             pos->sleep.alarm_time = 0;
172             thread_setsignal(pos, _SIGALRM);
173         }
174
175         if (!wtime && !atime) {
176         del:
177             llist_delete(&pos->sleep.sleepers);
178         }
179     }
180 }
181
182 void
183 schedule()
184 {
185     assert(sched_ctx.ptable_len && sched_ctx.ttable_len);
186
187     // 上下文切换相当的敏感!我们不希望任何的中断打乱栈的顺序……
188     no_preemption();
189
190     if (!(current_thread->state & ~PS_RUNNING)) {
191         current_thread->state = PS_READY;
192         __current->state = PS_READY;
193
194     }
195
196     procvm_unmount_self(vmspace(__current));
197     check_sleepers();
198
199     // round-robin scheduler
200     
201     struct thread* current = current_thread;
202     struct thread* to_check = current;
203     
204     do {
205         to_check = list_next(to_check, struct thread, sched_sibs);
206
207         if (can_schedule(to_check)) {
208             break;
209         }
210
211         if (to_check == current) {
212             // FIXME do something less leathal here
213             fail("Ran out of threads!")
214             goto done;  
215         }
216
217     } while (1);
218
219     sched_ctx.procs_index = to_check->process->pid;
220
221 done:
222     run(to_check);
223
224     fail("unexpected return from scheduler");
225 }
226
227 __DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
228 {
229     if (!seconds) {
230         return 0;
231     }
232
233     time_t systime = clock_systime() / 1000;
234     struct haybed* bed = &current_thread->sleep;
235
236     if (bed->wakeup_time) {
237         return (bed->wakeup_time - systime);
238     }
239
240     bed->wakeup_time = systime + seconds;
241
242     if (llist_empty(&bed->sleepers)) {
243         llist_append(&sched_ctx.sleepers, &bed->sleepers);
244     }
245
246     store_retval(seconds);
247
248     block_current_thread();
249     schedule();
250
251     return 0;
252 }
253
254 __DEFINE_LXSYSCALL1(unsigned int, alarm, unsigned int, seconds)
255 {
256     struct haybed* bed = &current_thread->sleep;
257     time_t prev_ddl = bed->alarm_time;
258     time_t now = clock_systime() / 1000;
259
260     bed->alarm_time = seconds ? now + seconds : 0;
261
262     if (llist_empty(&bed->sleepers)) {
263         llist_append(&sched_ctx.sleepers, &bed->sleepers);
264     }
265
266     return prev_ddl ? (prev_ddl - now) : 0;
267 }
268
269 __DEFINE_LXSYSCALL1(void, exit, int, status)
270 {
271     terminate_current(status);
272     schedule();
273 }
274
275 __DEFINE_LXSYSCALL(void, yield)
276 {
277     schedule();
278 }
279
280 pid_t
281 _wait(pid_t wpid, int* status, int options);
282
283 __DEFINE_LXSYSCALL1(pid_t, wait, int*, status)
284 {
285     return _wait(-1, status, 0);
286 }
287
288 __DEFINE_LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options)
289 {
290     return _wait(pid, status, options);
291 }
292
293 __DEFINE_LXSYSCALL(int, geterrno)
294 {
295     return current_thread->syscall_ret;
296 }
297
298 pid_t
299 _wait(pid_t wpid, int* status, int options)
300 {
301     pid_t cur = __current->pid;
302     int status_flags = 0;
303     struct proc_info *proc, *n;
304     if (llist_empty(&__current->children)) {
305         return -1;
306     }
307
308     wpid = wpid ? wpid : -__current->pgid;
309
310 repeat:
311     llist_for_each(proc, n, &__current->children, siblings)
312     {
313         if (!~wpid || proc->pid == wpid || proc->pgid == -wpid) {
314             if (proc->state == PS_TERMNAT && !options) {
315                 status_flags |= PEXITTERM;
316                 goto done;
317             }
318             if (proc->state == PS_READY && (options & WUNTRACED)) {
319                 status_flags |= PEXITSTOP;
320                 goto done;
321             }
322         }
323     }
324     if ((options & WNOHANG)) {
325         return 0;
326     }
327     // 放弃当前的运行机会
328     yield_current();
329     goto repeat;
330
331 done:
332     if (status) {
333         *status = PEXITNUM(status_flags, proc->exit_code);
334     }
335     return destroy_process(proc->pid);
336 }
337
338 static inline pid_t
339 get_free_pid() {
340     pid_t i = 0;
341     
342     for (; i < sched_ctx.ptable_len && sched_ctx.procs[i]; i++)
343         ;
344     
345     if (unlikely(i == MAX_PROCESS)) {
346         fail("Panic in Ponyville shimmer!");
347     }
348
349     return i;
350 }
351
352 struct thread*
353 alloc_thread(struct proc_info* process) {
354     if (process->thread_count >= MAX_THREAD_PP) {
355         return NULL;
356     }
357     
358     struct thread* th = cake_grab(thread_pile);
359
360     th->process = process;
361     th->created = clock_systime();
362
363     // FIXME we need a better tid allocation method!
364     th->tid = th->created;
365     th->tid = (th->created ^ ((ptr_t)th)) % MAX_THREAD_PP;
366
367     th->state = PS_CREATED;
368     
369     llist_init_head(&th->sleep.sleepers);
370     llist_init_head(&th->sched_sibs);
371     llist_init_head(&th->proc_sibs);
372     waitq_init(&th->waitqueue);
373
374     return th;
375 }
376
377 struct proc_info*
378 alloc_process()
379 {
380     pid_t i = get_free_pid();
381
382     if (i == sched_ctx.ptable_len) {
383         sched_ctx.ptable_len++;
384     }
385
386     struct proc_info* proc = cake_grab(proc_pile);
387     if (!proc) {
388         return NULL;
389     }
390
391     proc->state = PS_CREATED;
392     proc->pid = i;
393     proc->created = clock_systime();
394     proc->pgid = proc->pid;
395
396     proc->sigreg = vzalloc(sizeof(struct sigregistry));
397     proc->fdtable = vzalloc(sizeof(struct v_fdtable));
398
399     proc->mm = procvm_create(proc);
400     
401     llist_init_head(&proc->tasks);
402     llist_init_head(&proc->children);
403     llist_init_head(&proc->grp_member);
404     llist_init_head(&proc->threads);
405
406     iopoll_init(&proc->pollctx);
407
408     sched_ctx.procs[i] = proc;
409
410     return proc;
411 }
412
413 void
414 commit_thread(struct thread* thread) {
415     struct proc_info* process = thread->process;
416
417     assert(process && !proc_terminated(process));
418
419     llist_append(&process->threads, &thread->proc_sibs);
420     
421     if (sched_ctx.threads) {
422         llist_append(sched_ctx.threads, &thread->sched_sibs);
423     } else {
424         sched_ctx.threads = &thread->sched_sibs;
425     }
426
427     sched_ctx.ttable_len++;
428     process->thread_count++;
429     thread->state = PS_READY;
430 }
431
432 void
433 commit_process(struct proc_info* process)
434 {
435     assert(process == sched_ctx.procs[process->pid]);
436     assert(process->state == PS_CREATED);
437
438     // every process is the child of first process (pid=1)
439     if (!process->parent) {
440         if (likely(!kernel_process(process))) {
441             process->parent = root_process;
442         } else {
443             process->parent = process;
444         }
445     } else {
446         assert(!proc_terminated(process->parent));
447     }
448
449     if (likely(sched_ctx.proc_list)) {
450         llist_append(sched_ctx.proc_list, &process->tasks);
451     } else {
452         sched_ctx.proc_list = &process->tasks;
453     }
454
455     llist_append(&process->parent->children, &process->siblings);
456
457     process->state = PS_READY;
458 }
459
460 void
461 destory_thread(struct thread* thread) 
462 {
463     cake_ensure_valid(thread);
464     
465     struct proc_info* proc = thread->process;
466
467     llist_delete(&thread->sched_sibs);
468     llist_delete(&thread->proc_sibs);
469     llist_delete(&thread->sleep.sleepers);
470     waitq_cancel_wait(&thread->waitqueue);
471
472     thread_release_mem(thread);
473
474     proc->thread_count--;
475     sched_ctx.ttable_len--;
476
477     cake_release(thread_pile, thread);
478 }
479
480 static void
481 orphan_children(struct proc_info* proc)
482 {
483     struct proc_info *root;
484     struct proc_info *pos, *n;
485
486     root = root_process;
487
488     llist_for_each(pos, n, &proc->children, siblings) {
489         pos->parent = root;
490         llist_append(&root->children, &pos->siblings);
491     }
492 }
493
494 void 
495 delete_process(struct proc_info* proc)
496 {
497     pid_t pid = proc->pid;
498     struct proc_mm* mm = vmspace(proc);
499
500     assert(pid);    // long live the pid0 !!
501
502     sched_ctx.procs[pid] = NULL;
503
504     llist_delete(&proc->siblings);
505     llist_delete(&proc->grp_member);
506     llist_delete(&proc->tasks);
507
508     iopoll_free(proc);
509
510     taskfs_invalidate(pid);
511
512     if (proc->cwd) {
513         vfs_unref_dnode(proc->cwd);
514     }
515
516     if (proc->cmd) {
517         vfree(proc->cmd);
518     }
519
520     for (size_t i = 0; i < VFS_MAX_FD; i++) {
521         struct v_fd* fd = proc->fdtable->fds[i];
522         if (fd) {
523             vfs_pclose(fd->file, pid);
524             vfs_free_fd(fd);
525         }
526     }
527
528     vfree(proc->fdtable);
529
530     signal_free_registry(proc->sigreg);
531
532     procvm_mount(mm);
533     
534     struct thread *pos, *n;
535     llist_for_each(pos, n, &proc->threads, proc_sibs) {
536         // terminate and destory all thread unconditionally
537         destory_thread(pos);
538     }
539
540     orphan_children(proc);
541
542     procvm_unmount_release(mm);
543
544     cake_release(proc_pile, proc);
545 }
546
547 pid_t
548 destroy_process(pid_t pid)
549 {    
550     int index = pid;
551     if (index <= 0 || index > sched_ctx.ptable_len) {
552         syscall_result(EINVAL);
553         return -1;
554     }
555
556     struct proc_info* proc = sched_ctx.procs[index];
557     delete_process(proc);
558
559     return pid;
560 }
561
562 static void 
563 terminate_proc_only(struct proc_info* proc, int exit_code) {
564     assert(proc->pid != 0);
565
566     proc->state = PS_TERMNAT;
567     proc->exit_code = exit_code;
568
569     proc_setsignal(proc->parent, _SIGCHLD);
570 }
571
572 void
573 terminate_thread(struct thread* thread, ptr_t val) {
574     thread->exit_val = val;
575     thread->state = PS_TERMNAT;
576
577     struct proc_info* proc = thread->process;
578     if (proc->thread_count == 1) {
579         terminate_proc_only(thread->process, 0);
580     }
581 }
582
583 void
584 terminate_current_thread(ptr_t val) {
585     terminate_thread(current_thread, val);
586 }
587
588 void 
589 terminate_proccess(struct proc_info* proc, int exit_code) {
590     assert(!kernel_process(proc));
591
592     if (proc->pid == 1) {
593         fail("Attempt to kill init");
594     }
595
596     terminate_proc_only(proc, exit_code);
597
598     struct thread *pos, *n;
599     llist_for_each(pos, n, &proc->threads, proc_sibs) {
600         pos->state = PS_TERMNAT;
601     }
602 }
603
604 void
605 terminate_current(int exit_code)
606 {
607     terminate_proccess(__current, exit_code);
608 }
609
610 struct proc_info*
611 get_process(pid_t pid)
612 {
613     int index = pid;
614     if (index < 0 || index > sched_ctx.ptable_len) {
615         return NULL;
616     }
617     return sched_ctx.procs[index];
618 }
619
620 int
621 orphaned_proc(pid_t pid)
622 {
623     if (!pid)
624         return 0;
625     if (pid >= sched_ctx.ptable_len)
626         return 0;
627     struct proc_info* proc = sched_ctx.procs[pid];
628     struct proc_info* parent = proc->parent;
629
630     // 如果其父进程的状态是terminated 或 destroy中的一种
631     // 或者其父进程是在该进程之后创建的,那么该进程为孤儿进程
632     return proc_terminated(parent) || parent->created > proc->created;
633 }