func GetProcessNameMap() map[uint32]string { defer metrics("GetProcessNameMap")(time.Now()) snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) if err != nil { common.Error("Fail to syscall CreateToolhelp32Snapshot: %v", err) return nil } defer syscall.CloseHandle(snapshot) var procEntry syscall.ProcessEntry32 procEntry.Size = uint32(unsafe.Sizeof(procEntry)) if err = syscall.Process32First(snapshot, &procEntry); err != nil { common.Error("Fail to syscall Process32First: %v", err) return nil } processNameMap := make(map[uint32]string) for { processNameMap[procEntry.ProcessID] = parseProcessName(procEntry.ExeFile) if err = syscall.Process32Next(snapshot, &procEntry); err != nil { if err == syscall.ERROR_NO_MORE_FILES { return processNameMap } common.Error("Fail to syscall Process32Next: %v", err) return nil } } }
// mmap memory maps a DB's data file. // Based on: https://github.com/edsrzf/mmap-go func mmap(db *DB, sz int) error { if !db.readOnly { // Truncate the database to the size of the mmap. if err := db.file.Truncate(int64(sz)); err != nil { return fmt.Errorf("truncate: %s", err) } } // Open a file mapping handle. sizelo := uint32(sz >> 32) sizehi := uint32(sz) & 0xffffffff h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil) if h == 0 { return os.NewSyscallError("CreateFileMapping", errno) } // Create the memory map. addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz)) if addr == 0 { return os.NewSyscallError("MapViewOfFile", errno) } // Close mapping handle. if err := syscall.CloseHandle(syscall.Handle(h)); err != nil { return os.NewSyscallError("CloseHandle", err) } // Convert to a byte array. db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr))) db.datasz = sz return nil }
func (sub *Subprocess) BottomHalf(d *SubprocessData, sig chan *SubprocessResult) { hProcess := d.platformData.hProcess hJob := d.platformData.hJob result := &SubprocessResult{} var waitResult uint32 waitResult = syscall.WAIT_TIMEOUT var runState runningState for result.SuccessCode == 0 && waitResult == syscall.WAIT_TIMEOUT { waitResult, _ = syscall.WaitForSingleObject(hProcess, uint32(sub.TimeQuantum.Nanoseconds()/1000000)) if waitResult != syscall.WAIT_TIMEOUT { break } _ = UpdateProcessTimes(&d.platformData, result, false) if sub.MemoryLimit > 0 { UpdateProcessMemory(&d.platformData, result) } runState.Update(sub, result) } switch waitResult { case syscall.WAIT_OBJECT_0: _ = syscall.GetExitCodeProcess(hProcess, &result.ExitCode) case syscall.WAIT_TIMEOUT: for waitResult == syscall.WAIT_TIMEOUT { syscall.TerminateProcess(hProcess, 0) waitResult, _ = syscall.WaitForSingleObject(hProcess, 100) } } _ = UpdateProcessTimes(&d.platformData, result, true) UpdateProcessMemory(&d.platformData, result) syscall.CloseHandle(hProcess) if hJob != syscall.InvalidHandle { syscall.CloseHandle(hJob) } sub.SetPostLimits(result) for _ = range d.startAfterStart { err := <-d.bufferChan if err != nil { log.Error(err) } } if d.stdOut.Len() > 0 { result.Output = d.stdOut.Bytes() } if d.stdErr.Len() > 0 { result.Error = d.stdErr.Bytes() } sig <- result }
func (d *PlatformData) terminateAndClose() (err error) { if err = terminateProcessLoop(d.hProcess); err != nil { return } syscall.CloseHandle(d.hThread) syscall.CloseHandle(d.hProcess) return }
func RunAndCollectSysStats(cmd *exec.Cmd, res *Result, N uint64, prefix string) (string, error) { initJobOnce.Do(initJob) childMu.Lock() children := childProcesses childProcesses = []syscall.Handle{} childMu.Unlock() for _, proc := range children { syscall.CloseHandle(proc) } var out bytes.Buffer cmd.Stdout = &out cmd.Stderr = &out t0 := time.Now() if err := cmd.Run(); err != nil { return out.String(), err } t1 := time.Now() res.RunTime = uint64(t1.Sub(t0)) / N res.Metrics[prefix+"time"] = res.RunTime childMu.Lock() children = childProcesses childProcesses = []syscall.Handle{} childMu.Unlock() if len(children) == 0 { log.Printf("sysStats.Collect: no child processes?") return out.String(), nil } defer func() { for _, proc := range children { syscall.CloseHandle(proc) } }() cputime := uint64(0) rss := uint64(0) for _, proc := range children { var Mem PROCESS_MEMORY_COUNTERS if err := getProcessMemoryInfo(proc, &Mem); err != nil { log.Printf("GetProcessMemoryInfo failed: %v", err) return out.String(), nil } var CPU syscall.Rusage if err := syscall.GetProcessTimes(proc, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil { log.Printf("GetProcessTimes failed: %v", err) return out.String(), nil } cputime += getCPUTime(CPU) / N rss += uint64(Mem.PeakWorkingSetSize) } res.Metrics[prefix+"cputime"] = cputime res.Metrics[prefix+"rss"] = rss return out.String(), nil }
func (d *dev) Close() (err error) { d.Drain() syscall.CloseHandle(d.ev.r) syscall.CloseHandle(d.ev.w) if e := syscall.CloseHandle(d.fd); e != nil { err = d.error("close", e) } return nil }
// Login and load user profile. Also, set finalizer on s to logout() above. func (s *LoginInfo) Prepare() error { var err error if s.Username == "" { return nil } ec := tools.ErrorContext("LoginInfo.Prepare") s.HUser, err = win32.LogonUser( syscall.StringToUTF16Ptr(s.Username), syscall.StringToUTF16Ptr("."), syscall.StringToUTF16Ptr(s.Password), win32.LOGON32_LOGON_INTERACTIVE, win32.LOGON32_PROVIDER_DEFAULT) if err != nil { return ec.NewError(err) } s.HProfile, err = loadProfile(s.HUser, s.Username) if err != nil { syscall.CloseHandle(s.HUser) s.HUser = syscall.InvalidHandle return ec.NewError(err) } runtime.SetFinalizer(s, logout) return nil }
// TODO(pknap) : doc func (r *readdcw) loop() { var n, key uint32 var overlapped *syscall.Overlapped for { err := syscall.GetQueuedCompletionStatus(r.cph, &n, &key, &overlapped, syscall.INFINITE) if key == stateCPClose { r.Lock() handle := r.cph r.cph = syscall.InvalidHandle r.Unlock() syscall.CloseHandle(handle) r.wg.Done() return } if overlapped == nil { // TODO: check key == rewatch delete or 0(panic) continue } overEx := (*overlappedEx)(unsafe.Pointer(overlapped)) if n == 0 { r.loopstate(overEx) } else { r.loopevent(n, overEx) if err = overEx.parent.readDirChanges(); err != nil { // TODO: error handling } } } }
func TestCreateToolhelp32Snapshot(t *testing.T) { handle, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) if err != nil { t.Fatal(err) } defer syscall.CloseHandle(syscall.Handle(handle)) // Iterate over the snapshots until our PID is found. pid := uint32(syscall.Getpid()) for { process, err := Process32Next(handle) if errors.Cause(err) == syscall.ERROR_NO_MORE_FILES { break } if err != nil { t.Fatal(err) } t.Logf("CreateToolhelp32Snapshot: ProcessEntry32=%v", process) if process.ProcessID == pid { assert.EqualValues(t, syscall.Getppid(), process.ParentProcessID) return } } assert.Fail(t, "Snapshot not found for PID=%v", pid) }
// findExePath searches for process pid, and returns its executable path. func findExePath(pid int) (string, error) { // Original code suggested different approach (see below). // Maybe it could be useful in the future. // // Find executable path from PID/handle on Windows: // https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx p, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid)) if err != nil { return "", err } defer syscall.CloseHandle(p) n := uint32(128) for { buf := make([]uint16, int(n)) err = _QueryFullProcessImageName(p, 0, &buf[0], &n) switch err { case syscall.ERROR_INSUFFICIENT_BUFFER: // try bigger buffer n *= 2 // but stop if it gets too big if n > 10000 { return "", err } case nil: return syscall.UTF16ToString(buf[:n]), nil default: return "", err } } }
func (s *winSys) loadFileId() error { if s.path == "" { // already done return nil } s.Lock() defer s.Unlock() pathp, e := syscall.UTF16PtrFromString(s.path) if e != nil { return e } h, e := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) if e != nil { return e } defer syscall.CloseHandle(h) var i syscall.ByHandleFileInformation e = syscall.GetFileInformationByHandle(syscall.Handle(h), &i) if e != nil { return e } s.path = "" s.vol = i.VolumeSerialNumber s.idxhi = i.FileIndexHigh s.idxlo = i.FileIndexLow return nil }
func getIno(path string) (ino *inode, err error) { pathp, e := syscall.UTF16PtrFromString(path) if e != nil { return nil, e } h, e := syscall.CreateFile(pathp, syscall.FILE_LIST_DIRECTORY, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) if e != nil { return nil, os.NewSyscallError("CreateFile", e) } var fi syscall.ByHandleFileInformation if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { syscall.CloseHandle(h) return nil, os.NewSyscallError("GetFileInformationByHandle", e) } ino = &inode{ handle: h, volume: fi.VolumeSerialNumber, index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), } return ino, nil }
// munmap Windows implementation // Based on: https://github.com/edsrzf/mmap-go // Based on: https://github.com/boltdb/bolt/bolt_windows.go func munmap(b []byte) (err error) { handleLock.Lock() defer handleLock.Unlock() addr := (uintptr)(unsafe.Pointer(&b[0])) if err := syscall.UnmapViewOfFile(addr); err != nil { return os.NewSyscallError("UnmapViewOfFile", err) } handle, ok := handleMap[addr] if !ok { // should be impossible; we would've seen the error above return errors.New("unknown base address") } delete(handleMap, addr) e := syscall.CloseHandle(syscall.Handle(handle)) if e != nil { return os.NewSyscallError("CloseHandle", e) } file, ok := fileMap[addr] if !ok { // should be impossible; we would've seen the error above return errors.New("unknown base address") } delete(fileMap, addr) e = file.Close() if e != nil { return errors.New("close file" + e.Error()) } return nil }
func munmap(b []byte) (err error) { m := MMap(b) dh := m.header() addr := dh.Data length := uintptr(dh.Len) flush(addr, length) err = syscall.UnmapViewOfFile(addr) if err != nil { return err } handleLock.Lock() defer handleLock.Unlock() handle, ok := handleMap[addr] if !ok { // should be impossible; we would've errored above return errors.New("unknown base address") } delete(handleMap, addr) e := syscall.CloseHandle(syscall.Handle(handle)) return os.NewSyscallError("CloseHandle", e) }
func openDevice(ifPattern string) (*Interface, error) { createNewTAPDevice() handle, err := queryNetworkKey() if err != nil { Log(Error, "Failed to query Windows registry: %v", err) return nil, err } dev, err := queryAdapters(handle) if err != nil { Log(Error, "Failed to query network adapters: %v", err) return nil, err } if dev == nil { Log(Error, "All devices are in use") return nil, errors.New("No free TAP devices") } if dev.Name == "" { Log(Error, "Failed to query network adapters: %v", err) return nil, errors.New("Empty network adapter") } err = syscall.CloseHandle(handle) if err != nil { Log(Error, "Failed to close retrieved handle: %v", err) } return dev, nil }
func mmapFile(f *os.File) mmapData { st, err := f.Stat() if err != nil { log.Fatal(err) } size := st.Size() if int64(int(size+4095)) != size+4095 { log.Fatalf("%s: too large for mmap", f.Name()) } if size == 0 { return mmapData{f, nil, nil} } h, err := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, uint32(size>>32), uint32(size), nil) if err != nil { log.Fatalf("CreateFileMapping %s: %v", f.Name(), err) } defer syscall.CloseHandle(syscall.Handle(h)) addr, err := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, 0) if err != nil { log.Fatalf("MapViewOfFile %s: %v", f.Name(), err) } data := (*[1 << 30]byte)(unsafe.Pointer(addr)) return mmapData{f, data[:size], data[:]} }
// Must run within the I/O thread. func (w *Watcher) startRead(watch *watch) error { if e := syscall.CancelIo(watch.ino.handle); e != nil { w.Error <- os.NewSyscallError("CancelIo", e) w.deleteWatch(watch) } mask := toWindowsFlags(watch.mask) for _, m := range watch.names { mask |= toWindowsFlags(m) } if mask == 0 { if e := syscall.CloseHandle(watch.ino.handle); e != nil { w.Error <- os.NewSyscallError("CloseHandle", e) } delete(w.watches[watch.ino.volume], watch.ino.index) return nil } e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) if e != nil { err := os.NewSyscallError("ReadDirectoryChanges", e) if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { // Watched directory was probably removed if w.sendEvent(watch.path, watch.mask&FS_DELETE_SELF) { if watch.mask&FS_ONESHOT != 0 { watch.mask = 0 } } err = nil } w.deleteWatch(watch) w.startRead(watch) return err } return nil }
func (self *ProcTime) Get(pid int) error { handle, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid)) defer syscall.CloseHandle(handle) if err != nil { return fmt.Errorf("OpenProcess fails with %v", err) } var CPU syscall.Rusage if err := syscall.GetProcessTimes(handle, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil { return fmt.Errorf("GetProcessTimes fails with %v", err) } // convert to millis self.StartTime = uint64(FiletimeToDuration(&CPU.CreationTime).Nanoseconds() / 1e6) self.User = uint64(FiletimeToDuration(&CPU.UserTime).Nanoseconds() / 1e6) self.Sys = uint64(FiletimeToDuration(&CPU.KernelTime).Nanoseconds() / 1e6) self.Total = self.User + self.Sys return nil }
// AcceptPipe accepts the next incoming call and returns the new connection. func (l *PipeListener) AcceptPipe() (*PipeConn, error) { if l == nil || l.addr == "" || l.closed { return nil, syscall.EINVAL } // the first time we call accept, the handle will have been created by the Listen // call. This is to prevent race conditions where the client thinks the server // isn't listening because it hasn't actually called create yet. After the first time, we'll // have to create a new handle each time handle := l.handle if handle == 0 { var err error handle, err = createPipe(string(l.addr), false) if err != nil { return nil, err } } else { l.handle = 0 } overlapped, err := newOverlapped() if err != nil { return nil, err } defer syscall.CloseHandle(overlapped.HEvent) if err := connectNamedPipe(handle, overlapped); err != nil && err != error_pipe_connected { if err == error_io_incomplete || err == syscall.ERROR_IO_PENDING { _, err = waitForCompletion(handle, overlapped) } if err != nil { return nil, err } } return &PipeConn{handle: handle, addr: l.addr}, nil }
func Open(filename string) (mf *memfile, err error) { f, err := os.Open(filename) if err != nil { return nil, err } defer f.Close() fs, err := f.Stat() if err != nil { return nil, err } fsize := fs.Size() fmap, err := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, 0, uint32(fsize), nil) if err != nil { return nil, err } defer syscall.CloseHandle(fmap) ptr, err := syscall.MapViewOfFile(fmap, syscall.FILE_MAP_READ, 0, 0, uintptr(fsize)) if err != nil { return nil, err } defer func() { if recover() != nil { mf = nil err = errors.New("Failed option a file") } }() return &memfile{ptr, fsize, (*[1 << 30]byte)(unsafe.Pointer(ptr))[:fsize]}, nil }
func (self *ProcMem) Get(pid int) error { handle, err := syscall.OpenProcess(PROCESS_ALL_ACCESS, false, uint32(pid)) defer syscall.CloseHandle(handle) if err != nil { return fmt.Errorf("OpenProcess fails with %v", err) } var mem PROCESS_MEMORY_COUNTERS_EX mem.CB = uint32(unsafe.Sizeof(mem)) r1, _, e1 := procGetProcessMemoryInfo.Call( uintptr(handle), uintptr(unsafe.Pointer(&mem)), uintptr(mem.CB), ) if r1 == 0 { if e1 != nil { return error(e1) } else { return syscall.EINVAL } } self.Resident = uint64(mem.WorkingSetSize) self.Size = uint64(mem.PrivateUsage) // Size contains only to the Private Bytes // Virtual Bytes are the Working Set plus paged Private Bytes and standby list. return nil }
// re-implementation of private function in https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L945 func getProcessEntry(pid int) (pe *syscall.ProcessEntry32, err error) { snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) if err != nil { return nil, err } defer syscall.CloseHandle(syscall.Handle(snapshot)) var processEntry syscall.ProcessEntry32 processEntry.Size = uint32(unsafe.Sizeof(processEntry)) err = syscall.Process32First(snapshot, &processEntry) if err != nil { return nil, err } for { if processEntry.ProcessID == uint32(pid) { pe = &processEntry return } err = syscall.Process32Next(snapshot, &processEntry) if err != nil { return nil, err } } }
func (file *file) close() error { if file == nil { return syscall.EINVAL } if file.isdir() && file.dirinfo.isempty { // "special" empty directories return nil } if file.fd == syscall.InvalidHandle { return syscall.EINVAL } var e error if file.isdir() { e = syscall.FindClose(syscall.Handle(file.fd)) } else { e = syscall.CloseHandle(syscall.Handle(file.fd)) } var err error if e != nil { err = &PathError{"close", file.name, e} } file.fd = syscall.InvalidHandle // so it can't be closed again // no need for a finalizer anymore runtime.SetFinalizer(file, nil) return err }
func (p Process) threads() ([]*Thread, error) { var ret []*Thread snapshot, err := win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPTHREAD, p.Pid) if err != nil { return ret, err } defer syscall.CloseHandle(snapshot) var thEntry win32.ThreadEntry32 thEntry.Size = uint32(unsafe.Sizeof(thEntry)) if err = win32.Thread32First(snapshot, &thEntry); err != nil { return ret, err } for { t := &Thread{ ThreadID: thEntry.ThreadID, OwnerProcessID: thEntry.OwnerProcessID, BasePriority: thEntry.BasePriority, } ret = append(ret, t) err = win32.Thread32Next(snapshot, &thEntry) if err != nil { if err == syscall.ERROR_NO_MORE_FILES { break } return ret, err } } return ret, nil }
func getProcessEntry(pid int) (pe *processEntry32, err error) { snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) if snapshot == uintptr(syscall.InvalidHandle) { err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) return } defer syscall.CloseHandle(syscall.Handle(snapshot)) var processEntry processEntry32 processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) if ok == 0 { err = fmt.Errorf("Process32First: %v", e1) return } for { if processEntry.th32ProcessID == uint32(pid) { pe = &processEntry return } ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) if ok == 0 { err = fmt.Errorf("Process32Next: %v", e1) return } } }
func (process *jobProcess) Wait() (int, error) { s, e := syscall.WaitForSingleObject(syscall.Handle(process.processHandle), syscall.INFINITE) switch s { case syscall.WAIT_OBJECT_0: break case syscall.WAIT_FAILED: return -1, os.NewSyscallError("WaitForSingleObject", e) default: return -1, errors.New("os: unexpected result from WaitForSingleObject") } var ec uint32 e = syscall.GetExitCodeProcess(syscall.Handle(process.processHandle), &ec) if e != nil { return -1, os.NewSyscallError("GetExitCodeProcess", e) } var u syscall.Rusage e = syscall.GetProcessTimes(syscall.Handle(process.processHandle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime) if e != nil { return -1, os.NewSyscallError("GetProcessTimes", e) } // NOTE(brainman): It seems that sometimes process is not dead // when WaitForSingleObject returns. But we do not know any // other way to wait for it. Sleeping for a while seems to do // the trick sometimes. So we will sleep and smell the roses. defer time.Sleep(5 * time.Millisecond) defer syscall.CloseHandle(syscall.Handle(process.processHandle)) return int(ec), nil }
func enableCurrentThreadPrivilege(privilegeName string) error { ct, err := windows.GetCurrentThread() if err != nil { return err } var t syscall.Token err = windows.OpenThreadToken(ct, syscall.TOKEN_QUERY|windows.TOKEN_ADJUST_PRIVILEGES, false, &t) if err != nil { return err } defer syscall.CloseHandle(syscall.Handle(t)) var tp windows.TOKEN_PRIVILEGES privStr, err := syscall.UTF16PtrFromString(privilegeName) if err != nil { return err } err = windows.LookupPrivilegeValue(nil, privStr, &tp.Privileges[0].Luid) if err != nil { return err } tp.PrivilegeCount = 1 tp.Privileges[0].Attributes = windows.SE_PRIVILEGE_ENABLED return windows.AdjustTokenPrivileges(t, false, &tp, 0, nil, nil) }
func (fs *fileStat) loadFileId() error { fs.Lock() defer fs.Unlock() if fs.path == "" { // already done return nil } pathp, err := syscall.UTF16PtrFromString(fs.path) if err != nil { return err } h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) if err != nil { return err } defer syscall.CloseHandle(h) var i syscall.ByHandleFileInformation err = syscall.GetFileInformationByHandle(syscall.Handle(h), &i) if err != nil { return err } fs.path = "" fs.vol = i.VolumeSerialNumber fs.idxhi = i.FileIndexHigh fs.idxlo = i.FileIndexLow return nil }
func queryIOCounters(name string, freq time.Duration, qio QueryIO) { h, err := syscall.Open(name, syscall.O_RDONLY, 0) if err != nil { log.Fatal(err) } for { select { case <-time.After(freq): diskPerf, err := win32.IoctlDiskPerformance(h) if err != nil { log.Fatal(err) } ioc := &IOCounters{ Name: name, ReadCount: diskPerf.ReadCount, WriteCount: diskPerf.WriteCount, ReadBytes: sysmon.Size(diskPerf.BytesRead), WriteBytes: sysmon.Size(diskPerf.BytesWritten), ReadTime: toDuration(diskPerf.ReadTime), WriteTime: toDuration(diskPerf.WriteTime), IoTime: toTime(diskPerf.QueryTime), } qio.IOCounterChan <- ioc case <-qio.quit: // we have received a signal to stop syscall.CloseHandle(h) return } } }
// Must run within the I/O thread. func (w *Watcher) addWatch(pathname string, flags uint64) error { dir, err := getDir(pathname) if err != nil { return err } if flags&sys_FS_ONLYDIR != 0 && pathname != dir { return nil } ino, err := getIno(dir) if err != nil { return err } w.mu.Lock() watchEntry := w.watches.get(ino) w.mu.Unlock() if watchEntry == nil { if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { syscall.CloseHandle(ino.handle) return os.NewSyscallError("CreateIoCompletionPort", e) } watchEntry = &watch{ ino: ino, path: dir, names: make(map[string]uint64), } w.mu.Lock() w.watches.set(ino, watchEntry) w.mu.Unlock() flags |= provisional } else { syscall.CloseHandle(ino.handle) } if pathname == dir { watchEntry.mask |= flags } else { watchEntry.names[filepath.Base(pathname)] |= flags } if err = w.startRead(watchEntry); err != nil { return err } if pathname == dir { watchEntry.mask &= ^provisional } else { watchEntry.names[filepath.Base(pathname)] &= ^provisional } return nil }