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

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

1/ Fix a bug in the Multithreaded "sort" applicationr:
The pthread_create() arguments must be declared as global variables.
2/ The exit syscall can be called by any thread of a process..

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