github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/kernel/task_sched.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 kernel
    16  
    17  // CPU scheduling, real and fake.
    18  
    19  import (
    20  	"fmt"
    21  	"math/rand"
    22  	"time"
    23  
    24  	"github.com/metacubex/gvisor/pkg/abi/linux"
    25  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    26  	"github.com/metacubex/gvisor/pkg/sentry/hostcpu"
    27  	"github.com/metacubex/gvisor/pkg/sentry/kernel/sched"
    28  	ktime "github.com/metacubex/gvisor/pkg/sentry/kernel/time"
    29  	"github.com/metacubex/gvisor/pkg/sentry/limits"
    30  	"github.com/metacubex/gvisor/pkg/sentry/usage"
    31  )
    32  
    33  // TaskGoroutineState is a coarse representation of the current execution
    34  // status of a kernel.Task goroutine.
    35  type TaskGoroutineState int
    36  
    37  const (
    38  	// TaskGoroutineNonexistent indicates that the task goroutine has either
    39  	// not yet been created by Task.Start() or has returned from Task.run().
    40  	// This must be the zero value for TaskGoroutineState.
    41  	TaskGoroutineNonexistent TaskGoroutineState = iota
    42  
    43  	// TaskGoroutineRunningSys indicates that the task goroutine is executing
    44  	// sentry code.
    45  	TaskGoroutineRunningSys
    46  
    47  	// TaskGoroutineRunningApp indicates that the task goroutine is executing
    48  	// application code.
    49  	TaskGoroutineRunningApp
    50  
    51  	// TaskGoroutineBlockedInterruptible indicates that the task goroutine is
    52  	// blocked in Task.block(), and hence may be woken by Task.interrupt()
    53  	// (e.g. due to signal delivery).
    54  	TaskGoroutineBlockedInterruptible
    55  
    56  	// TaskGoroutineBlockedUninterruptible indicates that the task goroutine is
    57  	// stopped outside of Task.block() and Task.doStop(), and hence cannot be
    58  	// woken by Task.interrupt().
    59  	TaskGoroutineBlockedUninterruptible
    60  
    61  	// TaskGoroutineStopped indicates that the task goroutine is blocked in
    62  	// Task.doStop(). TaskGoroutineStopped is similar to
    63  	// TaskGoroutineBlockedUninterruptible, but is a separate state to make it
    64  	// possible to determine when Task.stop is meaningful.
    65  	TaskGoroutineStopped
    66  )
    67  
    68  // TaskGoroutineSchedInfo contains task goroutine scheduling state which must
    69  // be read and updated atomically.
    70  //
    71  // +stateify savable
    72  type TaskGoroutineSchedInfo struct {
    73  	// Timestamp was the value of Kernel.cpuClock when this
    74  	// TaskGoroutineSchedInfo was last updated.
    75  	Timestamp uint64
    76  
    77  	// State is the current state of the task goroutine.
    78  	State TaskGoroutineState
    79  
    80  	// UserTicks is the amount of time the task goroutine has spent executing
    81  	// its associated Task's application code, in units of linux.ClockTick.
    82  	UserTicks uint64
    83  
    84  	// SysTicks is the amount of time the task goroutine has spent executing in
    85  	// the sentry, in units of linux.ClockTick.
    86  	SysTicks uint64
    87  }
    88  
    89  // userTicksAt returns the extrapolated value of ts.UserTicks after
    90  // Kernel.CPUClockNow() indicates a time of now.
    91  //
    92  // Preconditions: now <= Kernel.CPUClockNow(). (Since Kernel.cpuClock is
    93  // monotonic, this is satisfied if now is the result of a previous call to
    94  // Kernel.CPUClockNow().) This requirement exists because otherwise a racing
    95  // change to t.gosched can cause userTicksAt to adjust stats by too much,
    96  // making the observed stats non-monotonic.
    97  func (ts *TaskGoroutineSchedInfo) userTicksAt(now uint64) uint64 {
    98  	if ts.Timestamp < now && ts.State == TaskGoroutineRunningApp {
    99  		// Update stats to reflect execution since the last update.
   100  		return ts.UserTicks + (now - ts.Timestamp)
   101  	}
   102  	return ts.UserTicks
   103  }
   104  
   105  // sysTicksAt returns the extrapolated value of ts.SysTicks after
   106  // Kernel.CPUClockNow() indicates a time of now.
   107  //
   108  // Preconditions: As for userTicksAt.
   109  func (ts *TaskGoroutineSchedInfo) sysTicksAt(now uint64) uint64 {
   110  	if ts.Timestamp < now && ts.State == TaskGoroutineRunningSys {
   111  		return ts.SysTicks + (now - ts.Timestamp)
   112  	}
   113  	return ts.SysTicks
   114  }
   115  
   116  // Preconditions: The caller must be running on the task goroutine.
   117  func (t *Task) accountTaskGoroutineEnter(state TaskGoroutineState) {
   118  	now := t.k.CPUClockNow()
   119  	if t.gosched.State != TaskGoroutineRunningSys {
   120  		panic(fmt.Sprintf("Task goroutine switching from state %v (expected %v) to %v", t.gosched.State, TaskGoroutineRunningSys, state))
   121  	}
   122  	t.goschedSeq.BeginWrite()
   123  	// This function is very hot; avoid defer.
   124  	t.gosched.SysTicks += now - t.gosched.Timestamp
   125  	t.gosched.Timestamp = now
   126  	t.gosched.State = state
   127  	t.goschedSeq.EndWrite()
   128  
   129  	if state != TaskGoroutineRunningApp {
   130  		// Task is blocking/stopping.
   131  		t.k.decRunningTasks()
   132  	}
   133  }
   134  
   135  // Preconditions:
   136  //   - The caller must be running on the task goroutine
   137  //   - The caller must be leaving a state indicated by a previous call to
   138  //     t.accountTaskGoroutineEnter(state).
   139  func (t *Task) accountTaskGoroutineLeave(state TaskGoroutineState) {
   140  	if state != TaskGoroutineRunningApp {
   141  		// Task is unblocking/continuing.
   142  		t.k.incRunningTasks()
   143  	}
   144  
   145  	now := t.k.CPUClockNow()
   146  	if t.gosched.State != state {
   147  		panic(fmt.Sprintf("Task goroutine switching from state %v (expected %v) to %v", t.gosched.State, state, TaskGoroutineRunningSys))
   148  	}
   149  	t.goschedSeq.BeginWrite()
   150  	// This function is very hot; avoid defer.
   151  	if state == TaskGoroutineRunningApp {
   152  		t.gosched.UserTicks += now - t.gosched.Timestamp
   153  	}
   154  	t.gosched.Timestamp = now
   155  	t.gosched.State = TaskGoroutineRunningSys
   156  	t.goschedSeq.EndWrite()
   157  }
   158  
   159  // Preconditions: The caller must be running on the task goroutine.
   160  func (t *Task) accountTaskGoroutineRunning() {
   161  	now := t.k.CPUClockNow()
   162  	if t.gosched.State != TaskGoroutineRunningSys {
   163  		panic(fmt.Sprintf("Task goroutine in state %v (expected %v)", t.gosched.State, TaskGoroutineRunningSys))
   164  	}
   165  	t.goschedSeq.BeginWrite()
   166  	t.gosched.SysTicks += now - t.gosched.Timestamp
   167  	t.gosched.Timestamp = now
   168  	t.goschedSeq.EndWrite()
   169  }
   170  
   171  // TaskGoroutineSchedInfo returns a copy of t's task goroutine scheduling info.
   172  // Most clients should use t.CPUStats() instead.
   173  func (t *Task) TaskGoroutineSchedInfo() TaskGoroutineSchedInfo {
   174  	return SeqAtomicLoadTaskGoroutineSchedInfo(&t.goschedSeq, &t.gosched)
   175  }
   176  
   177  // CPUStats returns the CPU usage statistics of t.
   178  func (t *Task) CPUStats() usage.CPUStats {
   179  	return t.cpuStatsAt(t.k.CPUClockNow())
   180  }
   181  
   182  // Preconditions: As for TaskGoroutineSchedInfo.userTicksAt.
   183  func (t *Task) cpuStatsAt(now uint64) usage.CPUStats {
   184  	tsched := t.TaskGoroutineSchedInfo()
   185  	return usage.CPUStats{
   186  		UserTime:          time.Duration(tsched.userTicksAt(now) * uint64(linux.ClockTick)),
   187  		SysTime:           time.Duration(tsched.sysTicksAt(now) * uint64(linux.ClockTick)),
   188  		VoluntarySwitches: t.yieldCount.Load(),
   189  	}
   190  }
   191  
   192  // CPUStats returns the combined CPU usage statistics of all past and present
   193  // threads in tg.
   194  func (tg *ThreadGroup) CPUStats() usage.CPUStats {
   195  	tg.pidns.owner.mu.RLock()
   196  	defer tg.pidns.owner.mu.RUnlock()
   197  	// Hack to get a pointer to the Kernel.
   198  	if tg.leader == nil {
   199  		// Per comment on tg.leader, this is only possible if nothing in the
   200  		// ThreadGroup has ever executed anyway.
   201  		return usage.CPUStats{}
   202  	}
   203  	return tg.cpuStatsAtLocked(tg.leader.k.CPUClockNow())
   204  }
   205  
   206  // Preconditions: Same as TaskGoroutineSchedInfo.userTicksAt, plus:
   207  //   - The TaskSet mutex must be locked.
   208  func (tg *ThreadGroup) cpuStatsAtLocked(now uint64) usage.CPUStats {
   209  	stats := tg.exitedCPUStats
   210  	// Account for live tasks.
   211  	for t := tg.tasks.Front(); t != nil; t = t.Next() {
   212  		stats.Accumulate(t.cpuStatsAt(now))
   213  	}
   214  	return stats
   215  }
   216  
   217  // JoinedChildCPUStats implements the semantics of RUSAGE_CHILDREN: "Return
   218  // resource usage statistics for all children of [tg] that have terminated and
   219  // been waited for. These statistics will include the resources used by
   220  // grandchildren, and further removed descendants, if all of the intervening
   221  // descendants waited on their terminated children."
   222  func (tg *ThreadGroup) JoinedChildCPUStats() usage.CPUStats {
   223  	tg.pidns.owner.mu.RLock()
   224  	defer tg.pidns.owner.mu.RUnlock()
   225  	return tg.childCPUStats
   226  }
   227  
   228  // taskClock is a ktime.Clock that measures the time that a task has spent
   229  // executing. taskClock is primarily used to implement CLOCK_THREAD_CPUTIME_ID.
   230  //
   231  // +stateify savable
   232  type taskClock struct {
   233  	t *Task
   234  
   235  	// If includeSys is true, the taskClock includes both time spent executing
   236  	// application code as well as time spent in the sentry. Otherwise, the
   237  	// taskClock includes only time spent executing application code.
   238  	includeSys bool
   239  
   240  	// Implements waiter.Waitable. TimeUntil wouldn't change its estimation
   241  	// based on either of the clock events, so there's no event to be
   242  	// notified for.
   243  	ktime.NoClockEvents `state:"nosave"`
   244  
   245  	// Implements ktime.Clock.WallTimeUntil.
   246  	//
   247  	// As an upper bound, a task's clock cannot advance faster than CPU
   248  	// time. It would have to execute at a rate of more than 1 task-second
   249  	// per 1 CPU-second, which isn't possible.
   250  	ktime.WallRateClock `state:"nosave"`
   251  }
   252  
   253  // UserCPUClock returns a clock measuring the CPU time the task has spent
   254  // executing application code.
   255  func (t *Task) UserCPUClock() ktime.Clock {
   256  	return &taskClock{t: t, includeSys: false}
   257  }
   258  
   259  // CPUClock returns a clock measuring the CPU time the task has spent executing
   260  // application and "kernel" code.
   261  func (t *Task) CPUClock() ktime.Clock {
   262  	return &taskClock{t: t, includeSys: true}
   263  }
   264  
   265  // Now implements ktime.Clock.Now.
   266  func (tc *taskClock) Now() ktime.Time {
   267  	stats := tc.t.CPUStats()
   268  	if tc.includeSys {
   269  		return ktime.FromNanoseconds((stats.UserTime + stats.SysTime).Nanoseconds())
   270  	}
   271  	return ktime.FromNanoseconds(stats.UserTime.Nanoseconds())
   272  }
   273  
   274  // tgClock is a ktime.Clock that measures the time a thread group has spent
   275  // executing. tgClock is primarily used to implement CLOCK_PROCESS_CPUTIME_ID.
   276  //
   277  // +stateify savable
   278  type tgClock struct {
   279  	tg *ThreadGroup
   280  
   281  	// If includeSys is true, the tgClock includes both time spent executing
   282  	// application code as well as time spent in the sentry. Otherwise, the
   283  	// tgClock includes only time spent executing application code.
   284  	includeSys bool
   285  
   286  	// Implements waiter.Waitable.
   287  	ktime.ClockEventsQueue `state:"nosave"`
   288  }
   289  
   290  // Now implements ktime.Clock.Now.
   291  func (tgc *tgClock) Now() ktime.Time {
   292  	stats := tgc.tg.CPUStats()
   293  	if tgc.includeSys {
   294  		return ktime.FromNanoseconds((stats.UserTime + stats.SysTime).Nanoseconds())
   295  	}
   296  	return ktime.FromNanoseconds(stats.UserTime.Nanoseconds())
   297  }
   298  
   299  // WallTimeUntil implements ktime.Clock.WallTimeUntil.
   300  func (tgc *tgClock) WallTimeUntil(t, now ktime.Time) time.Duration {
   301  	// Thread group CPU time should not exceed wall time * live tasks, since
   302  	// task goroutines exit after the transition to TaskExitZombie in
   303  	// runExitNotify.
   304  	tgc.tg.pidns.owner.mu.RLock()
   305  	n := tgc.tg.liveTasks
   306  	tgc.tg.pidns.owner.mu.RUnlock()
   307  	if n == 0 {
   308  		if t.Before(now) {
   309  			return 0
   310  		}
   311  		// The timer tick raced with thread group exit, after which no more
   312  		// tasks can enter the thread group. So tgc.Now() will never advance
   313  		// again. Return a large delay; the timer should be stopped long before
   314  		// it comes again anyway.
   315  		return time.Hour
   316  	}
   317  	// This is a lower bound on the amount of time that can elapse before an
   318  	// associated timer expires, so returning this value tends to result in a
   319  	// sequence of closely-spaced ticks just before timer expiry. To avoid
   320  	// this, round up to the nearest ClockTick; CPU usage measurements are
   321  	// limited to this resolution anyway.
   322  	remaining := time.Duration(t.Sub(now).Nanoseconds()/int64(n)) * time.Nanosecond
   323  	return ((remaining + (linux.ClockTick - time.Nanosecond)) / linux.ClockTick) * linux.ClockTick
   324  }
   325  
   326  // UserCPUClock returns a ktime.Clock that measures the time that a thread
   327  // group has spent executing.
   328  func (tg *ThreadGroup) UserCPUClock() ktime.Clock {
   329  	return &tgClock{tg: tg, includeSys: false}
   330  }
   331  
   332  // CPUClock returns a ktime.Clock that measures the time that a thread group
   333  // has spent executing, including sentry time.
   334  func (tg *ThreadGroup) CPUClock() ktime.Clock {
   335  	return &tgClock{tg: tg, includeSys: true}
   336  }
   337  
   338  func (k *Kernel) runCPUClockTicker() {
   339  	rng := rand.New(rand.NewSource(rand.Int63()))
   340  	var tgs []*ThreadGroup
   341  
   342  	for {
   343  		// Stop the CPU clock while nothing is running.
   344  		if k.runningTasks.Load() == 0 {
   345  			k.runningTasksMu.Lock()
   346  			if k.runningTasks.Load() == 0 {
   347  				k.cpuClockTickerRunning = false
   348  				k.cpuClockTickerStopCond.Broadcast()
   349  				k.runningTasksCond.Wait()
   350  				// k.cpuClockTickerRunning was set to true by our waker
   351  				// (Kernel.incRunningTasks()). For reasons described there, we must
   352  				// process at least one CPU clock tick between calls to
   353  				// k.runningTasksCond.Wait().
   354  			}
   355  			k.runningTasksMu.Unlock()
   356  		}
   357  
   358  		// Wait for the next CPU clock tick.
   359  		select {
   360  		case <-k.cpuClockTickTimer.C:
   361  			k.cpuClockTickTimer.Reset(linux.ClockTick)
   362  		case <-k.cpuClockTickerWakeCh:
   363  			continue
   364  		}
   365  
   366  		// Advance the CPU clock, and timers based on the CPU clock, atomically
   367  		// under cpuClockMu.
   368  		k.cpuClockMu.Lock()
   369  		now := k.cpuClock.Add(1)
   370  
   371  		// Check thread group CPU timers.
   372  		tgs = k.tasks.Root.ThreadGroupsAppend(tgs)
   373  		for _, tg := range tgs {
   374  			if tg.cpuTimersEnabled.Load() == 0 {
   375  				continue
   376  			}
   377  
   378  			k.tasks.mu.RLock()
   379  			if tg.leader == nil {
   380  				// No tasks have ever run in this thread group.
   381  				k.tasks.mu.RUnlock()
   382  				continue
   383  			}
   384  			// Accumulate thread group CPU stats, and randomly select running tasks
   385  			// using reservoir sampling to receive CPU timer signals.
   386  			var virtReceiver *Task
   387  			nrVirtCandidates := 0
   388  			var profReceiver *Task
   389  			nrProfCandidates := 0
   390  			tgUserTime := tg.exitedCPUStats.UserTime
   391  			tgSysTime := tg.exitedCPUStats.SysTime
   392  			for t := tg.tasks.Front(); t != nil; t = t.Next() {
   393  				tsched := t.TaskGoroutineSchedInfo()
   394  				tgUserTime += time.Duration(tsched.userTicksAt(now) * uint64(linux.ClockTick))
   395  				tgSysTime += time.Duration(tsched.sysTicksAt(now) * uint64(linux.ClockTick))
   396  				switch tsched.State {
   397  				case TaskGoroutineRunningApp:
   398  					// Considered by ITIMER_VIRT, ITIMER_PROF, and RLIMIT_CPU
   399  					// timers.
   400  					nrVirtCandidates++
   401  					if int(randInt31n(rng, int32(nrVirtCandidates))) == 0 {
   402  						virtReceiver = t
   403  					}
   404  					fallthrough
   405  				case TaskGoroutineRunningSys:
   406  					// Considered by ITIMER_PROF and RLIMIT_CPU timers.
   407  					nrProfCandidates++
   408  					if int(randInt31n(rng, int32(nrProfCandidates))) == 0 {
   409  						profReceiver = t
   410  					}
   411  				}
   412  			}
   413  			tgVirtNow := ktime.FromNanoseconds(tgUserTime.Nanoseconds())
   414  			tgProfNow := ktime.FromNanoseconds((tgUserTime + tgSysTime).Nanoseconds())
   415  
   416  			// All of the following are standard (not real-time) signals, which are
   417  			// automatically deduplicated, so we ignore the number of expirations.
   418  			tg.signalHandlers.mu.Lock()
   419  			// It should only be possible for these timers to advance if we found
   420  			// at least one running task.
   421  			if virtReceiver != nil {
   422  				// ITIMER_VIRTUAL
   423  				newItimerVirtSetting, exp := tg.itimerVirtSetting.At(tgVirtNow)
   424  				tg.itimerVirtSetting = newItimerVirtSetting
   425  				if exp != 0 {
   426  					virtReceiver.sendSignalLocked(SignalInfoPriv(linux.SIGVTALRM), true)
   427  				}
   428  			}
   429  			if profReceiver != nil {
   430  				// ITIMER_PROF
   431  				newItimerProfSetting, exp := tg.itimerProfSetting.At(tgProfNow)
   432  				tg.itimerProfSetting = newItimerProfSetting
   433  				if exp != 0 {
   434  					profReceiver.sendSignalLocked(SignalInfoPriv(linux.SIGPROF), true)
   435  				}
   436  				// RLIMIT_CPU soft limit
   437  				newRlimitCPUSoftSetting, exp := tg.rlimitCPUSoftSetting.At(tgProfNow)
   438  				tg.rlimitCPUSoftSetting = newRlimitCPUSoftSetting
   439  				if exp != 0 {
   440  					profReceiver.sendSignalLocked(SignalInfoPriv(linux.SIGXCPU), true)
   441  				}
   442  				// RLIMIT_CPU hard limit
   443  				rlimitCPUMax := tg.limits.Get(limits.CPU).Max
   444  				if rlimitCPUMax != limits.Infinity && !tgProfNow.Before(ktime.FromSeconds(int64(rlimitCPUMax))) {
   445  					profReceiver.sendSignalLocked(SignalInfoPriv(linux.SIGKILL), true)
   446  				}
   447  			}
   448  			tg.signalHandlers.mu.Unlock()
   449  
   450  			k.tasks.mu.RUnlock()
   451  		}
   452  
   453  		k.cpuClockMu.Unlock()
   454  
   455  		// Retain tgs between calls to Notify to reduce allocations.
   456  		for i := range tgs {
   457  			tgs[i] = nil
   458  		}
   459  		tgs = tgs[:0]
   460  	}
   461  }
   462  
   463  // randInt31n returns a random integer in [0, n).
   464  //
   465  // randInt31n is equivalent to math/rand.Rand.int31n(), which is unexported.
   466  // See that function for details.
   467  func randInt31n(rng *rand.Rand, n int32) int32 {
   468  	v := rng.Uint32()
   469  	prod := uint64(v) * uint64(n)
   470  	low := uint32(prod)
   471  	if low < uint32(n) {
   472  		thresh := uint32(-n) % uint32(n)
   473  		for low < thresh {
   474  			v = rng.Uint32()
   475  			prod = uint64(v) * uint64(n)
   476  			low = uint32(prod)
   477  		}
   478  	}
   479  	return int32(prod >> 32)
   480  }
   481  
   482  // NotifyRlimitCPUUpdated is called by setrlimit.
   483  //
   484  // Preconditions: The caller must be running on the task goroutine.
   485  func (t *Task) NotifyRlimitCPUUpdated() {
   486  	t.k.cpuClockMu.Lock()
   487  	defer t.k.cpuClockMu.Unlock()
   488  	t.tg.pidns.owner.mu.RLock()
   489  	defer t.tg.pidns.owner.mu.RUnlock()
   490  	t.tg.signalHandlers.mu.Lock()
   491  	defer t.tg.signalHandlers.mu.Unlock()
   492  	rlimitCPU := t.tg.limits.Get(limits.CPU)
   493  	t.tg.rlimitCPUSoftSetting = ktime.Setting{
   494  		Enabled: rlimitCPU.Cur != limits.Infinity,
   495  		Next:    ktime.FromNanoseconds((time.Duration(rlimitCPU.Cur) * time.Second).Nanoseconds()),
   496  		Period:  time.Second,
   497  	}
   498  	if rlimitCPU.Max != limits.Infinity {
   499  		// Check if tg is already over the hard limit.
   500  		tgcpu := t.tg.cpuStatsAtLocked(t.k.CPUClockNow())
   501  		tgProfNow := ktime.FromNanoseconds((tgcpu.UserTime + tgcpu.SysTime).Nanoseconds())
   502  		if !tgProfNow.Before(ktime.FromSeconds(int64(rlimitCPU.Max))) {
   503  			t.sendSignalLocked(SignalInfoPriv(linux.SIGKILL), true)
   504  		}
   505  	}
   506  	t.tg.updateCPUTimersEnabledLocked()
   507  }
   508  
   509  // Preconditions: The signal mutex must be locked.
   510  func (tg *ThreadGroup) updateCPUTimersEnabledLocked() {
   511  	rlimitCPU := tg.limits.Get(limits.CPU)
   512  	if tg.itimerVirtSetting.Enabled || tg.itimerProfSetting.Enabled || tg.rlimitCPUSoftSetting.Enabled || rlimitCPU.Max != limits.Infinity {
   513  		tg.cpuTimersEnabled.Store(1)
   514  	} else {
   515  		tg.cpuTimersEnabled.Store(0)
   516  	}
   517  }
   518  
   519  // StateStatus returns a string representation of the task's current state,
   520  // appropriate for /proc/[pid]/status.
   521  func (t *Task) StateStatus() string {
   522  	switch s := t.TaskGoroutineSchedInfo().State; s {
   523  	case TaskGoroutineNonexistent, TaskGoroutineRunningSys:
   524  		t.tg.pidns.owner.mu.RLock()
   525  		defer t.tg.pidns.owner.mu.RUnlock()
   526  		switch t.exitState {
   527  		case TaskExitZombie:
   528  			return "Z (zombie)"
   529  		case TaskExitDead:
   530  			return "X (dead)"
   531  		default:
   532  			// The task goroutine can't exit before passing through
   533  			// runExitNotify, so if s == TaskGoroutineNonexistent, the task has
   534  			// been created but the task goroutine hasn't yet started. The
   535  			// Linux equivalent is struct task_struct::state == TASK_NEW
   536  			// (kernel/fork.c:copy_process() =>
   537  			// kernel/sched/core.c:sched_fork()), but the TASK_NEW bit is
   538  			// masked out by TASK_REPORT for /proc/[pid]/status, leaving only
   539  			// TASK_RUNNING.
   540  			return "R (running)"
   541  		}
   542  	case TaskGoroutineRunningApp:
   543  		return "R (running)"
   544  	case TaskGoroutineBlockedInterruptible:
   545  		return "S (sleeping)"
   546  	case TaskGoroutineStopped:
   547  		t.tg.signalHandlers.mu.Lock()
   548  		defer t.tg.signalHandlers.mu.Unlock()
   549  		switch t.stop.(type) {
   550  		case *groupStop:
   551  			return "T (stopped)"
   552  		case *ptraceStop:
   553  			return "t (tracing stop)"
   554  		}
   555  		fallthrough
   556  	case TaskGoroutineBlockedUninterruptible:
   557  		// This is the name Linux uses for TASK_UNINTERRUPTIBLE and
   558  		// TASK_KILLABLE (= TASK_UNINTERRUPTIBLE | TASK_WAKEKILL):
   559  		// fs/proc/array.c:task_state_array.
   560  		return "D (disk sleep)"
   561  	default:
   562  		panic(fmt.Sprintf("Invalid TaskGoroutineState: %v", s))
   563  	}
   564  }
   565  
   566  // CPUMask returns a copy of t's allowed CPU mask.
   567  func (t *Task) CPUMask() sched.CPUSet {
   568  	t.mu.Lock()
   569  	defer t.mu.Unlock()
   570  	return t.allowedCPUMask.Copy()
   571  }
   572  
   573  // SetCPUMask sets t's allowed CPU mask based on mask. It takes ownership of
   574  // mask.
   575  //
   576  // Preconditions: mask.Size() ==
   577  // sched.CPUSetSize(t.Kernel().ApplicationCores()).
   578  func (t *Task) SetCPUMask(mask sched.CPUSet) error {
   579  	if want := sched.CPUSetSize(t.k.applicationCores); mask.Size() != want {
   580  		panic(fmt.Sprintf("Invalid CPUSet %v (expected %d bytes)", mask, want))
   581  	}
   582  
   583  	// Remove CPUs in mask above Kernel.applicationCores.
   584  	mask.ClearAbove(t.k.applicationCores)
   585  
   586  	// Ensure that at least 1 CPU is still allowed.
   587  	if mask.NumCPUs() == 0 {
   588  		return linuxerr.EINVAL
   589  	}
   590  
   591  	if t.k.useHostCores {
   592  		// No-op; pretend the mask was immediately changed back.
   593  		return nil
   594  	}
   595  
   596  	t.tg.pidns.owner.mu.RLock()
   597  	rootTID := t.tg.pidns.owner.Root.tids[t]
   598  	t.tg.pidns.owner.mu.RUnlock()
   599  
   600  	t.mu.Lock()
   601  	defer t.mu.Unlock()
   602  	t.allowedCPUMask = mask
   603  	t.cpu.Store(assignCPU(mask, rootTID))
   604  	return nil
   605  }
   606  
   607  // CPU returns the cpu id for a given task.
   608  func (t *Task) CPU() int32 {
   609  	if t.k.useHostCores {
   610  		return int32(hostcpu.GetCPU())
   611  	}
   612  
   613  	return t.cpu.Load()
   614  }
   615  
   616  // assignCPU returns the virtualized CPU number for the task with global TID
   617  // tid and allowedCPUMask allowed.
   618  func assignCPU(allowed sched.CPUSet, tid ThreadID) (cpu int32) {
   619  	// To pretend that threads are evenly distributed to allowed CPUs, choose n
   620  	// to be less than the number of CPUs in allowed ...
   621  	n := int(tid) % int(allowed.NumCPUs())
   622  	// ... then pick the nth CPU in allowed.
   623  	allowed.ForEachCPU(func(c uint) {
   624  		if n == 0 {
   625  			cpu = int32(c)
   626  		}
   627  		n--
   628  	})
   629  	return cpu
   630  }
   631  
   632  // Niceness returns t's niceness.
   633  func (t *Task) Niceness() int {
   634  	t.mu.Lock()
   635  	defer t.mu.Unlock()
   636  	return t.niceness
   637  }
   638  
   639  // Priority returns t's priority.
   640  func (t *Task) Priority() int {
   641  	t.mu.Lock()
   642  	defer t.mu.Unlock()
   643  	return t.niceness + 20
   644  }
   645  
   646  // SetNiceness sets t's niceness to n.
   647  func (t *Task) SetNiceness(n int) {
   648  	t.mu.Lock()
   649  	defer t.mu.Unlock()
   650  	t.niceness = n
   651  }
   652  
   653  // NumaPolicy returns t's current numa policy.
   654  func (t *Task) NumaPolicy() (policy linux.NumaPolicy, nodeMask uint64) {
   655  	t.mu.Lock()
   656  	defer t.mu.Unlock()
   657  	return t.numaPolicy, t.numaNodeMask
   658  }
   659  
   660  // SetNumaPolicy sets t's numa policy.
   661  func (t *Task) SetNumaPolicy(policy linux.NumaPolicy, nodeMask uint64) {
   662  	t.mu.Lock()
   663  	defer t.mu.Unlock()
   664  	t.numaPolicy = policy
   665  	t.numaNodeMask = nodeMask
   666  }