Index: trunk/kernel/kern/scheduler.c
===================================================================
--- trunk/kernel/kern/scheduler.c	(revision 406)
+++ trunk/kernel/kern/scheduler.c	(revision 407)
@@ -24,4 +24,5 @@
 #include <kernel_config.h>
 #include <hal_types.h>
+#include <hal_switch.h>
 #include <hal_irqmask.h>
 #include <hal_context.h>
@@ -38,5 +39,5 @@
 
 extern chdev_directory_t    chdev_dir;            // allocated in kernel_init.c file
-
+extern uint32_t             switch_save_sr[];     // allocated in kernel_init.c file
 
 ////////////////////////////////
@@ -127,24 +128,4 @@
 }  // end sched_remove()
 
-///////////////////////////////////////////
-void sched_kill_thread( thread_t * thread )
-{
-    // check thread locks
-    if( thread_can_yield() == false )
-    {
-        panic("thread %x in process %x on core[%x][%d]"
-              " did not released all locks",
-              thread->trdid , thread->process->pid, 
-              local_cxy , thread->core->lid ); 
-    }
-
-    // remove thread from scheduler
-    sched_remove_thread( thread );
-
-    // reset the THREAD_SIG_KILL signal
-    thread_reset_signal( thread , THREAD_SIG_KILL );
-
-}  // end sched_kill_thread()
-
 ////////////////////////////////////////
 thread_t * sched_select( core_t * core )
@@ -154,7 +135,4 @@
     scheduler_t * sched = &core->scheduler;
 
-    sched_dmsg("\n[DMSG] %s : enter core[%x,%d] / cycle %d\n",
-    __FUNCTION__ , local_cxy , core->lid , hal_time_stamp() );
-
     // take lock protecting sheduler lists
     spinlock_lock( &sched->lock );
@@ -163,5 +141,5 @@
     list_entry_t * last;
 
-    // first : scan the kernel threads list if not empty 
+    // first loop : scan the kernel threads list if not empty 
     if( list_is_empty( &sched->k_root ) == false )
     {
@@ -179,20 +157,32 @@
             thread = LIST_ELEMENT( current , thread_t , sched_list );
 
-            // return thread if not idle_thread and runnable 
-            if( (thread->type != THREAD_IDLE) && (thread->blocked == 0) ) 
+            // analyse kernel thread type
+            switch( thread->type )
             {
-                // release lock 
-                spinlock_unlock( &sched->lock );
-
-                sched_dmsg("\n[DMSG] %s : exit core[%x,%d] / k_thread = %x / cycle %d\n",
-                __FUNCTION__ , local_cxy , core->lid , thread->trdid , hal_time_stamp() );
-
-                return thread;
-            }
+                case THREAD_IDLE: // skip IDLE thread
+                break;
+
+                case THREAD_RPC:  // RPC thread if non blocked and FIFO non-empty
+                if( (thread->blocked == 0) && 
+                    (local_fifo_is_empty( &LOCAL_CLUSTER->rpc_fifo ) == 0) )
+                {
+                    spinlock_unlock( &sched->lock );
+                    return thread;
+                }
+                break;
+
+                default:          // DEV thread if non blocked
+                if( thread->blocked == 0 )
+                {
+                    spinlock_unlock( &sched->lock );
+                    return thread;
+                }
+                break;
+            }  // end switch type
         }
         while( current != last );
     }
 
-    // second : scan the user threads list if not empty 
+    // second loop : scan the user threads list if not empty 
     if( list_is_empty( &sched->u_root ) == false )
     {
@@ -213,9 +203,5 @@
             if( thread->blocked == 0 )
             {
-                // release lock 
                 spinlock_unlock( &sched->lock );
-
-                sched_dmsg("\n[DMSG] %s : exit core[%x,%d] / u_thread = %x / cycle %d\n",
-                __FUNCTION__ , local_cxy , core->lid , thread->trdid , hal_time_stamp() );
                 return thread;
             }
@@ -224,14 +210,39 @@
     }
 
-    // release lock 
+    // third : return idle thread if no runnable thread
     spinlock_unlock( &sched->lock );
-
-    sched_dmsg("\n[DMSG] %s : exit core[%x,%d] / idle = %x / cycle %d\n",
-    __FUNCTION__ , local_cxy , core->lid , sched->idle->trdid , hal_time_stamp() );
-
-    // third : return idle thread if no runnable thread
     return sched->idle;
 
 }  // end sched_select()
+
+///////////////////////////////////////////
+void sched_kill_thread( thread_t * thread )
+{
+    // check locks
+    if( thread_can_yield() == false )
+    {
+        panic("locks not released for thread %x in process %x on core[%x][%d]",
+        thread->trdid , thread->process->pid, local_cxy , thread->core->lid ); 
+    }
+
+    // remove thread from scheduler
+    sched_remove_thread( thread );
+
+    // reset the THREAD_SIG_KILL signal
+    thread_reset_signal( thread , THREAD_SIG_KILL );
+
+    // detached thread can suicide
+    if( thread->signals & THREAD_SIG_SUICIDE ) 
+    {
+        assert( (thread->flags & THREAD_FLAG_DETACHED), __FUNCTION__,
+        "thread must be detached in case of suicide\n" );
+
+        // remove thread from process
+        process_remove_thread( thread );
+
+        // release memory for thread descriptor 
+        thread_destroy( thread );
+    }
+}  // end sched_kill_thread()
 
 //////////////////////////////////////////
@@ -242,7 +253,4 @@
     scheduler_t  * sched = &core->scheduler;
 
-    sched_dmsg("\n[DMSG] %s : enter / thread %x on core[%x,%d]\n",
-    __FUNCTION__, CURRENT_THREAD->trdid , local_cxy , core->lid );
-
     // take lock protecting threads lists
     spinlock_lock( &sched->lock );
@@ -252,5 +260,5 @@
     {
         thread = LIST_ELEMENT( iter , thread_t , sched_list );
-        if( thread->signals & THREAD_SIG_KILL )  sched_kill_thread( thread );
+        if( thread->signals ) sched_kill_thread( thread );
     }
 
@@ -259,5 +267,5 @@
     {
         thread = LIST_ELEMENT( iter , thread_t , sched_list );
-        if( thread->signals & THREAD_SIG_KILL )  sched_kill_thread( thread );
+        if( thread->signals ) sched_kill_thread( thread );
     }
 
@@ -265,23 +273,30 @@
     spinlock_unlock( &sched->lock );
 
-    sched_dmsg("\n[DMSG] %s : exit / thread %x on core[%x,%d]\n",
-    __FUNCTION__, CURRENT_THREAD->trdid , local_cxy , core->lid );
-
 } // end sched_handle_signals()
 
-///////////////////////////////////
-void sched_yield( thread_t * next )
-{
-    reg_t         sr_save;
-
+//////////////////////////////////////
+void sched_update( thread_t * current,
+                   thread_t * next )
+{
+    scheduler_t * sched = &current->core->scheduler;
+
+    if( current->type == THREAD_USER ) sched->u_last = &current->sched_list;
+    else                               sched->k_last = &current->sched_list;
+
+    sched->current = next;
+}
+
+//////////////////
+void sched_yield()
+{
+    thread_t    * next;
     thread_t    * current = CURRENT_THREAD;
-    core_t      * core    = current->core;
-    scheduler_t * sched   = &core->scheduler;
-
-    sched_dmsg("\n[DMSG] %s : thread %x on core[%x,%d] enter / cycle %d\n",
-    __FUNCTION__, current->trdid, local_cxy, core->lid, hal_time_stamp() );
+ 
+#if( CONFIG_SCHED_DEBUG & 0x1 )
+if( hal_time_stamp() > CONFIG_SCHED_DEBUG ) sched_display( current->core->lid );
+#endif
 
     // delay the yield if current thread has locks
-    if( thread_can_yield() == false )
+    if( (current->local_locks != 0) || (current->remote_locks != 0) )
     {
         current->flags |= THREAD_FLAG_SCHED;
@@ -289,53 +304,57 @@
     }
 
-    // first loop on all threads to handle pending signals
-    sched_handle_signals( core );
-
-    // second loop on threads to select next thread if required
-    if( next == NULL ) next = sched_select( core );
+    // loop on threads to select next thread 
+    next = sched_select( current->core );
 
     // check next thread attached to same core as the calling thread
-    assert( (next->core == current->core), __FUNCTION__ , "next core != current core\n");
-
-    // check next thread not blocked
-    assert( (next->blocked == 0), __FUNCTION__ , "next thread is blocked\n");
+    assert( (next->core == current->core), __FUNCTION__ , 
+    "next core != current core\n");
+
+    // check next thread not blocked when type != IDLE
+    assert( (next->blocked == 0) || (next->type = THREAD_IDLE) , __FUNCTION__ ,
+    "next thread %x (%s) is blocked on core[%x,%d]\n", 
+    next->trdid , thread_type_str(next->type) , local_cxy , current->core->lid );
 
     // switch contexts and update scheduler state if next != current
 	if( next != current )
     {
-        sched_dmsg("\n[DMSG] %s : trd %x (%s) on core[%x,%d] => trd %x (%s) / cycle %d\n",
-        __FUNCTION__, current->trdid, thread_type_str(current->type), local_cxy, core->lid, 
-        next->trdid, thread_type_str(next->type), hal_time_stamp() );
-
-        // calling thread desactivate IRQs
-        hal_disable_irq( &sr_save );
+        // current thread desactivate IRQs
+        hal_disable_irq( &switch_save_sr[CURRENT_THREAD->core->lid] );
+
+sched_dmsg("\n[DBG] %s : core[%x,%d] / trd %x (%s) (%x,%x) => trd %x (%s) (%x,%x) / cycle %d\n",
+__FUNCTION__, local_cxy, current->core->lid, 
+current, thread_type_str(current->type), current->process->pid, current->trdid,
+next   , thread_type_str(next->type)   , next->process->pid   , next->trdid,
+hal_time_stamp() );
 
         // update scheduler 
-        if( current->type == THREAD_USER ) sched->u_last = &current->sched_list;
-        else                               sched->k_last = &current->sched_list;
-        sched->current = next;
-
-        // handle FPU
+        sched_update( current , next );
+
+        // handle FPU ownership
 	    if( next->type == THREAD_USER )
         {
-	        if( next == core->fpu_owner )  hal_fpu_enable();
-	        else                           hal_fpu_disable();
+	        if( next == current->core->fpu_owner )  hal_fpu_enable();
+	        else                                    hal_fpu_disable();
         }
 
-        // switch contexts 
-        hal_cpu_context_switch( current , next );
-
-        // restore IRQs when calling thread resume
-        hal_restore_irq( sr_save );
+        // switch CPU from calling thread context to new thread context
+        hal_do_cpu_switch( current->cpu_context, next->cpu_context );
+
+        // restore IRQs when next thread resume
+        hal_restore_irq( switch_save_sr[CURRENT_THREAD->core->lid] );
     }
     else
     {
-        sched_dmsg("\n[DMSG] %s : thread %x on core[%x,%d] continue / cycle %d\n",
-        __FUNCTION__, current->trdid, local_cxy, core->lid, hal_time_stamp() );
+
+sched_dmsg("\n[DBG] %s : core[%x,%d] / thread %x (%s) continue / cycle %d\n",
+__FUNCTION__, local_cxy, current->core->lid, current->trdid, 
+thread_type_str(current->type) ,hal_time_stamp() );
+
     }
 }  // end sched_yield()
 
-////////////////////
-void sched_display()
+
+///////////////////////////////
+void sched_display( lid_t lid )
 {
     list_entry_t * iter;
@@ -343,10 +362,16 @@
     uint32_t       save_sr;
 
-    thread_t     * current = CURRENT_THREAD;
-    core_t       * core    = current->core;
+    if( lid >= LOCAL_CLUSTER->cores_nr )
+    {
+        printk("\n[ERROR] in %s : illegal local index %d in cluster %x\n",
+        __FUNCTION__ , lid , local_cxy );
+        return;
+    }
+
+    core_t       * core    = &LOCAL_CLUSTER->core_tbl[lid];
     scheduler_t  * sched   = &core->scheduler;
     
     // get pointers on TXT0 chdev
-    xptr_t    txt0_xp  = chdev_dir.txt[0];
+    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
     cxy_t     txt0_cxy = GET_CXY( txt0_xp );
     chdev_t * txt0_ptr = GET_PTR( txt0_xp );
@@ -358,8 +383,9 @@
     remote_spinlock_lock_busy( lock_xp , &save_sr );
 
-    nolock_printk("\n***** scheduler state for core[%x,%d]\n"
-           "kernel_threads = %d / user_threads = %d / current = %x\n",
-            local_cxy , core->lid, 
-            sched->k_threads_nr, sched->u_threads_nr, sched->current->trdid );
+    nolock_printk("\n***** scheduler state for core[%x,%d] at cycle %d\n"
+           "kernel_threads = %d / user_threads = %d / current = %x / idle = %x\n",
+            local_cxy , core->lid, hal_time_stamp(),
+            sched->k_threads_nr, sched->u_threads_nr,
+            sched->current->trdid , sched->idle->trdid );
 
     // display kernel threads
@@ -367,5 +393,5 @@
     {
         thread = LIST_ELEMENT( iter , thread_t , sched_list );
-        nolock_printk(" - type = %s / trdid = %x / pid = %x / func = %x / blocked_vect = %x\n",
+        nolock_printk(" - type = %s / trdid = %X / pid = %X / func = %X / blocked = %X\n",
         thread_type_str( thread->type ), thread->trdid, thread->process->pid,
         thread->entry_func, thread->blocked );
@@ -376,5 +402,5 @@
     {
         thread = LIST_ELEMENT( iter , thread_t , sched_list );
-        nolock_printk(" - type = %s / trdid = %x / pid = %x / func = %x / blocked_vect = %x\n",
+        nolock_printk(" - type = %s / trdid = %X / pid = %X / func = %X / blocked = %X\n",
         thread_type_str( thread->type ), thread->trdid, thread->process->pid,
         thread->entry_func, thread->blocked );
