mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
Add a new method `ConcurrencyCount()` to the `platform.Platform` interface. This method returns the maximum number of tasks that can run in parallel on the platform. For most platforms, this is effectively infinite (math.MaxInt). For the KVM platform, this is the number of available vCPUs. Introduce a new method `Preempt()` to the `platform.Context` interface. The CPU clock ticker now checks if the number of running tasks is greater than Platform.ConcurrencyCount(). If it is, it calls `t.p.Preempt()` on each running task to trigger a preemption. This mechanism ensures that on platforms with a fixed number of execution units, like KVM with a limited number of vCPUs, tasks are periodically preempted to allow other runnable tasks to be scheduled. This prevents any single task from monopolizing a vCPU and improves overall fairness and responsiveness. The `Preempt()` implementation in most platforms is a no-op. In the KVM platform, `Preempt()` is implemented by leveraging the existing interrupt mechanism, effectively signaling the vCPU to exit. PiperOrigin-RevId: 805926296
111 lines
2.9 KiB
Go
111 lines
2.9 KiB
Go
// Copyright 2018 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.
|
|
|
|
// Package interrupt provides an interrupt helper.
|
|
package interrupt
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gvisor.dev/gvisor/pkg/sync"
|
|
)
|
|
|
|
// Receiver receives interrupt notifications from a Forwarder.
|
|
type Receiver interface {
|
|
// NotifyInterrupt is called when the Receiver receives an interrupt.
|
|
NotifyInterrupt()
|
|
}
|
|
|
|
// Forwarder is a helper for delivering delayed signal interruptions.
|
|
//
|
|
// This helps platform implementations with Interrupt semantics.
|
|
type Forwarder struct {
|
|
// mu protects the below.
|
|
mu sync.Mutex
|
|
|
|
// dst is the function to be called when NotifyInterrupt() is called. If
|
|
// dst is nil, pending will be set instead, causing the next call to
|
|
// Enable() to return false.
|
|
dst Receiver
|
|
pending bool
|
|
}
|
|
|
|
// Enable attempts to enable interrupt forwarding to r. If f has already
|
|
// received an interrupt, Enable does nothing and returns false. Otherwise,
|
|
// future calls to f.NotifyInterrupt() cause r.NotifyInterrupt() to be called,
|
|
// and Enable returns true.
|
|
//
|
|
// Usage:
|
|
//
|
|
// if !f.Enable(r) {
|
|
// // There was an interrupt.
|
|
// return
|
|
// }
|
|
//
|
|
// defer f.Disable()
|
|
//
|
|
// Preconditions:
|
|
// - r must not be nil.
|
|
// - f must not already be forwarding interrupts to a Receiver.
|
|
func (f *Forwarder) Enable(r Receiver) bool {
|
|
if r == nil {
|
|
panic("nil Receiver")
|
|
}
|
|
f.mu.Lock()
|
|
if f.dst != nil {
|
|
f.mu.Unlock()
|
|
panic(fmt.Sprintf("already forwarding interrupts to %+v", f.dst))
|
|
}
|
|
if f.pending {
|
|
f.pending = false
|
|
f.mu.Unlock()
|
|
return false
|
|
}
|
|
f.dst = r
|
|
f.mu.Unlock()
|
|
return true
|
|
}
|
|
|
|
// Disable stops interrupt forwarding. If interrupt forwarding is already
|
|
// disabled, Disable is a no-op.
|
|
func (f *Forwarder) Disable() {
|
|
f.mu.Lock()
|
|
f.dst = nil
|
|
f.mu.Unlock()
|
|
}
|
|
|
|
// NotifyInterrupt implements Receiver.NotifyInterrupt. If interrupt forwarding
|
|
// is enabled, the configured Receiver will be notified. Otherwise the
|
|
// interrupt will be delivered to the next call to Enable.
|
|
func (f *Forwarder) NotifyInterrupt() {
|
|
f.mu.Lock()
|
|
if f.dst != nil {
|
|
f.dst.NotifyInterrupt()
|
|
} else {
|
|
f.pending = true
|
|
}
|
|
f.mu.Unlock()
|
|
}
|
|
|
|
// Preempt preempts the running context. Preempt is a weaker version of
|
|
// NotifyInterrupt, it doesn't set the pending flag which is set when a context
|
|
// isn't actually running at this moment.
|
|
func (f *Forwarder) Preempt() {
|
|
f.mu.Lock()
|
|
if f.dst != nil {
|
|
f.dst.NotifyInterrupt()
|
|
}
|
|
f.mu.Unlock()
|
|
}
|