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

Last change on this file since 446 was 446, checked in by alain, 4 years ago

miscelaneous...

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