github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_epoll.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 package linux 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 20 "github.com/SagerNet/gvisor/pkg/hostarch" 21 "github.com/SagerNet/gvisor/pkg/sentry/arch" 22 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 23 "github.com/SagerNet/gvisor/pkg/sentry/kernel/epoll" 24 "github.com/SagerNet/gvisor/pkg/sentry/syscalls" 25 "github.com/SagerNet/gvisor/pkg/syserror" 26 "github.com/SagerNet/gvisor/pkg/waiter" 27 ) 28 29 // LINT.IfChange 30 31 // EpollCreate1 implements the epoll_create1(2) linux syscall. 32 func EpollCreate1(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 33 flags := args[0].Int() 34 if flags & ^linux.EPOLL_CLOEXEC != 0 { 35 return 0, nil, linuxerr.EINVAL 36 } 37 38 closeOnExec := flags&linux.EPOLL_CLOEXEC != 0 39 fd, err := syscalls.CreateEpoll(t, closeOnExec) 40 if err != nil { 41 return 0, nil, err 42 } 43 44 return uintptr(fd), nil, nil 45 } 46 47 // EpollCreate implements the epoll_create(2) linux syscall. 48 func EpollCreate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 49 size := args[0].Int() 50 51 if size <= 0 { 52 return 0, nil, linuxerr.EINVAL 53 } 54 55 fd, err := syscalls.CreateEpoll(t, false) 56 if err != nil { 57 return 0, nil, err 58 } 59 60 return uintptr(fd), nil, nil 61 } 62 63 // EpollCtl implements the epoll_ctl(2) linux syscall. 64 func EpollCtl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 65 epfd := args[0].Int() 66 op := args[1].Int() 67 fd := args[2].Int() 68 eventAddr := args[3].Pointer() 69 70 // Capture the event state if needed. 71 flags := epoll.EntryFlags(0) 72 mask := waiter.EventMask(0) 73 var data [2]int32 74 if op != linux.EPOLL_CTL_DEL { 75 var e linux.EpollEvent 76 if _, err := e.CopyIn(t, eventAddr); err != nil { 77 return 0, nil, err 78 } 79 80 if e.Events&linux.EPOLLONESHOT != 0 { 81 flags |= epoll.OneShot 82 } 83 84 if e.Events&linux.EPOLLET != 0 { 85 flags |= epoll.EdgeTriggered 86 } 87 88 mask = waiter.EventMaskFromLinux(e.Events) 89 data = e.Data 90 } 91 92 // Perform the requested operations. 93 switch op { 94 case linux.EPOLL_CTL_ADD: 95 // See fs/eventpoll.c. 96 mask |= waiter.EventHUp | waiter.EventErr 97 return 0, nil, syscalls.AddEpoll(t, epfd, fd, flags, mask, data) 98 case linux.EPOLL_CTL_DEL: 99 return 0, nil, syscalls.RemoveEpoll(t, epfd, fd) 100 case linux.EPOLL_CTL_MOD: 101 // Same as EPOLL_CTL_ADD. 102 mask |= waiter.EventHUp | waiter.EventErr 103 return 0, nil, syscalls.UpdateEpoll(t, epfd, fd, flags, mask, data) 104 default: 105 return 0, nil, linuxerr.EINVAL 106 } 107 } 108 109 func waitEpoll(t *kernel.Task, fd int32, eventsAddr hostarch.Addr, max int, timeoutInNanos int64) (uintptr, *kernel.SyscallControl, error) { 110 r, err := syscalls.WaitEpoll(t, fd, max, timeoutInNanos) 111 if err != nil { 112 return 0, nil, syserror.ConvertIntr(err, syserror.EINTR) 113 } 114 115 if len(r) != 0 { 116 if _, err := linux.CopyEpollEventSliceOut(t, eventsAddr, r); err != nil { 117 return 0, nil, err 118 } 119 } 120 121 return uintptr(len(r)), nil, nil 122 123 } 124 125 // EpollWait implements the epoll_wait(2) linux syscall. 126 func EpollWait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 127 epfd := args[0].Int() 128 eventsAddr := args[1].Pointer() 129 maxEvents := int(args[2].Int()) 130 // Convert milliseconds to nanoseconds. 131 timeoutInNanos := int64(args[3].Int()) * 1000000 132 return waitEpoll(t, epfd, eventsAddr, maxEvents, timeoutInNanos) 133 } 134 135 // EpollPwait implements the epoll_pwait(2) linux syscall. 136 func EpollPwait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 137 maskAddr := args[4].Pointer() 138 maskSize := uint(args[5].Uint()) 139 140 if maskAddr != 0 { 141 mask, err := CopyInSigSet(t, maskAddr, maskSize) 142 if err != nil { 143 return 0, nil, err 144 } 145 146 oldmask := t.SignalMask() 147 t.SetSignalMask(mask) 148 t.SetSavedSignalMask(oldmask) 149 } 150 151 return EpollWait(t, args) 152 } 153 154 // EpollPwait2 implements the epoll_pwait(2) linux syscall. 155 func EpollPwait2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 156 epfd := args[0].Int() 157 eventsAddr := args[1].Pointer() 158 maxEvents := int(args[2].Int()) 159 timeoutPtr := args[3].Pointer() 160 maskAddr := args[4].Pointer() 161 maskSize := uint(args[5].Uint()) 162 haveTimeout := timeoutPtr != 0 163 164 var timeoutInNanos int64 = -1 165 if haveTimeout { 166 timeout, err := copyTimespecIn(t, timeoutPtr) 167 if err != nil { 168 return 0, nil, err 169 } 170 timeoutInNanos = timeout.ToNsec() 171 172 } 173 174 if maskAddr != 0 { 175 mask, err := CopyInSigSet(t, maskAddr, maskSize) 176 if err != nil { 177 return 0, nil, err 178 } 179 180 oldmask := t.SignalMask() 181 t.SetSignalMask(mask) 182 t.SetSavedSignalMask(oldmask) 183 } 184 185 return waitEpoll(t, epfd, eventsAddr, maxEvents, timeoutInNanos) 186 } 187 188 // LINT.ThenChange(vfs2/epoll.go)