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

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

Cosmetic: improve debug.

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