kernel: don't hold TaskSet.mu during most of Kernel.runCPUClockTicker()

The removed `tg.leader == nil` check doesn't actually affect the correctness of
the rest of the loop body.

PiperOrigin-RevId: 681163998
This commit is contained in:
Jamie Liu
2024-10-01 14:25:47 -07:00
committed by gVisor bot
parent 51fa369cf1
commit a32d047f68
3 changed files with 11 additions and 13 deletions
+2 -2
View File
@@ -737,13 +737,13 @@ func (t *Task) exitNotifyLocked(fromPtraceDetach bool) {
ns.deleteTask(t)
}
t.userCounters.decRLimitNProc()
t.tg.exitedCPUStats.Accumulate(t.CPUStats())
t.tg.ioUsage.Accumulate(t.ioUsage)
t.tg.signalHandlers.mu.Lock()
t.tg.tasks.Remove(t)
t.tg.tasksCount--
tc := t.tg.tasksCount
t.tg.exitedCPUStats.Accumulate(t.CPUStats())
t.tg.signalHandlers.mu.Unlock()
t.tg.ioUsage.Accumulate(t.ioUsage)
if tc == 1 && t != t.tg.leader {
// Our fromPtraceDetach doesn't matter here (in Linux terms, this
// is via a call to release_task()).
+4 -10
View File
@@ -204,7 +204,7 @@ func (tg *ThreadGroup) CPUStats() usage.CPUStats {
}
// Preconditions: Same as TaskGoroutineSchedInfo.userTicksAt, plus:
// - The TaskSet mutex must be locked.
// - Either the TaskSet mutex or the signal mutex must be locked.
func (tg *ThreadGroup) cpuStatsAtLocked(now uint64) usage.CPUStats {
stats := tg.exitedCPUStats
// Account for live tasks.
@@ -375,12 +375,8 @@ func (k *Kernel) runCPUClockTicker() {
continue
}
k.tasks.mu.RLock()
if tg.leader == nil {
// No tasks have ever run in this thread group.
k.tasks.mu.RUnlock()
continue
}
sh := tg.signalLock()
// Accumulate thread group CPU stats, and randomly select running tasks
// using reservoir sampling to receive CPU timer signals.
var virtReceiver *Task
@@ -415,7 +411,6 @@ func (k *Kernel) runCPUClockTicker() {
// All of the following are standard (not real-time) signals, which are
// automatically deduplicated, so we ignore the number of expirations.
tg.signalHandlers.mu.Lock()
// It should only be possible for these timers to advance if we found
// at least one running task.
if virtReceiver != nil {
@@ -445,9 +440,8 @@ func (k *Kernel) runCPUClockTicker() {
profReceiver.sendSignalLocked(SignalInfoPriv(linux.SIGKILL), true)
}
}
tg.signalHandlers.mu.Unlock()
k.tasks.mu.RUnlock()
sh.mu.Unlock()
}
k.cpuClockMu.Unlock()
+5 -1
View File
@@ -204,7 +204,11 @@ type ThreadGroup struct {
nextTimerID linux.TimerID
// exitedCPUStats is the CPU usage for all exited tasks in the thread
// group. exitedCPUStats is protected by the TaskSet mutex.
// group. exitedCPUStats is protected by both the TaskSet mutex and the
// signal mutex. Mutating it requires that the TaskSet mutex is locked for
// writing *and* that the signal mutex is locked. Reading it requires
// locking the TaskSet mutex (for reading or writing) *or* locking the
// signal mutex.
exitedCPUStats usage.CPUStats
// childCPUStats is the CPU usage of all joined descendants of this thread