Index: trunk/kernel/kern/scheduler.c
===================================================================
--- trunk/kernel/kern/scheduler.c	(revision 582)
+++ trunk/kernel/kern/scheduler.c	(revision 583)
@@ -40,4 +40,5 @@
 
 extern chdev_directory_t    chdev_dir;          // allocated in kernel_init.c
+extern process_t            process_zero;       // allocated in kernel_init.c
 
 ///////////////////////////////////////////////////////////////////////////////////////////
@@ -83,6 +84,5 @@
 
 // check kernel threads list
-assert( (count < sched->k_threads_nr),
-"bad kernel threads list" );
+assert( (count < sched->k_threads_nr), "bad kernel threads list" );
 
             // get next entry in kernel list
@@ -118,6 +118,5 @@
 
 // check user threads list
-assert( (count < sched->u_threads_nr),
-"bad user threads list" );
+assert( (count < sched->u_threads_nr), "bad user threads list" );
 
             // get next entry in user list
@@ -146,13 +145,18 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is the only function that can remove a thread from the scheduler.
+// This static function is the only function that can actually delete a thread.
 // It is private, because it is called by the sched_yield() public function.
 // It scan all threads attached to a given scheduler, and executes the relevant
-// actions for pending requests: 
+// actions for two types of pending requests: 
 // - REQ_ACK : it checks that target thread is blocked, decrements the response counter
 //   to acknowledge the client thread, and reset the pending request. 
-// - REQ_DELETE : it detach the target thread from parent if attached, detach it from
-//   the process, remove it from scheduler, release memory allocated to thread descriptor,
-//   and destroy the process descriptor it the target thread was the last thread.
+// - REQ_DELETE : it removes the target thread from the process th_tbl[], remove it
+//   from the scheduler list, and release the memory allocated to thread descriptor.
+//   For an user thread, it destroys the process descriptor it the target thread is
+//   the last thread in the local process descriptor.
+//
+// Implementation note:
+// We use a while to scan the threads in scheduler lists, because some threads can
+// be destroyed, and we want not use a LIST_FOREACH()
 ////////////////////////////////////////////////////////////////////////////////////////////
 // @ core    : local pointer on the core descriptor.
@@ -166,19 +170,14 @@
     process_t    * process;
     scheduler_t  * sched;
-    bool_t         last;
+    uint32_t       threads_nr;   // number of threads in scheduler list
+    ltid_t         ltid;         // thread local index
+    uint32_t       count;        // number of threads in local process
 
     // get pointer on scheduler
     sched = &core->scheduler;
 
-    // get pointer on user threads root
+    ////// scan user threads to handle both ACK and DELETE requests
     root = &sched->u_root;
-
-    // We use a while to scan the user threads, to control the iterator increment,
-    // because some threads will be destroyed, and we want not use a LIST_FOREACH()
-
-    // initialise list iterator
     iter = root->next;
-
-    // scan all user threads
     while( iter != root )
     {
@@ -210,12 +209,15 @@
             process = thread->process;
 
-	        // release FPU if required
-	        if( thread->core->fpu_owner == thread )  thread->core->fpu_owner = NULL;
-
-            // take lock protecting sheduler state
+            // get thread ltid
+            ltid = LTID_FROM_TRDID( thread->trdid);
+
+            // take the lock protecting th_tbl[]
+            rwlock_wr_acquire( &process->th_lock );
+
+            // take the lock protecting sheduler state
             busylock_acquire( &sched->lock );
 
             // update scheduler state
-            uint32_t threads_nr = sched->u_threads_nr;
+            threads_nr = sched->u_threads_nr;
             sched->u_threads_nr = threads_nr - 1;
             list_unlink( &thread->sched_list );
@@ -236,18 +238,31 @@
             }
 
-            // release lock protecting scheduler state
+            // release the lock protecting sheduler state
             busylock_release( &sched->lock );
 
-            // delete thread descriptor
-            last = thread_destroy( thread );
+            // get number of threads in local process
+            count = process->th_nr;
+
+// check th_nr value
+assert( (count > 0) , "process th_nr cannot be 0\n" );
+
+            // remove thread from process th_tbl[]
+            process->th_tbl[ltid] = NULL;
+            process->th_nr = count - 1;
+ 
+            // release the lock protecting th_tbl[]
+            rwlock_wr_release( &process->th_lock );
+
+            // release memory allocated for thread descriptor
+            thread_destroy( thread );
 
 #if DEBUG_SCHED_HANDLE_SIGNALS
 uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_SCHED_HANDLE_SIGNALS < cycle )
-printk("\n[DBG] %s : thread %x in process %x on core[%x,%d] deleted / cycle %d\n",
-__FUNCTION__ , thread->trdid , process->pid , local_cxy , thread->core->lid , cycle );
+printk("\n[DBG] %s : thread[%x,%x] on core[%x,%d] deleted / cycle %d\n",
+__FUNCTION__ , process->pid , thread->trdid , local_cxy , thread->core->lid , cycle );
 #endif
-            // destroy process descriptor if no more threads
-            if( last ) 
+            // destroy process descriptor if last thread
+            if( count == 1 ) 
             {
                 // delete process    
@@ -262,4 +277,79 @@
             }
         }
+    }  // end user threads
+
+    ////// scan kernel threads for DELETE only
+    root = &sched->k_root;
+    iter = root->next;
+    while( iter != root )
+    {
+        // get pointer on thread
+        thread = LIST_ELEMENT( iter , thread_t , sched_list );
+
+        // increment iterator
+        iter = iter->next;
+
+        // handle REQ_DELETE only if target thread != calling thread
+        if( (thread->flags & THREAD_FLAG_REQ_DELETE) && (thread != CURRENT_THREAD) )
+        {
+
+// check process descriptor is local kernel process
+assert( ( thread->process == &process_zero ) , "illegal process descriptor\n");
+
+            // get thread ltid
+            ltid = LTID_FROM_TRDID( thread->trdid);
+
+            // take the lock protecting th_tbl[]
+            rwlock_wr_acquire( &process_zero.th_lock );
+
+            // take lock protecting sheduler state
+            busylock_acquire( &sched->lock );
+
+            // update scheduler state
+            threads_nr = sched->k_threads_nr;
+            sched->k_threads_nr = threads_nr - 1;
+            list_unlink( &thread->sched_list );
+            if( sched->k_last == &thread->sched_list )
+            {
+                if( threads_nr == 1 ) 
+                {
+                    sched->k_last = NULL;
+                }
+                else if( sched->k_root.next == &thread->sched_list )
+                {
+                    sched->k_last = sched->k_root.pred;
+                }
+                else
+                {
+                    sched->k_last = sched->k_root.next;
+                }
+            }
+
+            // release lock protecting scheduler state
+            busylock_release( &sched->lock );
+
+            // get number of threads in local kernel process
+            count = process_zero.th_nr;
+
+// check th_nr value
+assert( (count > 0) , "kernel process th_nr cannot be 0\n" );
+
+            // remove thread from process th_tbl[]
+            process_zero.th_tbl[ltid] = NULL;
+            process_zero.th_nr = count - 1;
+ 
+            // release the lock protecting th_tbl[]
+            rwlock_wr_release( &process_zero.th_lock );
+
+            // delete thread descriptor
+            thread_destroy( thread );
+
+#if DEBUG_SCHED_HANDLE_SIGNALS
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_SCHED_HANDLE_SIGNALS < cycle )
+printk("\n[DBG] %s : thread[%x,%x] on core[%x,%d] deleted / cycle %d\n",
+__FUNCTION__ , process_zero.pid , thread->trdid , local_cxy , thread->core->lid , cycle );
+#endif
+        }
     }
 } // end sched_handle_signals()
@@ -268,6 +358,6 @@
 // This static function is called by the sched_yield function when the RFC_FIFO
 // associated to the core is not empty. 
-// It checks if it exists an idle (blocked) RPC thread for this core, and unblock 
-// it if found. It creates a new RPC thread if no idle RPC thread is found.
+// It search an idle RPC thread for this core, and unblock it if found. 
+// It creates a new RPC thread if no idle RPC thread is found.
 ////////////////////////////////////////////////////////////////////////////////////////////
 // @ sched   : local pointer on scheduler.
@@ -285,7 +375,8 @@
     {
         thread = LIST_ELEMENT( iter , thread_t , sched_list );
-        if( (thread->type == THREAD_RPC) && (thread->blocked == THREAD_BLOCKED_IDLE ) ) 
-        {
-            // exit loop
+
+        if( (thread->type == THREAD_RPC) && 
+            (thread->blocked == THREAD_BLOCKED_IDLE ) ) 
+        {
             found = true;
             break;
@@ -303,5 +394,5 @@
         if ( error )
         {
-            printk("\n[WARNING] in %s : no memory to create a RPC thread in cluster %x\n",
+            printk("\n[ERROR] in %s : no memory to create a RPC thread in cluster %x\n",
             __FUNCTION__, local_cxy );
         }
@@ -317,6 +408,6 @@
 uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_SCHED_RPC_ACTIVATE < cycle ) 
-printk("\n[DBG] %s : new RPC thread %x created for core[%x,%d] / cycle %d\n",
-__FUNCTION__, thread->trdid, local_cxy, lid, cycle );
+printk("\n[DBG] %s : new RPC thread %x created for core[%x,%d] / total %d / cycle %d\n",
+__FUNCTION__, thread->trdid, local_cxy, lid, LOCAL_CLUSTER->rpc_threads[lid], cycle );
 #endif
         }
@@ -476,5 +567,5 @@
         busylock_release( &sched->lock );
 
-#if DEBUG_SCHED_YIELD 
+#if (DEBUG_SCHED_YIELD & 1)
 if( sched->trace )
 printk("\n[DBG] %s : core[%x,%d] / cause = %s\n"
@@ -519,6 +610,7 @@
     remote_busylock_acquire( lock_xp );
 
-    nolock_printk("\n***** threads on core[%x,%d] / current %x / cycle %d\n",
-    local_cxy , core->lid, sched->current, (uint32_t)hal_get_cycles() );
+    nolock_printk("\n***** threads on core[%x,%d] / current %x / rpc_threads %d / cycle %d\n",
+    local_cxy , core->lid, sched->current, LOCAL_CLUSTER->rpc_threads[lid],
+    (uint32_t)hal_get_cycles() );
 
     // display kernel threads
@@ -564,5 +656,4 @@
 "illegal cluster %x\n", cxy );
 
-// check lid
 assert( (lid < hal_remote_l32( XPTR( cxy , &LOCAL_CLUSTER->cores_nr ) ) ),
 "illegal core index %d\n", lid );
@@ -590,7 +681,10 @@
     remote_busylock_acquire( lock_xp );
 
+    // get rpc_threads
+    uint32_t rpcs = hal_remote_l32( XPTR( cxy , &LOCAL_CLUSTER->rpc_threads[lid] ) );
+ 
     // display header
-    nolock_printk("\n***** threads on core[%x,%d] / current %x / cycle %d\n",
-    cxy , lid, current, (uint32_t)hal_get_cycles() );
+    nolock_printk("\n***** threads on core[%x,%d] / current %x / rpc_threads %d / cycle %d\n",
+    cxy , lid, current, rpcs, (uint32_t)hal_get_cycles() );
 
     // display kernel threads
