Timer.Alarm callback is blocked by caller

  • Hi,

    I am experiencing an issue in the way the Timer.Alarm functionality appears to be working on my project, in that if I setup an alarm to fire a callback in X seconds, and the calling process then works for Y seconds (sleep, loop etc) and Y>X, the Alarm callback won't fire until the caller has finished.

    For example (and yes I know this is not the best way but for illustrative purposes):

    def timer_callback(src):
        Timer.Alarm(timer_callback, 5)    
        t = utime.gmtime()
        print("{0:02}:{1:02}:{2:02} - Timer Callback".format(t[3], t[4], t[5]))

    So this sets the callback to trigger every 5 seconds, prints out the current time and sleeps for 10 seconds

    >>> alarm_test.timer_callback(None)
    00:01:17 - Timer Callback
    00:01:22 - Timer Callback
    00:01:32 - Timer Callback
    00:01:42 - Timer Callback
    00:01:52 - Timer Callback
    00:02:02 - Timer Callback
    00:02:12 - Timer Callback

    So from this you can see that a Timer callback that sets an Alarm will block the timer until its processing has finished (as you can see with the output happening every 10 seconds, not 5). Is this the intended behavior? I would expect the alarm to trigger regardless of what the calling program is doing like an interrupt.

    Just for the sake of it I even implemented another function just to set the alarm and call it in a new thread

    def setalarm_thread(fn, alarmtime):    
        Timer.Alarm(fn, alarmtime)
    def timer_callback(src):
        _thread.start_new_thread(setalarm_thread, (timer_callback, 5))    
        t = utime.gmtime()
        print("{0:02}:{1:02}:{2:02} - Timer Callback".format(t[3], t[4], t[5]))

    And the result is the exact same, the Alarm callback is blocked until the calling function has finished.

    So is this the expected behavior? Or am I doing something silly here? Any help would be greatly appreciated.

  • @robert-hh Thanks for that insight. My issue was that (unlike my example) the callback would trigger a separate function that included an additional but non-related alarm call back that would get 'stalled' from the original callback.

    Having worked out that as long as an alarm is created from the 'main' thread it will not be blocked by work from the caller I have adjusted my program to use a mix of sensor alarms and secondary "worker" threads which are triggered by not run from the alarm callback. Not sure if it is the best way but seems to allow things to run smoothly without blocking.

  • @nathanh two things:
    a) usually, the time alarm is not enabled in the callback, at least not for periodic callbacks. You can do that one one_shot callbacks.
    b) Callbacks are comfortable variants of an Interrupt Service Routine (ISR). Like ISR's, they are meant to finish as soon as possible. Until they return, further calls to it are blocked. That is the intended behavior. So having a long sleep in a callback is clearly a DON'T. Having the callback working longer than the expected time between interrupts is a design problem.

Pycom on Twitter