Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/syscall/fork.c
2093 views
1
#include <types.h>
2
#include <lib.h>
3
#include <copyinout.h>
4
#include <proc.h>
5
#include <thread.h>
6
#include <current.h>
7
#include <filedesc.h>
8
#include <addrspace.h>
9
#include <kern/errno.h>
10
#include <machine/trapframe.h>
11
#include <synch.h>
12
#include <syscall.h>
13
14
/**
15
* structure containings all the information
16
* necessary for the child fork thread.
17
*/
18
struct child_fork_args {
19
struct addrspace *as_source;
20
struct proc *td_proc;
21
struct trapframe *tf;
22
};
23
24
25
/**
26
* this is the first function that gets executed
27
* when the child thread runs.
28
*/
29
static
30
void
31
fork_child_return( void *v_args, unsigned long not_used ) {
32
struct child_fork_args *args = NULL;
33
struct trapframe tf;
34
35
(void)not_used;
36
37
//cast to something we can work with.
38
args = v_args;
39
40
//the return value of fork() for the child is 0.
41
args->tf->tf_v0 = 0;
42
args->tf->tf_a3 = 0;
43
44
//skip to the next instruction to avoid fork()ing again.
45
args->tf->tf_epc += 4;
46
47
//make the current thread aware of its process.
48
curthread->td_proc = args->td_proc;
49
50
//set the current addrspace.
51
KASSERT( curthread->t_addrspace == NULL );
52
curthread->t_addrspace = args->as_source;
53
54
//activate it.
55
as_activate( curthread->t_addrspace );
56
57
//copy from kernel stack into user stack.
58
memcpy( &tf, args->tf, sizeof( struct trapframe ) );
59
60
//clean-up the arguments passed by fork().
61
kfree( args->tf );
62
kfree( args );
63
64
//off we go to usermode.
65
mips_usermode( &tf );
66
}
67
68
/**
69
* helper function to clone a trapframe.
70
*/
71
static
72
int
73
trapframe_clone( struct trapframe *tf, struct trapframe **newtf ) {
74
*newtf = kmalloc( sizeof( struct trapframe ) );
75
if( *newtf == NULL )
76
return ENOMEM;
77
78
memcpy( *newtf, tf, sizeof( struct trapframe ) );
79
return 0;
80
}
81
82
int
83
sys_fork( struct trapframe *tf, int *retval ) {
84
struct proc *p_new = NULL;
85
struct trapframe *tf_new = NULL;
86
int err;
87
struct child_fork_args *args;
88
pid_t pid;
89
90
KASSERT( curthread != NULL );
91
KASSERT( curthread->td_proc != NULL );
92
KASSERT( tf != NULL );
93
94
//attempt to create a clone.
95
err = proc_clone( curthread->td_proc, &p_new );
96
if( err )
97
return err;
98
99
//hold on to the pid.
100
pid = p_new->p_pid;
101
102
//set the parent process of the new process to be us.
103
p_new->p_proc = curthread->td_proc;
104
105
//clone the trapframe.
106
err = trapframe_clone( tf, &tf_new );
107
if( err ) {
108
file_close_all( p_new );
109
proc_destroy( p_new );
110
return err;
111
}
112
113
//prepare the arguments for the fork child thread.
114
args = kmalloc( sizeof( struct child_fork_args ) );
115
if( args == NULL ) {
116
kfree( tf_new );
117
file_close_all( p_new );
118
proc_destroy( p_new );
119
return ENOMEM;
120
}
121
122
//copy the trapframe and wrapping proc
123
//into the args structure.
124
args->tf = tf_new;
125
args->td_proc = p_new;
126
127
//copy the addresspace.
128
err = as_copy( curthread->t_addrspace, &args->as_source );
129
if( err ) {
130
//clean after ourselves.
131
kfree( args->tf );
132
kfree( args );
133
134
file_close_all( p_new );
135
proc_destroy( p_new );
136
return err;
137
}
138
139
//finalize the creation of the thread.
140
err = thread_fork(
141
curthread->t_name,
142
fork_child_return,
143
args,
144
0,
145
NULL
146
);
147
148
//oh well, thread creation failed.
149
//make sure we clean-up after ourselves.
150
if( err ) {
151
as_destroy( args->as_source );
152
kfree( args->tf );
153
kfree( args );
154
155
//close all possible files open by the proc.
156
file_close_all( p_new );
157
proc_destroy( p_new );
158
return err;
159
}
160
161
162
//parent returns with no errors.
163
*retval = pid;
164
return 0;
165
}
166
167