// createSession creates a new session for a threadgroup.
//
// Precondition: callers must hold TaskSet.mu and the signal mutex for writing.
createSession creates a new session for a threadgroup.

callers must hold TaskSet.mu and the signal mutex for writing.
// createSession creates a new session for a threadgroup . // // Precondition : callers must hold TaskSet . mu and the signal mutex for writing .
func (tg *ThreadGroup) createSession() error {
	id := tg.pidns.tgids[tg]
	for s := tg.pidns.owner.sessions.Front(); s != nil; s = s.Next() {
		if s.leader.pidns != tg.pidns {
			continue
		}
		if s.leader == tg {
			return syserror.EPERM
		}
		if s.id == SessionID(id) {
			return syserror.EPERM
		}
		for pg := s.processGroups.Front(); pg != nil; pg = pg.Next() {
			if pg.id == ProcessGroupID(id) {
				return syserror.EPERM
			}
		}
	}
	s := &Session{
		id:     SessionID(id),
		leader: tg,
	}
	s.InitRefs()
	 Note that since this is a new session and a new process group, there
	 will be zero ancestors for this process group. (It is an orphan at
	 this point.)
	pg := &ProcessGroup{
		id:         ProcessGroupID(id),
		originator: tg,
		session:    s,
		ancestors:  0,
	}
	pg.refs.InitRefs()
	 Tie them and return the result.
	s.processGroups.PushBack(pg)
	tg.pidns.owner.sessions.PushBack(s)
	 Leave the current group, and assign the new one.
	if tg.processGroup != nil {
		oldParentPG := tg.parentPG()
		tg.forEachChildThreadGroupLocked(func(childTG *ThreadGroup) {
			childTG.processGroup.incRefWithParent(pg)
			childTG.processGroup.decRefWithParent(oldParentPG)
		})
		 If tg.processGroup is an orphan, decRefWithParent will lock
		 the signal mutex of each thread group in tg.processGroup.
		 However, tg's signal mutex may already be locked at this
		 point. We change tg's process group before calling
		 decRefWithParent to avoid locking tg's signal mutex twice.
		oldPG := tg.processGroup
		tg.processGroup = pg
		oldPG.decRefWithParent(oldParentPG)
	} else {
		 The current process group may be nil only in the case of an
		 unparented thread group (i.e. the init process). This would
		 not normally occur, but we allow it for the convenience of
		 CreateSession working from that point. There will be no
		 child processes. We always say that the very first group
		 created has ancestors (avoids checks elsewhere).
		 Note that this mirrors the parent == nil logic in
		 incRef/decRef/reparent, which counts nil as an ancestor.
		tg.processGroup = pg
		tg.processGroup.ancestors++
	}
	 Ensure a translation is added to all namespaces.
	for ns := tg.pidns; ns != nil; ns = ns.parent {
		local := ns.tgids[tg]
		ns.sids[s] = SessionID(local)
		ns.sessions[SessionID(local)] = s
		ns.pgids[pg] = ProcessGroupID(local)
		ns.processGroups[ProcessGroupID(local)] = pg
	}
	 Disconnect from the controlling terminal.
	tg.tty = nil
	return nil
}
func ( tg * ThreadGroup ) createSession ( ) error { id := tg . pidns . tgids [ tg ] for s := tg . pidns . owner . sessions . Front ( ) ; s != nil ; s = s . Next ( ) { if s . leader . pidns != tg . pidns { continue } if s . leader == tg { return syserror . EPERM } if s . id == SessionID ( id ) { return syserror . EPERM } for pg := s . processGroups . Front ( ) ; pg != nil ; pg = pg . Next ( ) { if pg . id == ProcessGroupID ( id ) { return syserror . EPERM } } } s := & Session { id : SessionID ( id ) , leader : tg , } s . InitRefs ( ) pg := & ProcessGroup { id : ProcessGroupID ( id ) , originator : tg , session : s , ancestors : 0 , } pg . refs . InitRefs ( ) s . processGroups . PushBack ( pg ) tg . pidns . owner . sessions . PushBack ( s ) if tg . processGroup != nil { oldParentPG := tg . parentPG ( ) tg . forEachChildThreadGroupLocked ( func ( childTG * ThreadGroup ) { childTG . processGroup . incRefWithParent ( pg ) childTG . processGroup . decRefWithParent ( oldParentPG ) } ) oldPG := tg . processGroup tg . processGroup = pg oldPG . decRefWithParent ( oldParentPG ) } else { tg . processGroup = pg tg . processGroup . ancestors ++ } for ns := tg . pidns ; ns != nil ; ns = ns . parent { local := ns . tgids [ tg ] ns . sids [ s ] = SessionID ( local ) ns . sessions [ SessionID ( local ) ] = s ns . pgids [ pg ] = ProcessGroupID ( local ) ns . processGroups [ ProcessGroupID ( local ) ] = pg } tg . tty = nil return nil }
createSession creates a new session for a threadgroup.
createSession creates a new session for a threadgroup .
// Get the ID for this thread in the current namespace. // Check if this ThreadGroup already leads a Session, or // if the proposed group is already taken. // Create a new Session, with a single reference. // Create a new ProcessGroup, belonging to that Session. // This also has a single reference (assigned below). // // Note that since this is a new session and a new process group, there // will be zero ancestors for this process group. (It is an orphan at // this point.) // Tie them and return the result. // Leave the current group, and assign the new one. // If tg.processGroup is an orphan, decRefWithParent will lock // the signal mutex of each thread group in tg.processGroup. // However, tg's signal mutex may already be locked at this // point. We change tg's process group before calling // decRefWithParent to avoid locking tg's signal mutex twice. // The current process group may be nil only in the case of an // unparented thread group (i.e. the init process). This would // not normally occur, but we allow it for the convenience of // CreateSession working from that point. There will be no // child processes. We always say that the very first group // created has ancestors (avoids checks elsewhere). // // Note that this mirrors the parent == nil logic in // incRef/decRef/reparent, which counts nil as an ancestor. // Ensure a translation is added to all namespaces. // Disconnect from the controlling terminal.