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

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

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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