source: trunk/kernel/syscalls/sys_fork.c@ 23

Last change on this file since 23 was 23, checked in by alain, 9 years ago

Introduce syscalls.

File size: 7.7 KB
Line 
1/*
2 * sys_fork.c - Fork the current process.
3 *
4 * Authors Alain Greiner (2016,2017)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <kernel_config.h>
25#include <hal_types.h>
26#include <hal_atomic.h>
27#include <errno.h>
28#include <printk.h>
29#include <core.h>
30#include <cluster.h>
31#include <list.h>
32#include <thread.h>
33#include <scheduler.h>
34#include <kmem.h>
35#include <dqdt.h>
36#include <process.h>
37
38//////////////
39int sys_fork()
40{
41 process_t * parent_process; // pointer on parent process descriptor
42 pid_t parent_pid; // parent process identifier
43 thread_t * parent_thread; // pointer on parent thread descriptor
44 process_t * child_process; // pointer on child process descriptor
45 pid_t child_pid; // child process identifier
46 thread_t * child_thread; // pointer on child main thread descriptor
47 trdid_t child_trdid; // child main thread identifier
48 lid_t child_core_lid; // core local index for the child main thread
49 cxy_t target_cxy; // final target cluster for forked child process
50 error_t error;
51
52 // get pointers on parent process and thread
53 parent_thread = CURRENT_THREAD;
54 parent_process = parent_thread->process;
55 parent_pid = parent_process->pid;
56
57 // check parent process children number
58 if( hal_atomic_add( &parent_process->children_nr , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
59 {
60 printk("\n[ERROR] in %s : too much children processes\n", __FUNCTION__);
61 hal_atomic_add ( &parent_process->children_nr , -1 );
62 return EAGAIN;
63 }
64
65 fork_dmsg("\n[INFO] %s : enters for process %d at cycle [%d]\n",
66 __FUNCTION__, parent_process->pid, hal_time_stamp());
67
68 // save FPU state in fpu_context if parent process is FPU owner
69 // because we want the child process to share the FPU context
70 if( CURRENT_CORE->fpu_owner == parent_thread )
71 {
72 hal_fpu_context_save( parent_thread );
73 fork_dmsg("\n[INFO] %s : save FPU\n", __FUNCTION__);
74 }
75
76 // Select target cluster for future migration of child process and main thread.
77 // If placement is not user-defined, the placement is defined by the DQDT.
78 // The two first processes ("init" and "sh") on boot cluster do not migrate.
79
80 if( parent_thread->fork_user )
81 {
82 // user defined placement
83 target_cxy = parent_thread->fork_cxy;
84 parent_thread->fork_user = false;
85 }
86 else if( (LPID_FROM_PID(parent_process->pid) < 2) && (local_cxy == 0) )
87 {
88 // 2 first process stay in boot cluster
89 target_cxy = local_cxy;
90 }
91 else
92 {
93 // DQDT placement
94 target_cxy = dqdt_get_cluster_for_process();
95 }
96
97 fork_dmsg("INFO : %s select target_cluster = %x\n",
98 __FUNCTION__ , target_cxy );
99
100 // allocates memory in local cluster for the child process descriptor
101 child_process = process_alloc();
102
103 if( child_process == NULL )
104 {
105 printk("\n[ERROR] in %s : cannot allocate child process\n", __FUNCTION__ );
106 hal_atomic_add ( &parent_process->children_nr , -1 );
107 return EAGAIN;
108 }
109
110 // get a new PID for child process,
111 if( target_cxy == local_cxy ) // target cluster is local
112 {
113 error = cluster_pid_alloc( XPTR( target_cxy , child_process ) , &child_pid );
114 }
115 else // target cluster is remote
116 {
117 rpc_process_pid_alloc_client( target_cxy , child_process , &error , &child_pid );
118 }
119
120 if( error )
121 {
122 printk("\n[ERROR] in %s : cannot allocate PID\n", __FUNCTION__ );
123 hal_atomic_add ( &parent_process->children_nr , -1 );
124 process_destroy( child_process );
125 return EAGAIN;
126 }
127
128 // initialize and register the child process descriptor
129 process_reference_init( child_process , child_pid , parent_pid );
130
131 fork_dmsg("\n[INFO] : %s created child process : pid = %x / ppid = %x\n",
132 __FUNCTION__, child_pid , parent_pid );
133
134 // initialises child process standard files structures
135 // ( root / cwd / bin ) from parent process descriptor
136
137 vfs_file_count_up( parent_process->vfs_root_xp );
138 child_process->vfs_root_xp = parent_process->vfs_root_xp;
139
140 vfs_file_count_up( parent_process->vfs_cwd_xp );
141 child_process->vfs_cwd_xp = parent_process->vfs_cwd_xp;
142
143 vfs_file_count_up( parent_process->vfs_bin_xp );
144 child_process->vfs_bin_xp = parent_process->vfs_bin_xp;
145
146 // copy the parent process fd_array to the child process fd_array
147 process_fd_remote_copy( XPTR( local_cxy , &child_process->fd_array ),
148 XPTR( local_cxy , &parent_process->fd_array ) );
149
150 fork_dmsg("\n[INFO] %s : duplicated child process from parent process\n",
151 __FUNCTION__ );
152
153 // replicates virtual memory manager
154 error = vmm_copy( child_process , parent_process );
155
156 if( error )
157 {
158 printk("\n[ERROR] in %s : cannot duplicate VMM\n", __FUNCTION__ );
159 hal_atomic_add ( &parent_process->children_nr , -1 );
160 process_destroy( child_process );
161 return ENOMEM;
162 }
163
164 fork_dmsg("\n[INFO] %s : parent vmm duplicated in child process\n", __FUNCTION__ );
165
166 // create child main thread descriptor in local cluster
167 error = thread_user_fork( parent_process , &child_thread );
168
169 if( error )
170 {
171 printk("\n[ERROR] in %s : cannot duplicate thread\n", __FUNCTION__ );
172 hal_atomic_add( &parent_process->children_nr , -1 );
173 process_destroy( child_process );
174 return ENOMEM;
175 }
176
177 // register child thread in child process, and get a TRDID
178 spinlock_lock( &child_process->th_lock );
179 error = process_register_thread( child_process, child_thread , &child_trdid );
180 spinlock_unlock( &child_process->th_lock );
181
182 if( error )
183 {
184 printk("\n[ERROR] in %s : cannot register thread\n", __FUNCTION__ );
185 hal_atomic_add ( &parent_process->children_nr , -1 );
186 thread_destroy( child_thread );
187 process_destroy( child_process );
188 return EAGAIN;
189 }
190
191 // get a local core to execute child thread
192 child_core_lid = cluster_select_local_core();
193
194 // Update child thread descriptor
195 child_thread->core = &LOCAL_CLUSTER->core_tbl[child_core_lid];
196 child_thread->process = child_process;
197 child_thread->trdid = child_trdid;
198
199 fork_dmsg("\n[INFO] %s : initialised child main thread\n", __FUNCTION__ );
200
201 // register local child thread into local child process th_tbl[]
202 // we don't use the th_lock because there is no concurrent access
203 ltid_t ltid = LTID_FROM_TRDID( child_trdid );
204 child_process->th_tbl[ltid] = child_thread;
205 child_process->th_nr = 1;
206
207 // register child thread in scheduler
208 sched_register_thread( child_thread->core , child_thread );
209
210 fork_dmsg("\n[INFO] %s : registered main thread in scheduler\n", __FUNCTION__);
211
212 // update DQDT for the child thread
213 dqdt_local_update_threads( 1 );
214
215 fork_dmsg("\n[INFO] %s : completed / parent pid = %x / child pid = %x / at cycle [%d]\n",
216 __FUNCTION__, parent_process->pid, child_process->pid, hal_time_stamp() );
217
218 return child_process->pid;
219
220} // end sys_fork()
221
Note: See TracBrowser for help on using the repository browser.