github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/fdnotifier/poll_unsafe.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build linux 16 // +build linux 17 18 package fdnotifier 19 20 import ( 21 "unsafe" 22 23 "golang.org/x/sys/unix" 24 "github.com/nicocha30/gvisor-ligolo/pkg/waiter" 25 ) 26 27 // NonBlockingPoll polls the given FD in non-blocking fashion. It is used just 28 // to query the FD's current state. 29 func NonBlockingPoll(fd int32, mask waiter.EventMask) waiter.EventMask { 30 e := struct { 31 fd int32 32 events int16 33 revents int16 34 }{ 35 fd: fd, 36 events: int16(mask.ToLinux()), 37 } 38 39 ts := unix.Timespec{ 40 Sec: 0, 41 Nsec: 0, 42 } 43 44 for { 45 n, _, err := unix.RawSyscall6(unix.SYS_PPOLL, uintptr(unsafe.Pointer(&e)), 1, 46 uintptr(unsafe.Pointer(&ts)), 0, 0, 0) 47 // Interrupted by signal, try again. 48 if err == unix.EINTR { 49 continue 50 } 51 // If an error occur we'll conservatively say the FD is ready for 52 // whatever is being checked. 53 if err != 0 { 54 return mask 55 } 56 57 // If no FDs were returned, it wasn't ready for anything. 58 if n == 0 { 59 return 0 60 } 61 62 // Otherwise we got the ready events in the revents field. 63 return waiter.EventMaskFromLinux(uint32(e.revents)) 64 } 65 } 66 67 // epollWait performs a blocking wait on epfd. 68 // 69 // Preconditions: len(events) > 0 70 func epollWait(epfd int, events []unix.EpollEvent, msec int) (int, error) { 71 if len(events) == 0 { 72 panic("Empty events passed to EpollWait") 73 } 74 75 // We actually use epoll_pwait with NULL sigmask instead of epoll_wait 76 // since that is what the Go >= 1.11 runtime prefers. 77 r, _, e := unix.Syscall6(unix.SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(unsafe.Pointer(&events[0])), uintptr(len(events)), uintptr(msec), 0, 0) 78 if e != 0 { 79 return 0, e 80 } 81 return int(r), nil 82 }