I have a Python program which uses named pipes for various purposes. Each pipe is managed from a different thread so it won't block the main thread.
Let's say I have a thread which is blocking on a call to open('in', 'rb')
where in
is the relative path of the named pipe.
If I wish to shut down my program, I use something like this to unblock my thread from an other one:
with suppress(OSError):
fd = os.open('in', O_WRONLY | O_NONBLOCK)
os.close(fd)
This just opens the pipe in write mode, so that the thread blocking on open
can move on, then close it. I use O_NONBLOCK
to avoid blocking in case the other thread has already terminated (and ignore the potential OSError
).
This works fine until someone decides to delete the named pipe in
while my thread is blocking on open
.
In this case I cannot use my "try to open the pipe in non blocking mode and close it" method, because the pipe is no longer visible on the file system (and the non blocking open would just create a brand new pipe).
What is the proper solution to this problem other than killing the thread? Note that I cannot prevent other processes from removing the pipe and permissions won't help (the deleting process could run as root).
I have solved my problem by using os.open('in', O_RDONLY | O_NONBLOCK)
, which yields a file descriptor even if there is no writer on the other side of the pipe.
Once I had a valid file descriptor for reading, I was able to feed this to the select()
system call to block until there is something to read.
In order to deal with the "what if someone deletes the pipe from the file system while I'm blocking" problem, I've used the pipe()
syscall to get an unnamed pipe (the Python version just yields 2 file descriptors for the 2 ends of the pipe).
I feed the read descriptor of this unnamed pipe to the select()
call as well, so any time I wish to stop my program I just unblock select()
by writing to the write descriptor of the unnamed pipe regardless of what's up with the named pipe.