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

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

Fix several bugs in the fork() syscall.

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