Menu

#136 GPIO.remove_event_detect + C-call = segmentation fault

Accepted
None
Medium
Defect
2016-11-14
2016-06-21
Jonas Kunze
No

When I call GPIO.remove_event_detect inside of a event callback and then run a C API call like Image.open or suprocess.Popen I get a segmentation fault as soon as the callback returns.

Here's a minimal example:

import RPi.GPIO as GPIO
import time
from PIL import Image
from PIL import ImageStat

GPIO.setmode(GPIO.BCM)
GPIO.setup(3, GPIO.IN)  

def on_buzzer_pushed_once(channel):
    GPIO.remove_event_detect(channel) # swapping this with the following line
    im = Image.open("capt0000.jpg")   # fixes the issue
    print("This is printed, segfault comes after this line")

GPIO.add_event_detect(3, GPIO.FALLING, callback=on_buzzer_pushed_once)
while True:
    time.sleep(1)

The result is simply this:

$ python test.py 
This is printed, segfault comes after this line
Segmentation fault

If I swap the two lines in the callback, it works as expected!

raspi-gpio version is 0.6.2
issue appears on python 3.4.2 and 2.7.9

GDB did not help much so far:

gdb python
GNU gdb (Raspbian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from python...(no debugging symbols found)...done.
(gdb) r test.py
Starting program: /usr/bin/python test.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
[New Thread 0x76721460 (LWP 7043)]
Cannot access memory at address 0x3000e27a

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x76721460 (LWP 7043)]
0x7692ab84 in ?? () from /usr/lib/python2.7/dist-packages/RPi/_GPIO.arm-linux-gnueabihf.so
(gdb) bt
#-1 0x7692ab84 in ?? ()
   from /usr/lib/python2.7/dist-packages/RPi/_GPIO.arm-linux-gnueabihf.so
#0  0x7692ab84 in ?? ()
   from /usr/lib/python2.7/dist-packages/RPi/_GPIO.arm-linux-gnueabihf.so
/build/gdb-nrlhe3/gdb-7.7.1+dfsg/gdb/frame.c:472: internal-error: get_frame_id: Assertion `fi->this_id.p' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)

Discussion

  • Momo

    Momo - 2016-08-24

    I have something similar but changing the order does not result in working code.

    Minimized example:

    import time
    from time import mktime, time, sleep
    import RPi.GPIO as GPIO
    import requests
    
    def button_press_isr1(channel):
        GPIO.remove_event_detect(18)
        cnt = 0
        edge_start1 = time()
        while (time() - edge_start1) <= 0.035 :
            if GPIO.input(18) == 0 : 
                cnt += 1
            else: 
                cnt = 0
            if cnt == 7 :
                break
        if cnt == 7 :
            response = requests.post(url="http://192.168.1.5:8080")
        GPIO.add_event_detect(18, GPIO.FALLING, callback=button_press_isr1)
    
    def init():
      GPIO.setwarnings(True)
      GPIO.setmode(GPIO.BCM)
      GPIO.setup(18, GPIO.IN)
    
      GPIO.add_event_detect(18, GPIO.FALLING, callback=button_press_isr1)
    
    def main():
      try:
        while True:
          sleep(0.03)
    
      except KeyboardInterrupt:
          # exit with CTRL+C
          print("CTRL+C used to end Program")
      finally:
        GPIO.cleanup()
    
    if __name__ == "__main__":
        init()
        main()
    
     
  • Momo

    Momo - 2016-08-26

    Found a Workaround for this by using a variable to skip the callback code if we are already inside:

    import time
    from time import mktime, time, sleep
    import RPi.GPIO as GPIO
    import requests
    
    def button_press_isr1(channel):
        #Do not use >> SEGFAULT
        #GPIO.remove_event_detect(18)
        #Instead use a variable to set the callback on ignore
        if ignoreCalls==1:
            return
        ignoreCalls=1
        cnt = 0
        edge_start1 = time()
        while (time() - edge_start1) <= 0.035 :
            if GPIO.input(18) == 0 : 
                cnt += 1
            else: 
                cnt = 0
            if cnt == 7 :
                break
        if cnt == 7 :
            response = requests.post(url="http://192.168.1.5:8080")
        #and wherever you would activate the callback again, just remove the ignoreCalls switch
        ignoreCalls=0
        #GPIO.add_event_detect(18, GPIO.FALLING, callback=button_press_isr1)
    
    def init():
      #variable used as workaround for the SEGFAULT Problem
      global ignoreCalls
      ignoreCalls=0
      GPIO.setwarnings(True)
      GPIO.setmode(GPIO.BCM)
      GPIO.setup(18, GPIO.IN)
    
      GPIO.add_event_detect(18, GPIO.FALLING, callback=button_press_isr1)
    
    def main():
      try:
        while True:
          sleep(0.03)
    
      except KeyboardInterrupt:
          # exit with CTRL+C
          print("CTRL+C used to end Program")
      finally:
        GPIO.cleanup()
    
    if __name__ == "__main__":
        init()
        main()
    
     
  • Ben Croston

    Ben Croston - 2016-10-15
    • status: New --> Accepted
    • Priority: High --> Medium
     
  • Ben Croston

    Ben Croston - 2016-10-15

    There will be a fix for this in 0.6.3 - I have been sent a patch for the issue which I am currently evaluating.

     
  • Erik Houet

    Erik Houet - 2016-11-14

    Problem is still there in 0.6.3

    sometimes 'Segmentation fault' occurs after removing the event with 'remove_event_detect'.

    I'm using the event to measure the frequency of a 4 kHz square wave. When the measurement is stopped I don't want the event any more. But removing will cause an error.

    A workaround would be fine, but it is not as simple as the above...

     

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.