Skip to content

Events should be non-reentrant #72

@trailhead

Description

@trailhead

In the following code, a noisy button press can cause the callback be called once, then interrupted by a second edge and called again.

def cb(gp):
  print("Start");
  print(gp);
  print("End");

GPIO.setup("P8_17", GPIO.IN, GPIO.PUD_UP);

GPIO.add_event_detect("P8_17", GPIO.FALLING, cb, 200);

Leading to output like this...

Start
Start
P8_17
End
P8_17
End

This is not detected as a bounce because in run_py_callbacks the cb->lastcall property isn't set until after the callback returns. At the time of the second call, cb->lastcall is still equal to zero. This can be worked around by setting cb->lastcall just before calling the callback function. This does not address bounces of the other edge, which leads to incorrect callbacks.

diff --git a/source/py_gpio.c b/source/py_gpio.c
index 67f6ba4..e8e3baa 100644
--- a/source/py_gpio.c
+++ b/source/py_gpio.c
@@ -185,6 +185,10 @@ static void run_py_callbacks(unsigned int gpio)
          gettimeofday(&tv_timenow, NULL);
          timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
          if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcal$
+
+            // save lastcall before calling func to prevent reentrant bounce
+            cb->lastcall = timenow;
+
             // run callback
             gstate = PyGILState_Ensure();
             result = PyObject_CallFunction(cb->py_cb, "s", cb->channel);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions