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

Last change on this file since 407 was 407, checked in by alain, 6 years ago

First implementation of fork/exec.

File size: 7.8 KB
RevLine 
[1]1/*
[23]2 * sys_fork.c - Fork the current process.
[1]3 *
[23]4 * Authors  Alain Greiner  (2016,2017)
[1]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
[23]24#include <kernel_config.h>
25#include <hal_types.h>
[407]26#include <hal_context.h>
27#include <hal_switch.h>
[23]28#include <hal_atomic.h>
[1]29#include <errno.h>
[23]30#include <printk.h>
31#include <core.h>
[1]32#include <cluster.h>
33#include <list.h>
34#include <thread.h>
35#include <scheduler.h>
36#include <kmem.h>
37#include <dqdt.h>
38#include <process.h>
39
[23]40//////////////
41int sys_fork()
[1]42{
43        process_t          * parent_process;  // pointer on parent process descriptor
44    pid_t                parent_pid;      // parent process identifier
45    thread_t           * parent_thread;   // pointer on parent thread descriptor
46        process_t          * child_process;   // pointer on child process descriptor
47    pid_t                child_pid;       // child process identifier
48        thread_t           * child_thread;    // pointer on child main thread descriptor
[407]49    cxy_t                target_cxy;      // target cluster for forked child process
[1]50        error_t              error;
51
[407]52        uint64_t      tm_start;
53        uint64_t      tm_end;
54
55        tm_start = hal_get_cycles();
56
[1]57    // get pointers on parent process and thread
58        parent_thread  = CURRENT_THREAD;
59        parent_process = parent_thread->process;
[23]60    parent_pid     = parent_process->pid;
[1]61
[407]62fork_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x / cycle %d\n",
63__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid , (uint32_t)tm_start );
64
[1]65    // check parent process children number
[23]66        if( hal_atomic_add( &parent_process->children_nr , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
[1]67        {
[23]68            printk("\n[ERROR] in %s : too much children processes\n", __FUNCTION__);
69            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]70        return EAGAIN;
71        }
72
73    // Select target cluster for future migration of child process and main thread.
[23]74    // If placement is not user-defined, the placement is defined by the DQDT.
75    // The two first processes ("init" and "sh") on boot cluster do not migrate.
76
77        if( parent_thread->fork_user )
[1]78        {
79        // user defined placement
[23]80        target_cxy = parent_thread->fork_cxy;
81        parent_thread->fork_user = false;
[1]82        }
[23]83    else if( (LPID_FROM_PID(parent_process->pid) < 2)  && (local_cxy == 0) )
[1]84    {
85        // 2 first process stay in boot cluster
[23]86        target_cxy = local_cxy;
[1]87    }
88        else
89        {
90        // DQDT placement
91                target_cxy = dqdt_get_cluster_for_process();
92        }
93
[407]94//printk("\n[DBG] %s : core[%x,%d] for process %x selects target_cluster = %x\n",
95//__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid , target_cxy );
[1]96
97    // allocates memory in local cluster for the child process descriptor
98        child_process = process_alloc(); 
[23]99
[1]100        if( child_process == NULL )
101        {
[23]102            printk("\n[ERROR] in %s : cannot allocate child process\n", __FUNCTION__ );
103            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]104        return EAGAIN;
105        }
106
[23]107    // get a new PID for child process,
108    if( target_cxy == local_cxy )                // target cluster is local
[1]109    {
[23]110        error = cluster_pid_alloc( XPTR( target_cxy , child_process ) , &child_pid );
[1]111    }
[23]112    else                                         // target cluster is remote
[1]113    {
[23]114        rpc_process_pid_alloc_client( target_cxy , child_process , &error , &child_pid );
[1]115    }
[23]116
[1]117    if( error )
118    {
[23]119            printk("\n[ERROR] in %s : cannot allocate PID\n", __FUNCTION__ );
120            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]121        process_destroy( child_process );
122        return EAGAIN;
123    }
124
125    // initialize and register the child process descriptor
[407]126    process_reference_init( child_process , child_pid , XPTR(local_cxy, parent_process) );
[1]127
128    // initialises child process standard files structures
129    // ( root / cwd / bin ) from parent process descriptor
130
[23]131        vfs_file_count_up( parent_process->vfs_root_xp );
132        child_process->vfs_root_xp = parent_process->vfs_root_xp;
[1]133
[23]134        vfs_file_count_up( parent_process->vfs_cwd_xp );
135        child_process->vfs_cwd_xp  = parent_process->vfs_cwd_xp;
[1]136
[23]137        vfs_file_count_up( parent_process->vfs_bin_xp );
138    child_process->vfs_bin_xp = parent_process->vfs_bin_xp;
[1]139
140    // copy the parent process fd_array to the child process fd_array
[23]141        process_fd_remote_copy( XPTR( local_cxy , &child_process->fd_array ),
142                            XPTR( local_cxy , &parent_process->fd_array ) );
[1]143
[407]144//printk("\n[DBG] %s : core[%x,%d] for process %x created child process %x\n",
145//__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid , child_pid );
[1]146
[407]147    // replicate VMM
[23]148        error = vmm_copy( child_process , parent_process );
149
[1]150        if( error )
151    {
[23]152            printk("\n[ERROR] in %s : cannot duplicate VMM\n", __FUNCTION__ );
153            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]154        process_destroy( child_process );
[23]155        return ENOMEM;
[1]156    }
157 
[407]158//printk("\n[DBG] %s : core[%x,%d] for process %x duplicated vmm in child process\n",
159//__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid );
160//vmm_display( parent_process , true );
161//vmm_display( child_process , true );
[1]162
[407]163    // create child main thread in local cluster
164    error = thread_user_fork( child_process,
165                              parent_thread->u_stack_size,
166                              parent_thread->u_stack_base,
167                              &child_thread );
[1]168        if( error )
169    {
[407]170            printk("\n[ERROR] in %s : cannot duplicate main thread\n", __FUNCTION__ );
[23]171            hal_atomic_add( &parent_process->children_nr , -1 );
[1]172        process_destroy( child_process );
[23]173        return ENOMEM;
[1]174    }
175
[407]176//printk("\n[DBG] %s : core[%x,%d] initialised child main thread\n",
177//__FUNCTION__ , local_cxy , parent_thread->core->lid );
[1]178
[407]179        // update DQDT for the child thread
180    dqdt_local_update_threads( 1 );
[1]181
[407]182    // set child_thread FPU_context from parent_thread register values
183    // only when the parent process is the FPU owner
184        if( CURRENT_THREAD->core->fpu_owner == parent_thread )
185        {
186                hal_fpu_context_save( child_thread->fpu_context );
187        }
[1]188
[407]189    // set child_thread CPU context from parent_thread register values
190    hal_do_cpu_save( child_thread->cpu_context,
191                     child_thread,
192                     (int)((intptr_t)child_thread - (intptr_t)parent_thread) );
[1]193
194
[407]195    // from this point, both parent and child threads execute the following code
196    // but child execute it only when it has been unblocked by its parent
[1]197
[407]198    thread_t * current = CURRENT_THREAD;
[1]199
[407]200    if( current == parent_thread )
201    {
202        // parent_thread unblock child_thread
203        thread_unblock( XPTR( local_cxy , child_thread ) , THREAD_BLOCKED_GLOBAL );
[1]204
[407]205        tm_end = hal_get_cycles();
[1]206
[407]207fork_dmsg("\n[DBG] %s : core[%x,%d] parent_process %x exit / cycle %d\n"
208"     child_process %x / child_thread = %x / cost = %d\n",
209__FUNCTION__, local_cxy, parent_thread->core->lid,  parent_pid, (uint32_t)tm_start,
210child_pid, child_thread->trdid , (uint32_t)(tm_end - tm_start) );
211
212        return child_pid;
213    }
214        else  // current == child_thread
215    {
216        assert( (current == child_thread) , __FUNCTION__ , 
217        "current thread %x is not the child thread %x\n", current , child_thread );
218
219fork_dmsg("\n[DBG] %s : core[%x,%d] child process %x exit / cycle %d\n",
220__FUNCTION__, local_cxy, parent_thread->core->lid, child_pid, (uint32_t)hal_get_cycles() );
221
222        return 0;
223    }
224
[1]225}  // end sys_fork()
226
Note: See TracBrowser for help on using the repository browser.