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

Last change on this file since 485 was 485, checked in by viala@…, 6 years ago

[kern] Add void type to function prototypes with no parameter

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