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

Last change on this file since 619 was 619, checked in by alain, 5 years ago

1) Fix a bug in KSH : after the "load" command,

the [ksh] prompt is now printed after completion
of the loaded application.

2) Fix a bug in vmm_handle_cow() : the copy-on-write

use now a hal_remote_memcpy() to replicate the page content.


File size: 78.5 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    thread_t         * client;            // pointer on client thread
531    xptr_t             client_xp;         // extended pointer on client thread
532    process_t        * local;             // pointer on process copy in local cluster
533    uint32_t           remote_nr;         // number of remote process copies
534    rpc_desc_t         rpc;               // shared RPC descriptor
535    uint32_t           responses;         // shared RPC responses counter
536
537    client    = CURRENT_THREAD;
538    client_xp = XPTR( local_cxy , client );
539    local     = NULL;
540    remote_nr = 0;
541
542    // check calling thread can yield
543    thread_assert_can_yield( client , __FUNCTION__ );
544
545#if DEBUG_PROCESS_SIGACTION
546uint32_t cycle = (uint32_t)hal_get_cycles();
547if( DEBUG_PROCESS_SIGACTION < cycle )
548printk("\n[%s] thread[%x,%x] enter to %s process %x / cycle %d\n",
549__FUNCTION__ , client->process->pid, client->trdid,
550process_action_str( type ) , pid , cycle );
551#endif
552
553    // get pointer on local cluster manager
554    cluster = LOCAL_CLUSTER;
555
556    // get owner cluster identifier and process lpid
557    owner_cxy = CXY_FROM_PID( pid );
558    lpid      = LPID_FROM_PID( pid );
559
560    // get root of list of copies and lock from owner cluster
561    root_xp   = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
562    lock_xp   = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
563
564// check action type
565assert( ((type == DELETE_ALL_THREADS ) ||
566         (type == BLOCK_ALL_THREADS )  ||
567         (type == UNBLOCK_ALL_THREADS )), "illegal action type" );
568             
569    // This client thread send parallel RPCs to all remote clusters containing
570    // target process copies, wait all responses, and then handles directly
571    // the threads in local cluster, when required.
572    // The client thread allocates a - shared - RPC descriptor in the stack,
573    // because all parallel, non-blocking, server threads use the same input
574    // arguments, and use the shared RPC response field
575
576    // mask IRQs
577    hal_disable_irq( &save_sr);
578
579    // client thread blocks itself
580    thread_block( client_xp , THREAD_BLOCKED_RPC );
581
582    // initialize RPC responses counter
583    responses = 0;
584
585    // initialize shared RPC descriptor
586    // can be shared, because no out arguments
587    rpc.rsp       = &responses;
588    rpc.blocking  = false;
589    rpc.index     = RPC_PROCESS_SIGACTION;
590    rpc.thread    = client;
591    rpc.lid       = client->core->lid;
592    rpc.args[0]   = pid;
593    rpc.args[1]   = type;
594
595    // take the lock protecting process copies
596    remote_queuelock_acquire( lock_xp );
597
598    // scan list of process copies
599    XLIST_FOREACH( root_xp , iter_xp )
600    {
601        // get extended pointers and cluster on process
602        process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
603        process_cxy = GET_CXY( process_xp );
604        process_ptr = GET_PTR( process_xp );
605
606        if( process_cxy == local_cxy )    // process copy is local
607        { 
608            local = process_ptr;
609        }
610        else                              // process copy is remote
611        {
612            // update number of remote process copies
613            remote_nr++;
614
615            // atomically increment RPC responses counter
616            hal_atomic_add( &responses , 1 );
617
618#if DEBUG_PROCESS_SIGACTION
619if( DEBUG_PROCESS_SIGACTION < cycle )
620printk("\n[%s] thread[%x,%x] send RPC to cluster %x for process %x\n",
621__FUNCTION__, client->process->pid, client->trdid, process_cxy, pid );
622#endif
623            // call RPC in target cluster
624            rpc_send( process_cxy , &rpc );
625        }
626    }  // end list of copies
627
628    // release the lock protecting process copies
629    remote_queuelock_release( lock_xp );
630
631    // restore IRQs
632    hal_restore_irq( save_sr);
633
634    // - if there is remote process copies, the client thread deschedules,
635    //   (it will be unblocked by the last RPC server thread).
636    // - if there is no remote copies, the client thread unblock itself.
637    if( remote_nr )
638    {
639        sched_yield("blocked on rpc_process_sigaction");
640    } 
641    else
642    {
643        thread_unblock( client_xp , THREAD_BLOCKED_RPC );
644    }
645
646    // handle the local process copy if required
647    if( local != NULL )
648    {
649
650#if DEBUG_PROCESS_SIGACTION
651if( DEBUG_PROCESS_SIGACTION < cycle )
652printk("\n[%s] thread[%x,%x] handles local process %x in cluster %x\n",
653__FUNCTION__, client->process->pid, client->trdid, pid , local_cxy );
654#endif
655        if     (type == DELETE_ALL_THREADS  ) process_delete_threads ( local , client_xp ); 
656        else if(type == BLOCK_ALL_THREADS   ) process_block_threads  ( local ); 
657        else if(type == UNBLOCK_ALL_THREADS ) process_unblock_threads( local );
658    }
659
660#if DEBUG_PROCESS_SIGACTION
661cycle = (uint32_t)hal_get_cycles();
662if( DEBUG_PROCESS_SIGACTION < cycle )
663printk("\n[%s] thread[%x,%x] exit after %s process %x / cycle %d\n",
664__FUNCTION__, client->process->pid, client->trdid,
665process_action_str( type ), pid, cycle );
666#endif
667
668}  // end process_sigaction()
669
670/////////////////////////////////////////////////
671void process_block_threads( process_t * process )
672{
673    thread_t          * target;         // pointer on target thread
674    thread_t          * this;           // pointer on calling thread
675    uint32_t            ltid;           // index in process th_tbl[]
676    cxy_t               owner_cxy;      // target process owner cluster
677    uint32_t            count;          // requests counter
678    volatile uint32_t   ack_count;      // acknowledges counter
679
680    // get calling thread pointer
681    this = CURRENT_THREAD;
682
683#if DEBUG_PROCESS_SIGACTION
684pid_t pid = process->pid;
685uint32_t cycle = (uint32_t)hal_get_cycles();
686if( DEBUG_PROCESS_SIGACTION < cycle )
687printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
688__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy , cycle );
689#endif
690
691// check target process is an user process
692assert( (LPID_FROM_PID( process->pid ) != 0 ),
693"process %x is not an user process\n", process->pid );
694
695    // get target process owner cluster
696    owner_cxy = CXY_FROM_PID( process->pid );
697
698    // get lock protecting process th_tbl[]
699    rwlock_rd_acquire( &process->th_lock );
700
701    // loop on target process local threads
702    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
703    // - if the calling thread and the target thread are not running on the same
704    //   core, we ask the target scheduler to acknowlege the blocking
705    //   to be sure that the target thread is not running.
706    // - if the calling thread and the target thread are running on the same core,
707    //   we don't need confirmation from scheduler.
708           
709    for( ltid = 0 , count = 0 , ack_count = 0 ; count < process->th_nr ; ltid++ )
710    {
711        target = process->th_tbl[ltid];
712
713        if( target != NULL )                                 // thread exist
714        {
715            count++;
716
717            // set the global blocked bit in target thread descriptor.
718            thread_block( XPTR( local_cxy , target ) , THREAD_BLOCKED_GLOBAL );
719 
720            if( this->core->lid != target->core->lid )
721            {
722                // increment responses counter
723                hal_atomic_add( (void*)&ack_count , 1 );
724
725                // set FLAG_REQ_ACK and &ack_rsp_count in target descriptor
726                thread_set_req_ack( target , (uint32_t *)&ack_count );
727
728                // force scheduling on target thread
729                dev_pic_send_ipi( local_cxy , target->core->lid );
730            }
731        }
732    }
733
734    // release lock protecting process th_tbl[]
735    rwlock_rd_release( &process->th_lock );
736
737    // wait other threads acknowledges  TODO this could be improved...
738    while( 1 )
739    {
740        // exit when all scheduler acknowledges received
741        if ( ack_count == 0 ) break;
742   
743        // wait 1000 cycles before retry
744        hal_fixed_delay( 1000 );
745    }
746
747#if DEBUG_PROCESS_SIGACTION
748cycle = (uint32_t)hal_get_cycles();
749if( DEBUG_PROCESS_SIGACTION < cycle )
750printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
751__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy , cycle );
752#endif
753
754}  // end process_block_threads()
755
756/////////////////////////////////////////////////
757void process_delete_threads( process_t * process,
758                             xptr_t      client_xp )
759{
760    thread_t          * this;          // pointer on calling thread
761    thread_t          * target;        // local pointer on target thread
762    xptr_t              target_xp;     // extended pointer on target thread
763    cxy_t               owner_cxy;     // owner process cluster
764    uint32_t            ltid;          // index in process th_tbl
765    uint32_t            count;         // threads counter
766
767    // get calling thread pointer
768    this = CURRENT_THREAD;
769
770    // get target process owner cluster
771    owner_cxy = CXY_FROM_PID( process->pid );
772
773#if DEBUG_PROCESS_SIGACTION
774uint32_t cycle = (uint32_t)hal_get_cycles();
775if( DEBUG_PROCESS_SIGACTION < cycle )
776printk("\n[%s] thread[%x,%x] enter in cluster %x for process %x / cycle %d\n",
777__FUNCTION__, this->process->pid, this->trdid, local_cxy, process->pid, cycle );
778#endif
779
780// check target process is an user process
781assert( (LPID_FROM_PID( process->pid ) != 0),
782"process %x is not an user process\n", process->pid );
783
784    // get lock protecting process th_tbl[]
785    rwlock_wr_acquire( &process->th_lock );
786
787    // loop on target process local threads                       
788    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
789    for( ltid = 0 , count = 0  ; count < process->th_nr ; ltid++ )
790    {
791        target = process->th_tbl[ltid];
792
793        if( target != NULL )    // valid thread 
794        {
795            count++;
796            target_xp = XPTR( local_cxy , target );
797
798            // main thread and client thread should not be deleted
799            if( ((ltid != 0) || (owner_cxy != local_cxy)) &&         // not main thread
800                (client_xp) != target_xp )                           // not client thread
801            {
802                // mark target thread for delete and block it
803                thread_delete( target_xp , process->pid , false );   // not forced
804            }
805        }
806    }
807
808    // release lock protecting process th_tbl[]
809    rwlock_wr_release( &process->th_lock );
810
811#if DEBUG_PROCESS_SIGACTION
812cycle = (uint32_t)hal_get_cycles();
813if( DEBUG_PROCESS_SIGACTION < cycle )
814printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
815__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy , cycle );
816#endif
817
818}  // end process_delete_threads()
819
820///////////////////////////////////////////////////
821void process_unblock_threads( process_t * process )
822{
823    thread_t          * target;        // pointer on target thead
824    thread_t          * this;          // pointer on calling thread
825    uint32_t            ltid;          // index in process th_tbl
826    uint32_t            count;         // requests counter
827
828    // get calling thread pointer
829    this = CURRENT_THREAD;
830
831#if DEBUG_PROCESS_SIGACTION
832pid_t pid = process->pid;
833uint32_t cycle = (uint32_t)hal_get_cycles();
834if( DEBUG_PROCESS_SIGACTION < cycle )
835printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
836__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy , cycle );
837#endif
838
839// check target process is an user process
840assert( ( LPID_FROM_PID( process->pid ) != 0 ),
841"process %x is not an user process\n", process->pid );
842
843    // get lock protecting process th_tbl[]
844    rwlock_rd_acquire( &process->th_lock );
845
846    // loop on process threads to unblock all threads
847    // we use both "ltid" and "count" because it can exist "holes" in th_tbl
848    for( ltid = 0 , count = 0 ; count < process->th_nr ; ltid++ )
849    {
850        target = process->th_tbl[ltid];
851
852        if( target != NULL )             // thread found
853        {
854            count++;
855
856            // reset the global blocked bit in target thread descriptor.
857            thread_unblock( XPTR( local_cxy , target ) , THREAD_BLOCKED_GLOBAL );
858        }
859    }
860
861    // release lock protecting process th_tbl[]
862    rwlock_rd_release( &process->th_lock );
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_unblock_threads()
872
873///////////////////////////////////////////////
874process_t * process_get_local_copy( pid_t pid )
875{
876    error_t        error;
877    process_t    * process_ptr;   // local pointer on process
878    xptr_t         process_xp;    // extended pointer on process
879
880    cluster_t * cluster = LOCAL_CLUSTER;
881
882#if DEBUG_PROCESS_GET_LOCAL_COPY
883thread_t * this = CURRENT_THREAD;
884uint32_t cycle = (uint32_t)hal_get_cycles();
885if( DEBUG_PROCESS_GET_LOCAL_COPY < cycle )
886printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
887__FUNCTION__, this->process->pid, this->trdid, pid, local_cxy, cycle );
888#endif
889
890    // get lock protecting local list of processes
891    remote_queuelock_acquire( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
892
893    // scan the local list of process descriptors to find the process
894    xptr_t  iter;
895    bool_t  found = false;
896    XLIST_FOREACH( XPTR( local_cxy , &cluster->pmgr.local_root ) , iter )
897    {
898        process_xp  = XLIST_ELEMENT( iter , process_t , local_list );
899        process_ptr = GET_PTR( process_xp );
900        if( process_ptr->pid == pid )
901        {
902            found = true;
903            break;
904        }
905    }
906
907    // release lock protecting local list of processes
908    remote_queuelock_release( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
909
910    // allocate memory for a new local process descriptor
911    // and initialise it from reference cluster if not found
912    if( !found )
913    {
914        // get extended pointer on reference process descriptor
915        xptr_t ref_xp = cluster_get_reference_process_from_pid( pid );
916
917        assert( (ref_xp != XPTR_NULL) , "illegal pid\n" );
918
919        // allocate memory for local process descriptor
920        process_ptr = process_alloc();
921
922        if( process_ptr == NULL )  return NULL;
923
924        // initialize local process descriptor copy
925        error = process_copy_init( process_ptr , ref_xp );
926
927        if( error ) return NULL;
928    }
929
930#if DEBUG_PROCESS_GET_LOCAL_COPY
931cycle = (uint32_t)hal_get_cycles();
932if( DEBUG_PROCESS_GET_LOCAL_COPY < cycle )
933printk("\n[%s] thread[%x,%x] exit in cluster %x / process %x / cycle %d\n",
934__FUNCTION__, this->process->pid, this->trdid, local_cxy, process_ptr, cycle );
935#endif
936
937    return process_ptr;
938
939}  // end process_get_local_copy()
940
941////////////////////////////////////////////
942pid_t process_get_ppid( xptr_t  process_xp )
943{
944    cxy_t       process_cxy;
945    process_t * process_ptr;
946    xptr_t      parent_xp;
947    cxy_t       parent_cxy;
948    process_t * parent_ptr;
949
950    // get process cluster and local pointer
951    process_cxy = GET_CXY( process_xp );
952    process_ptr = GET_PTR( process_xp );
953
954    // get pointers on parent process
955    parent_xp  = (xptr_t)hal_remote_l64( XPTR( process_cxy , &process_ptr->parent_xp ) );
956    parent_cxy = GET_CXY( parent_xp );
957    parent_ptr = GET_PTR( parent_xp );
958
959    return hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
960}
961
962//////////////////////////////////////////////////////////////////////////////////////////
963// File descriptor array related functions
964//////////////////////////////////////////////////////////////////////////////////////////
965
966///////////////////////////////////////////
967void process_fd_init( process_t * process )
968{
969    uint32_t fd;
970
971    // initialize lock
972    remote_queuelock_init( XPTR( local_cxy , &process->fd_array.lock ), LOCK_PROCESS_FDARRAY );
973
974    // initialize number of open files
975    process->fd_array.current = 0;
976
977    // initialize array
978    for ( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
979    {
980        process->fd_array.array[fd] = XPTR_NULL;
981    }
982}
983////////////////////////////////////////////////////
984error_t process_fd_register( xptr_t      process_xp,
985                             xptr_t      file_xp,
986                             uint32_t  * fdid )
987{
988    bool_t    found;
989    uint32_t  id;
990    xptr_t    xp;
991
992    // get reference process cluster and local pointer
993    process_t * process_ptr = GET_PTR( process_xp );
994    cxy_t       process_cxy = GET_CXY( process_xp );
995
996// check client process is reference process
997assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp ) ) ),
998"client process must be reference process\n" );
999
1000#if DEBUG_PROCESS_FD_REGISTER
1001thread_t * this  = CURRENT_THREAD;
1002uint32_t   cycle = (uint32_t)hal_get_cycles();
1003pid_t      pid   = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
1004if( DEBUG_PROCESS_FD_REGISTER < cycle )
1005printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
1006__FUNCTION__, this->process->pid, this->trdid, pid, cycle );
1007#endif
1008
1009    // build extended pointer on lock protecting reference fd_array
1010    xptr_t lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
1011
1012    // take lock protecting reference fd_array
1013        remote_queuelock_acquire( lock_xp );
1014
1015    found   = false;
1016
1017    for ( id = 0; id < CONFIG_PROCESS_FILE_MAX_NR ; id++ )
1018    {
1019        xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
1020        if ( xp == XPTR_NULL )
1021        {
1022            // update reference fd_array
1023            hal_remote_s64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) , file_xp );
1024                hal_remote_atomic_add( XPTR( process_cxy , &process_ptr->fd_array.current ) , 1 );
1025
1026            // exit
1027                        *fdid = id;
1028            found = true;
1029            break;
1030        }
1031    }
1032
1033    // release lock protecting fd_array
1034        remote_queuelock_release( lock_xp );
1035
1036#if DEBUG_PROCESS_FD_REGISTER
1037cycle = (uint32_t)hal_get_cycles();
1038if( DEBUG_PROCESS_FD_REGISTER < cycle )
1039printk("\n[%s] thread[%x,%x] exit for process %x / fdid %d / cycle %d\n",
1040__FUNCTION__, this->process->pid, this->trdid, pid, id, cycle );
1041#endif
1042
1043    if ( !found ) return -1;
1044    else          return 0;
1045
1046}  // end process_fd_register()
1047
1048////////////////////////////////////////////////
1049xptr_t process_fd_get_xptr( process_t * process,
1050                            uint32_t    fdid )
1051{
1052    xptr_t  file_xp;
1053    xptr_t  lock_xp;
1054
1055    // access local copy of process descriptor
1056    file_xp = process->fd_array.array[fdid];
1057
1058    if( file_xp == XPTR_NULL )
1059    {
1060        // get reference process cluster and local pointer
1061        xptr_t      ref_xp  = process->ref_xp;
1062        cxy_t       ref_cxy = GET_CXY( ref_xp );
1063        process_t * ref_ptr = GET_PTR( ref_xp );
1064
1065        // build extended pointer on lock protecting reference fd_array
1066        lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
1067
1068        // take lock protecting reference fd_array
1069            remote_queuelock_acquire( lock_xp );
1070
1071        // access reference process descriptor
1072        file_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->fd_array.array[fdid] ) );
1073
1074        // update local fd_array if found
1075        if( file_xp != XPTR_NULL )  process->fd_array.array[fdid] = file_xp;
1076       
1077        // release lock protecting reference fd_array
1078            remote_queuelock_release( lock_xp );
1079    }
1080
1081    return file_xp;
1082
1083}  // end process_fd_get_xptr()
1084
1085///////////////////////////////////////////
1086void process_fd_remote_copy( xptr_t dst_xp,
1087                             xptr_t src_xp )
1088{
1089    uint32_t fd;
1090    xptr_t   entry;
1091
1092    // get cluster and local pointer for src fd_array
1093    cxy_t        src_cxy = GET_CXY( src_xp );
1094    fd_array_t * src_ptr = GET_PTR( src_xp );
1095
1096    // get cluster and local pointer for dst fd_array
1097    cxy_t        dst_cxy = GET_CXY( dst_xp );
1098    fd_array_t * dst_ptr = GET_PTR( dst_xp );
1099
1100    // get the remote lock protecting the src fd_array
1101        remote_queuelock_acquire( XPTR( src_cxy , &src_ptr->lock ) );
1102
1103    // loop on all fd_array entries
1104    for( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
1105        {
1106                entry = (xptr_t)hal_remote_l64( XPTR( src_cxy , &src_ptr->array[fd] ) );
1107
1108                if( entry != XPTR_NULL )
1109                {
1110            // increment file descriptor refcount
1111            vfs_file_count_up( entry );
1112
1113                        // copy entry in destination process fd_array
1114                        hal_remote_s64( XPTR( dst_cxy , &dst_ptr->array[fd] ) , entry );
1115                }
1116        }
1117
1118    // release lock on source process fd_array
1119        remote_queuelock_release( XPTR( src_cxy , &src_ptr->lock ) );
1120
1121}  // end process_fd_remote_copy()
1122
1123
1124////////////////////////////////////
1125bool_t process_fd_array_full( void )
1126{
1127    // get extended pointer on reference process
1128    xptr_t ref_xp = CURRENT_THREAD->process->ref_xp;
1129
1130    // get reference process cluster and local pointer
1131    process_t * ref_ptr = GET_PTR( ref_xp );
1132    cxy_t       ref_cxy = GET_CXY( ref_xp );
1133
1134    // get number of open file descriptors from reference fd_array
1135    uint32_t current = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->fd_array.current ) );
1136
1137        return ( current >= CONFIG_PROCESS_FILE_MAX_NR );
1138}
1139
1140
1141////////////////////////////////////////////////////////////////////////////////////
1142//  Thread related functions
1143////////////////////////////////////////////////////////////////////////////////////
1144
1145/////////////////////////////////////////////////////
1146error_t process_register_thread( process_t * process,
1147                                 thread_t  * thread,
1148                                 trdid_t   * trdid )
1149{
1150    ltid_t         ltid;
1151    bool_t         found = false;
1152 
1153// check arguments
1154assert( (process != NULL) , "process argument is NULL" );
1155assert( (thread != NULL) , "thread argument is NULL" );
1156
1157    // get the lock protecting th_tbl for all threads
1158    // but the idle thread executing kernel_init (cannot yield)
1159    if( thread->type != THREAD_IDLE ) rwlock_wr_acquire( &process->th_lock );
1160
1161    // scan th_tbl
1162    for( ltid = 0 ; ltid < CONFIG_THREADS_MAX_PER_CLUSTER ; ltid++ )
1163    {
1164        if( process->th_tbl[ltid] == NULL )
1165        {
1166            found = true;
1167            break;
1168        }
1169    }
1170
1171    if( found )
1172    {
1173        // register thread in th_tbl[]
1174        process->th_tbl[ltid] = thread;
1175        process->th_nr++;
1176
1177        // returns trdid
1178        *trdid = TRDID( local_cxy , ltid );
1179    }
1180
1181    // release the lock protecting th_tbl
1182    if( thread->type != THREAD_IDLE ) rwlock_wr_release( &process->th_lock );
1183
1184    return (found) ? 0 : 0xFFFFFFFF;
1185
1186}  // end process_register_thread()
1187
1188/////////////////////////////////////////////////
1189bool_t process_remove_thread( thread_t * thread )
1190{
1191    uint32_t count;  // number of threads in local process descriptor
1192
1193    process_t * process = thread->process;
1194
1195    // get thread local index
1196    ltid_t  ltid = LTID_FROM_TRDID( thread->trdid );
1197   
1198    // get the lock protecting th_tbl[]
1199    rwlock_wr_acquire( &process->th_lock );
1200
1201    // get number of threads
1202    count = process->th_nr;
1203
1204// check thread
1205assert( (thread != NULL) , "thread argument is NULL" );
1206
1207// check th_nr value
1208assert( (count > 0) , "process th_nr cannot be 0\n" );
1209
1210    // remove thread from th_tbl[]
1211    process->th_tbl[ltid] = NULL;
1212    process->th_nr = count-1;
1213
1214    // release lock protecting th_tbl
1215    rwlock_wr_release( &process->th_lock );
1216
1217    return (count == 1);
1218
1219}  // end process_remove_thread()
1220
1221/////////////////////////////////////////////////////////
1222error_t process_make_fork( xptr_t      parent_process_xp,
1223                           xptr_t      parent_thread_xp,
1224                           pid_t     * child_pid,
1225                           thread_t ** child_thread )
1226{
1227    process_t * process;         // local pointer on child process descriptor
1228    thread_t  * thread;          // local pointer on child thread descriptor
1229    pid_t       new_pid;         // process identifier for child process
1230    pid_t       parent_pid;      // process identifier for parent process
1231    xptr_t      ref_xp;          // extended pointer on reference process
1232    xptr_t      vfs_bin_xp;      // extended pointer on .elf file
1233    error_t     error;
1234
1235    // get cluster and local pointer for parent process
1236    cxy_t       parent_process_cxy = GET_CXY( parent_process_xp );
1237    process_t * parent_process_ptr = GET_PTR( parent_process_xp );
1238
1239    // get parent process PID and extended pointer on .elf file
1240    parent_pid = hal_remote_l32 (XPTR( parent_process_cxy , &parent_process_ptr->pid));
1241    vfs_bin_xp = hal_remote_l64(XPTR( parent_process_cxy , &parent_process_ptr->vfs_bin_xp));
1242
1243    // get extended pointer on reference process
1244    ref_xp = hal_remote_l64( XPTR( parent_process_cxy , &parent_process_ptr->ref_xp ) );
1245
1246// check parent process is the reference process
1247assert( (parent_process_xp == ref_xp ) ,
1248"parent process must be the reference process\n" );
1249
1250#if DEBUG_PROCESS_MAKE_FORK
1251uint32_t cycle   = (uint32_t)hal_get_cycles();
1252thread_t * this  = CURRENT_THREAD;
1253trdid_t    trdid = this->trdid;
1254pid_t      pid   = this->process->pid;
1255if( DEBUG_PROCESS_MAKE_FORK < cycle )
1256printk("\n[%s] thread[%x,%x] enter / cluster %x / cycle %d\n",
1257__FUNCTION__, pid, trdid, local_cxy, cycle );
1258#endif
1259
1260    // allocate a process descriptor
1261    process = process_alloc();
1262    if( process == NULL )
1263    {
1264        printk("\n[ERROR] in %s : cannot get process in cluster %x\n", 
1265        __FUNCTION__, local_cxy ); 
1266        return -1;
1267    }
1268
1269    // allocate a child PID from local cluster
1270    error = cluster_pid_alloc( process , &new_pid );
1271    if( error ) 
1272    {
1273        printk("\n[ERROR] in %s : cannot get PID in cluster %x\n", 
1274        __FUNCTION__, local_cxy ); 
1275        process_free( process );
1276        return -1;
1277    }
1278
1279#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1280cycle = (uint32_t)hal_get_cycles();
1281if( DEBUG_PROCESS_MAKE_FORK < cycle )
1282printk("\n[%s] thread[%x,%x] allocated process %x / cycle %d\n",
1283__FUNCTION__, pid, trdid, new_pid, cycle );
1284#endif
1285
1286    // initializes child process descriptor from parent process descriptor
1287    process_reference_init( process,
1288                            new_pid,
1289                            parent_process_xp );
1290
1291#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1292cycle = (uint32_t)hal_get_cycles();
1293if( DEBUG_PROCESS_MAKE_FORK < cycle )
1294printk("\n[%s] thread[%x,%x] initialized child_process %x / cycle %d\n",
1295__FUNCTION__, pid, trdid, new_pid, cycle );
1296#endif
1297
1298
1299    // copy VMM from parent descriptor to child descriptor
1300    error = vmm_fork_copy( process,
1301                           parent_process_xp );
1302    if( error )
1303    {
1304        printk("\n[ERROR] in %s : cannot copy VMM in cluster %x\n", 
1305        __FUNCTION__, local_cxy ); 
1306        process_free( process );
1307        cluster_pid_release( new_pid );
1308        return -1;
1309    }
1310
1311#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1312cycle = (uint32_t)hal_get_cycles();
1313if( DEBUG_PROCESS_MAKE_FORK < cycle )
1314printk("\n[%s] thread[%x,%x] copied VMM from parent to child / cycle %d\n",
1315__FUNCTION__, pid, trdid, cycle );
1316#endif
1317
1318    // if parent_process is INIT, or if parent_process is the TXT owner,
1319    // the child_process becomes the owner of its TXT terminal
1320    if( (parent_pid == 1) || process_txt_is_owner( parent_process_xp ) )
1321    {
1322        process_txt_set_ownership( XPTR( local_cxy , process ) );
1323
1324#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1325cycle = (uint32_t)hal_get_cycles();
1326if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1327printk("\n[%s] thread[%x,%x] / child takes TXT ownership / cycle %d\n",
1328__FUNCTION__ , pid, trdid, cycle );
1329#endif
1330
1331    }
1332
1333    // update extended pointer on .elf file
1334    process->vfs_bin_xp = vfs_bin_xp;
1335
1336    // create child thread descriptor from parent thread descriptor
1337    error = thread_user_fork( parent_thread_xp,
1338                              process,
1339                              &thread );
1340    if( error )
1341    {
1342        printk("\n[ERROR] in %s : cannot create thread in cluster %x\n",
1343        __FUNCTION__, local_cxy ); 
1344        process_free( process );
1345        cluster_pid_release( new_pid );
1346        return -1;
1347    }
1348
1349// check main thread LTID
1350assert( (LTID_FROM_TRDID(thread->trdid) == 0) ,
1351"main thread must have LTID == 0\n" );
1352
1353#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1354cycle = (uint32_t)hal_get_cycles();
1355if( DEBUG_PROCESS_MAKE_FORK < cycle )
1356printk("\n[%s] thread[%x,%x] created main thread %x / cycle %d\n", 
1357__FUNCTION__, pid, trdid, thread, cycle );
1358#endif
1359
1360    // set Copy_On_Write flag in parent process GPT
1361    // this includes all replicated GPT copies
1362    if( parent_process_cxy == local_cxy )   // reference is local
1363    {
1364        vmm_set_cow( parent_process_ptr );
1365    }
1366    else                                    // reference is remote
1367    {
1368        rpc_vmm_set_cow_client( parent_process_cxy,
1369                                parent_process_ptr );
1370    }
1371
1372    // set Copy_On_Write flag in child process GPT
1373    vmm_set_cow( process );
1374 
1375#if( DEBUG_PROCESS_MAKE_FORK & 1 )
1376cycle = (uint32_t)hal_get_cycles();
1377if( DEBUG_PROCESS_MAKE_FORK < cycle )
1378printk("\n[%s] thread[%x,%x] set COW in parent and child / cycle %d\n",
1379__FUNCTION__, pid, trdid, cycle );
1380#endif
1381
1382    // get extended pointers on parent children_root, children_lock and children_nr
1383    xptr_t children_root_xp = XPTR( parent_process_cxy , &parent_process_ptr->children_root );
1384    xptr_t children_lock_xp = XPTR( parent_process_cxy , &parent_process_ptr->children_lock );
1385    xptr_t children_nr_xp   = XPTR( parent_process_cxy , &parent_process_ptr->children_nr   );
1386
1387    // register process in parent children list
1388    remote_queuelock_acquire( children_lock_xp );
1389        xlist_add_last( children_root_xp , XPTR( local_cxy , &process->children_list ) );
1390        hal_remote_atomic_add( children_nr_xp , 1 );
1391    remote_queuelock_release( children_lock_xp );
1392
1393    // return success
1394    *child_thread = thread;
1395    *child_pid    = new_pid;
1396
1397#if DEBUG_PROCESS_MAKE_FORK
1398cycle = (uint32_t)hal_get_cycles();
1399if( DEBUG_PROCESS_MAKE_FORK < cycle )
1400printk("\n[%s] thread[%x,%x] exit / created process %x / cycle %d\n",
1401__FUNCTION__, pid, trdid, new_pid, cycle );
1402#endif
1403
1404    return 0;
1405
1406}   // end process_make_fork()
1407
1408/////////////////////////////////////////////////////
1409error_t process_make_exec( exec_info_t  * exec_info )
1410{
1411    thread_t       * thread;                  // local pointer on this thread
1412    process_t      * process;                 // local pointer on this process
1413    pid_t            pid;                     // this process identifier
1414    xptr_t           ref_xp;                  // reference process for this process
1415        error_t          error;                   // value returned by called functions
1416    char           * path;                    // path to .elf file
1417    xptr_t           file_xp;                 // extended pointer on .elf file descriptor
1418    uint32_t         file_id;                 // file index in fd_array
1419    uint32_t         args_nr;                 // number of main thread arguments
1420    char          ** args_pointers;           // array of pointers on main thread arguments
1421
1422    // get thread, process, pid and ref_xp
1423    thread  = CURRENT_THREAD;
1424    process = thread->process;
1425    pid     = process->pid;
1426    ref_xp  = process->ref_xp;
1427
1428        // get relevant infos from exec_info
1429        path          = exec_info->path;
1430    args_nr       = exec_info->args_nr;
1431    args_pointers = exec_info->args_pointers;
1432
1433#if DEBUG_PROCESS_MAKE_EXEC
1434uint32_t cycle = (uint32_t)hal_get_cycles();
1435if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1436printk("\n[%s] thread[%x,%x] enters for %s / cycle %d\n",
1437__FUNCTION__, pid, thread->trdid, path, cycle );
1438#endif
1439
1440    // open the file identified by <path>
1441    file_xp = XPTR_NULL;
1442    file_id = 0xFFFFFFFF;
1443        error   = vfs_open( process->vfs_root_xp,
1444                            path,
1445                        ref_xp,
1446                            O_RDONLY,
1447                            0,
1448                            &file_xp,
1449                            &file_id );
1450        if( error )
1451        {
1452                printk("\n[ERROR] in %s : failed to open file <%s>\n", __FUNCTION__ , path );
1453                return -1;
1454        }
1455
1456#if (DEBUG_PROCESS_MAKE_EXEC & 1)
1457cycle = (uint32_t)hal_get_cycles();
1458if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1459printk("\n[%s] thread[%x,%x] opened file <%s> / cycle %d\n",
1460__FUNCTION__, pid, thread->trdid, path, cycle );
1461#endif
1462
1463    // delete all threads other than this main thread in all clusters
1464    process_sigaction( pid , DELETE_ALL_THREADS );
1465
1466#if (DEBUG_PROCESS_MAKE_EXEC & 1)
1467cycle = (uint32_t)hal_get_cycles();
1468if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1469printk("\n[%s] thread[%x,%x] deleted all threads / cycle %d\n",
1470__FUNCTION__, pid, thread->trdid, cycle );
1471#endif
1472
1473    // reset local process VMM
1474    vmm_destroy( process );
1475
1476#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
1477cycle = (uint32_t)hal_get_cycles();
1478if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1479printk("\n[%s] thread[%x,%x] reset VMM / cycle %d\n",
1480__FUNCTION__, pid, thread->trdid, cycle );
1481#endif
1482
1483    // re-initialize the VMM (kentry/args/envs vsegs registration)
1484    error = vmm_init( process );
1485    if( error )
1486    {
1487        printk("\n[ERROR] in %s : cannot initialise VMM for %s\n", __FUNCTION__ , path );
1488        vfs_close( file_xp , file_id );
1489        // FIXME restore old process VMM
1490        return -1;
1491    }
1492   
1493#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
1494cycle = (uint32_t)hal_get_cycles();
1495if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1496printk("\n[%s] thread[%x,%x] / kentry/args/envs vsegs registered / cycle %d\n",
1497__FUNCTION__, pid, thread->trdid, cycle );
1498#endif
1499
1500    // register code & data vsegs as well as entry-point in process VMM,
1501    // and register extended pointer on .elf file in process descriptor
1502        error = elf_load_process( file_xp , process );
1503    if( error )
1504        {
1505                printk("\n[ERROR] in %s : failed to access <%s>\n", __FUNCTION__ , path );
1506        vfs_close( file_xp , file_id );
1507        // FIXME restore old process VMM
1508        return -1;
1509        }
1510
1511#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
1512cycle = (uint32_t)hal_get_cycles();
1513if( DEBUG_PROCESS_MAKE_EXEC < cycle )
1514printk("\n[%s] thread[%x,%x] / code/data vsegs registered / cycle %d\n",
1515__FUNCTION__, pid, thread->trdid, cycle );
1516#endif
1517
1518    // update the existing main thread descriptor... and jump to user code
1519    error = thread_user_exec( (void *)process->vmm.entry_point,
1520                              args_nr,
1521                              args_pointers );
1522    if( error )
1523    {
1524        printk("\n[ERROR] in %s : cannot update main thread for %s\n", __FUNCTION__ , path );
1525        vfs_close( file_xp , file_id );
1526        // FIXME restore old process VMM
1527        return -1;
1528    }
1529
1530    assert( false, "we should not execute this code");
1531 
1532        return 0;
1533
1534}  // end process_make_exec()
1535
1536
1537///////////////////////////////////////////////
1538void process_zero_create( process_t * process )
1539{
1540    error_t error;
1541    pid_t   pid;
1542
1543#if DEBUG_PROCESS_ZERO_CREATE
1544uint32_t cycle = (uint32_t)hal_get_cycles();
1545if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1546printk("\n[%s] enter / cluster %x / cycle %d\n",
1547__FUNCTION__, local_cxy, cycle );
1548#endif
1549
1550    // get PID from local cluster manager for this kernel process
1551    error = cluster_pid_alloc( process , &pid );
1552
1553    if( error || (LPID_FROM_PID( pid ) != 0) )
1554    {
1555        printk("\n[PANIC] in %s : cannot get valid PID in cluster %x / PID = %x\n",
1556        __FUNCTION__ , local_cxy, pid );
1557        hal_core_sleep();
1558    }
1559
1560    // initialize PID, REF_XP, PARENT_XP, and STATE
1561    // the kernel process_zero is its own parent_process,
1562    // reference_process, and owner_process, and cannot be killed...
1563    process->pid        = pid;
1564    process->ref_xp     = XPTR( local_cxy , process );
1565    process->owner_xp   = XPTR( local_cxy , process );
1566    process->parent_xp  = XPTR( local_cxy , process );
1567    process->term_state = 0;
1568
1569    // reset th_tbl[] array and associated fields
1570    uint32_t i;
1571    for( i = 0 ; i < CONFIG_THREADS_MAX_PER_CLUSTER ; i++ )
1572        {
1573        process->th_tbl[i] = NULL;
1574    }
1575    process->th_nr  = 0;
1576    rwlock_init( &process->th_lock , LOCK_PROCESS_THTBL );
1577
1578
1579    // reset children list as empty
1580    xlist_root_init( XPTR( local_cxy , &process->children_root ) );
1581    process->children_nr = 0;
1582    remote_queuelock_init( XPTR( local_cxy , &process->children_lock ),
1583                           LOCK_PROCESS_CHILDREN );
1584
1585    // register kernel process in cluster manager local_list
1586    cluster_process_local_link( process );
1587   
1588        hal_fence();
1589
1590#if DEBUG_PROCESS_ZERO_CREATE
1591cycle = (uint32_t)hal_get_cycles();
1592if( DEBUG_PROCESS_ZERO_CREATE < cycle )
1593printk("\n[%s] exit / cluster %x / cycle %d\n",
1594__FUNCTION__, local_cxy, cycle );
1595#endif
1596
1597}  // end process_zero_create()
1598
1599////////////////////////////////
1600void process_init_create( void )
1601{
1602    process_t      * process;       // local pointer on process descriptor
1603    pid_t            pid;           // process_init identifier
1604    thread_t       * thread;        // local pointer on main thread
1605    pthread_attr_t   attr;          // main thread attributes
1606    lid_t            lid;           // selected core local index for main thread
1607    xptr_t           file_xp;       // extended pointer on .elf file descriptor
1608    uint32_t         file_id;       // file index in fd_array
1609    error_t          error;
1610
1611#if DEBUG_PROCESS_INIT_CREATE
1612thread_t * this = CURRENT_THREAD;
1613uint32_t cycle = (uint32_t)hal_get_cycles();
1614if( DEBUG_PROCESS_INIT_CREATE < cycle )
1615printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1616__FUNCTION__, this->process->pid, this->trdid, cycle );
1617#endif
1618
1619    // allocates memory for process descriptor from local cluster
1620        process = process_alloc(); 
1621       
1622// check memory allocator
1623assert( (process != NULL),
1624"no memory for process descriptor in cluster %x\n", local_cxy  );
1625
1626    // set the CWD and VFS_ROOT fields in process descriptor
1627    process->cwd_xp      = process_zero.vfs_root_xp;
1628    process->vfs_root_xp = process_zero.vfs_root_xp;
1629
1630    // get PID from local cluster
1631    error = cluster_pid_alloc( process , &pid );
1632
1633// check PID allocator
1634assert( (error == 0),
1635"cannot allocate PID in cluster %x\n", local_cxy );
1636
1637// check PID value
1638assert( (pid == 1) ,
1639"process INIT must be first process in cluster 0\n" );
1640
1641    // initialize process descriptor / parent is local process_zero
1642    process_reference_init( process,
1643                            pid,
1644                            XPTR( local_cxy , &process_zero ) ); 
1645
1646#if(DEBUG_PROCESS_INIT_CREATE & 1)
1647if( DEBUG_PROCESS_INIT_CREATE < cycle )
1648printk("\n[%s] thread[%x,%x] initialized process descriptor\n",
1649__FUNCTION__, this->process->pid, this->trdid );
1650#endif
1651
1652    // open the file identified by CONFIG_PROCESS_INIT_PATH
1653    file_xp = XPTR_NULL;
1654    file_id = -1;
1655        error   = vfs_open( process->vfs_root_xp,
1656                            CONFIG_PROCESS_INIT_PATH,
1657                        XPTR( local_cxy , process ),
1658                            O_RDONLY,
1659                            0,
1660                            &file_xp,
1661                            &file_id );
1662
1663assert( (error == 0),
1664"failed to open file <%s>\n", CONFIG_PROCESS_INIT_PATH );
1665
1666#if(DEBUG_PROCESS_INIT_CREATE & 1)
1667if( DEBUG_PROCESS_INIT_CREATE < cycle )
1668printk("\n[%s] thread[%x,%x] open .elf file decriptor\n",
1669__FUNCTION__, this->process->pid, this->trdid );
1670#endif
1671
1672   // register "code" and "data" vsegs as well as entry-point
1673    // in process VMM, using information contained in the elf file.
1674        error = elf_load_process( file_xp , process );
1675
1676assert( (error == 0),
1677"cannot access .elf file <%s>\n", CONFIG_PROCESS_INIT_PATH );
1678
1679#if(DEBUG_PROCESS_INIT_CREATE & 1)
1680if( DEBUG_PROCESS_INIT_CREATE < cycle )
1681printk("\n[%s] thread[%x,%x] registered code/data vsegs in VMM\n",
1682__FUNCTION__, this->process->pid, this->trdid );
1683#endif
1684
1685    // get extended pointers on process_zero children_root, children_lock
1686    xptr_t children_root_xp = XPTR( local_cxy , &process_zero.children_root );
1687    xptr_t children_lock_xp = XPTR( local_cxy , &process_zero.children_lock );
1688
1689    // take lock protecting kernel process children list
1690    remote_queuelock_acquire( children_lock_xp );
1691
1692    // register process INIT in parent local process_zero
1693        xlist_add_last( children_root_xp , XPTR( local_cxy , &process->children_list ) );
1694        hal_atomic_add( &process_zero.children_nr , 1 );
1695
1696    // release lock protecting kernel process children list
1697    remote_queuelock_release( children_lock_xp );
1698
1699#if(DEBUG_PROCESS_INIT_CREATE & 1)
1700if( DEBUG_PROCESS_INIT_CREATE < cycle )
1701printk("\n[%s] thread[%x,%x] registered init process in parent\n",
1702__FUNCTION__, this->process->pid, this->trdid );
1703#endif
1704
1705    // select a core in local cluster to execute the main thread
1706    lid  = cluster_select_local_core();
1707
1708    // initialize pthread attributes for main thread
1709    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
1710    attr.cxy        = local_cxy;
1711    attr.lid        = lid;
1712
1713    // create and initialize thread descriptor
1714        error = thread_user_create( pid,
1715                                (void *)process->vmm.entry_point,
1716                                NULL,
1717                                &attr,
1718                                &thread );
1719
1720assert( (error == 0),
1721"cannot create main thread for <%s>\n", CONFIG_PROCESS_INIT_PATH );
1722
1723assert( (thread->trdid == 0),
1724"main thread must have index 0 for <%s>\n", CONFIG_PROCESS_INIT_PATH );
1725
1726#if(DEBUG_PROCESS_INIT_CREATE & 1)
1727if( DEBUG_PROCESS_INIT_CREATE < cycle )
1728printk("\n[%s] thread[%x,%x] created main thread\n",
1729__FUNCTION__, this->process->pid, this->trdid );
1730#endif
1731
1732    // activate thread
1733        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_GLOBAL );
1734
1735    hal_fence();
1736
1737#if DEBUG_PROCESS_INIT_CREATE
1738cycle = (uint32_t)hal_get_cycles();
1739if( DEBUG_PROCESS_INIT_CREATE < cycle )
1740printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1741__FUNCTION__, this->process->pid, this->trdid, cycle );
1742#endif
1743
1744}  // end process_init_create()
1745
1746/////////////////////////////////////////
1747void process_display( xptr_t process_xp )
1748{
1749    process_t   * process_ptr;
1750    cxy_t         process_cxy;
1751
1752    xptr_t        parent_xp;       // extended pointer on parent process
1753    process_t   * parent_ptr;
1754    cxy_t         parent_cxy;
1755
1756    xptr_t        owner_xp;        // extended pointer on owner process
1757    process_t   * owner_ptr;
1758    cxy_t         owner_cxy;
1759
1760    pid_t         pid;
1761    pid_t         ppid;
1762    lpid_t        lpid;
1763    uint32_t      state;
1764    uint32_t      th_nr;
1765
1766    xptr_t        txt_file_xp;     // extended pointer on TXT_RX file descriptor
1767    xptr_t        txt_chdev_xp;    // extended pointer on TXT_RX chdev
1768    chdev_t     * txt_chdev_ptr;
1769    cxy_t         txt_chdev_cxy;
1770    xptr_t        txt_owner_xp;    // extended pointer on TXT owner process
1771
1772    xptr_t        elf_file_xp;     // extended pointer on .elf file
1773    cxy_t         elf_file_cxy;
1774    vfs_file_t  * elf_file_ptr;
1775    vfs_inode_t * elf_inode_ptr;   // local pointer on .elf inode
1776
1777    char          txt_name[CONFIG_VFS_MAX_NAME_LENGTH];
1778    char          elf_name[CONFIG_VFS_MAX_NAME_LENGTH];
1779
1780    // get cluster and local pointer on process
1781    process_ptr = GET_PTR( process_xp );
1782    process_cxy = GET_CXY( process_xp );
1783
1784    // get process PID, LPID, and state
1785    pid   = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
1786    lpid  = LPID_FROM_PID( pid );
1787    state = hal_remote_l32( XPTR( process_cxy , &process_ptr->term_state ) );
1788
1789    // get process PPID
1790    parent_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->parent_xp ) );
1791    parent_cxy = GET_CXY( parent_xp );
1792    parent_ptr = GET_PTR( parent_xp );
1793    ppid       = hal_remote_l32( XPTR( parent_cxy , &parent_ptr->pid ) );
1794
1795    // get number of threads
1796    th_nr      = hal_remote_l32( XPTR( process_cxy , &process_ptr->th_nr ) );
1797
1798    // get pointers on owner process descriptor
1799    owner_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) );
1800    owner_cxy = GET_CXY( owner_xp );
1801    owner_ptr = GET_PTR( owner_xp );
1802
1803    // get process TXT name and .elf name
1804    if( lpid )                                   // user process
1805    {
1806
1807        // get extended pointer on file descriptor associated to TXT_RX
1808        txt_file_xp = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->fd_array.array[0] ) );
1809
1810        assert( (txt_file_xp != XPTR_NULL) ,
1811        "process must be attached to one TXT terminal\n" ); 
1812
1813        // get TXT_RX chdev pointers
1814        txt_chdev_xp  = chdev_from_file( txt_file_xp );
1815        txt_chdev_cxy = GET_CXY( txt_chdev_xp );
1816        txt_chdev_ptr = GET_PTR( txt_chdev_xp );
1817
1818        // get TXT_RX name and ownership
1819        hal_remote_strcpy( XPTR( local_cxy , txt_name ) ,
1820                           XPTR( txt_chdev_cxy , txt_chdev_ptr->name ) );
1821   
1822        txt_owner_xp = (xptr_t)hal_remote_l64( XPTR( txt_chdev_cxy, 
1823                                                     &txt_chdev_ptr->ext.txt.owner_xp ) );
1824
1825        // get process .elf name
1826        elf_file_xp   = hal_remote_l64( XPTR( process_cxy , &process_ptr->vfs_bin_xp ) );
1827        elf_file_cxy  = GET_CXY( elf_file_xp );
1828        elf_file_ptr  = GET_PTR( elf_file_xp );
1829        elf_inode_ptr = hal_remote_lpt( XPTR( elf_file_cxy , &elf_file_ptr->inode ) );
1830        vfs_inode_get_name( XPTR( elf_file_cxy , elf_inode_ptr ) , elf_name );
1831    }
1832    else                                         // kernel process_zero
1833    {
1834        // TXT name and .elf name are not registered in kernel process_zero
1835        strcpy( txt_name , "txt0_rx" );
1836        txt_owner_xp = process_xp; 
1837        strcpy( elf_name , "kernel.elf" );
1838    }
1839
1840    // display process info
1841    if( txt_owner_xp == process_xp )
1842    {
1843        nolock_printk("PID %X | %s (FG) | %X | PPID %X | TS %X | %d | %s\n", 
1844        pid, txt_name, process_ptr, ppid, state, th_nr, elf_name );
1845    }
1846    else
1847    {
1848        nolock_printk("PID %X | %s (BG) | %X | PPID %X | TS %X | %d | %s\n", 
1849        pid, txt_name, process_ptr, ppid, state, th_nr, elf_name );
1850    }
1851}  // end process_display()
1852
1853
1854////////////////////////////////////////////////////////////////////////////////////////
1855//     Terminals related functions
1856////////////////////////////////////////////////////////////////////////////////////////
1857
1858//////////////////////////////////
1859uint32_t process_txt_alloc( void )
1860{
1861    uint32_t  index;       // TXT terminal index
1862    xptr_t    chdev_xp;    // extended pointer on TXT_RX chdev
1863    chdev_t * chdev_ptr;   // local pointer on TXT_RX chdev
1864    cxy_t     chdev_cxy;   // TXT_RX chdev cluster
1865    xptr_t    root_xp;     // extended pointer on owner field in chdev
1866
1867    // scan the user TXT_RX chdevs (TXT0 is reserved for kernel)
1868    for( index = 1 ; index < LOCAL_CLUSTER->nb_txt_channels ; index ++ )
1869    {
1870        // get pointers on TXT_RX[index]
1871        chdev_xp  = chdev_dir.txt_rx[index];
1872        chdev_cxy = GET_CXY( chdev_xp );
1873        chdev_ptr = GET_PTR( chdev_xp );
1874
1875        // get extended pointer on root of attached process
1876        root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
1877
1878        // return free TXT index if found
1879        if( xlist_is_empty( root_xp ) ) return index; 
1880    }
1881
1882    assert( false , "no free TXT terminal found" );
1883
1884    return -1;
1885
1886} // end process_txt_alloc()
1887
1888/////////////////////////////////////////////
1889void process_txt_attach( process_t * process,
1890                         uint32_t    txt_id )
1891{
1892    xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
1893    cxy_t       chdev_cxy;    // TXT_RX chdev cluster
1894    chdev_t *   chdev_ptr;    // local pointer on TXT_RX chdev
1895    xptr_t      root_xp;      // extended pointer on list root in chdev
1896    xptr_t      lock_xp;      // extended pointer on list lock in chdev
1897
1898// check process is in owner cluster
1899assert( (CXY_FROM_PID( process->pid ) == local_cxy) ,
1900"process descriptor not in owner cluster" );
1901
1902// check terminal index
1903assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
1904"illegal TXT terminal index" );
1905
1906    // get pointers on TXT_RX[txt_id] chdev
1907    chdev_xp  = chdev_dir.txt_rx[txt_id];
1908    chdev_cxy = GET_CXY( chdev_xp );
1909    chdev_ptr = GET_PTR( chdev_xp );
1910
1911    // get extended pointer on root & lock of attached process list
1912    root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
1913    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
1914
1915    // get lock protecting list of processes attached to TXT
1916    remote_busylock_acquire( lock_xp );
1917
1918    // insert process in attached process list
1919    xlist_add_last( root_xp , XPTR( local_cxy , &process->txt_list ) );
1920
1921    // release lock protecting list of processes attached to TXT
1922    remote_busylock_release( lock_xp );
1923
1924#if DEBUG_PROCESS_TXT
1925thread_t * this = CURRENT_THREAD;
1926uint32_t cycle = (uint32_t)hal_get_cycles();
1927if( DEBUG_PROCESS_TXT < cycle )
1928printk("\n[%s] thread[%x,%x] attached process %x to TXT %d / cycle %d\n",
1929__FUNCTION__, this->process->pid, this->trdid, process->pid, txt_id , cycle );
1930#endif
1931
1932} // end process_txt_attach()
1933
1934/////////////////////////////////////////////
1935void process_txt_detach( xptr_t  process_xp )
1936{
1937    process_t * process_ptr;  // local pointer on process in owner cluster
1938    cxy_t       process_cxy;  // process owner cluster
1939    pid_t       process_pid;  // process identifier
1940    xptr_t      file_xp;      // extended pointer on stdin file
1941    xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
1942    cxy_t       chdev_cxy;    // TXT_RX chdev cluster
1943    chdev_t *   chdev_ptr;    // local pointer on TXT_RX chdev
1944    xptr_t      lock_xp;      // extended pointer on list lock in chdev
1945
1946    // get process cluster, local pointer, and PID
1947    process_cxy = GET_CXY( process_xp );
1948    process_ptr = GET_PTR( process_xp );
1949    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
1950
1951// check process descriptor in owner cluster
1952assert( (CXY_FROM_PID( process_pid ) == process_cxy ) ,
1953"process descriptor not in owner cluster" );
1954
1955    // release TXT ownership (does nothing if not TXT owner)
1956    process_txt_transfer_ownership( process_xp );
1957
1958    // get extended pointer on process stdin file
1959    file_xp = (xptr_t)hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
1960
1961    // get pointers on TXT_RX chdev
1962    chdev_xp  = chdev_from_file( file_xp );
1963    chdev_cxy = GET_CXY( chdev_xp );
1964    chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
1965
1966    // get extended pointer on lock protecting attached process list
1967    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
1968
1969    // get lock protecting list of processes attached to TXT
1970    remote_busylock_acquire( lock_xp );
1971
1972    // unlink process from attached process list
1973    xlist_unlink( XPTR( process_cxy , &process_ptr->txt_list ) );
1974
1975    // release lock protecting list of processes attached to TXT
1976    remote_busylock_release( lock_xp );
1977
1978#if DEBUG_PROCESS_TXT
1979thread_t * this = CURRENT_THREAD;
1980uint32_t cycle  = (uint32_t)hal_get_cycles();
1981uint32_t txt_id = hal_remote_l32( XPTR( chdev_cxy , &chdev_ptr->channel ) );
1982if( DEBUG_PROCESS_TXT < cycle )
1983printk("\n[%s] thread[%x,%x] detached process %x from TXT %d / cycle %d\n",
1984__FUNCTION__, this->process->pid, this->trdid, process_pid, txt_id, cycle );
1985#endif
1986
1987} // end process_txt_detach()
1988
1989///////////////////////////////////////////////////
1990void process_txt_set_ownership( xptr_t process_xp )
1991{
1992    process_t * process_ptr;
1993    cxy_t       process_cxy;
1994    pid_t       process_pid;
1995    xptr_t      file_xp;
1996    xptr_t      txt_xp;     
1997    chdev_t   * txt_ptr;
1998    cxy_t       txt_cxy;
1999
2000    // get pointers on process in owner cluster
2001    process_cxy = GET_CXY( process_xp );
2002    process_ptr = GET_PTR( process_xp );
2003    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
2004
2005    // check owner cluster
2006    assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
2007    "process descriptor not in owner cluster\n" );
2008
2009    // get extended pointer on stdin pseudo file
2010    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
2011
2012    // get pointers on TXT chdev
2013    txt_xp  = chdev_from_file( file_xp );
2014    txt_cxy = GET_CXY( txt_xp );
2015    txt_ptr = GET_PTR( txt_xp );
2016
2017    // set owner field in TXT chdev
2018    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , process_xp );
2019
2020#if DEBUG_PROCESS_TXT
2021thread_t * this = CURRENT_THREAD;
2022uint32_t cycle  = (uint32_t)hal_get_cycles();
2023uint32_t txt_id = hal_remote_l32( XPTR( txt_cxy , &txt_ptr->channel ) );
2024if( DEBUG_PROCESS_TXT < cycle )
2025printk("\n[%s] thread[%x,%x] give TXT %d to process %x / cycle %d\n",
2026__FUNCTION__, this->process->pid, this->trdid, txt_id, process_pid, cycle );
2027#endif
2028
2029}  // end process_txt_set ownership()
2030
2031////////////////////////////////////////////////////////
2032void process_txt_transfer_ownership( xptr_t process_xp )
2033{
2034    process_t * process_ptr;     // local pointer on process releasing ownership
2035    cxy_t       process_cxy;     // process cluster
2036    pid_t       process_pid;     // process identifier
2037    xptr_t      file_xp;         // extended pointer on TXT_RX pseudo file
2038    xptr_t      txt_xp;          // extended pointer on TXT_RX chdev
2039    chdev_t   * txt_ptr;         // local pointer on TXT_RX chdev
2040    cxy_t       txt_cxy;         // cluster of TXT_RX chdev
2041    uint32_t    txt_id;          // TXT_RX channel
2042    xptr_t      owner_xp;        // extended pointer on current TXT_RX owner
2043    xptr_t      root_xp;         // extended pointer on root of attached process list
2044    xptr_t      lock_xp;         // extended pointer on lock protecting attached process list
2045    xptr_t      iter_xp;         // iterator for xlist
2046    xptr_t      current_xp;      // extended pointer on current process
2047    process_t * current_ptr;     // local pointer on current process
2048    cxy_t       current_cxy;     // cluster for current process
2049
2050#if DEBUG_PROCESS_TXT
2051thread_t * this  = CURRENT_THREAD;
2052uint32_t   cycle;
2053#endif
2054
2055    // get pointers on process in owner cluster
2056    process_cxy = GET_CXY( process_xp );
2057    process_ptr = GET_PTR( process_xp );
2058    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
2059
2060    // check owner cluster
2061    assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
2062    "process descriptor not in owner cluster\n" );
2063
2064    // get extended pointer on stdin pseudo file
2065    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
2066
2067    // get pointers on TXT chdev
2068    txt_xp  = chdev_from_file( file_xp );
2069    txt_cxy = GET_CXY( txt_xp );
2070    txt_ptr = GET_PTR( txt_xp );
2071
2072    // get extended pointer on TXT_RX owner and TXT channel
2073    owner_xp = hal_remote_l64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) );
2074    txt_id   = hal_remote_l32 ( XPTR( txt_cxy , &txt_ptr->channel ) );
2075
2076    // transfer ownership only if process is the TXT owner
2077    if( (owner_xp == process_xp) && (txt_id > 0) ) 
2078    {
2079        // get extended pointers on root and lock of attached processes list
2080        root_xp = XPTR( txt_cxy , &txt_ptr->ext.txt.root );
2081        lock_xp = XPTR( txt_cxy , &txt_ptr->ext.txt.lock );
2082
2083        // get lock
2084        remote_busylock_acquire( lock_xp );
2085
2086        if( process_get_ppid( process_xp ) != 1 )           // process is not KSH
2087        {
2088            // scan attached process list to find KSH process
2089            XLIST_FOREACH( root_xp , iter_xp )
2090            {
2091                current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2092                current_cxy = GET_CXY( current_xp );
2093                current_ptr = GET_PTR( current_xp );
2094
2095                if( process_get_ppid( current_xp ) == 1 )  // current is KSH
2096                {
2097                    // release lock
2098                    remote_busylock_release( lock_xp );
2099
2100                    // set owner field in TXT chdev
2101                    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , current_xp );
2102
2103#if DEBUG_PROCESS_TXT
2104cycle = (uint32_t)hal_get_cycles();
2105uint32_t ksh_pid = hal_remote_l32( XPTR( current_cxy , &current_ptr->pid ) );
2106if( DEBUG_PROCESS_TXT < cycle )
2107printk("\n[%s] thread[%x,%x] release TXT %d to KSH %x / cycle %d\n",
2108__FUNCTION__, this->process->pid, this->trdid, txt_id, ksh_pid, cycle );
2109process_txt_display( txt_id );
2110#endif
2111                     return;
2112                }
2113            }
2114 
2115            // release lock
2116            remote_busylock_release( lock_xp );
2117
2118            // PANIC if KSH not found
2119            assert( false , "KSH process not found for TXT %d" );
2120
2121            return;
2122        }
2123        else                                               // process is KSH
2124        {
2125            // scan attached process list to find another process
2126            XLIST_FOREACH( root_xp , iter_xp )
2127            {
2128                current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2129                current_cxy = GET_CXY( current_xp );
2130                current_ptr = GET_PTR( current_xp );
2131
2132                if( current_xp != process_xp )            // current is not KSH
2133                {
2134                    // release lock
2135                    remote_busylock_release( lock_xp );
2136
2137                    // set owner field in TXT chdev
2138                    hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , current_xp );
2139
2140#if DEBUG_PROCESS_TXT
2141cycle  = (uint32_t)hal_get_cycles();
2142uint32_t new_pid = hal_remote_l32( XPTR( current_cxy , &current_ptr->pid ) );
2143if( DEBUG_PROCESS_TXT < cycle )
2144printk("\n[%s] thread[%x,%x] release TXT %d to process %x / cycle %d\n",
2145__FUNCTION__,this->process->pid, this->trdid, txt_id, new_pid, cycle );
2146process_txt_display( txt_id );
2147#endif
2148                     return;
2149                }
2150            }
2151
2152            // release lock
2153            remote_busylock_release( lock_xp );
2154
2155            // no more owner for TXT if no other process found
2156            hal_remote_s64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) , XPTR_NULL );
2157
2158#if DEBUG_PROCESS_TXT
2159cycle = (uint32_t)hal_get_cycles();
2160if( DEBUG_PROCESS_TXT < cycle )
2161printk("\n[%s] thread[%x,%x] release TXT %d to nobody / cycle %d\n",
2162__FUNCTION__, this->process->pid, this->trdid, txt_id, cycle );
2163process_txt_display( txt_id );
2164#endif
2165            return;
2166        }
2167    }
2168    else
2169    {
2170
2171#if DEBUG_PROCESS_TXT
2172cycle = (uint32_t)hal_get_cycles();
2173if( DEBUG_PROCESS_TXT < cycle )
2174printk("\n[%s] thread %x in process %d does nothing (not TXT owner) / cycle %d\n",
2175__FUNCTION__, this->trdid, process_pid, cycle );
2176process_txt_display( txt_id );
2177#endif
2178
2179    }
2180}  // end process_txt_transfer_ownership()
2181
2182
2183////////////////////////////////////////////////
2184bool_t process_txt_is_owner( xptr_t process_xp )
2185{
2186    // get local pointer and cluster of process in owner cluster
2187    cxy_t       process_cxy = GET_CXY( process_xp );
2188    process_t * process_ptr = GET_PTR( process_xp );
2189
2190// check calling thread execute in target process owner cluster
2191pid_t process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
2192assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
2193"process descriptor not in owner cluster\n" );
2194
2195    // get extended pointer on stdin pseudo file
2196    xptr_t file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0] ) );
2197
2198    // get pointers on TXT chdev
2199    xptr_t    txt_xp  = chdev_from_file( file_xp );
2200    cxy_t     txt_cxy = GET_CXY( txt_xp );
2201    chdev_t * txt_ptr = GET_PTR( txt_xp );
2202
2203    // get extended pointer on TXT_RX owner process
2204    xptr_t owner_xp = hal_remote_l64( XPTR( txt_cxy , &txt_ptr->ext.txt.owner_xp ) );
2205
2206    return (process_xp == owner_xp);
2207
2208}   // end process_txt_is_owner()
2209
2210////////////////////////////////////////////////     
2211xptr_t process_txt_get_owner( uint32_t channel )
2212{
2213    xptr_t      txt_rx_xp  = chdev_dir.txt_rx[channel];
2214    cxy_t       txt_rx_cxy = GET_CXY( txt_rx_xp );
2215    chdev_t *   txt_rx_ptr = GET_PTR( txt_rx_xp );
2216
2217    return (xptr_t)hal_remote_l64( XPTR( txt_rx_cxy , &txt_rx_ptr->ext.txt.owner_xp ) );
2218
2219}  // end process_txt_get_owner()
2220
2221///////////////////////////////////////////
2222void process_txt_display( uint32_t txt_id )
2223{
2224    xptr_t      chdev_xp;
2225    cxy_t       chdev_cxy;
2226    chdev_t   * chdev_ptr;
2227    xptr_t      root_xp;
2228    xptr_t      lock_xp;
2229    xptr_t      current_xp;
2230    xptr_t      iter_xp;
2231    cxy_t       txt0_cxy;
2232    chdev_t   * txt0_ptr;
2233    xptr_t      txt0_xp;
2234    xptr_t      txt0_lock_xp;
2235   
2236    assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
2237    "illegal TXT terminal index" );
2238
2239    // get pointers on TXT0 chdev
2240    txt0_xp  = chdev_dir.txt_tx[0];
2241    txt0_cxy = GET_CXY( txt0_xp );
2242    txt0_ptr = GET_PTR( txt0_xp );
2243
2244    // get extended pointer on TXT0 lock
2245    txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
2246
2247    // get pointers on TXT_RX[txt_id] chdev
2248    chdev_xp  = chdev_dir.txt_rx[txt_id];
2249    chdev_cxy = GET_CXY( chdev_xp );
2250    chdev_ptr = GET_PTR( chdev_xp );
2251
2252    // get extended pointer on root & lock of attached process list
2253    root_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.root );
2254    lock_xp = XPTR( chdev_cxy , &chdev_ptr->ext.txt.lock );
2255
2256    // get lock on attached process list
2257    remote_busylock_acquire( lock_xp );
2258
2259    // get TXT0 lock in busy waiting mode
2260    remote_busylock_acquire( txt0_lock_xp );
2261
2262    // display header
2263    nolock_printk("\n***** processes attached to TXT_%d / cycle %d\n",
2264    txt_id , (uint32_t)hal_get_cycles() );
2265
2266    // scan attached process list
2267    XLIST_FOREACH( root_xp , iter_xp )
2268    {
2269        current_xp  = XLIST_ELEMENT( iter_xp , process_t , txt_list );
2270        process_display( current_xp );
2271    }
2272
2273    // release TXT0 lock in busy waiting mode
2274    remote_busylock_release( txt0_lock_xp );
2275
2276    // release lock on attached process list
2277    remote_busylock_release( lock_xp );
2278
2279}  // end process_txt_display
Note: See TracBrowser for help on using the repository browser.