Subscribed events cause context switch?

I had the following code:

  system_tick_t now = millis();
  system_tick_t time_since_change = now - m_last_state_change;
  system_tick_t time_since_update = now - m_last_current_temp;

  ...

  if (time_since_update > (10 * 60 * 1000UL))...

  ...

  Particle.subscribe(X, update);

  ...

  void update(const char *event, const char *data) {
    m_last_current_temp = millis();
  }
  

and I noticed that the if was firing even though updates were being received at regular intervals. After some testing it seems sometimes that period can go negative. I figure it must happen when an event is received between the first couple of lines.

I switched the code to:

  system_tick_t now, time_since_change, time_since_update;
  SINGLE_THREADED_BLOCK() {
    now = millis();
    time_since_change = now - m_last_state_change;
    time_since_update = now - m_last_current_temp;
  }

and so far haven’t seen the issue return.

This does make me suspect of other code I’ve used and seen used that does the same operation on one line. For example the following code if it was possible that a lastSync was updated outside of the loop.

  if (millis() - lastSync > ONE_DAY_MILLIS) {

Are these all not safe? and is SINGLE_THREADED_BLOCK the correct way to make them safe?

If so I suppose I’d suggest an update to the subscribe documentation that makes it clear that received messages can interrupt the normal program flow even if not using any special threading.

(if this also occurs outside of mesh feel free to relocate this thread)

@rickkas7 where this behaviour is unexpected, should it be covered in the Automatic Mode section of the documentation?

Have you tried adding volatile to the time_since_update variable definition?

When implementing an interrupt handler, the handler must execute quickly, or the system operation may be impaired. Any variables shared between the interrupt handler and the main program should be declared as volatile to ensure that changes in the interrupt handler are visible in the main loop and vice versa.

From https://docs.particle.io/reference/device-os/firmware/argon/#system-interrupts

Hi @Fragma. Thanks for the suggestion. I actually realized by it that I’d made a mistake in my pared down version of the code. update() updates m_last_current_temp, not time_since_update, as I originally had it.

With the three system_tick_t only accessed in the loop I don’t think volatile will do anything there, and if I added it to m_last_current_temp then it seems only likely to make the issue worse as if anything I’d actually like the older value.

Maybe I’ve misunderstood how the firmware code handles this type of call, as I was under the impression that without enabling system_thread I only had to worry about particle code running if I called Particle.process() or delay().