Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does polling a file for changes work?

The problem

I expected the script below to print at most one event and then stop (it's written only to illustrate the problem).

#!/usr/bin/env python

from select import poll, POLLIN

filename = "test.tmp"

# make sure file exists
open(filename, "a").close()

file = open(filename, "r+")

p = poll()
p.register(file.fileno(), POLLIN)

while True:
    events = p.poll(100)
    for e in events:
        print e
        # Read data, so that the event goes away?
        file.read()

However, it prints about 70000 events per second. Why?

Background

I've written a class that uses the pyudev.Monitor class internally. Amongst other things, it polls the fileno supplied by the fileno() method for changes using a poll object.

Now I'm trying to write an unit test for my class (I realize I'm supposed to write the unit test first, so no need to point it out), and therefore I need to write my own fileno() method for my mock pyudev.Monitor object, and I need to control it so that I can trigger the poll object to report an event. As the above code demonstrates, I can't make it stop reporting seemingly non-existent events!

I can find no acknowledge_event() or similar in the poll class to make the event go away (I suspect there's just one event that's somehow stuck), searching google and this site has yielded nothing. I'm using python 2.6.6 on Ubuntu 10.10.

like image 220
Lauritz V. Thaulow Avatar asked Jan 24 '11 13:01

Lauritz V. Thaulow


People also ask

What is polling a file?

A file polling port periodically polls a monitoring directory for the arrival of files. Integration Server then runs a special file processing service against the file. For more information on file polling ports, see Flat File User's Guide .


1 Answers

You'll have better luck using pipes rather than files. Try this instead:

#!/usr/bin/env python
import os
from   select import poll, POLLIN

r_fd, w_fd = os.pipe()

p = poll()
p.register(r_fd, POLLIN)

os.write(w_fd, 'X') # Put something in the pipe so p.poll() will return

while True:
    events = p.poll(100)
    for e in events:
        print e
        os.read(r_fd, 1)

This will print out the single event you're looking for. To trigger the poll event, all you have to do is write a byte to the writeable file descriptor.

like image 142
Rakis Avatar answered Sep 28 '22 08:09

Rakis