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

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

Fix a bug in scheduler related to RPC blocking.

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