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

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