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

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