summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-04-08 09:42:29 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-04-15 08:37:12 +0200
commit69aa33490b1cd357519ab70b15ad150e11bb752e (patch)
tree8aa1ac3807bfe65ae1157629d0ad21548c35a5cb
parentscore: Static scheduler configuration (diff)
downloadrtems-69aa33490b1cd357519ab70b15ad150e11bb752e.tar.bz2
score: Simplify thread control initialization
The thread control block contains fields that point to application configuration dependent memory areas, like the scheduler information, the API control blocks, the user extension context table, the RTEMS notepads and the Newlib re-entrancy support. Account for these areas in the configuration and avoid extra workspace allocations for these areas. This helps also to avoid heap fragementation and reduces the per thread memory due to a reduced heap allocation overhead.
-rw-r--r--cpukit/libcsupport/include/rtems/libcsupport.h7
-rw-r--r--cpukit/libcsupport/src/newlibc_reent.c26
-rw-r--r--cpukit/posix/src/pthread.c25
-rw-r--r--cpukit/rtems/include/rtems/rtems/tasks.h2
-rw-r--r--cpukit/rtems/src/tasks.c40
-rw-r--r--cpukit/sapi/include/confdefs.h160
-rw-r--r--cpukit/score/Makefile.am3
-rw-r--r--cpukit/score/include/rtems/score/scheduler.h6
-rw-r--r--cpukit/score/include/rtems/score/schedulercbs.h4
-rw-r--r--cpukit/score/include/rtems/score/scheduleredf.h17
-rw-r--r--cpukit/score/include/rtems/score/schedulerimpl.h2
-rw-r--r--cpukit/score/include/rtems/score/schedulerpriority.h30
-rw-r--r--cpukit/score/include/rtems/score/schedulerpriorityaffinitysmp.h4
-rw-r--r--cpukit/score/include/rtems/score/schedulerprioritysmp.h4
-rw-r--r--cpukit/score/include/rtems/score/thread.h60
-rw-r--r--cpukit/score/src/schedulercbsallocate.c20
-rw-r--r--cpukit/score/src/schedulerdefaultallocatefree.c4
-rw-r--r--cpukit/score/src/scheduleredfallocate.c18
-rw-r--r--cpukit/score/src/scheduleredffree.c36
-rw-r--r--cpukit/score/src/schedulerpriorityaffinitysmp.c8
-rw-r--r--cpukit/score/src/schedulerpriorityallocate.c38
-rw-r--r--cpukit/score/src/schedulerpriorityfree.c35
-rw-r--r--cpukit/score/src/thread.c3
-rw-r--r--cpukit/score/src/threadinitialize.c65
-rw-r--r--cpukit/score/src/threadrestart.c2
25 files changed, 200 insertions, 419 deletions
diff --git a/cpukit/libcsupport/include/rtems/libcsupport.h b/cpukit/libcsupport/include/rtems/libcsupport.h
index 7d40084ece..c1bb9a191c 100644
--- a/cpukit/libcsupport/include/rtems/libcsupport.h
+++ b/cpukit/libcsupport/include/rtems/libcsupport.h
@@ -85,11 +85,6 @@ bool newlib_create_hook(
#define __RTEMS_NEWLIB_BEGIN 0
-void newlib_delete_hook(
- rtems_tcb *current_task,
- rtems_tcb *deleted_task
-);
-
void newlib_terminate_hook(
rtems_tcb *current_task
);
@@ -99,7 +94,7 @@ void newlib_terminate_hook(
newlib_create_hook, /* rtems_task_create */ \
0, /* rtems_task_start */ \
0, /* rtems_task_restart */ \
- newlib_delete_hook, /* rtems_task_delete */ \
+ 0, /* rtems_task_delete */ \
0, /* task_switch */ \
__RTEMS_NEWLIB_BEGIN, /* task_begin */ \
0, /* task_exitted */ \
diff --git a/cpukit/libcsupport/src/newlibc_reent.c b/cpukit/libcsupport/src/newlibc_reent.c
index cd3ac2a0ec..430157cf0f 100644
--- a/cpukit/libcsupport/src/newlibc_reent.c
+++ b/cpukit/libcsupport/src/newlibc_reent.c
@@ -35,9 +35,6 @@ bool newlib_create_hook(
rtems_tcb *creating_task
)
{
- struct _reent *ptr;
- bool ok;
-
#if !defined(__DYNAMIC_REENT__)
if (_Thread_libc_reent == 0)
{
@@ -47,28 +44,9 @@ bool newlib_create_hook(
}
#endif
- /* It is OK to allocate from the workspace because these
- * hooks run with thread dispatching disabled.
- */
- ptr = (struct _reent *) _Workspace_Allocate(sizeof(*ptr));
- creating_task->libc_reent = ptr;
- ok = ptr != NULL;
-
- if (ok) {
- _REENT_INIT_PTR((ptr)); /* GCC extension: structure constants */
- }
-
- return ok;
-}
-
-void newlib_delete_hook(
- rtems_tcb *current_task,
- rtems_tcb *deleted_task
-)
-{
- (void) current_task;
+ _REENT_INIT_PTR((creating_task->libc_reent)); /* GCC extension: structure constants */
- _Workspace_Free(deleted_task->libc_reent);
+ return true;
}
void newlib_terminate_hook(
diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c
index 6f79658677..ab197f3a51 100644
--- a/cpukit/posix/src/pthread.c
+++ b/cpukit/posix/src/pthread.c
@@ -190,12 +190,7 @@ static bool _POSIX_Threads_Create_extension(
POSIX_API_Control *api;
POSIX_API_Control *executing_api;
- api = _Workspace_Allocate( sizeof( POSIX_API_Control ) );
-
- if ( !api )
- return false;
-
- created->API_Extensions[ THREAD_API_POSIX ] = api;
+ api = created->API_Extensions[ THREAD_API_POSIX ];
/* XXX check all fields are touched */
_POSIX_Threads_Initialize_attributes( &api->Attributes );
@@ -266,19 +261,6 @@ static void _POSIX_Threads_Restart_extension(
_POSIX_Threads_cancel_run( restarted );
}
-/*
- * _POSIX_Threads_Delete_extension
- *
- * This method is invoked for each thread deleted.
- */
-static void _POSIX_Threads_Delete_extension(
- Thread_Control *executing __attribute__((unused)),
- Thread_Control *deleted
-)
-{
- _Workspace_Free( deleted->API_Extensions[ THREAD_API_POSIX ] );
-}
-
static void _POSIX_Threads_Terminate_extension(
Thread_Control *executing
)
@@ -355,7 +337,7 @@ User_extensions_Control _POSIX_Threads_User_extensions = {
{ _POSIX_Threads_Create_extension, /* create */
NULL, /* start */
_POSIX_Threads_Restart_extension, /* restart */
- _POSIX_Threads_Delete_extension, /* delete */
+ NULL, /* delete */
NULL, /* switch */
NULL, /* begin */
_POSIX_Threads_Exitted_extension, /* exitted */
@@ -392,8 +374,7 @@ void _POSIX_Threads_Manager_initialization(void)
OBJECTS_POSIX_THREADS, /* object class */
Configuration_POSIX_API.maximum_threads,
/* maximum objects of this class */
- sizeof( Thread_Control ),
- /* size of this object's control block */
+ _Thread_Control_size, /* size of this object's control block */
true, /* true if names for this object are strings */
_POSIX_PATH_MAX /* maximum length of each object's name */
#if defined(RTEMS_MULTIPROCESSING)
diff --git a/cpukit/rtems/include/rtems/rtems/tasks.h b/cpukit/rtems/include/rtems/rtems/tasks.h
index 263cc531d9..56dd12d7f0 100644
--- a/cpukit/rtems/include/rtems/rtems/tasks.h
+++ b/cpukit/rtems/include/rtems/rtems/tasks.h
@@ -574,7 +574,7 @@ typedef struct {
*
* @note MUST BE LAST ENTRY.
*/
- uint32_t Notepads[ RTEMS_NUMBER_NOTEPADS ];
+ uint32_t Notepads[ RTEMS_ZERO_LENGTH_ARRAY ];
} RTEMS_API_Control;
/**
diff --git a/cpukit/rtems/src/tasks.c b/cpukit/rtems/src/tasks.c
index 209a43cb07..f989fff580 100644
--- a/cpukit/rtems/src/tasks.c
+++ b/cpukit/rtems/src/tasks.c
@@ -50,23 +50,9 @@ static bool _RTEMS_tasks_Create_extension(
)
{
RTEMS_API_Control *api;
- int i;
- size_t to_allocate;
+ size_t i;
- /*
- * Notepads must be the last entry in the structure and they
- * can be left off if disabled in the configuration.
- */
- to_allocate = sizeof( RTEMS_API_Control );
- if ( !rtems_configuration_get_notepads_enabled() )
- to_allocate -= (RTEMS_NUMBER_NOTEPADS * sizeof(uint32_t));
-
- api = _Workspace_Allocate( to_allocate );
-
- if ( !api )
- return false;
-
- created->API_Extensions[ THREAD_API_RTEMS ] = api;
+ api = created->API_Extensions[ THREAD_API_RTEMS ];
_Event_Initialize( &api->Event );
_Event_Initialize( &api->System_event );
@@ -104,24 +90,6 @@ static void _RTEMS_tasks_Start_extension(
_Event_Initialize( &api->System_event );
}
-/*
- * _RTEMS_tasks_Delete_extension
- *
- * This extension routine is invoked when a task is deleted.
- */
-
-static void _RTEMS_tasks_Delete_extension(
- Thread_Control *executing,
- Thread_Control *deleted
-)
-{
- /*
- * Free API specific memory
- */
-
- (void) _Workspace_Free( deleted->API_Extensions[ THREAD_API_RTEMS ] );
-}
-
static void _RTEMS_tasks_Terminate_extension(
Thread_Control *executing
)
@@ -204,7 +172,7 @@ User_extensions_Control _RTEMS_tasks_User_extensions = {
{ _RTEMS_tasks_Create_extension, /* create */
_RTEMS_tasks_Start_extension, /* start */
_RTEMS_tasks_Start_extension, /* restart */
- _RTEMS_tasks_Delete_extension, /* delete */
+ NULL, /* delete */
RTEMS_TASKS_SWITCH_EXTENSION, /* switch */
NULL, /* begin */
NULL, /* exitted */
@@ -221,7 +189,7 @@ void _RTEMS_tasks_Manager_initialization(void)
OBJECTS_RTEMS_TASKS, /* object class */
Configuration_RTEMS_API.maximum_tasks,
/* maximum objects of this class */
- sizeof( Thread_Control ), /* size of this object's control block */
+ _Thread_Control_size, /* size of this object's control block */
false, /* true if the name is a string */
RTEMS_MAXIMUM_NAME_LENGTH /* maximum length of an object name */
#if defined(RTEMS_MULTIPROCESSING)
diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h
index 959514f850..e62e9175cd 100644
--- a/cpukit/sapi/include/confdefs.h
+++ b/cpukit/sapi/include/confdefs.h
@@ -641,7 +641,7 @@ const rtems_libio_helper rtems_fs_init_helper =
* CONFIGURE_SCHEDULER_USER and the following:
* - CONFIGURE_SCHEDULER_CONTEXT
* - CONFIGURE_SCHEDULER_CONTROLS
- * - CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER - per task memory
+ * - CONFIGURE_SCHEDULER_USER_PER_THREAD
*/
/* If no scheduler is specified, the priority scheduler is default. */
@@ -676,12 +676,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_SCHEDULER_CONTROLS \
RTEMS_SCHEDULER_CONTROL_PRIORITY(dflt)
#endif
-
- /**
- * This defines the memory used by the priority scheduler.
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER ( \
- _Configure_From_workspace(sizeof(Scheduler_priority_Per_thread)) )
#endif
/*
@@ -699,12 +693,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_SCHEDULER_CONTROLS \
RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(dflt)
#endif
-
- /**
- * This defines the memory used by the priority scheduler.
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER ( \
- _Configure_From_workspace(sizeof(Scheduler_priority_Per_thread)) )
#endif
/*
@@ -722,12 +710,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_SCHEDULER_CONTROLS \
RTEMS_SCHEDULER_CONTROL_PRIORITY_AFFINITY_SMP(dflt)
#endif
-
- /**
- * This defines the memory used by the priority scheduler.
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER ( \
- _Configure_From_workspace(sizeof(Scheduler_priority_Per_thread)) )
#endif
/*
@@ -739,11 +721,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_SCHEDULER_CONTROLS RTEMS_SCHEDULER_CONTROL_SIMPLE(dflt)
#endif
-
- /**
- * define the memory used by the simple scheduler
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER (0)
#endif
/*
@@ -757,13 +734,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_SCHEDULER_CONTROLS \
RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(dflt)
#endif
-
- /**
- * Define the memory used by the Simple SMP Scheduler
- *
- * NOTE: This is the same as the Simple Scheduler
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER (0)
#endif
/*
@@ -775,12 +745,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_SCHEDULER_CONTROLS RTEMS_SCHEDULER_CONTROL_EDF(dflt)
#endif
-
- /**
- * define the memory used by the EDF scheduler
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER ( \
- _Configure_From_workspace(sizeof(Scheduler_EDF_Per_thread)))
#endif
/*
@@ -804,12 +768,6 @@ const rtems_libio_helper rtems_fs_init_helper =
Scheduler_CBS_Server
_Scheduler_CBS_Server_list[ CONFIGURE_CBS_MAXIMUM_SERVERS ];
#endif
-
- /**
- * define the memory used by the CBS scheduler
- */
- #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER ( \
- _Configure_From_workspace(sizeof(Scheduler_CBS_Per_thread)))
#endif
/*
@@ -1596,15 +1554,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_NOTEPADS_ENABLED FALSE
#endif
- #ifndef CONFIGURE_DISABLE_CLASSIC_API_NOTEPADS
- #define CONFIGURE_MEMORY_PER_TASK_FOR_CLASSIC_API \
- _Configure_From_workspace( sizeof(RTEMS_API_Control) )
- #else
- #define CONFIGURE_MEMORY_PER_TASK_FOR_CLASSIC_API \
- _Configure_From_workspace( sizeof(RTEMS_API_Control) - \
- (RTEMS_NUMBER_NOTEPADS * sizeof(uint32_t)))
- #endif
-
/**
* This macro calculates the memory required for task variables.
*
@@ -1840,9 +1789,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_MAXIMUM_POSIX_THREADS 0
#endif
- #define CONFIGURE_MEMORY_PER_TASK_FOR_POSIX_API \
- _Configure_From_workspace(sizeof(POSIX_API_Control))
-
#ifndef CONFIGURE_MAXIMUM_POSIX_MUTEXES
#define CONFIGURE_MAXIMUM_POSIX_MUTEXES 0
#endif
@@ -1979,7 +1925,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#else
#define CONFIGURE_MAXIMUM_POSIX_THREADS 0
- #define CONFIGURE_MEMORY_PER_TASK_FOR_POSIX_API 0
#define CONFIGURE_MEMORY_FOR_POSIX 0
#endif /* RTEMS_POSIX_API */
@@ -2056,23 +2001,6 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_MAXIMUM_GO_CHANNELS 0
#endif
-#ifndef RTEMS_SCHEDSIM
-/**
- * This macro specifies the amount of memory to be reserved for the
- * Newlib C Library reentrancy structure -- if we are using newlib.
- */
-
-#if (defined(RTEMS_NEWLIB) && !defined(CONFIGURE_DISABLE_NEWLIB_REENTRANCY))
- #define CONFIGURE_MEMORY_PER_TASK_FOR_NEWLIB \
- _Configure_From_workspace(sizeof(struct _reent))
-#else
- #define CONFIGURE_MEMORY_PER_TASK_FOR_NEWLIB 0
-#endif
-
-#else
- #define CONFIGURE_MEMORY_PER_TASK_FOR_NEWLIB 0
-#endif
-
/**
* This is so we can account for tasks with stacks greater than minimum
* size. This is in bytes.
@@ -2104,17 +2032,7 @@ const rtems_libio_helper rtems_fs_init_helper =
#define CONFIGURE_MEMORY_FOR_TASKS(_tasks, _number_FP_tasks) \
( \
- _Configure_Object_RAM(_tasks, sizeof(Thread_Control)) \
- + _Configure_Max_Objects(_tasks) \
- * ( \
- CONFIGURE_MEMORY_PER_TASK_FOR_CLASSIC_API \
- + CONFIGURE_MEMORY_PER_TASK_FOR_NEWLIB \
- + CONFIGURE_MEMORY_PER_TASK_FOR_POSIX_API \
- + CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER \
- + _Configure_From_workspace( \
- (CONFIGURE_MAXIMUM_USER_EXTENSIONS + 1) * sizeof(void *) \
- ) \
- ) \
+ _Configure_Object_RAM(_tasks, sizeof(Configuration_Thread_control)) \
+ _Configure_Max_Objects(_number_FP_tasks) \
* _Configure_From_workspace(CONTEXT_FP_SIZE) \
* (CONTEXT_FP_SIZE != 0) \
@@ -2380,6 +2298,78 @@ const rtems_libio_helper rtems_fs_init_helper =
)
#ifdef CONFIGURE_INIT
+ typedef struct {
+ Thread_Control Control;
+ #if CONFIGURE_MAXIMUM_USER_EXTENSIONS > 0
+ void *extensions[ CONFIGURE_MAXIMUM_USER_EXTENSIONS + 1 ];
+ #endif
+ union {
+ #ifdef CONFIGURE_SCHEDULER_CBS
+ Scheduler_CBS_Per_thread CBS;
+ #endif
+ #ifdef CONFIGURE_SCHEDULER_EDF
+ Scheduler_EDF_Per_thread EDF;
+ #endif
+ #if defined(CONFIGURE_SCHEDULER_PRIORITY) \
+ || defined(CONFIGURE_SCHEDULER_PRIORITY_SMP)
+ Scheduler_priority_Per_thread Priority;
+ #endif
+ #ifdef CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP
+ Scheduler_priority_affinity_SMP_Per_thread Priority_affinity;
+ #endif
+ #ifdef CONFIGURE_SCHEDULER_USER_PER_THREAD
+ CONFIGURE_SCHEDULER_USER_PER_THREAD User;
+ #endif
+ } Scheduler;
+ RTEMS_API_Control API_RTEMS;
+ #ifndef CONFIGURE_DISABLE_CLASSIC_API_NOTEPADS
+ uint32_t Notepads[ RTEMS_NUMBER_NOTEPADS ];
+ #endif
+ #ifdef RTEMS_POSIX_API
+ POSIX_API_Control API_POSIX;
+ #endif
+ #if !defined(RTEMS_SCHEDSIM) \
+ && defined(RTEMS_NEWLIB) \
+ && !defined(CONFIGURE_DISABLE_NEWLIB_REENTRANCY)
+ struct _reent Newlib;
+ #else
+ struct { /* Empty */ } Newlib;
+ #endif
+ } Configuration_Thread_control;
+
+ const size_t _Thread_Control_size = sizeof( Configuration_Thread_control );
+
+ const Thread_Control_add_on _Thread_Control_add_ons[] = {
+ {
+ offsetof( Configuration_Thread_control, Control.scheduler_info ),
+ offsetof( Configuration_Thread_control, Scheduler )
+ }, {
+ offsetof(
+ Configuration_Thread_control,
+ Control.API_Extensions[ THREAD_API_RTEMS ]
+ ),
+ offsetof( Configuration_Thread_control, API_RTEMS )
+ }, {
+ offsetof(
+ Configuration_Thread_control,
+ Control.libc_reent
+ ),
+ offsetof( Configuration_Thread_control, Newlib )
+ }
+ #ifdef RTEMS_POSIX_API
+ , {
+ offsetof(
+ Configuration_Thread_control,
+ Control.API_Extensions[ THREAD_API_POSIX ]
+ ),
+ offsetof( Configuration_Thread_control, API_POSIX )
+ }
+ #endif
+ };
+
+ const size_t _Thread_Control_add_on_count =
+ RTEMS_ARRAY_SIZE( _Thread_Control_add_ons );
+
/**
* This is the Classic API Configuration Table.
*/
@@ -2572,7 +2562,6 @@ const rtems_libio_helper rtems_fs_init_helper =
uint32_t INTERRUPT_VECTOR_TABLE;
uint32_t INTERRUPT_STACK_MEMORY;
uint32_t MEMORY_FOR_IDLE_TASK;
- uint32_t MEMORY_PER_TASK_FOR_SCHEDULER;
/* Classic API Pieces */
uint32_t CLASSIC_TASKS;
@@ -2628,7 +2617,6 @@ const rtems_libio_helper rtems_fs_init_helper =
CONFIGURE_INTERRUPT_VECTOR_TABLE,
CONFIGURE_INTERRUPT_STACK_MEMORY,
CONFIGURE_MEMORY_FOR_IDLE_TASK,
- CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER,
/* Classic API Pieces */
CONFIGURE_MEMORY_FOR_TASKS(CONFIGURE_MAXIMUM_TASKS, 0),
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index 07cb52022b..4cd89d792a 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -203,12 +203,10 @@ libscore_a_SOURCES += src/schedulerdefaultupdate.c
## SCHEDULERPRIORITY_C_FILES
libscore_a_SOURCES += src/schedulerpriority.c \
- src/schedulerpriorityallocate.c \
src/schedulerpriorityblock.c \
src/schedulerpriorityenqueue.c \
src/schedulerpriorityenqueuefirst.c \
src/schedulerpriorityextract.c \
- src/schedulerpriorityfree.c \
src/schedulerpriorityprioritycompare.c \
src/schedulerpriorityschedule.c \
src/schedulerpriorityunblock.c \
@@ -234,7 +232,6 @@ libscore_a_SOURCES += src/scheduleredf.c \
src/scheduleredfenqueue.c \
src/scheduleredfenqueuefirst.c \
src/scheduleredfextract.c \
- src/scheduleredffree.c \
src/scheduleredfprioritycompare.c \
src/scheduleredfreleasejob.c \
src/scheduleredfschedule.c \
diff --git a/cpukit/score/include/rtems/score/scheduler.h b/cpukit/score/include/rtems/score/scheduler.h
index 931f008c06..d4e1339afb 100644
--- a/cpukit/score/include/rtems/score/scheduler.h
+++ b/cpukit/score/include/rtems/score/scheduler.h
@@ -67,7 +67,7 @@ typedef struct {
void ( *unblock )( const Scheduler_Control *, Thread_Control * );
/** allocates the scheduler field of the given thread */
- void * ( *allocate )( const Scheduler_Control *, Thread_Control * );
+ bool ( *allocate )( const Scheduler_Control *, Thread_Control * );
/** frees the scheduler field of the given thread */
void ( *free )( const Scheduler_Control *, Thread_Control * );
@@ -199,9 +199,9 @@ extern const Scheduler_Control _Scheduler_Table[];
* @param[in] scheduler Unused.
* @param[in] the_thread Unused.
*
- * @return An arbitrary non-NULL value.
+ * @retval true Always.
*/
-void *_Scheduler_default_Allocate(
+bool _Scheduler_default_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
);
diff --git a/cpukit/score/include/rtems/score/schedulercbs.h b/cpukit/score/include/rtems/score/schedulercbs.h
index 3abfdc5d99..e546c8d1e3 100644
--- a/cpukit/score/include/rtems/score/schedulercbs.h
+++ b/cpukit/score/include/rtems/score/schedulercbs.h
@@ -53,7 +53,7 @@ extern "C" {
_Scheduler_EDF_Block, /* block entry point */ \
_Scheduler_CBS_Unblock, /* unblock entry point */ \
_Scheduler_CBS_Allocate, /* allocate entry point */ \
- _Scheduler_EDF_Free, /* free entry point */ \
+ _Scheduler_default_Free, /* free entry point */ \
_Scheduler_EDF_Update, /* update entry point */ \
_Scheduler_EDF_Enqueue, /* enqueue entry point */ \
_Scheduler_EDF_Enqueue_first, /* enqueue_first entry point */ \
@@ -344,7 +344,7 @@ void _Scheduler_CBS_Budget_callout(
* @param[in] the_thread is the thread the scheduler is allocating
* management memory for.
*/
-void *_Scheduler_CBS_Allocate(
+bool _Scheduler_CBS_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
);
diff --git a/cpukit/score/include/rtems/score/scheduleredf.h b/cpukit/score/include/rtems/score/scheduleredf.h
index c6aba2dee2..fabce7e288 100644
--- a/cpukit/score/include/rtems/score/scheduleredf.h
+++ b/cpukit/score/include/rtems/score/scheduleredf.h
@@ -46,7 +46,7 @@ extern "C" {
_Scheduler_EDF_Block, /* block entry point */ \
_Scheduler_EDF_Unblock, /* unblock entry point */ \
_Scheduler_EDF_Allocate, /* allocate entry point */ \
- _Scheduler_EDF_Free, /* free entry point */ \
+ _Scheduler_default_Free, /* free entry point */ \
_Scheduler_EDF_Update, /* update entry point */ \
_Scheduler_EDF_Enqueue, /* enqueue entry point */ \
_Scheduler_EDF_Enqueue_first, /* enqueue_first entry point */ \
@@ -150,20 +150,7 @@ void _Scheduler_EDF_Schedule(
* @param[in] the_thread is the thread the scheduler is allocating
* management memory for.
*/
-void *_Scheduler_EDF_Allocate(
- const Scheduler_Control *scheduler,
- Thread_Control *the_thread
-);
-
-/**
- * @brief Frees EDF information of a thread.
- *
- * This routine frees the EDF specific information of @a the_thread.
- *
- * @param[in] the_thread is the thread whose scheduler specific information
- * will be deallocated.
- */
-void _Scheduler_EDF_Free(
+bool _Scheduler_EDF_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
);
diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h
index 25866e5ba7..5c787239d0 100644
--- a/cpukit/score/include/rtems/score/schedulerimpl.h
+++ b/cpukit/score/include/rtems/score/schedulerimpl.h
@@ -124,7 +124,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Unblock(
*
* This routine allocates @a the_thread->scheduler
*/
-RTEMS_INLINE_ROUTINE void* _Scheduler_Allocate(
+RTEMS_INLINE_ROUTINE bool _Scheduler_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
)
diff --git a/cpukit/score/include/rtems/score/schedulerpriority.h b/cpukit/score/include/rtems/score/schedulerpriority.h
index 7706bf32ce..b46c0fa29a 100644
--- a/cpukit/score/include/rtems/score/schedulerpriority.h
+++ b/cpukit/score/include/rtems/score/schedulerpriority.h
@@ -52,8 +52,8 @@ extern "C" {
_Scheduler_priority_Yield, /* yield entry point */ \
_Scheduler_priority_Block, /* block entry point */ \
_Scheduler_priority_Unblock, /* unblock entry point */ \
- _Scheduler_priority_Allocate, /* allocate entry point */ \
- _Scheduler_priority_Free, /* free entry point */ \
+ _Scheduler_default_Allocate, /* allocate entry point */ \
+ _Scheduler_default_Free, /* free entry point */ \
_Scheduler_priority_Update, /* update entry point */ \
_Scheduler_priority_Enqueue, /* enqueue entry point */ \
_Scheduler_priority_Enqueue_first, /* enqueue_first entry point */ \
@@ -126,32 +126,6 @@ void _Scheduler_priority_Schedule(
);
/**
- * @brief Allocates @a the_thread->scheduler.
- *
- * This routine allocates @a the_thread->scheduler.
- *
- * @param[in] the_thread is the thread the scheduler is allocating
- * management memory for
- */
-void * _Scheduler_priority_Allocate(
- const Scheduler_Control *scheduler,
- Thread_Control *the_thread
-);
-
-/**
- * @brief Frees @a the_thread->scheduler.
- *
- * This routine frees @a the_thread->scheduler.
- *
- * @param[in] the_thread is the thread whose scheduler specific information
- * will be deallocated.
- */
-void _Scheduler_priority_Free(
- const Scheduler_Control *scheduler,
- Thread_Control *the_thread
-);
-
-/**
* @brief Update the scheduler priority.
* This routine updates @a the_thread->scheduler based on @a the_scheduler
* structures and thread state.
diff --git a/cpukit/score/include/rtems/score/schedulerpriorityaffinitysmp.h b/cpukit/score/include/rtems/score/schedulerpriorityaffinitysmp.h
index 54fca12bf0..4f31722eb1 100644
--- a/cpukit/score/include/rtems/score/schedulerpriorityaffinitysmp.h
+++ b/cpukit/score/include/rtems/score/schedulerpriorityaffinitysmp.h
@@ -55,7 +55,7 @@ extern "C" {
_Scheduler_priority_SMP_Block, \
_Scheduler_priority_SMP_Enqueue_fifo, \
_Scheduler_priority_affinity_SMP_Allocate, \
- _Scheduler_priority_Free, \
+ _Scheduler_default_Free, \
_Scheduler_priority_SMP_Update, \
_Scheduler_priority_SMP_Enqueue_fifo, \
_Scheduler_priority_SMP_Enqueue_lifo, \
@@ -77,7 +77,7 @@ extern "C" {
* @param[in] the_thread is the thread the scheduler is allocating
* management memory for.
*/
-void * _Scheduler_priority_affinity_SMP_Allocate(
+bool _Scheduler_priority_affinity_SMP_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
);
diff --git a/cpukit/score/include/rtems/score/schedulerprioritysmp.h b/cpukit/score/include/rtems/score/schedulerprioritysmp.h
index df8af184e3..8506623c8f 100644
--- a/cpukit/score/include/rtems/score/schedulerprioritysmp.h
+++ b/cpukit/score/include/rtems/score/schedulerprioritysmp.h
@@ -63,8 +63,8 @@ typedef struct {
_Scheduler_priority_SMP_Yield, \
_Scheduler_priority_SMP_Block, \
_Scheduler_priority_SMP_Enqueue_fifo, \
- _Scheduler_priority_Allocate, \
- _Scheduler_priority_Free, \
+ _Scheduler_default_Allocate, \
+ _Scheduler_default_Free, \
_Scheduler_priority_SMP_Update, \
_Scheduler_priority_SMP_Enqueue_fifo, \
_Scheduler_priority_SMP_Enqueue_lifo, \
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index 2765f56286..77e105bf28 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -566,8 +566,6 @@ struct Thread_Control_struct {
struct _reent *libc_reent;
/** This array contains the API extension area pointers. */
void *API_Extensions[ THREAD_API_LAST + 1 ];
- /** This field points to the user extension pointers. */
- void **extensions;
#if !defined(RTEMS_SMP)
/** This field points to the set of per task variables. */
@@ -584,6 +582,13 @@ struct Thread_Control_struct {
Chain_Control Key_Chain;
Thread_Life_control Life;
+
+ /**
+ * @brief Variable length array of user extension pointers.
+ *
+ * The length is defined by the application via <rtems/confdefs.h>.
+ */
+ void *extensions[ RTEMS_ZERO_LENGTH_ARRAY ];
};
#if (CPU_PROVIDES_IDLE_THREAD_BODY == FALSE)
@@ -638,6 +643,57 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Get_executing( void )
return executing;
}
+/**
+ * @brief Thread control add-on.
+ */
+typedef struct {
+ /**
+ * @brief Offset of the pointer field in Thread_Control referencing an
+ * application configuration dependent memory area in the thread control
+ * block.
+ */
+ size_t destination_offset;
+
+ /**
+ * @brief Offset relative to the thread control block begin to an application
+ * configuration dependent memory area.
+ */
+ size_t source_offset;
+} Thread_Control_add_on;
+
+/**
+ * @brief Thread control add-ons.
+ *
+ * The thread control block contains fields that point to application
+ * configuration dependent memory areas, like the scheduler information, the
+ * API control blocks, the user extension context table, the RTEMS notepads and
+ * the Newlib re-entrancy support. Account for these areas in the
+ * configuration and avoid extra workspace allocations for these areas.
+ *
+ * This array is provided via <rtems/confdefs.h>.
+ *
+ * @see _Thread_Control_add_on_count and _Thread_Control_size.
+ */
+extern const Thread_Control_add_on _Thread_Control_add_ons[];
+
+/**
+ * @brief Thread control add-on count.
+ *
+ * Count of entries in _Thread_Control_add_ons.
+ *
+ * This value is provided via <rtems/confdefs.h>.
+ */
+extern const size_t _Thread_Control_add_on_count;
+
+/**
+ * @brief Size of the thread control block of a particular application.
+ *
+ * This value is provided via <rtems/confdefs.h>.
+ *
+ * @see _Thread_Control_add_ons.
+ */
+extern const size_t _Thread_Control_size;
+
/**@}*/
#ifdef __cplusplus
diff --git a/cpukit/score/src/schedulercbsallocate.c b/cpukit/score/src/schedulercbsallocate.c
index 1190b84254..a6f89c35a9 100644
--- a/cpukit/score/src/schedulercbsallocate.c
+++ b/cpukit/score/src/schedulercbsallocate.c
@@ -25,24 +25,18 @@
#include <rtems/score/schedulercbs.h>
#include <rtems/score/wkspace.h>
-void *_Scheduler_CBS_Allocate(
+bool _Scheduler_CBS_Allocate(
const Scheduler_Control *scheduler,
- Thread_Control *the_thread
+ Thread_Control *the_thread
)
{
- void *sched;
- Scheduler_CBS_Per_thread *schinfo;
+ Scheduler_CBS_Per_thread *schinfo = the_thread->scheduler_info;
(void) scheduler;
- sched = _Workspace_Allocate(sizeof(Scheduler_CBS_Per_thread));
- if ( sched ) {
- the_thread->scheduler_info = sched;
- schinfo = (Scheduler_CBS_Per_thread *)(the_thread->scheduler_info);
- schinfo->edf_per_thread.thread = the_thread;
- schinfo->edf_per_thread.queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
- schinfo->cbs_server = NULL;
- }
+ schinfo->edf_per_thread.thread = the_thread;
+ schinfo->edf_per_thread.queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
+ schinfo->cbs_server = NULL;
- return sched;
+ return true;
}
diff --git a/cpukit/score/src/schedulerdefaultallocatefree.c b/cpukit/score/src/schedulerdefaultallocatefree.c
index 4efed5bad8..c865385dfb 100644
--- a/cpukit/score/src/schedulerdefaultallocatefree.c
+++ b/cpukit/score/src/schedulerdefaultallocatefree.c
@@ -21,7 +21,7 @@
#include <rtems/score/scheduler.h>
-void *_Scheduler_default_Allocate(
+bool _Scheduler_default_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
)
@@ -29,7 +29,7 @@ void *_Scheduler_default_Allocate(
( void ) scheduler;
( void ) the_thread;
- return ( void * )-1; /* maybe pick an appropriate poison value */
+ return true;
}
void _Scheduler_default_Free(
diff --git a/cpukit/score/src/scheduleredfallocate.c b/cpukit/score/src/scheduleredfallocate.c
index 68ae12450c..3dc9dd5070 100644
--- a/cpukit/score/src/scheduleredfallocate.c
+++ b/cpukit/score/src/scheduleredfallocate.c
@@ -24,24 +24,18 @@
#include <rtems/score/scheduleredf.h>
#include <rtems/score/wkspace.h>
-void *_Scheduler_EDF_Allocate(
+bool _Scheduler_EDF_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
)
{
- void *sched;
- Scheduler_EDF_Per_thread *schinfo;
+ Scheduler_EDF_Per_thread *schinfo = the_thread->scheduler_info;
(void) scheduler;
- sched = _Workspace_Allocate( sizeof(Scheduler_EDF_Per_thread) );
+ schinfo = (Scheduler_EDF_Per_thread *)(the_thread->scheduler_info);
+ schinfo->thread = the_thread;
+ schinfo->queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
- if ( sched ) {
- the_thread->scheduler_info = sched;
- schinfo = (Scheduler_EDF_Per_thread *)(the_thread->scheduler_info);
- schinfo->thread = the_thread;
- schinfo->queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
- }
-
- return sched;
+ return true;
}
diff --git a/cpukit/score/src/scheduleredffree.c b/cpukit/score/src/scheduleredffree.c
deleted file mode 100644
index 3529ac9c41..0000000000
--- a/cpukit/score/src/scheduleredffree.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @file
- *
- * @brief Frees EDF Thread Information
- *
- * @ingroup ScoreScheduler
- */
-
-/*
- * Copyright (C) 2011 Petr Benes.
- * Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
- *
- * 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/system.h>
-#include <rtems/config.h>
-#include <rtems/score/scheduler.h>
-#include <rtems/score/scheduleredf.h>
-#include <rtems/score/wkspace.h>
-
-void _Scheduler_EDF_Free(
- const Scheduler_Control *scheduler,
- Thread_Control *the_thread
-)
-{
- (void) scheduler;
-
- _Workspace_Free( the_thread->scheduler_info );
-}
diff --git a/cpukit/score/src/schedulerpriorityaffinitysmp.c b/cpukit/score/src/schedulerpriorityaffinitysmp.c
index 2ab12b4824..0ea4336321 100644
--- a/cpukit/score/src/schedulerpriorityaffinitysmp.c
+++ b/cpukit/score/src/schedulerpriorityaffinitysmp.c
@@ -31,20 +31,18 @@ _Scheduler_priority_affinity_Get_scheduler_info( Thread_Control *thread )
return ( Scheduler_priority_affinity_SMP_Per_thread * ) thread->scheduler_info;
}
-void * _Scheduler_priority_affinity_SMP_Allocate(
+bool _Scheduler_priority_affinity_SMP_Allocate(
const Scheduler_Control *scheduler,
Thread_Control *the_thread
)
{
Scheduler_priority_affinity_SMP_Per_thread *info =
- _Workspace_Allocate( sizeof( *info ) );
+ the_thread->scheduler_info;
info->Affinity = *_CPU_set_Default();
info->Affinity.set = &info->Affinity.preallocated;
-
- the_thread->scheduler_info = info;
- return info;
+ return true;
}
bool _Scheduler_priority_affinity_SMP_Get_affinity(
diff --git a/cpukit/score/src/schedulerpriorityallocate.c b/cpukit/score/src/schedulerpriorityallocate.c
deleted file mode 100644
index 32feabb97b..0000000000
--- a/cpukit/score/src/schedulerpriorityallocate.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @file
- *
- * @brief Allocate Scheduler Priority
- * @ingroup ScoreScheduler
- */
-
-/*
- * Copyright (C) 2010 Gedare Bloom.
- * Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
- *
- * 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/schedulerpriority.h>
-#include <rtems/score/thread.h>
-#include <rtems/score/wkspace.h>
-
-void *_Scheduler_priority_Allocate (
- const Scheduler_Control *scheduler,
- Thread_Control *the_thread
-)
-{
- Scheduler_priority_Per_thread *sched_info_of_thread =
- _Workspace_Allocate( sizeof( *sched_info_of_thread ) );
-
- (void) scheduler;
-
- the_thread->scheduler_info = sched_info_of_thread;
-
- return sched_info_of_thread;
-}
diff --git a/cpukit/score/src/schedulerpriorityfree.c b/cpukit/score/src/schedulerpriorityfree.c
deleted file mode 100644
index b2daa26493..0000000000
--- a/cpukit/score/src/schedulerpriorityfree.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file
- *
- * @brief Free Scheduler Priority
- * @ingroup ScoreScheduler
- */
-
-/*
- * Copyright (C) 2010 Gedare Bloom.
- * Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
- *
- * 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/system.h>
-#include <rtems/config.h>
-#include <rtems/score/scheduler.h>
-#include <rtems/score/schedulerpriority.h>
-#include <rtems/score/wkspace.h>
-
-void _Scheduler_priority_Free (
- const Scheduler_Control *scheduler,
- Thread_Control *the_thread
-)
-{
- (void) scheduler;
-
- _Workspace_Free( the_thread->scheduler_info );
-}
diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c
index a77fe5fa8c..226e63af1a 100644
--- a/cpukit/score/src/thread.c
+++ b/cpukit/score/src/thread.c
@@ -64,8 +64,7 @@ void _Thread_Handler_initialization(void)
OBJECTS_INTERNAL_API,
OBJECTS_INTERNAL_THREADS,
_Thread_Get_maximum_internal_threads(),
- sizeof( Thread_Control ),
- /* size of this object's control block */
+ _Thread_Control_size, /* size of this object's control block */
false, /* true if names for this object are strings */
8 /* maximum length of each object's name */
#if defined(RTEMS_MULTIPROCESSING)
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index 6864df58e9..153c1d0b13 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -42,15 +42,15 @@ bool _Thread_Initialize(
Objects_Name name
)
{
- size_t actual_stack_size = 0;
- void *stack = NULL;
+ size_t actual_stack_size = 0;
+ void *stack = NULL;
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
- void *fp_area;
+ void *fp_area = NULL;
#endif
- void *sched = NULL;
- void *extensions_area;
- bool extension_status;
- int i;
+ bool extension_status;
+ size_t i;
+ bool scheduler_allocated = false;
+ const Scheduler_Control *scheduler;
/*
* Do not use _TLS_Size here since this will lead GCC to assume that this
@@ -64,6 +64,13 @@ bool _Thread_Initialize(
}
#endif
+ for ( i = 0 ; i < _Thread_Control_add_on_count ; ++i ) {
+ const Thread_Control_add_on *add_on = &_Thread_Control_add_ons[ i ];
+
+ *(void **) ( (char *) the_thread + add_on->destination_offset ) =
+ (char *) the_thread + add_on->source_offset;
+ }
+
/*
* Initialize the Ada self pointer
*/
@@ -71,20 +78,8 @@ bool _Thread_Initialize(
the_thread->rtems_ada_self = NULL;
#endif
- /*
- * Zero out all the allocated memory fields
- */
- for ( i=0 ; i <= THREAD_API_LAST ; i++ )
- the_thread->API_Extensions[i] = NULL;
-
- extensions_area = NULL;
- the_thread->libc_reent = NULL;
the_thread->Start.tls_area = NULL;
- #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
- fp_area = NULL;
- #endif
-
/*
* Allocate and Initialize the stack for this thread.
*/
@@ -153,18 +148,6 @@ bool _Thread_Initialize(
#endif
/*
- * Allocate the extensions area for this thread
- */
- if ( rtems_configuration_get_maximum_extensions() ) {
- extensions_area = _Workspace_Allocate(
- (rtems_configuration_get_maximum_extensions() + 1) * sizeof( void * )
- );
- if ( !extensions_area )
- goto failed;
- }
- the_thread->extensions = (void **) extensions_area;
-
- /*
* Clear the extensions area so extension users can determine
* if they are linked to the thread. An extension user may
* create the extension long after tasks have been created
@@ -215,9 +198,13 @@ bool _Thread_Initialize(
the_thread->resource_count = 0;
the_thread->real_priority = priority;
the_thread->Start.initial_priority = priority;
- sched =_Scheduler_Allocate( _Scheduler_Get( the_thread ), the_thread );
- if ( !sched )
+
+ scheduler = _Scheduler_Get( _Thread_Get_executing() );
+ scheduler_allocated = _Scheduler_Allocate( scheduler, the_thread );
+ if ( !scheduler_allocated ) {
goto failed;
+ }
+
_Thread_Set_priority( the_thread, priority );
/*
@@ -260,21 +247,17 @@ bool _Thread_Initialize(
return true;
failed:
- _Workspace_Free( the_thread->Start.tls_area );
-
- _Workspace_Free( the_thread->libc_reent );
- for ( i=0 ; i <= THREAD_API_LAST ; i++ )
- _Workspace_Free( the_thread->API_Extensions[i] );
+ if ( scheduler_allocated ) {
+ _Scheduler_Free( scheduler, the_thread );
+ }
- _Workspace_Free( extensions_area );
+ _Workspace_Free( the_thread->Start.tls_area );
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
_Workspace_Free( fp_area );
#endif
- _Workspace_Free( sched );
-
_Thread_Stack_Free( the_thread );
return false;
}
diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c
index 47c27929dd..422ee33a6d 100644
--- a/cpukit/score/src/threadrestart.c
+++ b/cpukit/score/src/threadrestart.c
@@ -91,8 +91,6 @@ static void _Thread_Free( Thread_Control *the_thread )
*/
_Thread_Stack_Free( the_thread );
- _Workspace_Free( the_thread->extensions );
-
_Workspace_Free( the_thread->Start.tls_area );
_Objects_Free(