Finally, I found eventlet-inotifyx
.
Last active
February 3, 2017 08:31
-
-
Save hkwi/3034e3b98aa6d643e91e9a77fa2218bc to your computer and use it in GitHub Desktop.
inotify eventlet integration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import errno | |
import ctypes.util | |
libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) | |
IN_NONBLOCK = os.O_NONBLOCK | |
if hasattr(os, "O_CLOEXEC"): # >=python3.3 | |
IN_CLOEXEC = os.O_CLOEXEC | |
class Event(ctypes.Structure): | |
name = None | |
_fields_ = [("wd", ctypes.c_int), | |
("mask", ctypes.c_uint32), | |
("cookie", ctypes.c_uint32), | |
("len", ctypes.c_uint32)] | |
def __repr__(self): | |
return "(wd=%d, mask=%s, cookie=%d, name=%s)" % (self.wd, mask_tostr(self.mask), self.cookie, self.name) | |
def parse_events(buf, rlen): | |
evs = [] | |
off = 0 | |
while off < rlen: | |
ev = Event.from_buffer(buf, off) | |
ev.name = buf[off+ctypes.sizeof(ev):][:ev.len] | |
off += ctypes.sizeof(ev) + ev.len | |
evs.append(ev) | |
return evs | |
_mask_flags = ( | |
("IN_ACCESS" , 0x00000001), | |
("IN_MODIFY" , 0x00000002), | |
("IN_ATTRIB" , 0x00000004), | |
("IN_CLOSE_WRITE" , 0x00000008), | |
("IN_CLOSE_NOWRITE" , 0x00000010), | |
("IN_OPEN" , 0x00000020), | |
("IN_MOVED_FROM" , 0x00000040), | |
("IN_MOVED_TO" , 0x00000080), | |
("IN_CREATE" , 0x00000100), | |
("IN_DELETE" , 0x00000200), | |
("IN_DELETE_SELF" , 0x00000400), | |
("IN_MOVE_SELF" , 0x00000800), | |
("IN_UNMOUNT" , 0x00002000), | |
("IN_Q_OVERFLOW" , 0x00004000), | |
("IN_IGNORED" , 0x00008000), | |
("IN_ONLYDIR" , 0x01000000), | |
("IN_DONT_FOLLOW" , 0x02000000), | |
("IN_EXCL_UNLINK" , 0x04000000), | |
("IN_MASK_ADD" , 0x20000000), | |
("IN_ISDIR" , 0x40000000), | |
("IN_ONESHOT" , 0x80000000), | |
) | |
for k,v in _mask_flags: | |
globals()[k] = v | |
def mask_tostr(mask): | |
nm = [] | |
for k,v in _mask_flags: | |
if v&mask: | |
nm.append(k) | |
return "|".join(nm) | |
_mask_names = ( | |
("IN_CLOSE" , IN_CLOSE_WRITE | IN_CLOSE_NOWRITE), | |
("IN_MOVE" , IN_MOVED_FROM | IN_MOVED_TO), | |
("IN_ALL_EVENTS" , (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | | |
IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | | |
IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | | |
IN_MOVE_SELF)) | |
) | |
for k,v in _mask_names: | |
globals()[k] = v | |
def _check_fail(rc): | |
if rc == -1: | |
raise OSError(ctypes.get_errno()) | |
return rc | |
for k in ("init","init1","add_watch","rm_watch"): | |
name = "inotify_"+k | |
func = getattr(libc, name) | |
func.restype = _check_fail | |
globals()[name] = func | |
def read(fd, nonblocking=False): | |
evs = [] | |
n = 128 | |
buf = ctypes.create_string_buffer(n) | |
while True: | |
if len(buf) != n: | |
buf = ctypes.create_string_buffer(n) | |
rlen = libc.read(fd, ctypes.pointer(buf), len(buf)) | |
if not nonblocking: | |
if rlen == -1: | |
raise OSError(ctypes.get_errno()) | |
else: | |
return parse_events(buf,rlen) | |
elif rlen == 0: | |
n *= 2 | |
continue | |
elif rlen == -1: | |
err = ctypes.get_errno() | |
if err == errno.EINVAL: | |
n *= 2 | |
continue | |
elif err == errno.EINTR: | |
continue | |
elif err == errno.EAGAIN: | |
break | |
else: | |
raise OSError(err) | |
else: | |
evs += parse_events(buf,rlen) | |
return evs | |
if __name__=="__main__": | |
fd=inotify_init() | |
print(inotify_add_watch(fd,"/home/vagrant",IN_ALL_EVENTS)) | |
print(read(fd)) | |
fd=inotify_init1(IN_NONBLOCK) | |
print(inotify_add_watch(fd,"/home/vagrant",IN_ALL_EVENTS)) | |
import select | |
select.select([fd],[],[]) | |
print(read(fd, nonblocking=True)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import eventlet.hubs | |
from inotify import * | |
class Inotify(object): | |
def __init__(self): | |
self.fd = inotify_init1(IN_NONBLOCK) | |
self.wds = dict() | |
hub = eventlet.hubs.get_hub() | |
def cb(fd): | |
assert fd == self.fd | |
for ev in read(fd): # TODO: After some real-world test, one callback invocation per one read looks better. | |
watch = self.wds.get(ev.wd, None) | |
if watch: | |
watch.callback(ev.mask, ev.cookie, ev.name) | |
eventlet.getcurrent().switch() | |
hub.add(hub.READ, self.fd, cb, eventlet.getcurrent().throw, lambda: None) | |
def watch(self, path, mask, callback): | |
''' | |
callback signature is: `callback(event_flags, cookie, filename)` | |
''' | |
wd = inotify_add_watch(self.fd, path, mask) | |
w = Watch(self, wd, callback) | |
self.wds[wd] = w | |
return w | |
class Watch(object): | |
def __init__(self, inotify, wd, callback): | |
self.inotify = inotify | |
self.wd = wd | |
self.callback = callback | |
def close(self): | |
inotify_rm_watch(self.inotify.fd, self.wd) | |
del(self.inotify.wds[self.wd]) | |
if __name__=="__main__": | |
def hoge(mask, cookie, name): | |
print(mask_tostr(mask), cookie, name) | |
w = Inotify().watch(".", IN_ALL_EVENTS, hoge) | |
eventlet.sleep(30) | |
w.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment