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

Last change on this file since 450 was 450, checked in by alain, 6 years ago

Fix a bug in function sched_handle_signal():
When the deleted user thread is the last executed thread,
the sched->u_last field must be updated to point on another user thread.

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