Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python gobject.mainloop gobbles signal events

I have one module which uses python "threading" for concurrency, and "signal" for shutdown hook:

signal.signal(signal.SIGINT, self.shutdownhook)

I have another module which uses dbus and gobject

dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
....
GObject.threads_init()
mainloop = GObject.MainLoop()
mainloop.run()

When I run them seperately, they both operate as expected and ctrl+c causes termination via "KeyboardInterrupt".

However, when I run them together the mainloop terminates but the shutdown hook is never called - the process does not terminate without kill -9 pid.

Can someone please explain why this occurs, and how best to integrate the two models

Here is a working example which highlights my problem. I cannot exit the program with just a CTRL+C and the shutdown hook is not called in this case either.

import threading
import signal
import sys
from gi.repository import GObject


def runMainloop():
        print('running mainloop')
        mainloop.run()

def shutdown():
        print('shutdown')

def readInput():
        print('readInput')
        print(sys.stdin.readline())

if __name__ == '__main__':
        signal.signal(signal.SIGINT, shutdown)
        signal.signal(signal.SIGTERM, shutdown)
        GObject.threads_init()
        mainloop = GObject.MainLoop()

        mainloopThread = threading.Thread(name='mainloop', target=runMainloop)
        mainloopThread.setDaemon(True)
        mainloopThread.start()
        print('started')

        inputThread = threading.Thread(name='input', target=readInput)
        inputThread.start()
        print('started input')
like image 300
pstanton Avatar asked Dec 05 '17 06:12

pstanton


2 Answers

No one is interested, so let me try.

Just to be on the same page:

import signal
from gi.repository import GObject

GObject.threads_init()
mainloop = GObject.MainLoop()

signal.signal(signal.SIGINT, lambda n, f: mainloop.quit())

mainloop.run()

This code works:

import signal
from gi.repository import GObject

signal.signal(signal.SIGINT, lambda n, f: print("kill"))

GObject.threads_init()
mainloop = GObject.MainLoop()
mainloop.run()

I've first registered signal handler, and then initiated the loop. Strange is that it is not called. However result is - as expected...

As a side note - according to their doc... mainloop is deprecated. That is first thing.

Edit

Here is example with reading from stdin inside MainLoop:

import signal
import sys
from gi.repository import GObject, GLib

GObject.threads_init()

def readInput():
    print('readInput\n')
    while True:
        input = sys.stdin.readline()
        print(input)
        if input.strip() == 'exit':
            print('closing main loop')
            mainloop.quit()
            print('terminating thread')
            return

if __name__ == '__main__':
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    mainloop = GObject.MainLoop.new(None, False)
    GObject.timeout_add(1000, readInput)

    # inputThread = threading.Thread(name='input', target=readInput)
    # inputThread.start()
    # print('started input')

    print('running mainloop\n')
    try:
        mainloop.run()
    except KeyboardInterrupt:
        mainloop.quit()

Adding .new(None, False) allows CTRL-C working normally. Took it from here, also here is another thread about integrating pulse audio controller with GLib/GObject loop. There are samples about integration dbus with the loop, but I'm not sure which way you wish to go...

like image 179
Michał Zaborowski Avatar answered Nov 16 '22 17:11

Michał Zaborowski


Adding a timer makes the loop receive Unix signals.

import gi
from gi.repository import GLib
import signal

GLib.threads_init()

mainloop = GLib.MainLoop()

signal.signal(signal.SIGTERM, lambda signum, frame: mainloop.quit())

GLib.timeout_add(1000, lambda *args: (print("tick") or True))

try:
    mainloop.run()
except KeyboardInterrupt:
    print()
like image 2
haael Avatar answered Nov 16 '22 18:11

haael