10 years, 4 months ago.

How to determine if currently running inside a thread

There are cases where a constructor needs to have relatively long "waits" within the constructor - for example when communicating with SPI flash or other external devices that have relatively long reset cycles.

For example:

SPI Flash constructor

FlashM25PSpi::FlashM25PSpi(RTOS_SPI *spi, PinName enable, int bits, int mode) :
    _spi(spi)
    , _enable(enable)
    , _size(0)
{
    if (bits) _spi->format(bits, mode);

    _enable = 1;

    Thread::wait(1);  // Flash chip power-on reset cycle, 1ms

    _enable = 0;
    wait_us(1);

    uint8_t chipSig;
    // Ask for chip signature
   // SNIP
}

This is good as it allows another thread to run while the FlashSPI object is being constructed.

However, if I construct the object from outside a thread, eg:

main.cpp

#include "mbed.h"
#include "rtos.h"
#include "flash25spi.h"

// SPI Flash memory
RTOS_SPI spi(PTD6, PTD7, PTD5);
FlashM25PSpi flashMem(&spi, PTA12);

int main()
{
  // Do Stuff
}

It crashes because there aren't any Threads at the time of construction.

So, in order to make a robust library I need a way to check whether or not the constructor is being run inside a thread, and thus select the appropriate wait method.

Does that exist?

I tried Thread::gettid() but that also crashes when run outside a thread.

Question relating to:

Official mbed Real Time Operating System based on the RTX implementation of the CMSIS-RTOS API open standard. cmsis, rtos, RTX

3 Answers

10 years, 4 months ago.

I actually had a similar issue once, and only found out what I think is the solution after I just decided to keep them inside a thread. So I haven't really verified, but I think this should solve your issue, just had to google the correct function name:

#include "mbed.h"
#include "rtos.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);

class myclass {
    public:
        myclass() {
        if (osKernelRunning())
            led1 = 1;
        else
            led2 = 1;
    }
};


//myclass name;
 
int main()
{
    myclass name;
    
    while(1);
}

Which led is turned on nicely depends on where the constructor is placed.

Accepted Answer

Thanks, that's exactly what I needed!

posted by Richard Thompson 26 Jun 2014
10 years, 4 months ago.

I put incrementing counters within the RTOS threads and check them in main

...kevin

10 years, 4 months ago.

Hello,

are you aware when are constructors called for global objects? If your application does not handle those objects dynamically, the approach above (thread wait) does not have any use.. If you still insist on the approach, start RTOS before the constructor is invoked. The ARM C library provides some hooks to do so.

Regards, 0xc0170

It appears that you did not understand my question, let me clarify for future reference.

I am fully aware that a global object is constructed before the RTOS is running, and that Thread::wait() cannot be called at this point.

When I publish an RTOS-enabled library for other people to use, they may wish to construct its objects globally, or they may wish to construct them in a thread.

If they do it in a thread, they expect it to yield to other threads during long waits.

However, if they do it globally, they do not expect it to crash.

Therefore, to fully support the RTOS, the constructor should programmatically detect when it is being constructed and select the appropriate wait method.

posted by Richard Thompson 26 Jun 2014

I understood, therefore I suggested to run RTOS before even C runtime initialization is invoked.

I would not use any yeld inside the constructor call. What if a scheduler switches to a function which might use the the object which has not been initialized yet...

posted by Martin Kojtal 30 Jun 2014

That's their lookout!

It's always possible for the scheduler to switch threads in the middle of a constructor - or for an interrupt to occur - so if somebody wants multiple threads to access the same object then they always need to guard against incomplete construction, whether by using a null-check, RTOS message or assignment method.

Yielding does make that thread switch more probable - one can argue that is a good thing as it means the crash happens more often and is thus easier to find and fix.

I don't want to start the RTOS earlier as this would means they can no longer assume that the RTOS is not running during construction of the global objects, which could easily break other code that makes this assumption.

posted by Richard Thompson 30 Jun 2014