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

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

Introduce syscalls.

File size: 7.7 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>
26#include <hal_atomic.h>
[1]27#include <errno.h>
[23]28#include <printk.h>
29#include <core.h>
[1]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
[23]38//////////////
39int sys_fork()
[1]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;
[23]55    parent_pid     = parent_process->pid;
[1]56
57    // check parent process children number
[23]58        if( hal_atomic_add( &parent_process->children_nr , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
[1]59        {
[23]60            printk("\n[ERROR] in %s : too much children processes\n", __FUNCTION__);
61            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]62        return EAGAIN;
63        }
64
[23]65        fork_dmsg("\n[INFO] %s : enters for process %d at cycle [%d]\n",
[1]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 );
[23]73                fork_dmsg("\n[INFO] %s : save FPU\n", __FUNCTION__);
[1]74        }
75
76    // Select target cluster for future migration of child process and main thread.
[23]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 )
[1]81        {
82        // user defined placement
[23]83        target_cxy = parent_thread->fork_cxy;
84        parent_thread->fork_user = false;
[1]85        }
[23]86    else if( (LPID_FROM_PID(parent_process->pid) < 2)  && (local_cxy == 0) )
[1]87    {
88        // 2 first process stay in boot cluster
[23]89        target_cxy = local_cxy;
[1]90    }
91        else
92        {
93        // DQDT placement
94                target_cxy = dqdt_get_cluster_for_process();
95        }
96
[23]97        fork_dmsg("INFO : %s select target_cluster = %x\n",
[1]98              __FUNCTION__ , target_cxy );
99
100    // allocates memory in local cluster for the child process descriptor
101        child_process = process_alloc(); 
[23]102
[1]103        if( child_process == NULL )
104        {
[23]105            printk("\n[ERROR] in %s : cannot allocate child process\n", __FUNCTION__ );
106            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]107        return EAGAIN;
108        }
109
[23]110    // get a new PID for child process,
111    if( target_cxy == local_cxy )                // target cluster is local
[1]112    {
[23]113        error = cluster_pid_alloc( XPTR( target_cxy , child_process ) , &child_pid );
[1]114    }
[23]115    else                                         // target cluster is remote
[1]116    {
[23]117        rpc_process_pid_alloc_client( target_cxy , child_process , &error , &child_pid );
[1]118    }
[23]119
[1]120    if( error )
121    {
[23]122            printk("\n[ERROR] in %s : cannot allocate PID\n", __FUNCTION__ );
123            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]124        process_destroy( child_process );
125        return EAGAIN;
126    }
127
128    // initialize and register the child process descriptor
[23]129    process_reference_init( child_process , child_pid , parent_pid );
[1]130
[23]131        fork_dmsg("\n[INFO] : %s created child process : pid = %x / ppid = %x\n", 
[1]132              __FUNCTION__, child_pid , parent_pid );
133
134    // initialises child process standard files structures
135    // ( root / cwd / bin ) from parent process descriptor
136
[23]137        vfs_file_count_up( parent_process->vfs_root_xp );
138        child_process->vfs_root_xp = parent_process->vfs_root_xp;
[1]139
[23]140        vfs_file_count_up( parent_process->vfs_cwd_xp );
141        child_process->vfs_cwd_xp  = parent_process->vfs_cwd_xp;
[1]142
[23]143        vfs_file_count_up( parent_process->vfs_bin_xp );
144    child_process->vfs_bin_xp = parent_process->vfs_bin_xp;
[1]145
146    // copy the parent process fd_array to the child process fd_array
[23]147        process_fd_remote_copy( XPTR( local_cxy , &child_process->fd_array ),
148                            XPTR( local_cxy , &parent_process->fd_array ) );
[1]149
[23]150        fork_dmsg("\n[INFO] %s : duplicated child process from parent process\n",
[1]151                  __FUNCTION__ );
152
153    // replicates virtual memory manager
[23]154        error = vmm_copy( child_process , parent_process );
155
[1]156        if( error )
157    {
[23]158            printk("\n[ERROR] in %s : cannot duplicate VMM\n", __FUNCTION__ );
159            hal_atomic_add ( &parent_process->children_nr , -1 );
[1]160        process_destroy( child_process );
[23]161        return ENOMEM;
[1]162    }
163 
[23]164        fork_dmsg("\n[INFO] %s : parent vmm duplicated in child process\n", __FUNCTION__ );
[1]165
[23]166    // create child main thread descriptor in local cluster
167    error = thread_user_fork( parent_process , &child_thread );
168
[1]169        if( error )
170    {
[23]171            printk("\n[ERROR] in %s : cannot duplicate thread\n", __FUNCTION__ );
172            hal_atomic_add( &parent_process->children_nr , -1 );
[1]173        process_destroy( child_process );
[23]174        return ENOMEM;
[1]175    }
176
177    // register child thread in child process, and get a TRDID
[23]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 );
[1]181
182    if( error ) 
183    {
[23]184        printk("\n[ERROR] in %s : cannot register thread\n", __FUNCTION__ );
185            hal_atomic_add ( &parent_process->children_nr , -1 );
[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
[23]195        child_thread->core    = &LOCAL_CLUSTER->core_tbl[child_core_lid];
[1]196        child_thread->process = child_process;
[23]197    child_thread->trdid   = child_trdid;
[1]198
[23]199        fork_dmsg("\n[INFO] %s : initialised child main thread\n", __FUNCTION__ );
[1]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
[23]203    ltid_t ltid = LTID_FROM_TRDID( child_trdid );
204        child_process->th_tbl[ltid] = child_thread;
205        child_process->th_nr = 1;
[1]206
207    // register child thread in scheduler
[23]208        sched_register_thread( child_thread->core , child_thread );
[1]209 
[23]210        fork_dmsg("\n[INFO] %s : registered main thread in scheduler\n", __FUNCTION__);
[1]211
212        // update DQDT for the child thread
[23]213    dqdt_local_update_threads( 1 );
[1]214
[23]215        fork_dmsg("\n[INFO] %s : completed / parent pid = %x / child pid = %x / at cycle [%d]\n",
[1]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.