diff --git a/pkg/sentry/kernel/fd_table.go b/pkg/sentry/kernel/fd_table.go index 0542c8537..3eb0ddf69 100644 --- a/pkg/sentry/kernel/fd_table.go +++ b/pkg/sentry/kernel/fd_table.go @@ -93,7 +93,7 @@ func (f *FDTable) saveDescriptorTable() map[int32]descriptor { m := make(map[int32]descriptor) f.mu.Lock() defer f.mu.Unlock() - f.forEach(context.Background(), func(fd int32, file *vfs.FileDescription, flags FDFlags) bool { + f.ForEach(context.Background(), func(fd int32, file *vfs.FileDescription, flags FDFlags) bool { m[fd] = descriptor{ file: file, flags: flags, @@ -172,10 +172,10 @@ func (f *FDTable) forEachUpTo(ctx context.Context, maxFd int32, fn func(fd int32 }) } -// forEach iterates over all non-nil files upto maxFd in sorted order. +// ForEach iterates over all non-nil files upto maxFd in sorted order. // // It is the caller's responsibility to acquire an appropriate lock. -func (f *FDTable) forEach(ctx context.Context, fn func(fd int32, file *vfs.FileDescription, flags FDFlags) bool) { +func (f *FDTable) ForEach(ctx context.Context, fn func(fd int32, file *vfs.FileDescription, flags FDFlags) bool) { f.forEachUpTo(ctx, MaxFdLimit, fn) } @@ -187,7 +187,7 @@ func (f *FDTable) String() string { f.mu.Lock() // Can't release f.mu from defer, because vfsObj.PathnameWithDeleted // should not be called under the fdtable mutex. - f.forEach(ctx, func(fd int32, file *vfs.FileDescription, flags FDFlags) bool { + f.ForEach(ctx, func(fd int32, file *vfs.FileDescription, flags FDFlags) bool { if file != nil { file.IncRef() files[fd] = file @@ -424,7 +424,7 @@ func (f *FDTable) GetFDs(ctx context.Context) []int32 { f.mu.Lock() defer f.mu.Unlock() fds := make([]int32, 0, int(f.fdBitmap.GetNumOnes())) - f.forEach(ctx, func(fd int32, _ *vfs.FileDescription, _ FDFlags) bool { + f.ForEach(ctx, func(fd int32, _ *vfs.FileDescription, _ FDFlags) bool { fds = append(fds, fd) return true }) @@ -486,7 +486,7 @@ func (f *FDTable) RemoveIf(ctx context.Context, cond func(*vfs.FileDescription, var files []*vfs.FileDescription f.mu.Lock() - f.forEach(ctx, func(fd int32, file *vfs.FileDescription, flags FDFlags) bool { + f.ForEach(ctx, func(fd int32, file *vfs.FileDescription, flags FDFlags) bool { if cond(file, flags) { // Clear from table. if df := f.set(fd, nil, FDFlags{}); df != nil { diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 18c554ddd..368fec637 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -1215,7 +1215,7 @@ func (k *Kernel) pauseTimeLocked(ctx context.Context) { // This means we'll iterate FDTables shared by multiple tasks repeatedly, // but ktime.Timer.Pause is idempotent so this is harmless. if t.fdTable != nil { - t.fdTable.forEach(ctx, func(_ int32, fd *vfs.FileDescription, _ FDFlags) bool { + t.fdTable.ForEach(ctx, func(_ int32, fd *vfs.FileDescription, _ FDFlags) bool { if tfd, ok := fd.Impl().(*timerfd.TimerFileDescription); ok { tfd.PauseTimer() } @@ -1246,7 +1246,7 @@ func (k *Kernel) resumeTimeLocked(ctx context.Context) { } } if t.fdTable != nil { - t.fdTable.forEach(ctx, func(_ int32, fd *vfs.FileDescription, _ FDFlags) bool { + t.fdTable.ForEach(ctx, func(_ int32, fd *vfs.FileDescription, _ FDFlags) bool { if tfd, ok := fd.Impl().(*timerfd.TimerFileDescription); ok { tfd.ResumeTimer() } @@ -1354,6 +1354,11 @@ func (k *Kernel) Pause() { k.tasks.aioGoroutines.Wait() } +// IsPaused returns true if the kernel is currently paused. +func (k *Kernel) IsPaused() bool { + return k.tasks.isExternallyStopped() +} + // ReceiveTaskStates receives full states for all tasks. func (k *Kernel) ReceiveTaskStates() { k.extMu.Lock() diff --git a/pkg/sentry/kernel/task_stop.go b/pkg/sentry/kernel/task_stop.go index 44b4ff102..083b68cf2 100644 --- a/pkg/sentry/kernel/task_stop.go +++ b/pkg/sentry/kernel/task_stop.go @@ -241,3 +241,11 @@ func (ts *TaskSet) EndExternalStop() { t.tg.signalHandlers.mu.Unlock() } } + +// isExternallyStopped returns true if BeginExternalStop() has been called on +// this TaskSet, without a corresponding call to EndExternalStop(). +func (ts *TaskSet) isExternallyStopped() bool { + ts.mu.Lock() + defer ts.mu.Unlock() + return ts.stopCount > 0 +} diff --git a/pkg/sentry/kernel/threads.go b/pkg/sentry/kernel/threads.go index a0b2cbc38..f25ca7076 100644 --- a/pkg/sentry/kernel/threads.go +++ b/pkg/sentry/kernel/threads.go @@ -106,6 +106,13 @@ func newTaskSet(pidns *PIDNamespace) *TaskSet { return ts } +// ForEachThreadGroup applies f to each thread group in ts. +func (ts *TaskSet) ForEachThreadGroup(f func(tg *ThreadGroup)) { + ts.mu.RLock() + defer ts.mu.RUnlock() + ts.forEachThreadGroupLocked(f) +} + // forEachThreadGroupLocked applies f to each thread group in ts. // // Preconditions: ts.mu must be locked (for reading or writing).