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

Last change on this file since 8 was 1, checked in by alain, 8 years ago

First import

File size: 9.4 KB
Line 
1/*
2 * sys_fork.c - fork the current process
3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *          Mohamed Lamine Karaoui (2015)
6 *          Alain Greiner (2016)
7 *
8 * Copyright (c) UPMC Sorbonne Universites
9 *
10 * This file is part of ALMOS-MKH.
11 *
12 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2.0 of the License.
15 *
16 * ALMOS-MKH.is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <errno.h>
27#include <config.h>
28#include <cpu.h>
29#include <cluster.h>
30#include <event.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#if CONFIG_FORK_DEBUG
39#define fork_debug(...) printk(__VA_ARGS__)
40#else
41#define fork_debug(...) /**/
42#endif
43
44/***********************************************************************************************
45 * This kernel function implement the "fork" system call.
46 * The calling process descriptor (parent process), and the associated thread descriptor are
47 * replicated in the same cluster as the calling thread, but the new process (child process)
48 * is registered in another target cluster, that will become the process owner.
49 * The child process and the associated main thread will be migrated to the target cluster
50 * later, when the child process makes an "exec" or any other system call.
51 * The target cluster depends on the "fork_user" flag and "fork_cxy" variable that can be
52 * stored in the calling thread descriptor by the specific fork_place() system call.
53 * If not, the sys_fork() function makes a query to the DQDT to select the target cluster.
54 * @ returns child process PID if success / returns -1 if failure
55 **********************************************************************************************/
56int sys_fork();
57{
58        process_t          * parent_process;  // pointer on parent process descriptor
59    pid_t                parent_pid;      // parent process identifier
60    thread_t           * parent_thread;   // pointer on parent thread descriptor
61        process_t          * child_process;   // pointer on child process descriptor
62    pid_t                child_pid;       // child process identifier
63        thread_t           * child_thread;    // pointer on child main thread descriptor
64    trdid_t              child_trdid;     // child main thread identifier
65    core_t             * child_core;      // pointer on core for child main thread
66    lid_t                child_core_lid;  // core local index for the child main thread
67    cxy_t                target_cxy;      // final target cluster for forked child process
68        error_t              error;
69
70    cluster_t          * parent_cluster = LOCAL_CLUSTER;
71
72    // get pointers on parent process and thread
73        parent_thread  = CURRENT_THREAD;
74        parent_process = parent_thread->process;
75
76    // check parent process children number
77        if( hal_atomic_add( &parent_process->childs_nr , 1 ) >= CONFIG_PROCESS_CHILDS_MAX_NR )
78        {
79            printk("ERROR in %s : too much children processes\n", __FUNCTION__);
80            hal_atomic_add ( &parent_process->childs_nr , -1 );
81        return EAGAIN;
82        }
83
84        fork_debug("INFO : %s enters for process %d at cycle [%d]\n",
85                  __FUNCTION__, parent_process->pid, hal_time_stamp());
86
87    // save FPU state in fpu_context if parent process is FPU owner
88    // because we want the child process to share the FPU context
89        if( CURRENT_CORE->fpu_owner == parent_thread )
90        {
91                hal_fpu_context_save( parent_thread );
92                fork_debug("INFO : %s save FPU\n", __FUNCTION__);
93        }
94
95    // Select target cluster for future migration of child process and main thread.
96    // The placement can be specified by user. If placement is not user-defined,
97    // the placement is defined by the DQDT.
98    // The two first processes ("init" and "sh") on boot cluster will not migrate.
99        if( parent_threads->fork_user )
100        {
101        // user defined placement
102        target_cxy = parent->thread.fork_cxy;
103        parent->thread.fork_cxy = false;
104        }
105    else if( (LPID_FROM_PID(parent_process->pid) < 2 ) 
106             && ( parent_cluster->cxy == parent_cluster->boot_cxy ) )
107    {
108        // 2 first process stay in boot cluster
109        target_cxy = parent_cluster->cxy;
110    }
111        else
112        {
113        // DQDT placement
114                target_cxy = dqdt_get_cluster_for_process();
115        }
116
117        fork_debug("INFO : %s select target_cluster = %x\n",
118              __FUNCTION__ , target_cxy );
119
120    // allocates memory in local cluster for the child process descriptor
121        child_process = process_alloc(); 
122        if( child_process == NULL )
123        {
124            printk("ERROR in %s : cannot allocate memory for child process\n", __FUNCTION__ );
125            hal_atomic_add ( &parent_process->childs_nr , -1 );
126        return EAGAIN;
127        }
128
129    // get a new PID for child process
130    // it requires an RPC if target cluster is remote
131    xptr_t xp = XPTR( target_cxy , child_process ); 
132    if( target_cxy == parent_cluster->cxy )   // local cluster
133    {
134        error = process_pid_alloc( xp , &child_pid );
135    }
136    else                            // remote cluster
137    {
138        rpc_process_pid_alloc_server( target_cxy , xp , &error , &child_pid );
139    }
140    if( error )
141    {
142            printk("ERROR in %s : cannot allocate PID\n", __FUNCTION__ );
143            atomic_add ( &parent_process->childs_nr , -1 );
144        process_destroy( child_process );
145        return EAGAIN;
146    }
147
148    // initialize and register the child process descriptor
149    error = process_reference_init( child_process , child_pid , parent_pid );
150    if( error )
151    {
152            printk("ERROR in %s : cannot initialise child process\n", __FUNCTION__ );
153            atomic_add ( &parent_process->childs_nr , -1 );
154        process_destroy( child_process );
155        return EAGAIN;
156    }
157
158        fork_debug("INFO : %s created child process : pid = %x / ppid = %x\n", 
159              __FUNCTION__, child_pid , parent_pid );
160
161    // set IS_REFERENCE flag in child process descriptor
162    child_process->flags = PDF_IS_REFERENCE;
163
164    // initialises child process standard files structures
165    // ( root / cwd / bin ) from parent process descriptor
166        spinlock_lock( &parent_process->cwd_lock );
167
168        vfs_file_count_up( &parent_process->vfs_root );
169        child_process->vfs_root = parent_process->vfs_root;
170
171        vfs_file_count_up( &parent_process->vfs_cwd );
172        child_process->vfs_cwd  = parent_process->vfs_cwd;
173
174        vfs_file_count_up( &parent_process->vfs_bin );
175    child_process->vfs_bin = parent_process->vfs_bin;
176
177        spinlock_unlock( &parent_process->cwd_lock );
178 
179    // copy the parent process fd_array to the child process fd_array
180        process_fd_fork( child_process , parent_process );
181
182    // initialise child process signal manager TODO ???
183        signal_manager_init( child_process );
184 
185        fork_debug("INFO : %s duplicated child process from parent process\n",
186                  __FUNCTION__ );
187
188    // replicates virtual memory manager
189        error = vmm_dup( &child_process->vmm , &parent_process->vmm );
190        if( error )
191    {
192            printk("ERROR in %s : cannot duplicate VMM\n", __FUNCTION__ );
193            atomic_add ( &parent_process->childs_nr , -1 );
194        process_destroy( child_process );
195        return EAGAIN;
196    }
197 
198        fork_debug("INFO : %s: parent vmm duplicated in child process\n", __FUNCTION__ );
199
200    // create child main thread descriptor in local cluster TODO stack ???
201    error = thread_user_fork( &child_thread , process , parent_thread );
202        if( error )
203    {
204            printk("ERROR in %s : cannot duplicate thread\n", __FUNCTION__ );
205            atomic_add ( &parent_process->childs_nr , -1 );
206        process_destroy( child_process );
207        return EAGAIN;
208    }
209
210    // register child thread in child process, and get a TRDID
211    spinlock_lock( &child->process->th_lock );
212    error = process_register_thread( child->process, child->thread , &child_trdid );
213    spinlock_unlock( &process->th_lock );
214
215    if( error ) 
216    {
217        printk("ERROR in %s : cannot register thread\n", __FUNCTION__ );
218            atomic_add ( &parent_process->childs_nr , -1 );
219        thread_destroy( child_thread );
220        process_destroy( child_process );
221        return EAGAIN;
222    }
223 
224    // get a local core to execute child thread
225    child_core_lid = cluster_select_local_core();
226
227        // Update child thread descriptor
228        child_thread->core    = process->core_tbl[child_core_lid];
229        child_thread->process = child_process;
230    child_thread->trdid   = chid_trdid;
231
232        fork_debug("INFO : %s initialised child main thread\n", __FUNCTION__ );
233
234    // register local child thread into local child process th_tbl[]
235    // we don't use the th_lock because there is no concurrent access
236    ltid_t ltid = LTID_FROM_TRDID( trdid );
237        child_process->th_tbl[ltid] = XPTR( local_cxy , child_thread );
238        child_process->threads_nr = 1;
239
240    // register child thread in scheduler
241        sched_register( child_thread->core , child_thread );
242 
243        fork_debug("INFO : %s registered main thread in scheduler\n", __FUNCTION__);
244
245        // update DQDT for the child thread
246    dqdt_update_threads_number( 1 );
247
248        fork_debug("INFO :%s completed / parent pid = %x / child pid = %x / at cycle [%d]\n",
249                  __FUNCTION__, parent_process->pid, child_process->pid, hal_time_stamp() );
250
251        return child_process->pid;
252
253}  // end sys_fork()
254
Note: See TracBrowser for help on using the repository browser.