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

Last change on this file since 625 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
Line 
1/*
2 * sys_fork.c - Kernel function implementing the "fork" system call.
3 *
4 * Authors Alain Greiner (2016,2017,2018,2019)
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_kernel_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#include <syscalls.h>
41
42////////////////////
43int sys_fork( void )
44{
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
49 cxy_t parent_cxy; // parent thread cluster
50
51 pid_t child_pid; // child process identifier
52 thread_t * child_thread_ptr; // local pointer on remote child thread descriptor
53 cxy_t child_cxy; // target cluster for forked child process
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
58
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;
67 parent_cxy = local_cxy;
68
69#if (DEBUG_SYS_FORK || CONFIG_INSTRUMENTATION_SYSCALLS)
70uint64_t tm_start = hal_get_cycles();
71#endif
72
73#if DEBUG_SYS_FORK
74if( DEBUG_SYS_FORK < tm_start )
75printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
76__FUNCTION__, parent_pid, parent_thread_ptr->trdid, (uint32_t)tm_start );
77#endif
78
79 // get infos on reference parent process
80 ref_process_xp = parent_process_ptr->ref_xp;
81 ref_process_cxy = GET_CXY( ref_process_xp );
82 ref_process_ptr = GET_PTR( ref_process_xp );
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 )
87 {
88
89#if DEBUG_SYSCALLS_ERROR
90printk("\n[ERROR] in %s : thread[%x,%x] cannot fork : too much children\n",
91__FUNCTION__, parent_pid, parent_thread_ptr->trdid );
92#endif
93 hal_remote_atomic_add ( children_xp , -1 );
94 parent_thread_ptr->errno = EAGAIN;
95 return -1;
96 }
97
98 // Select target cluster for child process and main thread.
99 // If placement is not user-defined, it is defined by the DQDT.
100 if( parent_thread_ptr->fork_user )
101 {
102 child_cxy = parent_thread_ptr->fork_cxy;
103 parent_thread_ptr->fork_user = false;
104 }
105 else // DQDT placement
106 {
107 child_cxy = dqdt_get_cluster_for_process();
108 }
109
110#if (DEBUG_SYS_FORK & 1 )
111if( DEBUG_SYS_FORK < tm_start )
112printk("\n[%s] thread[%x,%x] selected cluster %x\n",
113__FUNCTION__, parent_pid, parent_thread_ptr->trdid, child_cxy );
114#endif
115
116 // call process_make_fork in target cluster
117 if( child_cxy == local_cxy )
118 {
119 error = process_make_fork( ref_process_xp,
120 parent_thread_xp,
121 &child_pid,
122 &child_thread_ptr );
123 }
124 else
125 {
126 rpc_process_make_fork_client( child_cxy,
127 ref_process_xp,
128 parent_thread_xp,
129 &child_pid,
130 &child_thread_ptr,
131 &error );
132 }
133
134 if( error )
135 {
136
137#if DEBUG_SYSCALLS_ERROR
138printk("\n[ERROR] in %s : thread[%x,%x] cannot fork\n",
139__FUNCTION__, parent_pid, parent_thread_ptr->trdid );
140#endif
141 parent_thread_ptr->errno = EAGAIN;
142 return -1;
143 }
144
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 )
148 {
149 hal_fpu_context_save( XPTR( child_cxy , child_thread_ptr ) );
150 }
151
152 // set remote child CPU context from parent_thread register values
153 // replicates the parent thread kernel stack to the child thread descriptor,
154 // and finally unblock the child thread.
155 hal_cpu_context_fork( XPTR( child_cxy , child_thread_ptr ) );
156
157 // From this point, both parent and child threads execute the following code,
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
162
163 thread_t * current = CURRENT_THREAD;
164
165#if (DEBUG_SYS_FORK || CONFIG_INSTRUMENTATION_SYSCALLS)
166uint64_t tm_end = hal_get_cycles();
167#endif
168
169 if( (current == parent_thread_ptr) && (local_cxy == parent_cxy) ) // parent thread
170 {
171
172#if DEBUG_SYS_FORK
173if( DEBUG_SYS_FORK < tm_end )
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 );
176#endif
177
178// only parent contribute to instrumentation
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 );
182#endif
183 return child_pid;
184 }
185 else // child_thread
186 {
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
194 return 0;
195 }
196
197} // end sys_fork()
198
Note: See TracBrowser for help on using the repository browser.