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

Last change on this file since 459 was 457, checked in by alain, 6 years ago

This version modifies the exec syscall and fixes a large number of small bugs.
The version number has been updated (0.1)

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