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

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

Complete restructuration of kernel locks.

File size: 76.8 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
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 )
[457]125printk("\n[DBG] %s : thread %x in process %x enter to initalialize process %x / cycle %d\n",
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 )
[457]144printk("\n[DBG] %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.
[457]152    if( (pid == 1) || (parent_pid == 1)) // INIT or KSH process
[408]153    {
[457]154        // allocate 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 )
164printk("\n[DBG] %s : thread %x in process %x / process %x attached to TXT%d / cycle %d\n", 
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 )
[457]185printk("\n[DBG] %s : thread %x in process %x / stdin open for process %x / cycle %d\n", 
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 )
[457]203printk("\n[DBG] %s : thread %x in process %x / stdout open for process %x / cycle %d\n", 
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 )
[457]221printk("\n[DBG] %s : thread %x in process %x / stderr open for process %x / cycle %d\n", 
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 )
[564]262printk("\n[DBG] %s : thread %x in process %x / set fd_array for process %x / cycle %d\n", 
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 )
[564]303printk("\n[DBG] %s : thread %x in process %x exit for process %x / cycle %d\n", 
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 )
[564]330printk("\n[DBG] %s : thread %x in process %x enter for process %x / cycle %d\n",
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 )
[564]385printk("\n[DBG] %s : thread %x in process %x exit for process %x / cycle %d\n",
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
[492]404        assert( (process->th_nr == 0) ,
[437]405    "process %x in cluster %x has still active 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 )
[564]410printk("\n[DBG] %s : thread %x in process %x enter for process %x in cluster %x / cycle %d\n",
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 )
[564]459printk("\n[DBG] %s : thread %x in process %x exit / process %x in cluster %x / cycle %d\n",
460__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, pid, local_cxy, cycle );
[433]461#endif
[428]462
[407]463}  // end process_destroy()
464
[409]465/////////////////////////////////////////////////
[527]466const char * process_action_str( process_sigactions_t action_type )
[409]467{
[527]468  switch ( action_type ) {
469  case BLOCK_ALL_THREADS:   return "BLOCK";
470  case UNBLOCK_ALL_THREADS: return "UNBLOCK";
471  case DELETE_ALL_THREADS:  return "DELETE";
472  default:                  return "undefined";
473  }
[409]474}
475
[435]476////////////////////////////////////////
477void process_sigaction( pid_t       pid,
[457]478                        uint32_t    type )
[409]479{
480    cxy_t              owner_cxy;         // owner cluster identifier
481    lpid_t             lpid;              // process index in owner cluster
482    cluster_t        * cluster;           // pointer on cluster manager
483    xptr_t             root_xp;           // extended pointer on root of copies
484    xptr_t             lock_xp;           // extended pointer on lock protecting copies
485    xptr_t             iter_xp;           // iterator on copies list
486    xptr_t             process_xp;        // extended pointer on process copy
487    cxy_t              process_cxy;       // process copy cluster identifier
[457]488    process_t        * process_ptr;       // local pointer on process copy
[436]489    reg_t              save_sr;           // for critical section
490    rpc_desc_t         rpc;               // shared RPC descriptor
[457]491    thread_t         * client;            // pointer on client thread
492    xptr_t             client_xp;         // extended pointer on client thread
493    process_t        * local;             // pointer on process copy in local cluster
494    uint32_t           remote_nr;         // number of remote process copies
[409]495
[457]496    client    = CURRENT_THREAD;
497    client_xp = XPTR( local_cxy , client );
498    local     = NULL;
499    remote_nr = 0;
[435]500
[564]501// check calling thread can yield
502assert( (client->busylocks == 0),
503"cannot yield : busylocks = %d\n", client->busylocks );
504
[438]505#if DEBUG_PROCESS_SIGACTION
[433]506uint32_t cycle = (uint32_t)hal_get_cycles();
[438]507if( DEBUG_PROCESS_SIGACTION < cycle )
[457]508printk("\n[DBG] %s : thread %x in process %x enter to %s process %x / cycle %d\n",
509__FUNCTION__ , client->trdid, client->process->pid,
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
[435]520    // get root of list of copies, lock, and number of copies 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
[416]524    // check action type
[457]525    assert( ((type == DELETE_ALL_THREADS ) ||
526             (type == BLOCK_ALL_THREADS )  ||
[492]527             (type == UNBLOCK_ALL_THREADS )), "illegal action type" );
[416]528             
529
[457]530    // The client thread send parallel RPCs to all remote clusters containing
[564]531    // target process copies, wait all responses, and then handles directly
532    // the threads in local cluster, when required.
[457]533    // The client thread allocates a - shared - RPC descriptor in the stack,
534    // because all parallel, non-blocking, server threads use the same input
535    // arguments, and use the shared RPC response field
[436]536
537    // mask IRQs
538    hal_disable_irq( &save_sr);
539
[457]540    // client thread blocks itself
541    thread_block( client_xp , THREAD_BLOCKED_RPC );
[436]542
[564]543    // take the lock protecting process copies
544    remote_queuelock_acquire( lock_xp );
[409]545
[436]546    // initialize shared RPC descriptor
[438]547    rpc.responses = 0;
548    rpc.blocking  = false;
549    rpc.index     = RPC_PROCESS_SIGACTION;
550    rpc.thread    = client;
551    rpc.lid       = client->core->lid;
[457]552    rpc.args[0]   = type;
[438]553    rpc.args[1]   = pid;
[436]554
[457]555    // scan list of process copies
556    // to send RPCs to remote copies
[409]557    XLIST_FOREACH( root_xp , iter_xp )
558    {
[457]559        // get extended pointers and cluster on process
[440]560        process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
561        process_cxy = GET_CXY( process_xp );
[457]562        process_ptr = GET_PTR( process_xp );
[440]563
[457]564        if( process_cxy == local_cxy )    // process is local
565        { 
566            local = process_ptr;
567        }
568        else                              // process is remote
569        {
570            // update number of remote process copies
571            remote_nr++;
572
573            // atomically increment responses counter
574            hal_atomic_add( (void *)&rpc.responses , 1 );
575
[438]576#if DEBUG_PROCESS_SIGACTION
577if( DEBUG_PROCESS_SIGACTION < cycle )
[457]578printk("\n[DBG] %s : thread %x in process %x handles remote process %x in cluster %x\n",
579__FUNCTION__, client->trdid, client->process->pid, pid , process_cxy );
[433]580#endif
[457]581            // call RPC in target cluster
582            rpc_process_sigaction_client( process_cxy , &rpc );
583        }
584    }  // end list of copies
585
[409]586    // release the lock protecting process copies
[564]587    remote_queuelock_release( lock_xp );
[409]588
[436]589    // restore IRQs
590    hal_restore_irq( save_sr);
[409]591
[457]592    // - if there is remote process copies, the client thread deschedules,
593    //   (it will be unblocked by the last RPC server thread).
594    // - if there is no remote copies, the client thread unblock itself.
595    if( remote_nr )
596    {
597        sched_yield("blocked on rpc_process_sigaction");
598    } 
599    else
600    {
601        thread_unblock( client_xp , THREAD_BLOCKED_RPC );
602    }
[409]603
[457]604    // handle the local process copy if required
605    if( local != NULL )
606    {
607
608#if DEBUG_PROCESS_SIGACTION
609if( DEBUG_PROCESS_SIGACTION < cycle )
610printk("\n[DBG] %s : thread %x in process %x handles local process %x in cluster %x\n",
611__FUNCTION__, client->trdid, client->process->pid, pid , local_cxy );
612#endif
613        if     (type == DELETE_ALL_THREADS  ) process_delete_threads ( local , client_xp ); 
614        else if(type == BLOCK_ALL_THREADS   ) process_block_threads  ( local , client_xp ); 
615        else if(type == UNBLOCK_ALL_THREADS ) process_unblock_threads( local );
616    }
617
[438]618#if DEBUG_PROCESS_SIGACTION
[433]619cycle = (uint32_t)hal_get_cycles();
[438]620if( DEBUG_PROCESS_SIGACTION < cycle )
[457]621printk("\n[DBG] %s : thread %x in process %x exit after %s process %x / cycle %d\n",
622__FUNCTION__, client->trdid, client->process->pid,
623process_action_str( type ), pid, cycle );
[433]624#endif
[416]625
[409]626}  // end process_sigaction()
627
[433]628/////////////////////////////////////////////////
[440]629void process_block_threads( process_t * process,
630                            xptr_t      client_xp )
[1]631{
[409]632    thread_t          * target;         // pointer on target thread
[433]633    thread_t          * this;           // pointer on calling thread
[564]634    uint32_t            ltid;           // index in process th_tbl[]
[436]635    cxy_t               owner_cxy;      // target process owner cluster
[409]636    uint32_t            count;          // requests counter
[436]637    volatile uint32_t   ack_count;      // scheduler acknowledge counter
[1]638
[416]639    // get calling thread pointer
[433]640    this = CURRENT_THREAD;
[407]641
[438]642#if DEBUG_PROCESS_SIGACTION
[564]643pid_t pid = process->pid;
[433]644uint32_t cycle = (uint32_t)hal_get_cycles();
[438]645if( DEBUG_PROCESS_SIGACTION < cycle )
[564]646printk("\n[DBG] %s : thread %x in process %x enter for process %x in cluster %x / cycle %d\n",
647__FUNCTION__, this->trdid, this->process->pid, pid, local_cxy , cycle );
[433]648#endif
[409]649
[564]650// check target process is an user process
651assert( ( process->pid != 0 ),
652"target process must be an user process" );
653
654    // get target process owner cluster
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
[436]662    for( ltid = 0 , count = 0 , ack_count = 0 ; count < process->th_nr ; ltid++ )
[1]663    {
[409]664        target = process->th_tbl[ltid];
[1]665
[436]666        if( target != NULL )                                 // thread exist
[1]667        {
668            count++;
[409]669
[440]670            // main thread and client thread should not be blocked
671            if( ((ltid != 0) || (owner_cxy != local_cxy)) &&         // not main thread
672                (client_xp) != XPTR( local_cxy , target ) )          // not client thread
[416]673            {
674                // set the global blocked bit in target thread descriptor.
[436]675                thread_block( XPTR( local_cxy , target ) , THREAD_BLOCKED_GLOBAL );
676 
677                // - if the calling thread and the target thread are on the same core,
678                //   we don't need confirmation from scheduler,
679                // - if the calling thread and the target thread are not running on the same
680                //   core, we ask the target scheduler to acknowlege the blocking
681                //   to be sure that the target thread is not running.
682           
683                if( this->core->lid != target->core->lid )
684                {
685                    // increment responses counter
686                    hal_atomic_add( (void*)&ack_count , 1 );
[409]687
[436]688                    // set FLAG_REQ_ACK and &ack_rsp_count in target descriptor
689                    thread_set_req_ack( target , (uint32_t *)&ack_count );
[409]690
[436]691                    // force scheduling on target thread
692                    dev_pic_send_ipi( local_cxy , target->core->lid );
693                }
[409]694            }
[1]695        }
[172]696    }
697
[428]698    // release lock protecting process th_tbl[]
[564]699    rwlock_rd_release( &process->th_lock );
[416]700
[564]701    // busy waiting acknowledges
702    // TODO this could be improved...
[409]703    while( 1 )
704    {
[436]705        // exit when all scheduler acknoledges received
706        if ( ack_count == 0 ) break;
[409]707   
708        // wait 1000 cycles before retry
709        hal_fixed_delay( 1000 );
710    }
[1]711
[438]712#if DEBUG_PROCESS_SIGACTION
[433]713cycle = (uint32_t)hal_get_cycles();
[438]714if( DEBUG_PROCESS_SIGACTION < cycle )
[564]715printk("\n[DBG] %s : thread %x in process %x exit for process %x in cluster %x / cycle %d\n",
716__FUNCTION__, this, this->process->pid, pid, local_cxy , cycle );
[433]717#endif
[409]718
[428]719}  // end process_block_threads()
[409]720
[440]721/////////////////////////////////////////////////
722void process_delete_threads( process_t * process,
723                             xptr_t      client_xp )
[409]724{
[433]725    thread_t          * this;          // pointer on calling thread
[440]726    thread_t          * target;        // local pointer on target thread
727    xptr_t              target_xp;     // extended pointer on target thread
728    cxy_t               owner_cxy;     // owner process cluster
[409]729    uint32_t            ltid;          // index in process th_tbl
[440]730    uint32_t            count;         // threads counter
[409]731
[433]732    // get calling thread pointer
733    this = CURRENT_THREAD;
[409]734
[440]735    // get target process owner cluster
736    owner_cxy = CXY_FROM_PID( process->pid );
737
[438]738#if DEBUG_PROCESS_SIGACTION
[564]739pid_t pid = process->pid;
[433]740uint32_t cycle = (uint32_t)hal_get_cycles();
[438]741if( DEBUG_PROCESS_SIGACTION < cycle )
[564]742printk("\n[DBG] %s : thread %x n process %x enter for process %x in cluster %x / cycle %d\n",
743__FUNCTION__, this->trdid, this->process->pid, pid, local_cxy , cycle );
[433]744#endif
745
[564]746// check target process is an user process
747assert( ( process->pid != 0 ),
748"target process must be an user process" );
749
[409]750    // get lock protecting process th_tbl[]
[564]751    rwlock_rd_acquire( &process->th_lock );
[409]752
[440]753    // loop on target process local threads                       
[416]754    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
[440]755    for( ltid = 0 , count = 0  ; count < process->th_nr ; ltid++ )
[1]756    {
[409]757        target = process->th_tbl[ltid];
[1]758
[440]759        if( target != NULL )    // valid thread 
[1]760        {
[416]761            count++;
[440]762            target_xp = XPTR( local_cxy , target );
[1]763
[564]764            // main thread and client thread should not be deleted
[440]765            if( ((ltid != 0) || (owner_cxy != local_cxy)) &&         // not main thread
766                (client_xp) != target_xp )                           // not client thread
767            {
768                // mark target thread for delete and block it
769                thread_delete( target_xp , process->pid , false );   // not forced
770            }
[409]771        }
772    }
[1]773
[428]774    // release lock protecting process th_tbl[]
[564]775    rwlock_rd_release( &process->th_lock );
[407]776
[438]777#if DEBUG_PROCESS_SIGACTION
[433]778cycle = (uint32_t)hal_get_cycles();
[438]779if( DEBUG_PROCESS_SIGACTION < cycle )
[564]780printk("\n[DBG] %s : thread %x in process %x exit for process %x in cluster %x / cycle %d\n",
781__FUNCTION__, this->trdid, this->process->pid, pid, local_cxy , cycle );
[433]782#endif
[407]783
[440]784}  // end process_delete_threads()
[409]785
[440]786///////////////////////////////////////////////////
787void process_unblock_threads( process_t * process )
[409]788{
[440]789    thread_t          * target;        // pointer on target thead
790    thread_t          * this;          // pointer on calling thread
[409]791    uint32_t            ltid;          // index in process th_tbl
[440]792    uint32_t            count;         // requests counter
[409]793
[440]794    // get calling thread pointer
795    this = CURRENT_THREAD;
796
[438]797#if DEBUG_PROCESS_SIGACTION
[564]798pid_t pid = process->pid;
[433]799uint32_t cycle = (uint32_t)hal_get_cycles();
[438]800if( DEBUG_PROCESS_SIGACTION < cycle )
[564]801printk("\n[DBG] %s : thread %x in process %x enter for process %x in cluster %x / cycle %d\n",
802__FUNCTION__, this->trdid, this->process->pid, pid, local_cxy , cycle );
[433]803#endif
804
[564]805// check target process is an user process
806assert( ( process->pid != 0 ),
807"target process must be an user process" );
808
[416]809    // get lock protecting process th_tbl[]
[564]810    rwlock_rd_acquire( &process->th_lock );
[416]811
[440]812    // loop on process threads to unblock all threads
[416]813    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
[440]814    for( ltid = 0 , count = 0 ; count < process->th_nr ; ltid++ )
[409]815    {
[416]816        target = process->th_tbl[ltid];
[409]817
[440]818        if( target != NULL )             // thread found
[409]819        {
820            count++;
[440]821
822            // reset the global blocked bit in target thread descriptor.
823            thread_unblock( XPTR( local_cxy , target ) , THREAD_BLOCKED_GLOBAL );
[1]824        }
825    }
826
[428]827    // release lock protecting process th_tbl[]
[564]828    rwlock_rd_release( &process->th_lock );
[407]829
[438]830#if DEBUG_PROCESS_SIGACTION
[433]831cycle = (uint32_t)hal_get_cycles();
[438]832if( DEBUG_PROCESS_SIGACTION < cycle )
[564]833printk("\n[DBG] %s : thread %x in process %x exit for process %x in cluster %x / cycle %d\n",
834__FUNCTION__, this->trdid, this->process->pid, pid, local_cxy, cycle );
[433]835#endif
[1]836
[440]837}  // end process_unblock_threads()
[407]838
[1]839///////////////////////////////////////////////
840process_t * process_get_local_copy( pid_t pid )
841{
842    error_t        error;
[172]843    process_t    * process_ptr;   // local pointer on process
[23]844    xptr_t         process_xp;    // extended pointer on process
[1]845
846    cluster_t * cluster = LOCAL_CLUSTER;
847
[564]848#if DEBUG_PROCESS_GET_LOCAL_COPY
849thread_t * this = CURRENT_THREAD;
850uint32_t cycle = (uint32_t)hal_get_cycles();
851if( DEBUG_PROCESS_GET_LOCAL_COPY < cycle )
852printk("\n[DBG] %s : thread %x in cluster %x enter for process %x in cluster %x / cycle %d\n",
853__FUNCTION__, this->trdid, this->process->pid, pid, local_cxy, cycle );
854#endif
855
[1]856    // get lock protecting local list of processes
[564]857    remote_queuelock_acquire( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
[1]858
859    // scan the local list of process descriptors to find the process
[23]860    xptr_t  iter;
861    bool_t  found = false;
862    XLIST_FOREACH( XPTR( local_cxy , &cluster->pmgr.local_root ) , iter )
[1]863    {
[23]864        process_xp  = XLIST_ELEMENT( iter , process_t , local_list );
[435]865        process_ptr = GET_PTR( process_xp );
[23]866        if( process_ptr->pid == pid )
[1]867        {
868            found = true;
869            break;
870        }
871    }
872
873    // release lock protecting local list of processes
[564]874    remote_queuelock_release( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
[1]875
[172]876    // allocate memory for a new local process descriptor
[440]877    // and initialise it from reference cluster if not found
[1]878    if( !found )
879    {
880        // get extended pointer on reference process descriptor
[23]881        xptr_t ref_xp = cluster_get_reference_process_from_pid( pid );
[1]882
[492]883        assert( (ref_xp != XPTR_NULL) , "illegal pid\n" );
[23]884
[1]885        // allocate memory for local process descriptor
[23]886        process_ptr = process_alloc();
[443]887
[23]888        if( process_ptr == NULL )  return NULL;
[1]889
890        // initialize local process descriptor copy
[23]891        error = process_copy_init( process_ptr , ref_xp );
[443]892
[1]893        if( error ) return NULL;
894    }
895
[440]896#if DEBUG_PROCESS_GET_LOCAL_COPY
[564]897cycle = (uint32_t)hal_get_cycles();
[440]898if( DEBUG_PROCESS_GET_LOCAL_COPY < cycle )
[564]899printk("\n[DBG] %s : thread %x in cluster %x exit in cluster %x / process %x / cycle %d\n",
900__FUNCTION__, this->trdid, this->process->pid, local_cxy, process_ptr, cycle );
[440]901#endif
902
[23]903    return process_ptr;
[1]904
[409]905}  // end process_get_local_copy()
906
[436]907////////////////////////////////////////////
908pid_t process_get_ppid( xptr_t  process_xp )
909{
910    cxy_t       process_cxy;
911    process_t * process_ptr;
912    xptr_t      parent_xp;
913    cxy_t       parent_cxy;
914    process_t * parent_ptr;
915
916    // get process cluster and local pointer
917    process_cxy = GET_CXY( process_xp );
918    process_ptr = GET_PTR( process_xp );
919
920    // get pointers on parent process
[564]921    parent_xp  = (xptr_t)hal_remote_l64( XPTR( process_cxy , &process_ptr->parent_xp ) );
[436]922    parent_cxy = GET_CXY( parent_xp );
923    parent_ptr = GET_PTR( parent_xp );
924
[564]925    return hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
[436]926}
927
[1]928//////////////////////////////////////////////////////////////////////////////////////////
929// File descriptor array related functions
930//////////////////////////////////////////////////////////////////////////////////////////
931
932///////////////////////////////////////////
933void process_fd_init( process_t * process )
934{
935    uint32_t fd;
936
[564]937    remote_queuelock_init( XPTR( local_cxy , &process->fd_array.lock ), LOCK_PROCESS_FDARRAY );
[1]938
[23]939    process->fd_array.current = 0;
940
[1]941    // initialize array
[23]942    for ( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
[1]943    {
944        process->fd_array.array[fd] = XPTR_NULL;
945    }
946}
947/////////////////////////////////////////////////
[407]948error_t process_fd_register( process_t * process,
949                             xptr_t      file_xp,
950                             uint32_t  * fdid )
[1]951{
952    bool_t    found;
[23]953    uint32_t  id;
[564]954    uint32_t  count;
[23]955    xptr_t    xp;
[1]956
[23]957    // get reference process cluster and local pointer
[407]958    xptr_t ref_xp = process->ref_xp;
[435]959    process_t * ref_ptr = GET_PTR( ref_xp );
[23]960    cxy_t       ref_cxy = GET_CXY( ref_xp );
961
962    // take lock protecting reference fd_array
[564]963        remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->fd_array.lock ) );
[23]964
[1]965    found   = false;
966
[23]967    for ( id = 0; id < CONFIG_PROCESS_FILE_MAX_NR ; id++ )
[1]968    {
[564]969        xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->fd_array.array[id] ) );
[23]970        if ( xp == XPTR_NULL )
[1]971        {
[564]972            // update reference fd_array
973            hal_remote_s64( XPTR( ref_cxy , &ref_ptr->fd_array.array[id] ) , file_xp );
974                count = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->fd_array.current ) ) + 1;
975            hal_remote_s32( XPTR( ref_cxy , &ref_ptr->fd_array.current ) , count );
976
977            // update local fd_array copy if required
978            if( ref_cxy != local_cxy )
979            {
980                process->fd_array.array[id] = file_xp;
981                process->fd_array.current   = count;
982            }
983
984            // exit
985                        *fdid = id;
[1]986            found = true;
987            break;
988        }
989    }
990
[23]991    // release lock protecting reference fd_array
[564]992        remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->fd_array.lock ) );
[1]993
[428]994    if ( !found ) return -1;
[1]995    else          return 0;
[172]996}
[1]997
[172]998////////////////////////////////////////////////
[23]999xptr_t process_fd_get_xptr( process_t * process,
[407]1000                            uint32_t    fdid )
[1]1001{
[23]1002    xptr_t  file_xp;
[564]1003    xptr_t  lock_xp;
[1]1004
[23]1005    // access local copy of process descriptor
[407]1006    file_xp = process->fd_array.array[fdid];
[1]1007
[23]1008    if( file_xp == XPTR_NULL )
1009    {
1010        // get reference process cluster and local pointer
1011        xptr_t      ref_xp  = process->ref_xp;
1012        cxy_t       ref_cxy = GET_CXY( ref_xp );
[435]1013        process_t * ref_ptr = GET_PTR( ref_xp );
[1]1014
[564]1015        // build extended pointer on lock protecting reference fd_array
1016        lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
1017
1018        // take lock protecting reference fd_array
1019            remote_queuelock_acquire( lock_xp );
1020
[23]1021        // access reference process descriptor
[564]1022        file_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->fd_array.array[fdid] ) );
[1]1023
[23]1024        // update local fd_array if found
[564]1025        if( file_xp != XPTR_NULL )  process->fd_array.array[fdid] = file_xp;
1026       
1027        // release lock protecting reference fd_array
1028            remote_queuelock_release( lock_xp );
[23]1029    }
[1]1030
[23]1031    return file_xp;
[1]1032
[407]1033}  // end process_fd_get_xptr()
1034
[1]1035///////////////////////////////////////////
1036void process_fd_remote_copy( xptr_t dst_xp,
1037                             xptr_t src_xp )
1038{
1039    uint32_t fd;
1040    xptr_t   entry;
1041
1042    // get cluster and local pointer for src fd_array
1043    cxy_t        src_cxy = GET_CXY( src_xp );
[435]1044    fd_array_t * src_ptr = GET_PTR( src_xp );
[1]1045
1046    // get cluster and local pointer for dst fd_array
1047    cxy_t        dst_cxy = GET_CXY( dst_xp );
[435]1048    fd_array_t * dst_ptr = GET_PTR( dst_xp );
[1]1049
1050    // get the remote lock protecting the src fd_array
[564]1051        remote_queuelock_acquire( XPTR( src_cxy , &src_ptr->lock ) );
[1]1052
[428]1053    // loop on all fd_array entries
1054    for( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
[1]1055        {
[564]1056                entry = (xptr_t)hal_remote_l64( XPTR( src_cxy , &src_ptr->array[fd] ) );
[1]1057
1058                if( entry != XPTR_NULL )
1059                {
[459]1060            // increment file descriptor refcount
[1]1061            vfs_file_count_up( entry );
1062
1063                        // copy entry in destination process fd_array
[564]1064                        hal_remote_s64( XPTR( dst_cxy , &dst_ptr->array[fd] ) , entry );
[1]1065                }
1066        }
1067
1068    // release lock on source process fd_array
[564]1069        remote_queuelock_release( XPTR( src_cxy , &src_ptr->lock ) );
[1]1070
[407]1071}  // end process_fd_remote_copy()
1072
[564]1073
1074////////////////////////////////////
1075bool_t process_fd_array_full( void )
1076{
1077    // get extended pointer on reference process
1078    xptr_t ref_xp = CURRENT_THREAD->process->ref_xp;
1079
1080    // get reference process cluster and local pointer
1081    process_t * ref_ptr = GET_PTR( ref_xp );
1082    cxy_t       ref_cxy = GET_CXY( ref_xp );
1083
1084    // get number of open file descriptors from reference fd_array
1085    uint32_t current = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->fd_array.current ) );
1086
1087        return ( current >= CONFIG_PROCESS_FILE_MAX_NR );
1088}
1089
1090
[1]1091////////////////////////////////////////////////////////////////////////////////////
1092//  Thread related functions
1093////////////////////////////////////////////////////////////////////////////////////
1094
1095/////////////////////////////////////////////////////
1096error_t process_register_thread( process_t * process,
1097                                 thread_t  * thread,
1098                                 trdid_t   * trdid )
1099{
[472]1100    ltid_t         ltid;
1101    bool_t         found = false;
1102 
[564]1103// check arguments
1104assert( (process != NULL) , "process argument is NULL" );
1105assert( (thread != NULL) , "thread argument is NULL" );
[1]1106
[564]1107    // get the lock protecting th_tbl for all threads
1108    // but the idle thread executing kernel_init (cannot yield)
1109    if( thread->type != THREAD_IDLE ) rwlock_wr_acquire( &process->th_lock );
[1]1110
[564]1111    // scan kth_tbl
1112    for( ltid = 0 ; ltid < CONFIG_THREADS_MAX_PER_CLUSTER ; ltid++ )
[1]1113    {
1114        if( process->th_tbl[ltid] == NULL )
1115        {
1116            found = true;
1117            break;
1118        }
1119    }
1120
1121    if( found )
1122    {
1123        // register thread in th_tbl[]
1124        process->th_tbl[ltid] = thread;
1125        process->th_nr++;
1126
1127        // returns trdid
1128        *trdid = TRDID( local_cxy , ltid );
1129    }
1130
[564]1131    // get the lock protecting th_tbl for all threads
1132    // but the idle thread executing kernel_init (cannot yield)
1133    if( thread->type != THREAD_IDLE ) rwlock_wr_release( &process->th_lock );
[428]1134
[564]1135    return (found) ? 0 : 0xFFFFFFFF;
[204]1136
1137}  // end process_register_thread()
1138
[443]1139/////////////////////////////////////////////////
1140bool_t process_remove_thread( thread_t * thread )
[1]1141{
[443]1142    uint32_t count;  // number of threads in local process descriptor
1143
[564]1144// check argument
1145assert( (thread != NULL) , "thread argument is NULL" );
[172]1146
[1]1147    process_t * process = thread->process;
1148
1149    // get thread local index
1150    ltid_t  ltid = LTID_FROM_TRDID( thread->trdid );
[564]1151   
1152    // the lock depends on thread user/kernel type, because we cannot
1153    // use a descheduling policy for the lock protecting the kth_tbl
[1]1154
[564]1155    // get the lock protecting th_tbl[]
1156    rwlock_wr_acquire( &process->th_lock );
[428]1157
[564]1158    // get number of kernel threads
[443]1159    count = process->th_nr;
[428]1160
[564]1161// check th_nr value
1162assert( (count > 0) , "process kth_nr cannot be 0\n" );
[443]1163
[1]1164    // remove thread from th_tbl[]
1165    process->th_tbl[ltid] = NULL;
[450]1166    process->th_nr = count-1;
[1]1167
[564]1168    // release lock protecting kth_tbl
1169    rwlock_wr_release( &process->th_lock );
[428]1170
[443]1171    return (count == 1);
1172
[450]1173}  // end process_remove_thread()
[204]1174
[408]1175/////////////////////////////////////////////////////////
1176error_t process_make_fork( xptr_t      parent_process_xp,
1177                           xptr_t      parent_thread_xp,
1178                           pid_t     * child_pid,
1179                           thread_t ** child_thread )
[1]1180{
[408]1181    process_t * process;         // local pointer on child process descriptor
1182    thread_t  * thread;          // local pointer on child thread descriptor
1183    pid_t       new_pid;         // process identifier for child process
1184    pid_t       parent_pid;      // process identifier for parent process
1185    xptr_t      ref_xp;          // extended pointer on reference process
[428]1186    xptr_t      vfs_bin_xp;      // extended pointer on .elf file
[408]1187    error_t     error;
[1]1188
[408]1189    // get cluster and local pointer for parent process
1190    cxy_t       parent_process_cxy = GET_CXY( parent_process_xp );
[435]1191    process_t * parent_process_ptr = GET_PTR( parent_process_xp );
[101]1192
[428]1193    // get parent process PID and extended pointer on .elf file
[564]1194    parent_pid = hal_remote_l32 (XPTR( parent_process_cxy , &parent_process_ptr->pid));
1195    vfs_bin_xp = hal_remote_l64(XPTR( parent_process_cxy , &parent_process_ptr->vfs_bin_xp));
[428]1196
[564]1197    // get extended pointer on reference process
1198    ref_xp = hal_remote_l64( XPTR( parent_process_cxy , &parent_process_ptr->ref_xp ) );
[438]1199
[564]1200// check parent process is the reference process
1201assert( (parent_process_xp == ref_xp ) ,
1202"parent process must be the reference process\n" );
[407]1203
[438]1204#if DEBUG_PROCESS_MAKE_FORK
[433]1205uint32_t cycle = (uint32_t)hal_get_cycles();
[438]1206if( DEBUG_PROCESS_MAKE_FORK < cycle )
[457]1207printk("\n[DBG] %s : thread %x in process %x enter / cluster %x / cycle %d\n",
1208__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, 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 )
1233printk("\n[DBG] %s : thread %x in process %x allocated process %x / cycle %d\n",
1234__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, new_pid, cycle );
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 )
[457]1245printk("\n[DBG] %s : thread %x in process %x initialized child_process %x / cycle %d\n",
1246__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, 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 )
[457]1265printk("\n[DBG] %s : thread %x in process %x copied VMM from parent %x to child %x / cycle %d\n",
1266__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, 
1267parent_pid, new_pid, cycle );
[433]1268#endif
[407]1269
[564]1270    // if parent_process is INIT, or if parent_process is the TXT owner,
1271    // the child_process becomes the owner of its TXT terminal
1272    if( (parent_pid == 1) || process_txt_is_owner( parent_process_xp ) )
[457]1273    {
1274        process_txt_set_ownership( XPTR( local_cxy , process ) );
1275
1276#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1277cycle = (uint32_t)hal_get_cycles();
1278if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[564]1279printk("\n[DBG] %s : thread %x in process %x / child takes TXT ownership / cycle %d\n",
1280__FUNCTION__ , CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, cycle );
[457]1281#endif
1282
1283    }
1284
[428]1285    // update extended pointer on .elf file
1286    process->vfs_bin_xp = vfs_bin_xp;
1287
[408]1288    // create child thread descriptor from parent thread descriptor
1289    error = thread_user_fork( parent_thread_xp,
1290                              process,
1291                              &thread );
1292    if( error )
1293    {
1294        printk("\n[ERROR] in %s : cannot create thread in cluster %x\n",
1295        __FUNCTION__, local_cxy ); 
1296        process_free( process );
1297        cluster_pid_release( new_pid );
1298        return -1;
1299    }
[172]1300
[564]1301// check main thread LTID
1302assert( (LTID_FROM_TRDID(thread->trdid) == 0) ,
1303"main thread must have LTID == 0\n" );
[428]1304
[564]1305#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[433]1306cycle = (uint32_t)hal_get_cycles();
[438]1307if( DEBUG_PROCESS_MAKE_FORK < cycle )
[469]1308printk("\n[DBG] %s : thread %x in process %x created main thread %x / cycle %d\n", 
1309__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, thread, cycle );
[433]1310#endif
[1]1311
[433]1312    // set Copy_On_Write flag in parent process GPT
[408]1313    // this includes all replicated GPT copies
1314    if( parent_process_cxy == local_cxy )   // reference is local
1315    {
1316        vmm_set_cow( parent_process_ptr );
1317    }
1318    else                                    // reference is remote
1319    {
1320        rpc_vmm_set_cow_client( parent_process_cxy,
1321                                parent_process_ptr );
1322    }
[1]1323
[433]1324    // set Copy_On_Write flag in child process GPT
1325    vmm_set_cow( process );
1326 
[438]1327#if( DEBUG_PROCESS_MAKE_FORK & 1 )
[433]1328cycle = (uint32_t)hal_get_cycles();
[438]1329if( DEBUG_PROCESS_MAKE_FORK < cycle )
[457]1330printk("\n[DBG] %s : thread %x in process %x set COW in parent and child / cycle %d\n",
1331__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, cycle );
[433]1332#endif
[101]1333
[428]1334    // get extended pointers on parent children_root, children_lock and children_nr
1335    xptr_t children_root_xp = XPTR( parent_process_cxy , &parent_process_ptr->children_root );
1336    xptr_t children_lock_xp = XPTR( parent_process_cxy , &parent_process_ptr->children_lock );
1337    xptr_t children_nr_xp   = XPTR( parent_process_cxy , &parent_process_ptr->children_nr   );
[101]1338
[428]1339    // register process in parent children list
[564]1340    remote_queuelock_acquire( children_lock_xp );
[428]1341        xlist_add_last( children_root_xp , XPTR( local_cxy , &process->children_list ) );
1342        hal_remote_atomic_add( children_nr_xp , 1 );
[564]1343    remote_queuelock_release( children_lock_xp );
[204]1344
[408]1345    // return success
1346    *child_thread = thread;
1347    *child_pid    = new_pid;
[1]1348
[438]1349#if DEBUG_PROCESS_MAKE_FORK
[433]1350cycle = (uint32_t)hal_get_cycles();
[438]1351if( DEBUG_PROCESS_MAKE_FORK < cycle )
[457]1352printk("\n[DBG] %s : thread %x in process %x exit / created process %x / cycle %d\n",
1353__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, new_pid, cycle );
[433]1354#endif
[428]1355
[408]1356    return 0;
1357
[416]1358}   // end process_make_fork()
[408]1359
1360/////////////////////////////////////////////////////
1361error_t process_make_exec( exec_info_t  * exec_info )
1362{
[457]1363    thread_t       * thread;                  // local pointer on this thread
1364    process_t      * process;                 // local pointer on this process
1365    pid_t            pid;                     // this process identifier
[441]1366        error_t          error;                   // value returned by called functions
[457]1367    char           * path;                    // path to .elf file
1368    xptr_t           file_xp;                 // extended pointer on .elf file descriptor
1369    uint32_t         file_id;                 // file index in fd_array
1370    uint32_t         args_nr;                 // number of main thread arguments
1371    char          ** args_pointers;           // array of pointers on main thread arguments
[446]1372
[457]1373    // get thread, process & PID
1374    thread  = CURRENT_THREAD;
1375    process = thread->process;
1376    pid     = process->pid;
[408]1377
[457]1378        // get relevant infos from exec_info
1379        path          = exec_info->path;
1380    args_nr       = exec_info->args_nr;
1381    args_pointers = exec_info->args_pointers;
[408]1382
[438]1383#if DEBUG_PROCESS_MAKE_EXEC
[433]1384uint32_t cycle = (uint32_t)hal_get_cycles();
[438]1385if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[446]1386printk("\n[DBG] %s : thread %x in process %x enters / path %s / cycle %d\n",
[457]1387__FUNCTION__, thread->trdid, pid, path, cycle );
[433]1388#endif
[408]1389
[457]1390    // open the file identified by <path>
1391    file_xp = XPTR_NULL;
[564]1392    file_id = 0xFFFFFFFF;
[457]1393        error   = vfs_open( process,
1394                            path,
1395                            O_RDONLY,
1396                            0,
1397                            &file_xp,
1398                            &file_id );
1399        if( error )
1400        {
1401                printk("\n[ERROR] in %s : failed to open file <%s>\n", __FUNCTION__ , path );
1402                return -1;
1403        }
1404
[446]1405#if (DEBUG_PROCESS_MAKE_EXEC & 1)
[469]1406cycle = (uint32_t)hal_get_cycles();
[446]1407if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[469]1408printk("\n[DBG] %s : thread %x in process %x opened file <%s> / cycle %d\n",
1409__FUNCTION__, thread->trdid, pid, path, cycle );
[446]1410#endif
1411
[457]1412    // delete all threads other than this main thread in all clusters
1413    process_sigaction( pid , DELETE_ALL_THREADS );
[446]1414
[469]1415#if (DEBUG_PROCESS_MAKE_EXEC & 1)
1416cycle = (uint32_t)hal_get_cycles();
1417if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1418printk("\n[DBG] %s : thread %x in process %x deleted all threads / cycle %d\n",
1419__FUNCTION__, thread->trdid, pid, cycle );
1420#endif
1421
[457]1422    // reset local process VMM
1423    vmm_destroy( process );
[446]1424
[457]1425#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
1426cycle = (uint32_t)hal_get_cycles();
1427if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[469]1428printk("\n[DBG] %s : thread %x in process %x reset VMM / cycle %d\n",
[457]1429__FUNCTION__, thread->trdid, pid, cycle );
1430#endif
[408]1431
[457]1432    // re-initialize the VMM (kentry/args/envs vsegs registration)
1433    error = vmm_init( process );
1434    if( error )
[416]1435    {
[457]1436        printk("\n[ERROR] in %s : cannot initialise VMM for %s\n", __FUNCTION__ , path );
1437        vfs_close( file_xp , file_id );
1438        // FIXME restore old process VMM
[416]1439        return -1;
1440    }
[457]1441   
[438]1442#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
[433]1443cycle = (uint32_t)hal_get_cycles();
[438]1444if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[457]1445printk("\n[DBG] %s : thread %x in process %x / kentry/args/envs vsegs registered / cycle %d\n",
1446__FUNCTION__, thread->trdid, pid, cycle );
[433]1447#endif
[428]1448
[457]1449    // register code & data vsegs as well as entry-point in process VMM,
[428]1450    // and register extended pointer on .elf file in process descriptor
[457]1451        error = elf_load_process( file_xp , process );
[441]1452    if( error )
[1]1453        {
[441]1454                printk("\n[ERROR] in %s : failed to access <%s>\n", __FUNCTION__ , path );
[457]1455        vfs_close( file_xp , file_id );
1456        // FIXME restore old process VMM
[408]1457        return -1;
[1]1458        }
1459
[438]1460#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
[433]1461cycle = (uint32_t)hal_get_cycles();
[438]1462if( DEBUG_PROCESS_MAKE_EXEC < cycle )
[457]1463printk("\n[DBG] %s : thread %x in process %x / code/data vsegs registered / cycle %d\n",
1464__FUNCTION__, thread->trdid, pid, cycle );
[433]1465#endif
[1]1466
[457]1467    // update the existing main thread descriptor... and jump to user code
1468    error = thread_user_exec( (void *)process->vmm.entry_point,
1469                              args_nr,
1470                              args_pointers );
1471    if( error )
1472    {
[469]1473        printk("\n[ERROR] in %s : cannot update main thread for %s\n", __FUNCTION__ , path );
[457]1474        vfs_close( file_xp , file_id );
1475        // FIXME restore old process VMM
[408]1476        return -1;
[457]1477    }
[1]1478
[492]1479    assert( false, "we should not execute this code");
[457]1480 
[409]1481        return 0;
1482
1483}  // end process_make_exec()
1484
[457]1485
[428]1486///////////////////////////////////////////////
1487void process_zero_create( process_t * process )
1488{
1489
[438]1490#if DEBUG_PROCESS_ZERO_CREATE
[433]1491uint32_t cycle = (uint32_t)hal_get_cycles();
[438]1492if( DEBUG_PROCESS_ZERO_CREATE < cycle )
[564]1493printk("\n[DBG] %s : enter / cluster %x / cycle %d\n",
1494__FUNCTION__, local_cxy, cycle );
[433]1495#endif
[428]1496
1497    // initialize PID, REF_XP, PARENT_XP, and STATE
[433]1498    process->pid        = 0;
1499    process->ref_xp     = XPTR( local_cxy , process );
[443]1500    process->owner_xp   = XPTR( local_cxy , process );
[433]1501    process->parent_xp  = XPTR_NULL;
1502    process->term_state = 0;
[428]1503
[564]1504    // reset th_tbl[] array and associated fields
[428]1505    uint32_t i;
[564]1506    for( i = 0 ; i < CONFIG_THREADS_MAX_PER_CLUSTER ; i++ )
[428]1507        {
1508        process->th_tbl[i] = NULL;
1509    }
1510    process->th_nr  = 0;
[564]1511    rwlock_init( &process->th_lock , LOCK_PROCESS_THTBL );
[428]1512
[564]1513
[428]1514    // reset children list as empty
1515    xlist_root_init( XPTR( local_cxy , &process->children_root ) );
1516    process->children_nr = 0;
[564]1517    remote_queuelock_init( XPTR( local_cxy , &process->children_lock ),
1518                           LOCK_PROCESS_CHILDREN );
[428]1519
1520        hal_fence();
1521
[438]1522#if DEBUG_PROCESS_ZERO_CREATE
[433]1523cycle = (uint32_t)hal_get_cycles();
[438]1524if( DEBUG_PROCESS_ZERO_CREATE < cycle )
[564]1525printk("\n[DBG] %s : exit / cluster %x / cycle %d\n",
1526__FUNCTION__, local_cxy, cycle );
[433]1527#endif
[428]1528
1529}  // end process_zero_init()
1530
[564]1531////////////////////////////////
[485]1532void process_init_create( void )
[1]1533{
[428]1534    process_t      * process;       // local pointer on process descriptor
[409]1535    pid_t            pid;           // process_init identifier
1536    thread_t       * thread;        // local pointer on main thread
1537    pthread_attr_t   attr;          // main thread attributes
1538    lid_t            lid;           // selected core local index for main thread
[457]1539    xptr_t           file_xp;       // extended pointer on .elf file descriptor
1540    uint32_t         file_id;       // file index in fd_array
[409]1541    error_t          error;
[1]1542
[438]1543#if DEBUG_PROCESS_INIT_CREATE
[433]1544uint32_t cycle = (uint32_t)hal_get_cycles();
[438]1545if( DEBUG_PROCESS_INIT_CREATE < cycle )
[457]1546printk("\n[DBG] %s : thread %x in process %x enter / cycle %d\n",
1547__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, cycle );
[433]1548#endif
[1]1549
[408]1550    // allocates memory for process descriptor from local cluster
1551        process = process_alloc(); 
[457]1552       
[564]1553// check memory allocator
1554assert( (process != NULL),
1555"no memory for process descriptor in cluster %x\n", local_cxy  );
[101]1556
[409]1557    // get PID from local cluster
[416]1558    error = cluster_pid_alloc( process , &pid );
[408]1559
[564]1560// check PID allocator
1561assert( (error == 0),
1562"cannot allocate PID in cluster %x\n", local_cxy );
[409]1563
[564]1564// check PID value
1565assert( (pid == 1) ,
1566"process INIT must be first process in cluster 0\n" );
[457]1567
[409]1568    // initialize process descriptor / parent is local process_zero
1569    process_reference_init( process,
[408]1570                            pid,
[457]1571                            XPTR( local_cxy , &process_zero ) ); 
[408]1572
[564]1573#if(DEBUG_PROCESS_INIT_CREATE & 1)
1574if( DEBUG_PROCESS_INIT_CREATE < cycle )
1575printk("\n[DBG] %s : thread %x in process %x initialized process descriptor\n",
1576__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
1577#endif
1578
[457]1579    // open the file identified by CONFIG_PROCESS_INIT_PATH
1580    file_xp = XPTR_NULL;
1581    file_id = -1;
1582        error   = vfs_open( process,
1583                            CONFIG_PROCESS_INIT_PATH,
1584                            O_RDONLY,
1585                            0,
1586                            &file_xp,
1587                            &file_id );
1588
[564]1589assert( (error == 0),
1590"failed to open file <%s>\n", CONFIG_PROCESS_INIT_PATH );
[457]1591
[564]1592#if(DEBUG_PROCESS_INIT_CREATE & 1)
1593if( DEBUG_PROCESS_INIT_CREATE < cycle )
1594printk("\n[DBG] %s : thread %x in process %x open .elf file decriptor\n",
1595__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
1596#endif
1597
1598   // register "code" and "data" vsegs as well as entry-point
[409]1599    // in process VMM, using information contained in the elf file.
[457]1600        error = elf_load_process( file_xp , process );
[101]1601
[564]1602assert( (error == 0),
1603"cannot access .elf file <%s>\n", CONFIG_PROCESS_INIT_PATH );
[457]1604
[564]1605#if(DEBUG_PROCESS_INIT_CREATE & 1)
1606if( DEBUG_PROCESS_INIT_CREATE < cycle )
1607printk("\n[DBG] %s : thread %x in process %x registered code/data vsegs in VMM\n",
1608__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
1609#endif
1610
[428]1611    // get extended pointers on process_zero children_root, children_lock
1612    xptr_t children_root_xp = XPTR( local_cxy , &process_zero.children_root );
1613    xptr_t children_lock_xp = XPTR( local_cxy , &process_zero.children_lock );
1614
[564]1615    // take lock protecting kernel process children list
1616    remote_queuelock_acquire( children_lock_xp );
1617
[428]1618    // register process INIT in parent local process_zero
1619        xlist_add_last( children_root_xp , XPTR( local_cxy , &process->children_list ) );
1620        hal_atomic_add( &process_zero.children_nr , 1 );
1621
[564]1622    // release lock protecting kernel process children list
1623    remote_queuelock_release( children_lock_xp );
1624
1625#if(DEBUG_PROCESS_INIT_CREATE & 1)
1626if( DEBUG_PROCESS_INIT_CREATE < cycle )
1627printk("\n[DBG] %s : thread %x in process %x registered init process in parent\n",
1628__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
1629#endif
1630
[409]1631    // select a core in local cluster to execute the main thread
1632    lid  = cluster_select_local_core();
1633
1634    // initialize pthread attributes for main thread
1635    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
1636    attr.cxy        = local_cxy;
1637    attr.lid        = lid;
1638
1639    // create and initialize thread descriptor
1640        error = thread_user_create( pid,
1641                                (void *)process->vmm.entry_point,
1642                                NULL,
1643                                &attr,
1644                                &thread );
[1]1645
[564]1646assert( (error == 0),
1647"cannot create main thread for <%s>\n", CONFIG_PROCESS_INIT_PATH );
[428]1648
[564]1649assert( (thread->trdid == 0),
1650"main thread must have index 0 for <%s>\n", CONFIG_PROCESS_INIT_PATH );
[457]1651
[564]1652#if(DEBUG_PROCESS_INIT_CREATE & 1)
1653if( DEBUG_PROCESS_INIT_CREATE < cycle )
1654printk("\n[DBG] %s : thread %x in process %x created main thread\n",
1655__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
1656#endif
1657
[409]1658    // activate thread
1659        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_GLOBAL );
1660
[124]1661    hal_fence();
[1]1662
[438]1663#if DEBUG_PROCESS_INIT_CREATE
[433]1664cycle = (uint32_t)hal_get_cycles();
[438]1665if( DEBUG_PROCESS_INIT_CREATE < cycle )
[457]1666printk("\n[DBG] %s : thread %x in process %x exit / cycle %d\n",
1667__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, cycle );
[433]1668#endif
[409]1669
[204]1670}  // end process_init_create()
1671
[428]1672/////////////////////////////////////////
1673void process_display( xptr_t process_xp )
1674{
1675    process_t   * process_ptr;
1676    cxy_t         process_cxy;
[443]1677
[428]1678    xptr_t        parent_xp;       // extended pointer on parent process
1679    process_t   * parent_ptr;
1680    cxy_t         parent_cxy;
1681
[443]1682    xptr_t        owner_xp;        // extended pointer on owner process
1683    process_t   * owner_ptr;
1684    cxy_t         owner_cxy;
1685
[428]1686    pid_t         pid;
1687    pid_t         ppid;
1688    uint32_t      state;
1689    uint32_t      th_nr;
1690
[443]1691    xptr_t        txt_file_xp;     // extended pointer on TXT_RX file descriptor
1692    xptr_t        txt_chdev_xp;    // extended pointer on TXT_RX chdev
1693    chdev_t     * txt_chdev_ptr;
1694    cxy_t         txt_chdev_cxy;
1695    xptr_t        txt_owner_xp;    // extended pointer on TXT owner process
[428]1696
1697    xptr_t        elf_file_xp;     // extended pointer on .elf file
1698    cxy_t         elf_file_cxy;
1699    vfs_file_t  * elf_file_ptr;
1700    vfs_inode_t * elf_inode_ptr;   // local pointer on .elf inode
1701
1702    char          txt_name[CONFIG_VFS_MAX_NAME_LENGTH];
1703    char          elf_name[CONFIG_VFS_MAX_NAME_LENGTH];
1704
1705    // get cluster and local pointer on process
1706    process_ptr = GET_PTR( process_xp );
1707    process_cxy = GET_CXY( process_xp );
1708
1709    // get PID and state
[564]1710    pid   = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
1711    state = hal_remote_l32( XPTR( process_cxy , &process_ptr->term_state ) );
[428]1712
1713    // get PPID
[564]1714    parent_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->parent_xp ) );
[428]1715    parent_cxy = GET_CXY( parent_xp );
1716    parent_ptr = GET_PTR( parent_xp );
[564]1717    ppid       = hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
[428]1718
1719    // get number of threads
[564]1720    th_nr      = hal_remote_l32( XPTR( process_cxy , &process_ptr->th_nr ) );
[428]1721
[443]1722    // get pointers on owner process descriptor
[564]1723    owner_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) );
[443]1724    owner_cxy = GET_CXY( owner_xp );
1725    owner_ptr = GET_PTR( owner_xp );
[428]1726
[443]1727    // get extended pointer on TXT_RX file descriptor attached to process
[564]1728    txt_file_xp = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->fd_array.array[0] ) );
[443]1729
[492]1730    assert( (txt_file_xp != XPTR_NULL) ,
[428]1731    "process must be attached to one TXT terminal\n" ); 
1732
[443]1733    // get TXT_RX chdev pointers
1734    txt_chdev_xp  = chdev_from_file( txt_file_xp );
1735    txt_chdev_cxy = GET_CXY( txt_chdev_xp );
1736    txt_chdev_ptr = GET_PTR( txt_chdev_xp );
1737
1738    // get TXT_RX name and ownership
[428]1739    hal_remote_strcpy( XPTR( local_cxy , txt_name ) ,
[443]1740                       XPTR( txt_chdev_cxy , txt_chdev_ptr->name ) );
[428]1741   
[564]1742    txt_owner_xp = (xptr_t)hal_remote_l64( XPTR( txt_chdev_cxy, 
[443]1743                                                 &txt_chdev_ptr->ext.txt.owner_xp ) );
1744   
[428]1745    // get process .elf name
[564]1746    elf_file_xp   = hal_remote_l64( XPTR( process_cxy , &process_ptr->vfs_bin_xp ) );
[428]1747    elf_file_cxy  = GET_CXY( elf_file_xp );
1748    elf_file_ptr  = (vfs_file_t *)GET_PTR( elf_file_xp );
1749    elf_inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( elf_file_cxy , &elf_file_ptr->inode ) );
1750    vfs_inode_get_name( XPTR( elf_file_cxy , elf_inode_ptr ) , elf_name );
1751
1752    // display process info
[443]1753    if( txt_owner_xp == process_xp )
[428]1754    {
[446]1755        nolock_printk("PID %X | PPID %X | TS %X | %s (FG) | %X | %d | %s\n", 
[433]1756        pid, ppid, state, txt_name, process_ptr, th_nr, elf_name );
[428]1757    }
1758    else
1759    {
[446]1760        nolock_printk("PID %X | PPID %X | TS %X | %s (BG) | %X | %d | %s\n", 
[433]1761        pid, ppid, state, txt_name, process_ptr, th_nr, elf_name );
[428]1762    }
1763}  // end process_display()
1764
1765
1766////////////////////////////////////////////////////////////////////////////////////////
1767//     Terminals related functions
1768////////////////////////////////////////////////////////////////////////////////////////
1769
1770////////////////////////////
[485]1771uint32_t process_txt_alloc( void )
[428]1772{
1773    uint32_t  index;       // TXT terminal index
1774    xptr_t    chdev_xp;    // extended pointer on TXT_RX chdev
1775    chdev_t * chdev_ptr;   // local pointer on TXT_RX chdev
1776    cxy_t     chdev_cxy;   // TXT_RX chdev cluster
1777    xptr_t    root_xp;     // extended pointer on owner field in chdev
1778
1779    // scan the user TXT_RX chdevs (TXT0 is reserved for kernel)
1780    for( index = 1 ; index < LOCAL_CLUSTER->nb_txt_channels ; index ++ )
1781    {
1782        // get pointers on TXT_RX[index]
1783        chdev_xp  = chdev_dir.txt_rx[index];
1784        chdev_cxy = GET_CXY( chdev_xp );
1785        chdev_ptr = GET_PTR( chdev_xp );
1786
1787        // get extended pointer on root of attached process
1788        root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
1789
1790        // return free TXT index if found
1791        if( xlist_is_empty( root_xp ) ) return index; 
1792    }
1793
[492]1794    assert( false , "no free TXT terminal found" );
[428]1795
1796    return -1;
1797
1798} // end process_txt_alloc()
1799
1800/////////////////////////////////////////////
1801void process_txt_attach( process_t * process,
1802                         uint32_t    txt_id )
1803{
1804    xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
1805    cxy_t       chdev_cxy;    // TXT_RX chdev cluster
1806    chdev_t *   chdev_ptr;    // local pointer on TXT_RX chdev
1807    xptr_t      root_xp;      // extended pointer on list root in chdev
1808    xptr_t      lock_xp;      // extended pointer on list lock in chdev
1809
[564]1810// check process is in owner cluster
1811assert( (CXY_FROM_PID( process->pid ) == local_cxy) ,
1812"process descriptor not in owner cluster" );
[428]1813
[564]1814// check terminal index
1815assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
1816"illegal TXT terminal index" );
[428]1817
1818    // get pointers on TXT_RX[txt_id] chdev
1819    chdev_xp  = chdev_dir.txt_rx[txt_id];
1820    chdev_cxy = GET_CXY( chdev_xp );
1821    chdev_ptr = GET_PTR( chdev_xp );
1822
1823    // get extended pointer on root & lock of attached process list
1824    root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
1825    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
1826
[564]1827    // get lock protecting list of processes attached to TXT
1828    remote_busylock_acquire( lock_xp );
1829
[428]1830    // insert process in attached process list
1831    xlist_add_last( root_xp , XPTR( local_cxy , &process->txt_list ) );
1832
[564]1833    // release lock protecting list of processes attached to TXT
1834    remote_busylock_release( lock_xp );
1835
[446]1836#if DEBUG_PROCESS_TXT
[457]1837uint32_t cycle = (uint32_t)hal_get_cycles();
[446]1838if( DEBUG_PROCESS_TXT < cycle )
[457]1839printk("\n[DBG] %s : thread %x in process %x attached process %x to TXT %d / cycle %d\n",
1840__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
1841process->pid, txt_id , cycle );
[433]1842#endif
[428]1843
1844} // end process_txt_attach()
1845
[436]1846/////////////////////////////////////////////
1847void process_txt_detach( xptr_t  process_xp )
[428]1848{
[436]1849    process_t * process_ptr;  // local pointer on process in owner cluster
1850    cxy_t       process_cxy;  // process owner cluster
1851    pid_t       process_pid;  // process identifier
1852    xptr_t      file_xp;      // extended pointer on stdin file
[428]1853    xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
1854    cxy_t       chdev_cxy;    // TXT_RX chdev cluster
1855    chdev_t *   chdev_ptr;    // local pointer on TXT_RX chdev
1856    xptr_t      lock_xp;      // extended pointer on list lock in chdev
1857
[436]1858    // get process cluster, local pointer, and PID
1859    process_cxy = GET_CXY( process_xp );
1860    process_ptr = GET_PTR( process_xp );
[564]1861    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[436]1862
[564]1863// check process descriptor in owner cluster
1864assert( (CXY_FROM_PID( process_pid ) == process_cxy ) ,
1865"process descriptor not in owner cluster" );
[436]1866
1867    // release TXT ownership (does nothing if not TXT owner)
1868    process_txt_transfer_ownership( process_xp );
[428]1869
[436]1870    // get extended pointer on process stdin file
[564]1871    file_xp = (xptr_t)hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[436]1872
1873    // get pointers on TXT_RX chdev
1874    chdev_xp  = chdev_from_file( file_xp );
[428]1875    chdev_cxy = GET_CXY( chdev_xp );
1876    chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
1877
[436]1878    // get extended pointer on lock protecting attached process list
[428]1879    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
1880
[564]1881    // get lock protecting list of processes attached to TXT
1882    remote_busylock_acquire( lock_xp );
1883
[428]1884    // unlink process from attached process list
[436]1885    xlist_unlink( XPTR( process_cxy , &process_ptr->txt_list ) );
1886
[564]1887    // release lock protecting list of processes attached to TXT
1888    remote_busylock_release( lock_xp );
1889
[446]1890#if DEBUG_PROCESS_TXT
[457]1891uint32_t cycle  = (uint32_t)hal_get_cycles();
[564]1892uint32_t txt_id = hal_remote_l32( XPTR( chdev_cxy , &chdev_ptr->channel ) );
[446]1893if( DEBUG_PROCESS_TXT < cycle )
[457]1894printk("\n[DBG] %s : thread %x in process %x detached process %x from TXT %d / cycle %d\n",
1895__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
1896process_pid, txt_id, cycle );
[433]1897#endif
[428]1898
1899} // end process_txt_detach()
1900
1901///////////////////////////////////////////////////
1902void process_txt_set_ownership( xptr_t process_xp )
1903{
1904    process_t * process_ptr;
1905    cxy_t       process_cxy;
[436]1906    pid_t       process_pid;
[428]1907    xptr_t      file_xp;
1908    xptr_t      txt_xp;     
1909    chdev_t   * txt_ptr;
1910    cxy_t       txt_cxy;
1911
[436]1912    // get pointers on process in owner cluster
[428]1913    process_cxy = GET_CXY( process_xp );
[435]1914    process_ptr = GET_PTR( process_xp );
[564]1915    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[436]1916
1917    // check owner cluster
[492]1918    assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
[436]1919    "process descriptor not in owner cluster\n" );
1920
[428]1921    // get extended pointer on stdin pseudo file
[564]1922    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[428]1923
1924    // get pointers on TXT chdev
1925    txt_xp  = chdev_from_file( file_xp );
1926    txt_cxy = GET_CXY( txt_xp );
[435]1927    txt_ptr = GET_PTR( txt_xp );
[428]1928
1929    // set owner field in TXT chdev
[564]1930    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , process_xp );
[428]1931
[446]1932#if DEBUG_PROCESS_TXT
[457]1933uint32_t cycle  = (uint32_t)hal_get_cycles();
[564]1934uint32_t txt_id = hal_remote_l32( XPTR( txt_cxy , &txt_ptr->channel ) );
[446]1935if( DEBUG_PROCESS_TXT < cycle )
[457]1936printk("\n[DBG] %s : thread %x in process %x give TXT %d to process %x / cycle %d\n",
1937__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, txt_id, process_pid, cycle );
[436]1938#endif
1939
[428]1940}  // end process_txt_set ownership()
1941
[436]1942////////////////////////////////////////////////////////
1943void process_txt_transfer_ownership( xptr_t process_xp )
[428]1944{
[436]1945    process_t * process_ptr;     // local pointer on process releasing ownership
1946    cxy_t       process_cxy;     // process cluster
1947    pid_t       process_pid;     // process identifier
[428]1948    xptr_t      file_xp;         // extended pointer on TXT_RX pseudo file
1949    xptr_t      txt_xp;          // extended pointer on TXT_RX chdev
[433]1950    chdev_t   * txt_ptr;         // local pointer on TXT_RX chdev
1951    cxy_t       txt_cxy;         // cluster of TXT_RX chdev
1952    uint32_t    txt_id;          // TXT_RX channel
[428]1953    xptr_t      owner_xp;        // extended pointer on current TXT_RX owner
1954    xptr_t      root_xp;         // extended pointer on root of attached process list
[436]1955    xptr_t      lock_xp;         // extended pointer on lock protecting attached process list
[428]1956    xptr_t      iter_xp;         // iterator for xlist
1957    xptr_t      current_xp;      // extended pointer on current process
[433]1958    process_t * current_ptr;     // local pointer on current process
1959    cxy_t       current_cxy;     // cluster for current process
[428]1960
[457]1961#if DEBUG_PROCESS_TXT
1962uint32_t cycle;
1963#endif
1964
[436]1965    // get pointers on process in owner cluster
[428]1966    process_cxy = GET_CXY( process_xp );
[435]1967    process_ptr = GET_PTR( process_xp );
[564]1968    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
[436]1969
1970    // check owner cluster
[492]1971    assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
[436]1972    "process descriptor not in owner cluster\n" );
1973
[428]1974    // get extended pointer on stdin pseudo file
[564]1975    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[428]1976
1977    // get pointers on TXT chdev
1978    txt_xp  = chdev_from_file( file_xp );
1979    txt_cxy = GET_CXY( txt_xp );
[433]1980    txt_ptr = GET_PTR( txt_xp );
[428]1981
[433]1982    // get extended pointer on TXT_RX owner and TXT channel
[564]1983    owner_xp = hal_remote_l64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) );
1984    txt_id   = hal_remote_l32 ( XPTR( txt_cxy , &txt_ptr->channel ) );
[428]1985
[436]1986    // transfer ownership only if process is the TXT owner
1987    if( (owner_xp == process_xp) && (txt_id > 0) ) 
[428]1988    {
[436]1989        // get extended pointers on root and lock of attached processes list
1990        root_xp = XPTR( txt_cxy , &txt_ptr->ext.txt.root );
1991        lock_xp = XPTR( txt_cxy , &txt_ptr->ext.txt.lock );
[428]1992
[436]1993        // get lock
[564]1994        remote_busylock_acquire( lock_xp );
[436]1995
1996        if( process_get_ppid( process_xp ) != 1 )           // process is not KSH
[428]1997        {
[436]1998            // scan attached process list to find KSH process
1999            XLIST_FOREACH( root_xp , iter_xp )
2000            {
2001                current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2002                current_cxy = GET_CXY( current_xp );
2003                current_ptr = GET_PTR( current_xp );
[435]2004
[436]2005                if( process_get_ppid( current_xp ) == 1 )  // current is KSH
2006                {
2007                    // release lock
[564]2008                    remote_busylock_release( lock_xp );
[436]2009
2010                    // set owner field in TXT chdev
[564]2011                    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , current_xp );
[436]2012
[446]2013#if DEBUG_PROCESS_TXT
[457]2014cycle   = (uint32_t)hal_get_cycles();
[564]2015uint32_t ksh_pid = hal_remote_l32( XPTR( current_cxy , &current_ptr->pid ) );
[446]2016if( DEBUG_PROCESS_TXT < cycle )
[457]2017printk("\n[DBG] %s : thread %x in process %x release TXT %d to KSH %x / cycle %d\n",
2018__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, txt_id, ksh_pid, cycle );
2019process_txt_display( txt_id );
[436]2020#endif
2021                     return;
2022                }
2023            }
2024 
2025            // release lock
[564]2026            remote_busylock_release( lock_xp );
[436]2027
2028            // PANIC if KSH not found
[492]2029            assert( false , "KSH process not found for TXT %d" );
[436]2030
2031            return;
2032        }
2033        else                                               // process is KSH
2034        {
2035            // scan attached process list to find another process
2036            XLIST_FOREACH( root_xp , iter_xp )
[428]2037            {
[436]2038                current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2039                current_cxy = GET_CXY( current_xp );
2040                current_ptr = GET_PTR( current_xp );
2041
2042                if( current_xp != process_xp )            // current is not KSH
2043                {
2044                    // release lock
[564]2045                    remote_busylock_release( lock_xp );
[436]2046
2047                    // set owner field in TXT chdev
[564]2048                    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , current_xp );
[436]2049
[446]2050#if DEBUG_PROCESS_TXT
[457]2051cycle   = (uint32_t)hal_get_cycles();
[564]2052uint32_t new_pid = hal_remote_l32( XPTR( current_cxy , &current_ptr->pid ) );
[446]2053if( DEBUG_PROCESS_TXT < cycle )
[457]2054printk("\n[DBG] %s : thread %x in process %x release TXT %d to process %x / cycle %d\n",
2055__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, txt_id, new_pid, cycle );
2056process_txt_display( txt_id );
[436]2057#endif
2058                     return;
2059                }
[428]2060            }
[436]2061
2062            // release lock
[564]2063            remote_busylock_release( lock_xp );
[436]2064
2065            // no more owner for TXT if no other process found
[564]2066            hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , XPTR_NULL );
[436]2067
[446]2068#if DEBUG_PROCESS_TXT
[436]2069cycle = (uint32_t)hal_get_cycles();
[446]2070if( DEBUG_PROCESS_TXT < cycle )
[457]2071printk("\n[DBG] %s : thread %x in process %x release TXT %d to nobody / cycle %d\n",
2072__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, txt_id, cycle );
2073process_txt_display( txt_id );
[436]2074#endif
2075            return;
[428]2076        }
[436]2077    }
2078    else
2079    {
[433]2080
[446]2081#if DEBUG_PROCESS_TXT
[436]2082cycle = (uint32_t)hal_get_cycles();
[446]2083if( DEBUG_PROCESS_TXT < cycle )
[457]2084printk("\n[DBG] %s : thread %x in process %d does nothing (not TXT owner) / cycle %d\n",
2085__FUNCTION__, CURRENT_THREAD->trdid, process_pid, cycle );
2086process_txt_display( txt_id );
[436]2087#endif
2088
[428]2089    }
[436]2090}  // end process_txt_transfer_ownership()
[428]2091
2092
[564]2093////////////////////////////////////////////////
2094bool_t process_txt_is_owner( xptr_t process_xp )
[457]2095{
2096    // get local pointer and cluster of process in owner cluster
2097    cxy_t       process_cxy = GET_CXY( process_xp );
2098    process_t * process_ptr = GET_PTR( process_xp );
2099
[564]2100// check calling thread execute in target process owner cluster
2101pid_t process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
2102assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
2103"process descriptor not in owner cluster\n" );
[457]2104
2105    // get extended pointer on stdin pseudo file
[564]2106    xptr_t file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
[457]2107
2108    // get pointers on TXT chdev
2109    xptr_t    txt_xp  = chdev_from_file( file_xp );
2110    cxy_t     txt_cxy = GET_CXY( txt_xp );
2111    chdev_t * txt_ptr = GET_PTR( txt_xp );
2112
2113    // get extended pointer on TXT_RX owner process
[564]2114    xptr_t owner_xp = hal_remote_l64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) );
[457]2115
2116    return (process_xp == owner_xp);
2117
2118}   // end process_txt_is_owner()
2119
[436]2120////////////////////////////////////////////////     
2121xptr_t process_txt_get_owner( uint32_t channel )
[435]2122{
2123    xptr_t      txt_rx_xp  = chdev_dir.txt_rx[channel];
2124    cxy_t       txt_rx_cxy = GET_CXY( txt_rx_xp );
2125    chdev_t *   txt_rx_ptr = GET_PTR( txt_rx_xp );
2126
[564]2127    return (xptr_t)hal_remote_l64( XPTR( txt_rx_cxy , &txt_rx_ptr->ext.txt.owner_xp ) );
[435]2128
[457]2129}  // end process_txt_get_owner()
2130
[435]2131///////////////////////////////////////////
2132void process_txt_display( uint32_t txt_id )
2133{
2134    xptr_t      chdev_xp;
2135    cxy_t       chdev_cxy;
2136    chdev_t   * chdev_ptr;
2137    xptr_t      root_xp;
2138    xptr_t      lock_xp;
2139    xptr_t      current_xp;
2140    xptr_t      iter_xp;
[443]2141    cxy_t       txt0_cxy;
2142    chdev_t   * txt0_ptr;
2143    xptr_t      txt0_xp;
2144    xptr_t      txt0_lock_xp;
2145   
[435]2146    assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
[492]2147    "illegal TXT terminal index" );
[435]2148
[443]2149    // get pointers on TXT0 chdev
2150    txt0_xp  = chdev_dir.txt_tx[0];
2151    txt0_cxy = GET_CXY( txt0_xp );
2152    txt0_ptr = GET_PTR( txt0_xp );
2153
2154    // get extended pointer on TXT0 lock
2155    txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
2156
[435]2157    // get pointers on TXT_RX[txt_id] chdev
2158    chdev_xp  = chdev_dir.txt_rx[txt_id];
2159    chdev_cxy = GET_CXY( chdev_xp );
2160    chdev_ptr = GET_PTR( chdev_xp );
2161
2162    // get extended pointer on root & lock of attached process list
2163    root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
2164    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
2165
[443]2166    // get lock on attached process list
[564]2167    remote_busylock_acquire( lock_xp );
[443]2168
2169    // get TXT0 lock in busy waiting mode
[564]2170    remote_busylock_acquire( txt0_lock_xp );
[443]2171
[435]2172    // display header
[443]2173    nolock_printk("\n***** processes attached to TXT_%d / cycle %d\n",
2174    txt_id , (uint32_t)hal_get_cycles() );
[435]2175
[436]2176    // scan attached process list
[435]2177    XLIST_FOREACH( root_xp , iter_xp )
2178    {
2179        current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2180        process_display( current_xp );
2181    }
2182
[443]2183    // release TXT0 lock in busy waiting mode
[564]2184    remote_busylock_release( txt0_lock_xp );
[443]2185
2186    // release lock on attached process list
[564]2187    remote_busylock_release( lock_xp );
[435]2188
2189}  // end process_txt_display
Note: See TracBrowser for help on using the repository browser.