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

Last change on this file since 188 was 188, checked in by alain, 9 years ago

Redefine the PIC device API.

File size: 26.8 KB
Line 
1/*
2 * thread.c - implementation of thread operations (user & kernel)
3 *
4 * Author Ghassan Almaless (2008,2009,2010,2011,2012)
5 * Alain Greiner (2016,2017)
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_types.h>
27#include <hal_context.h>
28#include <hal_irqmask.h>
29#include <hal_special.h>
30#include <hal_remote.h>
31#include <memcpy.h>
32#include <printk.h>
33#include <cluster.h>
34#include <process.h>
35#include <scheduler.h>
36#include <dev_pic.h>
37#include <core.h>
38#include <list.h>
39#include <xlist.h>
40#include <page.h>
41#include <kmem.h>
42#include <ppm.h>
43#include <thread.h>
44
45//////////////////////////////////////////////////////////////////////////////////////
46// Extern global variables
47//////////////////////////////////////////////////////////////////////////////////////
48
49extern process_t process_zero;
50
51//////////////////////////////////////////////////////////////////////////////////////
52// This function returns a printable string for the thread type.
53//////////////////////////////////////////////////////////////////////////////////////
54char * thread_type_str( uint32_t type )
55{
56 if ( type == THREAD_USER ) return "USER";
57 else if( type == THREAD_RPC ) return "RPC";
58 else if( type == THREAD_DEV ) return "DEV";
59 else if( type == THREAD_KERNEL ) return "KERNEL";
60 else if( type == THREAD_IDLE ) return "IDLE";
61 else return "undefined";
62}
63
64/////////////////////////////////////////////////////////////////////////////////////
65// This static function allocates physical memory for a thread descriptor.
66// It can be called by the three functions:
67// - thread_user_create()
68// - thread_user_fork()
69// - thread_kernel_create()
70/////////////////////////////////////////////////////////////////////////////////////
71// @ return pointer on thread descriptor if success / return NULL if failure.
72/////////////////////////////////////////////////////////////////////////////////////
73static thread_t * thread_alloc()
74{
75 page_t * page; // pointer on page descriptor containing thread descriptor
76 kmem_req_t req; // kmem request
77
78 // allocates memory for thread descriptor + kernel stack
79 req.type = KMEM_PAGE;
80 req.size = CONFIG_THREAD_DESC_ORDER;
81 req.flags = AF_KERNEL | AF_ZERO;
82 page = kmem_alloc( &req );
83
84 // return pointer on new thread descriptor
85 if( page == NULL ) return NULL;
86 else return (thread_t *)ppm_page2vaddr( page );
87}
88
89/////////////////////////////////////////////////////////////////////////////////////
90// This static function releases the physical memory for a thread descriptor.
91// It is called by the three functions:
92// - thread_user_create()
93// - thread_user_fork()
94// - thread_kernel_create()
95/////////////////////////////////////////////////////////////////////////////////////
96// @ thread : pointer on thread descriptor.
97/////////////////////////////////////////////////////////////////////////////////////
98static void thread_release( thread_t * thread )
99{
100 kmem_req_t req;
101
102 req.type = KMEM_PAGE;
103 req.ptr = ppm_vaddr2page( thread );
104 kmem_free( &req );
105}
106
107/////////////////////////////////////////////////////////////////////////////////////
108// This static function initializes a thread descriptor (kernel or user).
109// It can be called by the four functions:
110// - thread_user_create()
111// - thread_user_fork()
112// - thread_kernel_create()
113// - thread_user_init()
114/////////////////////////////////////////////////////////////////////////////////////
115// @ thread : pointer on thread descriptor
116// @ process : pointer on process descriptor.
117// @ type : thread type.
118// @ func : pointer on thread entry function.
119// @ args : pointer on thread entry function arguments.
120// @ core_lid : target core local index.
121// @ u_stack_base : stack base (user thread only)
122// @ u_stack_size : stack base (user thread only)
123/////////////////////////////////////////////////////////////////////////////////////
124static error_t thread_init( thread_t * thread,
125 process_t * process,
126 thread_type_t type,
127 void * func,
128 void * args,
129 lid_t core_lid,
130 intptr_t u_stack_base,
131 uint32_t u_stack_size )
132{
133 error_t error;
134 trdid_t trdid; // allocated thread identifier
135
136 cluster_t * local_cluster = LOCAL_CLUSTER;
137
138 // register new thread in process descriptor, and get a TRDID
139 spinlock_lock( &process->th_lock );
140 error = process_register_thread( process, thread , &trdid );
141 spinlock_unlock( &process->th_lock );
142
143 if( error )
144 {
145 printk("\n[ERROR] in %s : cannot get TRDID\n", __FUNCTION__ );
146 return EINVAL;
147 }
148
149 // Initialize new thread descriptor
150 thread->trdid = trdid;
151 thread->type = type;
152 thread->quantum = 0; // TODO
153 thread->ticks_nr = 0; // TODO
154 thread->time_last_check = 0;
155 thread->core = &local_cluster->core_tbl[core_lid];
156 thread->process = process;
157
158 thread->local_locks = 0;
159 list_root_init( &thread->locks_root );
160
161 thread->remote_locks = 0;
162 xlist_root_init( XPTR( local_cxy , &thread->xlocks_root ) );
163
164 thread->u_stack_base = u_stack_base;
165 thread->u_stack_size = u_stack_size;
166 thread->k_stack_base = (intptr_t)thread;
167 thread->k_stack_size = CONFIG_THREAD_DESC_SIZE;
168
169 thread->entry_func = func; // thread entry point
170 thread->entry_args = args; // thread function arguments
171 thread->flags = 0; // all flags reset
172 thread->signals = 0; // no pending signal
173 thread->errno = 0; // no error detected
174 thread->fork_user = 0; // no fork required
175 thread->fork_cxy = 0;
176
177 // thread blocked
178 thread->blocked = THREAD_BLOCKED_GLOBAL;
179
180 // reset children list
181 xlist_root_init( XPTR( local_cxy , &thread->children_root ) );
182 thread->children_nr = 0;
183
184 // reset sched list and brothers list
185 list_entry_init( &thread->sched_list );
186 xlist_entry_init( XPTR( local_cxy , &thread->brothers_list ) );
187
188 // reset thread info
189 memset( &thread->info , 0 , sizeof(thread_info_t) );
190
191 // initialise signature
192 thread->signature = THREAD_SIGNATURE;
193
194 // update local DQDT
195 dqdt_local_update_threads( 1 );
196
197 // register new thread in core scheduler
198 sched_register_thread( thread->core , thread );
199
200 return 0;
201}
202
203/////////////////////////////////////////////////////////
204error_t thread_user_create( pid_t pid,
205 void * start_func,
206 void * start_arg,
207 pthread_attr_t * attr,
208 thread_t ** new_thread )
209{
210 error_t error;
211 thread_t * thread; // pointer on created thread descriptor
212 process_t * process; // pointer to local process descriptor
213 lid_t core_lid; // selected core local index
214 vseg_t * vseg; // stack vseg
215
216 thread_dmsg("\n[INFO] %s : enters for process %x\n", __FUNCTION__ , pid );
217
218 // get process descriptor local copy
219 process = process_get_local_copy( pid );
220
221 if( process == NULL )
222 {
223 printk("\n[ERROR] in %s : cannot get process descriptor %x\n",
224 __FUNCTION__ , pid );
225 return ENOMEM;
226 }
227
228 // select a target core in local cluster
229 if( attr->attributes & PT_ATTR_CORE_DEFINED ) core_lid = attr->lid;
230 else core_lid = cluster_select_local_core();
231
232 // check core local index
233 if( core_lid >= LOCAL_CLUSTER->cores_nr )
234 {
235 printk("\n[ERROR] in %s : illegal core index attribute = %d\n",
236 __FUNCTION__ , core_lid );
237
238 return EINVAL;
239 }
240
241 // allocate a stack from local VMM
242 vseg = vmm_create_vseg( process, 0 , 0 , VSEG_TYPE_STACK );
243
244 if( vseg == NULL )
245 {
246 printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
247 return ENOMEM;
248 }
249
250 // allocate memory for thread descriptor
251 thread = thread_alloc();
252
253 if( thread == NULL )
254 {
255 printk("\n[ERROR] in %s : cannot create new thread\n", __FUNCTION__ );
256 vmm_remove_vseg( vseg );
257 return ENOMEM;
258 }
259
260 // initialize thread descriptor
261 error = thread_init( thread,
262 process,
263 THREAD_USER,
264 start_func,
265 start_arg,
266 core_lid,
267 vseg->min,
268 vseg->max - vseg->min );
269
270 if( error )
271 {
272 printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ );
273 vmm_remove_vseg( vseg );
274 thread_release( thread );
275 return EINVAL;
276 }
277
278 // set LOADABLE flag
279 thread->flags = THREAD_FLAG_LOADABLE;
280
281 // set DETACHED flag if required
282 if( attr->attributes & PT_ATTR_DETACH ) thread->flags |= THREAD_FLAG_DETACHED;
283
284 // allocate & initialize CPU context
285 error = hal_cpu_context_create( thread );
286
287 if( error )
288 {
289 printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ );
290 vmm_remove_vseg( vseg );
291 thread_release( thread );
292 return ENOMEM;
293 }
294
295 // allocate & initialize FPU context
296 error = hal_fpu_context_create( thread );
297
298 if( error )
299 {
300 printk("\n[ERROR] in %s : cannot create FPU context\n", __FUNCTION__ );
301 vmm_remove_vseg( vseg );
302 thread_release( thread );
303 return ENOMEM;
304 }
305
306 thread_dmsg("\n[INFO] %s : exit / trdid = %x / process %x / core = %d\n",
307 __FUNCTION__ , thread->trdid , process->pid , core_lid );
308
309 *new_thread = thread;
310 return 0;
311}
312
313//////////////////////////////////////////////
314error_t thread_user_fork( process_t * process,
315 thread_t ** new_thread )
316{
317 error_t error;
318 thread_t * thread; // pointer on new thread descriptor
319 lid_t core_lid; // selected core local index
320 vseg_t * vseg; // stack vseg
321
322 thread_dmsg("\n[INFO] %s : enters\n", __FUNCTION__ );
323
324 // allocate a stack from local VMM
325 vseg = vmm_create_vseg( process, 0 , 0 , VSEG_TYPE_STACK );
326
327 if( vseg == NULL );
328 {
329 printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
330 return ENOMEM;
331 }
332
333 // select a target core in local cluster
334 core_lid = cluster_select_local_core();
335
336 // get pointer on calling thread descriptor
337 thread_t * this = CURRENT_THREAD;
338
339 // allocate memory for new thread descriptor
340 thread = thread_alloc();
341
342 if( thread == NULL )
343 {
344 printk("\n[ERROR] in %s : cannot allocate new thread\n", __FUNCTION__ );
345 vmm_remove_vseg( vseg );
346 return ENOMEM;
347 }
348
349 // initialize thread descriptor
350 error = thread_init( thread,
351 process,
352 THREAD_USER,
353 this->entry_func,
354 this->entry_args,
355 core_lid,
356 vseg->min,
357 vseg->max - vseg->min );
358
359 if( error )
360 {
361 printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ );
362 vmm_remove_vseg( vseg );
363 thread_release( thread );
364 return EINVAL;
365 }
366
367 // set ATTACHED flag if set in this thread
368 if( this->flags & THREAD_FLAG_DETACHED ) thread->flags = THREAD_FLAG_DETACHED;
369
370 // allocate & initialize CPU context from calling thread
371 error = hal_cpu_context_copy( thread , this );
372
373 if( error )
374 {
375 printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ );
376 vmm_remove_vseg( vseg );
377 thread_release( thread );
378 return ENOMEM;
379 }
380
381 // allocate & initialize FPU context from calling thread
382 error = hal_fpu_context_copy( thread , this );
383
384 if( error )
385 {
386 printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ );
387 vmm_remove_vseg( vseg );
388 thread_release( thread );
389 return ENOMEM;
390 }
391
392 thread_dmsg("\n[INFO] %s : exit / thread %x for process %x on core %d in cluster %x\n",
393 __FUNCTION__, thread->trdid, process->pid, core_lid, local_cxy );
394
395 *new_thread = thread;
396 return 0;
397}
398
399/////////////////////////////////////////////////////////
400error_t thread_kernel_create( thread_t ** new_thread,
401 thread_type_t type,
402 void * func,
403 void * args,
404 lid_t core_lid )
405{
406 error_t error;
407 thread_t * thread; // pointer on new thread descriptor
408
409 thread_dmsg("\n[INFO] %s : enters for type %s in cluster %x\n",
410 __FUNCTION__ , thread_type_str( type ) , local_cxy );
411
412 assert( ( (type == THREAD_KERNEL) || (type == THREAD_RPC) ||
413 (type == THREAD_IDLE) || (type == THREAD_DEV) ) ,
414 __FUNCTION__ , "illegal thread type" );
415
416 assert( (core_lid < LOCAL_CLUSTER->cores_nr) ,
417 __FUNCTION__ , "illegal core_lid" );
418
419 // allocate memory for new thread descriptor
420 thread = thread_alloc();
421
422 if( thread == NULL ) return ENOMEM;
423
424 // initialize thread descriptor
425 error = thread_init( thread,
426 &process_zero,
427 type,
428 func,
429 args,
430 core_lid,
431 0 , 0 ); // no user stack for a kernel thread
432
433 if( error ) // release allocated memory for thread descriptor
434 {
435 thread_release( thread );
436 return EINVAL;
437 }
438
439 // allocate & initialize CPU context
440 hal_cpu_context_create( thread );
441
442 thread_dmsg("\n[INFO] %s : exit in cluster %x / trdid = %x / core_lid = %d\n",
443 __FUNCTION__ , local_cxy , thread->trdid , core_lid );
444
445 *new_thread = thread;
446 return 0;
447}
448
449///////////////////////////////////////////////////
450error_t thread_kernel_init( thread_t * thread,
451 thread_type_t type,
452 void * func,
453 void * args,
454 lid_t core_lid )
455{
456 assert( ( (type == THREAD_KERNEL) || (type == THREAD_RPC) ||
457 (type == THREAD_IDLE) || (type == THREAD_DEV) ) ,
458 __FUNCTION__ , "illegal thread type" );
459
460 if( core_lid >= LOCAL_CLUSTER->cores_nr )
461 {
462 printk("\n[PANIC] in %s : illegal core_lid / cores = %d / lid = %d / cxy = %x\n",
463 __FUNCTION__ , LOCAL_CLUSTER->cores_nr , core_lid , local_cxy );
464 hal_core_sleep();
465 }
466
467 error_t error = thread_init( thread,
468 &process_zero,
469 type,
470 func,
471 args,
472 core_lid,
473 0 , 0 ); // no user stack for a kernel thread
474
475 // allocate & initialize CPU context if success
476 if( error == 0 ) hal_cpu_context_create( thread );
477
478 return error;
479}
480
481///////////////////////////////////////////////////////////////////////////////////////
482// TODO: check that all memory dynamically allocated during thread execution
483// has been released, using a cache of mmap and malloc requests. [AG]
484///////////////////////////////////////////////////////////////////////////////////////
485void thread_destroy( thread_t * thread )
486{
487 uint32_t tm_start;
488 uint32_t tm_end;
489 reg_t state;
490
491 process_t * process = thread->process;
492 core_t * core = thread->core;
493
494 thread_dmsg("\n[INFO] %s : enters for thread %x in process %x / type = %s\n",
495 __FUNCTION__ , thread->trdid , process->pid , thread_type_str( thread->type ) );
496
497 assert( (thread->children_nr == 0) , __FUNCTION__ , "still attached children" );
498
499 assert( (thread->local_locks == 0) , __FUNCTION__ , "all local locks not released" );
500
501 assert( (thread->remote_locks == 0) , __FUNCTION__ , "all remote locks not released" );
502
503 tm_start = hal_get_cycles();
504
505 // update intrumentation values
506 uint32_t pgfaults = thread->info.pgfault_nr;
507 uint32_t u_errors = thread->info.u_err_nr;
508 uint32_t m_errors = thread->info.m_err_nr;
509
510 process->vmm.pgfault_nr += pgfaults;
511 process->vmm.u_err_nr += u_errors;
512 process->vmm.m_err_nr += m_errors;
513
514 // release memory allocated for CPU context and FPU context
515 hal_cpu_context_destroy( thread );
516 hal_fpu_context_destroy( thread );
517
518 // release FPU if required
519 // TODO This should be done before calling thread_destroy()
520 hal_disable_irq( &state );
521 if( core->fpu_owner == thread )
522 {
523 core->fpu_owner = NULL;
524 hal_fpu_disable();
525 }
526 hal_restore_irq( state );
527
528 // remove thread from process th_tbl[]
529 // TODO This should be done before calling thread_destroy()
530 ltid_t ltid = LTID_FROM_TRDID( thread->trdid );
531
532 spinlock_lock( &process->th_lock );
533 process->th_tbl[ltid] = XPTR_NULL;
534 process->th_nr--;
535 spinlock_unlock( &process->th_lock );
536
537 // update local DQDT
538 dqdt_local_update_threads( -1 );
539
540 // invalidate thread descriptor
541 thread->signature = 0;
542
543 // release memory for thread descriptor
544 thread_release( thread );
545
546 tm_end = hal_get_cycles();
547
548 thread_dmsg("\n[INFO] %s : exit for thread %x in process %x / duration = %d\n",
549 __FUNCTION__, thread->trdid , process->pid , tm_end - tm_start );
550}
551
552/////////////////////////////////////////////////
553void thread_child_parent_link( xptr_t xp_parent,
554 xptr_t xp_child )
555{
556 // get extended pointers on children list root
557 cxy_t parent_cxy = GET_CXY( xp_parent );
558 thread_t * parent_ptr = (thread_t *)GET_PTR( xp_parent );
559 xptr_t root = XPTR( parent_cxy , &parent_ptr->children_root );
560
561 // get extended pointer on children list entry
562 cxy_t child_cxy = GET_CXY( xp_child );
563 thread_t * child_ptr = (thread_t *)GET_PTR( xp_child );
564 xptr_t entry = XPTR( child_cxy , &child_ptr->brothers_list );
565
566 // set the link
567 xlist_add_first( root , entry );
568 hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr ) , 1 );
569}
570
571///////////////////////////////////////////////////
572void thread_child_parent_unlink( xptr_t xp_parent,
573 xptr_t xp_child )
574{
575 // get extended pointer on children list lock
576 cxy_t parent_cxy = GET_CXY( xp_parent );
577 thread_t * parent_ptr = (thread_t *)GET_PTR( xp_parent );
578 xptr_t lock = XPTR( parent_cxy , &parent_ptr->children_lock );
579
580 // get extended pointer on children list entry
581 cxy_t child_cxy = GET_CXY( xp_child );
582 thread_t * child_ptr = (thread_t *)GET_PTR( xp_child );
583 xptr_t entry = XPTR( child_cxy , &child_ptr->brothers_list );
584
585 // get the lock
586 remote_spinlock_lock( lock );
587
588 // remove the link
589 xlist_unlink( entry );
590 hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr ) , -1 );
591
592 // release the lock
593 remote_spinlock_unlock( lock );
594}
595
596/////////////////////////////////////////////////
597inline void thread_set_signal( thread_t * thread,
598 uint32_t mask )
599{
600 hal_atomic_or( &thread->signals , mask );
601}
602
603///////////////////////////////////////////////////
604inline void thread_reset_signal( thread_t * thread,
605 uint32_t mask )
606{
607 hal_atomic_and( &thread->signals , ~mask );
608}
609
610//////////////////////////////////
611inline bool_t thread_is_joinable()
612{
613 thread_t * this = CURRENT_THREAD;
614 return( (this->brothers_list.next != XPTR_NULL) &&
615 (this->brothers_list.pred != XPTR_NULL) );
616}
617
618//////////////////////////////////
619inline bool_t thread_is_runnable()
620{
621 thread_t * this = CURRENT_THREAD;
622 return( this->blocked == 0 );
623}
624
625////////////////////////////////
626inline bool_t thread_can_yield()
627{
628 thread_t * this = CURRENT_THREAD;
629 return ( (this->local_locks == 0) && (this->remote_locks == 0) );
630}
631
632///////////////////////////
633bool_t thread_check_sched()
634{
635 thread_t * this = CURRENT_THREAD;
636
637 // check locks count
638 if( (this->local_locks != 0) || (this->remote_locks != 0) ) return false;
639
640 // compute elapsed time, taking into account 32 bits register wrap
641 uint32_t elapsed;
642 uint32_t time_now = hal_get_cycles();
643 uint32_t time_last = this->time_last_check;
644 if( time_now < time_last ) elapsed = (0xFFFFFFFF - time_last) + time_now;
645 else elapsed = time_now - time_last;
646
647 // update thread time
648 this->time_last_check = time_now;
649
650 // check elapsed time
651 if( elapsed < CONFIG_CORE_CHECK_EVERY ) return false;
652 else return true;
653}
654
655/////////////////////
656error_t thread_exit()
657{
658 reg_t sr_save;
659
660 thread_t * this = CURRENT_THREAD;
661
662 // test if this thread can be descheduled
663 if( !thread_can_yield() )
664 {
665 printk("ERROR in %s : thread %x in process %x on core %d in cluster %x\n"
666 " did not released all locks\n",
667 __FUNCTION__ , this->trdid , this->process->pid ,
668 CURRENT_CORE->lid , local_cxy );
669 return EINVAL;
670 }
671
672 if( this->flags & THREAD_FLAG_DETACHED )
673 {
674 // if detached set signal and set blocking cause atomically
675 hal_disable_irq( &sr_save );
676 thread_set_signal( this , THREAD_SIG_KILL );
677 thread_block( this , THREAD_BLOCKED_EXIT );
678 hal_restore_irq( sr_save );
679 }
680 else
681 {
682 // if attached, set blocking cause
683 thread_block( this , THREAD_BLOCKED_EXIT );
684 }
685
686 // deschedule
687 sched_yield();
688 return 0;
689}
690
691/////////////////////////////////////
692void thread_block( thread_t * thread,
693 uint32_t cause )
694{
695 // set blocking cause
696 hal_atomic_or( &thread->blocked , cause );
697}
698
699////////////////////////////////////
700void thread_unblock( xptr_t thread,
701 uint32_t cause )
702{
703 // get thread cluster and local pointer
704 cxy_t cxy = GET_CXY( thread );
705 thread_t * ptr = (thread_t *)GET_PTR( thread );
706
707 // reset blocking cause
708 hal_remote_atomic_and( XPTR( cxy , &ptr->blocked ) , ~cause );
709}
710
711/////////////////////////////////////
712void thread_kill( thread_t * target )
713{
714 // set SIG_KILL signal in target thread descriptor
715 thread_set_signal( target , THREAD_SIG_KILL );
716
717 // set the global blocked bit in target thread descriptor.
718 thread_block( target , THREAD_BLOCKED_GLOBAL );
719
720 // send an IPI to schedule the target thread core.
721 dev_pic_send_ipi( local_cxy , target->core->lid );
722}
723
724///////////////////////
725void thread_idle_func()
726{
727#if CONFIG_IDLE_DEBUG
728 lid_t lid = CURRENT_CORE->lid;
729#endif
730
731 while( 1 )
732 {
733 idle_dmsg("\n[INFO] %s : core[%x][%d] goes to sleep at cycle %d\n",
734 __FUNCTION__ , local_cxy , lid , hal_get_cycles() );
735
736 // force core to sleeping state
737 hal_core_sleep();
738
739 idle_dmsg("\n[INFO] %s : core[%x][%d] wake up at cycle %d\n",
740 __FUNCTION__ , local_cxy , lid , hal_get_cycles() );
741
742 // force scheduling
743 sched_yield();
744 }
745}
746
747/////////////////////////////////////////////////
748void thread_user_time_update( thread_t * thread )
749{
750 // TODO
751 printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ );
752}
753
754///////////////////////////////////////////////////
755void thread_kernel_time_update( thread_t * thread )
756{
757 // TODO
758 printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ );
759}
760
761////////////////////////////////////////////////
762void thread_signals_handle( thread_t * thread )
763{
764 // TODO
765 printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ );
766}
767
768/////////////////////////////////////
769xptr_t thread_get_xptr( pid_t pid,
770 trdid_t trdid )
771{
772 cxy_t target_cxy; // target thread cluster identifier
773 ltid_t target_thread_ltid; // target thread local index
774 thread_t * target_thread_ptr; // target thread local pointer
775 xptr_t target_process_xp; // extended pointer on target process descriptor
776 process_t * target_process_ptr; // local pointer on target process descriptor
777 pid_t target_process_pid; // target process identifier
778 xlist_entry_t root; // root of list of process in target cluster
779 xptr_t lock_xp; // extended pointer on lock protecting this list
780
781 // get target cluster identifier and local thread identifier
782 target_cxy = CXY_FROM_TRDID( trdid );
783 target_thread_ltid = LTID_FROM_TRDID( trdid );
784
785 // get root of list of process descriptors in target cluster
786 hal_remote_memcpy( XPTR( local_cxy , &root ),
787 XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ),
788 sizeof(xlist_entry_t) );
789
790 // get extended pointer on lock protecting the list of processes
791 lock_xp = XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_lock );
792
793 // take the lock protecting the list of processes in target cluster
794 remote_spinlock_lock( lock_xp );
795
796 // loop on list of process in target cluster to find the PID process
797 xptr_t iter;
798 bool_t found = false;
799 XLIST_FOREACH( XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ) , iter )
800 {
801 target_process_xp = XLIST_ELEMENT( iter , process_t , local_list );
802 target_process_ptr = (process_t *)GET_PTR( target_process_xp );
803 target_process_pid = hal_remote_lw( XPTR( target_cxy , &target_process_ptr->pid ) );
804 if( target_process_pid == pid )
805 {
806 found = true;
807 break;
808 }
809 }
810
811 // release the lock protecting the list of processes in target cluster
812 remote_spinlock_unlock( lock_xp );
813
814 // check target thread found
815 if( found == false )
816 {
817 return XPTR_NULL;
818 }
819
820 // get target thread local pointer
821 xptr_t xp = XPTR( target_cxy , &target_process_ptr->th_tbl[target_thread_ltid] );
822 target_thread_ptr = (thread_t *)hal_remote_lpt( xp );
823
824 if( target_thread_ptr == NULL )
825 {
826 return XPTR_NULL;
827 }
828
829 return XPTR( target_cxy , target_thread_ptr );
830}
831
Note: See TracBrowser for help on using the repository browser.