source: trunk/kernel/kern/thread.c @ 625

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 52.3 KB
Line 
1/*
2 * thread.c -   thread operations implementation (user & kernel)
3 *
4 * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *         Alain Greiner (2016,2017,2018,2019)
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <kernel_config.h>
26#include <hal_kernel_types.h>
27#include <hal_context.h>
28#include <hal_irqmask.h>
29#include <hal_special.h>
30#include <hal_remote.h>
31#include <hal_vmm.h>
32#include <memcpy.h>
33#include <printk.h>
34#include <cluster.h>
35#include <process.h>
36#include <scheduler.h>
37#include <dev_pic.h>
38#include <core.h>
39#include <list.h>
40#include <xlist.h>
41#include <page.h>
42#include <kmem.h>
43#include <ppm.h>
44#include <thread.h>
45#include <rpc.h>
46
47//////////////////////////////////////////////////////////////////////////////////////
48// Extern global variables
49//////////////////////////////////////////////////////////////////////////////////////
50
51extern process_t            process_zero;       // allocated in kernel_init.c
52extern char               * lock_type_str[];    // allocated in kernel_init.c
53extern chdev_directory_t    chdev_dir;          // allocated in kernel_init.c
54
55//////////////////////////////////////////////////////////////////////////////////////
56// This function returns a printable string for the thread type.
57//////////////////////////////////////////////////////////////////////////////////////
58const char * thread_type_str( thread_type_t type )
59{
60  switch ( type ) {
61  case THREAD_USER:   return "USR";
62  case THREAD_RPC:    return "RPC";
63  case THREAD_DEV:    return "DEV";
64  case THREAD_IDLE:   return "IDL";
65  default:            return "undefined";
66  }
67}
68
69/////////////////////////////////////////////////////////////////////////////////////
70// This static function allocates physical memory for a thread descriptor.
71// It can be called by the three functions:
72// - thread_user_create()
73// - thread_user_fork()
74// - thread_kernel_create()
75/////////////////////////////////////////////////////////////////////////////////////
76// @ return pointer on thread descriptor if success / return NULL if failure.
77/////////////////////////////////////////////////////////////////////////////////////
78static thread_t * thread_alloc( void )
79{
80        page_t       * page;   // pointer on page descriptor containing thread descriptor
81        kmem_req_t     req;    // kmem request
82
83        // allocates memory for thread descriptor + kernel stack
84        req.type  = KMEM_PAGE;
85        req.size  = CONFIG_THREAD_DESC_ORDER;
86        req.flags = AF_KERNEL | AF_ZERO;
87        page      = kmem_alloc( &req );
88
89        if( page == NULL ) return NULL;
90
91    // return pointer on new thread descriptor
92    xptr_t base_xp = ppm_page2base( XPTR(local_cxy , page ) );
93    return GET_PTR( base_xp );
94
95}  // end thread_alloc()
96 
97
98/////////////////////////////////////////////////////////////////////////////////////
99// This static function initializes a thread descriptor (kernel or user).
100// It can be called by the four functions:
101// - thread_user_create()
102// - thread_user_fork()
103// - thread_kernel_create()
104// - thread_idle_init()
105// The "type" and "trdid" fields must have been previously set.
106// It updates the local DQDT.
107/////////////////////////////////////////////////////////////////////////////////////
108// @ thread          : pointer on local thread descriptor
109// @ process         : pointer on local process descriptor.
110// @ type            : thread type.
111// @ trdid           : thread identifier
112// @ func            : pointer on thread entry function.
113// @ args            : pointer on thread entry function arguments.
114// @ core_lid        : target core local index.
115// @ user_stack_vseg : local pointer on user stack vseg (user thread only)
116/////////////////////////////////////////////////////////////////////////////////////
117static error_t thread_init( thread_t      * thread,
118                            process_t     * process,
119                            thread_type_t   type,
120                            trdid_t         trdid,
121                            void          * func,
122                            void          * args,
123                            lid_t           core_lid,
124                            vseg_t        * user_stack_vseg )
125{
126
127// check type and trdid fields initialized
128assert( (thread->type == type)   , "bad type argument" );
129assert( (thread->trdid == trdid) , "bad trdid argument" );
130
131#if DEBUG_THREAD_INIT
132uint32_t   cycle = (uint32_t)hal_get_cycles();
133thread_t * this  = CURRENT_THREAD;
134if( DEBUG_THREAD_INIT < cycle )
135printk("\n[%s] thread[%x,%x] enter for thread %x in process %x / cycle %d\n",
136__FUNCTION__, this->process->pid, this->trdid, thread->trdid, process->pid , cycle );
137#endif
138
139    // compute thread descriptor size without kernel stack
140    uint32_t desc_size = (intptr_t)(&thread->signature) - (intptr_t)thread + 4; 
141
142        // Initialize new thread descriptor
143    thread->quantum         = 0;            // TODO
144    thread->ticks_nr        = 0;            // TODO
145    thread->time_last_check = 0;            // TODO
146        thread->core            = &LOCAL_CLUSTER->core_tbl[core_lid];
147        thread->process         = process;
148    thread->busylocks       = 0;
149
150#if DEBUG_BUSYLOCK
151    xlist_root_init( XPTR( local_cxy , &thread->busylocks_root ) );
152#endif
153
154    thread->user_stack_vseg = user_stack_vseg;
155    thread->k_stack_base    = (intptr_t)thread + desc_size;
156    thread->k_stack_size    = CONFIG_THREAD_DESC_SIZE - desc_size;
157    thread->entry_func      = func;         // thread entry point
158    thread->entry_args      = args;         // thread function arguments
159    thread->flags           = 0;            // all flags reset
160    thread->errno           = 0;            // no error detected
161    thread->fork_user       = 0;            // no user defined placement for fork
162    thread->fork_cxy        = 0;            // user defined target cluster for fork
163    thread->blocked         = THREAD_BLOCKED_GLOBAL;
164
165    // initialize sched list
166    list_entry_init( &thread->sched_list );
167
168    // initialize waiting queue entries
169    list_entry_init( &thread->wait_list );
170    xlist_entry_init( XPTR( local_cxy , &thread->wait_xlist ) );
171
172    // initialize thread info
173    memset( &thread->info , 0 , sizeof(thread_info_t) );
174
175    // initialize join_lock
176    remote_busylock_init( XPTR( local_cxy , &thread->join_lock ), LOCK_THREAD_JOIN );
177
178    // initialise signature
179        thread->signature = THREAD_SIGNATURE;
180
181    // FIXME define and call an architecture specific hal_thread_init()
182    // function to initialise the save_sr field
183    thread->save_sr = 0xFF13;
184
185    // register new thread in core scheduler
186    sched_register_thread( thread->core , thread );
187
188        // update DQDT
189    dqdt_increment_threads();
190
191#if DEBUG_THREAD_INIT
192cycle = (uint32_t)hal_get_cycles();
193if( DEBUG_THREAD_INIT < cycle )
194printk("\n[%s] thread[%x,%x] exit for thread %x in process %x / cycle %d\n",
195__FUNCTION__, this->process->pid, this->trdid, thread, process->pid, cycle );
196#endif
197
198        return 0;
199
200} // end thread_init()
201
202//////////////////////////////////////////////////
203error_t thread_user_create( pid_t             pid,
204                            void            * start_func,
205                            void            * start_arg,
206                            pthread_attr_t  * attr,
207                            thread_t       ** new_thread )
208{
209    error_t        error;
210        thread_t     * thread;       // pointer on created thread descriptor
211    trdid_t        trdid;        // created thred identifier
212    process_t    * process;      // pointer to local process descriptor
213    lid_t          core_lid;     // selected core local index
214    vseg_t       * us_vseg;      // user stack vseg
215
216assert( (attr != NULL) , "pthread attributes must be defined" );
217
218#if DEBUG_THREAD_USER_CREATE
219thread_t * this  = CURRENT_THREAD;
220uint32_t   cycle = (uint32_t)hal_get_cycles();
221if( DEBUG_THREAD_USER_CREATE < cycle )
222printk("\n[%s] thread[%x,%x] enter in cluster %x for process %x / cycle %d\n",
223__FUNCTION__, this->process->pid , this->trdid , local_cxy , pid , cycle );
224#endif
225
226    // get process descriptor local copy
227    process = process_get_local_copy( pid );
228
229    if( process == NULL )
230    {
231                printk("\n[ERROR] in %s : cannot get process descriptor %x\n",
232        __FUNCTION__ , pid );
233        return -1;
234    }
235
236#if( DEBUG_THREAD_USER_CREATE & 1)
237if( DEBUG_THREAD_USER_CREATE < cycle )
238printk("\n[%s] process descriptor = %x for process %x in cluster %x\n",
239__FUNCTION__, process , pid , local_cxy );
240#endif
241
242    // select a target core in local cluster
243    if( attr->attributes & PT_ATTR_CORE_DEFINED )
244    {
245        core_lid = attr->lid;
246        if( core_lid >= LOCAL_CLUSTER->cores_nr )
247        {
248                printk("\n[ERROR] in %s : illegal core index attribute = %d\n",
249            __FUNCTION__ , core_lid );
250            return -1;
251        }
252    }
253    else
254    {
255        core_lid = cluster_select_local_core();
256    }
257
258#if( DEBUG_THREAD_USER_CREATE & 1)
259if( DEBUG_THREAD_USER_CREATE < cycle )
260printk("\n[%s] core[%x,%d] selected\n",
261__FUNCTION__, local_cxy , core_lid );
262#endif
263
264    // allocate memory for thread descriptor
265    thread = thread_alloc();
266
267    if( thread == NULL )
268    {
269            printk("\n[ERROR] in %s : cannot create new thread in cluster %x\n",
270        __FUNCTION__, local_cxy );
271        return -1;
272    }
273
274#if( DEBUG_THREAD_USER_CREATE & 1)
275if( DEBUG_THREAD_USER_CREATE < cycle )
276printk("\n[%s] new thread descriptor %x allocated\n",
277__FUNCTION__, thread );
278#endif
279
280    // set type in thread descriptor
281    thread->type = THREAD_USER;
282
283    // register new thread in process descriptor, and get a TRDID
284    error = process_register_thread( process, thread , &trdid );
285
286    if( error )
287    {
288        printk("\n[ERROR] in %s : cannot register new thread in process %x\n",
289        __FUNCTION__, pid );
290        thread_destroy( thread );
291        return -1;
292    }
293
294    // set trdid in thread descriptor
295    thread->trdid = trdid;
296
297#if( DEBUG_THREAD_USER_CREATE & 1)
298if( DEBUG_THREAD_USER_CREATE < cycle )
299printk("\n[%s] new thread %x registered in process %x\n",
300__FUNCTION__, trdid, pid );
301#endif
302
303    // allocate a stack from local VMM
304    us_vseg = vmm_create_vseg( process,
305                               VSEG_TYPE_STACK,
306                               LTID_FROM_TRDID( trdid ),
307                               0,                         // size unused
308                               0,                         // file_offset unused
309                               0,                         // file_size unused
310                               XPTR_NULL,                 // mapper_xp unused
311                               local_cxy );
312
313    if( us_vseg == NULL )
314    {
315            printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
316        process_remove_thread( thread );
317        thread_destroy( thread );
318                return -1;
319    }
320
321#if( DEBUG_THREAD_USER_CREATE & 1)
322if( DEBUG_THREAD_USER_CREATE < cycle )
323printk("\n[%s] stack vseg created / vpn_base %x / %d pages\n",
324__FUNCTION__, us_vseg->vpn_base, us_vseg->vpn_size );
325#endif
326
327    // initialize thread descriptor
328    error = thread_init( thread,
329                         process,
330                         THREAD_USER,
331                         trdid,
332                         start_func,
333                         start_arg,
334                         core_lid,
335                         us_vseg );
336    if( error )
337    {
338            printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ );
339        vmm_remove_vseg( process , us_vseg );
340        process_remove_thread( thread );
341        thread_destroy( thread );
342        return -1;
343    }
344
345#if( DEBUG_THREAD_USER_CREATE & 1)
346if( DEBUG_THREAD_USER_CREATE < cycle )
347printk("\n[%s] new thread %x in process %x initialised\n",
348__FUNCTION__, thread->trdid, process->pid );
349#endif
350
351    // set DETACHED flag if required
352    if( attr->attributes & PT_ATTR_DETACH ) 
353    {
354        thread->flags |= THREAD_FLAG_DETACHED;
355    }
356
357    // allocate & initialize CPU context
358        if( hal_cpu_context_alloc( thread ) )
359    {
360            printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ );
361        vmm_remove_vseg( process , us_vseg );
362        process_remove_thread( thread );
363        thread_destroy( thread );
364        return -1;
365    }
366    hal_cpu_context_init( thread );
367
368    // allocate & initialize FPU context
369    if( hal_fpu_context_alloc( thread ) )
370    {
371            printk("\n[ERROR] in %s : cannot create FPU context\n", __FUNCTION__ );
372        vmm_remove_vseg( process , us_vseg );
373        process_remove_thread( thread );
374        thread_destroy( thread );
375        return -1;
376    }
377    hal_fpu_context_init( thread );
378
379#if( DEBUG_THREAD_USER_CREATE & 1)
380if( DEBUG_THREAD_USER_CREATE < cycle )
381printk("\n[%s] CPU & FPU contexts created\n",
382__FUNCTION__, thread->trdid );
383hal_vmm_display( process , true );
384#endif
385
386#if DEBUG_THREAD_USER_CREATE
387cycle = (uint32_t)hal_get_cycles();
388if( DEBUG_THREAD_USER_CREATE < cycle )
389printk("\n[%s] thread[%x,%x] exit / new_thread %x / core %d / cycle %d\n",
390__FUNCTION__, this->process->pid , this->trdid , thread->trdid, core_lid, cycle );
391#endif
392
393    *new_thread = thread;
394        return 0;
395
396}  // end thread_user_create()
397
398///////////////////////////////////////////////////////
399error_t thread_user_fork( xptr_t      parent_thread_xp,
400                          process_t * child_process,
401                          thread_t ** child_thread )
402{
403    error_t        error;
404        thread_t     * child_ptr;        // local pointer on child thread
405    trdid_t        child_trdid;      // child thread identifier
406    lid_t          core_lid;         // selected core local index
407    thread_t     * parent_ptr;       // local pointer on remote parent thread
408    cxy_t          parent_cxy;       // parent thread cluster
409    process_t    * parent_process;   // local pointer on parent process
410    xptr_t         parent_gpt_xp;    // extended pointer on parent thread GPT
411    void         * parent_func;      // parent thread entry_func
412    void         * parent_args;      // parent thread entry_args
413    uint32_t       parent_flags;     // parent_thread flags
414    vseg_t       * parent_us_vseg;   // parent thread user stack vseg
415    vseg_t       * child_us_vseg;    // child thread user stack vseg
416
417#if DEBUG_THREAD_USER_FORK
418uint32_t   cycle = (uint32_t)hal_get_cycles();
419thread_t * this  = CURRENT_THREAD;
420if( DEBUG_THREAD_USER_FORK < cycle )
421printk("\n[%s] thread[%x,%x] enter for child_process %x / cycle %d\n",
422__FUNCTION__, this->process->pid, this->trdid, child_process->pid, cycle );
423#endif
424
425    // select a target core in local cluster
426    core_lid = cluster_select_local_core();
427
428#if (DEBUG_THREAD_USER_FORK & 1)
429if( DEBUG_THREAD_USER_FORK < cycle )
430printk("\n[%s] thread[%x,%x] selected core [%x,%d]\n",
431__FUNCTION__, this->process->pid, this->trdid, local_cxy, core_lid );
432#endif
433
434    // get cluster and local pointer on parent thread descriptor
435    parent_cxy = GET_CXY( parent_thread_xp );
436    parent_ptr = GET_PTR( parent_thread_xp );
437
438    // get relevant infos from parent thread
439    parent_func    = (void *)  hal_remote_lpt( XPTR(parent_cxy,&parent_ptr->entry_func ));
440    parent_args    = (void *)  hal_remote_lpt( XPTR(parent_cxy,&parent_ptr->entry_args ));
441    parent_flags   = (uint32_t)hal_remote_l32( XPTR(parent_cxy,&parent_ptr->flags ));
442    parent_us_vseg = (vseg_t *)hal_remote_lpt( XPTR(parent_cxy,&parent_ptr->user_stack_vseg ));
443
444    // get pointer on parent process in parent thread cluster
445    parent_process = (process_t *)hal_remote_lpt( XPTR( parent_cxy,
446                                                        &parent_ptr->process ) );
447 
448    // build extended pointer on parent GPT in parent thread cluster
449    parent_gpt_xp = XPTR( parent_cxy , &parent_process->vmm.gpt );
450
451#if (DEBUG_THREAD_USER_FORK & 1)
452if( DEBUG_THREAD_USER_FORK < cycle )
453printk("\n[%s] thread[%x,%x] get parent GPT\n",
454__FUNCTION__, this->process->pid, this->trdid );
455#endif
456
457    // allocate memory for child thread descriptor
458    child_ptr = thread_alloc();
459
460    if( child_ptr == NULL )
461    {
462        printk("\n[ERROR] in %s : cannot allocate new thread\n",
463        __FUNCTION__ );
464        return -1;
465    }
466
467#if (DEBUG_THREAD_USER_FORK & 1)
468if( DEBUG_THREAD_USER_FORK < cycle )
469printk("\n[%s] thread[%x,%x] allocated new thread descriptor %x\n",
470__FUNCTION__, this->process->pid, this->trdid, child_ptr );
471#endif
472
473    // set type in thread descriptor
474    child_ptr->type = THREAD_USER;
475
476    // register new thread in process descriptor, and get a TRDID
477    error = process_register_thread( child_process, child_ptr , &child_trdid );
478
479    if( error )
480    {
481        printk("\n[ERROR] in %s : cannot register new thread in process %x\n",
482        __FUNCTION__, child_process->pid );
483        thread_destroy( child_ptr );
484        return -1;
485    }
486
487    // set trdid in thread descriptor
488    child_ptr->trdid = child_trdid;
489
490#if (DEBUG_THREAD_USER_FORK & 1)
491if( DEBUG_THREAD_USER_FORK < cycle )
492printk("\n[%s] thread[%x,%x] registered child thread %x in child process %x\n",
493__FUNCTION__, this->process->pid, this->trdid, child_trdid, child_process->pid );
494#endif
495
496    // get an user stack vseg from local VMM allocator
497    child_us_vseg = vmm_create_vseg( child_process,
498                                     VSEG_TYPE_STACK,
499                                     LTID_FROM_TRDID( child_trdid ), 
500                                     0,                               // size unused
501                                     0,                               // file_offset unused
502                                     0,                               // file_size unused
503                                     XPTR_NULL,                       // mapper_xp unused
504                                     local_cxy );
505    if( child_us_vseg == NULL )
506    {
507            printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
508        process_remove_thread( child_ptr );
509        thread_destroy( child_ptr );
510        return -1;
511    }
512
513#if (DEBUG_THREAD_USER_FORK & 1)
514if( DEBUG_THREAD_USER_FORK < cycle )
515printk("\n[%s] thread[%x,%x] created an user stack vseg / vpn_base %x / %d pages\n",
516__FUNCTION__, this->process->pid, this->trdid,
517child_us_vseg->vpn_base, child_us_vseg->vpn_size );
518#endif
519
520    // initialize thread descriptor
521    error = thread_init( child_ptr,
522                         child_process,
523                         THREAD_USER,
524                         child_trdid,
525                         parent_func,
526                         parent_args,
527                         core_lid,
528                         child_us_vseg );
529    if( error )
530    {
531            printk("\n[ERROR] in %s : cannot initialize child thread\n", __FUNCTION__ );
532        vmm_remove_vseg( child_process , child_us_vseg ); 
533        process_remove_thread( child_ptr );
534        thread_destroy( child_ptr );
535        return -1;
536    }
537
538#if (DEBUG_THREAD_USER_FORK & 1)
539if( DEBUG_THREAD_USER_FORK < cycle )
540printk("\n[%s] thread[%x,%x] initialised thread %x in process %x\n",
541__FUNCTION__, this->process->pid, this->trdid, child_ptr->trdid, child_process->pid );
542#endif
543
544    // set detached flag if required
545    if( parent_flags & THREAD_FLAG_DETACHED ) child_ptr->flags = THREAD_FLAG_DETACHED;
546
547    // allocate a CPU context for child thread
548        if( hal_cpu_context_alloc( child_ptr ) )
549    {
550            printk("\n[ERROR] in %s : cannot allocate CPU context\n", __FUNCTION__ );
551        vmm_remove_vseg( child_process , child_us_vseg );
552        process_remove_thread( child_ptr );
553        thread_destroy( child_ptr );
554        return -1;
555    }
556
557    // allocate a FPU context for child thread
558        if( hal_fpu_context_alloc( child_ptr ) )
559    {
560            printk("\n[ERROR] in %s : cannot allocate FPU context\n", __FUNCTION__ );
561        vmm_remove_vseg( child_process , child_us_vseg );
562        process_remove_thread( child_ptr );
563        thread_destroy( child_ptr );
564        return -1;
565    }
566
567#if (DEBUG_THREAD_USER_FORK & 1)
568if( DEBUG_THREAD_USER_FORK < cycle )
569printk("\n[%s] thread[%x,%x] created CPU & FPU contexts for thread %x in process %x\n",
570__FUNCTION__, this->process->pid, this->trdid, child_ptr->trdid, child_process->pid );
571#endif
572
573    // scan parent GPT, and copy all valid entries
574    // associated to user stack vseg into child GPT
575    vpn_t  parent_vpn;
576    vpn_t  child_vpn;
577    bool_t mapped;
578    ppn_t  ppn;
579    vpn_t  parent_vpn_base = hal_remote_l32( XPTR( parent_cxy, &parent_us_vseg->vpn_base ) );
580    vpn_t  parent_vpn_size = hal_remote_l32( XPTR( parent_cxy, &parent_us_vseg->vpn_size ) );
581    vpn_t  child_vpn_base  = child_us_vseg->vpn_base;
582    for( parent_vpn = parent_vpn_base , child_vpn = child_vpn_base ; 
583         parent_vpn < (parent_vpn_base + parent_vpn_size) ;
584         parent_vpn++ , child_vpn++ )
585    {
586        error = hal_gpt_pte_copy( &child_process->vmm.gpt,
587                                  child_vpn,
588                                  parent_gpt_xp,
589                                  parent_vpn,
590                                  true,                 // set cow
591                                  &ppn,
592                                  &mapped );
593        if( error )
594        {
595            printk("\n[ERROR] in %s : cannot update child GPT\n", __FUNCTION__ );
596            vmm_remove_vseg( child_process , child_us_vseg );
597            process_remove_thread( child_ptr );
598            thread_destroy( child_ptr );
599            return -1;
600        }
601
602        // increment pending forks counter for a mapped page
603        if( mapped )
604        {
605            // get pointers on the page descriptor
606            xptr_t   page_xp  = ppm_ppn2page( ppn );
607            cxy_t    page_cxy = GET_CXY( page_xp );
608            page_t * page_ptr = GET_PTR( page_xp );
609
610            // build extended pointers on forks and lock fields
611            xptr_t forks_xp = XPTR( page_cxy , &page_ptr->forks );
612            xptr_t lock_xp  = XPTR( page_cxy , &page_ptr->lock );
613
614            // get lock protecting page
615            remote_busylock_acquire( lock_xp ); 
616
617            // increment the forks counter in page descriptor
618            hal_remote_atomic_add( forks_xp , 1 );
619
620            // release lock protecting page
621            remote_busylock_release( lock_xp ); 
622        }
623    }
624
625#if (DEBUG_THREAD_USER_FORK & 1)
626if( DEBUG_THREAD_USER_FORK < cycle )
627printk("\n[%s] thread[%x,%x] copied all stack vseg PTEs to child GPT\n",
628__FUNCTION__, this->process->pid, this->trdid );
629#endif
630
631    // set COW flag for all mapped entries of user stack vseg in parent GPT
632    hal_gpt_set_cow( parent_gpt_xp,
633                     parent_vpn_base,
634                     parent_vpn_size );
635
636#if (DEBUG_THREAD_USER_FORK & 1)
637if( DEBUG_THREAD_USER_FORK < cycle )
638printk("\n[%s] thread[%x,%x] set the COW flag for stack vseg in parent GPT\n",
639__FUNCTION__, this->process->pid, this->trdid );
640#endif
641
642    // return child pointer
643    *child_thread = child_ptr;
644
645#if DEBUG_THREAD_USER_FORK
646cycle = (uint32_t)hal_get_cycles();
647if( DEBUG_THREAD_USER_FORK < cycle )
648printk("\n[%s] thread[%x,%x] exit / created thread[%x,%x] / cycle %d\n",
649__FUNCTION__, this->process->pid, this->trdid,
650child_ptr->process->pid, child_ptr->trdid, cycle );
651#endif
652
653        return 0;
654
655}  // end thread_user_fork()
656
657////////////////////////////////////////////////
658error_t thread_user_exec( void     * entry_func,
659                          uint32_t   argc,
660                          char    ** argv )
661{
662    thread_t  * thread  = CURRENT_THREAD;
663    process_t * process = thread->process;
664
665#if DEBUG_THREAD_USER_EXEC
666uint32_t cycle = (uint32_t)hal_get_cycles();
667if( DEBUG_THREAD_USER_EXEC < cycle )
668printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
669__FUNCTION__, process->pid, thread->trdid, cycle );
670#endif
671
672// check parent thread attributes
673assert( (thread->type == THREAD_USER )          , "bad type" );
674assert( (thread->signature == THREAD_SIGNATURE) , "bad signature" );
675assert( (thread->busylocks == 0)                , "bad busylocks" );
676
677        // re-initialize various thread descriptor fields
678    thread->quantum         = 0;            // TODO
679    thread->ticks_nr        = 0;            // TODO
680    thread->time_last_check = 0;            // TODO
681
682    thread->entry_func      = entry_func;
683    thread->main_argc       = argc; 
684    thread->main_argv       = argv;
685
686    // the main thread is always detached
687    thread->flags           = THREAD_FLAG_DETACHED;
688    thread->blocked         = 0;
689    thread->errno           = 0;
690    thread->fork_user       = 0;    // not inherited
691    thread->fork_cxy        = 0;    // not inherited
692
693    // re-initialize busylocks counters
694    thread->busylocks       = 0;
695
696    // reset thread info
697    memset( &thread->info , 0 , sizeof(thread_info_t) );
698
699    // re-initialize join_lock
700    remote_busylock_init( XPTR( local_cxy , &thread->join_lock ), LOCK_THREAD_JOIN );
701
702    // allocate an user stack vseg for main thread
703    vseg_t * us_vseg = vmm_create_vseg( process,
704                                        VSEG_TYPE_STACK,
705                                        LTID_FROM_TRDID( thread->trdid ),
706                                        0,                 // length unused
707                                        0,                 // file_offset unused
708                                        0,                 // file_size unused
709                                        XPTR_NULL,         // mapper_xp unused
710                                        local_cxy );
711    if( us_vseg == NULL )
712    {
713            printk("\n[ERROR] in %s : cannot create stack vseg for main thread\n", __FUNCTION__ );
714                return -1;
715    }
716
717    // update user stack in thread descriptor
718    thread->user_stack_vseg = us_vseg;
719   
720    // release FPU ownership if required
721    if( thread->core->fpu_owner == thread ) thread->core->fpu_owner = NULL;
722
723    // re-initialize  FPU context
724    hal_fpu_context_init( thread );
725
726#if DEBUG_THREAD_USER_EXEC
727cycle = (uint32_t)hal_get_cycles();
728if( DEBUG_THREAD_USER_EXEC < cycle )
729printk("\n[%s] thread[%x,%x] set CPU context & jump to user code / cycle %d\n",
730__FUNCTION__, process->pid, thread->trdid, cycle );
731hal_vmm_display( process , true );
732#endif
733
734    // re-initialize CPU context... and jump to user code
735        hal_cpu_context_exec( thread );
736
737    assert( false, "we should not execute this code");
738 
739    return 0;
740
741}  // end thread_user_exec()
742
743/////////////////////////////////////////////////////////
744error_t thread_kernel_create( thread_t     ** new_thread,
745                              thread_type_t   type,
746                              void          * func,
747                              void          * args,
748                                              lid_t           core_lid )
749{
750    error_t        error;
751        thread_t     * thread;       // pointer on new thread descriptor
752    trdid_t        trdid;        // new thread identifier
753
754    thread_t * this = CURRENT_THREAD; 
755
756assert( ( (type == THREAD_IDLE) || (type == THREAD_RPC) || (type == THREAD_DEV) ) ,
757"illegal thread type" );
758
759assert( (core_lid < LOCAL_CLUSTER->cores_nr) ,
760"illegal core_lid" );
761
762#if DEBUG_THREAD_KERNEL_CREATE
763uint32_t   cycle = (uint32_t)hal_get_cycles();
764if( DEBUG_THREAD_KERNEL_CREATE < cycle )
765printk("\n[%s] thread[%x,%x] enter / requested_type %s / cycle %d\n",
766__FUNCTION__, this->process->pid, this->trdid, thread_type_str(type), cycle );
767#endif
768
769    // allocate memory for new thread descriptor
770    thread = thread_alloc();
771
772    if( thread == NULL )
773    {
774        printk("\n[ERROR] in %s : thread %x in process %x\n"
775        "   no memory for thread descriptor\n",
776        __FUNCTION__, this->trdid, this->process->pid );
777        return ENOMEM;
778    }
779
780    // set type in thread descriptor
781    thread->type = type;
782
783    // register new thread in local kernel process descriptor, and get a TRDID
784    error = process_register_thread( &process_zero , thread , &trdid );
785
786    if( error )
787    {
788        printk("\n[ERROR] in %s : cannot register thread in kernel process\n", __FUNCTION__ );
789        return -1;
790    }
791
792    // set trdid in thread descriptor
793    thread->trdid = trdid;
794
795    // initialize thread descriptor
796    error = thread_init( thread,
797                         &process_zero,
798                         type,
799                         trdid,
800                         func,
801                         args,
802                         core_lid,
803                         NULL );  // no user stack for a kernel thread
804
805    if( error ) // release allocated memory for thread descriptor
806    {
807        printk("\n[ERROR] in %s : cannot initialize thread descriptor\n", __FUNCTION__ );
808        thread_destroy( thread );
809        return ENOMEM;
810    }
811
812    // allocate & initialize CPU context
813        error = hal_cpu_context_alloc( thread );
814
815    if( error )
816    {
817        printk("\n[ERROR] in %s : thread %x in process %x\n"
818        "    cannot create CPU context\n",
819        __FUNCTION__, this->trdid, this->process->pid );
820        thread_destroy( thread );
821        return EINVAL;
822    }
823
824    hal_cpu_context_init( thread );
825
826    // set THREAD_BLOCKED_IDLE for DEV threads
827    if( type == THREAD_DEV ) thread->blocked |= THREAD_BLOCKED_IDLE;
828
829#if DEBUG_THREAD_KERNEL_CREATE
830cycle = (uint32_t)hal_get_cycles();
831if( DEBUG_THREAD_KERNEL_CREATE < cycle )
832printk("\n[%s] thread[%x,%x] exit / new_thread %x / type %s / cycle %d\n",
833__FUNCTION__, this->process->pid, this->trdid, thread, thread_type_str(type), cycle );
834#endif
835
836    *new_thread = thread;
837        return 0;
838
839} // end thread_kernel_create()
840
841//////////////////////////////////////////////
842void thread_idle_init( thread_t      * thread,
843                       thread_type_t   type,
844                       void          * func,
845                       void          * args,
846                           lid_t           core_lid )
847{
848    trdid_t trdid;   
849    error_t error;
850
851// check arguments
852assert( (type == THREAD_IDLE) , "illegal thread type" );
853assert( (core_lid < LOCAL_CLUSTER->cores_nr) , "illegal core index" );
854
855    // set type in thread descriptor
856    thread->type = THREAD_IDLE;
857
858    // register idle thread in local kernel process descriptor, and get a TRDID
859    error = process_register_thread( &process_zero , thread , &trdid );
860
861assert( (error == 0), "cannot register idle_thread in kernel process" );
862
863    // set trdid in thread descriptor
864    thread->trdid = trdid;
865
866    // initialize thread descriptor
867    error = thread_init( thread,
868                         &process_zero,
869                         THREAD_IDLE,
870                         trdid,
871                         func,
872                         args,
873                         core_lid,
874                         NULL );   // no user stack for a kernel thread
875
876assert( (error == 0), "cannot initialize idle_thread" );
877
878    // allocate & initialize CPU context if success
879    error = hal_cpu_context_alloc( thread );
880
881assert( (error == 0), "cannot allocate CPU context" );
882
883    hal_cpu_context_init( thread );
884
885}  // end thread_idle_init()
886
887////////////////////////////////////////////
888uint32_t thread_destroy( thread_t * thread )
889{
890    reg_t           save_sr;
891    uint32_t        count;
892
893    thread_type_t   type    = thread->type;
894    process_t     * process = thread->process;
895    core_t        * core    = thread->core;
896
897#if DEBUG_THREAD_DESTROY
898uint32_t   cycle = (uint32_t)hal_get_cycles();
899thread_t * this  = CURRENT_THREAD;
900if( DEBUG_THREAD_DESTROY < cycle )
901printk("\n[%s] thread[%x,%x] enter to destroy thread[%x,%x] / cycle %d\n",
902__FUNCTION__, this->process->pid, this->trdid, process->pid, thread->trdid, cycle );
903#endif
904
905    // check calling thread busylocks counter
906    thread_assert_can_yield( thread , __FUNCTION__ );
907
908    // update target process instrumentation counter
909        process->vmm.pgfault_nr += thread->info.pgfault_nr;
910
911    // remove thread from process th_tbl[]
912    count = process_remove_thread( thread );
913
914    // release memory allocated for CPU context and FPU context if required
915        hal_cpu_context_destroy( thread );
916        hal_fpu_context_destroy( thread );
917       
918    // release user stack vseg (for an user thread only)
919    if( type == THREAD_USER )  vmm_remove_vseg( process , thread->user_stack_vseg );
920
921    // release FPU ownership if required
922        hal_disable_irq( &save_sr );
923        if( core->fpu_owner == thread )
924        {
925                core->fpu_owner = NULL;
926                hal_fpu_disable();
927        }
928        hal_restore_irq( save_sr );
929
930    // invalidate thread descriptor
931        thread->signature = 0;
932
933    // release memory for thread descriptor (including kernel stack)
934    kmem_req_t   req;
935    xptr_t       base_xp = ppm_base2page( XPTR(local_cxy , thread ) );
936
937    req.type  = KMEM_PAGE;
938    req.ptr   = GET_PTR( base_xp );
939    kmem_free( &req );
940
941#if DEBUG_THREAD_DESTROY
942cycle = (uint32_t)hal_get_cycles();
943if( DEBUG_THREAD_DESTROY < cycle )
944printk("\n[%s] thread[%x,%x] exit / destroyed thread[%x,%x] / cycle %d\n",
945__FUNCTION__, this->process->pid, this->trdid, process->pid, thread->trdid, cycle );
946#endif
947
948    return count;
949
950}   // end thread_destroy()
951
952//////////////////////////////////////////////////
953inline void thread_set_req_ack( thread_t * target,
954                                uint32_t * rsp_count )
955{
956    reg_t    save_sr;   // for critical section
957
958    // get pointer on target thread scheduler
959    scheduler_t * sched = &target->core->scheduler;
960
961    // wait scheduler ready to handle a new request
962    while( sched->req_ack_pending ) asm volatile( "nop" );
963   
964    // enter critical section
965    hal_disable_irq( &save_sr );
966     
967    // set request in target thread scheduler
968    sched->req_ack_pending = true;
969
970    // set ack request in target thread "flags"
971    hal_atomic_or( &target->flags , THREAD_FLAG_REQ_ACK );
972
973    // set pointer on responses counter in target thread
974    target->ack_rsp_count = rsp_count;
975   
976    // exit critical section
977    hal_restore_irq( save_sr );
978
979    hal_fence();
980
981}  // thread_set_req_ack()
982
983/////////////////////////////////////////////////////
984inline void thread_reset_req_ack( thread_t * target )
985{
986    reg_t    save_sr;   // for critical section
987
988    // get pointer on target thread scheduler
989    scheduler_t * sched = &target->core->scheduler;
990
991    // check signal pending in scheduler
992    assert( sched->req_ack_pending , "no pending signal" );
993   
994    // enter critical section
995    hal_disable_irq( &save_sr );
996     
997    // reset signal in scheduler
998    sched->req_ack_pending = false;
999
1000    // reset signal in thread "flags"
1001    hal_atomic_and( &target->flags , ~THREAD_FLAG_REQ_ACK );
1002
1003    // reset pointer on responses counter
1004    target->ack_rsp_count = NULL;
1005   
1006    // exit critical section
1007    hal_restore_irq( save_sr );
1008
1009    hal_fence();
1010
1011}  // thread_reset_req_ack()
1012
1013//////////////////////////////////////
1014void thread_block( xptr_t   thread_xp,
1015                   uint32_t cause )
1016{
1017    // get thread cluster and local pointer
1018    cxy_t      cxy = GET_CXY( thread_xp );
1019    thread_t * ptr = GET_PTR( thread_xp );
1020
1021    // set blocking cause
1022    hal_remote_atomic_or( XPTR( cxy , &ptr->blocked ) , cause );
1023    hal_fence();
1024
1025#if DEBUG_THREAD_BLOCK
1026uint32_t    cycle   = (uint32_t)hal_get_cycles();
1027process_t * process = hal_remote_lpt( XPTR( cxy , &ptr->process ) );
1028thread_t  * this    = CURRENT_THREAD;
1029if( DEBUG_THREAD_BLOCK < cycle )
1030printk("\n[%s] thread[%x,%x] blocked thread %x in process %x / cause %x\n",
1031__FUNCTION__, this->process->pid, this->trdid,
1032ptr->trdid, hal_remote_l32(XPTR( cxy , &process->pid )), cause );
1033#endif
1034
1035} // end thread_block()
1036
1037////////////////////////////////////////////
1038uint32_t thread_unblock( xptr_t   thread_xp,
1039                         uint32_t cause )
1040{
1041    // get thread cluster and local pointer
1042    cxy_t      cxy = GET_CXY( thread_xp );
1043    thread_t * ptr = GET_PTR( thread_xp );
1044
1045    // reset blocking cause
1046    uint32_t previous = hal_remote_atomic_and( XPTR( cxy , &ptr->blocked ) , ~cause );
1047    hal_fence();
1048
1049#if DEBUG_THREAD_BLOCK
1050uint32_t    cycle   = (uint32_t)hal_get_cycles();
1051process_t * process = hal_remote_lpt( XPTR( cxy , &ptr->process ) );
1052thread_t  * this    = CURRENT_THREAD;
1053if( DEBUG_THREAD_BLOCK < cycle )
1054printk("\n[%s] thread[%x,%x] unblocked thread %x in process %x / cause %x\n",
1055__FUNCTION__, this->process->pid, this->trdid,
1056ptr->trdid, hal_remote_l32(XPTR( cxy , &process->pid )), cause );
1057#endif
1058
1059    // return a non zero value if the cause bit is modified
1060    return( previous & cause );
1061
1062}  // end thread_unblock()
1063
1064//////////////////////////////////////
1065void thread_delete( xptr_t  target_xp,
1066                    pid_t   pid,
1067                    bool_t  is_forced )
1068{
1069    reg_t       save_sr;                // for critical section
1070    bool_t      target_join_done;       // joining thread arrived first
1071    bool_t      target_attached;        // target thread attached
1072    xptr_t      killer_xp;              // extended pointer on killer thread (this)
1073    thread_t  * killer_ptr;             // pointer on killer thread (this)
1074    cxy_t       target_cxy;             // target thread cluster     
1075    thread_t  * target_ptr;             // pointer on target thread
1076    process_t * target_process;         // pointer on arget process
1077    pid_t       target_pid;             // target process identifier
1078    xptr_t      target_flags_xp;        // extended pointer on target thread <flags>
1079    xptr_t      target_join_lock_xp;    // extended pointer on target thread <join_lock>
1080    xptr_t      target_join_xp_xp;      // extended pointer on target thread <join_xp>
1081    trdid_t     target_trdid;           // target thread identifier
1082    ltid_t      target_ltid;            // target thread local index
1083    xptr_t      joining_xp;             // extended pointer on joining thread
1084    thread_t  * joining_ptr;            // pointer on joining thread
1085    cxy_t       joining_cxy;            // joining thread cluster
1086
1087    // get target thread cluster and local pointer
1088    target_cxy      = GET_CXY( target_xp );
1089    target_ptr      = GET_PTR( target_xp );
1090
1091    // get target thread identifier, attached flag, and process PID
1092    target_trdid    = hal_remote_l32( XPTR( target_cxy , &target_ptr->trdid ) );
1093    target_ltid     = LTID_FROM_TRDID( target_trdid );
1094    target_flags_xp = XPTR( target_cxy , &target_ptr->flags ); 
1095    target_attached = ( (hal_remote_l32( target_flags_xp ) & THREAD_FLAG_DETACHED) == 0 );
1096    target_process  = hal_remote_lpt( XPTR( target_cxy , &target_ptr->process ) );
1097    target_pid      = hal_remote_l32( XPTR( target_cxy , &target_process->pid ) );
1098
1099// check target PID
1100assert( (pid == target_pid),
1101"unconsistent pid and target_xp arguments" );
1102
1103    // get killer thread pointers
1104    killer_ptr = CURRENT_THREAD;
1105    killer_xp  = XPTR( local_cxy , killer_ptr );
1106
1107#if DEBUG_THREAD_DELETE
1108uint32_t cycle  = (uint32_t)hal_get_cycles();
1109if( DEBUG_THREAD_DELETE < cycle )
1110printk("\n[%s] killer[%x,%x] enters / target[%x,%x] / cycle %d\n",
1111__FUNCTION__, killer_ptr->process->pid, killer_ptr->trdid, 
1112target_ptr->process->pid, target_ptr->trdid, cycle );
1113#endif
1114
1115// check target thread is not the main thread, because the main thread
1116// must be deleted by the parent process sys_wait() function
1117assert( ((CXY_FROM_PID( pid ) != target_cxy) || (target_ltid != 0)),
1118"target thread cannot be the main thread" );
1119
1120    // check killer thread can yield
1121    thread_assert_can_yield( killer_ptr , __FUNCTION__ ); 
1122
1123    // if the target thread is attached, we must synchonize with the joining thread
1124    // before blocking and marking the target thead for delete.
1125
1126    if( target_attached && (is_forced == false) ) // synchronize with joining thread
1127    {
1128        // build extended pointers on target thread join fields
1129        target_join_lock_xp  = XPTR( target_cxy , &target_ptr->join_lock );
1130        target_join_xp_xp    = XPTR( target_cxy , &target_ptr->join_xp );
1131
1132        // enter critical section
1133        hal_disable_irq( &save_sr );
1134
1135        // take the join_lock in target thread descriptor
1136        remote_busylock_acquire( target_join_lock_xp );
1137
1138        // get join_done from target thread descriptor
1139        target_join_done = ((hal_remote_l32( target_flags_xp ) & THREAD_FLAG_JOIN_DONE) != 0);
1140   
1141        if( target_join_done )                     // joining thread arrived first
1142        {
1143            // get extended pointer on joining thread
1144            joining_xp  = (xptr_t)hal_remote_l64( target_join_xp_xp );
1145            joining_ptr = GET_PTR( joining_xp );
1146            joining_cxy = GET_CXY( joining_xp );
1147           
1148            // reset the join_done flag in target thread
1149            hal_remote_atomic_and( target_flags_xp , ~THREAD_FLAG_JOIN_DONE );
1150
1151            // unblock the joining thread
1152            thread_unblock( joining_xp , THREAD_BLOCKED_JOIN );
1153
1154            // release the join_lock in target thread descriptor
1155            remote_busylock_release( target_join_lock_xp );
1156
1157            // block the target thread
1158            thread_block( target_xp , THREAD_BLOCKED_GLOBAL );
1159
1160            // set the REQ_DELETE flag in target thread descriptor
1161            hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
1162
1163            // exit critical section
1164            hal_restore_irq( save_sr );
1165
1166#if DEBUG_THREAD_DELETE
1167cycle  = (uint32_t)hal_get_cycles;
1168if( DEBUG_THREAD_DELETE < cycle )
1169printk("\n[%s] killer[%x,%x] exit / target[%x,%x] marked after join / cycle %d\n",
1170__FUNCTION__, killer_ptr->process->pid, killer_ptr->trdid,
1171target_ptr->process->pid, target_ptr->trdid, cycle );
1172#endif
1173
1174        }
1175        else                                      // killer thread arrived first
1176        {
1177            // set the kill_done flag in target thread
1178            hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_KILL_DONE );
1179
1180            // block this thread on BLOCKED_JOIN
1181            thread_block( killer_xp , THREAD_BLOCKED_JOIN );
1182
1183            // set extended pointer on killer thread in target thread
1184            hal_remote_s64( target_join_xp_xp , killer_xp );
1185
1186            // release the join_lock in target thread descriptor
1187            remote_busylock_release( target_join_lock_xp );
1188
1189#if DEBUG_THREAD_DELETE
1190cycle  = (uint32_t)hal_get_cycles;
1191if( DEBUG_THREAD_DELETE < cycle )
1192printk("\n[%s] killer[%x,%x] deschedules / target[%x,%x] not completed / cycle %d\n",
1193__FUNCTION__, killer_ptr->process->pid, killer_ptr->trdid,
1194target_ptr->process->pid, target_ptr->trdid, cycle );
1195#endif
1196            // deschedule
1197            sched_yield( "killer thread wait joining thread" );
1198
1199            // block the target thread
1200            thread_block( target_xp , THREAD_BLOCKED_GLOBAL );
1201
1202            // set the REQ_DELETE flag in target thread descriptor
1203            hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
1204
1205            // exit critical section
1206            hal_restore_irq( save_sr );
1207
1208#if DEBUG_THREAD_DELETE
1209cycle  = (uint32_t)hal_get_cycles;
1210if( DEBUG_THREAD_DELETE < cycle )
1211printk("\n[%s] killer[%x,%x] exit / target[%x,%x] marked after join / cycle %d\n",
1212__FUNCTION__, killer_ptr->process->pid, killer_ptr->trdid,
1213target_ptr->process->pid, target_ptr->trdid, cycle );
1214#endif
1215
1216        }
1217    }
1218    else                     // no synchronization with joining thread required
1219    {
1220        // block the target thread
1221        thread_block( target_xp , THREAD_BLOCKED_GLOBAL );
1222
1223        // set the REQ_DELETE flag in target thread descriptor
1224        hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
1225
1226#if DEBUG_THREAD_DELETE
1227cycle  = (uint32_t)hal_get_cycles;
1228if( DEBUG_THREAD_DELETE < cycle )
1229printk("\n[%s] killer[%x,%x] exit / target [%x,%x] marked / no join / cycle %d\n",
1230__FUNCTION__, killer_ptr->process->pid, killer_ptr->trdid,
1231target_ptr->process->pid, target_ptr->trdid, cycle );
1232#endif
1233
1234    }
1235}  // end thread_delete()
1236
1237
1238
1239/////////////////////////////
1240void thread_idle_func( void )
1241{
1242
1243#if DEBUG_THREAD_IDLE
1244uint32_t cycle;
1245#endif
1246
1247    while( 1 )
1248    {
1249        // unmask IRQs
1250        hal_enable_irq( NULL );
1251
1252        // force core to low-power mode (optional)
1253        if( CONFIG_SCHED_IDLE_MODE_SLEEP ) 
1254        {
1255
1256#if DEBUG_THREAD_IDLE
1257cycle = (uint32_t)hal_get_cycles();
1258if( DEBUG_THREAD_IDLE < cycle )
1259printk("\n[%s] idle thread on core[%x,%d] goes to sleep / cycle %d\n",
1260__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, cycle );
1261#endif
1262
1263            hal_core_sleep();
1264
1265#if DEBUG_THREAD_IDLE
1266cycle = (uint32_t)hal_get_cycles();
1267if( DEBUG_THREAD_IDLE < cycle )
1268printk("\n[%s] idle thread on core[%x,%d] wake up / cycle %d\n",
1269__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, cycle );
1270#endif
1271
1272        }
1273
1274#if DEBUG_THREAD_IDLE
1275cycle = (uint32_t)hal_get_cycles();
1276if( DEBUG_THREAD_IDLE < cycle )
1277sched_display( CURRENT_THREAD->core->lid );
1278#endif     
1279        // search a runable thread
1280        sched_yield( "running idle thread" );
1281
1282    } // end while
1283
1284}  // end thread_idle()
1285
1286
1287///////////////////////////////////////////
1288void thread_time_update( thread_t * thread,
1289                         bool_t     is_user )
1290{
1291    cycle_t current_cycle;   // current cycle counter value
1292    cycle_t last_cycle;      // last cycle counter value
1293
1294    // get pointer on thread_info structure
1295    thread_info_t * info = &thread->info;
1296
1297    // get last cycle counter value
1298    last_cycle = info->last_cycle;
1299
1300    // get current cycle counter value
1301    current_cycle = hal_get_cycles();
1302
1303    // update thread_info structure
1304    info->last_cycle = current_cycle;
1305
1306    // update time in thread_info
1307    if( is_user ) info->usr_cycles += (current_cycle - last_cycle);
1308    else          info->sys_cycles += (current_cycle - last_cycle);
1309
1310}  // end thread_time_update()
1311
1312/////////////////////////////////////
1313xptr_t thread_get_xptr( pid_t    pid,
1314                        trdid_t  trdid )
1315{
1316    cxy_t         target_cxy;          // target thread cluster identifier
1317    ltid_t        target_thread_ltid;  // target thread local index
1318    thread_t    * target_thread_ptr;   // target thread local pointer
1319    xptr_t        target_process_xp;   // extended pointer on target process descriptor
1320    process_t   * target_process_ptr;  // local pointer on target process descriptor
1321    pid_t         target_process_pid;  // target process identifier
1322    xlist_entry_t root;                // root of list of process in target cluster
1323    xptr_t        lock_xp;             // extended pointer on lock protecting  this list
1324
1325#if DEBUG_THREAD_GET_XPTR
1326uint32_t cycle  = (uint32_t)hal_get_cycles();
1327thread_t * this = CURRENT_THREAD;
1328if( DEBUG_THREAD_GET_XPTR < cycle )
1329printk("\n[%s] thread %x in process %x enters / pid %x / trdid %x / cycle %d\n",
1330__FUNCTION__, this->trdid, this->process->pid, pid, trdid, cycle );
1331#endif
1332
1333    // get target cluster identifier and local thread identifier
1334    target_cxy         = CXY_FROM_TRDID( trdid );
1335    target_thread_ltid = LTID_FROM_TRDID( trdid );
1336
1337    // check trdid argument
1338        if( (target_thread_ltid >= CONFIG_THREADS_MAX_PER_CLUSTER) || 
1339        cluster_is_undefined( target_cxy ) )         return XPTR_NULL;
1340
1341    // get root of list of process descriptors in target cluster
1342    hal_remote_memcpy( XPTR( local_cxy  , &root ),
1343                       XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ),
1344                       sizeof(xlist_entry_t) );
1345
1346    // get extended pointer on lock protecting the list of local processes
1347    lock_xp = XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_lock );
1348
1349    // take the lock protecting the list of processes in target cluster
1350    remote_queuelock_acquire( lock_xp );
1351
1352#if( DEBUG_THREAD_GET_XPTR & 1 )
1353if( DEBUG_THREAD_GET_XPTR < cycle )
1354printk("\n[%s] scan processes in cluster %x :\n", __FUNCTION__, target_cxy );
1355#endif
1356
1357    // scan the list of local processes in target cluster
1358    xptr_t  iter;
1359    bool_t  found = false;
1360    XLIST_FOREACH( XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ) , iter )
1361    {
1362        target_process_xp  = XLIST_ELEMENT( iter , process_t , local_list );
1363        target_process_ptr = GET_PTR( target_process_xp );
1364        target_process_pid = hal_remote_l32( XPTR( target_cxy , &target_process_ptr->pid ) );
1365
1366#if( DEBUG_THREAD_GET_XPTR & 1 )
1367if( DEBUG_THREAD_GET_XPTR < cycle )
1368printk(" - process %x\n", target_process_pid );
1369#endif
1370
1371        if( target_process_pid == pid )
1372        {
1373            found = true;
1374            break;
1375        }
1376    }
1377
1378    // release the lock protecting the list of processes in target cluster
1379    remote_queuelock_release( lock_xp );
1380
1381    // check PID found
1382    if( found == false ) 
1383    {
1384
1385#if( DEBUG_THREAD_GET_XPTR & 1 )
1386if( DEBUG_THREAD_GET_XPTR < cycle )
1387printk("\n[%s] pid %x not found in cluster %x\n",
1388__FUNCTION__, pid, target_cxy );
1389#endif
1390        return XPTR_NULL;
1391    }
1392
1393    // get target thread local pointer
1394    xptr_t xp = XPTR( target_cxy , &target_process_ptr->th_tbl[target_thread_ltid] );
1395    target_thread_ptr = (thread_t *)hal_remote_lpt( xp );
1396
1397    if( target_thread_ptr == NULL )
1398    {
1399
1400#if( DEBUG_THREAD_GET_XPTR & 1 )
1401if( DEBUG_THREAD_GET_XPTR < cycle )
1402printk("\n[%s] thread %x not registered in process %x in cluster %x\n",
1403__FUNCTION__, trdid, pid, target_cxy );
1404#endif
1405        return XPTR_NULL;
1406    }
1407
1408#if DEBUG_THREAD_GET_XPTR
1409cycle  = (uint32_t)hal_get_cycles();
1410if( DEBUG_THREAD_GET_XPTR < cycle )
1411printk("\n[%s] thread %x in process %x exit / pid %x / trdid %x / cycle %d\n",
1412__FUNCTION__, this->trdid, this->process->pid, pid, trdid, cycle );
1413#endif
1414
1415    return XPTR( target_cxy , target_thread_ptr );
1416
1417}  // end thread_get_xptr()
1418
1419///////////////////////////////////////////////////
1420void thread_assert_can_yield( thread_t    * thread,
1421                              const char  * func_str )
1422{
1423    // does nothing if thread does not hold any busylock
1424
1425    if( thread->busylocks )
1426    {
1427        // get pointers on TXT0 chdev
1428        xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
1429        cxy_t     txt0_cxy = GET_CXY( txt0_xp );
1430        chdev_t * txt0_ptr = GET_PTR( txt0_xp );
1431
1432        // get extended pointer on TXT0 lock
1433        xptr_t  txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
1434
1435        // get TXT0 lock
1436        remote_busylock_acquire( txt0_lock_xp );
1437
1438        // display error message on TXT0
1439        nolock_printk("\n[PANIC] in %s / thread[%x,%x] cannot yield : "
1440        "hold %d busylock(s) / cycle %d\n",
1441        func_str, thread->process->pid, thread->trdid,
1442        thread->busylocks - 1, (uint32_t)hal_get_cycles() );
1443
1444#if DEBUG_BUSYLOCK
1445
1446// scan list of busylocks
1447xptr_t    iter_xp;
1448xptr_t    root_xp  = XPTR( local_cxy , &thread->busylocks_root );
1449XLIST_FOREACH( root_xp , iter_xp )
1450{
1451    xptr_t       lock_xp   = XLIST_ELEMENT( iter_xp , busylock_t , xlist );
1452    cxy_t        lock_cxy  = GET_CXY( lock_xp );
1453    busylock_t * lock_ptr  = GET_PTR( lock_xp );
1454    uint32_t     lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->type ) );
1455    nolock_printk(" - %s in cluster %x\n", lock_type_str[lock_type] , lock_cxy );
1456}
1457
1458#endif
1459
1460        // release TXT0 lock
1461        remote_busylock_release( txt0_lock_xp );
1462
1463        // suicide
1464        hal_core_sleep();
1465    }
1466}  // end thread_assert_can yield()
1467
1468//////////////////////////////////////////////////////
1469void thread_display_busylocks( xptr_t       thread_xp,
1470                               const char * string )
1471{
1472
1473    cxy_t      thread_cxy = GET_CXY( thread_xp );
1474    thread_t * thread_ptr = GET_PTR( thread_xp );
1475
1476#if DEBUG_BUSYLOCK
1477
1478    xptr_t     iter_xp;
1479
1480    // get relevant info from target thread descriptor
1481    uint32_t    locks   = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->busylocks ) );
1482    trdid_t     trdid   = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
1483    process_t * process = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
1484    pid_t       pid     = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
1485
1486    // get extended pointer on root of busylocks
1487    xptr_t root_xp = XPTR( thread_cxy , &thread_ptr->busylocks_root );
1488
1489    // get pointers on TXT0 chdev
1490    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
1491    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
1492    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
1493
1494    // get extended pointer on remote TXT0 lock
1495    xptr_t  txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
1496
1497    // get TXT0 lock
1498    remote_busylock_acquire( txt0_lock_xp );
1499
1500    // display header
1501    nolock_printk("\n***** thread[%x,%x] in <%s> : %d busylocks *****\n",
1502    pid, trdid, string, locks );
1503
1504    // scan the xlist of busylocks when required
1505    if( locks )
1506    {
1507        XLIST_FOREACH( root_xp , iter_xp )
1508        {
1509            xptr_t       lock_xp   = XLIST_ELEMENT( iter_xp , busylock_t , xlist );
1510            cxy_t        lock_cxy  = GET_CXY( lock_xp );
1511            busylock_t * lock_ptr  = GET_PTR( lock_xp );
1512            uint32_t     lock_type = hal_remote_l32(XPTR( lock_cxy , &lock_ptr->type ));
1513            nolock_printk(" - %s in cluster %x\n", lock_type_str[lock_type] , lock_cxy );
1514        }
1515    }
1516
1517    // release TXT0 lock
1518    remote_busylock_release( txt0_lock_xp );
1519
1520#else
1521
1522printk("\n[ERROR] in %s : set DEBUG_BUSYLOCK in kernel_config.h for %s / thread(%x,%x)\n",
1523__FUNCTION__, string, thread_cxy, thread_ptr );
1524
1525#endif
1526
1527    return;
1528
1529}  // end thread_display_busylock()
1530
Note: See TracBrowser for help on using the repository browser.