0

I am trying to write some non-blocking FIFO code with kqueue on my BSD machine. Here's the small server code: server.py

import os
import selectors

sel = selectors.KqueueSelector()

TMP_PATH="/tmp/myfifo"

def fifo_read(fd, mask):
    data = os.read(fd, 8)
    print("fd:{} gives:{} \n", fd, data)
    sel.unregister(fd)
    print("unregistered")

def fifo_accept(listen_fd, mask):
    print("accepted {}".format(listen_fd))
    fd = os.dup(listen_fd)
    print("duped to {}".format(fd))
    sel.register(fd, selectors.EVENT_READ, fifo_read)

if __name__ == "__main__":
    try:
        os.unlink(TMP_PATH)
    except:
        pass

    os.mkfifo(TMP_PATH)
    listen_fd = os.open(TMP_PATH, os.O_RDONLY, mode=0o600)

    sel.register(listen_fd, selectors.EVENT_READ, fifo_accept)

    while True:
        events = sel.select()
        for key, mask in events:
            cb = key.data
            cb(key.fileobj, mask)

    sel.close()

Now, when I run a client.py as:

import os

TMP_PATH="/tmp/myfifo"

fd = os.open(TMP_PATH, os.O_WRONLY, mode=0o600)

res = os.write(fd, b"1234567")

print("sent {}".format(res))

When I run the client, I get: sent 7

But on server, it runs to inifinite loop. Now I understand why the infinite loop is happening. I actually tried mimicking the socket way of using selectors in this Python Docs example. Here's what I have tried:

  • I did try the code without duplicating the fd, but it's still in infinite loop.
  • I tried calling sel.unregister on the original listen_fd, but in this case, running the client the second time doesn't work (which is expected).

Can anyone please let me know if I'm missing something?

Rahul Bharadwaj
  • 2,555
  • 2
  • 18
  • 29

1 Answers1

0

So I found one solution to this problem. With sockets, we get a new socket object on accept. So we need to emulate that behaviour by calling unregister on the original fileobj, open again and call register on that.

Fixed code:

import os
import selectors

sel = selectors.KqueueSelector()

try:
    os.unlink("./myfifo")
except:
    pass
os.mkfifo("./myfifo", 0o600)


def cb(fp):
    sel.unregister(fp)
    print(f"got {fp.read()}")
    fp.close()
    fp2 = open("./myfifo", "rb")
    sel.register(fp2, selectors.EVENT_READ, cb)

if __name__ == "__main__":
    orig_fp = open("./myfifo", "rb")
    print("open done")
    ev = sel.register(orig_fp, selectors.EVENT_READ, cb)
    print(f"registration done for {ev}")

    while True:
        events = sel.select()
        print(events)
        for key, mask in events:
            key.data(key.fileobj)
Rahul Bharadwaj
  • 2,555
  • 2
  • 18
  • 29