#include <nitro/os.h>
void OS_SetThreadDestructorStack( void* stack );
stack | The starting address of the stack pointer. Items are put onto the stack from the top, so be aware that the highest address of the stack must be specified. The address assigned must have a 4-byte alignment. |
None.
This function specifies the stack that will execute the destructor for all threads.
The value stack is assigned as a stack pointer immediately before destructor executes. This operation is not carried out (same as default) if NULL is specified. Note that the value passed as the stack is the highest address (+1) of the region.
A detailed description is given below.
If a thread is destroyed by another thread with OS_KillThread*()
and the destructor is executed, to accurately predict the amount of the stack used by the destroyed thread is difficult. If the stack is used continuously, a large amount of the stack is being used; therefore, there may not be enough room on the stack to execute the destructor function that destroys the thread.
To avoid this in the OSThread system, the following operations can be used to deal with stacks where one thread has been destroyed by another thread:
Specifying NULL for this function will cause the stack pointer to return to its initial value immediately before the destructor executes. This is also the default operation. Specifying a stack other than NULL will cause the specified stack to be used while the destructor executes. Note that because more than one destructor cannot execute at once, there are no problems specifying a common stack area for all threads and allowing multiple destructors to use the area.
Compared to the default operation, preparing seperate destructor stacks in some situations may reduce the amount of memory consumed. For instance, if the thread that normally uses only 100 bytes needs 1000 bytes for the destructor, 1000 bytes on the stack must be prepared in advance for the default operation. If there is more than one thread, the same is true for each separate thread. However, if a destructor stack of 1000 bytes is specified, a stack for normal processes require only 100 bytes.
In addition, if another stack is prepared, the thread being destroyed will not break down local variables of the function that is currenlty executing. For instance, all alarms are connected by a list in the case of OSAlarm. If you want to cancel a locally created instance of OSAlarm using a destructor, the stack region must remain until the destructor is used.
Note that if its own thread is specified with OS_KillThread*()
, the default operation of resetting the stack pointer will not execute. This is because the stack usage status when its own thread is being terminated is easy to guess. However, even in this case, if a destructor stack other than NULL is given for this function, using that destructor stack is the same for all cases.
Example of when another stack must be prepared
In the following program, after 10 seconds, a thread displays "10 seconds passed." and that thread is created inside main()
. The OSAlarm system is used to time 10 seconds. If the thread is destroyed before 10 seconds elapse, the thread destructor will attempt to delete the alarm. However, the thread exists in the thread stack because the alarm structure body is a local variable. Given this situation, the original stack must be prevented from being destroyed when the destructor is called. For this, a thread that executes the destructor is specified with OS_SetThreadDestructorstack()
immediately after OS_InitThread()
. (Some parts of the source code, such as declarations, have been simplified or omitted.)
OSAlarm* myAlarm = NULL;
u32 stack[ STACKSIZE ] ATTRIBUTE_ALIGN(32);
main()
{
:
OS_InitThread();
OS_SetThreadDestructorStack( &stack[STACKSIZE] );
:
OSThread thread;
OS_CreateThread( &thread, function, E); // Create thread
OS_SetThreadDestructor( &thread, dtor ); // Set destructor
OS_WakeupThreadDirect( thread ); // Wakeup thread
:
F
OS_KillThread( &thread ); // Destroy thread
:
}
function()
{
OSAlarm alarm; // alarm is a local variable
myAlarm = &alarm;
OS_SetAlarm( &alarm, OSSecondsToTicks( 10 ), handler, E); // handler is called after 10 seconds
:
}
handler()
{
OS_Printf( "10 seconds passed.\n" ); // Displays that 10 seconds have elapsed
myAlarm = NULL;
}
dtor()
{
:
if ( myAlarm != NULL )
{
OS_CancelAlarm( myAlarm ); // Cancel the alarm
}
:
}
OS_InitThread, OS_KillThread, OS_SetThreadDestructor
08/08/2005 Initial version.