[PATCH] score: Fix CPU time used by executing threads

Sebastian Huber sebastian.huber at embedded-brains.de
Wed Mar 16 07:53:11 UTC 2016


The CPU time used of a thread was previously maintained per-processor
mostly during _Thread_Dispatch().  However, on SMP configurations the
actual processor of a thread is difficult to figure out since thread
dispatching is a highly asynchronous process (e.g. via inter-processor
interrupts).  Only the intended processor of a thread is known to the
scheduler easily.  Do the CPU usage accounting during thread heir
updates in the context of the scheduler operations.  Provide the
function _Thread_Get_CPU_time_used() to get the CPU usage of a thread
using proper locks to get a consistent value.

Close #2627.
---
 cpukit/libcsupport/src/__times.c                 | 26 ++++----
 cpukit/libmisc/cpuuse/cpuusagereport.c           | 51 ++++++----------
 cpukit/libmisc/cpuuse/cpuusagereset.c            |  7 ++-
 cpukit/libmisc/cpuuse/cpuusagetop.c              | 23 +-------
 cpukit/rtems/src/ratemonperiod.c                 | 75 +++++++-----------------
 cpukit/score/Makefile.am                         |  1 +
 cpukit/score/include/rtems/score/percpu.h        | 15 +++--
 cpukit/score/include/rtems/score/schedulerimpl.h | 32 ++++++----
 cpukit/score/include/rtems/score/threadimpl.h    | 67 +++++++--------------
 cpukit/score/src/schedulersmpstartidle.c         |  1 +
 cpukit/score/src/threaddispatch.c                |  5 --
 cpukit/score/src/threadgetcputimeused.c          | 47 +++++++++++++++
 12 files changed, 157 insertions(+), 193 deletions(-)
 create mode 100644 cpukit/score/src/threadgetcputimeused.c

diff --git a/cpukit/libcsupport/src/__times.c b/cpukit/libcsupport/src/__times.c
index ea6d1c6..a30f720 100644
--- a/cpukit/libcsupport/src/__times.c
+++ b/cpukit/libcsupport/src/__times.c
@@ -26,9 +26,11 @@
 #include <rtems.h>
 
 #include <sys/times.h>
-#include <time.h>
 #include <sys/time.h>
-#include <errno.h>
+
+#include <string.h>
+#include <time.h>
+
 #include <rtems/seterr.h>
 #include <rtems/score/todimpl.h>
 #include <rtems/score/timestamp.h>
@@ -42,11 +44,12 @@ clock_t _times(
 )
 {
   rtems_interval ticks, us_per_tick;
-  Thread_Control *executing;
 
   if ( !ptms )
     rtems_set_errno_and_return_minus_one( EFAULT );
 
+  memset( ptms, 0, sizeof( *ptms ) );
+
   /*
    *  This call does not depend on TOD being initialized and can't fail.
    */
@@ -62,11 +65,12 @@ clock_t _times(
    *  this thread.
    */
   {
+    Timestamp_Control  cpu_time_used;
     Timestamp_Control  per_tick;
     uint32_t           ticks_of_executing;
     uint32_t           fractional_ticks;
-    Per_CPU_Control   *cpu_self;
 
+    _Thread_Get_CPU_time_used( _Thread_Get_executing(), &cpu_time_used );
     _Timestamp_Set(
       &per_tick,
       rtems_configuration_get_microseconds_per_tick() /
@@ -74,25 +78,17 @@ clock_t _times(
       (rtems_configuration_get_nanoseconds_per_tick() %
 	  TOD_NANOSECONDS_PER_SECOND)
     );
-
-    cpu_self = _Thread_Dispatch_disable();
-    executing = _Thread_Executing;
-    _Thread_Update_cpu_time_used(
-      executing,
-      &_Thread_Time_of_last_context_switch
-    );
     _Timestamp_Divide(
-      &executing->cpu_time_used,
+      &cpu_time_used,
       &per_tick,
       &ticks_of_executing,
       &fractional_ticks
     );
-    _Thread_Dispatch_enable( cpu_self );
+
     ptms->tms_utime = ticks_of_executing * us_per_tick;
   }
+
   ptms->tms_stime  = ticks * us_per_tick;
-  ptms->tms_cutime = 0;
-  ptms->tms_cstime = 0;
 
   return ticks * us_per_tick;
 }
diff --git a/cpukit/libmisc/cpuuse/cpuusagereport.c b/cpukit/libmisc/cpuuse/cpuusagereport.c
index 98b5f8b..95d0648 100644
--- a/cpukit/libmisc/cpuuse/cpuusagereport.c
+++ b/cpukit/libmisc/cpuuse/cpuusagereport.c
@@ -44,7 +44,7 @@ void rtems_cpu_usage_report_with_plugin(
   Objects_Information *information;
   char                 name[13];
   uint32_t             ival, fval;
-  Timestamp_Control  uptime, total, ran, uptime_at_last_reset;
+  Timestamp_Control  uptime, total, used, uptime_at_last_reset;
   uint32_t seconds, nanoseconds;
 
   if ( !print )
@@ -90,38 +90,23 @@ void rtems_cpu_usage_report_with_plugin(
           name
         );
 
-        {
-          Timestamp_Control last;
-
-          /*
-           * If this is the currently executing thread, account for time
-           * since the last context switch.
-           */
-          ran = the_thread->cpu_time_used;
-          if ( _Thread_Get_time_of_last_context_switch( the_thread, &last ) ) {
-            Timestamp_Control used;
-            _TOD_Get_uptime( &uptime );
-            _Timestamp_Subtract( &last, &uptime, &used );
-            _Timestamp_Add_to( &ran, &used );
-          } else {
-            _TOD_Get_uptime( &uptime );
-          }
-          _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
-          _Timestamp_Divide( &ran, &total, &ival, &fval );
-
-          /*
-           * Print the information
-           */
-
-          seconds = _Timestamp_Get_seconds( &ran );
-          nanoseconds = _Timestamp_Get_nanoseconds( &ran ) /
-            TOD_NANOSECONDS_PER_MICROSECOND;
-          (*print)( context,
-            "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
-            seconds, nanoseconds,
-            ival, fval
-          );
-        }
+        _Thread_Get_CPU_time_used( the_thread, &used );
+        _TOD_Get_uptime( &uptime );
+        _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
+        _Timestamp_Divide( &used, &total, &ival, &fval );
+
+        /*
+         * Print the information
+         */
+
+        seconds = _Timestamp_Get_seconds( &used );
+        nanoseconds = _Timestamp_Get_nanoseconds( &used ) /
+          TOD_NANOSECONDS_PER_MICROSECOND;
+        (*print)( context,
+          "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
+          seconds, nanoseconds,
+          ival, fval
+        );
       }
     }
   }
diff --git a/cpukit/libmisc/cpuuse/cpuusagereset.c b/cpukit/libmisc/cpuuse/cpuusagereset.c
index 8e9fe54..6ef50f9 100644
--- a/cpukit/libmisc/cpuuse/cpuusagereset.c
+++ b/cpukit/libmisc/cpuuse/cpuusagereset.c
@@ -21,13 +21,18 @@
 #include <rtems/cpuuse.h>
 #include <rtems/score/percpu.h>
 #include <rtems/score/todimpl.h>
+#include <rtems/score/schedulerimpl.h>
 #include <rtems/score/watchdogimpl.h>
 
 static void CPU_usage_Per_thread_handler(
   Thread_Control *the_thread
 )
 {
+  ISR_lock_Context lock_context;
+
+  _Scheduler_Acquire( the_thread, &lock_context );
   _Timestamp_Set_to_zero( &the_thread->cpu_time_used );
+  _Scheduler_Release( the_thread, &lock_context );
 }
 
 /*
@@ -44,7 +49,7 @@ void rtems_cpu_usage_reset( void )
   for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
     Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
 
-    cpu->time_of_last_context_switch = CPU_usage_Uptime_at_last_reset;
+    cpu->cpu_usage_timestamp = CPU_usage_Uptime_at_last_reset;
   }
 
   rtems_iterate_over_all_threads(CPU_usage_Per_thread_handler);
diff --git a/cpukit/libmisc/cpuuse/cpuusagetop.c b/cpukit/libmisc/cpuuse/cpuusagetop.c
index 6355e4e..9b92858 100644
--- a/cpukit/libmisc/cpuuse/cpuusagetop.c
+++ b/cpukit/libmisc/cpuuse/cpuusagetop.c
@@ -218,12 +218,14 @@ static void
 task_usage(Thread_Control* thread, void* arg)
 {
   rtems_cpu_usage_data* data = (rtems_cpu_usage_data*) arg;
-  Timestamp_Control     usage = thread->cpu_time_used;
+  Timestamp_Control     usage;
   Timestamp_Control     current = data->zero;
   int                   j;
 
   data->stack_size += thread->Start.Initial_stack.size;
 
+  _Thread_Get_CPU_time_used(thread, &usage);
+
   for (j = 0; j < data->last_task_count; j++)
   {
     if (thread == data->last_tasks[j])
@@ -497,25 +499,6 @@ rtems_cpuusage_top_thread (rtems_task_argument arg)
       current_usage = data->current_usage[i];
 
       /*
-       * If this is the currently executing thread, account for time since
-       * the last context switch.
-       */
-      if (_Thread_Get_time_of_last_context_switch(thread, &last))
-      {
-        Timestamp_Control used;
-        Timestamp_Control now;
-
-        /*
-         * Get the current uptime and assume we are not pre-empted to
-         * measure the time from the last switch this thread and now.
-         */
-        _TOD_Get_uptime(&now);
-        _Timestamp_Subtract(&last, &now, &used);
-        _Timestamp_Add_to(&usage, &used);
-        _Timestamp_Add_to(&current_usage, &used);
-      }
-
-      /*
        * Print the information
        */
       print_time(data, &usage, 19);
diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c
index 58be148..2a4b4eb 100644
--- a/cpukit/rtems/src/ratemonperiod.c
+++ b/cpukit/rtems/src/ratemonperiod.c
@@ -45,74 +45,39 @@ bool _Rate_monotonic_Get_status(
   /*
    *  Determine cpu usage since period initiated.
    */
-  used = owning_thread->cpu_time_used;
+  _Thread_Get_CPU_time_used( owning_thread, &used );
 
-  if (owning_thread == _Thread_Executing) {
-
-    Timestamp_Control ran;
-
-    /* How much time time since last context switch */
-    _Timestamp_Subtract(
-      &_Thread_Time_of_last_context_switch, &uptime, &ran
-    );
-
-    /* cpu usage += ran */
-    _Timestamp_Add_to( &used, &ran );
-
-    /*
-     *  The cpu usage info was reset while executing.  Can't
-     *  determine a status.
-     */
-    if (_Timestamp_Less_than(&used, &the_period->cpu_usage_period_initiated))
-      return false;
+  /*
+   *  The cpu usage info was reset while executing.  Can't
+   *  determine a status.
+   */
+  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
+    return false;
 
-     /* used = current cpu usage - cpu usage at start of period */
-    _Timestamp_Subtract(
-       &the_period->cpu_usage_period_initiated,
-       &used,
-       cpu_since_last_period
-    );
-  }
+   /* used = current cpu usage - cpu usage at start of period */
+  _Timestamp_Subtract(
+    &the_period->cpu_usage_period_initiated,
+    &used,
+    cpu_since_last_period
+  );
 
   return true;
 }
 
 void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period )
 {
-  Thread_Control    *owning_thread = the_period->owner;
-  Timestamp_Control  uptime;
-  ISR_Level          level;
-
-  _TOD_Get_uptime( &uptime );
+  ISR_Level level;
 
   /*
    *  Set the starting point and the CPU time used for the statistics.
    */
-  the_period->time_period_initiated = uptime;
-  the_period->cpu_usage_period_initiated = owning_thread->cpu_time_used;
-
-  /*
-   *  We need to take into account how much time the
-   *  executing thread has run since the last context switch.  When this
-   *  routine is invoked from rtems_rate_monotonic_period, the owner will
-   *  be the executing thread.  When this routine is invoked from
-   *  _Rate_monotonic_Timeout, it will not.
-   */
-  if (owning_thread == _Thread_Executing) {
-    Timestamp_Control ran;
-
-    /*
-     *  Adjust the CPU time used to account for the time since last
-     *  context switch.
-     */
-    _Timestamp_Subtract(
-      &_Thread_Time_of_last_context_switch, &uptime, &ran
-    );
-
-    _Timestamp_Add_to( &the_period->cpu_usage_period_initiated, &ran );
-  }
+  _TOD_Get_uptime( &the_period->time_period_initiated );
+  _Thread_Get_CPU_time_used(
+    the_period->owner,
+    &the_period->cpu_usage_period_initiated
+  );
 
-  _Scheduler_Release_job( owning_thread, the_period->next_length );
+  _Scheduler_Release_job( the_period->owner, the_period->next_length );
 
   _ISR_Disable( level );
   _Watchdog_Per_CPU_insert_relative(
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index af78f15..b6824ad 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -305,6 +305,7 @@ libscore_a_SOURCES += src/thread.c src/threadchangepriority.c \
 libscore_a_SOURCES += src/threadentryadaptoridle.c
 libscore_a_SOURCES += src/threadentryadaptornumeric.c
 libscore_a_SOURCES += src/threadentryadaptorpointer.c
+libscore_a_SOURCES += src/threadgetcputimeused.c
 libscore_a_SOURCES += src/threadglobalconstruction.c
 libscore_a_SOURCES += src/threadtimeout.c
 libscore_a_SOURCES += src/threadyield.c
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index 2201788..95c93dd 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -333,8 +333,17 @@ typedef struct Per_CPU_Control {
    */
   volatile bool dispatch_necessary;
 
-  /** This is the time of the last context switch on this CPU. */
-  Timestamp_Control time_of_last_context_switch;
+  /**
+   * @brief The CPU usage timestamp contains the time point of the last heir
+   * thread change or last CPU usage update of the executing thread of this
+   * processor.
+   *
+   * Protected by the scheduler lock.
+   *
+   * @see _Scheduler_Update_heir(), _Thread_Dispatch_update_heir() and
+   * _Thread_Get_CPU_time_used().
+   */
+  Timestamp_Control cpu_usage_timestamp;
 
   /**
    * @brief Watchdog state for this processor.
@@ -681,8 +690,6 @@ bool _Per_CPU_State_wait_for_non_initial_state(
   _Per_CPU_Get()->interrupt_stack_high
 #define _Thread_Dispatch_necessary \
   _Per_CPU_Get()->dispatch_necessary
-#define _Thread_Time_of_last_context_switch \
-  _Per_CPU_Get()->time_of_last_context_switch
 
 /**
  * @brief Returns the thread control block of the executing thread.
diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h
index d50c36a..a41b7ea 100644
--- a/cpukit/score/include/rtems/score/schedulerimpl.h
+++ b/cpukit/score/include/rtems/score/schedulerimpl.h
@@ -627,19 +627,6 @@ bool _Scheduler_Set_affinity(
 
 #endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
 
-RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir(
-  Thread_Control *new_heir,
-  bool            force_dispatch
-)
-{
-  Thread_Control *heir = _Thread_Heir;
-
-  if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) {
-    _Thread_Heir = new_heir;
-    _Thread_Dispatch_necessary = true;
-  }
-}
-
 RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block(
   const Scheduler_Control *scheduler,
   Thread_Control          *the_thread,
@@ -1356,6 +1343,25 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Ask_blocked_node_for_help(
 
 ISR_LOCK_DECLARE( extern, _Scheduler_Lock )
 
+RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir(
+  Thread_Control *new_heir,
+  bool            force_dispatch
+)
+{
+  Thread_Control *heir = _Thread_Heir;
+
+  if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) {
+#if defined(RTEMS_SMP)
+    /* We need this state only for _Thread_Get_CPU_time_used() */
+    _Scheduler_Thread_change_state( heir, THREAD_SCHEDULER_BLOCKED );
+    _Scheduler_Thread_change_state( new_heir, THREAD_SCHEDULER_SCHEDULED );
+#endif
+    _Thread_Update_CPU_time_used( heir, _Thread_Get_CPU( heir ) );
+    _Thread_Heir = new_heir;
+    _Thread_Dispatch_necessary = true;
+  }
+}
+
 /**
  * @brief Acquires the scheduler instance of the thread.
  *
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index ec9851d..3f8df85 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -578,36 +578,6 @@ RTEMS_INLINE_ROUTINE bool _Thread_Is_executing_on_a_processor(
 #endif
 
 /**
- * @brief Returns @a true and sets time_of_context_switch to the
- * time of the last context switch when the thread is currently executing
- * in the system, otherwise @a false.
- */
-RTEMS_INLINE_ROUTINE bool _Thread_Get_time_of_last_context_switch(
-  Thread_Control    *the_thread,
-  Timestamp_Control *time_of_context_switch
-)
-{
-  bool retval = false;
-
-  _Thread_Disable_dispatch();
-  #ifndef RTEMS_SMP
-    if ( _Thread_Executing->Object.id == the_thread->Object.id ) {
-      *time_of_context_switch = _Thread_Time_of_last_context_switch;
-      retval = true;
-    }
-  #else
-    if ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
-      *time_of_context_switch =
-        _Thread_Get_CPU( the_thread )->time_of_last_context_switch;
-      retval = true;
-    }
-  #endif
-  _Thread_Enable_dispatch();
-  return retval;
-}
-
-
-/**
  * This function returns true if the_thread is the heir
  * thread, and false otherwise.
  */
@@ -803,6 +773,20 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Get_heir_and_make_it_executing(
   return heir;
 }
 
+RTEMS_INLINE_ROUTINE void _Thread_Update_CPU_time_used(
+  Thread_Control  *the_thread,
+  Per_CPU_Control *cpu
+)
+{
+  Timestamp_Control last;
+  Timestamp_Control ran;
+
+  last = cpu->cpu_usage_timestamp;
+  _TOD_Get_uptime( &cpu->cpu_usage_timestamp );
+  _Timestamp_Subtract( &last, &cpu->cpu_usage_timestamp, &ran );
+  _Timestamp_Add_to( &the_thread->cpu_time_used, &ran );
+}
+
 #if defined( RTEMS_SMP )
 RTEMS_INLINE_ROUTINE void _Thread_Dispatch_update_heir(
   Per_CPU_Control *cpu_self,
@@ -810,6 +794,8 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_update_heir(
   Thread_Control  *heir
 )
 {
+  _Thread_Update_CPU_time_used( cpu_for_heir->heir, cpu_for_heir );
+
   cpu_for_heir->heir = heir;
 
   if ( cpu_for_heir == cpu_self ) {
@@ -820,23 +806,10 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_update_heir(
 }
 #endif
 
-RTEMS_INLINE_ROUTINE void _Thread_Update_cpu_time_used(
-  Thread_Control *executing,
-  Timestamp_Control *time_of_last_context_switch
-)
-{
-  Timestamp_Control uptime;
-  Timestamp_Control ran;
-
-  _TOD_Get_uptime( &uptime );
-  _Timestamp_Subtract(
-    time_of_last_context_switch,
-    &uptime,
-    &ran
-  );
-  *time_of_last_context_switch = uptime;
-  _Timestamp_Add_to( &executing->cpu_time_used, &ran );
-}
+void _Thread_Get_CPU_time_used(
+  Thread_Control    *the_thread,
+  Timestamp_Control *cpu_time_used
+);
 
 RTEMS_INLINE_ROUTINE void _Thread_Action_control_initialize(
   Thread_Action_control *action_control
diff --git a/cpukit/score/src/schedulersmpstartidle.c b/cpukit/score/src/schedulersmpstartidle.c
index de125d3..0ffb628 100644
--- a/cpukit/score/src/schedulersmpstartidle.c
+++ b/cpukit/score/src/schedulersmpstartidle.c
@@ -22,6 +22,7 @@ void _Scheduler_SMP_Start_idle(
   Scheduler_SMP_Context *self = _Scheduler_SMP_Get_self( context );
   Scheduler_SMP_Node *node = _Scheduler_SMP_Thread_get_node( thread );
 
+  _Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_SCHEDULED );
   node->state = SCHEDULER_SMP_NODE_SCHEDULED;
 
   _Thread_Set_CPU( thread, cpu );
diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c
index 1b36c93..ce5d118 100644
--- a/cpukit/score/src/threaddispatch.c
+++ b/cpukit/score/src/threaddispatch.c
@@ -108,11 +108,6 @@ void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
     _ISR_Enable( level );
 #endif
 
-    _Thread_Update_cpu_time_used(
-      executing,
-      &cpu_self->time_of_last_context_switch
-    );
-
     _User_extensions_Thread_switch( executing, heir );
     _Thread_Save_fp( executing );
     _Context_Switch( &executing->Registers, &heir->Registers );
diff --git a/cpukit/score/src/threadgetcputimeused.c b/cpukit/score/src/threadgetcputimeused.c
new file mode 100644
index 0000000..6bfe8ea
--- /dev/null
+++ b/cpukit/score/src/threadgetcputimeused.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/threadimpl.h>
+#include <rtems/score/schedulerimpl.h>
+
+static bool _Thread_Is_scheduled( const Thread_Control *the_thread )
+{
+#if defined(RTEMS_SMP)
+  return the_thread->Scheduler.state == THREAD_SCHEDULER_SCHEDULED;
+#else
+  return _Thread_Is_executing( the_thread );
+#endif
+}
+
+void _Thread_Get_CPU_time_used(
+  Thread_Control    *the_thread,
+  Timestamp_Control *cpu_time_used
+)
+{
+  ISR_lock_Context lock_context;
+
+  _Scheduler_Acquire( the_thread, &lock_context );
+
+  if ( _Thread_Is_scheduled( the_thread ) ) {
+    _Thread_Update_CPU_time_used( the_thread, _Thread_Get_CPU( the_thread ) );
+  }
+
+  *cpu_time_used = the_thread->cpu_time_used;
+
+  _Scheduler_Release( the_thread, &lock_context );
+}
-- 
1.8.4.5



More information about the devel mailing list