Search code examples
linuxpython-3.xnamed-pipesglibdbus

io_add_watch callback only fires once?


I have a named pipe which I want to react to when data is available. I am doing this in the context of dbus. For setup, I have the following:

mainloop = glib.MainLoop()
fifo = os.open('_notify', os.O_RDWR)
glib.io_add_watch(fifo, glib.IO_IN, notifyLoop, service)
try:
    mainloop.run()
except KeyboardInterrupt:
    mainloop.quit()

So in the 2nd and 3rd lines, I'm opening the named pipe, and adding a watch to it. My notifyLoop callback:

def notifyLoop(fifo, cb_cond, service):
    dataStream = service.characteristics[0]
    all = os.read(fifo, 2048)
    print('all', all, 'cb_cond', cb_cond)
    payload, all = all[:20], all[20:]
    while payload:
        newValue = {'Value': [dbus.Byte(x) for x in payload]}
        dataStream.PropertiesChanged(GATT_CHRC_IFACE, newValue, [])
        payload, all = all[:20], all[20:]

Basically, read everything in the pipe, and then break into chunks of size 20 and signal those. The problem is that the callback only fires once, the first time. The first time, I see the print, but when I write more data to the pipe from another program, nothing happens. Am I misunderstanding the way io_add_watch works?

Here's the code I used to write two separate things to the named pipe:

user@machine:/Directory# python3
Python 3.4.2 (default, Oct  8 2014, 14:38:51) 
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> fifo = os.open('_notify', os.O_RDWR)
>>> os.write(fifo, b'\xDE\xAD')
2
>>> os.write(fifo, b'\xBE\xEF')
2
>>> 

After the first write, I see

all b'\xde\xad' cb_cond <flags G_IO_IN of type GIOCondition>

where the dbus program is running. But nothing for the second write.


Solution

  • Your callback must return True in order to be re armed according to the pygtk2 reference. This can be used to make single fire callbacks by explicitly returning False.

    Also, this is not just for callbacks attached with GObject.io_add_watch but for any GObject callback.