예제 #1
0
// Unwatch implements trigger.
func (k *kq) Unwatch(w *watched) (err error) {
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE)

	_, err = syscall.Kevent(k.fd, kevn[:], nil, nil)
	return
}
예제 #2
0
// watch starts to watch given p file/directory.
func (k *kqueue) singlewatch(p string, e Event, direct bool,
	fi os.FileInfo) error {
	w, ok := k.pthLkp[p]
	if !ok {
		fd, err := syscall.Open(p, syscall.O_NONBLOCK|syscall.O_RDONLY, 0)
		if err != nil {
			return err
		}
		w = &watched{fd: fd, p: p, fi: fi}
	}
	if direct {
		w.eDir |= e
	} else {
		w.eNonDir |= e
	}
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE,
		syscall.EV_ADD|syscall.EV_CLEAR)
	kevn[0].Fflags = encode(w.eDir | w.eNonDir)
	if _, err := syscall.Kevent(k.fd, kevn[:], nil, nil); err != nil {
		return err
	}
	if !ok {
		k.idLkp[w.fd], k.pthLkp[w.p] = w, w
		return nil
	}
	return errAlreadyWatched
}
예제 #3
0
func (this *watcher) doDel(path string) error {
	info, found := this.watchedByPath[path]
	if !found {
		return errors.Newf("can't remove non-existent kevent watch for: %s", path)
	}

	var kbuf [1]syscall.Kevent_t
	watchEntry := &kbuf[0]
	syscall.SetKevent(watchEntry, info.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	entryFlags := watchEntry.Flags
	success, errno := syscall.Kevent(this.kq, kbuf[:], nil, nil)
	if success == sysCallFailed {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if entryFlags&syscall.EV_ERROR == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(info.fd)

	//Remove childs if it's directory
	for _, child := range info.childes {
		this.doDel(child)
	}

	delete(this.watchedByPath, path)
	delete(this.watchedByFD, info.fd)

	return nil
}
예제 #4
0
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}

		s.Unlock()
		n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
		s.Lock()

		if err != nil {
			if err == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", err)
		}
		if n == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[:n]
	}
	ev := &p.events[0]
	p.events = p.events[1:]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}
예제 #5
0
func runKqueue() {
	fd, err := syscall.Kqueue()
	evTrackList := make([]syscall.Kevent_t, 1024)
	if err != nil {
		log.Fatal("error initializing Kqueue: ", err)
		return
	}

	addFilesToKqueue(evTrackList, path)

	// configure timeout
	timeout := syscall.Timespec{
		Sec:  0,
		Nsec: 0,
	}

	// wait for events
	for {
		// create kevent
		events := make([]syscall.Kevent_t, 10)
		_, err := syscall.Kevent(fd, evTrackList, events, &timeout)
		if err != nil {
			log.Println("Error creating kevent")
		}
		// check if there was an event and process it
		if len(events) > 0 && events[0].Ident > 0 {
			processEvent()
		}
	}
}
예제 #6
0
func (p *pollster) Kevent(nsec int64) (result int, events []net_event, err error) {
	var t *syscall.Timespec
	if nsec > 0 {
		if t == nil {
			t = new(syscall.Timespec)
		}
		*t = syscall.NsecToTimespec(nsec)
	}
	n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)

	if err != nil {
		if err == syscall.EINTR {
			return 0, nil, nil
		} else {
			return -1, nil, os.NewSyscallError("kevent", err)
		}
	}
	if n == 0 {
		return -2, nil, nil
	}
	events = make([]net_event, n)
	for i, ev := range p.eventbuf {
		events[i].fd = int(ev.Ident)
		events[i].data = int(ev.Data)
		if ev.Filter == syscall.EVFILT_READ {
			events[i].mode = 'r'
		} else {
			events[i].mode = 'w'
		}
	}
	return n, events, nil
}
예제 #7
0
// Poll the kqueue file descriptor and dispatch to the Event channels
func (w *Watcher) readEvents() {
	listener, _ := w.listener.(*kqueueListener)
	events := make([]syscall.Kevent_t, 10)

	for {
		if w.isDone() {
			return
		}

		n, err := syscall.Kevent(listener.kq, nil, events, nil)
		if err != nil {
			w.Error <- err
			continue
		}

		for _, ev := range events[:n] {
			pid := int(ev.Ident)

			switch ev.Fflags {
			case syscall.NOTE_FORK:
				w.Fork <- &ProcEventFork{ParentPid: pid}
			case syscall.NOTE_EXEC:
				w.Exec <- &ProcEventExec{Pid: pid}
			case syscall.NOTE_EXIT:
				w.RemoveWatch(pid)
				w.Exit <- &ProcEventExit{Pid: pid}
			}
		}
	}
}
예제 #8
0
파일: fd_darwin.go 프로젝트: 8l/go-learn
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}
		nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t)
		if e != 0 {
			if e == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", e)
		}
		if nn == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[0:nn]
	}
	ev := &p.events[0]
	p.events = p.events[1:len(p.events)]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}
예제 #9
0
파일: kqueue.go 프로젝트: jonsen/kqueue
func (k *Kqueue) Wait(buf []syscall.Kevent_t) (int, error) {
	n, err := syscall.Kevent(k.Fd, nil, buf, nil)
	if err != nil {
		return 0, os.NewSyscallError("kevent", err)
	}
	return n, nil
}
예제 #10
0
파일: fd_darwin.go 프로젝트: 8l/go-learn
func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_ADD - add event to kqueue list
	// EV_RECEIPT - generate fake EV_ERROR as result of add,
	//	rather than waiting for real event
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD | syscall.EV_RECEIPT
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, e := syscall.Kevent(p.kq, &events, &events, nil)
	if e != 0 {
		return os.NewSyscallError("kevent", e)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return os.ErrorString("kqueue phase error")
	}
	if ev.Data != 0 {
		return os.Errno(int(ev.Data))
	}
	return nil
}
예제 #11
0
파일: kqueue.go 프로젝트: noonat/runit
// read retrieves pending events, or waits until an event occurs.
// A timeout of nil blocks indefinitely, while 0 polls the queue.
func read(kq int, events []syscall.Kevent_t, timeout *syscall.Timespec) ([]syscall.Kevent_t, error) {
	n, err := syscall.Kevent(kq, nil, events, timeout)
	if err != nil {
		return nil, err
	}
	return events[0:n], nil
}
예제 #12
0
// AddWatch adds path to the watched file set.
// The flags are interpreted as described in kevent(2).
func (w *Watcher) addWatch(path string, flags uint32) error {
	if w.isClosed {
		return errors.New("kevent instance already closed")
	}

	watchEntry := &w.kbuf[0]
	watchEntry.Fflags = flags

	watchfd, found := w.watches[path]
	if !found {
		fd, errno := syscall.Open(path, syscall.O_NONBLOCK|syscall.O_RDONLY, 0700)
		if fd == -1 {
			return &os.PathError{"kevent_add_watch", path, errno}
		}
		watchfd = fd

		w.watches[path] = watchfd
		w.paths[watchfd] = path

		fi, _ := os.Stat(path)
		w.finfo[watchfd] = &fi
	}
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)

	wd, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if wd == -1 {
		return &os.PathError{"kevent_add_watch", path, errno}
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return &os.PathError{"kevent_add_watch", path, errors.New(fmt.Sprintf("%v", watchEntry.Data))}
	}

	return nil
}
예제 #13
0
// unwatch stops watching p file/directory.
func (k *kqueue) singleunwatch(p string, direct bool) error {
	w := k.pthLkp[p]
	if w == nil {
		return errNotWatched
	}
	if direct {
		w.eDir = 0
	} else {
		w.eNonDir = 0
	}
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	if _, err := syscall.Kevent(k.fd, kevn[:], nil, nil); err != nil {
		return err
	}
	if w.eNonDir&w.eDir != 0 {
		if err := k.singlewatch(p, w.eNonDir|w.eDir, w.eNonDir == 0,
			w.fi); err != nil {
			return err
		}
	} else {
		k.del(*w)
	}
	return nil
}
예제 #14
0
// RemoveWatch removes path from the watched file set.
func (w *Watcher) removeWatch(path string) error {
	w.wmut.Lock()
	watchfd, ok := w.watches[path]
	w.wmut.Unlock()
	if !ok {
		return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
	}
	w.bufmut.Lock()
	defer w.bufmut.Unlock()
	watchEntry := &w.kbuf[0]
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	success, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(watchfd)
	w.wmut.Lock()
	delete(w.watches, path)
	w.wmut.Unlock()
	w.enmut.Lock()
	delete(w.enFlags, path)
	w.enmut.Unlock()
	w.pmut.Lock()
	delete(w.paths, watchfd)
	delete(w.finfo, watchfd)
	w.pmut.Unlock()
	return nil
}
예제 #15
0
// First return value is whether the pollServer should be woken up.
// This version always returns false.
func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
	// pollServer is locked.

	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	ev := &p.kbuf[0]
	// EV_ADD - add event to kqueue list
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
	if err != nil {
		return false, os.NewSyscallError("kevent", err)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return false, os.NewSyscallError("kqueue phase error", err)
	}
	if ev.Data != 0 {
		return false, syscall.Errno(int(ev.Data))
	}
	return false, nil
}
예제 #16
0
// Watch implements trigger.
func (k *kq) Watch(fi os.FileInfo, w *watched, e int64) (err error) {
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE,
		syscall.EV_ADD|syscall.EV_CLEAR)
	kevn[0].Fflags = uint32(e)

	_, err = syscall.Kevent(k.fd, kevn[:], nil, nil)
	return
}
예제 #17
0
// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
	name = filepath.Clean(name)
	w.wmut.Lock()
	watchfd, ok := w.watches[name]
	w.wmut.Unlock()
	if !ok {
		return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
	}
	var kbuf [1]syscall.Kevent_t
	watchEntry := &kbuf[0]
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	entryFlags := watchEntry.Flags
	success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil)
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(watchfd)
	w.wmut.Lock()
	delete(w.watches, name)
	w.wmut.Unlock()
	w.enmut.Lock()
	delete(w.enFlags, name)
	w.enmut.Unlock()
	w.pmut.Lock()
	delete(w.paths, watchfd)
	fInfo := w.finfo[watchfd]
	delete(w.finfo, watchfd)
	w.pmut.Unlock()

	// Find all watched paths that are in this directory that are not external.
	if fInfo.IsDir() {
		var pathsToRemove []string
		w.pmut.Lock()
		for _, wpath := range w.paths {
			wdir, _ := filepath.Split(wpath)
			if filepath.Clean(wdir) == filepath.Clean(name) {
				w.ewmut.Lock()
				if !w.externalWatches[wpath] {
					pathsToRemove = append(pathsToRemove, wpath)
				}
				w.ewmut.Unlock()
			}
		}
		w.pmut.Unlock()
		for _, name := range pathsToRemove {
			// Since these are internal, not much sense in propagating error
			// to the user, as that will just confuse them with an error about
			// a path they did not explicitly watch themselves.
			w.Remove(name)
		}
	}

	return nil
}
예제 #18
0
// Wait implements trigger.
func (k *kq) Wait() (interface{}, error) {
	var (
		kevn [1]syscall.Kevent_t
		err  error
	)
	kevn[0] = syscall.Kevent_t{}
	_, err = syscall.Kevent(k.fd, nil, kevn[:], nil)

	return kevn[0], err
}
예제 #19
0
// RemoveWatch removes path from the watched file set.
func (w *Watcher) removeWatch(path string) error {
	w.wmut.Lock()
	watchfd, ok := w.watches[path]
	w.wmut.Unlock()
	if !ok {
		return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
	}
	w.bufmut.Lock()
	watchEntry := &w.kbuf[0]
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	success, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	w.bufmut.Unlock()
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(watchfd)
	w.wmut.Lock()
	delete(w.watches, path)
	w.wmut.Unlock()
	w.enmut.Lock()
	delete(w.enFlags, path)
	w.enmut.Unlock()
	w.pmut.Lock()
	delete(w.paths, watchfd)
	fInfo := w.finfo[watchfd]
	delete(w.finfo, watchfd)
	w.pmut.Unlock()

	// Find all watched paths that are in this directory that are not external.
	if fInfo.IsDir() {
		pathsToRemove := make([]string, 0)
		w.pmut.Lock()
		for _, wpath := range w.paths {
			wdir, _ := filepath.Split(wpath)
			if filepath.Clean(wdir) == filepath.Clean(path) {
				w.ewmut.Lock()
				if _, extern := w.externalWatches[wpath]; !extern {
					pathsToRemove = append(pathsToRemove, wpath)
				}
				w.ewmut.Unlock()
			}
		}
		w.pmut.Unlock()
		for idx := 0; idx < len(pathsToRemove); idx++ {
			// Since these are internal, not much sense in propogating error
			// to the user, as that will just confuse them with an error about
			// a path they did not explicitly watch themselves.
			w.removeWatch(pathsToRemove[idx])
		}
	}

	return nil
}
예제 #20
0
파일: kqueue_bsd.go 프로젝트: jonsen/kqueue
func (k *Kqueue) Add(fd uintptr, filter, flags int, fflags uint32) error {
	var buf [1]syscall.Kevent_t
	ev := &buf[0]
	flags = flags | syscall.EV_ADD
	evset(ev, fd, filter, flags, fflags)
	_, err := syscall.Kevent(k.Fd, buf[:], nil, nil)
	if err != nil {
		return os.NewSyscallError("kevent", err)
	}
	return nil
}
예제 #21
0
// Initialize Kevent_t fields and propagate changelist for the given pid
func (w *Watcher) kevent(pid int, fflags uint32, flags int) error {
	listener, _ := w.listener.(*kqueueListener)
	event := &listener.buf[0]

	syscall.SetKevent(event, pid, syscall.EVFILT_PROC, flags)
	event.Fflags = fflags

	_, err := syscall.Kevent(listener.kq, listener.buf[:], nil, nil)

	return err
}
예제 #22
0
func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, &events, nil, nil)
}
예제 #23
0
// init initializes kqueue.
func (k *kqueue) init() (err error) {
	if k.fd, err = syscall.Kqueue(); err != nil {
		return
	}
	// Creates pipe used to stop `Kevent` call by registering it,
	// watching read end and writing to other end of it.
	if err = syscall.Pipe(k.pipefds[:]); err != nil {
		return
	}
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], k.pipefds[0], syscall.EVFILT_READ, syscall.EV_ADD)
	_, err = syscall.Kevent(k.fd, kevn[:], nil, nil)
	return
}
예제 #24
0
func (p *pollster) DelFD(fd int, mode int) {
	// pollServer is locked.

	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	ev := &p.kbuf[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
}
예제 #25
0
파일: fd_darwin.go 프로젝트: 8l/go-learn
func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	// EV_RECEIPT - generate fake EV_ERROR as result of add,
	//	rather than waiting for real event
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
	syscall.Kevent(p.kq, &events, &events, nil)
}
예제 #26
0
func (p *pollster) DelFD(fd int, mode int) {
	// pollServer is locked.

	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	ev := &p.kbuf[0]
	// EV_DELETE - delete event from kqueue list
	// EV_RECEIPT - generate fake EV_ERROR as result of add,
	//	rather than waiting for real event
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
	syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
}
예제 #27
0
파일: kqueue.go 프로젝트: noonat/runit
// register events with the queue
func register(kq int, fds []int, flags int, fflags uint32) error {
	changes := make([]syscall.Kevent_t, len(fds))

	for i, fd := range fds {
		// SetKevent converts int to the platform-specific types:
		syscall.SetKevent(&changes[i], fd, syscall.EVFILT_VNODE, flags)
		changes[i].Fflags = fflags
	}

	// register the events
	success, err := syscall.Kevent(kq, changes, nil, nil)
	if success == -1 {
		return err
	}
	return nil
}
예제 #28
0
func (k *kqueue) add(fd uintptr, filter, flags int, fflags uint32) error {
	var buf [1]syscall.Kevent_t
	ev := &buf[0]
	flags = flags | syscall.EV_ADD | syscall.EV_RECEIPT
	evset(ev, fd, filter, flags, fflags)
	n, err := syscall.Kevent(k.fd, buf[:], buf[:], nil)
	if err != nil {
		return os.NewSyscallError("kevent", err)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || uintptr(ev.Ident) != fd || int(ev.Filter) != filter {
		return errors.New("kqueue phase error")
	}
	if ev.Data != 0 {
		return syscall.Errno(ev.Data)
	}
	return nil
}
예제 #29
0
// RemoveWatch removes path from the watched file set.
func (w *Watcher) RemoveWatch(path string) error {
	watchfd, ok := w.watches[path]
	if !ok {
		return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
	}
	syscall.Close(watchfd)
	watchEntry := &w.kbuf[0]
	syscall.SetKevent(watchEntry, w.watches[path], syscall.EVFILT_VNODE, syscall.EV_DELETE)
	success, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return os.NewSyscallError("kevent_rm_watch", errors.New(fmt.Sprintf("%v", watchEntry.Data)))
	}
	delete(w.watches, path)
	return nil
}
예제 #30
0
// monitor reads reported kqueue events and forwards them further after
// performing additional processing. If read event concerns directory,
// it generates Create/Remove event and sent them further instead of directory
// event. This event is detected based on reading contents of analyzed
// directory. If no changes in file list are detected, no event is send further.
// Reading directory structure is less accurate than kqueue and can lead
// to lack of detection of all events.
func (k *kqueue) monitor() {
	var (
		kevn [1]syscall.Kevent_t
		n    int
		err  error
	)
	for {
		kevn[0] = syscall.Kevent_t{}
		switch n, err = syscall.Kevent(k.fd, nil, kevn[:], nil); {
		case err == syscall.EINTR:
		case err != nil:
			dbgprintf("kqueue: failed to read events: %q\n", err)
		case int(kevn[0].Ident) == k.pipefds[0]:
			k.s <- struct{}{}
			return
		case n > 0:
			k.sendEvents(k.process(kevn[0]))
		}
	}
}