Skip to content

Commit f14d87d

Browse files
nixprimegvisor-bot
authored andcommitted
sentry/kernel: allow pending signal sets to be read without locking
PiperOrigin-RevId: 772512411
1 parent 85c27ad commit f14d87d

File tree

3 files changed

+11
-14
lines changed

3 files changed

+11
-14
lines changed

pkg/sentry/kernel/pending_signals.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package kernel
1616

1717
import (
1818
"gvisor.dev/gvisor/pkg/abi/linux"
19+
"gvisor.dev/gvisor/pkg/atomicbitops"
1920
"gvisor.dev/gvisor/pkg/bits"
2021
)
2122

@@ -49,7 +50,7 @@ type pendingSignals struct {
4950

5051
// Bit i of pendingSet is set iff there is at least one signal with signo
5152
// i+1 pending.
52-
pendingSet linux.SignalSet `state:"manual"`
53+
pendingSet atomicbitops.Uint64 `state:"manual"`
5354
}
5455

5556
// pendingSignalQueue holds a pendingSignalList for a single signal number.
@@ -86,7 +87,7 @@ func (p *pendingSignals) enqueue(info *linux.SignalInfo, timer *IntervalTimer) b
8687
}
8788
q.pendingSignalList.PushBack(&pendingSignal{SignalInfo: info, timer: timer})
8889
q.length++
89-
p.pendingSet |= linux.SignalSetOf(sig)
90+
p.pendingSet.Store(p.pendingSet.RacyLoad() | uint64(linux.SignalSetOf(sig)))
9091
return true
9192
}
9293

@@ -103,7 +104,7 @@ func (p *pendingSignals) dequeue(mask linux.SignalSet) *linux.SignalInfo {
103104
// process, POSIX leaves it unspecified which is delivered first. Linux,
104105
// like many other implementations, gives priority to standard signals in
105106
// this case." - signal(7)
106-
lowestPendingUnblockedBit := bits.TrailingZeros64(uint64(p.pendingSet &^ mask))
107+
lowestPendingUnblockedBit := bits.TrailingZeros64(p.pendingSet.RacyLoad() &^ uint64(mask))
107108
if lowestPendingUnblockedBit >= linux.SignalMaximum {
108109
return nil
109110
}
@@ -119,7 +120,7 @@ func (p *pendingSignals) dequeueSpecific(sig linux.Signal) *linux.SignalInfo {
119120
q.pendingSignalList.Remove(ps)
120121
q.length--
121122
if q.length == 0 {
122-
p.pendingSet &^= linux.SignalSetOf(sig)
123+
p.pendingSet.Store(p.pendingSet.RacyLoad() &^ uint64(linux.SignalSetOf(sig)))
123124
}
124125
if ps.timer != nil {
125126
ps.timer.updateDequeuedSignalLocked(ps.SignalInfo)
@@ -137,5 +138,5 @@ func (p *pendingSignals) discardSpecific(sig linux.Signal) {
137138
}
138139
q.pendingSignalList.Reset()
139140
q.length = 0
140-
p.pendingSet &^= linux.SignalSetOf(sig)
141+
p.pendingSet.Store(p.pendingSet.RacyLoad() &^ uint64(linux.SignalSetOf(sig)))
141142
}

pkg/sentry/kernel/task_exit.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,12 @@ func (t *Task) killLocked() {
105105
//
106106
// Preconditions: The caller must be running on the task goroutine.
107107
func (t *Task) killed() bool {
108-
t.tg.signalHandlers.mu.Lock()
109-
defer t.tg.signalHandlers.mu.Unlock()
110-
return t.killedLocked()
108+
return linux.SignalSet(t.pendingSignals.pendingSet.Load())&linux.SignalSetOf(linux.SIGKILL) != 0
111109
}
112110

113111
// Preconditions: The signal mutex must be locked.
114112
func (t *Task) killedLocked() bool {
115-
return t.pendingSignals.pendingSet&linux.SignalSetOf(linux.SIGKILL) != 0
113+
return linux.SignalSet(t.pendingSignals.pendingSet.RacyLoad())&linux.SignalSetOf(linux.SIGKILL) != 0
116114
}
117115

118116
// PrepareExit indicates an exit with the given status.

pkg/sentry/kernel/task_signals.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,7 @@ func (tg *ThreadGroup) discardSpecificLocked(sig linux.Signal) {
146146

147147
// PendingSignals returns the set of pending signals.
148148
func (t *Task) PendingSignals() linux.SignalSet {
149-
sh := t.tg.signalLock()
150-
defer sh.mu.Unlock()
151-
return t.pendingSignals.pendingSet | t.tg.pendingSignals.pendingSet
149+
return linux.SignalSet(t.pendingSignals.pendingSet.Load() | t.tg.pendingSignals.pendingSet.Load())
152150
}
153151

154152
// deliverSignal delivers the given signal and returns the following run state.
@@ -612,7 +610,7 @@ func (t *Task) setSignalMaskLocked(mask linux.SignalSet) {
612610
// signal, but will no longer do so as a result of its new signal mask, so
613611
// we have to pick a replacement.
614612
blocked := mask &^ oldMask
615-
blockedGroupPending := blocked & t.tg.pendingSignals.pendingSet
613+
blockedGroupPending := blocked & linux.SignalSet(t.tg.pendingSignals.pendingSet.RacyLoad())
616614
if blockedGroupPending != 0 && t.interrupted() {
617615
linux.ForEachSignal(blockedGroupPending, func(sig linux.Signal) {
618616
if nt := t.tg.findSignalReceiverLocked(sig); nt != nil {
@@ -626,7 +624,7 @@ func (t *Task) setSignalMaskLocked(mask linux.SignalSet) {
626624
// the old mask, and at least one such signal is pending, we may now need
627625
// to handle that signal.
628626
unblocked := oldMask &^ mask
629-
unblockedPending := unblocked & (t.pendingSignals.pendingSet | t.tg.pendingSignals.pendingSet)
627+
unblockedPending := unblocked & linux.SignalSet(t.pendingSignals.pendingSet.RacyLoad()|t.tg.pendingSignals.pendingSet.RacyLoad())
630628
if unblockedPending != 0 {
631629
t.interruptSelf()
632630
}

0 commit comments

Comments
 (0)