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

Last change on this file since 618 was 618, checked in by alain, 3 years ago

fix a bug in process_destroy() : the vmm_destroy() must be called before
the PID release.

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