#include <nitro/os.h>
void OS_SetThreadDestructorStack( void* stack );
stack | 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 must be 4-byte aligned. |
None.
Specifies the stack that will be used to execute the destructor for all threads.
The value of the stack argument is substituted for a stack pointer immediately before the destructor executes. If NULL
is specified, this operation is not carried out (this is the default behavior). Note that the value passed is the (highest address +1) of the region.
A detailed description is given below.
If a thread is destroyed by another thread with the OS_KillThread*
function and the destructor is executed, during the operation it is difficult to accurately predict the amount of the stack consumed (or left unconsumed) by the destroyed thread. If the system continues using the stack after this operation, it is possible that occasionally a thread that is consuming a large amount of the stack will be destroyed and there will not be enough room left on the stack to execute the destructor.
To avoid this situation, in the OSThread
system you can use either of the following methods to deal with stacks where one thread has been destroyed by another thread.
Specifying NULL
for this function causes the stack pointer to return to its initial value (the value it had when the stack was created) immediately before the destructor executes. This is also the default operation. Specifying a non-NULL
value indicates that a separate stack will be used when the destructor executes. Note that because more than one destructor cannot execute at once, you can specify a single common stack area for all threads and pass this value to multiple destructors.
In some situations, preparing a separate stack for the destructor may reduce the amount of memory consumed compared to the default behavior. For example, if a thread that normally uses only 100 bytes needs a 1000-byte stack for the destructor, the default operation requires advance preparation of 1000 bytes on the stack. If there is more than one thread, the same is true for each separate thread. However, if you specify a separate 1000-byte destructor stack, the size of the stacks used for normal processes can be 100 bytes.
In addition, if a separate stack is prepared, the thread being destroyed will not corrupt the local variables of the function that is currently executing. For example, all OSAlarm
alarms are connected by a list. If you want to cancel a locally created instance of OSAlarm
using a destructor, you must maintain the stack region until the destructor is used.
Note that if a thread specifies itself with the OS_KillThread*
function, the default operation of resetting the stack pointer will not occur. This is because the amount of stack being used by a thread is easy to predict when a thread declares that it will terminate itself. However, if a non-NULL
destructor stack is given to this function, that stack will be used for the destructor in all cases.
Example of Preparing a Separate Stack
In the following program, a thread is created inside main()
that waits 10 seconds after it is created and then displays "10 seconds passed." It uses the OSAlarm
system to count the 10 seconds. If the thread is destroyed before 10 seconds elapse, the thread destructor attempts to delete the alarm. However, the alarm structure instance is a local variable, so it exists in the thread stack. Given this situation, the original stack must be prevented from being destroyed when the destructor is called. To do this, the 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, ...); // Create thread OS_SetThreadDestructor( &thread, dtor ); // Set destructor OS_WakeupThreadDirect( thread ); // Wakeup thread : : OS_KillThread( &thread ); // Destroy thread : } function() { OSAlarm alarm; // alarm is a local variable myAlarm = &alarm; OS_SetAlarm( &alarm, OSSecondsToTicks( 10 ), handler, ...); // 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
2005/08/08 Initial version.
CONFIDENTIAL