github.com/elastic/gosigar@v0.14.3/psnotify/psnotify_bsd.go (about) 1 // Copyright (c) 2012 VMware, Inc. 2 3 // +build darwin freebsd netbsd openbsd 4 5 // Go interface to BSD kqueue process events. 6 package psnotify 7 8 import ( 9 "syscall" 10 ) 11 12 const ( 13 // Flags (from <sys/event.h>) 14 PROC_EVENT_FORK = syscall.NOTE_FORK // fork() events 15 PROC_EVENT_EXEC = syscall.NOTE_EXEC // exec() events 16 PROC_EVENT_EXIT = syscall.NOTE_EXIT // exit() events 17 18 // Watch for all process events 19 PROC_EVENT_ALL = PROC_EVENT_FORK | PROC_EVENT_EXEC | PROC_EVENT_EXIT 20 ) 21 22 type kqueueListener struct { 23 kq int // The syscall.Kqueue() file descriptor 24 buf [1]syscall.Kevent_t // An event buffer for Add/Remove watch 25 } 26 27 // Initialize bsd implementation of the eventListener interface 28 func createListener() (eventListener, error) { 29 listener := &kqueueListener{} 30 kq, err := syscall.Kqueue() 31 listener.kq = kq 32 return listener, err 33 } 34 35 // Initialize Kevent_t fields and propagate changelist for the given pid 36 func (w *Watcher) kevent(pid int, fflags uint32, flags int) error { 37 listener, _ := w.listener.(*kqueueListener) 38 event := &listener.buf[0] 39 40 syscall.SetKevent(event, pid, syscall.EVFILT_PROC, flags) 41 event.Fflags = fflags 42 43 _, err := syscall.Kevent(listener.kq, listener.buf[:], nil, nil) 44 45 return err 46 } 47 48 // Delete filter for given pid from the queue 49 func (w *Watcher) unregister(pid int) error { 50 return w.kevent(pid, 0, syscall.EV_DELETE) 51 } 52 53 // Add and enable filter for given pid in the queue 54 func (w *Watcher) register(pid int, flags uint32) error { 55 return w.kevent(pid, flags, syscall.EV_ADD|syscall.EV_ENABLE) 56 } 57 58 // Poll the kqueue file descriptor and dispatch to the Event channels 59 func (w *Watcher) readEvents() { 60 listener, _ := w.listener.(*kqueueListener) 61 events := make([]syscall.Kevent_t, 10) 62 63 for { 64 if w.isDone() { 65 return 66 } 67 68 n, err := syscall.Kevent(listener.kq, nil, events, nil) 69 if err != nil { 70 w.Error <- err 71 continue 72 } 73 74 for _, ev := range events[:n] { 75 pid := int(ev.Ident) 76 77 switch ev.Fflags { 78 case syscall.NOTE_FORK: 79 w.Fork <- &ProcEventFork{ParentPid: pid} 80 case syscall.NOTE_EXEC: 81 w.Exec <- &ProcEventExec{Pid: pid} 82 case syscall.NOTE_EXIT: 83 w.RemoveWatch(pid) 84 w.Exit <- &ProcEventExit{Pid: pid} 85 } 86 } 87 } 88 } 89 90 // Close our kqueue file descriptor; deletes any remaining filters 91 func (listener *kqueueListener) close() error { 92 return syscall.Close(listener.kq) 93 }