rwilder wrote on Thursday, April 14, 2011:
Here are a few more details.
I’m using Atmel’s AVR32 Studio version 2.6.0 (eclipse-based IDE) which comes with
gcc compiler version 4.3.2 (atmel-1.2.0-(mingw32_special)), Atmel provides
a software framework including a port of FreeRTOS V6.0.0.
The test code below simply creates two instances of a thread. If thread-local
storage works as anticipated, then the loop would not hit the breakpoint.
I find that it always breaks, and that the pointer psTlsThreadParms refers to
the same address regardless of which instance is running.
Any ideas ???
//--------------------------------------------------
// start of file
//--------------------------------------------------
// TlsTest.c
// Test of thread-local storage using FreeRTOS on Atmel AVR32
// Richard Wilder - GrayBox Technologies LLC
//
#include “FreeRTOS.h”
#include “task.h”
#define TLSTEST_STACK_SIZE ( configMINIMAL_STACK_SIZE + 192 )
#define TLSTEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
void vTlsTestTask_init(void);
static portTASK_FUNCTION_PROTO( vTlsTestTask, pvParameters );
// Here we define a structure to hold thread data
typedef struct tag_STlsTestParameters
{
int iInstance;
int iCounter;
struct tag_STlsTestParameters* pSelf;
} STlsTestParameters;
// Here we make two instances
STlsTestParameters g_sThread1Parms;
STlsTestParameters g_sThread2Parms;
// Here we declare another instance using thread-local storage
__thread STlsTestParameters gTLS_sThreadParms;
//--------------------------------------------------
// vTlsTestTask_init()
//--------------------------------------------------
// This is the public API that you call from main()
void vTlsTestTask_init(void)
{
// initialize the first instance of parameter structure
g_sThread1Parms.iInstance = 1;
g_sThread1Parms.iCounter = 0;
g_sThread1Parms.pSelf = &g_sThread1Parms;
// initialize the second instance of parameter structure
g_sThread2Parms.iInstance = 2;
g_sThread2Parms.iCounter = 0;
g_sThread2Parms.pSelf = &g_sThread2Parms;
// launch the first instance of the thread
xTaskCreate( vTlsTestTask,
( const signed portCHAR * )“TlsTest1”,
TLSTEST_STACK_SIZE,
&g_sThread1Parms,
TLSTEST_TASK_PRIORITY,
( xTaskHandle * )NULL );
// launch the second instance of the thread
xTaskCreate( vTlsTestTask,
( const signed portCHAR * )“TlsTest2”,
TLSTEST_STACK_SIZE,
&g_sThread2Parms,
TLSTEST_TASK_PRIORITY,
( xTaskHandle * )NULL );
}
//--------------------------------------------------
// vTlsTestTask()
//--------------------------------------------------
// This is the thread/task function
static portTASK_FUNCTION( vTlsTestTask, pvParameters )
{
int iInstance;
int iCounter;
int iTlsCounter;
// cast our void-pointer argument back to our structure-pointer
STlsTestParameters* psThreadParms = (STlsTestParameters*) pvParameters;
// make a local copy (for viewing in debugger)
iInstance = psThreadParms->iInstance;
// take a snapshot of the TLS instance address (for viewing in debugger)
STlsTestParameters* psTlsThreadParms = &gTLS_sThreadParms;
// initialize the thread-local instance of the structure
gTLS_sThreadParms.iInstance = psThreadParms->iInstance;
gTLS_sThreadParms.iCounter = psThreadParms->iCounter;
gTLS_sThreadParms.pSelf = psTlsThreadParms;
// main loop
for(;
{
// make some changes
iTlsCounter = ++gTLS_sThreadParms.iCounter;
iCounter = ++psThreadParms->iCounter;
// if there is truly a thread-local instance of gTLS_sThreadParms
// then the counter values should always be equal
if (iTlsCounter != iCounter)
{
// >>> SET DEBUGGER BREAKPOINT HERE <<<
iCounter = iTlsCounter = 0;
}
// sleep an odd number of ticks to keep the two threads out-of-sync
vTaskDelay(47 + iInstance);
}
}
//--------------------------------------------------
// end of file
//--------------------------------------------------