// newTask is a helper for TaskSet.NewTask that only takes ownership of parts
// of cfg if it succeeds.
newTask is a helper for TaskSet.NewTask that only takes ownership of parts
of cfg if it succeeds.
// newTask is a helper for TaskSet . NewTask that only takes ownership of parts // of cfg if it succeeds .
func (ts *TaskSet) newTask(cfg *TaskConfig) (*Task, error) {
	tg := cfg.ThreadGroup
	image := cfg.TaskImage
	t := &Task{
		taskNode: taskNode{
			tg:       tg,
			parent:   cfg.Parent,
			children: make(map[*Task]struct{}),
		},
		runState:           (*runApp)(nil),
		interruptChan:      make(chan struct{}, 1),
		signalMask:         cfg.SignalMask,
		signalStack:        linux.SignalStack{Flags: linux.SS_DISABLE},
		image:              *image,
		fsContext:          cfg.FSContext,
		fdTable:            cfg.FDTable,
		p:                  cfg.Kernel.Platform.NewContext(),
		k:                  cfg.Kernel,
		ptraceTracees:      make(map[*Task]struct{}),
		allowedCPUMask:     cfg.AllowedCPUMask.Copy(),
		ioUsage:            &usage.IO{},
		niceness:           cfg.Niceness,
		netns:              cfg.NetworkNamespace,
		utsns:              cfg.UTSNamespace,
		ipcns:              cfg.IPCNamespace,
		abstractSockets:    cfg.AbstractSocketNamespace,
		mountNamespaceVFS2: cfg.MountNamespaceVFS2,
		rseqCPU:            -1,
		rseqAddr:           cfg.RSeqAddr,
		rseqSignature:      cfg.RSeqSignature,
		futexWaiter:        futex.NewWaiter(),
		containerID:        cfg.ContainerID,
		cgroups:            make(map[Cgroup]struct{}),
	}
	t.creds.Store(cfg.Credentials)
	t.endStopCond.L = &t.tg.signalHandlers.mu
	t.ptraceTracer.Store((*Task)(nil))
	ts.mu.Lock()
	defer ts.mu.Unlock()
	tg.signalHandlers.mu.Lock()
	defer tg.signalHandlers.mu.Unlock()
	if tg.exiting || tg.execing != nil {
		return nil, syserror.EINTR
	}
	if err := ts.assignTIDsLocked(t); err != nil {
		return nil, err
	}
	t.updateInfoLocked()
	if cfg.InheritParent != nil {
		t.parent = cfg.InheritParent.parent
	}
	if t.parent != nil {
		t.parent.children[t] = struct{}{}
	}
	if VFS2Enabled {
		t.EnterInitialCgroups(t.parent)
	}
	if tg.leader == nil {
		tg.leader = t
		if parentPG := tg.parentPG(); parentPG == nil {
			tg.createSession()
		} else {
			parentPG.incRefWithParent(parentPG)
			tg.processGroup = parentPG
			tg.tty = t.parent.tg.tty
		}
	}
	tg.tasks.PushBack(t)
	tg.tasksCount++
	tg.liveTasks++
	tg.activeTasks++
	t.stopCount = ts.stopCount
	t.mu.Lock()
	defer t.mu.Unlock()
	t.cpu = assignCPU(t.allowedCPUMask, ts.Root.tids[t])
	t.startTime = t.k.RealtimeClock().Now()
	return t, nil
}
func ( ts * TaskSet ) newTask ( cfg * TaskConfig ) ( * Task , error ) { tg := cfg . ThreadGroup image := cfg . TaskImage t := & Task { taskNode : taskNode { tg : tg , parent : cfg . Parent , children : make ( map [ * Task ] struct { } ) , } , runState : ( * runApp ) ( nil ) , interruptChan : make ( chan struct { } , 1 ) , signalMask : cfg . SignalMask , signalStack : linux . SignalStack { Flags : linux . SS_DISABLE } , image : * image , fsContext : cfg . FSContext , fdTable : cfg . FDTable , p : cfg . Kernel . Platform . NewContext ( ) , k : cfg . Kernel , ptraceTracees : make ( map [ * Task ] struct { } ) , allowedCPUMask : cfg . AllowedCPUMask . Copy ( ) , ioUsage : & usage . IO { } , niceness : cfg . Niceness , netns : cfg . NetworkNamespace , utsns : cfg . UTSNamespace , ipcns : cfg . IPCNamespace , abstractSockets : cfg . AbstractSocketNamespace , mountNamespaceVFS2 : cfg . MountNamespaceVFS2 , rseqCPU : - 1 , rseqAddr : cfg . RSeqAddr , rseqSignature : cfg . RSeqSignature , futexWaiter : futex . NewWaiter ( ) , containerID : cfg . ContainerID , cgroups : make ( map [ Cgroup ] struct { } ) , } t . creds . Store ( cfg . Credentials ) t . endStopCond . L = & t . tg . signalHandlers . mu t . ptraceTracer . Store ( ( * Task ) ( nil ) ) ts . mu . Lock ( ) defer ts . mu . Unlock ( ) tg . signalHandlers . mu . Lock ( ) defer tg . signalHandlers . mu . Unlock ( ) if tg . exiting || tg . execing != nil { return nil , syserror . EINTR } if err := ts . assignTIDsLocked ( t ) ; err != nil { return nil , err } t . updateInfoLocked ( ) if cfg . InheritParent != nil { t . parent = cfg . InheritParent . parent } if t . parent != nil { t . parent . children [ t ] = struct { } { } } if VFS2Enabled { t . EnterInitialCgroups ( t . parent ) } if tg . leader == nil { tg . leader = t if parentPG := tg . parentPG ( ) ; parentPG == nil { tg . createSession ( ) } else { parentPG . incRefWithParent ( parentPG ) tg . processGroup = parentPG tg . tty = t . parent . tg . tty } } tg . tasks . PushBack ( t ) tg . tasksCount ++ tg . liveTasks ++ tg . activeTasks ++ t . stopCount = ts . stopCount t . mu . Lock ( ) defer t . mu . Unlock ( ) t . cpu = assignCPU ( t . allowedCPUMask , ts . Root . tids [ t ] ) t . startTime = t . k . RealtimeClock ( ) . Now ( ) return t , nil }
newTask is a helper for TaskSet.NewTask that only takes ownership of parts
of cfg if it succeeds.
newTask is a helper for TaskSet . NewTask that only takes ownership of parts of cfg if it succeeds .
// We don't construct t.blockingTimer until Task.run(); see that function // for justification. // Make the new task (and possibly thread group) visible to the rest of // the system atomically. // If the caller is in the same thread group, then what we return // doesn't matter too much since the caller will exit before it returns // to userspace. If the caller isn't in the same thread group, then // we're in uncharted territory and can return whatever we want. // Below this point, newTask is expected not to fail (there is no rollback // of assignTIDsLocked or any of the following). // Logging on t's behalf will panic if t.logPrefix hasn't been // initialized. This is the earliest point at which we can do so // (since t now has thread IDs). // New thread group. // Inherit the process group and terminal. // Propagate external TaskSet stops to the new task.