1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/filesystem/dentry.h" |
4 | #include "mos/filesystem/vfs.h" |
5 | #include "mos/mm/mm.h" |
6 | #include "mos/tasks/schedule.h" |
7 | #include "mos/tasks/signal.h" |
8 | |
9 | #include <mos/lib/structures/hashmap.h> |
10 | #include <mos/lib/structures/list.h> |
11 | #include <mos/lib/structures/stack.h> |
12 | #include <mos/lib/sync/spinlock.h> |
13 | #include <mos/mm/cow.h> |
14 | #include <mos/mm/paging/paging.h> |
15 | #include <mos/mos_global.h> |
16 | #include <mos/platform/platform.h> |
17 | #include <mos/syslog/printk.h> |
18 | #include <mos/tasks/process.h> |
19 | #include <mos/tasks/task_types.h> |
20 | #include <mos/tasks/thread.h> |
21 | #include <mos_stdlib.h> |
22 | #include <mos_string.h> |
23 | |
24 | extern const char *vmap_type_str[]; |
25 | |
26 | process_t *process_do_fork(process_t *parent) |
27 | { |
28 | MOS_ASSERT(process_is_valid(parent)); |
29 | |
30 | process_t *child_p = process_allocate(parent, name: parent->name); |
31 | if (unlikely(!child_p)) |
32 | { |
33 | pr_emerg("failed to allocate process for fork" ); |
34 | return NULL; |
35 | } |
36 | |
37 | child_p->working_directory = dentry_ref_up_to(dentry: parent->working_directory, root: root_dentry); |
38 | |
39 | pr_demph(process, "process %d forked to %d" , parent->pid, child_p->pid); |
40 | |
41 | mm_lock_ctx_pair(ctx1: parent->mm, ctx2: child_p->mm); |
42 | list_foreach(vmap_t, vmap_p, parent->mm->mmaps) |
43 | { |
44 | vmap_t *child_vmap = NULL; |
45 | switch (vmap_p->type) |
46 | { |
47 | case VMAP_TYPE_SHARED: child_vmap = mm_clone_vmap_locked(src_vmap: vmap_p, dst_ctx: child_p->mm); break; |
48 | case VMAP_TYPE_PRIVATE: child_vmap = cow_clone_vmap_locked(target_mmctx: child_p->mm, source_vmap: vmap_p); break; |
49 | default: mos_panic("unknown vmap" ); break; |
50 | } |
51 | pr_dinfo2(process, "fork vmap %d->%d: %10s, %pvm -> %pvm" , parent->pid, child_p->pid, vmap_type_str[vmap_p->type], (void *) vmap_p, (void *) child_vmap); |
52 | vmap_finalise_init(vmap: child_vmap, content: vmap_p->content, type: vmap_p->type); |
53 | } |
54 | |
55 | mm_unlock_ctx_pair(ctx1: parent->mm, ctx2: child_p->mm); |
56 | |
57 | // copy the parent's files |
58 | for (int i = 0; i < MOS_PROCESS_MAX_OPEN_FILES; i++) |
59 | { |
60 | fd_type file = parent->files[i]; |
61 | if (io_valid(io: file.io)) |
62 | { |
63 | child_p->files[i].io = io_ref(io: file.io); |
64 | child_p->files[i].flags = file.flags; |
65 | } |
66 | } |
67 | |
68 | child_p->signal_info = parent->signal_info; |
69 | waitlist_init(list: &child_p->signal_info.sigchild_waitlist); |
70 | |
71 | // copy the thread |
72 | thread_t *const parent_thread = current_thread; |
73 | thread_t *child_t = thread_allocate(owner: child_p, tflags: parent_thread->mode); |
74 | pr_dinfo2(process, "fork: thread %d->%d" , parent_thread->tid, child_t->tid); |
75 | child_t->u_stack = parent_thread->u_stack; |
76 | child_t->name = strdup(src: parent_thread->name); |
77 | const ptr_t kstack_blk = phyframe_va(mm_get_free_pages(MOS_STACK_PAGES_KERNEL)); |
78 | stack_init(stack: &child_t->k_stack, mem_region_bottom: (void *) kstack_blk, MOS_STACK_PAGES_KERNEL * MOS_PAGE_SIZE); |
79 | spinlock_acquire(&parent_thread->signal_info.lock); |
80 | child_t->signal_info.mask = parent_thread->signal_info.mask; |
81 | list_foreach(sigpending_t, sig, parent_thread->signal_info.pending) |
82 | { |
83 | sigpending_t *new_sig = kmalloc(sigpending_slab); |
84 | linked_list_init(list_node(new_sig)); |
85 | new_sig->signal = sig->signal; |
86 | list_node_prepend(head: &child_t->signal_info.pending, list_node(new_sig)); |
87 | } |
88 | spinlock_release(&parent_thread->signal_info.lock); |
89 | |
90 | platform_context_clone(from: parent_thread, to: child_t); |
91 | |
92 | hashmap_put(map: &process_table, key: child_p->pid, value: child_p); |
93 | thread_complete_init(thread: child_t); |
94 | scheduler_add_thread(thread: child_t); |
95 | return child_p; |
96 | } |
97 | |