Reputation: 4484
I am trying to watch a directory using F_NOTIFY in Linux (Ubuntu 16, Python 3.5.2). However, it only works if I call fcntl
from the main thread. Why are there no signals when I call fcntl
from other threads? (I don't see any mention of threads in the python fcntl
documentation. Also, if fcntl
is failing, why doesn't it throw an exception?)
# Before running, create directory "a". To test, create a file in "a".
import fcntl, signal, os, threading
pipe_r, pipe_w = os.pipe()
def Unsafe_Handler(s,f):
os.write(pipe_w, b' ')
signal.signal(signal.SIGIO, Unsafe_Handler)
signal.siginterrupt(signal.SIGIO, False)
def Handler():
while True:
os.read(pipe_r, 1)
print("SIGNAL")
threading.Thread(target = Handler).start()
NOTIF_FLAGS = fcntl.DN_MODIFY | fcntl.DN_CREATE | fcntl.DN_MULTISHOT
def Watch_Dir(dn):
fd = os.open(dn, os.O_RDONLY)
fcntl.fcntl(fd, fcntl.F_SETSIG, 0)
fcntl.fcntl(fd, fcntl.F_NOTIFY, NOTIF_FLAGS)
print('Watching directory "%s", fd=%d' % (dn, fd))
return fd
def Init():
fd = Watch_Dir('a')
# this works
#Init()
# this doesn't work
t = threading.Thread(target = Init)
t.start()
t.join()
print("Awaiting signals...")
while True:
signal.pause()
Why signal handling in Python requires threads
The Handler
thread is required because of the following combination of facts:
signal.signal
can't safely do anything but write to a pipe.signal.pause()
, there is no way to safely wake up the main thread without a race condition (signal arrives just before the signal.pause()
) that could get the main thread stuck.Why calling fcntl
from the non-main thread is useful
This is simply because the main thread can't do real work, as already noted. (In my actual application, the handler needs to call fcntl
. For this question I've created a simpler example though).
Upvotes: 0
Views: 39