Menu

#85 Lightweight custom extend tskControlBlock

open
nobody
None
5
2015-01-28
2014-10-08
ilgitano
No

Working on an MSP430, I would like to be able to backup/restore the state of a few onchip modules over a task switch, most notably the CRC module and the hardware multiply module. (Though I understand it may not be possible to back up and restore the MPY module state completely)

I know pxTaskTag can be used to extend the task control block, but support has to be provided to locate/allocate/deallocate the memory used.

Can we instead embed a custom structure, which would be defined in FreeRTOSconfig.h? Then the existing task control block routines would do all the work automatically. Some API functions would be needed:

TaskControlBlockExtensionInit - when the task control block is created
TaskControlBlockExtensionSwitchOut - on suspending a task
TaskControlBlockExtensionSwitchIn - on resuming a task
TaskControlBlockExtensionDeinit - when a task is deleted

These would initialise/remove and switch out/in the module states.

This would provide a low cost means to manage oddball tcb extensions at a very low development cost.

Discussion

  • ilgitano

    ilgitano - 2014-10-11

    The idea is that the a user defined structure, defined in FreeRTOS, would have an instance as part of the tskTCB definition used in tasks.c, and some API functions called at creation/destruction and when switching tasks. Then things like the CRC and MPY module on the MSP430 could be used in a thread safe way.

    Currently I am using this hack:

    #define  traceTASK_SWITCHED_OUT()   (pxCurrentTCB->uxTaskNumber = CRCINIRES)
    #define  traceTASK_SWITCHED_IN()    (CRCINIRES = pxCurrentTCB->uxTaskNumber)
    

    to make the hardware CRC thread safe. Not the best, but certainly low-cost.

    The IAR compile uses dint/eint arround uses of the hardware MPY to make it safe, and would need 18 bytes to preserve/restore it. Almost certainly not worth it.

     
  • Arnab Bhaduri

    Arnab Bhaduri - 2014-11-13

    Hello, I'd like to make the same request. Cadence(Tensilica) is porting FreeRTOS to the Xtensa architecture, and we need a field in the TCB that we can use to point to extra storage for coprocessor state etc. What is described above will work for us, but at the minimum all we need is a pointer field. Since this field will need to be accessible from assembly, ideally it needs to stay at a fixed offset from the beginning of the TCB struct. i.e. its offset should not change if other conditional fields are added/removed from the struct.

    Please consider implementing this in your next release. Thanks.

     
  • ilgitano

    ilgitano - 2014-11-15

    I think configUSE_NEWLIB_REENTRANT could be generalised to do this or reimplemented using a more general mechanism that supports the desired functionality. It seems that what NEWLIB support requires is a particular example of what we're requesting.

    It should be possible to hijack the NEWLIB_REENTRANT mechanism for our purposes, in combination with vApplicationTickHook.

    That is:
    1. Define your own struct _reent, _impure_ptr and _REENT_INIT_PTR macro in FreeRTOSConfig.h
    2. In vAppicationTickHook, if _impure_ptr changes, save the current [coprocessor] states to the previous _impure_ptr, and restore from the new _impure_ptr.

    _impure_ptr would not need to be declared volatile since in any given thread it would be appear to be constant. vApplicationTickHook is called from interrupt or in a critical section always, so it won't change unexpectedly there either.

     

    Last edit: ilgitano 2014-11-15
  • Richard Barry

    Richard Barry - 2014-12-27

    I'm still not sure about this - why can this not be done with the task tag? If you set the task tag to a function pointer, then call xTaskCallApplicationTaskHook() from the tick hook to do whatever you want. Alternatively set the task tag to a pointer, then use xTaskGetApplicationTaskTag() to obtain the tag (the pointer) for whichever task?

    If you used the traceTASK_SWITCH_OUT/IN macro you would not even need to use the API functions as you can access the tag value from the TCB directly (pxCurrentTCB pointing to the TCB of the task switched our/in).

     
  • ilgitano

    ilgitano - 2014-12-30

    Yes it can be done with task tag - roughly what I did to back up the CRC hardware register for our MSP430 code. The issue is that sometimes you have only a very small amount of data (the CRC registers current contents is 16 bits) and don't want to pay the price of memory allocation/deallocation to put it somewhere else, or all the function call overheads to find out where it is and get it and set the hardware up.

    If we could have a user allocated piece of the TCB, then all work of allocation is already done (it's in the TCB) and finding it is trivial - no pointer derefs, check for NULL etc. No overhead at all.

    Just something like an embedded structure defined in FreeRTOS.h Anything more complicated makes it almost not worth preserving the CRC context. We seriously considered giving up on the onchip CRC module and using a SW implementation for this reason.

     
  • Richard Barry

    Richard Barry - 2015-01-26

    The head revision in SVN now contains a user configurable extension to the TCB.

    The TCB contains the following array:

    void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];

    ...and the two following functions have been added:

    / xTaskToSet is the task the TLS item is being set in, use NULL to set the calling task's TLS value. xIndex is the index into the pvThreadLocalStoragePointers array the value will be stored in, and pvValue is the value to store. /
    void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue );

    / xTaskToQuery is the task the TLS item is being read from, use NULL to query a TLS item from the calling task. xIndex is the index into the pvThreadLocalStoragePointers array the item is being read from. /
    void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex );

    You can test to see if a task has a TLS item, and if NULL is returned create an item and store it in the task. Note however that deleting the task will not automatically delete any memory allocated to the task through the TLS mechanism.

    Does this go any way to meeting you needs?

     
  • Rabih Chrabieh

    Rabih Chrabieh - 2015-01-26

    Hi,

    The Thread Local Storage pointers above can help. However, it does not seem the most efficient solution since accessing each pointer requires a function call. And it would be complicated to access from Assembly code.

    For the Cadence (Tensilica) port, we used a hack where we overloaded xMPUSettings at the beginning of the TCB. We redefined this structure as a general purpose structure that contains several parameters and local storage for the TCB.

    As mentioned when this thread was created, a custom structure inserted at the beginning of the TCB can be very useful. The custom structure could be defined in portmacro.h (rather than FreeRTOSConfig.h) and would contain all necessary parameters specific to the port. Easily accessible from Assembly code by adding a constant offset to pcCurrentTCB, and from C code ideally via an efficient inline function or macro.

    Best regards.

     
  • ilgitano

    ilgitano - 2015-01-28

    Too high level. We are trying to avoid the overheads in dynamic allocations, which an array of pointers requires. Each of those pointers has to be allocated, possibly deallocated and dereferenced in using them, and all the function call wrappers to do that.

    For something as small as the MSP430, all I need is a word of storage, which could be very efficiently included into the TCB itself. For one word, I don't want to have to reference/dereference a pointer, and all the headache of allocating/deallocating such a thing.

    Using the above, I would just cast one of those tags to the actual CRC content itself, which I suppose is neater than what I have.

    Could we not have something like:

    #if THREAD_LOCAL_STATE_PRESENT
        ThreadLocalState_t ThreadLocalState;
    #endif
    

    included in the TCB, where ThreadLocalState_t is a structure defined in FreeRTOSconfig.h

    and

    #if THREAD_LOCAL_STATE_PRESENT
        ThreadPreserveState( &TCB->ThreadLocalState );
    #endif
    ... switch context ...
    #if THREAD_LOCAL_STATE_PRESENT
        ThreadRestoreState( &TCB->ThreadLocalState );
    #endif
    

    This is at a much lower level than using TLS pointers, and TLS pointers can be implemented on top of such a thing easily. Just put the TLS array in the localstorage structure.

    In my case, the structure would only contain the CRC state (one word) and I could extend that as needed. This allows me to make the CRC hardware module on the MSP430 thread safe, which we otherwise cannot use.

    This is a small embedded system after all, doesn't have the resource for full fledged thread local storage implementation.

     

    Last edit: ilgitano 2015-01-28
  • Richard Barry

    Richard Barry - 2015-01-28

    Each of those pointers has to be allocated, possibly deallocated and dereferenced in using them

    <snip>

    Using the above, I would just cast one of those tags to the actual CRC content itself, which I suppose is neater than what I have.

    Exactly. Even if you wanted more than one word - it is just an array that has a guaranteed start alignment and a guaranteed size. You could use the array as one block of RAM if you like, you don't have access each pointer individually. For example, if you wanted to store a structure that was 10 bytes long, and each void * was four bytes, would could allocate a TLS pointer array of 3 in order to reserve 12 bytes directly in the TCB. You could then store your structure directly in the TCB, rather than have a TLS pointer point to it somewhere else in memory.

    all I need is a word of storage,

    That is what the task tag is for though.

    This is at a much lower level than using TLS pointers

    It could be done, but I would worry it was too inflexible. For example, the application writer or porter might use it for one thing, but a piece of middleware or C library might want to use it for something else simultaneously (this is a problem that has been encountered multiple times with the task tag). Have the array of TLS blocks with individual pointers was intended to provide the flexibility to allow multiple entities to use it for whatever they like without conflicting with each other - provided they agree which array indexes are for use by who.

    Regards.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.