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

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

Rewrite if-then-else return function into switch case.

For safety reason and performance:

1) Safety: GCC complain with a warning if you forgot an enum variant.
2) code-gen just outperform naive if-then-else.

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