/
fork.c
122 lines (107 loc) · 3.14 KB
/
fork.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "debug.h"
#include "kernel/process.h"
#include "kernel/calls.h"
#define CSIGNAL_ 0x000000ff
#define CLONE_VM_ 0x00000100
#define CLONE_FS_ 0x00000200
#define CLONE_FILES_ 0x00000400
#define CLONE_SIGHAND_ 0x00000800
#define CLONE_PTRACE_ 0x00002000
#define CLONE_VFORK_ 0x00004000
#define CLONE_PARENT_ 0x00008000
#define CLONE_THREAD_ 0x00010000
#define CLONE_NEWNS_ 0x00020000
#define CLONE_SYSVSEM_ 0x00040000
#define CLONE_SETTLS_ 0x00080000
#define CLONE_PARENT_SETTID_ 0x00100000
#define CLONE_CHILD_CLEARTID_ 0x00200000
#define CLONE_DETACHED_ 0x00400000
#define CLONE_UNTRACED_ 0x00800000
#define CLONE_CHILD_SETTID_ 0x01000000
#define CLONE_NEWCGROUP_ 0x02000000
#define CLONE_NEWUTS_ 0x04000000
#define CLONE_NEWIPC_ 0x08000000
#define CLONE_NEWUSER_ 0x10000000
#define CLONE_NEWPID_ 0x20000000
#define CLONE_NEWNET_ 0x40000000
#define CLONE_IO_ 0x80000000
static int copy_memory(struct process *proc, int flags) {
struct mem *mem = proc->cpu.mem;
if (flags & CLONE_VM_) {
mem_retain(mem);
return 0;
}
proc->cpu.mem = mem_new();
pt_copy_on_write(mem, 0, proc->cpu.mem, 0, MEM_PAGES);
return 0;
}
static int copy_files(struct process *proc, int flags) {
for (fd_t f = 0; f < MAX_FD; f++) {
if (proc->files[f]) {
proc->files[f] = generic_dup(proc->files[f]);
}
}
return 0;
}
static int init_process(struct process *proc, dword_t flags, addr_t ctid_addr) {
dword_t pid = proc->pid;
*proc = *current;
proc->pid = pid;
proc->ppid = current->pid;
int err = 0;
if ((err = copy_memory(proc, flags)) < 0)
goto fail_free_proc;
if ((err = copy_files(proc, flags)) < 0)
goto fail_free_proc;
proc->parent = current;
list_add(¤t->children, &proc->siblings);
list_init(&proc->children);
proc->cpu.eax = 0;
if (flags & CLONE_CHILD_SETTID_)
if (user_put_proc(proc, ctid_addr, proc->pid)) {
err = _EFAULT;
goto fail_free_proc;
}
start_thread(proc);
if (flags & CLONE_VFORK_)
wait_for(proc, vfork_done);
return 0;
fail_free_proc:
free(proc);
return err;
}
// eax = syscall number
// ebx = flags
// ecx = stack
// edx, esi, edi = unimplemented garbage
dword_t sys_clone(dword_t flags, addr_t stack, addr_t ptid, addr_t tls, addr_t ctid) {
STRACE("clone(%x, 0x%x, blah, blah, blah)", flags, stack);
if (ptid != 0 || tls != 0) {
FIXME("clone with ptid or ts not null");
return _EINVAL;
}
if ((flags & CSIGNAL_) != SIGCHLD_) {
FIXME("clone non sigchld");
return _EINVAL;
}
if (stack == 0)
TODO("clone with nonzero stack");
// stack = current->cpu.esp;
struct process *proc = process_create();
if (proc == NULL)
return _ENOMEM;
lock(proc);
int err = init_process(proc, flags, ctid);
unlock(proc);
if (err < 0) {
process_destroy(proc);
return err;
}
return proc->pid;
}
dword_t sys_fork() {
return sys_clone(SIGCHLD_, current->cpu.esp, 0, 0, 0);
}
dword_t sys_vfork() {
return sys_clone(CLONE_VFORK_ | CLONE_VM_ | SIGCHLD_, current->cpu.esp, 0, 0, 0);
}