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

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

First implementation of fork/exec.

File size: 7.8 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_context.h>
27#include <hal_switch.h>
28#include <hal_atomic.h>
29#include <errno.h>
30#include <printk.h>
31#include <core.h>
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
40//////////////
41int sys_fork()
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
49    cxy_t                target_cxy;      // target cluster for forked child process
50        error_t              error;
51
52        uint64_t      tm_start;
53        uint64_t      tm_end;
54
55        tm_start = hal_get_cycles();
56
57    // get pointers on parent process and thread
58        parent_thread  = CURRENT_THREAD;
59        parent_process = parent_thread->process;
60    parent_pid     = parent_process->pid;
61
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
65    // check parent process children number
66        if( hal_atomic_add( &parent_process->children_nr , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
67        {
68            printk("\n[ERROR] in %s : too much children processes\n", __FUNCTION__);
69            hal_atomic_add ( &parent_process->children_nr , -1 );
70        return EAGAIN;
71        }
72
73    // Select target cluster for future migration of child process and main thread.
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 )
78        {
79        // user defined placement
80        target_cxy = parent_thread->fork_cxy;
81        parent_thread->fork_user = false;
82        }
83    else if( (LPID_FROM_PID(parent_process->pid) < 2)  && (local_cxy == 0) )
84    {
85        // 2 first process stay in boot cluster
86        target_cxy = local_cxy;
87    }
88        else
89        {
90        // DQDT placement
91                target_cxy = dqdt_get_cluster_for_process();
92        }
93
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 );
96
97    // allocates memory in local cluster for the child process descriptor
98        child_process = process_alloc(); 
99
100        if( child_process == NULL )
101        {
102            printk("\n[ERROR] in %s : cannot allocate child process\n", __FUNCTION__ );
103            hal_atomic_add ( &parent_process->children_nr , -1 );
104        return EAGAIN;
105        }
106
107    // get a new PID for child process,
108    if( target_cxy == local_cxy )                // target cluster is local
109    {
110        error = cluster_pid_alloc( XPTR( target_cxy , child_process ) , &child_pid );
111    }
112    else                                         // target cluster is remote
113    {
114        rpc_process_pid_alloc_client( target_cxy , child_process , &error , &child_pid );
115    }
116
117    if( error )
118    {
119            printk("\n[ERROR] in %s : cannot allocate PID\n", __FUNCTION__ );
120            hal_atomic_add ( &parent_process->children_nr , -1 );
121        process_destroy( child_process );
122        return EAGAIN;
123    }
124
125    // initialize and register the child process descriptor
126    process_reference_init( child_process , child_pid , XPTR(local_cxy, parent_process) );
127
128    // initialises child process standard files structures
129    // ( root / cwd / bin ) from parent process descriptor
130
131        vfs_file_count_up( parent_process->vfs_root_xp );
132        child_process->vfs_root_xp = parent_process->vfs_root_xp;
133
134        vfs_file_count_up( parent_process->vfs_cwd_xp );
135        child_process->vfs_cwd_xp  = parent_process->vfs_cwd_xp;
136
137        vfs_file_count_up( parent_process->vfs_bin_xp );
138    child_process->vfs_bin_xp = parent_process->vfs_bin_xp;
139
140    // copy the parent process fd_array to the child process fd_array
141        process_fd_remote_copy( XPTR( local_cxy , &child_process->fd_array ),
142                            XPTR( local_cxy , &parent_process->fd_array ) );
143
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 );
146
147    // replicate VMM
148        error = vmm_copy( child_process , parent_process );
149
150        if( error )
151    {
152            printk("\n[ERROR] in %s : cannot duplicate VMM\n", __FUNCTION__ );
153            hal_atomic_add ( &parent_process->children_nr , -1 );
154        process_destroy( child_process );
155        return ENOMEM;
156    }
157 
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 );
162
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 );
168        if( error )
169    {
170            printk("\n[ERROR] in %s : cannot duplicate main thread\n", __FUNCTION__ );
171            hal_atomic_add( &parent_process->children_nr , -1 );
172        process_destroy( child_process );
173        return ENOMEM;
174    }
175
176//printk("\n[DBG] %s : core[%x,%d] initialised child main thread\n",
177//__FUNCTION__ , local_cxy , parent_thread->core->lid );
178
179        // update DQDT for the child thread
180    dqdt_local_update_threads( 1 );
181
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        }
188
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) );
193
194
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
197
198    thread_t * current = CURRENT_THREAD;
199
200    if( current == parent_thread )
201    {
202        // parent_thread unblock child_thread
203        thread_unblock( XPTR( local_cxy , child_thread ) , THREAD_BLOCKED_GLOBAL );
204
205        tm_end = hal_get_cycles();
206
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
225}  // end sys_fork()
226
Note: See TracBrowser for help on using the repository browser.