Skip to content

Commit b4eec0b

Browse files
authored
Implement listener Stop
Add ability to stop the listener - Use a pipe in the listener to stop the event poller when a message is received from the caller.
1 parent 1f75264 commit b4eec0b

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

fanotify_api.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ type Listener struct {
4848
kernelMajorVersion int
4949
kernelMinorVersion int
5050
watches map[string]bool
51+
stopper struct {
52+
r *os.File
53+
w *os.File
54+
}
5155
// Events a buffered channel holding fanotify notifications for the watched file/directory.
5256
Events chan Event
5357
}
@@ -93,9 +97,13 @@ func (l *Listener) Start() {
9397
if len(l.watches) == 0 {
9498
panic("Nothing to watch. Add Directory/File to the listener to watch")
9599
}
96-
var fds [1]unix.PollFd
100+
var fds [2]unix.PollFd
101+
// Fanotify Fd
97102
fds[0].Fd = int32(l.fd)
98103
fds[0].Events = unix.POLLIN
104+
// Stopper/Cancellation Fd
105+
fds[1].Fd = int32(l.stopper.r.Fd())
106+
fds[1].Events = unix.POLLIN
99107
for {
100108
n, err := unix.Poll(fds[:], -1)
101109
if n == 0 {
@@ -109,16 +117,30 @@ func (l *Listener) Start() {
109117
return
110118
}
111119
}
112-
l.readEvents() // blocks when the channel bufferred is full
120+
if fds[1].Revents != 0 {
121+
if fds[1].Revents&unix.POLLIN == unix.POLLIN {
122+
// found data on the stopper
123+
return
124+
}
125+
}
126+
if fds[0].Revents != 0 {
127+
if fds[0].Revents&unix.POLLIN == unix.POLLIN {
128+
l.readEvents() // blocks when the channel bufferred is full
129+
}
130+
}
113131
}
114132
}
115133

116-
// Close closes the notification group and the events channel
117-
func (l *Listener) Close() {
134+
// Stop stops the listener and closes the notification group and the events channel
135+
func (l *Listener) Stop() {
118136
if l == nil {
119137
return
120138
}
139+
// stop the listener
140+
unix.Write(int(l.stopper.w.Fd()), []byte("stop"))
121141
l.mountpoint.Close()
142+
l.stopper.r.Close()
143+
l.stopper.w.Close()
122144
close(l.Events)
123145
}
124146

fanotify_event.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,30 @@ func newListener(mountpointPath string, flags, eventFlags, maxEvents uint) (*Lis
156156
if err != nil {
157157
return nil, fmt.Errorf("error opening mountpoint %s: %w", mountpointPath, err)
158158
}
159+
r, w, err := os.Pipe()
160+
if err != nil {
161+
return nil, fmt.Errorf("cannot create stopper pipe: %v", err)
162+
}
163+
rfdFlags, err := unix.FcntlInt(r.Fd(), unix.F_GETFL, 0)
164+
if err != nil {
165+
return nil, fmt.Errorf("stopper error: cannot read fd flags: %v", err)
166+
}
167+
_, err = unix.FcntlInt(r.Fd(), unix.F_SETFL, rfdFlags|unix.O_NONBLOCK)
168+
if err != nil {
169+
return nil, fmt.Errorf("stopper error: cannot set fd to non-blocking: %v", err)
170+
}
159171
listener := &Listener{
160172
fd: fd,
161173
flags: flags,
162174
mountpoint: mountpoint,
163175
kernelMajorVersion: maj,
164176
kernelMinorVersion: min,
165177
watches: make(map[string]bool),
166-
Events: make(chan Event, maxEvents),
178+
stopper: struct {
179+
r *os.File
180+
w *os.File
181+
}{r, w},
182+
Events: make(chan Event, maxEvents),
167183
}
168184
return listener, nil
169185
}

0 commit comments

Comments
 (0)