diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2015-09-05 13:59:36 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2015-09-05 13:59:36 -0600 |
commit | a3e3251f2ef27ddb33a74a679729d6d5447307b5 (patch) | |
tree | f39f5c50e139291597265c0a83339f02b4307eb3 /src/inotify/inotify.go | |
parent | adc8af1a3a0d9077621d2b9b5e36b33452f31947 (diff) |
inotify: Avoid most of the race conditions, get rid of Cint
There's still a condition that could be a race with fd-reuse, if one
goroutine is calling inotify.{AddWatch,RmWatch,Read}(); another
goroutine is calling inotify.Close(), and several things happen between
loadFd() running and the add_watch/rm_watch/read syscall launching:
- syscall.Close() returns
- syscall.Open() reuses the filedescriptor
A B
syscall(loadFd()) inotify.Close(); syscall.Open()
----------------------------------------------------------
loadFd()
syscall.Close()
syscall.Open()
syscall()
Given that Read() can't be allowed to block Close() from running, I'm not
sure there's a way to fix this.
Diffstat (limited to 'src/inotify/inotify.go')
-rw-r--r-- | src/inotify/inotify.go | 50 |
1 files changed, 18 insertions, 32 deletions
diff --git a/src/inotify/inotify.go b/src/inotify/inotify.go index 6d74830..f7db1b0 100644 --- a/src/inotify/inotify.go +++ b/src/inotify/inotify.go @@ -1,23 +1,21 @@ package inotify import ( - "errors" "syscall" "unsafe" + "sync" ) -var InotifyAlreadyClosedError error = errors.New("inotify instance already closed") - type Inotify struct { - fd Cint - isClosed bool + fd Fd fullbuff [4096]byte buff []byte + buffLock sync.Mutex } type Event struct { - Wd Cint /* Watch descriptor */ + Wd Wd /* Watch descriptor */ Mask Mask /* Mask describing event */ Cookie uint32 /* Unique cookie associating related events (for rename(2)) */ Name *string /* Optional name */ @@ -26,54 +24,42 @@ type Event struct { func InotifyInit() (*Inotify, error) { fd, err := inotify_init() o := Inotify{ - fd: Cint(fd), - isClosed: false, + fd: fd, } o.buff = o.fullbuff[:0] return &o, err } -func InotifyInit1(flags Cint) (*Inotify, error) { +func InotifyInit1(flags int) (*Inotify, error) { fd, err := inotify_init1(flags) o := Inotify{ - fd: Cint(fd), - isClosed: false, + fd: fd, } o.buff = o.fullbuff[:0] return &o, err } -func (o *Inotify) AddWatch(path string, mask Mask) (Cint, error) { - if o.isClosed { - return -1, InotifyAlreadyClosedError - } - return inotify_add_watch(o.fd, path, uint32(mask)) +func (o *Inotify) AddWatch(path string, mask Mask) (Wd, error) { + return inotify_add_watch(loadFd(&o.fd), path, mask) } -func (o *Inotify) RmWatch(wd Cint) error { - if o.isClosed { - return InotifyAlreadyClosedError - } - return inotify_rm_watch(o.fd, wd) +func (o *Inotify) RmWatch(wd Wd) error { + return inotify_rm_watch(loadFd(&o.fd), wd) } func (o *Inotify) Close() error { - if o.isClosed { - return InotifyAlreadyClosedError - } - o.isClosed = true - return sysclose(o.fd) + return sysclose(swapFd(&o.fd, -1)) } func (o *Inotify) Read() (Event, error) { + o.buffLock.Lock() + defer o.buffLock.Unlock() + if len(o.buff) == 0 { - if o.isClosed { - return Event{Wd: -1}, InotifyAlreadyClosedError - } - len, err := sysread(o.fd, o.buff) + len, err := sysread(loadFd(&o.fd), o.buff) if len == 0 { return Event{Wd: -1}, o.Close() - } else if len <= 0 { + } else if len < 0 { return Event{Wd: -1}, err } o.buff = o.fullbuff[0:len] @@ -81,7 +67,7 @@ func (o *Inotify) Read() (Event, error) { raw := (*syscall.InotifyEvent)(unsafe.Pointer(&o.buff[0])) ret := Event{ - Wd: Cint(raw.Wd), + Wd: Wd(raw.Wd), Mask: Mask(raw.Mask), Cookie: raw.Cookie, Name: nil, |