# OS_SetThreadDestructorStack

## Syntax

      #include <nitro/os.h>

      void OS_SetThreadDestructorStack( void* stack );

## Arguments

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.

## Return Values

None.

## Description

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.

- Immediately before executing the destructor, return the stack pointer to its initial value when the stack was created (default behavior).
- Use another stack when executing the destructor.

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
>       }
>     	:
>     }

## See Also

`OS_InitThread`
`OS_KillThread`
`OS_SetThreadDestructor`

## Revision History

2005/08/08 Initial version.

CONFIDENTIAL