func (tg *ThreadGroup) ReleaseControllingTTY(tty *TTY) error {
	tty.mu.Lock()
	defer tty.mu.Unlock()

	// We might be asked to set the controlling terminal of multiple
	// processes, so we lock both the TaskSet and SignalHandlers.
	tg.pidns.owner.mu.RLock()
	defer tg.pidns.owner.mu.RUnlock()

	// Just below, we may re-lock signalHandlers in order to send signals.
	// Thus we can't defer Unlock here.
	tg.signalHandlers.mu.Lock()

	if tg.tty == nil || tg.tty != tty {
		tg.signalHandlers.mu.Unlock()
		return syserror.ENOTTY
	}

	// "If the process was session leader, then send SIGHUP and SIGCONT to
	// the foreground process group and all processes in the current
	// session lose their controlling terminal." - tty_ioctl(4)
	// Remove tty as the controlling tty for each process in the session,
	// then send them SIGHUP and SIGCONT.

	// If we're not the session leader, we don't have to do much.
	if tty.tg != tg {
		tg.tty = nil
		tg.signalHandlers.mu.Unlock()
		return nil
	}

	tg.signalHandlers.mu.Unlock()

	// We're the session leader. SIGHUP and SIGCONT the foreground process
	// group and remove all controlling terminals in the session.
	var lastErr error
	for othertg := range tg.pidns.owner.Root.tgids {
		if othertg.processGroup.session == tg.processGroup.session {
			othertg.signalHandlers.mu.Lock()
			othertg.tty = nil
			if othertg.processGroup == tg.processGroup.session.foreground {
				if err := othertg.leader.sendSignalLocked(&arch.SignalInfo{Signo: int32(linux.SIGHUP)}, true /* group */); err != nil {
					lastErr = err
				}
				if err := othertg.leader.sendSignalLocked(&arch.SignalInfo{Signo: int32(linux.SIGCONT)}, true /* group */); err != nil {
					lastErr = err
				}
			}
			othertg.signalHandlers.mu.Unlock()
		}
	}

	return lastErr
}
// ReleaseControllingTTY gives up tty as the controlling tty of tg.
ReleaseControllingTTY gives up tty as the controlling tty of tg.
// ReleaseControllingTTY gives up tty as the controlling tty of tg .
func (tg *ThreadGroup) ReleaseControllingTTY(tty *TTY) error {
	tty.mu.Lock()
	defer tty.mu.Unlock()
	tg.pidns.owner.mu.RLock()
	defer tg.pidns.owner.mu.RUnlock()
	tg.signalHandlers.mu.Lock()
	if tg.tty == nil || tg.tty != tty {
		tg.signalHandlers.mu.Unlock()
		return syserror.ENOTTY
	}
	if tty.tg != tg {
		tg.tty = nil
		tg.signalHandlers.mu.Unlock()
		return nil
	}
	tg.signalHandlers.mu.Unlock()
	var lastErr error
	for othertg := range tg.pidns.owner.Root.tgids {
		if othertg.processGroup.session == tg.processGroup.session {
			othertg.signalHandlers.mu.Lock()
			othertg.tty = nil
			if othertg.processGroup == tg.processGroup.session.foreground {
				if err := othertg.leader.sendSignalLocked(&arch.SignalInfo{Signo: int32(linux.SIGHUP)}, true ); err != nil {
					lastErr = err
				}
				if err := othertg.leader.sendSignalLocked(&arch.SignalInfo{Signo: int32(linux.SIGCONT)}, true ); err != nil {
					lastErr = err
				}
			}
			othertg.signalHandlers.mu.Unlock()
		}
	}
	return lastErr
}
func ( tg * ThreadGroup ) ReleaseControllingTTY ( tty * TTY ) error { tty . mu . Lock ( ) defer tty . mu . Unlock ( ) tg . pidns . owner . mu . RLock ( ) defer tg . pidns . owner . mu . RUnlock ( ) tg . signalHandlers . mu . Lock ( ) if tg . tty == nil || tg . tty != tty { tg . signalHandlers . mu . Unlock ( ) return syserror . ENOTTY } if tty . tg != tg { tg . tty = nil tg . signalHandlers . mu . Unlock ( ) return nil } tg . signalHandlers . mu . Unlock ( ) var lastErr error for othertg := range tg . pidns . owner . Root . tgids { if othertg . processGroup . session == tg . processGroup . session { othertg . signalHandlers . mu . Lock ( ) othertg . tty = nil if othertg . processGroup == tg . processGroup . session . foreground { if err := othertg . leader . sendSignalLocked ( & arch . SignalInfo { Signo : int32 ( linux . SIGHUP ) } , true ) ; err != nil { lastErr = err } if err := othertg . leader . sendSignalLocked ( & arch . SignalInfo { Signo : int32 ( linux . SIGCONT ) } , true ) ; err != nil { lastErr = err } } othertg . signalHandlers . mu . Unlock ( ) } } return lastErr }
ReleaseControllingTTY gives up tty as the controlling tty of tg.
ReleaseControllingTTY gives up tty as the controlling tty of tg .
// We might be asked to set the controlling terminal of multiple // processes, so we lock both the TaskSet and SignalHandlers. // Just below, we may re-lock signalHandlers in order to send signals. // Thus we can't defer Unlock here. // "If the process was session leader, then send SIGHUP and SIGCONT to // the foreground process group and all processes in the current // session lose their controlling terminal." - tty_ioctl(4) // Remove tty as the controlling tty for each process in the session, // then send them SIGHUP and SIGCONT. // If we're not the session leader, we don't have to do much. // We're the session leader. SIGHUP and SIGCONT the foreground process // group and remove all controlling terminals in the session. /* group */ /* group */