func doSelect(nfd int, r *syscall.FdSet, w *syscall.FdSet, e *syscall.FdSet, timeout *syscall.Timeval) (changed bool, err error) { err = syscall.Select(nfd, r, w, e, timeout) if err != nil { return false, err } return true, nil }
// WaitRead returns true if f can be readed without blocking or false if not or // error. func (s *syn) WaitRead(f *os.File) (bool, error) { pfd := s.pr.Fd() ffd := f.Fd() nfd := 1 if pfd < ffd { nfd += int(ffd) } else { nfd += int(pfd) } s.m.Lock() for { var r fdset r.Set(ffd) r.Set(pfd) n, err := syscall.Select(nfd, r.Sys(), nil, nil, nil) if err != nil { return false, err } if n > 0 { if r.IsSet(pfd) { // Command waits for access f. s.m.Unlock() return false, nil } return true, nil } } }
// WaitEvent can return dvb.ErrOverflow. If deadline is non zero time WaitEvent // returns true if it doesn't receive any event up to deatline. func (f API3) WaitEvent(ev *Event, deadline time.Time) (bool, error) { fd := f.Fd() if !deadline.IsZero() { timeout := deadline.Sub(time.Now()) if timeout <= 0 { return true, nil } var r syscall.FdSet r.Bits[fd/64] = 1 << (fd % 64) tv := syscall.NsecToTimeval(int64(timeout)) n, err := syscall.Select(int(fd+1), &r, nil, nil, &tv) if err != nil { return false, Error{"get", "event (select)", err} } if n == 0 { return true, nil } } _, _, e := syscall.Syscall( syscall.SYS_IOCTL, fd, _FE_GET_EVENT, uintptr(unsafe.Pointer(ev)), ) if e != 0 { if e == syscall.EOVERFLOW { return false, dvb.ErrOverflow } return false, Error{"get", "event", e} } return false, nil }
func main() { var ( rset, wset, eset syscall.FdSet still_running, curl_timeout int = 0, 0 err error ) ch1 := curl.EasyInit() ch2 := curl.EasyInit() ch1.Setopt(curl.OPT_URL, "http://www.163.com") ch1.Setopt(curl.OPT_HEADER, 0) ch1.Setopt(curl.OPT_VERBOSE, true) ch2.Setopt(curl.OPT_URL, "http://www.baidu.com") ch2.Setopt(curl.OPT_HEADER, 0) ch2.Setopt(curl.OPT_VERBOSE, true) mh := curl.MultiInit() mh.AddHandle(ch1) mh.AddHandle(ch2) for { FD_ZERO(&rset) FD_ZERO(&wset) FD_ZERO(&eset) timeout := syscall.Timeval{Sec: 1, Usec: 0} curl_timeout, err = mh.Timeout() if err != nil { fmt.Printf("Error multi_timeout: %s\n", err) } if curl_timeout >= 0 { timeout.Sec = int64(curl_timeout / 1000) if timeout.Sec > 1 { timeout.Sec = 1 } else { timeout.Usec = int64((curl_timeout % 1000)) * 1000 } } max_fd, err := mh.Fdset(&rset, &wset, &eset) if err != nil { fmt.Printf("Error FDSET: %s\n", err) } _, err = syscall.Select(int(max_fd+1), &rset, &wset, &eset, &timeout) if err != nil { fmt.Printf("Error select: %s\n", err) } else { still_running, err = mh.Perform() if still_running > 0 { fmt.Printf("Still running: %d\n", still_running) } else { break } } } }
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) { if p.nReady == 0 { var timeout *syscall.Timeval var tv syscall.Timeval timeout = nil if nsec > 0 { tv = syscall.NsecToTimeval(nsec) timeout = &tv } var n, e int var tmpReadFds, tmpWriteFds syscall.FdSet_t for { // Temporary syscall.FdSet_ts into which the values are copied // because select mutates the values. tmpReadFds = *p.readFds tmpWriteFds = *p.writeFds n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout) if e != syscall.EINTR { break } } if e != 0 { return -1, 0, os.NewSyscallError("select", e) } if n == 0 { return -1, 0, nil } p.nReady = n *p.readyReadFds = tmpReadFds *p.readyWriteFds = tmpWriteFds p.lastFd = 0 } flag := false for i := p.lastFd; i < p.maxFd+1; i++ { if syscall.FDIsSet(i, p.readyReadFds) { flag = true mode = 'r' syscall.FDClr(i, p.readyReadFds) } else if syscall.FDIsSet(i, p.readyWriteFds) { flag = true mode = 'w' syscall.FDClr(i, p.readyWriteFds) } if flag { if !syscall.FDIsSet(i, p.repeatFds) { p.DelFD(i, mode) } p.nReady-- p.lastFd = i return i, mode, nil } } // Will not reach here. Just to shut up the compiler. return -1, 0, nil }
func uxSelect(nfd int, r, w, e *fdSet, tv *syscall.Timeval) (n int, err error) { return syscall.Select(nfd, (*syscall.FdSet)(r), (*syscall.FdSet)(w), (*syscall.FdSet)(e), tv) }
// waitUntilReadable blocks until fd is readable. func waitUntilReadable(fd int) error { var fds syscall.FdSet fds.Bits[0] = 1 << uint(fd) for { _, err := syscall.Select(fd+1, &fds, nil, nil, nil) if err != nil { if err == EINTR { continue } return err } return nil // readable } }
func output(fd uintptr, out <-chan string, outready chan<- bool) { set := syscall.FdSet{} for { set.Bits[fd/64] = int32(fd) % 64 err := syscall.Select(int(fd+1), nil, &set, nil, nil) Assert(err == nil, "Select() for write on fd ", fd, ":", err) outready <- true cmd := <-out _, err = syscall.Write(int(fd), []byte(cmd)) Assert(err == nil, "Write() on fd ", fd, ":", err) } }
func (w *Watcher) fdSelect() { timeval := &syscall.Timeval{ Sec: 1, Usec: 0, } fdset := w.fds.FdSet() n, err := syscall.Select(int(w.fds[0]+1), nil, nil, fdset, timeval) if err != nil { fmt.Printf("failed to call syscall.Select, %s", err) os.Exit(1) } if n != 0 { w.notify(fdset) } }
func uxSelect(nfd int, r, w, e *fdSet, tv *syscall.Timeval) (n int, err error) { // The Go syscall.Select for the BSD unixes is buggy. It // returns only the error and not the number of active file // descriptors. To cope with this, we return "nfd" as the // number of active file-descriptors. This can cause // significant performance degradation but there's nothing // else we can do. err = syscall.Select(nfd, (*syscall.FdSet)(r), (*syscall.FdSet)(w), (*syscall.FdSet)(e), tv) if err != nil { return 0, err } return nfd, nil }
func Select(nfds int, readFds, writeFds *syscall.FdSet, timespec *Timespec) (int, error) { timeout := &syscall.Timeval{Sec: int64(timespec.Sec), Usec: int32(timespec.Nsec / 1000)} if err := syscall.Select(nfds, readFds, writeFds, nil, timeout); err != nil { return 0, err } else { max := 0 read := Fdset32{readFds.Bits} write := Fdset32{writeFds.Bits} fds := append(read.Fds(), write.Fds()...) for _, v := range fds { if v > max { max = v } } return max + 1, nil } }
func packetReader(t *DarwinTunTap) { var exit bool packet := make([]byte, 65535) fds := new(syscall.FdSet) fd := int(t.file.Fd()) FD_SET(fd, fds) for { // On Mac OS X, reading from the tun/tap device will do strange // things. We need to use syscall.Select. syscall.Select(fd+1, fds, nil, nil, nil) // We need to check whether we're to exit here - before the .Read() call // below, since the syscall above could have been terminated by the // closure of the associated fd. We do a non-blocking select that will // fall through to the default case if there is nothing to read from our // exit channel to determine this. select { case exit = <-t.exit: default: } if exit { log.Printf("Exit signal received\n") break } n, err := t.file.Read(packet) if err == io.EOF { break } else if err != nil { log.Printf("Error reading from tuntap: %s\n", err) // This wait is to stop us from getting stuck in an infinite loop // of reads that all error, and consuming 100% CPU forever. <-time.After(100 * time.Millisecond) continue } t.packets <- packet[0:n] } // This needs to be the last thing in the function. log.Printf("Done") t.finished <- true }
/*----------------------------------------------------------------------------- -- FUNCTION: read -- -- DATE: February 6, 2016 -- -- REVISIONS: February 11, 2016 - Modified for select -- -- DESIGNER: Marc Vouve -- -- PROGRAMMER: Marc Vouve -- -- INTERFACE: func fdSET(p *syscall.FdSet, i int) -- -- RETURNS: void -- -- NOTES: reimplementation of C macro ------------------------------------------------------------------------------*/ func serverInstance(srvInfo serverInfo) { var fdSet, rSet syscall.FdSet client := make(map[int]connectionInfo) highClient := srvInfo.listener fdZERO(&fdSet) fdSET(&fdSet, srvInfo.listener) for { copy(rSet.Bits[:], fdSet.Bits[:]) _, err := syscall.Select(highClient+1, &rSet, nil, nil, nil) if err != nil { log.Println("err", err) return // block shouldn't be hit under normal conditions. If it does something is really wrong. } if fdISSET(&rSet, srvInfo.listener) { // new client newClient, err := newConnection(srvInfo.listener) if err == nil { client[newClient.FileDescriptor] = newClient fdSET(&fdSet, newClient.FileDescriptor) srvInfo.serverConnection <- 1 if newClient.FileDescriptor > highClient { highClient = newClient.FileDescriptor } } } for conn := range client { socketfd := client[conn].FileDescriptor if fdISSET(&rSet, socketfd) { // existing connection connect := client[conn] err := handleData(&connect) client[conn] = connect if err != nil { if err != io.EOF { log.Println(err) } fdCLEAR(&fdSet, client[conn].FileDescriptor) endConnection(srvInfo, client[conn]) delete(client, conn) } } } } }
func (g *GPIO) Wait() (bool, error) { if g.fd == 0 { fd, err := syscall.Open(g.valuePath, syscall.O_RDONLY, 0666) if err != nil { return false, err } g.fd = fd g.fdSet = new(syscall.FdSet) FD_SET(g.fd, g.fdSet) g.buf = make([]byte, 64) syscall.Read(g.fd, g.buf) } syscall.Select(g.fd+1, nil, nil, g.fdSet, nil) syscall.Seek(g.fd, 0, 0) _, err := syscall.Read(g.fd, g.buf) if err != nil { return false, err } return string(g.buf[:2]) == "1\n", nil }
func (p *poller) loop(timeout time.Duration) error { var rset, wset syscall.FdSet var numfd int set(&rset, p.pr.Fd(), &numfd) tv := toTimeval(timeout) n, err := syscall.Select(numfd+1, &rset, &wset, nil, &tv) if err != nil { return err } for fd := uintptr(0); n > 0 && fd <= uintptr(numfd); fd++ { if isset(&rset, fd) { n-- log.Println(fd, "read") } if isset(&wset, fd) { n-- log.Println(fd, "write") } } return nil }
func waitWithTimeout(socket int, timeout time.Duration) (state SocketState, err error) { wfdset := &syscall.FdSet{} FD_ZERO(wfdset) FD_SET(wfdset, socket) timeval := syscall.NsecToTimeval(int64(timeout)) syscall.Select(socket+1, nil, wfdset, nil, &timeval) errcode, err := syscall.GetsockoptInt(socket, syscall.SOL_SOCKET, syscall.SO_ERROR) if err != nil { state = SocketError return } if errcode == int(syscall.EHOSTUNREACH) { state = SocketNotReached return } if errcode == int(syscall.ECONNREFUSED) { state = SocketPortClosed return } if errcode != 0 { state = SocketError err = fmt.Errorf("Connect Error: %v", errcode) return } if FD_ISSET(wfdset, socket) { state = SocketConnected } else { state = SocketTimedOut } return }
// Read reads from serial port. Port must be opened before calling this method. // It is blocked until all data received or timeout after p.timeout. func (p *port) Read(b []byte) (n int, err error) { var rfds syscall.FdSet fd := int(p.file.Fd()) fdSet(fd, &rfds) var tv *syscall.Timeval if p.timeout > 0 { timeout := syscall.NsecToTimeval(p.timeout.Nanoseconds()) tv = &timeout } if err = syscall.Select(fd+1, &rfds, nil, nil, tv); err != nil { err = fmt.Errorf("serial: could not select: %v", err) return } if !fdIsSet(fd, &rfds) { // Timeout err = ErrTimeout return } n, err = p.file.Read(b) return }
// Returns errors (if any) triggered by the inotify subsystem or when reading // the file. Errors when writing to the writer are ignored. func streamFile(writer io.Writer, path string, maxIdleTime uint32) error { handle, err := os.Open(path) if err != nil { return err } _, err = handle.Seek(0, os.SEEK_END) if err != nil { handle.Close() return err } reader := bufio.NewReader(handle) readBuffer := make([]byte, 4096) inotifyFd, err := syscall.InotifyInit() if err != nil { handle.Close() return err } watchDesc, err := syscall.InotifyAddWatch(inotifyFd, path, syscall.IN_MODIFY) if err != nil { syscall.Close(inotifyFd) handle.Close() return err } eventsBuffer := make([]byte, syscall.SizeofInotifyEvent*4096) selectMaxIdleTime := syscall.Timeval{} selectMaxIdleTime.Sec = int64(maxIdleTime) inotifyFdSet := syscall.FdSet{} lastWriteTime := time.Now() canScan := true for canScan && !timeout(lastWriteTime, maxIdleTime) { clearAll(&inotifyFdSet) set(&inotifyFdSet, inotifyFd) _, err := syscall.Select(inotifyFd+1, &inotifyFdSet, nil, nil, &selectMaxIdleTime) if err != nil { break } if !isSet(&inotifyFdSet, inotifyFd) { continue } numEventsBytes, err := syscall.Read(inotifyFd, eventsBuffer[0:]) if numEventsBytes < syscall.SizeofInotifyEvent { if numEventsBytes < 0 { err = errors.New("inotify: read failed.") } else { err = errors.New("inotify: short read.") } break } var offset uint32 = 0 for offset <= uint32(numEventsBytes-syscall.SizeofInotifyEvent) { event := (*syscall.InotifyEvent)(unsafe. Pointer(&eventsBuffer[offset])) n, err := reader.Read(readBuffer) if err != nil { // Ignore the EOF error and continue polling // the file until timeout. if err == io.EOF { err = nil } break } buffer := make([]byte, n) for index := 0; index < n; index++ { buffer[index] = readBuffer[index] } _, err = writer.Write(buffer) if err != nil { // Stop scanning for updates to the file. canScan = false // Ignore the write error. err = nil break } lastWriteTime = time.Now() // Move to the next event. offset += syscall.SizeofInotifyEvent + event.Len } } // The inotify watch gets automatically removed by the inotify system // when the file is removed. If the above loop times out, but the file // is removed only just before the if block below is executed, then the // removal of the watch below will throw an error as the watch // descriptor is obsolete. We ignore this error because it is harmless. syscall.InotifyRmWatch(inotifyFd, uint32(watchDesc)) // Though we return the first error that occured, we still need to // attempt to close all the file descriptors. inotifyCloseErr := syscall.Close(inotifyFd) handleCloseErr := handle.Close() if err != nil { return err } else if inotifyCloseErr != nil { return inotifyCloseErr } return handleCloseErr }
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { if p.nReady == 0 { var timeout *syscall.Timeval var tv syscall.Timeval timeout = nil if nsec > 0 { tv = syscall.NsecToTimeval(nsec) timeout = &tv } var n int var e error var tmpReadFds, tmpWriteFds syscall.FdSet for { if p.closed { return -1, 0, errors.New("pollster closed") } // Temporary syscall.FdSet's into which the values are copied // because select mutates the values. tmpReadFds = *p.readFds tmpWriteFds = *p.writeFds s.Unlock() n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout) s.Lock() if e != syscall.EINTR { break } } if e == syscall.EBADF { // Some file descriptor has been closed. tmpReadFds = syscall.FdSet{} tmpWriteFds = syscall.FdSet{} n = 0 for i := 0; i < p.maxFd+1; i++ { if syscall.FDIsSet(i, p.readFds) { var s syscall.Stat_t if syscall.Fstat(i, &s) == syscall.EBADF { syscall.FDSet(i, &tmpReadFds) n++ } } else if syscall.FDIsSet(i, p.writeFds) { var s syscall.Stat_t if syscall.Fstat(i, &s) == syscall.EBADF { syscall.FDSet(i, &tmpWriteFds) n++ } } } } else if e != nil { return -1, 0, os.NewSyscallError("select", e) } if n == 0 { return -1, 0, nil } p.nReady = n *p.readyReadFds = tmpReadFds *p.readyWriteFds = tmpWriteFds p.lastFd = 0 } flag := false for i := p.lastFd; i < p.maxFd+1; i++ { if syscall.FDIsSet(i, p.readyReadFds) { flag = true mode = 'r' syscall.FDClr(i, p.readyReadFds) } else if syscall.FDIsSet(i, p.readyWriteFds) { flag = true mode = 'w' syscall.FDClr(i, p.readyWriteFds) } if flag { if !syscall.FDIsSet(i, p.repeatFds) { p.DelFD(i, mode) } p.nReady-- p.lastFd = i return i, mode, nil } } // Will not reach here. Just to shut up the compiler. return -1, 0, nil }
func Select(nfd int, r *syscall.FdSet, w *syscall.FdSet, e *syscall.FdSet, timeout *syscall.Timeval) error { _, err := syscall.Select(nfd, r, w, e, timeout) return err }
func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *syscall.Timeval) error { _, err := syscall.Select(nfd, r.s(), w.s(), e.s(), timeout) return err }
func sysSelect(n int, r, w, e *FDSet, timeout *syscall.Timeval) error { _, err := syscall.Select(n, (*syscall.FdSet)(r), (*syscall.FdSet)(w), (*syscall.FdSet)(e), timeout) return err }
func selectFds(n int, r, w, e *syscall.FdSet, t *syscall.Timeval) (errno int) { _, errno = syscall.Select(n, r, w, e, t) return }
func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *syscall.Timeval) (err error) { return syscall.Select(nfd, r.s(), w.s(), e.s(), timeout) }
func cgcNativeSelect(nfds int, readFds, writeFds *syscall.FdSet, timespec *posix.Timespec) (int, error) { // TODO: 32-bit vs 64-bit timeout := &syscall.Timeval{Sec: int64(timespec.Sec), Usec: int64(timespec.Nsec / 1000)} return syscall.Select(nfds, readFds, writeFds, nil, timeout) }
func (sock fd) connectTimeout(addr ax25Addr, timeout time.Duration) (err error) { if timeout == 0 { return sock.connect(addr) } if err = syscall.SetNonblock(int(sock), true); err != nil { return err } err = sock.connect(addr) if err == nil { return nil // Connected } else if err != syscall.EINPROGRESS { return fmt.Errorf("Unable to connect: %s", err) } // Shamelessly stolen from src/pkg/exp/inotify/inotify_linux.go: // // Create fdSet, taking into consideration that // 64-bit OS uses Bits: [16]int64, while 32-bit OS uses Bits: [32]int32. // This only support File Descriptors up to 1024 // if sock > 1024 { panic(fmt.Errorf("connectTimeout: File Descriptor >= 1024: %v", sock)) } fdset := new(syscall.FdSet) fElemSize := 32 * 32 / len(fdset.Bits) fdset.Bits[int(sock)/fElemSize] |= 1 << uint(int(sock)%fElemSize) // // Thanks! // // Wait or timeout var n int var tv syscall.Timeval for { tv = syscall.NsecToTimeval(int64(timeout)) n, err = syscall.Select(int(sock)+1, nil, fdset, nil, &tv) if n < 0 && err != syscall.EINTR { return fmt.Errorf("Unable to connect: %s", err) } else if n > 0 { /* TODO: verify that connection is OK * lon = sizeof(int); * if (getsockopt(soc, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) { * fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); * exit(0); * } * // Check the value returned... * if (valopt) { * fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)); * exit(0); * } */ break } else { return fmt.Errorf("Unable to connect: timeout") } } syscall.SetNonblock(int(sock), false) return }
func main() { log.SetFlags(log.Lshortfile) // Create UDP socket fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { log.Fatalln(err) } // Ask operating system to let us do broadcasts from socket if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1); err != nil { log.Fatalln(err) } // Bind UDP socket to local port so we can receive pings if err := syscall.Bind(fd, &syscall.SockaddrInet4{Port: PING_PORT_NUMBER, Addr: [4]byte{0, 0, 0, 0}}); err != nil { log.Fatalln(err) } buffer := make([]byte, PING_MSG_SIZE) // We use syscall.Select to wait for activity on the UDP socket. // We send a beacon once a second, and we collect and report // beacons that come in from other nodes: rfds := &syscall.FdSet{} timeout := &syscall.Timeval{} // Send first ping right away ping_at := time.Now() bcast := &syscall.SockaddrInet4{Port: PING_PORT_NUMBER, Addr: [4]byte{255, 255, 255, 255}} for { dur := int64(ping_at.Sub(time.Now()) / time.Microsecond) if dur < 0 { dur = 0 } timeout.Sec, timeout.Usec = dur/1000000, dur%1000000 FD_ZERO(rfds) FD_SET(rfds, fd) _, err := syscall.Select(fd+1, rfds, nil, nil, timeout) if err != nil { log.Fatalln(err) } // Someone answered our ping if FD_ISSET(rfds, fd) { _, addr, err := syscall.Recvfrom(fd, buffer, 0) if err != nil { log.Fatalln(err) } a := addr.(*syscall.SockaddrInet4) fmt.Printf("Found peer %v.%v.%v.%v:%v\n", a.Addr[0], a.Addr[1], a.Addr[2], a.Addr[3], a.Port) } if time.Now().After(ping_at) { // Broadcast our beacon fmt.Println("Pinging peers...") buffer[0] = '!' if err := syscall.Sendto(fd, buffer, 0, bcast); err != nil { log.Fatalln(err) } ping_at = time.Now().Add(PING_INTERVAL) } } }
func nativeSelect(nfds int, readfds, writefds, errorfds *syscall.FdSet, timeout *syscall.Timeval) error { _, err := syscall.Select(nfds, readfds, writefds, errorfds, timeout) return err }
func Select(nfds int, readFds, writeFds *syscall.FdSet, timespec *Timespec) (int, error) { return syscall.Select(nfds, readFds, writeFds, nil, timespec.Native()) }
// readEvents reads from the inotify file descriptor, converts the // received events into Event objects and sends them via the Event channel func (w *Watcher) readEvents() { var buf [syscall.SizeofInotifyEvent * 4096]byte // Timeout after 500 milliseconds when waiting for events // so we can reliably close the Watcher timeout := int64(500e6) readFds := newFdSet(w.fd) for { var n int var err error select { // See if there is a message on the "done" channel case <-w.done: // Otherwise select fd with timeout default: tmpSet := *readFds timeval := syscall.NsecToTimeval(timeout) n, err = syscall.Select(w.fd+1, &tmpSet, nil, nil, &timeval) if n == 1 { n, err = syscall.Read(w.fd, buf[0:]) } else if err != nil { w.Error <- err } else { continue } } // If EOF or a "done" message is received if n == 0 { goto done } if n < 0 { w.Error <- os.NewSyscallError("read", err) continue } if n < syscall.SizeofInotifyEvent { w.Error <- errors.New("inotify: short read in readEvents()") continue } var offset uint32 = 0 // We don't know how many events we just read into the buffer // While the offset points to at least one whole event... for offset <= uint32(n-syscall.SizeofInotifyEvent) { // Point "raw" to the event in the buffer raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) event := new(Event) event.Mask = uint32(raw.Mask) event.Cookie = uint32(raw.Cookie) nameLen := uint32(raw.Len) // If the event happened to the watched directory or the watched file, the kernel // doesn't append the filename to the event, but we would like to always fill the // the "Name" field with a valid filename. We retrieve the path of the watch from // the "paths" map. w.mu.Lock() event.Name = w.paths[int(raw.Wd)] // Check if the the watch was removed if event.Mask&IN_IGNORED != 0 { // remove stale watch delete(w.watches, event.Name) delete(w.paths, int(raw.Wd)) } w.mu.Unlock() if nameLen > 0 { // Point "bytes" at the first byte of the filename bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent])) // The filename is padded with NUL bytes. TrimRight() gets rid of those. event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") } // Send the event on the events channel w.Event <- event // Move to the next event in the buffer offset += syscall.SizeofInotifyEvent + nameLen } } done: w.isClosed = true // keep API behaviour consistent when EOF was read err := syscall.Close(w.fd) if err != nil { w.Error <- os.NewSyscallError("close", err) } close(w.Event) close(w.Error) for path, watch := range w.watches { delete(w.watches, path) delete(w.paths, int(watch.wd)) } }