gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/platform/interrupt/interrupt.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 interrupt provides an interrupt helper. 16 package interrupt 17 18 import ( 19 "fmt" 20 21 "gvisor.dev/gvisor/pkg/sync" 22 ) 23 24 // Receiver receives interrupt notifications from a Forwarder. 25 type Receiver interface { 26 // NotifyInterrupt is called when the Receiver receives an interrupt. 27 NotifyInterrupt() 28 } 29 30 // Forwarder is a helper for delivering delayed signal interruptions. 31 // 32 // This helps platform implementations with Interrupt semantics. 33 type Forwarder struct { 34 // mu protects the below. 35 mu sync.Mutex 36 37 // dst is the function to be called when NotifyInterrupt() is called. If 38 // dst is nil, pending will be set instead, causing the next call to 39 // Enable() to return false. 40 dst Receiver 41 pending bool 42 } 43 44 // Enable attempts to enable interrupt forwarding to r. If f has already 45 // received an interrupt, Enable does nothing and returns false. Otherwise, 46 // future calls to f.NotifyInterrupt() cause r.NotifyInterrupt() to be called, 47 // and Enable returns true. 48 // 49 // Usage: 50 // 51 // if !f.Enable(r) { 52 // // There was an interrupt. 53 // return 54 // } 55 // 56 // defer f.Disable() 57 // 58 // Preconditions: 59 // - r must not be nil. 60 // - f must not already be forwarding interrupts to a Receiver. 61 func (f *Forwarder) Enable(r Receiver) bool { 62 if r == nil { 63 panic("nil Receiver") 64 } 65 f.mu.Lock() 66 if f.dst != nil { 67 f.mu.Unlock() 68 panic(fmt.Sprintf("already forwarding interrupts to %+v", f.dst)) 69 } 70 if f.pending { 71 f.pending = false 72 f.mu.Unlock() 73 return false 74 } 75 f.dst = r 76 f.mu.Unlock() 77 return true 78 } 79 80 // Disable stops interrupt forwarding. If interrupt forwarding is already 81 // disabled, Disable is a no-op. 82 func (f *Forwarder) Disable() { 83 f.mu.Lock() 84 f.dst = nil 85 f.mu.Unlock() 86 } 87 88 // NotifyInterrupt implements Receiver.NotifyInterrupt. If interrupt forwarding 89 // is enabled, the configured Receiver will be notified. Otherwise the 90 // interrupt will be delivered to the next call to Enable. 91 func (f *Forwarder) NotifyInterrupt() { 92 f.mu.Lock() 93 if f.dst != nil { 94 f.dst.NotifyInterrupt() 95 } else { 96 f.pending = true 97 } 98 f.mu.Unlock() 99 }