func (i *inotify) loop(esch chan<- []*event) {
	epes := make([]unix.EpollEvent, 1)
	fd := atomic.LoadInt32(&i.fd)
	for {
		switch _, err := unix.EpollWait(i.epfd, epes, -1); err {
		case nil:
			switch epes[0].Fd {
			case fd:
				esch <- i.read()
				epes[0].Fd = 0
			case int32(i.pipefd[0]):
				i.Lock()
				defer i.Unlock()
				if err = unix.Close(int(fd)); err != nil && err != unix.EINTR {
					panic("notify: close(2) error " + err.Error())
				}
				atomic.StoreInt32(&i.fd, invalidDescriptor)
				if err = i.epollclose(); err != nil && err != unix.EINTR {
					panic("notify: epollclose error " + err.Error())
				}
				close(esch)
				return
			}
		case unix.EINTR:
			continue
		default:  
			panic("notify: epoll_wait(2) error " + err.Error())
		}
	}
}
loop blocks until either inotify or pipe file descriptor is ready for I/O.
All read operations triggered by filesystem notifications are forwarded to
one of the event's consumers. If pipe fd became ready, loop function closes
all file descriptors opened by lazyinit method and returns afterwards.
package notify
import (
	"bytes"
	"errors"
	"path/filepath"
	"runtime"
	"sync"
	"sync/atomic"
	"unsafe"
	"golang.org/x/sys/unix"
)
const eventBufferSize = 64 * (unix.SizeofInotifyEvent + unix.PathMax + 1)
const consumersCount = 2
const invalidDescriptor = -1
type watched struct {
	path string
	mask uint32
}
type inotify struct {
	sync.RWMutex                        
	m            map[int32]*watched     
	fd           int32                  
	pipefd       []int                  
	epfd         int                    
	epes         []unix.EpollEvent      
	buffer       [eventBufferSize]byte  
	wg           sync.WaitGroup         
	c            chan<- EventInfo       
}
func newWatcher(c chan<- EventInfo) watcher {
	i := &inotify{
		m:      make(map[int32]*watched),
		fd:     invalidDescriptor,
		pipefd: []int{invalidDescriptor, invalidDescriptor},
		epfd:   invalidDescriptor,
		epes:   make([]unix.EpollEvent, 0),
		c:      c,
	}
	runtime.SetFinalizer(i, func(i *inotify) {
		i.epollclose()
		if i.fd != invalidDescriptor {
			unix.Close(int(i.fd))
		}
	})
	return i
}
func (i *inotify) Watch(path string, e Event) error {
	return i.watch(path, e)
}
func (i *inotify) Rewatch(path string, _, newevent Event) error {
	return i.watch(path, newevent)
}
func (i *inotify) watch(path string, e Event) (err error) {
	if e&^(All|Event(unix.IN_ALL_EVENTS)) != 0 {
		return errors.New("notify: unknown event")
	}
	if err = i.lazyinit(); err != nil {
		return
	}
	iwd, err := unix.InotifyAddWatch(int(i.fd), path, encode(e))
	if err != nil {
		return
	}
	i.RLock()
	wd := i.m[int32(iwd)]
	i.RUnlock()
	if wd == nil {
		i.Lock()
		if i.m[int32(iwd)] == nil {
			i.m[int32(iwd)] = &watched{path: path, mask: uint32(e)}
		}
		i.Unlock()
	} else {
		i.Lock()
		wd.mask = uint32(e)
		i.Unlock()
	}
	return nil
}
func (i *inotify) lazyinit() error {
	if atomic.LoadInt32(&i.fd) == invalidDescriptor {
		i.Lock()
		defer i.Unlock()
		if atomic.LoadInt32(&i.fd) == invalidDescriptor {
			fd, err := unix.InotifyInit1(unix.IN_CLOEXEC)
			if err != nil {
				return err
			}
			i.fd = int32(fd)
			if err = i.epollinit(); err != nil {
				_, _ = i.epollclose(), unix.Close(int(fd))  
				i.fd = invalidDescriptor
				return err
			}
			esch := make(chan []*event)
			go i.loop(esch)
			i.wg.Add(consumersCount)
			for n := 0; n < consumersCount; n++ {
				go i.send(esch)
			}
		}
	}
	return nil
}
func (i *inotify) epollinit() (err error) {
	if i.epfd, err = unix.EpollCreate1(0); err != nil {
		return
	}
	if err = unix.Pipe(i.pipefd); err != nil {
		return
	}
	i.epes = []unix.EpollEvent{
		{Events: unix.EPOLLIN, Fd: i.fd},
		{Events: unix.EPOLLIN, Fd: int32(i.pipefd[0])},
	}
	if err = unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil {
		return
	}
	return unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1])
}
func (i *inotify) epollclose() (err error) {
	if i.epfd != invalidDescriptor {
		if err = unix.Close(i.epfd); err == nil {
			i.epfd = invalidDescriptor
		}
	}
	for n, fd := range i.pipefd {
		if fd != invalidDescriptor {
			switch e := unix.Close(fd); {
			case e != nil && err == nil:
				err = e
			case e == nil:
				i.pipefd[n] = invalidDescriptor
			}
		}
	}
	return
}