github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 "github.com/SagerNet/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 // defer f.Disable() 56 // 57 // Preconditions: 58 // * r must not be nil. 59 // * f must not already be forwarding interrupts to a Receiver. 60 func (f *Forwarder) Enable(r Receiver) bool { 61 if r == nil { 62 panic("nil Receiver") 63 } 64 f.mu.Lock() 65 if f.dst != nil { 66 f.mu.Unlock() 67 panic(fmt.Sprintf("already forwarding interrupts to %+v", f.dst)) 68 } 69 if f.pending { 70 f.pending = false 71 f.mu.Unlock() 72 return false 73 } 74 f.dst = r 75 f.mu.Unlock() 76 return true 77 } 78 79 // Disable stops interrupt forwarding. If interrupt forwarding is already 80 // disabled, Disable is a no-op. 81 func (f *Forwarder) Disable() { 82 f.mu.Lock() 83 f.dst = nil 84 f.mu.Unlock() 85 } 86 87 // NotifyInterrupt implements Receiver.NotifyInterrupt. If interrupt forwarding 88 // is enabled, the configured Receiver will be notified. Otherwise the 89 // interrupt will be delivered to the next call to Enable. 90 func (f *Forwarder) NotifyInterrupt() { 91 f.mu.Lock() 92 if f.dst != nil { 93 f.dst.NotifyInterrupt() 94 } else { 95 f.pending = true 96 } 97 f.mu.Unlock() 98 }