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

Last change on this file since 51 was 23, checked in by alain, 7 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.