diff options
author | Michael Pratt <mpratt@google.com> | 2019-04-17 12:13:46 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-04-17 12:15:01 -0700 |
commit | 08d99c5fbea76ecc92038280387d24ecdf7ed814 (patch) | |
tree | 76df71b51b5515098e8c61978c441e8c530526ff /pkg/sentry/syscalls/polling.go | |
parent | e091b4e7c07056e32120ab25cc9a78ed24f7c754 (diff) |
Convert poll/select to operate more directly on linux.PollFD
Current, doPoll copies the user struct pollfd array into a
[]syscalls.PollFD, which contains internal kdefs.FD and
waiter.EventMask types. While these are currently binary-compatible with
the Linux versions, we generally discourage copying directly to internal
types (someone may inadvertantly change kdefs.FD to uint64).
Instead, copy directly to a []linux.PollFD, which will certainly be
binary compatible. Most of syscalls/polling.go is included directly into
syscalls/linux/sys_poll.go, as it can then operate directly on
linux.PollFD. The additional syscalls.PollFD type is providing little
value.
I've also added explicit conversion functions for waiter.EventMask,
which creates the possibility of a different binary format.
PiperOrigin-RevId: 244042947
Change-Id: I24e5b642002a32b3afb95a9dcb80d4acd1288abf
Diffstat (limited to 'pkg/sentry/syscalls/polling.go')
-rw-r--r-- | pkg/sentry/syscalls/polling.go | 137 |
1 files changed, 0 insertions, 137 deletions
diff --git a/pkg/sentry/syscalls/polling.go b/pkg/sentry/syscalls/polling.go deleted file mode 100644 index 2b33d6c19..000000000 --- a/pkg/sentry/syscalls/polling.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package syscalls - -import ( - "syscall" - "time" - - "gvisor.googlesource.com/gvisor/pkg/sentry/fs" - "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" - "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs" - "gvisor.googlesource.com/gvisor/pkg/waiter" -) - -// PollFD describes a pollable FD. -type PollFD struct { - FD kdefs.FD - Events waiter.EventMask - REvents waiter.EventMask -} - -// pollState tracks the associated file descriptor and waiter of a PollFD. -type pollState struct { - file *fs.File - waiter waiter.Entry -} - -// initReadiness gets the current ready mask for the file represented by the FD -// stored in pfd.FD. If a channel is passed in, the waiter entry in "state" is -// used to register with the file for event notifications, and a reference to -// the file is stored in "state". -func (pfd *PollFD) initReadiness(t *kernel.Task, state *pollState, ch chan struct{}) { - if pfd.FD < 0 { - pfd.REvents = 0 - return - } - - file := t.FDMap().GetFile(pfd.FD) - if file == nil { - pfd.REvents = waiter.EventNVal - return - } - - if ch == nil { - defer file.DecRef() - } else { - state.file = file - state.waiter, _ = waiter.NewChannelEntry(ch) - file.EventRegister(&state.waiter, pfd.Events) - } - - pfd.REvents = file.Readiness(pfd.Events) & pfd.Events -} - -// releaseState releases all the pollState in "state". -func releaseState(state []pollState) { - for i := range state { - if state[i].file != nil { - state[i].file.EventUnregister(&state[i].waiter) - state[i].file.DecRef() - } - } -} - -// Poll polls the PollFDs in "pfd" with a bounded time specified in "timeout" -// when "timeout" is greater than zero. -// -// Poll returns the remaining timeout, which is always 0 on a timeout; and 0 or -// positive if interrupted by a signal. -func Poll(t *kernel.Task, pfd []PollFD, timeout time.Duration) (time.Duration, uintptr, error) { - var ch chan struct{} - if timeout != 0 { - ch = make(chan struct{}, 1) - } - - // Register for event notification in the files involved if we may - // block (timeout not zero). Once we find a file that has a non-zero - // result, we stop registering for events but still go through all files - // to get their ready masks. - state := make([]pollState, len(pfd)) - defer releaseState(state) - n := uintptr(0) - for i := range pfd { - pfd[i].initReadiness(t, &state[i], ch) - if pfd[i].REvents != 0 { - n++ - ch = nil - } - } - - if timeout == 0 { - return timeout, n, nil - } - - forever := timeout < 0 - - for n == 0 { - var err error - // Wait for a notification. - timeout, err = t.BlockWithTimeout(ch, !forever, timeout) - if err != nil { - if err == syscall.ETIMEDOUT { - err = nil - } - return timeout, 0, err - } - - // We got notified, count how many files are ready. If none, - // then this was a spurious notification, and we just go back - // to sleep with the remaining timeout. - for i := range state { - if state[i].file == nil { - continue - } - - ready := state[i].file.Readiness(pfd[i].Events) & pfd[i].Events - if ready != 0 { - pfd[i].REvents = ready - n++ - } - } - } - - return timeout, n, nil -} |