inotify: Correctly handle multi-struct reads

When reading from the *inotify* file descriptor, multiple structs can be
returned. Because the read loop was incorrectly calculating offsets,
messages would frequently get lost in this way. This commit simplifies
the logic of the read loop, using only a single position indicator and
correctly calculating all offsets from that on each iteration. The
result is that no more messages are incorrectly skipped.
master
Dustin 2018-09-03 14:26:46 -05:00
parent b7070876e5
commit eefcc554c0
1 changed files with 12 additions and 14 deletions

View File

@ -119,9 +119,9 @@ class InotifyError(OSError):
class Inotify(object): class Inotify(object):
'''Wrapper class for Linux inotify capabilities''' '''Wrapper class for Linux inotify capabilities'''
BUFSIZE = 4096
STRUCT_FMT = '@iIII' STRUCT_FMT = '@iIII'
STRUCT_SIZE = struct.calcsize(STRUCT_FMT) STRUCT_SIZE = struct.calcsize(STRUCT_FMT)
BUFSIZE = STRUCT_SIZE + 256
def __init__(self): def __init__(self):
fd = _libc.inotify_init() fd = _libc.inotify_init()
@ -173,21 +173,19 @@ class Inotify(object):
buf = memoryview(os.read(self.__fd, self.BUFSIZE)) buf = memoryview(os.read(self.__fd, self.BUFSIZE))
nread = len(buf) nread = len(buf)
i = begin = 0 pos = 0
end = self.STRUCT_SIZE while pos < nread:
while i < nread: packed = buf[pos:pos + self.STRUCT_SIZE]
wd, mask, cookie, sz = self._unpack(buf[begin:end]) pos += self.STRUCT_SIZE
begin = end wd, mask, cookie, sz = self._unpack(packed)
end += sz if sz:
x = begin name = buf[pos:pos + sz].tobytes()
while buf[x:x + 1] != b'\x00': name = name[:name.index(b'\x00')]
x += 1 pos += sz
name = buf[begin:x].tobytes() else:
name = None
pathname = self.__watches[wd] pathname = self.__watches[wd]
i += end
yield Event(wd, mask, cookie, name, pathname) yield Event(wd, mask, cookie, name, pathname)
begin = end
end += self.STRUCT_SIZE
def close(self): def close(self):
'''Close all watch descriptors and the inotify descriptor''' '''Close all watch descriptors and the inotify descriptor'''