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

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

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