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

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

Fix bugs in exec

File size: 32.4 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 "USR";
57 else if( type == THREAD_RPC ) return "RPC";
58 else if( type == THREAD_DEV ) return "DEV";
59 else if( type == THREAD_IDLE ) return "IDL";
60 else return "undefined";
61}
62
63/////////////////////////////////////////////////////////////////////////////////////
64// This static function allocates physical memory for a thread descriptor.
65// It can be called by the three functions:
66// - thread_user_create()
67// - thread_user_fork()
68// - thread_kernel_create()
69/////////////////////////////////////////////////////////////////////////////////////
70// @ return pointer on thread descriptor if success / return NULL if failure.
71/////////////////////////////////////////////////////////////////////////////////////
72static thread_t * thread_alloc()
73{
74 page_t * page; // pointer on page descriptor containing thread descriptor
75 kmem_req_t req; // kmem request
76
77 // allocates memory for thread descriptor + kernel stack
78 req.type = KMEM_PAGE;
79 req.size = CONFIG_THREAD_DESC_ORDER;
80 req.flags = AF_KERNEL | AF_ZERO;
81 page = kmem_alloc( &req );
82
83 if( page == NULL ) return NULL;
84
85 // return pointer on new thread descriptor
86 xptr_t base_xp = ppm_page2base( XPTR(local_cxy , page ) );
87 return (thread_t *)GET_PTR( base_xp );
88
89} // end thread_alloc()
90
91
92/////////////////////////////////////////////////////////////////////////////////////
93// This static function releases the physical memory for a thread descriptor.
94// It is called by the three functions:
95// - thread_user_create()
96// - thread_user_fork()
97// - thread_kernel_create()
98/////////////////////////////////////////////////////////////////////////////////////
99// @ thread : pointer on thread descriptor.
100/////////////////////////////////////////////////////////////////////////////////////
101static void thread_release( thread_t * thread )
102{
103 kmem_req_t req;
104
105 xptr_t base_xp = ppm_base2page( XPTR(local_cxy , thread ) );
106
107 req.type = KMEM_PAGE;
108 req.ptr = GET_PTR( base_xp );
109 kmem_free( &req );
110}
111
112/////////////////////////////////////////////////////////////////////////////////////
113// This static function initializes a thread descriptor (kernel or user).
114// It can be called by the three functions:
115// - thread_user_create()
116// - thread_user_fork()
117// - thread_kernel_create()
118/////////////////////////////////////////////////////////////////////////////////////
119// @ thread : pointer on thread descriptor
120// @ process : pointer on process descriptor.
121// @ type : thread type.
122// @ func : pointer on thread entry function.
123// @ args : pointer on thread entry function arguments.
124// @ core_lid : target core local index.
125// @ u_stack_base : stack base (user thread only)
126// @ u_stack_size : stack base (user thread only)
127/////////////////////////////////////////////////////////////////////////////////////
128static error_t thread_init( thread_t * thread,
129 process_t * process,
130 thread_type_t type,
131 void * func,
132 void * args,
133 lid_t core_lid,
134 intptr_t u_stack_base,
135 uint32_t u_stack_size )
136{
137 error_t error;
138 trdid_t trdid; // allocated thread identifier
139
140 cluster_t * local_cluster = LOCAL_CLUSTER;
141
142 // register new thread in process descriptor, and get a TRDID
143 spinlock_lock( &process->th_lock );
144 error = process_register_thread( process, thread , &trdid );
145 spinlock_unlock( &process->th_lock );
146
147 if( error )
148 {
149 printk("\n[ERROR] in %s : cannot get TRDID\n", __FUNCTION__ );
150 return EINVAL;
151 }
152
153 // compute thread descriptor size without kernel stack
154 uint32_t desc_size = (intptr_t)(&thread->signature) - (intptr_t)thread + 4;
155
156 // Initialize new thread descriptor
157 thread->trdid = trdid;
158 thread->type = type;
159 thread->quantum = 0; // TODO
160 thread->ticks_nr = 0; // TODO
161 thread->time_last_check = 0;
162 thread->core = &local_cluster->core_tbl[core_lid];
163 thread->process = process;
164
165 thread->local_locks = 0;
166 thread->remote_locks = 0;
167
168#if CONFIG_LOCKS_DEBUG
169 list_root_init( &thread->locks_root );
170 xlist_root_init( XPTR( local_cxy , &thread->xlocks_root ) );
171#endif
172
173 thread->u_stack_base = u_stack_base;
174 thread->u_stack_size = u_stack_size;
175 thread->k_stack_base = (intptr_t)thread + desc_size;
176 thread->k_stack_size = CONFIG_THREAD_DESC_SIZE - desc_size;
177
178 thread->entry_func = func; // thread entry point
179 thread->entry_args = args; // thread function arguments
180 thread->flags = 0; // all flags reset
181 thread->errno = 0; // no error detected
182 thread->fork_user = 0; // no user defined placement for fork
183 thread->fork_cxy = 0; // user defined target cluster for fork
184 thread->blocked = THREAD_BLOCKED_GLOBAL;
185
186 // reset children list
187 xlist_root_init( XPTR( local_cxy , &thread->children_root ) );
188 thread->children_nr = 0;
189
190 // reset sched list and brothers list
191 list_entry_init( &thread->sched_list );
192 xlist_entry_init( XPTR( local_cxy , &thread->brothers_list ) );
193
194 // reset thread info
195 memset( &thread->info , 0 , sizeof(thread_info_t) );
196
197 // initializes join_lock
198 remote_spinlock_init( XPTR( local_cxy , &thread->join_lock ) );
199
200 // initialise signature
201 thread->signature = THREAD_SIGNATURE;
202
203 // FIXME call hal_thread_init() function to initialise the save_sr field
204 thread->save_sr = 0xFF13;
205
206 // update local DQDT
207 dqdt_local_update_threads( 1 );
208
209 // register new thread in core scheduler
210 sched_register_thread( thread->core , thread );
211
212 return 0;
213
214} // end thread_init()
215
216/////////////////////////////////////////////////////////
217error_t thread_user_create( pid_t pid,
218 void * start_func,
219 void * start_arg,
220 pthread_attr_t * attr,
221 thread_t ** new_thread )
222{
223 error_t error;
224 thread_t * thread; // pointer on created thread descriptor
225 process_t * process; // pointer to local process descriptor
226 lid_t core_lid; // selected core local index
227 vseg_t * vseg; // stack vseg
228
229 assert( (attr != NULL) , __FUNCTION__, "pthread attributes must be defined" );
230
231 // get process descriptor local copy
232 process = process_get_local_copy( pid );
233
234 if( process == NULL )
235 {
236 printk("\n[ERROR] in %s : cannot get process descriptor %x\n",
237 __FUNCTION__ , pid );
238 return ENOMEM;
239 }
240
241 // select a target core in local cluster
242 if( attr->attributes & PT_ATTR_CORE_DEFINED )
243 {
244 core_lid = attr->lid;
245 if( core_lid >= LOCAL_CLUSTER->cores_nr )
246 {
247 printk("\n[ERROR] in %s : illegal core index attribute = %d\n",
248 __FUNCTION__ , core_lid );
249 return EINVAL;
250 }
251 }
252 else
253 {
254 core_lid = cluster_select_local_core();
255 }
256
257 // allocate a stack from local VMM
258 vseg = vmm_create_vseg( process,
259 VSEG_TYPE_STACK,
260 0, // size unused
261 0, // length unused
262 0, // file_offset unused
263 0, // file_size unused
264 XPTR_NULL, // mapper_xp unused
265 local_cxy );
266
267 if( vseg == NULL )
268 {
269 printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
270 return ENOMEM;
271 }
272
273 // allocate memory for thread descriptor
274 thread = thread_alloc();
275
276 if( thread == NULL )
277 {
278 printk("\n[ERROR] in %s : cannot create new thread\n", __FUNCTION__ );
279 vmm_remove_vseg( vseg );
280 return ENOMEM;
281 }
282
283 // initialize thread descriptor
284 error = thread_init( thread,
285 process,
286 THREAD_USER,
287 start_func,
288 start_arg,
289 core_lid,
290 vseg->min,
291 vseg->max - vseg->min );
292
293 if( error )
294 {
295 printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ );
296 vmm_remove_vseg( vseg );
297 thread_release( thread );
298 return EINVAL;
299 }
300
301 // set DETACHED flag if required
302 if( attr->attributes & PT_ATTR_DETACH )
303 {
304 thread->flags |= THREAD_FLAG_DETACHED;
305 }
306
307 // allocate & initialize CPU context
308 if( hal_cpu_context_create( thread ) )
309 {
310 printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ );
311 vmm_remove_vseg( vseg );
312 thread_release( thread );
313 return ENOMEM;
314 }
315
316 // allocate FPU context
317 if( hal_fpu_context_alloc( thread ) )
318 {
319 printk("\n[ERROR] in %s : cannot create FPU context\n", __FUNCTION__ );
320 vmm_remove_vseg( vseg );
321 thread_release( thread );
322 return ENOMEM;
323 }
324
325 // update DQDT for new thread
326 dqdt_local_update_threads( 1 );
327
328thread_dmsg("\n[DBG] %s : core[%x,%d] exit / trdid = %x / process %x / core = %d\n",
329__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid,
330thread->trdid , process->pid , core_lid );
331
332 *new_thread = thread;
333 return 0;
334
335} // end thread_user_create()
336
337///////////////////////////////////////////////////////
338error_t thread_user_fork( xptr_t parent_thread_xp,
339 process_t * child_process,
340 thread_t ** child_thread )
341{
342 error_t error;
343 thread_t * child_ptr; // local pointer on local child thread
344 lid_t core_lid; // selected core local index
345
346 thread_t * parent_ptr; // local pointer on remote parent thread
347 cxy_t parent_cxy; // parent thread cluster
348 process_t * parent_process; // local pointer on parent process
349 xptr_t parent_gpt_xp; // extended pointer on parent thread GPT
350
351 void * func; // parent thread entry_func
352 void * args; // parent thread entry_args
353 intptr_t base; // parent thread u_stack_base
354 uint32_t size; // parent thread u_stack_size
355 uint32_t flags; // parent_thread flags
356 vpn_t vpn_base; // parent thread stack vpn_base
357 vpn_t vpn_size; // parent thread stack vpn_size
358 reg_t * uzone; // parent thread pointer on uzone
359
360 vseg_t * vseg; // child thread STACK vseg
361
362thread_dmsg("\n[DBG] %s : core[%x,%d] enters at cycle %d\n",
363__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , hal_get_cycles() );
364
365 // select a target core in local cluster
366 core_lid = cluster_select_local_core();
367
368 // get cluster and local pointer on parent thread descriptor
369 parent_cxy = GET_CXY( parent_thread_xp );
370 parent_ptr = (thread_t *)GET_PTR( parent_thread_xp );
371
372 // get relevant fields from parent thread
373 func = (void *) hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->entry_func ) );
374 args = (void *) hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->entry_args ) );
375 base = (intptr_t)hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->u_stack_base ) );
376 size = (uint32_t)hal_remote_lw ( XPTR( parent_cxy , &parent_ptr->u_stack_size ) );
377 flags = hal_remote_lw ( XPTR( parent_cxy , &parent_ptr->flags ) );
378 uzone = (reg_t *) hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->uzone ) );
379
380 vpn_base = base >> CONFIG_PPM_PAGE_SHIFT;
381 vpn_size = size >> CONFIG_PPM_PAGE_SHIFT;
382
383 // get pointer on parent process in parent thread cluster
384 parent_process = (process_t *)hal_remote_lpt( XPTR( parent_cxy,
385 &parent_ptr->process ) );
386
387 // get extended pointer on parent GPT in parent thread cluster
388 parent_gpt_xp = XPTR( parent_cxy , &parent_process->vmm.gpt );
389
390 // allocate memory for child thread descriptor
391 child_ptr = thread_alloc();
392 if( child_ptr == NULL )
393 {
394 printk("\n[ERROR] in %s : cannot allocate new thread\n", __FUNCTION__ );
395 return -1;
396 }
397
398 // initialize thread descriptor
399 error = thread_init( child_ptr,
400 child_process,
401 THREAD_USER,
402 func,
403 args,
404 core_lid,
405 base,
406 size );
407 if( error )
408 {
409 printk("\n[ERROR] in %s : cannot initialize child thread\n", __FUNCTION__ );
410 thread_release( child_ptr );
411 return EINVAL;
412 }
413
414 // return child pointer
415 *child_thread = child_ptr;
416
417 // set detached flag if required
418 if( flags & THREAD_FLAG_DETACHED ) child_ptr->flags = THREAD_FLAG_DETACHED;
419
420 // update uzone pointer in child thread descriptor
421 child_ptr->uzone = (char *)((intptr_t)uzone +
422 (intptr_t)child_ptr -
423 (intptr_t)parent_ptr );
424
425
426 // allocate CPU context for child thread
427 if( hal_cpu_context_alloc( child_ptr ) )
428 {
429 printk("\n[ERROR] in %s : cannot allocate CPU context\n", __FUNCTION__ );
430 thread_release( child_ptr );
431 return -1;
432 }
433
434 // allocate FPU context for child thread
435 if( hal_fpu_context_alloc( child_ptr ) )
436 {
437 printk("\n[ERROR] in %s : cannot allocate FPU context\n", __FUNCTION__ );
438 thread_release( child_ptr );
439 return -1;
440 }
441
442 // create and initialize STACK vseg
443 vseg = vseg_alloc();
444 vseg_init( vseg,
445 VSEG_TYPE_STACK,
446 base,
447 size,
448 vpn_base,
449 vpn_size,
450 0, 0, XPTR_NULL, // not a file vseg
451 local_cxy );
452
453 // register STACK vseg in local child VSL
454 vseg_attach( &child_process->vmm , vseg );
455
456 // copy all valid STACK GPT entries
457 vpn_t vpn;
458 bool_t mapped;
459 ppn_t ppn;
460 for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
461 {
462 error = hal_gpt_pte_copy( &child_process->vmm.gpt,
463 parent_gpt_xp,
464 vpn,
465 true, // set cow
466 &ppn,
467 &mapped );
468 if( error )
469 {
470 vseg_detach( &child_process->vmm , vseg );
471 vseg_free( vseg );
472 thread_release( child_ptr );
473 printk("\n[ERROR] in %s : cannot update child GPT\n", __FUNCTION__ );
474 return -1;
475 }
476
477 // increment page descriptor fork_nr for the referenced page if mapped
478 if( mapped )
479 {
480 xptr_t page_xp = ppm_ppn2page( ppn );
481 cxy_t page_cxy = GET_CXY( page_xp );
482 page_t * page_ptr = (page_t *)GET_PTR( page_xp );
483 hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->fork_nr ) , 1 );
484
485thread_dmsg("\n[DBG] %s : core[%x,%d] copied PTE to child GPT : vpn %x\n",
486__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
487
488 }
489 }
490
491 // set COW flag for STAK vseg in parent thread GPT
492 hal_gpt_flip_cow( true, // set cow
493 parent_gpt_xp,
494 vpn_base,
495 vpn_size );
496
497 // update DQDT for child thread
498 dqdt_local_update_threads( 1 );
499
500thread_dmsg("\n[DBG] %s : core[%x,%d] exit / created main thread %x for process %x\n",
501__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, child_ptr->trdid, child_process->pid );
502
503 return 0;
504
505} // end thread_user_fork()
506
507/////////////////////////////////////////////////////////
508error_t thread_kernel_create( thread_t ** new_thread,
509 thread_type_t type,
510 void * func,
511 void * args,
512 lid_t core_lid )
513{
514 error_t error;
515 thread_t * thread; // pointer on new thread descriptor
516
517thread_dmsg("\n[DBG] %s : core[%x,%d] enters / type % / cycle %d\n",
518__FUNCTION__ , local_cxy , core_lid , thread_type_str( type ) , hal_time_stamp() );
519
520 assert( ( (type == THREAD_IDLE) || (type == THREAD_RPC) || (type == THREAD_DEV) ) ,
521 __FUNCTION__ , "illegal thread type" );
522
523 assert( (core_lid < LOCAL_CLUSTER->cores_nr) ,
524 __FUNCTION__ , "illegal core_lid" );
525
526 // allocate memory for new thread descriptor
527 thread = thread_alloc();
528
529 if( thread == NULL ) return ENOMEM;
530
531 // initialize thread descriptor
532 error = thread_init( thread,
533 &process_zero,
534 type,
535 func,
536 args,
537 core_lid,
538 0 , 0 ); // no user stack for a kernel thread
539
540 if( error ) // release allocated memory for thread descriptor
541 {
542 thread_release( thread );
543 return EINVAL;
544 }
545
546 // allocate & initialize CPU context
547 hal_cpu_context_create( thread );
548
549 // update DQDT for kernel thread
550 dqdt_local_update_threads( 1 );
551
552thread_dmsg("\n[DBG] %s : core = [%x,%d] exit / trdid = %x / type %s / cycle %d\n",
553__FUNCTION__, local_cxy, core_lid, thread->trdid, thread_type_str(type), hal_time_stamp() );
554
555 *new_thread = thread;
556 return 0;
557
558} // end thread_kernel_create()
559
560///////////////////////////////////////////////////
561error_t thread_kernel_init( thread_t * thread,
562 thread_type_t type,
563 void * func,
564 void * args,
565 lid_t core_lid )
566{
567 assert( (type == THREAD_IDLE) , __FUNCTION__ , "illegal thread type" );
568
569 assert( (core_lid < LOCAL_CLUSTER->cores_nr) , __FUNCTION__ , "illegal core index" );
570
571 error_t error = thread_init( thread,
572 &process_zero,
573 type,
574 func,
575 args,
576 core_lid,
577 0 , 0 ); // no user stack for a kernel thread
578
579 // allocate & initialize CPU context if success
580 if( error == 0 ) hal_cpu_context_create( thread );
581
582 return error;
583
584} // end thread_kernel_init()
585
586///////////////////////////////////////////////////////////////////////////////////////
587// TODO: check that all memory dynamically allocated during thread execution
588// has been released, using a cache of mmap and malloc requests. [AG]
589///////////////////////////////////////////////////////////////////////////////////////
590void thread_destroy( thread_t * thread )
591{
592 uint32_t tm_start;
593 uint32_t tm_end;
594 reg_t save_sr;
595
596 process_t * process = thread->process;
597 core_t * core = thread->core;
598
599 thread_dmsg("\n[DBG] %s : enters for thread %x in process %x / type = %s\n",
600 __FUNCTION__ , thread->trdid , process->pid , thread_type_str( thread->type ) );
601
602 assert( (thread->children_nr == 0) , __FUNCTION__ , "still attached children" );
603
604 assert( (thread->local_locks == 0) , __FUNCTION__ , "all local locks not released" );
605
606 assert( (thread->remote_locks == 0) , __FUNCTION__ , "all remote locks not released" );
607
608 tm_start = hal_get_cycles();
609
610 // update intrumentation values
611 process->vmm.pgfault_nr += thread->info.pgfault_nr;
612
613 // release memory allocated for CPU context and FPU context
614 hal_cpu_context_destroy( thread );
615 if ( thread->type == THREAD_USER ) hal_fpu_context_destroy( thread );
616
617 // release FPU if required
618 // TODO This should be done before calling thread_destroy()
619 hal_disable_irq( &save_sr );
620 if( core->fpu_owner == thread )
621 {
622 core->fpu_owner = NULL;
623 hal_fpu_disable();
624 }
625 hal_restore_irq( save_sr );
626
627 // remove thread from process th_tbl[]
628 // TODO This should be done before calling thread_destroy()
629 ltid_t ltid = LTID_FROM_TRDID( thread->trdid );
630
631 spinlock_lock( &process->th_lock );
632 process->th_tbl[ltid] = XPTR_NULL;
633 process->th_nr--;
634 spinlock_unlock( &process->th_lock );
635
636 // update local DQDT
637 dqdt_local_update_threads( -1 );
638
639 // invalidate thread descriptor
640 thread->signature = 0;
641
642 // release memory for thread descriptor
643 thread_release( thread );
644
645 tm_end = hal_get_cycles();
646
647 thread_dmsg("\n[DBG] %s : exit for thread %x in process %x / duration = %d\n",
648 __FUNCTION__, thread->trdid , process->pid , tm_end - tm_start );
649
650} // end thread_destroy()
651
652/////////////////////////////////////////////////
653void thread_child_parent_link( xptr_t xp_parent,
654 xptr_t xp_child )
655{
656 // get extended pointers on children list root
657 cxy_t parent_cxy = GET_CXY( xp_parent );
658 thread_t * parent_ptr = (thread_t *)GET_PTR( xp_parent );
659 xptr_t root = XPTR( parent_cxy , &parent_ptr->children_root );
660
661 // get extended pointer on children list entry
662 cxy_t child_cxy = GET_CXY( xp_child );
663 thread_t * child_ptr = (thread_t *)GET_PTR( xp_child );
664 xptr_t entry = XPTR( child_cxy , &child_ptr->brothers_list );
665
666 // set the link
667 xlist_add_first( root , entry );
668 hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr ) , 1 );
669
670} // end thread_child_parent_link()
671
672///////////////////////////////////////////////////
673void thread_child_parent_unlink( xptr_t xp_parent,
674 xptr_t xp_child )
675{
676 // get extended pointer on children list lock
677 cxy_t parent_cxy = GET_CXY( xp_parent );
678 thread_t * parent_ptr = (thread_t *)GET_PTR( xp_parent );
679 xptr_t lock = XPTR( parent_cxy , &parent_ptr->children_lock );
680
681 // get extended pointer on children list entry
682 cxy_t child_cxy = GET_CXY( xp_child );
683 thread_t * child_ptr = (thread_t *)GET_PTR( xp_child );
684 xptr_t entry = XPTR( child_cxy , &child_ptr->brothers_list );
685
686 // get the lock
687 remote_spinlock_lock( lock );
688
689 // remove the link
690 xlist_unlink( entry );
691 hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr ) , -1 );
692
693 // release the lock
694 remote_spinlock_unlock( lock );
695
696} // thread_child_parent_unlink()
697
698/////////////////////////////////////////////////
699inline void thread_set_signal( thread_t * thread,
700 uint32_t * sig_rsp_count )
701{
702 reg_t save_sr; // for critical section
703
704 // get pointer on thread thread scheduler
705 scheduler_t * thread_sched = &thread->core->scheduler;
706
707 // wait scheduler ready to handle a new signal
708 while( thread_sched->sig_pending ) asm volatile( "nop" );
709
710 // enter critical section
711 hal_disable_irq( &save_sr );
712
713 // set signal in thread scheduler
714 thread_sched->sig_pending = true;
715
716 // set signal in thread thread "flags"
717 hal_atomic_or( &thread->flags , THREAD_FLAG_SIGNAL );
718
719 // set pointer on responses counter in thread thread
720 thread->sig_rsp_count = sig_rsp_count;
721
722 // exit critical section
723 hal_restore_irq( save_sr );
724
725 hal_fence();
726
727} // thread_set_signal()
728
729////////////////////////////////////////////////////
730inline void thread_reset_signal( thread_t * thread )
731{
732 reg_t save_sr; // for critical section
733
734 // get pointer on target thread scheduler
735 scheduler_t * sched = &thread->core->scheduler;
736
737 // check signal pending in scheduler
738 assert( sched->sig_pending , __FUNCTION__ , "no pending signal" );
739
740 // enter critical section
741 hal_disable_irq( &save_sr );
742
743 // reset signal in scheduler
744 sched->sig_pending = false;
745
746 // reset signal in thread "flags"
747 hal_atomic_and( &thread->flags , ~THREAD_FLAG_SIGNAL );
748
749 // reset pointer on responses counter
750 thread->sig_rsp_count = NULL;
751
752 // exit critical section
753 hal_restore_irq( save_sr );
754
755 hal_fence();
756
757} // thread_reset_signal()
758
759////////////////////////////////
760inline bool_t thread_can_yield()
761{
762 thread_t * this = CURRENT_THREAD;
763 return (this->local_locks == 0) && (this->remote_locks == 0);
764}
765
766/////////////////////////
767void thread_check_sched()
768{
769 thread_t * this = CURRENT_THREAD;
770
771 if( (this->local_locks == 0) &&
772 (this->remote_locks == 0) &&
773 (this->flags & THREAD_FLAG_SCHED) )
774 {
775 this->flags &= ~THREAD_FLAG_SCHED;
776 sched_yield( "delayed scheduling" );
777 }
778
779} // end thread_check_sched()
780
781/////////////////////////////////////
782void thread_block( thread_t * thread,
783 uint32_t cause )
784{
785 // set blocking cause
786 hal_atomic_or( &thread->blocked , cause );
787 hal_fence();
788
789} // end thread_block()
790
791/////////////////////////////////////////
792uint32_t thread_unblock( xptr_t thread,
793 uint32_t cause )
794{
795 // get thread cluster and local pointer
796 cxy_t cxy = GET_CXY( thread );
797 thread_t * ptr = (thread_t *)GET_PTR( thread );
798
799 // reset blocking cause
800 uint32_t previous = hal_remote_atomic_and( XPTR( cxy , &ptr->blocked ) , ~cause );
801 hal_fence();
802
803 // return a non zero value if the cause bit is modified
804 return( previous & cause );
805
806} // end thread_unblock()
807
808/////////////////////////////////////
809void thread_kill( thread_t * target )
810{
811 volatile uint32_t sig_rsp_count = 1; // responses counter
812
813 thread_t * killer = CURRENT_THREAD;
814
815kill_dmsg("\n[DBG] %s : killer thread %x enter for target thread %x\n",
816__FUNCTION__, local_cxy, killer->trdid , target trdid );
817
818 // set the global blocked bit in target thread descriptor.
819 thread_block( target , THREAD_BLOCKED_GLOBAL );
820
821 // request target scheduler to deschedule the target thread
822 // when killer thread is not running on same core as target thread
823 if( killer->core->lid != target->core->lid )
824 {
825 // set signal in target thread descriptor and in target scheduler
826 thread_set_signal( target , (uint32_t *)(&sig_rsp_count) );
827
828 // send an IPI to the target thread core.
829 dev_pic_send_ipi( local_cxy , target->core->lid );
830
831 // poll the response
832 while( 1 )
833 {
834 // exit when response received from scheduler
835 if( sig_rsp_count == 0 ) break;
836
837 // deschedule without blocking
838 hal_fixed_delay( 1000 );
839 }
840 }
841
842 // release FPU if required
843 if( target->core->fpu_owner == target ) target->core->fpu_owner = NULL;
844
845 // detach thread from parent if attached
846 if( (target->flags & THREAD_FLAG_DETACHED) == 0 )
847 thread_child_parent_unlink( target->parent , XPTR( local_cxy , target ) );
848
849 // detach thread from process
850 process_remove_thread( target );
851
852 // remove thread from scheduler
853 sched_remove_thread( target );
854
855 // release memory allocated to target thread
856 thread_destroy( target );
857
858kill_dmsg("\n[DBG] %s : killer thread %x enter for target thread %x\n",
859__FUNCTION__, local_cxy, killer->trdid , target trdid );
860
861} // end thread_kill()
862
863///////////////////////
864void thread_idle_func()
865{
866 while( 1 )
867 {
868 // unmask IRQs
869 hal_enable_irq( NULL );
870
871 if( CONFIG_THREAD_IDLE_MODE_SLEEP ) // force core to low-power mode
872 {
873
874idle_dmsg("\n[DBG] %s : core[%x][%d] goes to sleep at cycle %d\n",
875__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , hal_get_cycles() );
876
877 hal_core_sleep();
878
879idle_dmsg("\n[DBG] %s : core[%x][%d] wake up at cycle %d\n",
880__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , hal_get_cycles() );
881
882 }
883 else // yield each ~ 100000 cycles
884
885 {
886 hal_fixed_delay( 500000 );
887 }
888
889 // force scheduling at each iteration
890 sched_yield( "idle" );
891 }
892} // end thread_idle()
893
894
895/////////////////////////////////////////////////
896void thread_user_time_update( thread_t * thread )
897{
898 // TODO
899 // printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ );
900}
901
902///////////////////////////////////////////////////
903void thread_kernel_time_update( thread_t * thread )
904{
905 // TODO
906 // printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ );
907}
908
909/////////////////////////////////////
910xptr_t thread_get_xptr( pid_t pid,
911 trdid_t trdid )
912{
913 cxy_t target_cxy; // target thread cluster identifier
914 ltid_t target_thread_ltid; // target thread local index
915 thread_t * target_thread_ptr; // target thread local pointer
916 xptr_t target_process_xp; // extended pointer on target process descriptor
917 process_t * target_process_ptr; // local pointer on target process descriptor
918 pid_t target_process_pid; // target process identifier
919 xlist_entry_t root; // root of list of process in target cluster
920 xptr_t lock_xp; // extended pointer on lock protecting this list
921
922 // get target cluster identifier and local thread identifier
923 target_cxy = CXY_FROM_TRDID( trdid );
924 target_thread_ltid = LTID_FROM_TRDID( trdid );
925
926 // get root of list of process descriptors in target cluster
927 hal_remote_memcpy( XPTR( local_cxy , &root ),
928 XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ),
929 sizeof(xlist_entry_t) );
930
931 // get extended pointer on lock protecting the list of processes
932 lock_xp = XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_lock );
933
934 // take the lock protecting the list of processes in target cluster
935 remote_spinlock_lock( lock_xp );
936
937 // loop on list of process in target cluster to find the PID process
938 xptr_t iter;
939 bool_t found = false;
940 XLIST_FOREACH( XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ) , iter )
941 {
942 target_process_xp = XLIST_ELEMENT( iter , process_t , local_list );
943 target_process_ptr = (process_t *)GET_PTR( target_process_xp );
944 target_process_pid = hal_remote_lw( XPTR( target_cxy , &target_process_ptr->pid ) );
945 if( target_process_pid == pid )
946 {
947 found = true;
948 break;
949 }
950 }
951
952 // release the lock protecting the list of processes in target cluster
953 remote_spinlock_unlock( lock_xp );
954
955 // check target thread found
956 if( found == false )
957 {
958 return XPTR_NULL;
959 }
960
961 // get target thread local pointer
962 xptr_t xp = XPTR( target_cxy , &target_process_ptr->th_tbl[target_thread_ltid] );
963 target_thread_ptr = (thread_t *)hal_remote_lpt( xp );
964
965 if( target_thread_ptr == NULL )
966 {
967 return XPTR_NULL;
968 }
969
970 return XPTR( target_cxy , target_thread_ptr );
971}
972
Note: See TracBrowser for help on using the repository browser.