Rodrigo Meurer Rodrigo Meurer - 2 months ago 10
Python Question

Python segmentation fault on Thread switch

I'm developing an application that should check if the computer is able to ping google.com. To do that I use python subprocess module and issue a call as shown in the code below:

response = subprocess.call("ping -c 1 google.com -q", shell=True)


However, after running for some time, the program exits with a segmentation fault.

I Have the following code:

daemon.py

def dataset_save(smartphone, mote):
print("DATA LOGGER:\tStarting Now")
with open('dataset.csv', 'a+') as dataset:
dataset.write(str(datetime.datetime.today()) + ',' + \
str(datetime.datetime.today().weekday()) + ',' + \
str(smartphone.connected) + ',' + \
str(mote.A0_pw) + ',' + \
str(mote.B00_pw) + ',' + \
str(mote.B01_pw) + ',' + \
str(mote.B10_pw) + ',' + \
str(mote.B11_pw) + ',' + \
str(presence.get_value()) + ',' + \
str(temperature.get_value()) + ',' + \
str(luminosity.get_value()) + '\n')
print("DATA LOGGER: \tData successfully logged @ %s!" %str(datetime.datetime.today()))
return


def run():
check_internet()
while True:
dataset_save(smartphone, gateway)
check_presence()


check_internet.py

def check_internet():
response = subprocess.call("ping -c 1 google.com -q", shell=True)
print(response)
if response == 0:
print ("CONNECTIVITY: \tConnected to internet")
threading.Timer(1, check_internet).start()
return

else:
print("CONNECTIVITY: \tUnable to connect to internet")
threading.Timer(1, check_internet).start()
return


Running this on GDB I get the following trace upon the segmentation fault:

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 146.626/146.626/146.626/0.000 ms
0
CONNECTIVITY: Connected to internet
[New Thread 0xb55ffb40 (LWP 4064)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb65ffb40 (LWP 4043)]
PING google.com (216.58.222.110) 56(84) bytes of data.
__deallocate_stack (pd=0xb65ffb40) at allocatestack.c:760
760 allocatestack.c: No such file or directory.
(gdb)
--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 146.504/146.504/146.504/0.000 ms

(gdb) bt
#0 __deallocate_stack (pd=0xb65ffb40) at allocatestack.c:760
#1 0xb7fc3eab in start_thread (arg=0xb65ffb40) at pthread_create.c:427
#2 0xb7e8164e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129
(gdb)


Is there any reason why I should not use threding.Timer like I'm using? It seems to me that the successive creation of threads is responsible for this segmentation fault.

Thanks.

Answer

You're rearming the timer from within the timer itself, which may not be too good (recursive call with threads, argh). You don't really need Timer if you're not too demanding about ping delay accuracy: you could start a thread that loops and pings google periodically like this:

import threading,subprocess,time

def check_internet():
    while True:
        time.sleep(1)
        response = subprocess.call("ping -n 1 google.com".split())
        print(response)
        if response == 0:
            print("CONNECTIVITY: \tConnected to internet")
        else:
            print("CONNECTIVITY: \tUnable to connect to internet")

t=threading.Thread(target=check_internet)
t.start()

print("Started")
t.join()

you only create 1 thread, which creates 1 ping process every 1+ seconds (it's not a regulated timer, but it should be enough).

EDIT: version without ping output:

import threading,subprocess,time

def check_internet():
    while True:
        time.sleep(1)
        p = subprocess.Popen("ping -n 1 google.com".split(),stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
        out,err = p.communicate()
        response = p.wait()
        if response == 0:
            print("CONNECTIVITY: \tConnected to internet")
        else:
            print("CONNECTIVITY: \tUnable to connect to internet")

t=threading.Thread(target=check_internet)
t.start()

print("Started")
t.join()