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

Last change on this file since 635 was 635, checked in by alain, 5 years ago

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

File size: 7.2 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
[635]74if( DEBUG_SYS_FORK < (uint32_t)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 )
[635]111if( DEBUG_SYS_FORK < (uint32_t)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
[635]152    // set the remote child CPU context from parent register values,
153    // set the remote child uzone from
[625]154    // replicates the parent thread kernel stack to the child thread descriptor,
155    // and finally unblock the child thread.
[438]156    hal_cpu_context_fork( XPTR( child_cxy , child_thread_ptr ) );
[1]157
[438]158    // From this point, both parent and child threads execute the following code,
[625]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
[1]163
[407]164    thread_t * current = CURRENT_THREAD;
[1]165
[566]166#if (DEBUG_SYS_FORK || CONFIG_INSTRUMENTATION_SYSCALLS)
167uint64_t     tm_end = hal_get_cycles();
168#endif
169
[625]170    if( (current == parent_thread_ptr) && (local_cxy == parent_cxy) )   // parent thread
171    {
172
[566]173#if DEBUG_SYS_FORK
[635]174if( DEBUG_SYS_FORK < (uint32_t)tm_end )
[625]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 );
[566]177#endif
178
[635]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
[566]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 );
[416]196#endif
[407]197        return child_pid;
198    }
[438]199        else                                                               // child_thread
[407]200    {
[625]201
202#if DEBUG_SYS_FORK
[635]203if( DEBUG_SYS_FORK < (uint32_t)tm_end )
[625]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
[407]208        return 0;
209    }
210
[1]211}  // end sys_fork()
212
Note: See TracBrowser for help on using the repository browser.