[rtems commit] score: Add Thread_Configuration
Sebastian Huber
sebh at rtems.org
Wed Feb 12 15:11:59 UTC 2020
Module: rtems
Branch: master
Commit: a08dcb2f7c7c883559e10c389404a4dc751376fa
Changeset: http://git.rtems.org/rtems/commit/?id=a08dcb2f7c7c883559e10c389404a4dc751376fa
Author: Sebastian Huber <sebastian.huber at embedded-brains.de>
Date: Mon Dec 9 13:57:51 2019 +0100
score: Add Thread_Configuration
Add the Thread_Configuration structure to reduce the parameter count of
_Thread_Initialize(). This makes it easier to add more parameters in
the future. It simplifies the code generation since most architectures
do not have that many registers available for function parameters.
Update #3835.
---
cpukit/include/rtems/score/threadimpl.h | 83 ++++++++++++++++++++++++---------
cpukit/posix/src/pthreadcreate.c | 51 ++++++++++----------
cpukit/rtems/src/taskcreate.c | 45 ++++++++----------
cpukit/score/src/mpci.c | 37 +++++++--------
cpukit/score/src/threadcreateidle.c | 37 +++++++--------
cpukit/score/src/threadinitialize.c | 70 +++++++++++++--------------
6 files changed, 170 insertions(+), 153 deletions(-)
diff --git a/cpukit/include/rtems/score/threadimpl.h b/cpukit/include/rtems/score/threadimpl.h
index 1289a30..54f6c8c 100644
--- a/cpukit/include/rtems/score/threadimpl.h
+++ b/cpukit/include/rtems/score/threadimpl.h
@@ -125,6 +125,61 @@ void _Thread_Create_idle(void);
void _Thread_Start_multitasking( void ) RTEMS_NO_RETURN;
/**
+ * @brief The configuration of a new thread to initialize.
+ */
+typedef struct {
+ /**
+ * @brief The scheduler control instance for the thread.
+ */
+ const struct _Scheduler_Control *scheduler;
+
+ /**
+ * @brief The starting address of the thread area.
+ */
+ void *stack_area;
+
+ /**
+ * @brief The size of the thread area in bytes.
+ */
+ size_t stack_size;
+
+ /**
+ * @brief The new thread's priority.
+ */
+ Priority_Control priority;
+
+ /**
+ * @brief The thread's budget algorithm.
+ */
+ Thread_CPU_budget_algorithms budget_algorithm;
+
+ /**
+ * @brief The thread's initial budget callout.
+ */
+ Thread_CPU_budget_algorithm_callout budget_callout;
+
+ /**
+ * @brief Name of the object for the thread.
+ */
+ Objects_Name name;
+
+ /**
+ * @brief The thread's initial ISR level.
+ */
+ uint32_t isr_level;
+
+ /**
+ * @brief Indicates whether the thread needs a floating-point area.
+ */
+ bool is_fp;
+
+ /**
+ * @brief Indicates whether the new thread is preemptible.
+ */
+ bool is_preemptible;
+} Thread_Configuration;
+
+/**
* @brief Initializes thread.
*
* This routine initializes the specified the thread. It allocates
@@ -138,34 +193,16 @@ void _Thread_Start_multitasking( void ) RTEMS_NO_RETURN;
* guaranteed to be of at least minimum size.
*
* @param information The thread information.
- * @param[out] the_thread The thread to initialize.
- * @param scheduler The scheduler control instance for the thread.
- * @param stack_area The starting address of the thread area.
- * @param stack_size The size of the thread area in bytes.
- * @param is_fp Indicates whether the thread needs a floating point area.
- * @param priority The new thread's priority.
- * @param is_preemptible Indicates whether the new thread is preemptible.
- * @param budget_algorithm The thread's budget algorithm.
- * @param budget_callout The thread's initial budget callout.
- * @param isr_level The thread's initial isr level.
- * @param name Name of the object for the thread.
+ * @param the_thread The thread to initialize.
+ * @param config The configuration of the thread to initialize.
*
* @retval true The thread initialization was successful.
* @retval false The thread initialization failed.
*/
bool _Thread_Initialize(
- Thread_Information *information,
- Thread_Control *the_thread,
- const struct _Scheduler_Control *scheduler,
- void *stack_area,
- size_t stack_size,
- bool is_fp,
- Priority_Control priority,
- bool is_preemptible,
- Thread_CPU_budget_algorithms budget_algorithm,
- Thread_CPU_budget_algorithm_callout budget_callout,
- uint32_t isr_level,
- Objects_Name name
+ Thread_Information *information,
+ Thread_Control *the_thread,
+ const Thread_Configuration *config
);
/**
diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c
index 47a408b..2a418c4 100644
--- a/cpukit/posix/src/pthreadcreate.c
+++ b/cpukit/posix/src/pthreadcreate.c
@@ -39,6 +39,8 @@
#include <rtems/score/userextimpl.h>
#include <rtems/sysinit.h>
+#include <string.h>
+
static inline size_t _POSIX_Threads_Ensure_minimum_stack (
size_t size
)
@@ -68,18 +70,12 @@ int pthread_create(
const pthread_attr_t *the_attr;
int normal_prio;
bool valid;
- Priority_Control core_normal_prio;
- Thread_CPU_budget_algorithms budget_algorithm;
- Thread_CPU_budget_algorithm_callout budget_callout;
- bool is_fp;
+ Thread_Configuration config;
bool status;
Thread_Control *the_thread;
Thread_Control *executing;
- const Scheduler_Control *scheduler;
int schedpolicy = SCHED_RR;
struct sched_param schedparam;
- size_t stacksize;
- Objects_Name name;
int error;
ISR_lock_Context lock_context;
#if defined(RTEMS_POSIX_API)
@@ -96,11 +92,15 @@ int pthread_create(
if ( !the_attr->is_initialized )
return EINVAL;
+ memset( &config, 0, sizeof( config ) );
+
/*
* Currently all POSIX threads are floating point if the hardware
* supports it.
*/
- is_fp = true;
+ config.is_fp = true;
+
+ config.is_preemptible = true;
/*
* Core Thread Initialize ensures we get the minimum amount of
@@ -110,13 +110,16 @@ int pthread_create(
* twice the minimum.
*/
if ( the_attr->stackaddr != NULL ) {
- if ( !_Stack_Is_enough( the_attr->stacksize, is_fp ) ) {
+ if ( !_Stack_Is_enough( the_attr->stacksize, config.is_fp ) ) {
return EINVAL;
}
- stacksize = the_attr->stacksize;
+ config.stack_area = the_attr->stackaddr;
+ config.stack_size = the_attr->stacksize;
} else {
- stacksize = _POSIX_Threads_Ensure_minimum_stack( the_attr->stacksize );
+ config.stack_size = _POSIX_Threads_Ensure_minimum_stack(
+ the_attr->stacksize
+ );
}
#if 0
@@ -164,8 +167,8 @@ int pthread_create(
error = _POSIX_Thread_Translate_sched_param(
schedpolicy,
&schedparam,
- &budget_algorithm,
- &budget_callout
+ &config.budget_algorithm,
+ &config.budget_callout
);
if ( error != 0 ) {
return error;
@@ -173,9 +176,13 @@ int pthread_create(
normal_prio = schedparam.sched_priority;
- scheduler = _Thread_Scheduler_get_home( executing );
+ config.scheduler = _Thread_Scheduler_get_home( executing );
- core_normal_prio = _POSIX_Priority_To_core( scheduler, normal_prio, &valid );
+ config.priority = _POSIX_Priority_To_core(
+ config.scheduler,
+ normal_prio,
+ &valid
+ );
if ( !valid ) {
return EINVAL;
}
@@ -187,7 +194,7 @@ int pthread_create(
low_prio = normal_prio;
}
- core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
+ core_low_prio = _POSIX_Priority_To_core( config.scheduler, low_prio, &valid );
if ( !valid ) {
return EINVAL;
}
@@ -211,20 +218,10 @@ int pthread_create(
/*
* Initialize the core thread for this task.
*/
- name.name_p = NULL; /* posix threads don't have a name by default */
status = _Thread_Initialize(
&_POSIX_Threads_Information,
the_thread,
- scheduler,
- the_attr->stackaddr,
- stacksize,
- is_fp,
- core_normal_prio,
- true, /* preemptible */
- budget_algorithm,
- budget_callout,
- 0, /* isr level */
- name /* posix threads don't have a name */
+ &config
);
if ( !status ) {
_POSIX_Threads_Free( the_thread );
diff --git a/cpukit/rtems/src/taskcreate.c b/cpukit/rtems/src/taskcreate.c
index e27b82c..5b53ed6 100644
--- a/cpukit/rtems/src/taskcreate.c
+++ b/cpukit/rtems/src/taskcreate.c
@@ -30,6 +30,8 @@
#include <rtems/score/userextimpl.h>
#include <rtems/sysinit.h>
+#include <string.h>
+
rtems_status_code rtems_task_create(
rtems_name name,
rtems_task_priority initial_priority,
@@ -40,8 +42,7 @@ rtems_status_code rtems_task_create(
)
{
Thread_Control *the_thread;
- const Scheduler_Control *scheduler;
- bool is_fp;
+ Thread_Configuration config;
#if defined(RTEMS_MULTIPROCESSING)
Objects_MP_Control *the_global_object = NULL;
bool is_global;
@@ -49,11 +50,9 @@ rtems_status_code rtems_task_create(
bool status;
rtems_attribute the_attribute_set;
bool valid;
- Priority_Control priority;
RTEMS_API_Control *api;
ASR_Information *asr;
-
if ( !id )
return RTEMS_INVALID_ADDRESS;
@@ -78,10 +77,15 @@ rtems_status_code rtems_task_create(
the_attribute_set =
_Attributes_Clear( the_attribute_set, ATTRIBUTES_NOT_SUPPORTED );
- if ( _Attributes_Is_floating_point( the_attribute_set ) )
- is_fp = true;
- else
- is_fp = false;
+ memset( &config, 0, sizeof( config ) );
+ config.stack_size = stack_size;
+ config.budget_algorithm = _Modes_Is_timeslice( initial_modes ) ?
+ THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE
+ : THREAD_CPU_BUDGET_ALGORITHM_NONE,
+ config.isr_level = _Modes_Get_interrupt_level( initial_modes );
+ config.name.name_u32 = name;
+ config.is_fp = _Attributes_Is_floating_point( the_attribute_set );
+ config.is_preemptible = _Modes_Is_preempt( initial_modes );
/*
* Validate the RTEMS API priority and convert it to the core priority range.
@@ -93,9 +97,13 @@ rtems_status_code rtems_task_create(
}
}
- scheduler = _Thread_Scheduler_get_home( _Thread_Get_executing() );
+ config.scheduler = _Thread_Scheduler_get_home( _Thread_Get_executing() );
- priority = _RTEMS_Priority_To_core( scheduler, initial_priority, &valid );
+ config.priority = _RTEMS_Priority_To_core(
+ config.scheduler,
+ initial_priority,
+ &valid
+ );
if ( !valid ) {
return RTEMS_INVALID_PRIORITY;
}
@@ -144,22 +152,7 @@ rtems_status_code rtems_task_create(
* Initialize the core thread for this task.
*/
- status = _Thread_Initialize(
- &_RTEMS_tasks_Information,
- the_thread,
- scheduler,
- NULL,
- stack_size,
- is_fp,
- priority,
- _Modes_Is_preempt(initial_modes) ? true : false,
- _Modes_Is_timeslice(initial_modes) ?
- THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE :
- THREAD_CPU_BUDGET_ALGORITHM_NONE,
- NULL, /* no budget algorithm callout */
- _Modes_Get_interrupt_level(initial_modes),
- (Objects_Name) name
- );
+ status = _Thread_Initialize( &_RTEMS_tasks_Information, the_thread, &config );
if ( !status ) {
#if defined(RTEMS_MULTIPROCESSING)
diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c
index 513d096..32489ac 100644
--- a/cpukit/score/src/mpci.c
+++ b/cpukit/score/src/mpci.c
@@ -29,6 +29,8 @@
#include <rtems/score/threadqimpl.h>
#include <rtems/sysinit.h>
+#include <string.h>
+
RTEMS_STATIC_ASSERT(
sizeof(MPCI_Internal_packet) <= MP_PACKET_MINIMUM_PACKET_SIZE,
MPCI_Internal_packet
@@ -111,8 +113,8 @@ static void _MPCI_Create_server( void )
}
}
};
- ISR_lock_Context lock_context;
- Objects_Name name;
+ Thread_Configuration config;
+ ISR_lock_Context lock_context;
if ( !_System_state_Is_multiprocessing )
@@ -123,24 +125,19 @@ static void _MPCI_Create_server( void )
*/
_MPCI_Receive_server_tcb = _Thread_Internal_allocate();
-
- name.name_u32 = _Objects_Build_name( 'M', 'P', 'C', 'I' );
- _Thread_Initialize(
- &_Thread_Information,
- _MPCI_Receive_server_tcb,
- &_Scheduler_Table[ 0 ],
- NULL, /* allocate the stack */
- _Stack_Minimum() +
- CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK +
- _MPCI_Configuration.extra_mpci_receive_server_stack,
- CPU_ALL_TASKS_ARE_FP,
- PRIORITY_PSEUDO_ISR,
- false, /* no preempt */
- THREAD_CPU_BUDGET_ALGORITHM_NONE,
- NULL, /* no budget algorithm callout */
- 0, /* all interrupts enabled */
- name
- );
+ _Assert( _MPCI_Receive_server_tcb != NULL );
+
+ memset( &config, 0, sizeof( config ) );
+ config.scheduler = &_Scheduler_Table[ 0 ];
+ config.stack_size = _Stack_Minimum()
+ + CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK
+ + _MPCI_Configuration.extra_mpci_receive_server_stack;
+ config.name.name_u32 = _Objects_Build_name( 'M', 'P', 'C', 'I' );
+ config.priority = PRIORITY_PSEUDO_ISR;
+ config.budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
+ config.is_fp = CPU_ALL_TASKS_ARE_FP;
+
+ _Thread_Initialize( &_Thread_Information, _MPCI_Receive_server_tcb, &config );
_ISR_lock_ISR_disable( &lock_context );
_Thread_Start( _MPCI_Receive_server_tcb, &entry, &lock_context );
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index 3e6f19e..e7243ae 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -25,21 +25,31 @@
#include <rtems/score/userextimpl.h>
#include <rtems/config.h>
+#include <string.h>
+
static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
{
- Objects_Name name;
+ Thread_Configuration config;
Thread_Control *idle;
- const Scheduler_Control *scheduler;
- scheduler = _Scheduler_Get_by_CPU( cpu );
+ memset( &config, 0, sizeof( config ) );
+ config.scheduler = _Scheduler_Get_by_CPU( cpu );
#if defined(RTEMS_SMP)
- if (scheduler == NULL) {
+ if ( config.scheduler == NULL ) {
return;
}
#endif
- name.name_u32 = _Objects_Build_name( 'I', 'D', 'L', 'E' );
+ config.stack_size = rtems_configuration_get_idle_task_stack_size();
+ config.priority = _Scheduler_Map_priority(
+ config.scheduler,
+ config.scheduler->maximum_priority
+ );
+ config.budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
+ config.name.name_u32 = _Objects_Build_name( 'I', 'D', 'L', 'E' );
+ config.is_fp = CPU_IDLE_TASK_IS_FP;
+ config.is_preemptible = true;
/*
* The entire workspace is zeroed during its initialization. Thus, all
@@ -49,20 +59,7 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
idle = _Thread_Internal_allocate();
_Assert( idle != NULL );
- _Thread_Initialize(
- &_Thread_Information,
- idle,
- scheduler,
- NULL, /* allocate the stack */
- rtems_configuration_get_idle_task_stack_size(),
- CPU_IDLE_TASK_IS_FP,
- _Scheduler_Map_priority( scheduler, scheduler->maximum_priority ),
- true, /* preemptable */
- THREAD_CPU_BUDGET_ALGORITHM_NONE,
- NULL, /* no budget algorithm callout */
- 0, /* all interrupts enabled */
- name
- );
+ _Thread_Initialize( &_Thread_Information, idle, &config );
/*
* WARNING!!! This is necessary to "kick" start the system and
@@ -78,7 +75,7 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
_Thread_Load_environment( idle );
idle->current_state = STATES_READY;
- _Scheduler_Start_idle( scheduler, idle, cpu );
+ _Scheduler_Start_idle( config.scheduler, idle, cpu );
_User_extensions_Thread_start( idle );
}
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index a1bc3b2..cf21602 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -28,23 +28,16 @@
#include <rtems/config.h>
bool _Thread_Initialize(
- Thread_Information *information,
- Thread_Control *the_thread,
- const Scheduler_Control *scheduler,
- void *stack_area,
- size_t stack_size,
- bool is_fp,
- Priority_Control priority,
- bool is_preemptible,
- Thread_CPU_budget_algorithms budget_algorithm,
- Thread_CPU_budget_algorithm_callout budget_callout,
- uint32_t isr_level,
- Objects_Name name
+ Thread_Information *information,
+ Thread_Control *the_thread,
+ const Thread_Configuration *config
)
{
uintptr_t tls_size;
bool extension_status;
size_t i;
+ char *stack_area;
+ size_t stack_size;
Scheduler_Node *scheduler_node;
#if defined(RTEMS_SMP)
Scheduler_Node *scheduler_node_for_index;
@@ -54,14 +47,14 @@ bool _Thread_Initialize(
Per_CPU_Control *cpu = _Per_CPU_Get_by_index( 0 );
#if defined(RTEMS_SMP)
- if ( !is_preemptible && rtems_configuration_is_smp_enabled() ) {
+ if ( !config->is_preemptible && rtems_configuration_is_smp_enabled() ) {
return false;
}
#endif
#if defined(RTEMS_SMP) || CPU_ENABLE_ROBUST_THREAD_DISPATCH == TRUE
if (
- isr_level != 0
+ config->isr_level != 0
#if CPU_ENABLE_ROBUST_THREAD_DISPATCH == FALSE
&& rtems_configuration_is_smp_enabled()
#endif
@@ -87,12 +80,12 @@ bool _Thread_Initialize(
/* Allocate the stack for this thread */
#if defined(RTEMS_SCORE_THREAD_ENABLE_USER_PROVIDED_STACK_VIA_API)
- if ( stack_area == NULL ) {
+ if ( config->stack_area == NULL ) {
#endif
- stack_size = _Stack_Ensure_minimum( stack_size );
+ stack_size = _Stack_Ensure_minimum( config->stack_size );
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
- if ( is_fp ) {
+ if ( config->is_fp ) {
stack_size += CONTEXT_FP_SIZE;
}
#endif
@@ -106,16 +99,19 @@ bool _Thread_Initialize(
the_thread->Start.allocated_stack = stack_area;
#if defined(RTEMS_SCORE_THREAD_ENABLE_USER_PROVIDED_STACK_VIA_API)
+ } else {
+ stack_area = config->stack_area;
+ stack_size = config->stack_size;
}
#endif
/* Allocate floating-point context in stack area */
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
- if ( is_fp ) {
- the_thread->fp_context = stack_area;
- the_thread->Start.fp_context = stack_area;
+ if ( config->is_fp ) {
+ the_thread->fp_context = ( Context_Control_fp *) stack_area;
+ the_thread->Start.fp_context = ( Context_Control_fp *) stack_area;
stack_size -= CONTEXT_FP_SIZE;
- stack_area = (char *) stack_area + CONTEXT_FP_SIZE;
+ stack_area += CONTEXT_FP_SIZE;
}
#endif
@@ -127,7 +123,7 @@ bool _Thread_Initialize(
the_thread->Start.tls_area = (void *)
( ( (uintptr_t) stack_area + tls_align - 1 ) & ~( tls_align - 1 ) );
stack_size -= tls_size;
- stack_area = (char *) stack_area + tls_size;
+ stack_area += tls_size;
}
_Stack_Initialize(
@@ -156,15 +152,15 @@ bool _Thread_Initialize(
* General initialization
*/
- the_thread->is_fp = is_fp;
- the_thread->Start.isr_level = isr_level;
- the_thread->Start.is_preemptible = is_preemptible;
- the_thread->Start.budget_algorithm = budget_algorithm;
- the_thread->Start.budget_callout = budget_callout;
+ the_thread->is_fp = config->is_fp;
+ the_thread->Start.isr_level = config->isr_level;
+ the_thread->Start.is_preemptible = config->is_preemptible;
+ the_thread->Start.budget_algorithm = config->budget_algorithm;
+ the_thread->Start.budget_callout = config->budget_callout;
_Thread_Timer_initialize( &the_thread->Timer, cpu );
- switch ( budget_algorithm ) {
+ switch ( config->budget_algorithm ) {
case THREAD_CPU_BUDGET_ALGORITHM_NONE:
case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
break;
@@ -188,8 +184,8 @@ bool _Thread_Initialize(
while ( scheduler_index < _Scheduler_Count ) {
Priority_Control priority_for_index;
- if ( scheduler_for_index == scheduler ) {
- priority_for_index = priority;
+ if ( scheduler_for_index == config->scheduler ) {
+ priority_for_index = config->priority;
scheduler_node = scheduler_node_for_index;
} else {
/*
@@ -226,15 +222,15 @@ bool _Thread_Initialize(
#else
scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
_Scheduler_Node_initialize(
- scheduler,
+ config->scheduler,
scheduler_node,
the_thread,
- priority
+ config->priority
);
scheduler_index = 1;
#endif
- _Priority_Node_initialize( &the_thread->Real_priority, priority );
+ _Priority_Node_initialize( &the_thread->Real_priority, config->priority );
_Priority_Initialize_one(
&scheduler_node->Wait.Priority,
&the_thread->Real_priority
@@ -242,7 +238,7 @@ bool _Thread_Initialize(
#if defined(RTEMS_SMP)
RTEMS_STATIC_ASSERT( THREAD_SCHEDULER_BLOCKED == 0, Scheduler_state );
- the_thread->Scheduler.home_scheduler = scheduler;
+ the_thread->Scheduler.home_scheduler = config->scheduler;
_ISR_lock_Initialize( &the_thread->Scheduler.Lock, "Thread Scheduler" );
_Processor_mask_Assign(
&the_thread->Scheduler.Affinity,
@@ -260,7 +256,7 @@ bool _Thread_Initialize(
the_thread->current_state = STATES_DORMANT;
the_thread->Wait.operations = &_Thread_queue_Operations_default;
- the_thread->Start.initial_priority = priority;
+ the_thread->Start.initial_priority = config->priority;
RTEMS_STATIC_ASSERT( THREAD_WAIT_FLAGS_INITIAL == 0, Wait_flags );
@@ -273,7 +269,7 @@ bool _Thread_Initialize(
/*
* Open the object
*/
- _Objects_Open( &information->Objects, &the_thread->Object, name );
+ _Objects_Open( &information->Objects, &the_thread->Object, config->name );
/*
* We assume the Allocator Mutex is locked and dispatching is
@@ -298,7 +294,7 @@ failed:
}
#else
if ( scheduler_index > 0 ) {
- _Scheduler_Node_destroy( scheduler, scheduler_node );
+ _Scheduler_Node_destroy( config->scheduler, scheduler_node );
}
#endif
More information about the vc
mailing list