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

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

Introduce the non-standard pthread_parallel_create() system call
and re-write the <fft> and <sort> applications to improve the
intrinsic paralelism in applications.

File size: 7.3 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 < (uint32_t)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_thread( LOCAL_CLUSTER->dqdt_root_xp );
108 }
109
110#if (DEBUG_SYS_FORK & 1 )
111if( DEBUG_SYS_FORK < (uint32_t)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 the remote child CPU context from parent register values,
153 // set the remote child uzone from
154 // replicates the parent thread kernel stack to the child thread descriptor,
155 // and finally unblock the child thread.
156 hal_cpu_context_fork( XPTR( child_cxy , child_thread_ptr ) );
157
158 // From this point, both parent and child threads execute the following code,
159 // but child thread will only execute it after being unblocked by parent thread.
160 // They can be distinguished by the (CURRENT_THREAD,local_cxy) values.
161 // - parent return child PID to user application.
162 // - child return 0 to user application
163
164 thread_t * current = CURRENT_THREAD;
165
166#if (DEBUG_SYS_FORK || CONFIG_INSTRUMENTATION_SYSCALLS)
167uint64_t tm_end = hal_get_cycles();
168#endif
169
170 if( (current == parent_thread_ptr) && (local_cxy == parent_cxy) ) // parent thread
171 {
172
173#if DEBUG_SYS_FORK
174if( DEBUG_SYS_FORK < (uint32_t)tm_end )
175printk("\n[%s] parent thread[%x,%x] exit / child_pid %x / cycle %d\n",
176__FUNCTION__, current->process->pid, current->trdid, child_pid, (uint32_t)tm_end );
177#endif
178
179// only parent display the parent and child VMM
180#if (DEBUG_SYS_FORK & 1 )
181if( DEBUG_SYS_FORK < (uint32_t)tm_end )
182{
183 process_t * child_process_ptr = hal_remote_lpt( XPTR( child_cxy ,
184 &child_thread_ptr->process ) );
185 xptr_t child_process_xp = XPTR( child_cxy , child_process_ptr );
186
187 hal_vmm_display( ref_process_xp , true );
188 hal_vmm_display( child_process_xp , true );
189}
190#endif
191
192// only parent contribute to syscalls instrumentation
193#if CONFIG_INSTRUMENTATION_SYSCALLS
194hal_atomic_add( &syscalls_cumul_cost[SYS_FORK] , tm_end - tm_start );
195hal_atomic_add( &syscalls_occurences[SYS_FORK] , 1 );
196#endif
197 return child_pid;
198 }
199 else // child_thread
200 {
201
202#if DEBUG_SYS_FORK
203if( DEBUG_SYS_FORK < (uint32_t)tm_end )
204printk("\n[%s] child thread[%x,%x] exit / child_pid %x / cycle %d\n",
205__FUNCTION__, current->process->pid, current->trdid, child_pid, (uint32_t)tm_end );
206#endif
207
208 return 0;
209 }
210
211} // end sys_fork()
212
Note: See TracBrowser for help on using the repository browser.