source: trunk/kernel/kern/process.c @ 657

Last change on this file since 657 was 657, checked in by alain, 4 years ago

Introduce remote_buf.c/.h & socket.c/.h files.
Update dev_nic.c/.h files.

File size: 87.6 KB
RevLine 
[1]1/*
[564]2 * process.c - process related functions definition.
[172]3 *
[1]4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *          Mohamed Lamine Karaoui (2015)
[657]6 *          Alain Greiner (2016,2017,2018,2019,2020)
[1]7 *
8 * Copyright (c) UPMC Sorbonne Universites
9 *
[409]10 * This file is part of ALMOS-MKH.
[1]11 *
[172]12 * ALMOS-MKH is free software; you can redistribute it and/or modify it
[1]13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2.0 of the License.
15 *
[172]16 * ALMOS-MKH is distributed in the hope that it will be useful, but
[1]17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
[172]22 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
[1]23 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
[14]26#include <kernel_config.h>
[457]27#include <hal_kernel_types.h>
[1]28#include <hal_remote.h>
29#include <hal_uspace.h>
[409]30#include <hal_irqmask.h>
[623]31#include <hal_vmm.h>
[1]32#include <errno.h>
33#include <printk.h>
34#include <memcpy.h>
35#include <bits.h>
36#include <kmem.h>
37#include <page.h>
38#include <vmm.h>
39#include <vfs.h>
40#include <core.h>
41#include <thread.h>
[428]42#include <chdev.h>
[1]43#include <list.h>
[407]44#include <string.h>
[1]45#include <scheduler.h>
[564]46#include <busylock.h>
47#include <queuelock.h>
48#include <remote_queuelock.h>
49#include <rwlock.h>
50#include <remote_rwlock.h>
[1]51#include <dqdt.h>
52#include <cluster.h>
53#include <ppm.h>
54#include <boot_info.h>
55#include <process.h>
56#include <elf.h>
[23]57#include <syscalls.h>
[435]58#include <shared_syscalls.h>
[1]59
60//////////////////////////////////////////////////////////////////////////////////////////
61// Extern global variables
62//////////////////////////////////////////////////////////////////////////////////////////
63
[428]64extern process_t           process_zero;     // allocated in kernel_init.c
65extern chdev_directory_t   chdev_dir;        // allocated in kernel_init.c
[1]66
67//////////////////////////////////////////////////////////////////////////////////////////
68// Process initialisation related functions
69//////////////////////////////////////////////////////////////////////////////////////////
70
[583]71/////////////////////////////////
[503]72process_t * process_alloc( void )
[1]73{
[635]74        kmem_req_t req;
[1]75
[635]76    req.type  = KMEM_KCM;
77        req.order = bits_log2( sizeof(process_t) );
[1]78        req.flags = AF_KERNEL;
79
[635]80    return kmem_alloc( &req );
[1]81}
82
83////////////////////////////////////////
84void process_free( process_t * process )
85{
86    kmem_req_t  req;
87
[635]88        req.type = KMEM_KCM;
[1]89        req.ptr  = process;
90        kmem_free( &req );
91}
92
[625]93////////////////////////////////////////////////////
94error_t process_reference_init( process_t * process,
95                                pid_t       pid,
96                                xptr_t      parent_xp )
[1]97{
[625]98    error_t     error;
[610]99    xptr_t      process_xp;
[428]100    cxy_t       parent_cxy;
101    process_t * parent_ptr;
[407]102    xptr_t      stdin_xp;
103    xptr_t      stdout_xp;
104    xptr_t      stderr_xp;
105    uint32_t    stdin_id;
106    uint32_t    stdout_id;
107    uint32_t    stderr_id;
[428]108    uint32_t    txt_id;
109    char        rx_path[40];
110    char        tx_path[40];
[440]111    xptr_t      file_xp;
[428]112    xptr_t      chdev_xp;
[625]113    chdev_t   * chdev_ptr;
[428]114    cxy_t       chdev_cxy;
115    pid_t       parent_pid;
[625]116    vmm_t     * vmm;
[1]117
[610]118    // build extended pointer on this reference process
119    process_xp = XPTR( local_cxy , process );
120
[625]121    // get pointer on process vmm
122    vmm = &process->vmm;
123
[428]124    // get parent process cluster and local pointer
125    parent_cxy = GET_CXY( parent_xp );
[435]126    parent_ptr = GET_PTR( parent_xp );
[204]127
[457]128    // get parent_pid
[564]129    parent_pid = hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
[428]130
[438]131#if DEBUG_PROCESS_REFERENCE_INIT
[610]132thread_t * this = CURRENT_THREAD;
[433]133uint32_t cycle = (uint32_t)hal_get_cycles();
[610]134if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
[625]135printk("\n[%s] thread[%x,%x] enter to initialize process %x / cycle %d\n",
136__FUNCTION__, this->process->pid, this->trdid, pid, cycle );
[433]137#endif
[428]138
[610]139    // initialize pid, ref_xp, parent_xp, owner_xp, term_state fields
[433]140        process->pid        = pid;
141    process->ref_xp     = XPTR( local_cxy , process );
[443]142    process->owner_xp   = XPTR( local_cxy , process );
[433]143    process->parent_xp  = parent_xp;
144    process->term_state = 0;
[428]145
[610]146    // initialize VFS root inode and CWD inode
147    process->vfs_root_xp = hal_remote_l64( XPTR( parent_cxy, &parent_ptr->vfs_root_xp ) );
148    process->cwd_xp      = hal_remote_l64( XPTR( parent_cxy, &parent_ptr->cwd_xp ) );
149
[625]150    // initialize VSL as empty
151    vmm->vsegs_nr = 0;
152        xlist_root_init( XPTR( local_cxy , &vmm->vsegs_root ) );
[564]153
[625]154    // create an empty GPT as required by the architecture
155    error = hal_gpt_create( &vmm->gpt );
156    if( error ) 
157    {
158        printk("\n[ERROR] in %s : cannot create empty GPT\n", __FUNCTION__ );
159        return -1;
160    }
161
162#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
163if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
164printk("\n[%s] thread[%x,%x] created empty GPT for process %x\n",
165__FUNCTION__, parent_pid, this->trdid, pid );
166#endif
167
[635]168    // initialize VSL lock
[625]169        remote_rwlock_init( XPTR( local_cxy , &vmm->vsl_lock ) , LOCK_VMM_VSL );
170
[635]171    // register kernel vsegs in user process VMM as required by the architecture
[625]172    error = hal_vmm_kernel_update( process );
173    if( error ) 
174    {
175        printk("\n[ERROR] in %s : cannot register kernel vsegs in VMM\n", __FUNCTION__ );
176        return -1;
177    }
178
179#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
180if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
[635]181printk("\n[%s] thread[%x,%x] registered kernel vsegs in VSL for process %x\n",
[625]182__FUNCTION__, parent_pid, this->trdid, pid );
183#endif
184
185    // create "args" and "envs" vsegs
186    // create "stacks" and "mmap" vsegs allocators
187    // initialize locks protecting GPT and VSL
188    error = vmm_user_init( process );
189    if( error ) 
190    {
191        printk("\n[ERROR] in %s : cannot register user vsegs in VMM\n", __FUNCTION__ );
192        return -1;
193    }
[415]194 
[438]195#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
[433]196cycle = (uint32_t)hal_get_cycles();
[610]197if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
[625]198printk("\n[%s] thread[%x,%x] initialized vmm for process %x\n", 
199__FUNCTION__, parent_pid, this->trdid, pid );
[433]200#endif
[1]201
[409]202    // initialize fd_array as empty
[408]203    process_fd_init( process );
[1]204
[428]205    // define the stdin/stdout/stderr pseudo files <=> select a TXT terminal.
[581]206    if( (pid == 1) || (parent_pid  == 1) )      // INIT or KSH  process
[408]207    {
[581]208        // select a TXT channel
209        if( pid == 1 )  txt_id = 0;                     // INIT
210        else            txt_id = process_txt_alloc();   // KSH
[428]211
[457]212        // attach process to TXT
[428]213        process_txt_attach( process , txt_id ); 
214
[457]215#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
216cycle = (uint32_t)hal_get_cycles();
[610]217if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
218printk("\n[%s] thread[%x,%x] / process %x attached to TXT%d / cycle %d\n", 
219__FUNCTION__, parent_pid, this->trdid, pid, txt_id, cycle );
[457]220#endif
[428]221        // build path to TXT_RX[i] and TXT_TX[i] chdevs
222        snprintf( rx_path , 40 , "/dev/external/txt%d_rx", txt_id );
223        snprintf( tx_path , 40 , "/dev/external/txt%d_tx", txt_id );
224
225        // create stdin pseudo file         
[610]226        error = vfs_open(  process->vfs_root_xp,
[428]227                           rx_path,
[610]228                           process_xp,
[408]229                           O_RDONLY, 
230                           0,                // FIXME chmod
231                           &stdin_xp, 
232                           &stdin_id );
[625]233        if( error )
234        {
235            printk("\n[ERROR] in %s : cannot open stdout pseudo-file\n", __FUNCTION__ );
236            return -1;
237        }
[1]238
[564]239assert( (stdin_id == 0) , "stdin index must be 0" );
[428]240
[440]241#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
242cycle = (uint32_t)hal_get_cycles();
[610]243if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
244printk("\n[%s] thread[%x,%x] / stdin open for process %x / cycle %d\n", 
245__FUNCTION__, parent_pid, this->trdid, pid, cycle );
[440]246#endif
247
[428]248        // create stdout pseudo file         
[610]249        error = vfs_open(  process->vfs_root_xp,
[428]250                           tx_path,
[610]251                           process_xp,
[408]252                           O_WRONLY, 
253                           0,                // FIXME chmod
254                           &stdout_xp, 
255                           &stdout_id );
[625]256        if( error )
257        {
258            printk("\n[ERROR] in %s : cannot open stdout pseudo-file\n", __FUNCTION__ );
259            return -1;
260        }
[1]261
[625]262assert( (stdout_id == 1) , "stdout index must be 1" );
[428]263
[440]264#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
265cycle = (uint32_t)hal_get_cycles();
[610]266if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
267printk("\n[%s] thread[%x,%x] / stdout open for process %x / cycle %d\n", 
268__FUNCTION__, parent_pid, this->trdid, pid, cycle );
[440]269#endif
270
[428]271        // create stderr pseudo file         
[610]272        error = vfs_open(  process->vfs_root_xp,
[428]273                           tx_path,
[610]274                           process_xp,
[408]275                           O_WRONLY, 
276                           0,                // FIXME chmod
277                           &stderr_xp, 
278                           &stderr_id );
[625]279        if( error )
280        {
281            printk("\n[ERROR] in %s : cannot open stderr pseudo-file\n", __FUNCTION__ );
282            return -1;
283        }
[428]284
[625]285assert( (stderr_id == 2) , "stderr index must be 2" );
[428]286
[440]287#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
288cycle = (uint32_t)hal_get_cycles();
[610]289if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
290printk("\n[%s] thread[%x,%x] / stderr open for process %x / cycle %d\n", 
291__FUNCTION__, parent_pid, this->trdid, pid, cycle );
[440]292#endif
293
[408]294    }
[428]295    else                                            // normal user process
[408]296    {
[457]297        // get extended pointer on stdin pseudo file in parent process
[625]298        file_xp = (xptr_t)hal_remote_l64( XPTR( parent_cxy,
299                                                &parent_ptr->fd_array.array[0] ) );
[440]300
[457]301        // get extended pointer on parent process TXT chdev
[440]302        chdev_xp = chdev_from_file( file_xp );
[428]303 
304        // get cluster and local pointer on chdev
305        chdev_cxy = GET_CXY( chdev_xp );
[435]306        chdev_ptr = GET_PTR( chdev_xp );
[428]307 
[564]308        // get parent process TXT terminal index
309        txt_id = hal_remote_l32( XPTR( chdev_cxy , &chdev_ptr->channel ) );
[407]310
[564]311        // attach child process to parent process TXT terminal
[428]312        process_txt_attach( process , txt_id ); 
[407]313
[457]314        // copy all open files from parent process fd_array to this process
[428]315        process_fd_remote_copy( XPTR( local_cxy , &process->fd_array ),
[457]316                                XPTR( parent_cxy , &parent_ptr->fd_array ) );
[408]317    }
[407]318
[610]319    // initialize lock protecting CWD changes
[625]320    remote_busylock_init( XPTR( local_cxy , 
321                                &process->cwd_lock ), LOCK_PROCESS_CWD );
[408]322
[438]323#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
[433]324cycle = (uint32_t)hal_get_cycles();
[610]325if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
326printk("\n[%s] thread[%x,%x] / set fd_array for process %x / cycle %d\n", 
327__FUNCTION__, parent_pid, this->trdid, pid , cycle );
[433]328#endif
[407]329
[408]330    // reset children list root
331    xlist_root_init( XPTR( local_cxy , &process->children_root ) );
332    process->children_nr     = 0;
[625]333    remote_queuelock_init( XPTR( local_cxy,
334                                 &process->children_lock ), LOCK_PROCESS_CHILDREN );
[407]335
[611]336    // reset semaphore / mutex / barrier / condvar list roots and lock
[408]337    xlist_root_init( XPTR( local_cxy , &process->sem_root ) );
338    xlist_root_init( XPTR( local_cxy , &process->mutex_root ) );
339    xlist_root_init( XPTR( local_cxy , &process->barrier_root ) );
340    xlist_root_init( XPTR( local_cxy , &process->condvar_root ) );
[625]341    remote_queuelock_init( XPTR( local_cxy , 
342                                 &process->sync_lock ), LOCK_PROCESS_USERSYNC );
[407]343
[611]344    // reset open directories root and lock
345    xlist_root_init( XPTR( local_cxy , &process->dir_root ) );
[625]346    remote_queuelock_init( XPTR( local_cxy , 
347                                 &process->dir_lock ), LOCK_PROCESS_DIR );
[611]348
[408]349    // register new process in the local cluster manager pref_tbl[]
350    lpid_t lpid = LPID_FROM_PID( pid );
351    LOCAL_CLUSTER->pmgr.pref_tbl[lpid] = XPTR( local_cxy , process );
[407]352
[408]353    // register new process descriptor in local cluster manager local_list
354    cluster_process_local_link( process );
[407]355
[408]356    // register new process descriptor in local cluster manager copies_list
357    cluster_process_copies_link( process );
[172]358
[564]359    // initialize th_tbl[] array and associated threads
[1]360    uint32_t i;
[564]361
362    for( i = 0 ; i < CONFIG_THREADS_MAX_PER_CLUSTER ; i++ )
[1]363        {
364        process->th_tbl[i] = NULL;
365    }
366    process->th_nr  = 0;
[564]367    rwlock_init( &process->th_lock , LOCK_PROCESS_THTBL );
[1]368
[124]369        hal_fence();
[1]370
[438]371#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
[433]372cycle = (uint32_t)hal_get_cycles();
[610]373if( DEBUG_PROCESS_REFERENCE_INIT < cycle )
374printk("\n[%s] thread[%x,%x] exit for process %x / cycle %d\n", 
375__FUNCTION__, parent_pid, this->trdid, pid, cycle );
[433]376#endif
[101]377
[635]378#if (DEBUG_PROCESS_REFERENCE_INIT & 1)
379hal_vmm_display( parent_xp , false );
380hal_vmm_display( XPTR( local_cxy , process ) , false );
381#endif
382
[625]383    return 0;
384
[428]385}  // process_reference_init()
[204]386
[1]387/////////////////////////////////////////////////////
388error_t process_copy_init( process_t * local_process,
389                           xptr_t      reference_process_xp )
390{
[625]391    error_t   error;
392    vmm_t   * vmm;
[415]393
[23]394    // get reference process cluster and local pointer
395    cxy_t       ref_cxy = GET_CXY( reference_process_xp );
[435]396    process_t * ref_ptr = GET_PTR( reference_process_xp );
[1]397
[625]398    // get pointer on process vmm
399    vmm = &local_process->vmm;
400
[428]401    // initialize PID, REF_XP, PARENT_XP, and STATE
[564]402    local_process->pid        = hal_remote_l32(  XPTR( ref_cxy , &ref_ptr->pid ) );
403    local_process->parent_xp  = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->parent_xp ) );
[433]404    local_process->ref_xp     = reference_process_xp;
[443]405    local_process->owner_xp   = reference_process_xp;
[433]406    local_process->term_state = 0;
[407]407
[564]408#if DEBUG_PROCESS_COPY_INIT
[610]409thread_t * this = CURRENT_THREAD; 
[433]410uint32_t cycle = (uint32_t)hal_get_cycles();
[610]411if( DEBUG_PROCESS_COPY_INIT < cycle )
412printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
413__FUNCTION__, this->process->pid, this->trdid, local_process->pid, cycle );
[433]414#endif
[407]415
[564]416// check user process
[625]417assert( (local_process->pid != 0), "LPID cannot be 0" );
[564]418
[625]419    // initialize VSL as empty
420    vmm->vsegs_nr = 0;
421        xlist_root_init( XPTR( local_cxy , &vmm->vsegs_root ) );
[1]422
[625]423    // create an empty GPT as required by the architecture
424    error = hal_gpt_create( &vmm->gpt );
425    if( error ) 
426    {
427        printk("\n[ERROR] in %s : cannot create empty GPT\n", __FUNCTION__ );
428        return -1;
429    }
430
431    // initialize GPT and VSL locks
432        remote_rwlock_init( XPTR( local_cxy , &vmm->vsl_lock ) , LOCK_VMM_VSL );
433
434    // register kernel vsegs in VMM as required by the architecture
435    error = hal_vmm_kernel_update( local_process );
436    if( error ) 
437    {
438        printk("\n[ERROR] in %s : cannot register kernel vsegs in VMM\n", __FUNCTION__ );
439        return -1;
440    }
441
442    // create "args" and "envs" vsegs
443    // create "stacks" and "mmap" vsegs allocators
444    // initialize locks protecting GPT and VSL
445    error = vmm_user_init( local_process );
446    if( error ) 
447    {
448        printk("\n[ERROR] in %s : cannot register user vsegs in VMM\n", __FUNCTION__ );
449        return -1;
450    }
451 
452#if (DEBUG_PROCESS_COPY_INIT & 1)
453cycle = (uint32_t)hal_get_cycles();
454if( DEBUG_PROCESS_COPY_INIT < cycle )
455printk("\n[%s] thread[%x,%x] initialized vmm for process %x / cycle %d\n", 
456__FUNCTION__, parent_pid, this->trdid, pid, cycle );
457#endif
458
459    // set process file descriptors array
[23]460        process_fd_init( local_process );
[1]461
[625]462    // set vfs_root_xp / vfs_bin_xp / cwd_xp fields
[564]463    local_process->vfs_root_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->vfs_root_xp ) );
464    local_process->vfs_bin_xp  = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->vfs_bin_xp ) );
[610]465    local_process->cwd_xp      = XPTR_NULL;
[1]466
467    // reset children list root (not used in a process descriptor copy)
468    xlist_root_init( XPTR( local_cxy , &local_process->children_root ) );
[172]469    local_process->children_nr   = 0;
[564]470    remote_queuelock_init( XPTR( local_cxy , &local_process->children_lock ),
471                           LOCK_PROCESS_CHILDREN );
[1]472
[428]473    // reset children_list (not used in a process descriptor copy)
474    xlist_entry_init( XPTR( local_cxy , &local_process->children_list ) );
[1]475
476    // reset semaphores list root (not used in a process descriptor copy)
477    xlist_root_init( XPTR( local_cxy , &local_process->sem_root ) );
[23]478    xlist_root_init( XPTR( local_cxy , &local_process->mutex_root ) );
479    xlist_root_init( XPTR( local_cxy , &local_process->barrier_root ) );
480    xlist_root_init( XPTR( local_cxy , &local_process->condvar_root ) );
[1]481
[564]482    // initialize th_tbl[] array and associated fields
[1]483    uint32_t i;
[564]484    for( i = 0 ; i < CONFIG_THREADS_MAX_PER_CLUSTER ; i++ )
[1]485        {
486        local_process->th_tbl[i] = NULL;
487    }
488    local_process->th_nr  = 0;
[564]489    rwlock_init( &local_process->th_lock , LOCK_PROCESS_THTBL );
[1]490
491    // register new process descriptor in local cluster manager local_list
492    cluster_process_local_link( local_process );
493
494    // register new process descriptor in owner cluster manager copies_list
495    cluster_process_copies_link( local_process );
496
[124]497        hal_fence();
[1]498
[438]499#if DEBUG_PROCESS_COPY_INIT
[433]500cycle = (uint32_t)hal_get_cycles();
[610]501if( DEBUG_PROCESS_COPY_INIT < cycle )
502printk("\n[%s] thread[%x,%x] exit for process %x / cycle %d\n",
503__FUNCTION__, this->process->pid, this->trdid, local_process->pid, cycle );
[433]504#endif
[279]505
[1]506    return 0;
507
[204]508} // end process_copy_init()
509
[1]510///////////////////////////////////////////
511void process_destroy( process_t * process )
512{
[428]513    xptr_t      parent_xp;
514    process_t * parent_ptr;
515    cxy_t       parent_cxy;
516    xptr_t      children_lock_xp;
[446]517    xptr_t      children_nr_xp;
[1]518
[437]519    pid_t       pid = process->pid;
520
[593]521// check no more threads
[618]522assert( (process->th_nr == 0),
523"process %x in cluster %x contains threads", pid , local_cxy );
[428]524
[438]525#if DEBUG_PROCESS_DESTROY
[610]526thread_t * this = CURRENT_THREAD;
[433]527uint32_t cycle = (uint32_t)hal_get_cycles();
[610]528if( DEBUG_PROCESS_DESTROY < cycle )
529printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
530__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy, cycle );
[433]531#endif
[428]532
[618]533    // Destroy VMM
534    vmm_destroy( process );
535
536#if (DEBUG_PROCESS_DESTROY & 1)
537if( DEBUG_PROCESS_DESTROY < cycle )
538printk("\n[%s] thread[%x,%x] destroyed VMM for process %x in cluster %x\n",
539__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy );
540#endif
541
[436]542    // remove process from local_list in local cluster manager
543    cluster_process_local_unlink( process );
[1]544
[618]545#if (DEBUG_PROCESS_DESTROY & 1)
546if( DEBUG_PROCESS_DESTROY < cycle )
547printk("\n[%s] thread[%x,%x] removed process %x in cluster %x from local list\n",
548__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy );
549#endif
550
[436]551    // remove process from copies_list in owner cluster manager
552    cluster_process_copies_unlink( process );
[23]553
[618]554#if (DEBUG_PROCESS_DESTROY & 1)
555if( DEBUG_PROCESS_DESTROY < cycle )
556printk("\n[%s] thread[%x,%x] removed process %x in cluster %x from copies list\n",
557__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy );
558#endif
559
[625]560    // when target process cluster is the owner cluster
561    // - remove process from TXT list and transfer ownership
562    // - remove process from children_list
563    // - release PID
[437]564    if( CXY_FROM_PID( pid ) == local_cxy )
[428]565    {
[625]566        process_txt_detach( XPTR( local_cxy , process ) );
567
568#if (DEBUG_PROCESS_DESTROY & 1)
569if( DEBUG_PROCESS_DESTROY < cycle )
570printk("\n[%s] thread[%x,%x] removed process %x from TXT list\n",
571__FUNCTION__, this->process->pid, this->trdid, pid );
572#endif
573
[428]574        // get pointers on parent process
575        parent_xp  = process->parent_xp;
576        parent_cxy = GET_CXY( parent_xp );
577        parent_ptr = GET_PTR( parent_xp );
578
579        // get extended pointer on children_lock in parent process
580        children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock );
[446]581        children_nr_xp   = XPTR( parent_cxy , &parent_ptr->children_nr );
[428]582
583        // remove process from children_list
[564]584        remote_queuelock_acquire( children_lock_xp );
[428]585        xlist_unlink( XPTR( local_cxy , &process->children_list ) );
[446]586            hal_remote_atomic_add( children_nr_xp , -1 );
[564]587        remote_queuelock_release( children_lock_xp );
[450]588
[618]589#if (DEBUG_PROCESS_DESTROY & 1)
590if( DEBUG_PROCESS_DESTROY < cycle )
[625]591printk("\n[%s] thread[%x,%x] removed process %x from parent process children list\n",
592__FUNCTION__, this->process->pid, this->trdid, pid );
[618]593#endif
594
[564]595        // release the process PID to cluster manager
596        cluster_pid_release( pid );
[428]597
[618]598#if (DEBUG_PROCESS_DESTROY & 1)
599if( DEBUG_PROCESS_DESTROY < cycle )
600printk("\n[%s] thread[%x,%x] released process PID %x to pmgr in cluster %x\n",
601__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy );
602#endif
[23]603
[618]604    }
[1]605
[623]606    // FIXME decrement the refcount on file pointer for vfs_bin_xp [AG]
607
[618]608    // FIXME close all open files [AG]
[623]609
[618]610    // FIXME synchronize dirty files [AG]
[1]611
[416]612    // release memory allocated to process descriptor
613    process_free( process );
[1]614
[438]615#if DEBUG_PROCESS_DESTROY
[433]616cycle = (uint32_t)hal_get_cycles();
[610]617if( DEBUG_PROCESS_DESTROY < cycle )
618printk("\n[%s] thread[%x,%x] exit / process %x in cluster %x / cycle %d\n",
619__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy, cycle );
[433]620#endif
[428]621
[407]622}  // end process_destroy()
623
[583]624///////////////////////////////////////////////////////////////////
[527]625const char * process_action_str( process_sigactions_t action_type )
[409]626{
[583]627    switch ( action_type )
628    {
629        case BLOCK_ALL_THREADS:   return "BLOCK";
630        case UNBLOCK_ALL_THREADS: return "UNBLOCK";
631        case DELETE_ALL_THREADS:  return "DELETE";
632        default:                  return "undefined";
633    }
[409]634}
635
[435]636////////////////////////////////////////
637void process_sigaction( pid_t       pid,
[457]638                        uint32_t    type )
[409]639{
640    cxy_t              owner_cxy;         // owner cluster identifier
641    lpid_t             lpid;              // process index in owner cluster
642    cluster_t        * cluster;           // pointer on cluster manager
643    xptr_t             root_xp;           // extended pointer on root of copies
644    xptr_t             lock_xp;           // extended pointer on lock protecting copies
645    xptr_t             iter_xp;           // iterator on copies list
646    xptr_t             process_xp;        // extended pointer on process copy
647    cxy_t              process_cxy;       // process copy cluster identifier
[457]648    process_t        * process_ptr;       // local pointer on process copy
[436]649    reg_t              save_sr;           // for critical section
[457]650    thread_t         * client;            // pointer on client thread
651    xptr_t             client_xp;         // extended pointer on client thread
652    process_t        * local;             // pointer on process copy in local cluster
653    uint32_t           remote_nr;         // number of remote process copies
[619]654    rpc_desc_t         rpc;               // shared RPC descriptor
655    uint32_t           responses;         // shared RPC responses counter
[409]656
[457]657    client    = CURRENT_THREAD;
658    client_xp = XPTR( local_cxy , client );
659    local     = NULL;
660    remote_nr = 0;
[435]661
[583]662    // check calling thread can yield
663    thread_assert_can_yield( client , __FUNCTION__ );
[564]664
[438]665#if DEBUG_PROCESS_SIGACTION
[433]666uint32_t cycle = (uint32_t)hal_get_cycles();
[438]667if( DEBUG_PROCESS_SIGACTION < cycle )
[593]668printk("\n[%s] thread[%x,%x] enter to %s process %x / cycle %d\n",
[583]669__FUNCTION__ , client->process->pid, client->trdid,
[457]670process_action_str( type ) , pid , cycle );
[433]671#endif
[409]672
[436]673    // get pointer on local cluster manager
[416]674    cluster = LOCAL_CLUSTER;
675
[409]676    // get owner cluster identifier and process lpid
[435]677    owner_cxy = CXY_FROM_PID( pid );
678    lpid      = LPID_FROM_PID( pid );
[409]679
[593]680    // get root of list of copies and lock from owner cluster
[436]681    root_xp   = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
682    lock_xp   = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
[435]683
[583]684// check action type
685assert( ((type == DELETE_ALL_THREADS ) ||
686         (type == BLOCK_ALL_THREADS )  ||
687         (type == UNBLOCK_ALL_THREADS )), "illegal action type" );
[416]688             
[593]689    // This client thread send parallel RPCs to all remote clusters containing
[564]690    // target process copies, wait all responses, and then handles directly
691    // the threads in local cluster, when required.
[457]692    // The client thread allocates a - shared - RPC descriptor in the stack,
693    // because all parallel, non-blocking, server threads use the same input
694    // arguments, and use the shared RPC response field
[436]695
696    // mask IRQs
697    hal_disable_irq( &save_sr);
698
[457]699    // client thread blocks itself
700    thread_block( client_xp , THREAD_BLOCKED_RPC );
[436]701
[619]702    // initialize RPC responses counter
703    responses = 0;
704
[436]705    // initialize shared RPC descriptor
[619]706    // can be shared, because no out arguments
707    rpc.rsp       = &responses;
[438]708    rpc.blocking  = false;
709    rpc.index     = RPC_PROCESS_SIGACTION;
710    rpc.thread    = client;
711    rpc.lid       = client->core->lid;
[611]712    rpc.args[0]   = pid;
713    rpc.args[1]   = type;
[436]714
[611]715    // take the lock protecting process copies
716    remote_queuelock_acquire( lock_xp );
717
[457]718    // scan list of process copies
[409]719    XLIST_FOREACH( root_xp , iter_xp )
720    {
[457]721        // get extended pointers and cluster on process
[440]722        process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
723        process_cxy = GET_CXY( process_xp );
[457]724        process_ptr = GET_PTR( process_xp );
[440]725
[593]726        if( process_cxy == local_cxy )    // process copy is local
[457]727        { 
728            local = process_ptr;
729        }
[593]730        else                              // process copy is remote
[457]731        {
732            // update number of remote process copies
733            remote_nr++;
734
[619]735            // atomically increment RPC responses counter
736            hal_atomic_add( &responses , 1 );
[457]737
[438]738#if DEBUG_PROCESS_SIGACTION
739if( DEBUG_PROCESS_SIGACTION < cycle )
[593]740printk("\n[%s] thread[%x,%x] send RPC to cluster %x for process %x\n",
[583]741__FUNCTION__, client->process->pid, client->trdid, process_cxy, pid );
[433]742#endif
[457]743            // call RPC in target cluster
[619]744            rpc_send( process_cxy , &rpc );
[457]745        }
746    }  // end list of copies
747
[409]748    // release the lock protecting process copies
[564]749    remote_queuelock_release( lock_xp );
[409]750
[436]751    // restore IRQs
752    hal_restore_irq( save_sr);
[409]753
[457]754    // - if there is remote process copies, the client thread deschedules,
755    //   (it will be unblocked by the last RPC server thread).
756    // - if there is no remote copies, the client thread unblock itself.
757    if( remote_nr )
758    {
759        sched_yield("blocked on rpc_process_sigaction");
760    } 
761    else
762    {
763        thread_unblock( client_xp , THREAD_BLOCKED_RPC );
764    }
[409]765
[457]766    // handle the local process copy if required
767    if( local != NULL )
768    {
769
770#if DEBUG_PROCESS_SIGACTION
771if( DEBUG_PROCESS_SIGACTION < cycle )
[593]772printk("\n[%s] thread[%x,%x] handles local process %x in cluster %x\n",
[583]773__FUNCTION__, client->process->pid, client->trdid, pid , local_cxy );
[457]774#endif
775        if     (type == DELETE_ALL_THREADS  ) process_delete_threads ( local , client_xp ); 
[583]776        else if(type == BLOCK_ALL_THREADS   ) process_block_threads  ( local ); 
[457]777        else if(type == UNBLOCK_ALL_THREADS ) process_unblock_threads( local );
778    }
779
[438]780#if DEBUG_PROCESS_SIGACTION
[433]781cycle = (uint32_t)hal_get_cycles();
[438]782if( DEBUG_PROCESS_SIGACTION < cycle )
[593]783printk("\n[%s] thread[%x,%x] exit after %s process %x / cycle %d\n",
[583]784__FUNCTION__, client->process->pid, client->trdid,
[457]785process_action_str( type ), pid, cycle );
[433]786#endif
[416]787
[409]788}  // end process_sigaction()
789
[433]790/////////////////////////////////////////////////
[583]791void process_block_threads( process_t * process )
[1]792{
[409]793    thread_t          * target;         // pointer on target thread
[433]794    thread_t          * this;           // pointer on calling thread
[564]795    uint32_t            ltid;           // index in process th_tbl[]
[409]796    uint32_t            count;          // requests counter
[593]797    volatile uint32_t   ack_count;      // acknowledges counter
[1]798
[416]799    // get calling thread pointer
[433]800    this = CURRENT_THREAD;
[407]801
[438]802#if DEBUG_PROCESS_SIGACTION
[564]803pid_t pid = process->pid;
[433]804uint32_t cycle = (uint32_t)hal_get_cycles();
[438]805if( DEBUG_PROCESS_SIGACTION < cycle )
[593]806printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
[583]807__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy , cycle );
[433]808#endif
[409]809
[564]810// check target process is an user process
[619]811assert( (LPID_FROM_PID( process->pid ) != 0 ),
812"process %x is not an user process\n", process->pid );
[564]813
[409]814    // get lock protecting process th_tbl[]
[564]815    rwlock_rd_acquire( &process->th_lock );
[1]816
[440]817    // loop on target process local threads
[409]818    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
[593]819    // - if the calling thread and the target thread are not running on the same
820    //   core, we ask the target scheduler to acknowlege the blocking
821    //   to be sure that the target thread is not running.
822    // - if the calling thread and the target thread are running on the same core,
823    //   we don't need confirmation from scheduler.
824           
[436]825    for( ltid = 0 , count = 0 , ack_count = 0 ; count < process->th_nr ; ltid++ )
[1]826    {
[409]827        target = process->th_tbl[ltid];
[1]828
[436]829        if( target != NULL )                                 // thread exist
[1]830        {
831            count++;
[409]832
[583]833            // set the global blocked bit in target thread descriptor.
834            thread_block( XPTR( local_cxy , target ) , THREAD_BLOCKED_GLOBAL );
[436]835 
[583]836            if( this->core->lid != target->core->lid )
837            {
838                // increment responses counter
839                hal_atomic_add( (void*)&ack_count , 1 );
[409]840
[583]841                // set FLAG_REQ_ACK and &ack_rsp_count in target descriptor
842                thread_set_req_ack( target , (uint32_t *)&ack_count );
[409]843
[583]844                // force scheduling on target thread
845                dev_pic_send_ipi( local_cxy , target->core->lid );
[409]846            }
[1]847        }
[172]848    }
849
[428]850    // release lock protecting process th_tbl[]
[564]851    rwlock_rd_release( &process->th_lock );
[416]852
[593]853    // wait other threads acknowledges  TODO this could be improved...
[409]854    while( 1 )
855    {
[610]856        // exit when all scheduler acknowledges received
[436]857        if ( ack_count == 0 ) break;
[409]858   
859        // wait 1000 cycles before retry
860        hal_fixed_delay( 1000 );
861    }
[1]862
[438]863#if DEBUG_PROCESS_SIGACTION
[433]864cycle = (uint32_t)hal_get_cycles();
[438]865if( DEBUG_PROCESS_SIGACTION < cycle )
[593]866printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
867__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy , cycle );
[433]868#endif
[409]869
[428]870}  // end process_block_threads()
[409]871
[440]872/////////////////////////////////////////////////
873void process_delete_threads( process_t * process,
874                             xptr_t      client_xp )
[409]875{
[440]876    thread_t          * target;        // local pointer on target thread
877    xptr_t              target_xp;     // extended pointer on target thread
878    cxy_t               owner_cxy;     // owner process cluster
[409]879    uint32_t            ltid;          // index in process th_tbl
[440]880    uint32_t            count;         // threads counter
[409]881
[433]882    // get calling thread pointer
[409]883
[440]884    // get target process owner cluster
885    owner_cxy = CXY_FROM_PID( process->pid );
886
[438]887#if DEBUG_PROCESS_SIGACTION
[633]888thread_t * this  = CURRENT_THREAD;
889uint32_t   cycle = (uint32_t)hal_get_cycles();
[438]890if( DEBUG_PROCESS_SIGACTION < cycle )
[625]891printk("\n[%s] thread[%x,%x] enter for process %x n cluster %x / cycle %d\n",
892__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
[433]893#endif
894
[564]895// check target process is an user process
[619]896assert( (LPID_FROM_PID( process->pid ) != 0),
897"process %x is not an user process\n", process->pid );
[564]898
[409]899    // get lock protecting process th_tbl[]
[583]900    rwlock_wr_acquire( &process->th_lock );
[409]901
[440]902    // loop on target process local threads                       
[416]903    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
[440]904    for( ltid = 0 , count = 0  ; count < process->th_nr ; ltid++ )
[1]905    {
[409]906        target = process->th_tbl[ltid];
[1]907
[440]908        if( target != NULL )    // valid thread 
[1]909        {
[416]910            count++;
[440]911            target_xp = XPTR( local_cxy , target );
[1]912
[564]913            // main thread and client thread should not be deleted
[440]914            if( ((ltid != 0) || (owner_cxy != local_cxy)) &&         // not main thread
915                (client_xp) != target_xp )                           // not client thread
916            {
917                // mark target thread for delete and block it
[651]918                thread_delete( target_xp , true );                   // forced
[440]919            }
[409]920        }
921    }
[1]922
[428]923    // release lock protecting process th_tbl[]
[583]924    rwlock_wr_release( &process->th_lock );
[407]925
[438]926#if DEBUG_PROCESS_SIGACTION
[433]927cycle = (uint32_t)hal_get_cycles();
[438]928if( DEBUG_PROCESS_SIGACTION < cycle )
[593]929printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
930__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy , cycle );
[433]931#endif
[407]932
[440]933}  // end process_delete_threads()
[409]934
[440]935///////////////////////////////////////////////////
936void process_unblock_threads( process_t * process )
[409]937{
[440]938    thread_t          * target;        // pointer on target thead
[409]939    uint32_t            ltid;          // index in process th_tbl
[440]940    uint32_t            count;         // requests counter
[409]941
[438]942#if DEBUG_PROCESS_SIGACTION
[633]943thread_t * this  = CURRENT_THREAD;
944pid_t      pid   = process->pid;
945uint32_t   cycle = (uint32_t)hal_get_cycles();
[438]946if( DEBUG_PROCESS_SIGACTION < cycle )
[593]947printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
[583]948__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy , cycle );
[433]949#endif
950
[564]951// check target process is an user process
[619]952assert( ( LPID_FROM_PID( process->pid ) != 0 ),
953"process %x is not an user process\n", process->pid );
[564]954
[416]955    // get lock protecting process th_tbl[]
[564]956    rwlock_rd_acquire( &process->th_lock );
[416]957
[440]958    // loop on process threads to unblock all threads
[416]959    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
[440]960    for( ltid = 0 , count = 0 ; count < process->th_nr ; ltid++ )
[409]961    {
[416]962        target = process->th_tbl[ltid];
[409]963
[440]964        if( target != NULL )             // thread found
[409]965        {
966            count++;
[440]967
968            // reset the global blocked bit in target thread descriptor.
969            thread_unblock( XPTR( local_cxy , target ) , THREAD_BLOCKED_GLOBAL );
[1]970        }
971    }
972
[428]973    // release lock protecting process th_tbl[]
[564]974    rwlock_rd_release( &process->th_lock );
[407]975
[438]976#if DEBUG_PROCESS_SIGACTION
[433]977cycle = (uint32_t)hal_get_cycles();
[438]978if( DEBUG_PROCESS_SIGACTION < cycle )
[593]979printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
[583]980__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy, cycle );
[433]981#endif
[1]982
[440]983}  // end process_unblock_threads()
[407]984
[1]985///////////////////////////////////////////////
986process_t * process_get_local_copy( pid_t pid )
987{
988    error_t        error;
[172]989    process_t    * process_ptr;   // local pointer on process
[23]990    xptr_t         process_xp;    // extended pointer on process
[1]991
992    cluster_t * cluster = LOCAL_CLUSTER;
993
[564]994#if DEBUG_PROCESS_GET_LOCAL_COPY
995thread_t * this = CURRENT_THREAD;
996uint32_t cycle = (uint32_t)hal_get_cycles();
997if( DEBUG_PROCESS_GET_LOCAL_COPY < cycle )
[593]998printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
[583]999__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy, cycle );
[564]1000#endif
1001
[1]1002    // get lock protecting local list of processes
[564]1003    remote_queuelock_acquire( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
[1]1004
1005    // scan the local list of process descriptors to find the process
[23]1006    xptr_t  iter;
1007    bool_t  found = false;
1008    XLIST_FOREACH( XPTR( local_cxy , &cluster->pmgr.local_root ) , iter )
[1]1009    {
[23]1010        process_xp  = XLIST_ELEMENT( iter , process_t , local_list );
[435]1011        process_ptr = GET_PTR( process_xp );
[23]1012        if( process_ptr->pid == pid )
[1]1013        {
1014            found = true;
1015            break;
1016        }
1017    }
1018
1019    // release lock protecting local list of processes
[564]1020    remote_queuelock_release( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
[1]1021
[172]1022    // allocate memory for a new local process descriptor
[440]1023    // and initialise it from reference cluster if not found
[1]1024    if( !found )
1025    {
1026        // get extended pointer on reference process descriptor
[23]1027        xptr_t ref_xp = cluster_get_reference_process_from_pid( pid );
[1]1028
[492]1029        assert( (ref_xp != XPTR_NULL) , "illegal pid\n" );
[23]1030
[1]1031        // allocate memory for local process descriptor
[23]1032        process_ptr = process_alloc();
[443]1033
[23]1034        if( process_ptr == NULL )  return NULL;
[1]1035
1036        // initialize local process descriptor copy
[23]1037        error = process_copy_init( process_ptr , ref_xp );
[443]1038
[1]1039        if( error ) return NULL;
1040    }
1041
[440]1042#if DEBUG_PROCESS_GET_LOCAL_COPY
[564]1043cycle = (uint32_t)hal_get_cycles();
[440]1044if( DEBUG_PROCESS_GET_LOCAL_COPY < cycle )
[593]1045printk("\n[%s] thread[%x,%x] exit in cluster %x / process %x / cycle %d\n",
[583]1046__FUNCTION__, this->process->pid, this->trdid, local_cxy, process_ptr, cycle );
[440]1047#endif
1048
[23]1049    return process_ptr;
[1]1050
[409]1051}  // end process_get_local_copy()
1052
[436]1053////////////////////////////////////////////
1054pid_t process_get_ppid( xptr_t  process_xp )
1055{
1056    cxy_t       process_cxy;
1057    process_t * process_ptr;
1058    xptr_t      parent_xp;
1059    cxy_t       parent_cxy;
1060    process_t * parent_ptr;
1061
1062    // get process cluster and local pointer
1063    process_cxy = GET_CXY( process_xp );
1064    process_ptr = GET_PTR( process_xp );
1065
1066    // get pointers on parent process
[564]1067    parent_xp  = (xptr_t)hal_remote_l64( XPTR( process_cxy , &process_ptr->parent_xp ) );
[436]1068    parent_cxy = GET_CXY( parent_xp );
1069    parent_ptr = GET_PTR( parent_xp );
1070
[564]1071    return hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
[436]1072}
1073
[1]1074//////////////////////////////////////////////////////////////////////////////////////////
1075// File descriptor array related functions
1076//////////////////////////////////////////////////////////////////////////////////////////
1077
1078///////////////////////////////////////////
1079void process_fd_init( process_t * process )
1080{
1081    uint32_t fd;
1082
[610]1083    // initialize lock
[564]1084    remote_queuelock_init( XPTR( local_cxy , &process->fd_array.lock ), LOCK_PROCESS_FDARRAY );
[1]1085
[610]1086    // initialize number of open files
[23]1087    process->fd_array.current = 0;
1088
[1]1089    // initialize array
[23]1090    for ( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
[1]1091    {
1092        process->fd_array.array[fd] = XPTR_NULL;
1093    }
1094}
[635]1095
[610]1096////////////////////////////////////////////////////
1097error_t process_fd_register( xptr_t      process_xp,
[407]1098                             xptr_t      file_xp,
1099                             uint32_t  * fdid )
[1]1100{
1101    bool_t    found;
[23]1102    uint32_t  id;
1103    xptr_t    xp;
[1]1104
[657]1105    // get target process cluster and local pointer
[610]1106    process_t * process_ptr = GET_PTR( process_xp );
1107    cxy_t       process_cxy = GET_CXY( process_xp );
[23]1108
[657]1109// check target process is reference process
[610]1110assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp ) ) ),
1111"client process must be reference process\n" );
1112
1113#if DEBUG_PROCESS_FD_REGISTER
1114thread_t * this  = CURRENT_THREAD;
1115uint32_t   cycle = (uint32_t)hal_get_cycles();
1116pid_t      pid   = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
1117if( DEBUG_PROCESS_FD_REGISTER < cycle )
1118printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
1119__FUNCTION__, this->process->pid, this->trdid, pid, cycle );
1120#endif
1121
1122    // build extended pointer on lock protecting reference fd_array
1123    xptr_t lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
1124
[23]1125    // take lock protecting reference fd_array
[610]1126        remote_queuelock_acquire( lock_xp );
[23]1127
[1]1128    found   = false;
1129
[23]1130    for ( id = 0; id < CONFIG_PROCESS_FILE_MAX_NR ; id++ )
[1]1131    {
[610]1132        xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
[23]1133        if ( xp == XPTR_NULL )
[1]1134        {
[564]1135            // update reference fd_array
[610]1136            hal_remote_s64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) , file_xp );
1137                hal_remote_atomic_add( XPTR( process_cxy , &process_ptr->fd_array.current ) , 1 );
[564]1138
1139            // exit
1140                        *fdid = id;
[1]1141            found = true;
1142            break;
1143        }
1144    }
1145
[610]1146    // release lock protecting fd_array
1147        remote_queuelock_release( lock_xp );
[1]1148
[610]1149#if DEBUG_PROCESS_FD_REGISTER
1150cycle = (uint32_t)hal_get_cycles();
1151if( DEBUG_PROCESS_FD_REGISTER < cycle )
1152printk("\n[%s] thread[%x,%x] exit for process %x / fdid %d / cycle %d\n",
1153__FUNCTION__, this->process->pid, this->trdid, pid, id, cycle );
1154#endif
1155
[428]1156    if ( !found ) return -1;
[1]1157    else          return 0;
1158
[610]1159}  // end process_fd_register()
1160
[657]1161/////////////////////////////////////////////
1162void process_fd_remove( xptr_t    process_xp,
1163                        uint32_t  fdid )
1164{
1165    pid_t       pid;           // target process PID
1166    lpid_t      lpid;          // target process LPID
1167    xptr_t      iter_xp;       // iterator for list of process copies
1168    xptr_t      copy_xp;       // extended pointer on process copy
1169    process_t * copy_ptr;      // local pointer on process copy 
1170    cxy_t       copy_cxy;      // process copy cluster identifier
1171
1172// check process_xp argument
1173assert( (process_xp != XPTR_NULL), "process_xp argument cannot be XPTR_NULL");
1174
1175    // get target process cluster and local pointer
1176    process_t * process_ptr = GET_PTR( process_xp );
1177    cxy_t       process_cxy = GET_CXY( process_xp );
1178
1179    // get target process pid and lpid
1180    pid  = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
1181    lpid = LPID_FROM_PID( pid );
1182
1183    // get process descriptor in owner cluster and in reference cluster
1184    xptr_t  owner_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ));
1185    xptr_t  ref_xp   = hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp   ));
1186
1187// check target process in in owner cluster
1188assert( (process_xp == owner_xp), "target process must be in owner process\n" );
1189
1190#if DEBUG_PROCESS_FD_REMOVE
1191uint32_t    cycle = (uint32_t)hal_get_cycles();
1192thread_t  * this  = CURRENT_THREAD;
1193if( DEBUG_PROCESS_FD_REMOVE < cycle )
1194printk("\n[%s] thread[%x,%x] enter for fdid %d in process %x / cycle %d\n",
1195__FUNCTION__, this->process->pid, this->trdid, fdid, pid, cycle );
1196#endif
1197
1198    // build extended pointers on list_of_copies root and lock (in owner cluster)
1199    xptr_t copies_root_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_root[lpid] );
1200    xptr_t copies_lock_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_lock[lpid] );
1201 
1202    // get reference process cluster and local pointer
1203    process_t * ref_ptr = GET_PTR( ref_xp );
1204    cxy_t       ref_cxy = GET_CXY( ref_xp );
1205
1206    // build extended pointer on lock protecting reference fd_array
1207    xptr_t fd_lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
1208
1209    // take lock protecting reference fd_array
1210        remote_queuelock_acquire( fd_lock_xp );
1211
1212    // take the lock protecting the list of copies
1213    remote_queuelock_acquire( copies_lock_xp );
1214
1215    // loop on list of process copies
1216    XLIST_FOREACH( copies_root_xp , iter_xp )
1217    {
1218        // get pointers on process copy
1219        copy_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
1220        copy_ptr = GET_PTR( copy_xp );
1221        copy_cxy = GET_CXY( copy_xp );
1222
1223        // release the fd_array entry in process copy
1224        hal_remote_s64( XPTR( copy_cxy , &copy_ptr->fd_array.array[fdid] ), XPTR_NULL );
1225    }
1226
1227    // release the lock protecting reference fd_array
1228        remote_queuelock_release( fd_lock_xp );
1229
1230    // release the lock protecting the list of copies
1231    remote_queuelock_release( copies_lock_xp );
1232
1233#if DEBUG_PROCESS_FD_REMOVE
1234cycle = (uint32_t)hal_get_cycles();
1235if( DEBUG_PROCESS_FD_REMOVE < cycle )
1236printk("\n[%s] thread[%x,%x] exit for fdid %d in process %x / cycle %d\n",
1237__FUNCTION__, this->process->pid, this->trdid, fdid, pid, cycle );
1238#endif
1239
1240}  // end process_fd_remove()
1241
[172]1242////////////////////////////////////////////////
[23]1243xptr_t process_fd_get_xptr( process_t * process,
[407]1244                            uint32_t    fdid )
[1]1245{
[23]1246    xptr_t  file_xp;
[564]1247    xptr_t  lock_xp;
[1]1248
[23]1249    // access local copy of process descriptor
[407]1250    file_xp = process->fd_array.array[fdid];
[1]1251
[23]1252    if( file_xp == XPTR_NULL )
1253    {
1254        // get reference process cluster and local pointer
1255        xptr_t      ref_xp  = process->ref_xp;
1256        cxy_t       ref_cxy = GET_CXY( ref_xp );
[435]1257        process_t * ref_ptr = GET_PTR( ref_xp );
[1]1258
[564]1259        // build extended pointer on lock protecting reference fd_array
1260        lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
1261
1262        // take lock protecting reference fd_array
1263            remote_queuelock_acquire( lock_xp );
1264
[23]1265        // access reference process descriptor
[564]1266        file_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->fd_array.array[fdid] ) );
[1]1267
[23]1268        // update local fd_array if found
[564]1269        if( file_xp != XPTR_NULL )  process->fd_array.array[fdid] = file_xp;
1270       
1271        // release lock protecting reference fd_array
1272            remote_queuelock_release( lock_xp );
[23]1273    }
[1]1274
[23]1275    return file_xp;
[1]1276
[407]1277}  // end process_fd_get_xptr()
1278
[1]1279///////////////////////////////////////////
1280void process_fd_remote_copy( xptr_t dst_xp,
1281                             xptr_t src_xp )
1282{
1283    uint32_t fd;
1284    xptr_t   entry;
1285
1286    // get cluster and local pointer for src fd_array
1287    cxy_t        src_cxy = GET_CXY( src_xp );
[435]1288    fd_array_t * src_ptr = GET_PTR( src_xp );
[1]1289
1290    // get cluster and local pointer for dst fd_array
1291    cxy_t        dst_cxy = GET_CXY( dst_xp );
[435]1292    fd_array_t * dst_ptr = GET_PTR( dst_xp );
[1]1293
1294    // get the remote lock protecting the src fd_array
[564]1295        remote_queuelock_acquire( XPTR( src_cxy , &src_ptr->lock ) );
[1]1296
[428]1297    // loop on all fd_array entries
1298    for( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
[1]1299        {
[564]1300                entry = (xptr_t)hal_remote_l64( XPTR( src_cxy , &src_ptr->array[fd] ) );
[1]1301
1302                if( entry != XPTR_NULL )
1303                {
[459]1304            // increment file descriptor refcount
[1]1305            vfs_file_count_up( entry );
1306
1307                        // copy entry in destination process fd_array
[564]1308                        hal_remote_s64( XPTR( dst_cxy , &dst_ptr->array[fd] ) , entry );
[1]1309                }
1310        }
1311
1312    // release lock on source process fd_array
[564]1313        remote_queuelock_release( XPTR( src_cxy , &src_ptr->lock ) );
[1]1314
[407]1315}  // end process_fd_remote_copy()
1316
[564]1317
1318////////////////////////////////////
1319bool_t process_fd_array_full( void )
1320{
1321    // get extended pointer on reference process
1322    xptr_t ref_xp = CURRENT_THREAD->process->ref_xp;
1323
1324    // get reference process cluster and local pointer
1325    process_t * ref_ptr = GET_PTR( ref_xp );
1326    cxy_t       ref_cxy = GET_CXY( ref_xp );
1327
1328    // get number of open file descriptors from reference fd_array
1329    uint32_t current = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->fd_array.current ) );
1330
1331        return ( current >= CONFIG_PROCESS_FILE_MAX_NR );
1332}
1333
1334
[1]1335////////////////////////////////////////////////////////////////////////////////////
1336//  Thread related functions
1337////////////////////////////////////////////////////////////////////////////////////
1338
1339/////////////////////////////////////////////////////
1340error_t process_register_thread( process_t * process,
1341                                 thread_t  * thread,
1342                                 trdid_t   * trdid )
1343{
[472]1344    ltid_t         ltid;
1345    bool_t         found = false;
1346 
[564]1347// check arguments
1348assert( (process != NULL) , "process argument is NULL" );
1349assert( (thread != NULL) , "thread argument is NULL" );
[1]1350
[564]1351    // get the lock protecting th_tbl for all threads
1352    // but the idle thread executing kernel_init (cannot yield)
1353    if( thread->type != THREAD_IDLE ) rwlock_wr_acquire( &process->th_lock );
[1]1354
[583]1355    // scan th_tbl
[564]1356    for( ltid = 0 ; ltid < CONFIG_THREADS_MAX_PER_CLUSTER ; ltid++ )
[1]1357    {
1358        if( process->th_tbl[ltid] == NULL )
1359        {
1360            found = true;
1361            break;
1362        }
1363    }
1364
1365    if( found )
1366    {
1367        // register thread in th_tbl[]
1368        process->th_tbl[ltid] = thread;
1369        process->th_nr++;
1370
1371        // returns trdid
1372        *trdid = TRDID( local_cxy , ltid );
1373    }
1374
[583]1375    // release the lock protecting th_tbl
[564]1376    if( thread->type != THREAD_IDLE ) rwlock_wr_release( &process->th_lock );
[428]1377
[564]1378    return (found) ? 0 : 0xFFFFFFFF;
[204]1379
1380}  // end process_register_thread()
1381
[625]1382///////////////////////////////////////////////////
1383uint32_t process_remove_thread( thread_t * thread )
[1]1384{
[443]1385    uint32_t count;  // number of threads in local process descriptor
1386
[625]1387// check thread
1388assert( (thread != NULL) , "thread argument is NULL" );
1389
[1]1390    process_t * process = thread->process;
1391
1392    // get thread local index
1393    ltid_t  ltid = LTID_FROM_TRDID( thread->trdid );
[564]1394   
1395    // get the lock protecting th_tbl[]
1396    rwlock_wr_acquire( &process->th_lock );
[428]1397
[583]1398    // get number of threads
[443]1399    count = process->th_nr;
[428]1400
[564]1401// check th_nr value
[624]1402assert( (count > 0) , "process th_nr cannot be 0" );
[443]1403
[1]1404    // remove thread from th_tbl[]
1405    process->th_tbl[ltid] = NULL;
[450]1406    process->th_nr = count-1;
[1]1407
[583]1408    // release lock protecting th_tbl
[564]1409    rwlock_wr_release( &process->th_lock );
[428]1410
[625]1411    return count;
[443]1412
[450]1413}  // end process_remove_thread()
[204]1414
[408]1415/////////////////////////////////////////////////////////
1416error_t process_make_fork( xptr_t      parent_process_xp,
1417                           xptr_t      parent_thread_xp,
1418                           pid_t     * child_pid,
1419                           thread_t ** child_thread )
[1]1420{
[408]1421    process_t * process;         // local pointer on child process descriptor
1422    thread_t  * thread;          // local pointer on child thread descriptor
1423    pid_t       new_pid;         // process identifier for child process
1424    pid_t       parent_pid;      // process identifier for parent process
1425    xptr_t      ref_xp;          // extended pointer on reference process
[428]1426    xptr_t      vfs_bin_xp;      // extended pointer on .elf file
[408]1427    error_t     error;
[1]1428
[408]1429    // get cluster and local pointer for parent process
1430    cxy_t       parent_process_cxy = GET_CXY( parent_process_xp );
[435]1431    process_t * parent_process_ptr = GET_PTR( parent_process_xp );
[101]1432
[428]1433    // get parent process PID and extended pointer on .elf file
[564]1434    parent_pid = hal_remote_l32 (XPTR( parent_process_cxy , &parent_process_ptr->pid));
1435    vfs_bin_xp = hal_remote_l64(XPTR( parent_process_cxy , &parent_process_ptr->vfs_bin_xp));
[428]1436
[564]1437    // get extended pointer on reference process
1438    ref_xp = hal_remote_l64( XPTR( parent_process_cxy , &parent_process_ptr->ref_xp ) );
[438]1439
[564]1440// check parent process is the reference process
1441assert( (parent_process_xp == ref_xp ) ,
[624]1442"parent process must be the reference process" );
[407]1443
[438]1444#if DEBUG_PROCESS_MAKE_FORK
[635]1445uint32_t   cycle;
[583]1446thread_t * this  = CURRENT_THREAD;
1447trdid_t    trdid = this->trdid;
1448pid_t      pid   = this->process->pid;
[635]1449#endif
1450
1451#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1452cycle   = (uint32_t)hal_get_cycles();
[438]1453if( DEBUG_PROCESS_MAKE_FORK < cycle )
[593]1454printk("\n[%s] thread[%x,%x] enter / cluster %x / cycle %d\n",
[583]1455__FUNCTION__, pid, trdid, local_cxy, cycle );
[433]1456#endif
[172]1457
[408]1458    // allocate a process descriptor
1459    process = process_alloc();
[635]1460
[408]1461    if( process == NULL )
1462    {
1463        printk("\n[ERROR] in %s : cannot get process in cluster %x\n", 
1464        __FUNCTION__, local_cxy ); 
1465        return -1;
1466    }
[1]1467
[408]1468    // allocate a child PID from local cluster
[416]1469    error = cluster_pid_alloc( process , &new_pid );
[428]1470    if( error ) 
[1]1471    {
[408]1472        printk("\n[ERROR] in %s : cannot get PID in cluster %x\n", 
1473        __FUNCTION__, local_cxy ); 
1474        process_free( process );
1475        return -1;
[1]1476    }
[408]1477
[469]1478#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[457]1479cycle = (uint32_t)hal_get_cycles();
1480if( DEBUG_PROCESS_MAKE_FORK < cycle )
[625]1481printk("\n[%s] thread[%x,%x] allocated child_process %x / cycle %d\n",
[583]1482__FUNCTION__, pid, trdid, new_pid, cycle );
[457]1483#endif
1484
[408]1485    // initializes child process descriptor from parent process descriptor
[625]1486    error = process_reference_init( process,
1487                                    new_pid,
1488                                    parent_process_xp );
1489    if( error ) 
1490    {
1491        printk("\n[ERROR] in %s : cannot initialize child process in cluster %x\n", 
1492        __FUNCTION__, local_cxy ); 
1493        process_free( process );
1494        return -1;
1495    }
[408]1496
[438]1497#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[433]1498cycle = (uint32_t)hal_get_cycles();
[438]1499if( DEBUG_PROCESS_MAKE_FORK < cycle )
[593]1500printk("\n[%s] thread[%x,%x] initialized child_process %x / cycle %d\n",
[583]1501__FUNCTION__, pid, trdid, new_pid, cycle );
[433]1502#endif
[408]1503
1504    // copy VMM from parent descriptor to child descriptor
1505    error = vmm_fork_copy( process,
1506                           parent_process_xp );
1507    if( error )
[101]1508    {
[408]1509        printk("\n[ERROR] in %s : cannot copy VMM in cluster %x\n", 
1510        __FUNCTION__, local_cxy ); 
1511        process_free( process );
1512        cluster_pid_release( new_pid );
1513        return -1;
[101]1514    }
[172]1515
[438]1516#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[433]1517cycle = (uint32_t)hal_get_cycles();
[438]1518if( DEBUG_PROCESS_MAKE_FORK < cycle )
[593]1519printk("\n[%s] thread[%x,%x] copied VMM from parent to child / cycle %d\n",
[583]1520__FUNCTION__, pid, trdid, cycle );
[635]1521hal_vmm_display( XPTR( local_cxy , process ) , true );
[433]1522#endif
[407]1523
[564]1524    // if parent_process is INIT, or if parent_process is the TXT owner,
1525    // the child_process becomes the owner of its TXT terminal
1526    if( (parent_pid == 1) || process_txt_is_owner( parent_process_xp ) )
[457]1527    {
1528        process_txt_set_ownership( XPTR( local_cxy , process ) );
1529
1530#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1531cycle = (uint32_t)hal_get_cycles();
[626]1532if( DEBUG_PROCESS_MAKE_FORK < cycle )
[635]1533printk("\n[%s] thread[%x,%x] / child_process %x takes TXT ownership / cycle %d\n",
1534__FUNCTION__ , pid, trdid, new_pid, cycle );
[457]1535#endif
1536
1537    }
1538
[428]1539    // update extended pointer on .elf file
1540    process->vfs_bin_xp = vfs_bin_xp;
1541
[408]1542    // create child thread descriptor from parent thread descriptor
1543    error = thread_user_fork( parent_thread_xp,
1544                              process,
1545                              &thread );
1546    if( error )
1547    {
1548        printk("\n[ERROR] in %s : cannot create thread in cluster %x\n",
1549        __FUNCTION__, local_cxy ); 
1550        process_free( process );
1551        cluster_pid_release( new_pid );
1552        return -1;
1553    }
[172]1554
[564]1555// check main thread LTID
1556assert( (LTID_FROM_TRDID(thread->trdid) == 0) ,
[624]1557"main thread must have LTID == 0" );
[428]1558
[564]1559#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[433]1560cycle = (uint32_t)hal_get_cycles();
[438]1561if( DEBUG_PROCESS_MAKE_FORK < cycle )
[593]1562printk("\n[%s] thread[%x,%x] created main thread %x / cycle %d\n", 
[583]1563__FUNCTION__, pid, trdid, thread, cycle );
[433]1564#endif
[1]1565
[635]1566    // set COW flag in DATA, ANON, REMOTE vsegs in parent process VMM
[629]1567    // this includes all parent process copies in all clusters
[408]1568    if( parent_process_cxy == local_cxy )   // reference is local
1569    {
1570        vmm_set_cow( parent_process_ptr );
1571    }
1572    else                                    // reference is remote
1573    {
1574        rpc_vmm_set_cow_client( parent_process_cxy,
1575                                parent_process_ptr );
1576    }
[1]1577
[625]1578    // set COW flag in DATA, ANON, REMOTE vsegs for child process VMM
[433]1579    vmm_set_cow( process );
1580 
[438]1581#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[433]1582cycle = (uint32_t)hal_get_cycles();
[438]1583if( DEBUG_PROCESS_MAKE_FORK < cycle )
[635]1584printk("\n[%s] thread[%x,%x] set COW in DATA / ANON / REMOTE for parent and child / cycle %d\n",
[583]1585__FUNCTION__, pid, trdid, cycle );
[433]1586#endif
[101]1587
[428]1588    // get extended pointers on parent children_root, children_lock and children_nr
1589    xptr_t children_root_xp = XPTR( parent_process_cxy , &parent_process_ptr->children_root );
1590    xptr_t children_lock_xp = XPTR( parent_process_cxy , &parent_process_ptr->children_lock );
1591    xptr_t children_nr_xp   = XPTR( parent_process_cxy , &parent_process_ptr->children_nr   );
[101]1592
[428]1593    // register process in parent children list
[564]1594    remote_queuelock_acquire( children_lock_xp );
[428]1595        xlist_add_last( children_root_xp , XPTR( local_cxy , &process->children_list ) );
1596        hal_remote_atomic_add( children_nr_xp , 1 );
[564]1597    remote_queuelock_release( children_lock_xp );
[204]1598
[408]1599    // return success
1600    *child_thread = thread;
1601    *child_pid    = new_pid;
[1]1602
[438]1603#if DEBUG_PROCESS_MAKE_FORK
[433]1604cycle = (uint32_t)hal_get_cycles();
[438]1605if( DEBUG_PROCESS_MAKE_FORK < cycle )
[593]1606printk("\n[%s] thread[%x,%x] exit / created process %x / cycle %d\n",
[583]1607__FUNCTION__, pid, trdid, new_pid, cycle );
[433]1608#endif
[428]1609
[408]1610    return 0;
1611
[416]1612}   // end process_make_fork()
[408]1613
1614/////////////////////////////////////////////////////
1615error_t process_make_exec( exec_info_t  * exec_info )
1616{
[457]1617    thread_t       * thread;                  // local pointer on this thread
1618    process_t      * process;                 // local pointer on this process
1619    pid_t            pid;                     // this process identifier
[610]1620    xptr_t           ref_xp;                  // reference process for this process
[441]1621        error_t          error;                   // value returned by called functions
[457]1622    char           * path;                    // path to .elf file
1623    xptr_t           file_xp;                 // extended pointer on .elf file descriptor
1624    uint32_t         file_id;                 // file index in fd_array
1625    uint32_t         args_nr;                 // number of main thread arguments
1626    char          ** args_pointers;           // array of pointers on main thread arguments
[446]1627
[625]1628    // get calling thread, process, pid and ref_xp
[457]1629    thread  = CURRENT_THREAD;
1630    process = thread->process;
1631    pid     = process->pid;
[610]1632    ref_xp  = process->ref_xp;
[408]1633
[457]1634        // get relevant infos from exec_info
1635        path          = exec_info->path;
1636    args_nr       = exec_info->args_nr;
1637    args_pointers = exec_info->args_pointers;
[408]1638
[438]1639#if DEBUG_PROCESS_MAKE_EXEC
[433]1640uint32_t cycle = (uint32_t)hal_get_cycles();
[635]1641if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[593]1642printk("\n[%s] thread[%x,%x] enters for %s / cycle %d\n",
[583]1643__FUNCTION__, pid, thread->trdid, path, cycle );
[433]1644#endif
[408]1645
[457]1646    // open the file identified by <path>
1647    file_xp = XPTR_NULL;
[564]1648    file_id = 0xFFFFFFFF;
[610]1649        error   = vfs_open( process->vfs_root_xp,
[457]1650                            path,
[610]1651                        ref_xp,
[457]1652                            O_RDONLY,
1653                            0,
1654                            &file_xp,
1655                            &file_id );
1656        if( error )
1657        {
1658                printk("\n[ERROR] in %s : failed to open file <%s>\n", __FUNCTION__ , path );
1659                return -1;
1660        }
1661
[446]1662#if (DEBUG_PROCESS_MAKE_EXEC & 1)
[469]1663cycle = (uint32_t)hal_get_cycles();
[635]1664if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[593]1665printk("\n[%s] thread[%x,%x] opened file <%s> / cycle %d\n",
[583]1666__FUNCTION__, pid, thread->trdid, path, cycle );
[446]1667#endif
1668
[457]1669    // delete all threads other than this main thread in all clusters
1670    process_sigaction( pid , DELETE_ALL_THREADS );
[446]1671
[469]1672#if (DEBUG_PROCESS_MAKE_EXEC & 1)
1673cycle = (uint32_t)hal_get_cycles();
[635]1674if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[625]1675printk("\n[%s] thread[%x,%x] deleted existing threads / cycle %d\n",
[583]1676__FUNCTION__, pid, thread->trdid, cycle );
[469]1677#endif
1678
[625]1679    // reset calling process VMM
1680    vmm_user_reset( process );
[446]1681
[457]1682#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
1683cycle = (uint32_t)hal_get_cycles();
[635]1684if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[625]1685printk("\n[%s] thread[%x,%x] completed VMM reset / cycle %d\n",
[583]1686__FUNCTION__, pid, thread->trdid, cycle );
[457]1687#endif
[408]1688
[625]1689    // re-initialize the VMM (args/envs vsegs registration)
1690    error = vmm_user_init( process );
[457]1691    if( error )
[416]1692    {
[457]1693        printk("\n[ERROR] in %s : cannot initialise VMM for %s\n", __FUNCTION__ , path );
1694        vfs_close( file_xp , file_id );
[623]1695        // FIXME restore old process VMM [AG]
[416]1696        return -1;
1697    }
[457]1698   
[438]1699#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
[433]1700cycle = (uint32_t)hal_get_cycles();
[635]1701if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[625]1702printk("\n[%s] thread[%x,%x] registered args/envs vsegs / cycle %d\n",
[583]1703__FUNCTION__, pid, thread->trdid, cycle );
[433]1704#endif
[428]1705
[457]1706    // register code & data vsegs as well as entry-point in process VMM,
[428]1707    // and register extended pointer on .elf file in process descriptor
[457]1708        error = elf_load_process( file_xp , process );
[441]1709    if( error )
[1]1710        {
[441]1711                printk("\n[ERROR] in %s : failed to access <%s>\n", __FUNCTION__ , path );
[457]1712        vfs_close( file_xp , file_id );
[623]1713        // FIXME restore old process VMM [AG]
[408]1714        return -1;
[1]1715        }
1716
[438]1717#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
[433]1718cycle = (uint32_t)hal_get_cycles();
[635]1719if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[625]1720printk("\n[%s] thread[%x,%x] registered code/data vsegs / cycle %d\n",
[583]1721__FUNCTION__, pid, thread->trdid, cycle );
[433]1722#endif
[1]1723
[457]1724    // update the existing main thread descriptor... and jump to user code
1725    error = thread_user_exec( (void *)process->vmm.entry_point,
1726                              args_nr,
1727                              args_pointers );
1728    if( error )
1729    {
[469]1730        printk("\n[ERROR] in %s : cannot update main thread for %s\n", __FUNCTION__ , path );
[457]1731        vfs_close( file_xp , file_id );
1732        // FIXME restore old process VMM
[408]1733        return -1;
[457]1734    }
[1]1735
[492]1736    assert( false, "we should not execute this code");
[457]1737 
[409]1738        return 0;
1739
1740}  // end process_make_exec()
1741
[457]1742
[623]1743////////////////////////////////////////////////
1744void process_zero_create( process_t   * process,
1745                          boot_info_t * info )
[428]1746{
[580]1747    error_t error;
1748    pid_t   pid;
[428]1749
[438]1750#if DEBUG_PROCESS_ZERO_CREATE
[433]1751uint32_t cycle = (uint32_t)hal_get_cycles();
[438]1752if( DEBUG_PROCESS_ZERO_CREATE < cycle )
[593]1753printk("\n[%s] enter / cluster %x / cycle %d\n",
[564]1754__FUNCTION__, local_cxy, cycle );
[433]1755#endif
[428]1756
[624]1757    // get pointer on VMM
1758    vmm_t * vmm = &process->vmm;
1759
[580]1760    // get PID from local cluster manager for this kernel process
1761    error = cluster_pid_alloc( process , &pid );
1762
1763    if( error || (LPID_FROM_PID( pid ) != 0) )
1764    {
1765        printk("\n[PANIC] in %s : cannot get valid PID in cluster %x / PID = %x\n",
1766        __FUNCTION__ , local_cxy, pid );
1767        hal_core_sleep();
1768    }
1769
[635]1770#if (DEBUG_PROCESS_ZERO_CREATE & 1)
1771if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1772printk("\n[%s] allocated pid %x in cluster %x\n", __FUNCTION__, pid, local_cxy );
1773#endif
1774
[428]1775    // initialize PID, REF_XP, PARENT_XP, and STATE
[580]1776    // the kernel process_zero is its own parent_process,
1777    // reference_process, and owner_process, and cannot be killed...
1778    process->pid        = pid;
[433]1779    process->ref_xp     = XPTR( local_cxy , process );
[443]1780    process->owner_xp   = XPTR( local_cxy , process );
[580]1781    process->parent_xp  = XPTR( local_cxy , process );
[433]1782    process->term_state = 0;
[428]1783
[635]1784    // initialize VSL as empty
[624]1785    vmm->vsegs_nr = 0;
1786        xlist_root_init( XPTR( local_cxy , &vmm->vsegs_root ) );
[623]1787
[635]1788#if (DEBUG_PROCESS_ZERO_CREATE & 1)
1789if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1790printk("\n[%s] initialized VSL empty in cluster %x\n", __FUNCTION__, local_cxy );
1791#endif
1792
1793    // initialize GPT as empty
[624]1794    error = hal_gpt_create( &vmm->gpt );
[635]1795
[624]1796    if( error ) 
1797    {
1798        printk("\n[PANIC] in %s : cannot create empty GPT\n", __FUNCTION__ );
1799        hal_core_sleep();
1800    }
1801
[635]1802#if (DEBUG_PROCESS_ZERO_CREATE & 1)
1803if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1804printk("\n[%s] initialized GPT empty in cluster %x\n", __FUNCTION__, local_cxy );
1805#endif
1806
[625]1807    // initialize VSL and GPT locks
[629]1808    remote_rwlock_init( XPTR( local_cxy , &vmm->vsl_lock ) , LOCK_VMM_VSL );
[624]1809   
1810    // create kernel vsegs in GPT and VSL, as required by the hardware architecture
1811    error = hal_vmm_kernel_init( info );
[635]1812
[624]1813    if( error ) 
1814    {
1815        printk("\n[PANIC] in %s : cannot create kernel vsegs in VMM\n", __FUNCTION__ );
1816        hal_core_sleep();
1817    }
1818
[635]1819#if (DEBUG_PROCESS_ZERO_CREATE & 1)
1820if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1821printk("\n[%s] initialized hal specific VMM in cluster%x\n", __FUNCTION__, local_cxy );
1822#endif
1823
[564]1824    // reset th_tbl[] array and associated fields
[428]1825    uint32_t i;
[564]1826    for( i = 0 ; i < CONFIG_THREADS_MAX_PER_CLUSTER ; i++ )
[428]1827        {
1828        process->th_tbl[i] = NULL;
1829    }
1830    process->th_nr  = 0;
[564]1831    rwlock_init( &process->th_lock , LOCK_PROCESS_THTBL );
[428]1832
[635]1833#if (DEBUG_PROCESS_ZERO_CREATE & 1)
1834if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1835printk("\n[%s] initialized th_tbl[] in cluster%x\n", __FUNCTION__, local_cxy );
1836#endif
[564]1837
[428]1838    // reset children list as empty
1839    xlist_root_init( XPTR( local_cxy , &process->children_root ) );
1840    process->children_nr = 0;
[564]1841    remote_queuelock_init( XPTR( local_cxy , &process->children_lock ),
1842                           LOCK_PROCESS_CHILDREN );
[428]1843
[635]1844#if (DEBUG_PROCESS_ZERO_CREATE & 1)
1845if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1846printk("\n[%s] initialized children list in cluster%x\n", __FUNCTION__, local_cxy );
1847#endif
1848
[580]1849    // register kernel process in cluster manager local_list
1850    cluster_process_local_link( process );
1851   
[428]1852        hal_fence();
1853
[438]1854#if DEBUG_PROCESS_ZERO_CREATE
[433]1855cycle = (uint32_t)hal_get_cycles();
[438]1856if( DEBUG_PROCESS_ZERO_CREATE < cycle )
[593]1857printk("\n[%s] exit / cluster %x / cycle %d\n",
[564]1858__FUNCTION__, local_cxy, cycle );
[433]1859#endif
[428]1860
[610]1861}  // end process_zero_create()
[428]1862
[564]1863////////////////////////////////
[485]1864void process_init_create( void )
[1]1865{
[428]1866    process_t      * process;       // local pointer on process descriptor
[409]1867    pid_t            pid;           // process_init identifier
1868    thread_t       * thread;        // local pointer on main thread
1869    pthread_attr_t   attr;          // main thread attributes
1870    lid_t            lid;           // selected core local index for main thread
[457]1871    xptr_t           file_xp;       // extended pointer on .elf file descriptor
1872    uint32_t         file_id;       // file index in fd_array
[409]1873    error_t          error;
[1]1874
[438]1875#if DEBUG_PROCESS_INIT_CREATE
[610]1876thread_t * this = CURRENT_THREAD;
[433]1877uint32_t cycle = (uint32_t)hal_get_cycles();
[438]1878if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]1879printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1880__FUNCTION__, this->process->pid, this->trdid, cycle );
[433]1881#endif
[1]1882
[408]1883    // allocates memory for process descriptor from local cluster
1884        process = process_alloc(); 
[625]1885    if( process == NULL )
1886    {
1887        printk("\n[PANIC] in %s : cannot allocate process\n", __FUNCTION__ );
1888        hal_core_sleep();
1889    }
[101]1890
[610]1891    // set the CWD and VFS_ROOT fields in process descriptor
1892    process->cwd_xp      = process_zero.vfs_root_xp;
1893    process->vfs_root_xp = process_zero.vfs_root_xp;
1894
[409]1895    // get PID from local cluster
[416]1896    error = cluster_pid_alloc( process , &pid );
[625]1897    if( error ) 
1898    {
1899        printk("\n[PANIC] in %s : cannot allocate PID\n", __FUNCTION__ );
1900        hal_core_sleep();
1901    }
1902    if( pid != 1 ) 
1903    {
1904        printk("\n[PANIC] in %s : process PID must be 0x1\n", __FUNCTION__ );
1905        hal_core_sleep();
1906    }
[408]1907
[409]1908    // initialize process descriptor / parent is local process_zero
[625]1909    error = process_reference_init( process,
1910                                    pid,
1911                                    XPTR( local_cxy , &process_zero ) ); 
1912    if( error )
1913    {
1914        printk("\n[PANIC] in %s : cannot initialize process\n", __FUNCTION__ );
1915        hal_core_sleep();
1916    }
[408]1917
[564]1918#if(DEBUG_PROCESS_INIT_CREATE & 1)
1919if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]1920printk("\n[%s] thread[%x,%x] initialized process descriptor\n",
1921__FUNCTION__, this->process->pid, this->trdid );
[564]1922#endif
1923
[457]1924    // open the file identified by CONFIG_PROCESS_INIT_PATH
1925    file_xp = XPTR_NULL;
1926    file_id = -1;
[610]1927        error   = vfs_open( process->vfs_root_xp,
[457]1928                            CONFIG_PROCESS_INIT_PATH,
[610]1929                        XPTR( local_cxy , process ),
[457]1930                            O_RDONLY,
1931                            0,
1932                            &file_xp,
1933                            &file_id );
[625]1934    if( error )
1935    {
1936        printk("\n[PANIC] in %s : cannot open file <%s>\n",
1937         __FUNCTION__, CONFIG_PROCESS_INIT_PATH  );
1938        hal_core_sleep();
1939    }
[457]1940
[564]1941#if(DEBUG_PROCESS_INIT_CREATE & 1)
1942if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]1943printk("\n[%s] thread[%x,%x] open .elf file decriptor\n",
1944__FUNCTION__, this->process->pid, this->trdid );
[564]1945#endif
1946
[625]1947    // register "code" and "data" vsegs as well as entry-point
[409]1948    // in process VMM, using information contained in the elf file.
[457]1949        error = elf_load_process( file_xp , process );
[101]1950
[625]1951    if( error ) 
1952    {
1953        printk("\n[PANIC] in %s : cannot access file <%s>\n",
1954         __FUNCTION__, CONFIG_PROCESS_INIT_PATH  );
1955        hal_core_sleep();
1956    }
[457]1957
[625]1958
[564]1959#if(DEBUG_PROCESS_INIT_CREATE & 1)
1960if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]1961printk("\n[%s] thread[%x,%x] registered code/data vsegs in VMM\n",
1962__FUNCTION__, this->process->pid, this->trdid );
[564]1963#endif
1964
[625]1965#if (DEBUG_PROCESS_INIT_CREATE & 1)
[635]1966hal_vmm_display( XPTR( local_cxy , process ) , true );
[625]1967#endif
1968
[428]1969    // get extended pointers on process_zero children_root, children_lock
1970    xptr_t children_root_xp = XPTR( local_cxy , &process_zero.children_root );
1971    xptr_t children_lock_xp = XPTR( local_cxy , &process_zero.children_lock );
1972
[564]1973    // take lock protecting kernel process children list
1974    remote_queuelock_acquire( children_lock_xp );
1975
[428]1976    // register process INIT in parent local process_zero
1977        xlist_add_last( children_root_xp , XPTR( local_cxy , &process->children_list ) );
1978        hal_atomic_add( &process_zero.children_nr , 1 );
1979
[564]1980    // release lock protecting kernel process children list
1981    remote_queuelock_release( children_lock_xp );
1982
1983#if(DEBUG_PROCESS_INIT_CREATE & 1)
1984if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]1985printk("\n[%s] thread[%x,%x] registered init process in parent\n",
1986__FUNCTION__, this->process->pid, this->trdid );
[564]1987#endif
1988
[409]1989    // select a core in local cluster to execute the main thread
[637]1990    lid  = cluster_select_local_core( local_cxy );
[409]1991
1992    // initialize pthread attributes for main thread
1993    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
1994    attr.cxy        = local_cxy;
1995    attr.lid        = lid;
1996
1997    // create and initialize thread descriptor
1998        error = thread_user_create( pid,
1999                                (void *)process->vmm.entry_point,
2000                                NULL,
2001                                &attr,
2002                                &thread );
[1]2003
[625]2004    if( error )
2005    {
2006        printk("\n[PANIC] in %s : cannot create main thread\n", __FUNCTION__  );
2007        hal_core_sleep();
2008    }
2009    if( thread->trdid != 0 )
2010    {
2011        printk("\n[PANIC] in %s : bad main thread trdid\n", __FUNCTION__  );
2012        hal_core_sleep();
2013    }
[428]2014
[564]2015#if(DEBUG_PROCESS_INIT_CREATE & 1)
2016if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]2017printk("\n[%s] thread[%x,%x] created main thread\n",
2018__FUNCTION__, this->process->pid, this->trdid );
[564]2019#endif
2020
[409]2021    // activate thread
2022        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_GLOBAL );
2023
[124]2024    hal_fence();
[1]2025
[438]2026#if DEBUG_PROCESS_INIT_CREATE
[433]2027cycle = (uint32_t)hal_get_cycles();
[438]2028if( DEBUG_PROCESS_INIT_CREATE < cycle )
[610]2029printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2030__FUNCTION__, this->process->pid, this->trdid, cycle );
[433]2031#endif
[409]2032
[204]2033}  // end process_init_create()
2034
[428]2035/////////////////////////////////////////
2036void process_display( xptr_t process_xp )
2037{
2038    process_t   * process_ptr;
2039    cxy_t         process_cxy;
[443]2040
[428]2041    xptr_t        parent_xp;       // extended pointer on parent process
2042    process_t   * parent_ptr;
2043    cxy_t         parent_cxy;
2044
[443]2045    xptr_t        owner_xp;        // extended pointer on owner process
2046    process_t   * owner_ptr;
2047    cxy_t         owner_cxy;
2048
[428]2049    pid_t         pid;
2050    pid_t         ppid;
[580]2051    lpid_t        lpid;
[428]2052    uint32_t      state;
2053    uint32_t      th_nr;
2054
[443]2055    xptr_t        txt_file_xp;     // extended pointer on TXT_RX file descriptor
2056    xptr_t        txt_chdev_xp;    // extended pointer on TXT_RX chdev
2057    chdev_t     * txt_chdev_ptr;
2058    cxy_t         txt_chdev_cxy;
2059    xptr_t        txt_owner_xp;    // extended pointer on TXT owner process
[428]2060
2061    xptr_t        elf_file_xp;     // extended pointer on .elf file
2062    cxy_t         elf_file_cxy;
2063    vfs_file_t  * elf_file_ptr;
2064    vfs_inode_t * elf_inode_ptr;   // local pointer on .elf inode
2065
2066    char          txt_name[CONFIG_VFS_MAX_NAME_LENGTH];
2067    char          elf_name[CONFIG_VFS_MAX_NAME_LENGTH];
2068
2069    // get cluster and local pointer on process
2070    process_ptr = GET_PTR( process_xp );
2071    process_cxy = GET_CXY( process_xp );
2072
[580]2073    // get process PID, LPID, and state
[564]2074    pid   = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[580]2075    lpid  = LPID_FROM_PID( pid );
[564]2076    state = hal_remote_l32( XPTR( process_cxy , &process_ptr->term_state ) );
[428]2077
[580]2078    // get process PPID
[564]2079    parent_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->parent_xp ) );
[428]2080    parent_cxy = GET_CXY( parent_xp );
2081    parent_ptr = GET_PTR( parent_xp );
[564]2082    ppid       = hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
[428]2083
2084    // get number of threads
[564]2085    th_nr      = hal_remote_l32( XPTR( process_cxy , &process_ptr->th_nr ) );
[428]2086
[443]2087    // get pointers on owner process descriptor
[564]2088    owner_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) );
[443]2089    owner_cxy = GET_CXY( owner_xp );
2090    owner_ptr = GET_PTR( owner_xp );
[428]2091
[580]2092    // get process TXT name and .elf name
2093    if( lpid )                                   // user process
2094    {
[443]2095
[580]2096        // get extended pointer on file descriptor associated to TXT_RX
2097        txt_file_xp = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->fd_array.array[0] ) );
[428]2098
[580]2099        assert( (txt_file_xp != XPTR_NULL) ,
[624]2100        "process must be attached to one TXT terminal" ); 
[443]2101
[580]2102        // get TXT_RX chdev pointers
2103        txt_chdev_xp  = chdev_from_file( txt_file_xp );
2104        txt_chdev_cxy = GET_CXY( txt_chdev_xp );
2105        txt_chdev_ptr = GET_PTR( txt_chdev_xp );
2106
2107        // get TXT_RX name and ownership
2108        hal_remote_strcpy( XPTR( local_cxy , txt_name ) ,
2109                           XPTR( txt_chdev_cxy , txt_chdev_ptr->name ) );
[428]2110   
[580]2111        txt_owner_xp = (xptr_t)hal_remote_l64( XPTR( txt_chdev_cxy, 
2112                                                     &txt_chdev_ptr->ext.txt.owner_xp ) );
[428]2113
[580]2114        // get process .elf name
2115        elf_file_xp   = hal_remote_l64( XPTR( process_cxy , &process_ptr->vfs_bin_xp ) );
2116        elf_file_cxy  = GET_CXY( elf_file_xp );
2117        elf_file_ptr  = GET_PTR( elf_file_xp );
2118        elf_inode_ptr = hal_remote_lpt( XPTR( elf_file_cxy , &elf_file_ptr->inode ) );
2119        vfs_inode_get_name( XPTR( elf_file_cxy , elf_inode_ptr ) , elf_name );
2120    }
2121    else                                         // kernel process_zero
2122    {
2123        // TXT name and .elf name are not registered in kernel process_zero
2124        strcpy( txt_name , "txt0_rx" );
2125        txt_owner_xp = process_xp; 
2126        strcpy( elf_name , "kernel.elf" );
2127    }
2128
[428]2129    // display process info
[443]2130    if( txt_owner_xp == process_xp )
[428]2131    {
[581]2132        nolock_printk("PID %X | %s (FG) | %X | PPID %X | TS %X | %d | %s\n", 
2133        pid, txt_name, process_ptr, ppid, state, th_nr, elf_name );
[428]2134    }
2135    else
2136    {
[581]2137        nolock_printk("PID %X | %s (BG) | %X | PPID %X | TS %X | %d | %s\n", 
2138        pid, txt_name, process_ptr, ppid, state, th_nr, elf_name );
[428]2139    }
2140}  // end process_display()
2141
2142
2143////////////////////////////////////////////////////////////////////////////////////////
2144//     Terminals related functions
2145////////////////////////////////////////////////////////////////////////////////////////
2146
[581]2147//////////////////////////////////
[485]2148uint32_t process_txt_alloc( void )
[428]2149{
2150    uint32_t  index;       // TXT terminal index
2151    xptr_t    chdev_xp;    // extended pointer on TXT_RX chdev
2152    chdev_t * chdev_ptr;   // local pointer on TXT_RX chdev
2153    cxy_t     chdev_cxy;   // TXT_RX chdev cluster
2154    xptr_t    root_xp;     // extended pointer on owner field in chdev
2155
2156    // scan the user TXT_RX chdevs (TXT0 is reserved for kernel)
2157    for( index = 1 ; index < LOCAL_CLUSTER->nb_txt_channels ; index ++ )
2158    {
2159        // get pointers on TXT_RX[index]
2160        chdev_xp  = chdev_dir.txt_rx[index];
2161        chdev_cxy = GET_CXY( chdev_xp );
2162        chdev_ptr = GET_PTR( chdev_xp );
2163
2164        // get extended pointer on root of attached process
2165        root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
2166
2167        // return free TXT index if found
2168        if( xlist_is_empty( root_xp ) ) return index; 
2169    }
2170
[492]2171    assert( false , "no free TXT terminal found" );
[428]2172
2173    return -1;
2174
2175} // end process_txt_alloc()
2176
2177/////////////////////////////////////////////
2178void process_txt_attach( process_t * process,
2179                         uint32_t    txt_id )
2180{
2181    xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
2182    cxy_t       chdev_cxy;    // TXT_RX chdev cluster
2183    chdev_t *   chdev_ptr;    // local pointer on TXT_RX chdev
2184    xptr_t      root_xp;      // extended pointer on list root in chdev
2185    xptr_t      lock_xp;      // extended pointer on list lock in chdev
2186
[564]2187// check process is in owner cluster
2188assert( (CXY_FROM_PID( process->pid ) == local_cxy) ,
2189"process descriptor not in owner cluster" );
[428]2190
[564]2191// check terminal index
2192assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
2193"illegal TXT terminal index" );
[428]2194
2195    // get pointers on TXT_RX[txt_id] chdev
2196    chdev_xp  = chdev_dir.txt_rx[txt_id];
2197    chdev_cxy = GET_CXY( chdev_xp );
2198    chdev_ptr = GET_PTR( chdev_xp );
2199
2200    // get extended pointer on root & lock of attached process list
2201    root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
2202    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
2203
[564]2204    // get lock protecting list of processes attached to TXT
2205    remote_busylock_acquire( lock_xp );
2206
[428]2207    // insert process in attached process list
2208    xlist_add_last( root_xp , XPTR( local_cxy , &process->txt_list ) );
2209
[564]2210    // release lock protecting list of processes attached to TXT
2211    remote_busylock_release( lock_xp );
2212
[446]2213#if DEBUG_PROCESS_TXT
[610]2214thread_t * this = CURRENT_THREAD;
[457]2215uint32_t cycle = (uint32_t)hal_get_cycles();
[446]2216if( DEBUG_PROCESS_TXT < cycle )
[610]2217printk("\n[%s] thread[%x,%x] attached process %x to TXT %d / cycle %d\n",
2218__FUNCTION__, this->process->pid, this->trdid, process->pid, txt_id , cycle );
[433]2219#endif
[428]2220
2221} // end process_txt_attach()
2222
[436]2223/////////////////////////////////////////////
2224void process_txt_detach( xptr_t  process_xp )
[428]2225{
[436]2226    process_t * process_ptr;  // local pointer on process in owner cluster
2227    cxy_t       process_cxy;  // process owner cluster
2228    pid_t       process_pid;  // process identifier
2229    xptr_t      file_xp;      // extended pointer on stdin file
[428]2230    xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
2231    cxy_t       chdev_cxy;    // TXT_RX chdev cluster
2232    chdev_t *   chdev_ptr;    // local pointer on TXT_RX chdev
2233    xptr_t      lock_xp;      // extended pointer on list lock in chdev
2234
[436]2235    // get process cluster, local pointer, and PID
2236    process_cxy = GET_CXY( process_xp );
2237    process_ptr = GET_PTR( process_xp );
[564]2238    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[436]2239
[564]2240// check process descriptor in owner cluster
2241assert( (CXY_FROM_PID( process_pid ) == process_cxy ) ,
2242"process descriptor not in owner cluster" );
[436]2243
2244    // release TXT ownership (does nothing if not TXT owner)
2245    process_txt_transfer_ownership( process_xp );
[428]2246
[625]2247    // get extended pointer on process stdin pseudo file
[564]2248    file_xp = (xptr_t)hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[436]2249
2250    // get pointers on TXT_RX chdev
2251    chdev_xp  = chdev_from_file( file_xp );
[428]2252    chdev_cxy = GET_CXY( chdev_xp );
2253    chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
2254
[436]2255    // get extended pointer on lock protecting attached process list
[428]2256    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
2257
[564]2258    // get lock protecting list of processes attached to TXT
2259    remote_busylock_acquire( lock_xp );
2260
[428]2261    // unlink process from attached process list
[436]2262    xlist_unlink( XPTR( process_cxy , &process_ptr->txt_list ) );
2263
[564]2264    // release lock protecting list of processes attached to TXT
2265    remote_busylock_release( lock_xp );
2266
[446]2267#if DEBUG_PROCESS_TXT
[610]2268thread_t * this = CURRENT_THREAD;
[457]2269uint32_t cycle  = (uint32_t)hal_get_cycles();
[564]2270uint32_t txt_id = hal_remote_l32( XPTR( chdev_cxy , &chdev_ptr->channel ) );
[446]2271if( DEBUG_PROCESS_TXT < cycle )
[625]2272printk("\n[%s] thread[%x,%x] detached process %x from TXT%d / cycle %d\n",
[610]2273__FUNCTION__, this->process->pid, this->trdid, process_pid, txt_id, cycle );
[433]2274#endif
[428]2275
2276} // end process_txt_detach()
2277
2278///////////////////////////////////////////////////
2279void process_txt_set_ownership( xptr_t process_xp )
2280{
2281    process_t * process_ptr;
2282    cxy_t       process_cxy;
[436]2283    pid_t       process_pid;
[428]2284    xptr_t      file_xp;
2285    xptr_t      txt_xp;     
2286    chdev_t   * txt_ptr;
2287    cxy_t       txt_cxy;
2288
[436]2289    // get pointers on process in owner cluster
[428]2290    process_cxy = GET_CXY( process_xp );
[435]2291    process_ptr = GET_PTR( process_xp );
[564]2292    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[436]2293
2294    // check owner cluster
[492]2295    assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
[624]2296    "process descriptor not in owner cluster" );
[436]2297
[428]2298    // get extended pointer on stdin pseudo file
[564]2299    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[428]2300
2301    // get pointers on TXT chdev
2302    txt_xp  = chdev_from_file( file_xp );
2303    txt_cxy = GET_CXY( txt_xp );
[435]2304    txt_ptr = GET_PTR( txt_xp );
[428]2305
2306    // set owner field in TXT chdev
[564]2307    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , process_xp );
[428]2308
[446]2309#if DEBUG_PROCESS_TXT
[610]2310thread_t * this = CURRENT_THREAD;
[457]2311uint32_t cycle  = (uint32_t)hal_get_cycles();
[564]2312uint32_t txt_id = hal_remote_l32( XPTR( txt_cxy , &txt_ptr->channel ) );
[446]2313if( DEBUG_PROCESS_TXT < cycle )
[625]2314printk("\n[%s] thread[%x,%x] give TXT%d ownership to process %x / cycle %d\n",
[610]2315__FUNCTION__, this->process->pid, this->trdid, txt_id, process_pid, cycle );
[436]2316#endif
2317
[428]2318}  // end process_txt_set ownership()
2319
[436]2320////////////////////////////////////////////////////////
2321void process_txt_transfer_ownership( xptr_t process_xp )
[428]2322{
[436]2323    process_t * process_ptr;     // local pointer on process releasing ownership
2324    cxy_t       process_cxy;     // process cluster
2325    pid_t       process_pid;     // process identifier
[428]2326    xptr_t      file_xp;         // extended pointer on TXT_RX pseudo file
2327    xptr_t      txt_xp;          // extended pointer on TXT_RX chdev
[433]2328    chdev_t   * txt_ptr;         // local pointer on TXT_RX chdev
2329    cxy_t       txt_cxy;         // cluster of TXT_RX chdev
2330    uint32_t    txt_id;          // TXT_RX channel
[428]2331    xptr_t      owner_xp;        // extended pointer on current TXT_RX owner
2332    xptr_t      root_xp;         // extended pointer on root of attached process list
[436]2333    xptr_t      lock_xp;         // extended pointer on lock protecting attached process list
[428]2334    xptr_t      iter_xp;         // iterator for xlist
2335    xptr_t      current_xp;      // extended pointer on current process
[625]2336    bool_t      found;
[428]2337
[457]2338#if DEBUG_PROCESS_TXT
[610]2339thread_t * this  = CURRENT_THREAD;
2340uint32_t   cycle;
[457]2341#endif
2342
[625]2343    // get pointers on target process
[428]2344    process_cxy = GET_CXY( process_xp );
[435]2345    process_ptr = GET_PTR( process_xp );
[564]2346    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[436]2347
[625]2348// check owner cluster
2349assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
2350"process descriptor not in owner cluster" );
[436]2351
[428]2352    // get extended pointer on stdin pseudo file
[564]2353    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[428]2354
2355    // get pointers on TXT chdev
2356    txt_xp  = chdev_from_file( file_xp );
2357    txt_cxy = GET_CXY( txt_xp );
[433]2358    txt_ptr = GET_PTR( txt_xp );
[428]2359
[625]2360    // get relevant infos from chdev descriptor
[564]2361    owner_xp = hal_remote_l64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) );
[625]2362    txt_id   = hal_remote_l32( XPTR( txt_cxy , &txt_ptr->channel ) );
[428]2363
[625]2364    // transfer ownership only if target process is the TXT owner
[436]2365    if( (owner_xp == process_xp) && (txt_id > 0) ) 
[428]2366    {
[436]2367        // get extended pointers on root and lock of attached processes list
2368        root_xp = XPTR( txt_cxy , &txt_ptr->ext.txt.root );
2369        lock_xp = XPTR( txt_cxy , &txt_ptr->ext.txt.lock );
[428]2370
[625]2371        if( process_get_ppid( process_xp ) != 1 )       // target process is not KSH
2372        {
2373            // get lock
2374            remote_busylock_acquire( lock_xp );
[436]2375
2376            // scan attached process list to find KSH process
[625]2377            found = false;
2378            for( iter_xp = hal_remote_l64( root_xp ) ;
2379                 (iter_xp != root_xp) && (found == false) ;
2380                 iter_xp = hal_remote_l64( iter_xp ) )
[436]2381            {
[625]2382                current_xp = XLIST_ELEMENT( iter_xp , process_t , txt_list );
[435]2383
[436]2384                if( process_get_ppid( current_xp ) == 1 )  // current is KSH
2385                {
2386                    // set owner field in TXT chdev
[564]2387                    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , current_xp );
[436]2388
[446]2389#if DEBUG_PROCESS_TXT
[610]2390cycle = (uint32_t)hal_get_cycles();
[446]2391if( DEBUG_PROCESS_TXT < cycle )
[625]2392printk("\n[%s] thread[%x,%x] transfered TXT%d ownership to KSH / cycle %d\n",
2393__FUNCTION__, this->process->pid, this->trdid, txt_id, cycle );
[436]2394#endif
[625]2395                    found = true;
[436]2396                }
2397            }
[625]2398
[436]2399            // release lock
[564]2400            remote_busylock_release( lock_xp );
[436]2401
[625]2402// It must exist a KSH process for each user TXT channel
2403assert( (found == true), "KSH process not found for TXT%d", txt_id );
[436]2404
2405        }
[625]2406        else                                           // target process is KSH
[436]2407        {
[625]2408            // get lock
2409            remote_busylock_acquire( lock_xp );
2410
[436]2411            // scan attached process list to find another process
[625]2412            found = false;
2413            for( iter_xp = hal_remote_l64( root_xp ) ;
2414                 (iter_xp != root_xp) && (found == false) ;
2415                 iter_xp = hal_remote_l64( iter_xp ) )
[428]2416            {
[436]2417                current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2418
2419                if( current_xp != process_xp )            // current is not KSH
2420                {
2421                    // set owner field in TXT chdev
[564]2422                    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , current_xp );
[436]2423
[446]2424#if DEBUG_PROCESS_TXT
[610]2425cycle  = (uint32_t)hal_get_cycles();
[625]2426cxy_t       current_cxy = GET_CXY( current_xp );
2427process_t * current_ptr = GET_PTR( current_xp );
2428uint32_t    new_pid     = hal_remote_l32( XPTR( current_cxy , &current_ptr->pid ) );
[446]2429if( DEBUG_PROCESS_TXT < cycle )
[625]2430printk("\n[%s] thread[%x,%x] transfered TXT%d ownership to process %x / cycle %d\n",
[610]2431__FUNCTION__,this->process->pid, this->trdid, txt_id, new_pid, cycle );
[436]2432#endif
[625]2433                    found = true;
[436]2434                }
[428]2435            }
[436]2436
2437            // release lock
[564]2438            remote_busylock_release( lock_xp );
[436]2439
2440            // no more owner for TXT if no other process found
[625]2441            if( found == false )
2442            {
2443                // set owner field in TXT chdev
2444                hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , XPTR_NULL );
[436]2445
[446]2446#if DEBUG_PROCESS_TXT
[436]2447cycle = (uint32_t)hal_get_cycles();
[446]2448if( DEBUG_PROCESS_TXT < cycle )
[625]2449printk("\n[%s] thread[%x,%x] released TXT%d (no attached process) / cycle %d\n",
[610]2450__FUNCTION__, this->process->pid, this->trdid, txt_id, cycle );
[436]2451#endif
[625]2452            }
[428]2453        }
[436]2454    }
2455    else
2456    {
[433]2457
[446]2458#if DEBUG_PROCESS_TXT
[436]2459cycle = (uint32_t)hal_get_cycles();
[446]2460if( DEBUG_PROCESS_TXT < cycle )
[625]2461printk("\n[%s] thread[%x,%x] does nothing for process %x (not TXT owner) / cycle %d\n",
2462__FUNCTION__, this->process->pid, this->trdid, process_pid, cycle );
[436]2463#endif
2464
[428]2465    }
[625]2466
[436]2467}  // end process_txt_transfer_ownership()
[428]2468
2469
[564]2470////////////////////////////////////////////////
2471bool_t process_txt_is_owner( xptr_t process_xp )
[457]2472{
2473    // get local pointer and cluster of process in owner cluster
2474    cxy_t       process_cxy = GET_CXY( process_xp );
2475    process_t * process_ptr = GET_PTR( process_xp );
2476
[564]2477// check calling thread execute in target process owner cluster
2478pid_t process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
2479assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
[624]2480"process descriptor not in owner cluster" );
[457]2481
2482    // get extended pointer on stdin pseudo file
[564]2483    xptr_t file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[457]2484
2485    // get pointers on TXT chdev
2486    xptr_t    txt_xp  = chdev_from_file( file_xp );
2487    cxy_t     txt_cxy = GET_CXY( txt_xp );
2488    chdev_t * txt_ptr = GET_PTR( txt_xp );
2489
2490    // get extended pointer on TXT_RX owner process
[564]2491    xptr_t owner_xp = hal_remote_l64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) );
[457]2492
2493    return (process_xp == owner_xp);
2494
2495}   // end process_txt_is_owner()
2496
[436]2497////////////////////////////////////////////////     
2498xptr_t process_txt_get_owner( uint32_t channel )
[435]2499{
2500    xptr_t      txt_rx_xp  = chdev_dir.txt_rx[channel];
2501    cxy_t       txt_rx_cxy = GET_CXY( txt_rx_xp );
2502    chdev_t *   txt_rx_ptr = GET_PTR( txt_rx_xp );
2503
[564]2504    return (xptr_t)hal_remote_l64( XPTR( txt_rx_cxy , &txt_rx_ptr->ext.txt.owner_xp ) );
[435]2505
[457]2506}  // end process_txt_get_owner()
2507
[435]2508///////////////////////////////////////////
2509void process_txt_display( uint32_t txt_id )
2510{
2511    xptr_t      chdev_xp;
2512    cxy_t       chdev_cxy;
2513    chdev_t   * chdev_ptr;
2514    xptr_t      root_xp;
2515    xptr_t      lock_xp;
2516    xptr_t      current_xp;
2517    xptr_t      iter_xp;
[443]2518    cxy_t       txt0_cxy;
2519    chdev_t   * txt0_ptr;
2520    xptr_t      txt0_xp;
2521    xptr_t      txt0_lock_xp;
2522   
[435]2523    assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
[492]2524    "illegal TXT terminal index" );
[435]2525
[443]2526    // get pointers on TXT0 chdev
2527    txt0_xp  = chdev_dir.txt_tx[0];
2528    txt0_cxy = GET_CXY( txt0_xp );
2529    txt0_ptr = GET_PTR( txt0_xp );
2530
2531    // get extended pointer on TXT0 lock
2532    txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
2533
[435]2534    // get pointers on TXT_RX[txt_id] chdev
2535    chdev_xp  = chdev_dir.txt_rx[txt_id];
2536    chdev_cxy = GET_CXY( chdev_xp );
2537    chdev_ptr = GET_PTR( chdev_xp );
2538
2539    // get extended pointer on root & lock of attached process list
2540    root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
2541    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
2542
[443]2543    // get lock on attached process list
[564]2544    remote_busylock_acquire( lock_xp );
[443]2545
2546    // get TXT0 lock in busy waiting mode
[564]2547    remote_busylock_acquire( txt0_lock_xp );
[443]2548
[435]2549    // display header
[443]2550    nolock_printk("\n***** processes attached to TXT_%d / cycle %d\n",
2551    txt_id , (uint32_t)hal_get_cycles() );
[435]2552
[436]2553    // scan attached process list
[435]2554    XLIST_FOREACH( root_xp , iter_xp )
2555    {
2556        current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2557        process_display( current_xp );
2558    }
2559
[443]2560    // release TXT0 lock in busy waiting mode
[564]2561    remote_busylock_release( txt0_lock_xp );
[443]2562
2563    // release lock on attached process list
[564]2564    remote_busylock_release( lock_xp );
[435]2565
2566}  // end process_txt_display
Note: See TracBrowser for help on using the repository browser.