diff --git a/pkg/sentry/platform/systrap/BUILD b/pkg/sentry/platform/systrap/BUILD index 39743e5a1..744e6d759 100644 --- a/pkg/sentry/platform/systrap/BUILD +++ b/pkg/sentry/platform/systrap/BUILD @@ -44,8 +44,6 @@ go_template_instance( go_library( name = "systrap", srcs = [ - "context_decoupling_disable.go", - "context_decoupling_enable.go", "context_list.go", "context_queue.go", "filters.go", diff --git a/pkg/sentry/platform/systrap/context_decoupling_disable.go b/pkg/sentry/platform/systrap/context_decoupling_disable.go deleted file mode 100644 index 63433fe2c..000000000 --- a/pkg/sentry/platform/systrap/context_decoupling_disable.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2023 The gVisor Authors. -// -// 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. - -//go:build context_decoupling_disabled -// +build context_decoupling_disabled - -package systrap - -var contextDecouplingExp bool = false diff --git a/pkg/sentry/platform/systrap/context_decoupling_enable.go b/pkg/sentry/platform/systrap/context_decoupling_enable.go deleted file mode 100644 index f8ee2ba87..000000000 --- a/pkg/sentry/platform/systrap/context_decoupling_enable.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2023 The gVisor Authors. -// -// 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. - -//go:build !context_decoupling_disabled -// +build !context_decoupling_disabled - -package systrap - -// contextDecouplingExp is a global flag that enables thread decoupling mode. -// In this mode thread contexts are able to migrate between systrap user -// process threads. This also allows and enables the following experimental -// optimizations: -// - Ability to run M contexts using N threads, where M > N. -// - Reduce synchronization overhead between sentry threads and user -// threads when switching contexts in and out of the sentry. -var contextDecouplingExp bool = true diff --git a/pkg/sentry/platform/systrap/shared_context.go b/pkg/sentry/platform/systrap/shared_context.go index 579b093a5..e4b106432 100644 --- a/pkg/sentry/platform/systrap/shared_context.go +++ b/pkg/sentry/platform/systrap/shared_context.go @@ -163,13 +163,6 @@ func (sc *sharedContext) threadID() uint32 { return atomic.LoadUint32(&sc.shared.ThreadID) } -func (sc *sharedContext) setThreadID(threadID uint32) { - if contextDecouplingExp { - panic("context decoupled systrap should never explicitly set ThreadID") - } - atomic.StoreUint32(&sc.shared.ThreadID, threadID) -} - // EnableSentryFastPath indicates that the polling mode is enabled for the // Sentry. It has to be called before putting the context into the context queue. // This function is used if contextDecouplingExp=true because the fastpath @@ -287,6 +280,13 @@ func (q *fastPathDispatcher) deactivateSubprocess(s *subprocess) { q.subprocessList.Remove(s) } +// deep_sleep_timeout is the timeout after which we stops polling and fall asleep. +// +// The value is 40µs for 2GHz CPU. This timeout matches the sentry<->stub round +// trip in the pure deep sleep case. +const deepSleepTimeout = uint64(80000) +const handshakeTimeout = uint64(1000) + // loop is processing contexts in the queue. Only one instance of it can be // running, because it has exclusive access to the list. // diff --git a/pkg/sentry/platform/systrap/stub_unsafe.go b/pkg/sentry/platform/systrap/stub_unsafe.go index 2f6def09f..fb7f096ba 100644 --- a/pkg/sentry/platform/systrap/stub_unsafe.go +++ b/pkg/sentry/platform/systrap/stub_unsafe.go @@ -141,14 +141,12 @@ func stubInit() { mapLen, _ = hostarch.PageRoundUp(mapLen + sysmsg.PerThreadMemSize*(maxSystemThreads+1)) // Allocate context queue region - if contextDecouplingExp { - stubContextQueueRegion = mapLen - stubContextQueueRegionLen, _ = hostarch.PageRoundUp(unsafe.Sizeof(contextQueue{})) - mapLen += stubContextQueueRegionLen + stubContextQueueRegion = mapLen + stubContextQueueRegionLen, _ = hostarch.PageRoundUp(unsafe.Sizeof(contextQueue{})) + mapLen += stubContextQueueRegionLen - stubSpinningThreadQueueAddr = mapLen - mapLen += sysmsg.SpinningQueueMemSize - } + stubSpinningThreadQueueAddr = mapLen + mapLen += sysmsg.SpinningQueueMemSize // Allocate thread context region stubContextRegion = mapLen @@ -220,23 +218,16 @@ func stubInit() { // Initialize stub globals p := (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_deep_sleep_timeout))) *p = deepSleepTimeout - p = (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_handshake_timeout))) - *p = handshakeTimeout p = (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_context_region))) *p = uint64(stubContextRegion) p = (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_stub_start))) *p = uint64(stubStart) archState := (*sysmsg.ArchState)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_arch_state))) archState.Init() - exp := (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_context_decoupling_exp))) - if contextDecouplingExp { - *exp = 1 - contextQueue := (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_context_queue_addr))) - *contextQueue = uint64(stubContextQueueRegion) - - p = (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_spinning_queue_addr))) - *p = uint64(stubSpinningThreadQueueAddr) - } + p = (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_context_queue_addr))) + *p = uint64(stubContextQueueRegion) + p = (*uint64)(unsafe.Pointer(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_spinning_queue_addr))) + *p = uint64(stubSpinningThreadQueueAddr) prepareSeccompRules(stubSysmsgStart, stubSysmsgRules, stubSysmsgRulesLen) @@ -253,5 +244,4 @@ func stubInit() { stubEnd = stubStart + mapLen + uintptr(gap) log.Debugf("stubStart %x stubSysmsgStart %x stubSysmsgStack %x, stubContextQueue %x, stubThreadContextRegion %x, mapLen %x", stubStart, stubSysmsgStart, stubSysmsgStack, stubContextQueueRegion, stubContextRegion, mapLen) log.Debugf(archState.String()) - log.Debugf("contextDecouplingExp=%t", contextDecouplingExp) } diff --git a/pkg/sentry/platform/systrap/subprocess.go b/pkg/sentry/platform/systrap/subprocess.go index ca21e4296..30b0a923c 100644 --- a/pkg/sentry/platform/systrap/subprocess.go +++ b/pkg/sentry/platform/systrap/subprocess.go @@ -315,14 +315,12 @@ func newSubprocess(create func() (*thread, error), memoryFile *pgalloc.MemoryFil sp.mapPrivateRegions() // Create the initial sysmsg thread. - if contextDecouplingExp { - atomic.AddUint32(&sp.contextQueue.numActiveThreads, 1) - if _, err := sp.createSysmsgThread(nil, nil, nil); err != nil { - atomic.AddUint32(&sp.contextQueue.numActiveThreads, ^uint32(0)) - return nil, err - } - sp.numSysmsgThreads++ + atomic.AddUint32(&sp.contextQueue.numActiveThreads, 1) + if err := sp.createSysmsgThread(); err != nil { + atomic.AddUint32(&sp.contextQueue.numActiveThreads, ^uint32(0)) + return nil, err } + sp.numSysmsgThreads++ return sp, nil } @@ -343,27 +341,25 @@ func (s *subprocess) mapSharedRegions() { Dir: pgalloc.TopDown, } - if contextDecouplingExp { - // Map shared regions into the sentry. - contextQueueFR, contextQueue := mmapContextQueueForSentry(s.memoryFile, opts) - contextQueue.init() + // Map shared regions into the sentry. + contextQueueFR, contextQueue := mmapContextQueueForSentry(s.memoryFile, opts) + contextQueue.init() - // Map thread context region into the syscall thread. - _, err := s.syscallThread.syscall( - unix.SYS_MMAP, - arch.SyscallArgument{Value: uintptr(stubContextQueueRegion)}, - arch.SyscallArgument{Value: uintptr(contextQueueFR.Length())}, - arch.SyscallArgument{Value: uintptr(unix.PROT_READ | unix.PROT_WRITE)}, - arch.SyscallArgument{Value: uintptr(unix.MAP_SHARED | unix.MAP_FILE | unix.MAP_FIXED)}, - arch.SyscallArgument{Value: uintptr(s.memoryFile.FD())}, - arch.SyscallArgument{Value: uintptr(contextQueueFR.Start)}) - if err != nil { - panic(fmt.Sprintf("failed to mmap context queue region into syscall thread: %v", err)) - } - - s.contextQueue = contextQueue + // Map thread context region into the syscall thread. + _, err := s.syscallThread.syscall( + unix.SYS_MMAP, + arch.SyscallArgument{Value: uintptr(stubContextQueueRegion)}, + arch.SyscallArgument{Value: uintptr(contextQueueFR.Length())}, + arch.SyscallArgument{Value: uintptr(unix.PROT_READ | unix.PROT_WRITE)}, + arch.SyscallArgument{Value: uintptr(unix.MAP_SHARED | unix.MAP_FILE | unix.MAP_FIXED)}, + arch.SyscallArgument{Value: uintptr(s.memoryFile.FD())}, + arch.SyscallArgument{Value: uintptr(contextQueueFR.Start)}) + if err != nil { + panic(fmt.Sprintf("failed to mmap context queue region into syscall thread: %v", err)) } + s.contextQueue = contextQueue + // Map thread context region into the sentry. threadContextFR, err := s.memoryFile.Allocate(uint64(stubContextRegionLen), opts) if err != nil { @@ -396,18 +392,16 @@ func (s *subprocess) mapSharedRegions() { } func (s *subprocess) mapPrivateRegions() { - if contextDecouplingExp { - _, err := s.syscallThread.syscall( - unix.SYS_MMAP, - arch.SyscallArgument{Value: uintptr(stubSpinningThreadQueueAddr)}, - arch.SyscallArgument{Value: uintptr(sysmsg.SpinningQueueMemSize)}, - arch.SyscallArgument{Value: uintptr(unix.PROT_READ | unix.PROT_WRITE)}, - arch.SyscallArgument{Value: uintptr(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_FIXED)}, - arch.SyscallArgument{Value: 0}, - arch.SyscallArgument{Value: 0}) - if err != nil { - panic(fmt.Sprintf("failed to mmap spinning queue region into syscall thread: %v", err)) - } + _, err := s.syscallThread.syscall( + unix.SYS_MMAP, + arch.SyscallArgument{Value: uintptr(stubSpinningThreadQueueAddr)}, + arch.SyscallArgument{Value: uintptr(sysmsg.SpinningQueueMemSize)}, + arch.SyscallArgument{Value: uintptr(unix.PROT_READ | unix.PROT_WRITE)}, + arch.SyscallArgument{Value: uintptr(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_FIXED)}, + arch.SyscallArgument{Value: 0}, + arch.SyscallArgument{Value: 0}) + if err != nil { + panic(fmt.Sprintf("failed to mmap spinning queue region into syscall thread: %v", err)) } } @@ -724,14 +718,8 @@ func (s *subprocess) decAwakeContexts() { // The second return value is true if a syscall instruction can be replaced on // a function call. func (s *subprocess) switchToApp(c *context, ac *arch.Context64) (isSyscall bool, shouldPatchSyscall bool, err error) { - // Get sysmsg thread bound to the context; no-op if contextDecoupling is on. - regs := &ac.StateData().Regs - sysThread, err := s.getSysmsgThread(regs, c, ac) - if err != nil { - return false, false, err - } - // Reset necessary registers. + regs := &ac.StateData().Regs s.resetSysemuRegs(regs) ctx := c.sharedContext ctx.shared.Regs = regs.PtraceRegs @@ -749,49 +737,26 @@ func (s *subprocess) switchToApp(c *context, ac *arch.Context64) (isSyscall bool c.interrupt.Disable() }() - if contextDecouplingExp { - restoreFPState(nil, ctx, 0, c, ac) + restoreFPState(ctx, c, ac) - // Place the context onto the context queue. - if ctx.sleeping { - ctx.sleeping = false - s.incAwakeContexts() - } - stubFastPathEnabled := dispatcher.stubFastPathEnabled() - ctx.setState(sysmsg.ContextStateNone) - s.contextQueue.add(ctx, stubFastPathEnabled) - s.waitOnState(ctx, stubFastPathEnabled) + // Place the context onto the context queue. + if ctx.sleeping { + ctx.sleeping = false + s.incAwakeContexts() + } + stubFastPathEnabled := dispatcher.stubFastPathEnabled() + ctx.setState(sysmsg.ContextStateNone) + s.contextQueue.add(ctx, stubFastPathEnabled) + s.waitOnState(ctx, stubFastPathEnabled) - // Check if there's been an error. - threadID := ctx.threadID() - if threadID != invalidThreadID { - if sysThread, ok := s.sysmsgThreads[threadID]; ok && sysThread.msg.Err != 0 { - msg := sysThread.msg - panic(fmt.Sprintf("stub thread %d failed: err 0x%x line %d: %s", sysThread.thread.tid, msg.Err, msg.Line, msg)) - } - log.Warningf("systrap: found unexpected ThreadContext.ThreadID field, expected %d found %d", invalidThreadID, threadID) - } - } else { - msg := sysThread.msg - t := sysThread.thread - - restoreFPState(msg, ctx, sysThread.fpuStateToMsgOffset, c, ac) - - msg.EnableSentryFastPath() - sysThread.waitEvent(sysmsg.ThreadStateDone, ctx) - - // Check if there's been an error. - if msg.Err != 0 { - panic(fmt.Sprintf("stub thread %d failed: err %d line %d: %s", t.tid, msg.Err, msg.Line, msg)) - } - - if ctx.state() != sysmsg.ContextStateSyscallTrap { - var err error - sysThread.fpuStateToMsgOffset, err = msg.FPUStateOffset() - if err != nil { - return false, false, err - } + // Check if there's been an error. + threadID := ctx.threadID() + if threadID != invalidThreadID { + if sysThread, ok := s.sysmsgThreads[threadID]; ok && sysThread.msg.Err != 0 { + msg := sysThread.msg + panic(fmt.Sprintf("stub thread %d failed: err 0x%x line %d: %s", sysThread.thread.tid, msg.Err, msg.Line, msg)) } + log.Warningf("systrap: found unexpected ThreadContext.ThreadID field, expected %d found %d", invalidThreadID, threadID) } // Copy register state locally. @@ -908,7 +873,7 @@ func (s *subprocess) kickSysmsgThread() bool { s.numSysmsgThreads++ s.sysmsgThreadsMu.Unlock() atomic.AddUint32(&s.contextQueue.numActiveThreads, 1) - if _, err := s.createSysmsgThread(nil, nil, nil); err != nil { + if err := s.createSysmsgThread(); err != nil { log.Warningf("Unable to create a new stub thread: %s", err) atomic.AddUint32(&s.contextQueue.numActiveThreads, ^uint32(0)) s.sysmsgThreadsMu.Lock() @@ -982,37 +947,10 @@ func (s *subprocess) PullFullState(c *context, ac *arch.Context64) error { if !c.sharedContext.isActiveInSubprocess(s) { panic("Attempted to PullFullState for context that is not used in subprocess") } - if contextDecouplingExp { - saveFPState(nil, c.sharedContext, 0, c, ac) - } else { - sysThread, err := s.getSysmsgThread(&ac.StateData().Regs, c, ac) - if err != nil { - return err - } - saveFPState(sysThread.msg, c.sharedContext, sysThread.fpuStateToMsgOffset, c, ac) - } + saveFPState(c.sharedContext, ac) return nil } -// getSysmsgThread returns a sysmsg thread for the specified context. -// (Unused if contextDecouplingExp=true). -func (s *subprocess) getSysmsgThread(tregs *arch.Registers, c *context, ac *arch.Context64) (*sysmsgThread, error) { - if contextDecouplingExp { - return nil, nil - } - sysThread := c.sysmsgThread - if sysThread != nil && sysThread.subproc != s { - // This can happen if a new address space - // has been created (e.g. fork). - sysThread.destroy() - sysThread = nil - } - if sysThread != nil { - return sysThread, nil - } - return s.createSysmsgThread(tregs, c, ac) -} - var sysmsgThreadPriority int func initSysmsgThreadPriority() { @@ -1025,16 +963,8 @@ func initSysmsgThreadPriority() { } // createSysmsgThread creates a new sysmsg thread. -// If contextDecouplingExp=false, the thread starts working on the given context. -// Otherwise the given function parameters are not used, and the thread starts -// processing any available context in the context queue. -func (s *subprocess) createSysmsgThread(tregs *arch.Registers, c *context, ac *arch.Context64) (*sysmsgThread, error) { - if contextDecouplingExp { - // We will not bind any specific context to this thread. We will still use - // tregs to setup the thread though. - tregs = &arch.Registers{} - } - +// The thread starts processing any available context in the context queue. +func (s *subprocess) createSysmsgThread() error { // Create a new seccomp process. var r requestThread r.thread = make(chan *thread) @@ -1115,12 +1045,6 @@ func (s *subprocess) createSysmsgThread(tregs *arch.Registers, c *context, ac *a sysThread.setMsg(sysmsg.StackAddrToMsg(sentryStackAddr)) sysThread.msg.Init(threadID) - if contextDecouplingExp { - sysThread.msg.Context = 0 - } else { - c.sharedContext.setThreadID(threadID) - sysThread.msg.Context = uint64(stubContextRegion + uintptr(c.sharedContext.contextID)*sysmsg.AllocatedSizeofThreadContextStruct) - } sysThread.msg.Self = uint64(sysmsgStackAddr + sysmsg.MsgOffsetFromSharedStack) sysThread.msg.SyshandlerStack = uint64(sysmsg.StackAddrToSyshandlerStack(sysThread.sysmsgPerThreadMemAddr())) sysThread.msg.Syshandler = uint64(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_syshandler)) @@ -1152,6 +1076,7 @@ func (s *subprocess) createSysmsgThread(tregs *arch.Registers, c *context, ac *a } // Prepare to start the BPF process. + tregs := &arch.Registers{} s.resetSysemuRegs(tregs) setArchSpecificRegs(sysThread, tregs) if err := p.setRegs(tregs); err != nil { @@ -1167,26 +1092,11 @@ func (s *subprocess) createSysmsgThread(tregs *arch.Registers, c *context, ac *a panic(fmt.Sprintf("can't detach new clone: %v", errno)) } - if !contextDecouplingExp { - sysThread.waitEvent(sysmsg.ThreadStateNone, c.sharedContext) - if msg := sysThread.msg; msg.Err != 0 { - panic(fmt.Sprintf("stub thread failed: %v (line %v)", msg.Err, msg.Line)) - } - - sysThread.fpuStateToMsgOffset, err = sysThread.msg.FPUStateOffset() - if err != nil { - sysThread.destroy() - return nil, err - } - - c.sysmsgThread = sysThread - } - s.sysmsgThreadsMu.Lock() s.sysmsgThreads[threadID] = sysThread s.sysmsgThreadsMu.Unlock() - return sysThread, nil + return nil } // PreFork implements platform.AddressSpace.PreFork. diff --git a/pkg/sentry/platform/systrap/subprocess_amd64.go b/pkg/sentry/platform/systrap/subprocess_amd64.go index b6d69a0ca..9fd897a14 100644 --- a/pkg/sentry/platform/systrap/subprocess_amd64.go +++ b/pkg/sentry/platform/systrap/subprocess_amd64.go @@ -214,11 +214,9 @@ func restoreArchSpecificState(ctx *sysmsg.ThreadContext, ac *arch.Context64) { } func setArchSpecificRegs(sysThread *sysmsgThread, regs *arch.Registers) { - if contextDecouplingExp { - // Set the start function and initial stack. - regs.PtraceRegs.Rip = uint64(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_start)) - regs.PtraceRegs.Rsp = uint64(sysmsg.StackAddrToSyshandlerStack(sysThread.sysmsgPerThreadMemAddr())) - } + // Set the start function and initial stack. + regs.PtraceRegs.Rip = uint64(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_start)) + regs.PtraceRegs.Rsp = uint64(sysmsg.StackAddrToSyshandlerStack(sysThread.sysmsgPerThreadMemAddr())) // Set gs_base; this is the only time we set it and we don't expect it to ever // change for any thread. @@ -229,12 +227,4 @@ func retrieveArchSpecificState(ctx *sysmsg.ThreadContext, ac *arch.Context64) { } func archSpecificSysmsgThreadInit(sysThread *sysmsgThread) { - // Send a fake event to stop the BPF process so that it enters the sighandler. - // If there is no coupled context we don't want that to happen because the - // thread needs to find a context first. - if !contextDecouplingExp { - if _, _, e := unix.RawSyscall(unix.SYS_TGKILL, uintptr(sysThread.thread.tgid), uintptr(sysThread.thread.tid), uintptr(unix.SIGSEGV)); e != 0 { - panic(fmt.Sprintf("tkill failed: %v", e)) - } - } } diff --git a/pkg/sentry/platform/systrap/subprocess_arm64.go b/pkg/sentry/platform/systrap/subprocess_arm64.go index 21db37029..1262887e6 100644 --- a/pkg/sentry/platform/systrap/subprocess_arm64.go +++ b/pkg/sentry/platform/systrap/subprocess_arm64.go @@ -192,13 +192,6 @@ func restoreArchSpecificState(ctx *sysmsg.ThreadContext, ac *arch.Context64) { } func setArchSpecificRegs(sysThread *sysmsgThread, regs *arch.Registers) { - if contextDecouplingExp { - // Set the start function and initial stack. On ARM __export_start does not - // actually get used because we send a signal to the thread upon startup - // right away (see archSpecificSysmsgThreadInit below). - regs.PtraceRegs.Pc = uint64(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_start)) - regs.PtraceRegs.Sp = uint64(sysmsg.StackAddrToSyshandlerStack(sysThread.sysmsgPerThreadMemAddr())) - } } func retrieveArchSpecificState(ctx *sysmsg.ThreadContext, ac *arch.Context64) { diff --git a/pkg/sentry/platform/systrap/subprocess_unsafe.go b/pkg/sentry/platform/systrap/subprocess_unsafe.go index c724ad9d8..17a067a77 100644 --- a/pkg/sentry/platform/systrap/subprocess_unsafe.go +++ b/pkg/sentry/platform/systrap/subprocess_unsafe.go @@ -41,6 +41,12 @@ func afterFork() //go:linkname afterForkInChild syscall.runtime_AfterForkInChild func afterForkInChild() +//go:linkname cputicks runtime.cputicks +func cputicks() int64 + +// spinloop is implemented in assembly. +func spinloop() + // getThreadContextFromID returns a ThreadContext struct that corresponds to the // given ID. // @@ -70,29 +76,16 @@ func mmapContextQueueForSentry(memoryFile *pgalloc.MemoryFile, opts pgalloc.Allo return fr, (*contextQueue)(unsafe.Pointer(addr)) } -//go:nosplit -func isFPStateInContextRegion(ctx *sharedContext) bool { - // If context decoupling experiment is ON then both the sighandler and - // syshandler save FPState to the context region since contexts will move - // threads. Otherwise only syshandler will save FPState to the region. - return contextDecouplingExp || ctx.state() == sysmsg.ContextStateSyscallTrap -} - -func saveFPState(msg *sysmsg.Msg, ctx *sharedContext, fpuToMsgOffset uint64, c *context, ac *arch.Context64) { +func saveFPState(ctx *sharedContext, ac *arch.Context64) { fpState := ac.FloatingPointData().BytePointer() dst := unsafeSlice(uintptr(unsafe.Pointer(fpState)), archState.FpLen()) - var src []byte - if isFPStateInContextRegion(ctx) { - src = ctx.shared.FPState[:] - } else { - src = unsafeSlice(uintptr(unsafe.Pointer(msg))+uintptr(fpuToMsgOffset), archState.FpLen()) - } + src := ctx.shared.FPState[:] copy(dst, src) } // restoreFPStateDecoupledContext writes FPState from c to the thread context // shared memory region if there is any need to do so. -func restoreFPState(msg *sysmsg.Msg, ctx *sharedContext, fpuToMsgOffset uint64, c *context, ac *arch.Context64) { +func restoreFPState(ctx *sharedContext, c *context, ac *arch.Context64) { if !c.needRestoreFPState { return } @@ -101,11 +94,6 @@ func restoreFPState(msg *sysmsg.Msg, ctx *sharedContext, fpuToMsgOffset uint64, fpState := ac.FloatingPointData().BytePointer() src := unsafeSlice(uintptr(unsafe.Pointer(fpState)), archState.FpLen()) - var dst []byte - if isFPStateInContextRegion(ctx) { - dst = ctx.shared.FPState[:] - } else { - dst = unsafeSlice(uintptr(unsafe.Pointer(msg))+uintptr(fpuToMsgOffset), archState.FpLen()) - } + dst := ctx.shared.FPState[:] copy(dst, src) } diff --git a/pkg/sentry/platform/systrap/sysmsg/BUILD b/pkg/sentry/platform/systrap/sysmsg/BUILD index 9b4d15466..2fd68ef83 100644 --- a/pkg/sentry/platform/systrap/sysmsg/BUILD +++ b/pkg/sentry/platform/systrap/sysmsg/BUILD @@ -127,9 +127,7 @@ go_library( visibility = ["//:sandbox"], deps = [ "//pkg/abi/linux", - "//pkg/abi/linux/errno", "//pkg/cpuid", - "//pkg/errors", "//pkg/hostarch", "//pkg/log", "//pkg/sentry/platform/interrupt", diff --git a/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c b/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c index 3c937ca0e..f138627a9 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c +++ b/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c @@ -34,7 +34,6 @@ // TODO(b/271631387): These globals are shared between AMD64 and ARM64; move to // sysmsg_lib.c. struct arch_state __export_arch_state; -uint64_t __export_context_decoupling_exp; uint64_t __export_stub_start; long __syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { @@ -160,18 +159,11 @@ static void set_fsbase(uint64_t fsbase) { // specific to amd64. struct thread_context *switch_context_amd64( struct sysmsg *sysmsg, struct thread_context *ctx, - enum thread_state new_thread_state, enum context_state new_context_state) { + enum context_state new_context_state) { struct thread_context *old_ctx = sysmsg->context; for (;;) { - // TODO(b/271631387): Once stub code globals can be used between objects - // move this check into sysmsg_lib:switch_context(). - if (__export_context_decoupling_exp) { - ctx = switch_context(sysmsg, ctx, new_context_state); - } else { - ctx->state = new_context_state; - wait_state(sysmsg, new_thread_state); - } + ctx = switch_context(sysmsg, ctx, new_context_state); // After setting THREAD_STATE_NONE, syshandled can be interrupted by // SIGCHLD. In this case, we consider that the current context contains @@ -207,8 +199,7 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { if (sysmsg != sysmsg->self) panic(0xdeaddead); int32_t thread_state = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if (__export_context_decoupling_exp && - thread_state == THREAD_STATE_INITIALIZING) { + if (thread_state == THREAD_STATE_INITIALIZING) { // This thread was interrupted before it even had a context. return; } @@ -239,13 +230,9 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { ucontext->uc_mcontext.gregs[REG_RIP] < __export_stub_start) { ctx->ptregs.fs_base = fs_base; gregs_to_ptregs(ucontext, &ctx->ptregs); - if (__export_context_decoupling_exp) { - memcpy(ctx->fpstate, (uint8_t *)ucontext->uc_mcontext.fpregs, - __export_arch_state.fp_len); - } else { - sysmsg->fpstate = - (unsigned long)ucontext->uc_mcontext.fpregs - (unsigned long)sysmsg; - } + memcpy(ctx->fpstate, (uint8_t *)ucontext->uc_mcontext.fpregs, + __export_arch_state.fp_len); + __atomic_store_n(&ctx->fpstate_changed, 0, __ATOMIC_RELEASE); } @@ -332,13 +319,12 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { return; } - ctx = switch_context_amd64(sysmsg, ctx, THREAD_STATE_EVENT, ctx_state); + ctx = switch_context_amd64(sysmsg, ctx, ctx_state); if (fs_base != ctx->ptregs.fs_base) { set_fsbase(ctx->ptregs.fs_base); } - if (__export_context_decoupling_exp && - __atomic_load_n(&ctx->fpstate_changed, __ATOMIC_ACQUIRE)) { + if (__atomic_load_n(&ctx->fpstate_changed, __ATOMIC_ACQUIRE)) { prep_fpstate_for_sigframe( ctx->fpstate, __export_arch_state.fp_len, __export_arch_state.xsave_mode != XSAVE_MODE_FXSAVE); @@ -366,7 +352,7 @@ void __syshandler() { long fs_base = get_fsbase(); ctx->ptregs.fs_base = fs_base; - ctx = switch_context_amd64(sysmsg, ctx, THREAD_STATE_EVENT, ctx_state); + ctx = switch_context_amd64(sysmsg, ctx, ctx_state); // switch_context_amd64 changed sysmsg->state to THREAD_STATE_NONE, so we can // only resume the current process, all other actions are // prohibited after this point. @@ -384,8 +370,8 @@ void __export_start(struct sysmsg *sysmsg, void *_ucontext) { } #endif - struct thread_context *ctx = switch_context_amd64( - sysmsg, NULL, THREAD_STATE_EVENT, CONTEXT_STATE_INVALID); + struct thread_context *ctx = + switch_context_amd64(sysmsg, NULL, CONTEXT_STATE_INVALID); restore_state(sysmsg, ctx, _ucontext); } diff --git a/pkg/sentry/platform/systrap/sysmsg/sighandler_arm64.c b/pkg/sentry/platform/systrap/sysmsg/sighandler_arm64.c index f65e7ca8a..d0e04e46d 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sighandler_arm64.c +++ b/pkg/sentry/platform/systrap/sysmsg/sighandler_arm64.c @@ -32,7 +32,6 @@ // TODO(b/271631387): These globals are shared between AMD64 and ARM64; move to // sysmsg_lib.c. struct arch_state __export_arch_state; -uint64_t __export_context_decoupling_exp; uint64_t __export_stub_start; long __syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { @@ -105,8 +104,7 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { uint32_t ctx_state = CONTEXT_STATE_INVALID; struct thread_context *ctx = NULL, *old_ctx = NULL; - if (__export_context_decoupling_exp && - thread_state == THREAD_STATE_INITIALIZING) { + if (thread_state == THREAD_STATE_INITIALIZING) { // Find a new context and exit to restore it. goto init; } @@ -129,11 +127,8 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { } uint8_t *fpStatePointer = (uint8_t *)&ucontext->uc_mcontext.__reserved + kSigframeMagicHeaderLen; - if (__export_context_decoupling_exp) { - memcpy(ctx->fpstate, fpStatePointer, __export_arch_state.fp_len); - } else { - sysmsg->fpstate = (uint64_t)(fpStatePointer) - (uint64_t)sysmsg; - } + + memcpy(ctx->fpstate, fpStatePointer, __export_arch_state.fp_len); ctx->tls = get_tls(); ctx->siginfo = *siginfo; switch (signo) { @@ -162,12 +157,7 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { init: for (;;) { - if (__export_context_decoupling_exp) { - ctx = switch_context(sysmsg, ctx, ctx_state); - } else { - ctx->state = ctx_state; - wait_state(sysmsg, THREAD_STATE_EVENT); - } + ctx = switch_context(sysmsg, ctx, ctx_state); if (__atomic_load_n(&ctx->interrupt, __ATOMIC_ACQUIRE) != 0) { // This context got interrupted while it was waiting in the queue. @@ -197,8 +187,7 @@ void restore_state(struct sysmsg *sysmsg, struct thread_context *ctx, (struct fpsimd_context *)&ucontext->uc_mcontext.__reserved; uint8_t *fpStatePointer = (uint8_t *)&fpctx->fpsr; - if (__export_context_decoupling_exp && - __atomic_load_n(&ctx->fpstate_changed, __ATOMIC_ACQUIRE)) { + if (__atomic_load_n(&ctx->fpstate_changed, __ATOMIC_ACQUIRE)) { memcpy(fpStatePointer, ctx->fpstate, __export_arch_state.fp_len); } ptregs_to_gregs(ucontext, &ctx->ptregs); diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg.go b/pkg/sentry/platform/systrap/sysmsg/sysmsg.go index b6b6f7643..cd6853b60 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg.go +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg.go @@ -26,8 +26,6 @@ import ( "sync/atomic" "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/abi/linux/errno" - "gvisor.dev/gvisor/pkg/errors" "gvisor.dev/gvisor/pkg/hostarch" ) @@ -111,9 +109,6 @@ const ( // ThreadStateDone means that last event has been handled and the stub thread // can be resumed. ThreadStateDone - // ThreadStateEvent means that there is a new event which has to be handled by - // Sentry. (Used only if !contextDecoupledExp) - ThreadStateEvent // ThreadStatePrep means that syshandler started filling the sysmsg struct. ThreadStatePrep // ThreadStateAsleep means that this thread fell asleep because there was not @@ -164,27 +159,6 @@ type Msg struct { Line int32 // Debug is a variable to use to get visibility into the stub from the sentry. Debug uint64 - // fpState is an offset relative to the sighandler stack to the fpState, stored - // by the sighandler. - fpState uint64 - // The fast path is the mode when a thread is polling msg->state to - // wait for a required state instead of calling FUTEX_WAIT. - // - // If core tagging is supported by the kernel, the Sentry thread, and a - // stub thread share the same cookie and run on two associated - // hyper-threads. The thread which is polling msg->state calls the - // pause instruction, so the second thread gets almost the entire core - // to run its workload. - // - // If core tagging isn't supported, a polling thread calls sched_yield - // to let other processes to run. - - // StubFastPath is set if a stub process uses the fast path to wait for - // events. Only the stub thread can set it before switching to the - // sentry, but the Sentry can clear it. - stubFastPath uint32 - sentryFastPath uint32 - AckedEvents uint32 // ThreadID is the ID of the sysmsg thread. ThreadID uint32 } @@ -292,9 +266,8 @@ type ThreadContext struct { func (m *Msg) Init(threadID uint32) { m.Err = 0 m.Line = -1 - m.stubFastPath = 0 - m.sentryFastPath = 1 m.ThreadID = threadID + m.Context = 0 } // Init initializes the ThreadContext instance. @@ -307,40 +280,6 @@ func (c *ThreadContext) Init(initialThreadID uint32) { c.ThreadID = initialThreadID } -// StubFastPath returns true if the stub thread in the polling mode. -func (m *Msg) StubFastPath() bool { - return atomic.LoadUint32(&m.stubFastPath) != 0 -} - -// DisableStubFastPath disables the polling mode for the stub thread. -func (m *Msg) DisableStubFastPath() { - atomic.StoreUint32(&m.stubFastPath, 0) -} - -// EnableSentryFastPath enables the polling mode for the Sentry. It has to be -// called before switching controls to the stub process. -// This function is used if contextDecouplingExp=false because the fastpath -// is negotiated in Sysmsg. -func (m *Msg) EnableSentryFastPath() { - m.sentryFastPath = 1 -} - -// DisableSentryFastPath disables the polling mode for the Sentry. -// This function is used if contextDecouplingExp=false because the fastpath -// is negotiated in Sysmsg. -func (m *Msg) DisableSentryFastPath() { - atomic.StoreUint32(&m.sentryFastPath, 0) -} - -// FPUStateOffset returns the offset of a saved FPU state to the msg. -func (m *Msg) FPUStateOffset() (uint64, error) { - offset := m.fpState - if int64(offset) > -MsgOffsetFromSharedStack && int64(offset) < 0 { - return offset, nil - } - return 0, errors.New(errno.EFAULT, fmt.Sprintf("FPU offset has been corrupted: %x", offset)) -} - func (m *Msg) String() string { var b strings.Builder fmt.Fprintf(&b, "sysmsg.Msg{msg: %x state %d", m.Self, m.State) diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg.h index 5590bc949..432297987 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg.h +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg.h @@ -41,7 +41,6 @@ struct arch_state { enum thread_state { THREAD_STATE_NONE, THREAD_STATE_DONE, - THREAD_STATE_EVENT, THREAD_STATE_PREP, THREAD_STATE_ASLEEP, THREAD_STATE_INITIALIZING, @@ -66,10 +65,6 @@ struct sysmsg { int32_t err; int32_t err_line; uint64_t debug; - uint64_t fpstate; - uint32_t stub_fast_path; - uint32_t sentry_fast_path; - uint32_t acked_events; uint32_t thread_id; }; @@ -122,7 +117,6 @@ struct thread_context { extern uint64_t __export_pr_sched_core; extern uint64_t __export_deep_sleep_timeout; extern struct arch_state __export_arch_state; -extern uint64_t __export_context_decoupling_exp; struct context_queue; extern struct context_queue *__export_context_queue_addr; @@ -154,10 +148,7 @@ static void __panic(int err, long line) { struct thread_context *ctx = sysmsg->context; sysmsg->err = err; sysmsg->err_line = line; - // Normally sentry waits on sysmsg->state. - __atomic_store_n(&sysmsg->state, THREAD_STATE_EVENT, __ATOMIC_RELEASE); - sys_futex(&sysmsg->state, FUTEX_WAKE, 1, NULL, NULL, 666); - // Under context-decoupling the sentry waits on ctx->state. + // Wake up the goroutine waiting on the current context. __atomic_store_n(&ctx->state, CONTEXT_STATE_FAULT, __ATOMIC_RELEASE); sys_futex(&ctx->state, FUTEX_WAKE, 1, NULL, NULL, 666); // crash the stub process. diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c b/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c index 2ce172e6d..69c1aed9d 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c @@ -27,7 +27,6 @@ // __export_deep_sleep_timeout is the timeout after which the stub thread stops // polling and fall asleep. uint64_t __export_deep_sleep_timeout; -uint64_t __export_handshake_timeout; // LINT.IfChange #define MAX_GUEST_CONTEXTS (4095) @@ -372,66 +371,6 @@ struct thread_context *switch_context(struct sysmsg *sysmsg, return get_context(sysmsg); } -int wait_state(struct sysmsg *sysmsg, enum thread_state new_thread_state) { - unsigned long handshake_timeout; - uint64_t acked_events_prev; - unsigned long start; - int ret, v, fast_path; - - acked_events_prev = __atomic_load_n(&sysmsg->acked_events, __ATOMIC_SEQ_CST); - // stub_fast_path can be changed non-atomically before we change the state and - // wake up the Sentry. - sysmsg->stub_fast_path = 1; - __atomic_store_n(&sysmsg->state, new_thread_state, __ATOMIC_SEQ_CST); - - fast_path = __atomic_load_n(&sysmsg->sentry_fast_path, __ATOMIC_SEQ_CST); - if (!fast_path) { - ret = sys_futex(&sysmsg->state, FUTEX_WAKE, 1, NULL, NULL, 0); - if (ret < 0) panic(ret); - } - - v = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if (v == THREAD_STATE_DONE) goto out; - - handshake_timeout = __export_handshake_timeout; - start = rdtsc(); - while (1) { - v = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if (v == THREAD_STATE_DONE) goto out; - - // The Sentry can change stub_fast_path to zero if it finds out that the - // user task has to sleep. - fast_path = __atomic_load_n(&sysmsg->stub_fast_path, __ATOMIC_ACQUIRE); - if (fast_path) { - unsigned long delta = rdtsc() - start; - - if (delta > __export_deep_sleep_timeout) { - fast_path = 0; - __atomic_store_n(&sysmsg->stub_fast_path, 0, __ATOMIC_SEQ_CST); - } - if (handshake_timeout != 0) { - if (__atomic_load_n(&sysmsg->acked_events, __ATOMIC_SEQ_CST) != - acked_events_prev) { - handshake_timeout = 0; - } else if (delta > handshake_timeout) { - __syscall(__NR_sched_yield, 0, 0, 0, 0, 0, 0); - handshake_timeout += __export_handshake_timeout; - continue; - } - } - } - - if (fast_path) { - spinloop(); - } else { - sys_futex(&sysmsg->state, FUTEX_WAIT, v, NULL, NULL, 0); - } - } -out: - __atomic_fetch_add(&sysmsg->acked_events, 1, __ATOMIC_SEQ_CST); - return v; -} - void verify_offsets() { BUILD_BUG_ON(offsetof_sysmsg_self != offsetof(struct sysmsg, self)); BUILD_BUG_ON(offsetof_sysmsg_ret_addr != offsetof(struct sysmsg, ret_addr)); diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h index 5daed1bbd..4689f0dde 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h @@ -46,7 +46,7 @@ #define offsetof_thread_context_ptregs 0x8 + MAX_FPSTATE_LEN #define kTHREAD_STATE_NONE 0 -#define kTHREAD_STATE_INTERRUPT 4 +#define kTHREAD_STATE_INTERRUPT 3 // LINT.ThenChange(sysmsg.h, sysmsg_lib.c) diff --git a/pkg/sentry/platform/systrap/sysmsg_thread.go b/pkg/sentry/platform/systrap/sysmsg_thread.go index b6b5c29c0..416bff7ec 100644 --- a/pkg/sentry/platform/systrap/sysmsg_thread.go +++ b/pkg/sentry/platform/systrap/sysmsg_thread.go @@ -16,7 +16,6 @@ package systrap import ( "fmt" - "sync/atomic" "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" @@ -24,7 +23,6 @@ import ( "gvisor.dev/gvisor/pkg/seccomp" "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/sentry/memmap" - "gvisor.dev/gvisor/pkg/sentry/platform/interrupt" "gvisor.dev/gvisor/pkg/sentry/platform/systrap/sysmsg" ) @@ -34,8 +32,7 @@ import ( // This type of thread is used to execute user processes. type sysmsgThread struct { // subproc is a link to the subprocess which is used to call native - // system calls and track when a sysmsg thread has to be recreated. - // Look at getSysmsgThread() for more details. + // system calls. subproc *subprocess // thread is a thread identifier. @@ -55,7 +52,8 @@ type sysmsgThread struct { fpuStateToMsgOffset uint64 } -// sysmsgStackAddr returns a sysmsg stack address in the thread address space. +// sysmsgPerThreadMemAddr returns a sysmsg stack address in the thread address +// space. func (p *sysmsgThread) sysmsgPerThreadMemAddr() uintptr { return stubSysmsgStack + sysmsg.PerThreadMemSize*uintptr(p.thread.sysmsgStackID) } @@ -117,22 +115,6 @@ func (p *sysmsgThread) mapPrivateStack(addr uintptr, size uintptr) error { return err } -func (p *sysmsgThread) waitEvent(switchToState sysmsg.ThreadState, interruptor interrupt.Receiver) { - msg := p.msg - wakeup := false - acked := atomic.LoadUint32(&msg.AckedEvents) - if switchToState != sysmsg.ThreadStateNone { - msg.State.Set(switchToState) - wakeup = msg.StubFastPath() == false - } else { - acked-- - } - - if errno := futexWaitForState(msg, sysmsg.ThreadStateEvent, wakeup, acked, interruptor); errno != 0 { - panic(fmt.Sprintf("error waiting for state: %v", errno)) - } -} - func (p *sysmsgThread) Debugf(format string, v ...any) { if !log.IsLogging(log.Debug) { return diff --git a/pkg/sentry/platform/systrap/sysmsg_thread_unsafe.go b/pkg/sentry/platform/systrap/sysmsg_thread_unsafe.go index 90c016419..ec71034a8 100644 --- a/pkg/sentry/platform/systrap/sysmsg_thread_unsafe.go +++ b/pkg/sentry/platform/systrap/sysmsg_thread_unsafe.go @@ -16,15 +16,11 @@ package systrap import ( "fmt" - "runtime" - "sync/atomic" - "syscall" "unsafe" "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/sentry/arch" - "gvisor.dev/gvisor/pkg/sentry/platform/interrupt" "gvisor.dev/gvisor/pkg/sentry/platform/systrap/sysmsg" ) @@ -78,82 +74,6 @@ func (p *sysmsgThread) init(sentryAddr, guestAddr uintptr) { } } -func futexWake(msg *sysmsg.Msg) syscall.Errno { - _, _, e := unix.RawSyscall6(unix.SYS_FUTEX, uintptr(unsafe.Pointer(&msg.State)), linux.FUTEX_WAKE, 1, 0, 0, 0) - return e -} - -//go:linkname cputicks runtime.cputicks -func cputicks() int64 - -// spinloop is implemented in assembly. -func spinloop() - -//go:linkname entersyscall runtime.entersyscall -func entersyscall() - -//go:linkname exitsyscall runtime.exitsyscall -func exitsyscall() - -// deep_sleep_timeout is the timeout after which we stops polling and fall asleep. -// -// The value is 40µs for 2GHz CPU. This timeout matches the sentry<->stub round -// trip in the pure deep sleep case. -const deepSleepTimeout = uint64(80000) -const handshakeTimeout = uint64(1000) - -func futexWaitForState(msg *sysmsg.Msg, state sysmsg.ThreadState, wakeup bool, acked uint32, interruptor interrupt.Receiver) syscall.Errno { - slowPath := false - errno := syscall.Errno(0) - start := cputicks() - htimeout := handshakeTimeout - handshake := false - for { - curState := msg.State.Get() - if curState == state { - break - } - if wakeup { - if errno = futexWake(msg); errno != 0 { - break - } - wakeup = false - continue - } - - if !slowPath { - delta := uint64(cputicks() - start) - if delta > deepSleepTimeout { - msg.DisableSentryFastPath() - slowPath = true - continue - } - - if !handshake { - if acked != atomic.LoadUint32(&msg.AckedEvents) { - handshake = true - continue - } - if delta > htimeout { - htimeout += handshakeTimeout - runtime.Gosched() - } - } - } - - if slowPath { - errno = msg.SleepOnState(curState, interruptor) - if errno != 0 { - break - } - } else { - spinloop() - } - } - atomic.AddUint32(&msg.AckedEvents, 1) - return errno -} - // sysmsgSigactions installs signal handles for signals which can be triggered // by stubProcess and have to be handled by Sentry. // diff --git a/pkg/sentry/platform/systrap/systrap.go b/pkg/sentry/platform/systrap/systrap.go index d8f9b7613..426b1c51a 100644 --- a/pkg/sentry/platform/systrap/systrap.go +++ b/pkg/sentry/platform/systrap/systrap.go @@ -136,10 +136,6 @@ type context struct { // this is also only meaningful if lastFaultSP is non-nil. lastFaultIP hostarch.Addr - // sysmsgThread is a sysmsg thread descriptor which is used to execute - // application code. (Note: Unused if contextDecouplingExp=true). - sysmsgThread *sysmsgThread - // needRestoreFPState indicates that the FPU state has been changed by // the Sentry and has to be updated on the stub thread. needRestoreFPState bool @@ -278,9 +274,6 @@ func (c *context) Interrupt() { // Release releases all platform resources used by the context. func (c *context) Release() { - if c.sysmsgThread != nil { - c.sysmsgThread.destroy() - } if c.sharedContext != nil { c.sharedContext.release() c.sharedContext = nil @@ -289,18 +282,13 @@ func (c *context) Release() { // PrepareSleep implements platform.Context.platform.PrepareSleep. func (c *context) PrepareSleep() { - if contextDecouplingExp { - ctx := c.sharedContext - if ctx == nil { - return - } - if !ctx.sleeping { - ctx.sleeping = true - ctx.subprocess.decAwakeContexts() - } + ctx := c.sharedContext + if ctx == nil { return - } else if c.sysmsgThread != nil { - c.sysmsgThread.msg.DisableStubFastPath() + } + if !ctx.sleeping { + ctx.sleeping = true + ctx.subprocess.decAwakeContexts() } }