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

Last change on this file since 629 was 625, checked in by alain, 7 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 6.7 KB
RevLine 
[1]1/*
[409]2 * sys_fork.c - Kernel function implementing the "fork" system call.
[1]3 *
[625]4 * Authors Alain Greiner (2016,2017,2018,2019)
[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>
[457]25#include <hal_kernel_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
[506]40#include <syscalls.h>
41
[566]42////////////////////
[479]43int sys_fork( void )
[1]44{
[408]45 process_t * parent_process_ptr; // pointer on local parent process descriptor
46 xptr_t parent_thread_xp; // extended pointer on parent thread descriptor
47 pid_t parent_pid; // parent process identifier
48 thread_t * parent_thread_ptr; // local pointer on local parent thread descriptor
[438]49 cxy_t parent_cxy; // parent thread cluster
[1]50
[408]51 pid_t child_pid; // child process identifier
52 thread_t * child_thread_ptr; // local pointer on remote child thread descriptor
[438]53 cxy_t child_cxy; // target cluster for forked child process
[408]54
55 xptr_t ref_process_xp; // extended pointer on reference parent process
56 cxy_t ref_process_cxy; // cluster of reference parent process
57 process_t * ref_process_ptr; // local pointer on reference parent process
[407]58
[408]59 error_t error;
60
61
62 // get pointers on local parent process and thread
63 parent_thread_ptr = CURRENT_THREAD;
64 parent_thread_xp = XPTR( local_cxy , parent_thread_ptr );
65 parent_process_ptr = parent_thread_ptr->process;
66 parent_pid = parent_process_ptr->pid;
[438]67 parent_cxy = local_cxy;
[1]68
[566]69#if (DEBUG_SYS_FORK || CONFIG_INSTRUMENTATION_SYSCALLS)
70uint64_t tm_start = hal_get_cycles();
71#endif
72
[438]73#if DEBUG_SYS_FORK
74if( DEBUG_SYS_FORK < tm_start )
[625]75printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
[584]76__FUNCTION__, parent_pid, parent_thread_ptr->trdid, (uint32_t)tm_start );
[416]77#endif
[407]78
[438]79 // get infos on reference parent process
[408]80 ref_process_xp = parent_process_ptr->ref_xp;
81 ref_process_cxy = GET_CXY( ref_process_xp );
[440]82 ref_process_ptr = GET_PTR( ref_process_xp );
[408]83
84 // check parent process children number from reference
85 xptr_t children_xp = XPTR( ref_process_cxy , &ref_process_ptr->children_nr );
86 if( hal_remote_atomic_add( children_xp , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
[1]87 {
[435]88
[438]89#if DEBUG_SYSCALLS_ERROR
[584]90printk("\n[ERROR] in %s : thread[%x,%x] cannot fork : too much children\n",
91__FUNCTION__, parent_pid, parent_thread_ptr->trdid );
[435]92#endif
[408]93 hal_remote_atomic_add ( children_xp , -1 );
94 parent_thread_ptr->errno = EAGAIN;
95 return -1;
[1]96 }
97
[408]98 // Select target cluster for child process and main thread.
[438]99 // If placement is not user-defined, it is defined by the DQDT.
100 if( parent_thread_ptr->fork_user )
[1]101 {
[438]102 child_cxy = parent_thread_ptr->fork_cxy;
[408]103 parent_thread_ptr->fork_user = false;
[1]104 }
[408]105 else // DQDT placement
[1]106 {
[438]107 child_cxy = dqdt_get_cluster_for_process();
[1]108 }
109
[440]110#if (DEBUG_SYS_FORK & 1 )
[438]111if( DEBUG_SYS_FORK < tm_start )
[594]112printk("\n[%s] thread[%x,%x] selected cluster %x\n",
[584]113__FUNCTION__, parent_pid, parent_thread_ptr->trdid, child_cxy );
[438]114#endif
115
[408]116 // call process_make_fork in target cluster
[438]117 if( child_cxy == local_cxy )
[1]118 {
[408]119 error = process_make_fork( ref_process_xp,
120 parent_thread_xp,
121 &child_pid,
122 &child_thread_ptr );
[1]123 }
[408]124 else
[1]125 {
[438]126 rpc_process_make_fork_client( child_cxy,
[408]127 ref_process_xp,
128 parent_thread_xp,
129 &child_pid,
130 &child_thread_ptr,
131 &error );
[1]132 }
[23]133
[1]134 if( error )
135 {
[435]136
[438]137#if DEBUG_SYSCALLS_ERROR
[584]138printk("\n[ERROR] in %s : thread[%x,%x] cannot fork\n",
139__FUNCTION__, parent_pid, parent_thread_ptr->trdid );
[435]140#endif
[408]141 parent_thread_ptr->errno = EAGAIN;
142 return -1;
[1]143 }
144
[408]145 // set remote child FPU_context from parent_thread register values
146 // only when the parent thread is the FPU owner
147 if( CURRENT_THREAD->core->fpu_owner == parent_thread_ptr )
[407]148 {
[438]149 hal_fpu_context_save( XPTR( child_cxy , child_thread_ptr ) );
[407]150 }
[1]151
[438]152 // set remote child CPU context from parent_thread register values
[625]153 // replicates the parent thread kernel stack to the child thread descriptor,
154 // and finally unblock the child thread.
[438]155 hal_cpu_context_fork( XPTR( child_cxy , child_thread_ptr ) );
[1]156
[438]157 // From this point, both parent and child threads execute the following code,
[625]158 // but child thread will only execute it after being unblocked by parent thread.
159 // They can be distinguished by the (CURRENT_THREAD,local_cxy) values.
160 // - parent return child PID to user application.
161 // - child return 0 to user application
[1]162
[407]163 thread_t * current = CURRENT_THREAD;
[1]164
[566]165#if (DEBUG_SYS_FORK || CONFIG_INSTRUMENTATION_SYSCALLS)
166uint64_t tm_end = hal_get_cycles();
167#endif
168
[625]169 if( (current == parent_thread_ptr) && (local_cxy == parent_cxy) ) // parent thread
170 {
171
[566]172#if DEBUG_SYS_FORK
173if( DEBUG_SYS_FORK < tm_end )
[625]174printk("\n[%s] parent thread[%x,%x] exit / child_pid %x / cycle %d\n",
175__FUNCTION__, current->process->pid, current->trdid, child_pid, (uint32_t)tm_end );
[566]176#endif
177
[625]178// only parent contribute to instrumentation
[566]179#if CONFIG_INSTRUMENTATION_SYSCALLS
180hal_atomic_add( &syscalls_cumul_cost[SYS_FORK] , tm_end - tm_start );
181hal_atomic_add( &syscalls_occurences[SYS_FORK] , 1 );
[416]182#endif
[407]183 return child_pid;
184 }
[438]185 else // child_thread
[407]186 {
[625]187
188#if DEBUG_SYS_FORK
189if( DEBUG_SYS_FORK < tm_end )
190printk("\n[%s] child thread[%x,%x] exit / child_pid %x / cycle %d\n",
191__FUNCTION__, current->process->pid, current->trdid, child_pid, (uint32_t)tm_end );
192#endif
193
[407]194 return 0;
195 }
196
[1]197} // end sys_fork()
198
Note: See TracBrowser for help on using the repository browser.