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

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

blip

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