/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ifndef _SYS_SESSION_H_
#define _SYS_SESSION_H_	1

#ident	"$Header: session.h 1.15 90/01/17 $"

/* session structures
 */

/* $Log:	session.h,v $
 */

/*
 * A session_info structure is allocated per session.
 * and holds information about the controlling tty (ctty) and
 * a linkage structure that contains pointers to every member of the session.
 * Each member of the session has p->p_session pointing to one of these
 * it also has p->p_sid set to p->p_session->s_sid;
 *
 * Each group within a session has one its member linked to the
 * s_pgrp chain. This is a double linked null forward terminated list.
 * (each member still has p->p_session pointing back).
 *
 * Each member of the process group has a double linked circular list
 * of members. If the group only has one member then p_pgrpf and p_pgrpb
 * both pointer to the same proc slot.
 *
 *       s:     --------------
 *              | s_sid  S   |
 *              | s_pgrp     |
 *              ______________
 *                |
 *                V
 *       a: ----------    b: -----------   c: ----------- 
 *          | p_sessf |----->| p_sessf |----->| p_sessf |--->NULL
 *   c: <---| p_sessb |<-----| p_sessb |<-----| p_sessb |
 *  a2: <---| p_pgrpb |      |         |      |         |
 *          | p_pgrpf |      |         |      |         |
 *          ----------       -----------      ----------- 
 *            /\   V
 *    a1:   ----------       
 *          | p_pgrpb |
 *          | p_pgrpf |          All these procs (a,b,c,a1 and a2) are members
 *          ----------           of the session "S". Each had p_sid set to "S".
 *           /\    V             Each has p_session pointing to "s".
 *     a2:  ----------             a,a1 and a2 are a porcess group "a", each is
 *          | p_pgrpb |          linked via a doubled linked list p_pgrpf and
 *          | p_pgrpf |          p_pgrpb. On memeber of each group forms the
 *          ----------           circular linked p_sessb chain and the NULL
 *                V	         terminated p_sessf chain.
 *                a:
 */
struct	session {
	pid_t		s_sid;		/* the Session ID number */
	struct	vnode	*s_vp;		/* the vnode of the controlling tty */
	sema_t		s_sema;		/* ctty semaphore */
	ulong		s_ctty_count;	/* number of concurrent ctty ops */
	struct	ctty	*s_ctty;	/* pointer to ctty information */
	lock_t		s_lock;		/* lock for all values */
	struct proc	*s_pgrp;	/* pointer to process group */
};

typedef struct session	sess_t;

/*
 * A copy of "sid" is also kept in the process structure.
 * vp is null or set to the vnode of the controlling terminal; the
 * controlling terminal is only valid if vp is set.
 * The pointer s_sidp and s_fgidp are initialised
 * to zero by setsid(). The pointer s_fgid is set when the controling
 * terminal is established and can be changed via the TIOCSPGRP ioctl.
 * s_sidp is set to point to a sid vaule stored in a per device structure.
 * Once set it is and error to change the pointer.
 * The lock s_lock is held whenever the s_pgrp pointers are being traversed.
 * Since once a particular process is found its state and flags may be 
 * manipulated the following order must be followed.
 *   p_lock(&p->p_session->s_lock,SPLSESS)
 *   p_lock(&proc_list,
 *   p_lock(&q->p_state,
 *   v_lock(&q->p_state,
 *   v_lock(&proc_list,
 *   v_lock(&p->p_session->s_lock,
 */

extern	struct	session	*sess;
extern	lock_t	sess_list;

#define SPLSESS	(SPL5)	/* set to highest level asynchronus access (SPLSTR)*/

/*
 * Add a new process (p) to an the end of the old process group.
 */
#define PGRP_INS( p, old ) \
{\
	(p)->p_pgrpf = (old); \
	(p)->p_pgrpb = (old)->p_pgrpb;\
	(old)->p_pgrpb->p_pgrpf = (p); \
	(old)->p_pgrpb = (p); \
}
/*
 * delete an entry from a process group and place it in its own.
 * Note if it was the only memeber then it remains so !
 */
#define PGRP_DEL( p ) \
{\
	(p)->p_pgrpb->p_pgrpf = (p)->p_pgrpf; \
	(p)->p_pgrpf->p_pgrpb = (p)->p_pgrpb; \
	(p)->p_pgrpb = (p);\
	(p)->p_pgrpf = (p);\
}
/*
 * Add a new process group list (p is a process group leader) to the tail of 
 * session list for session s.
 * set our back pointer to the old end of list.
 * set the forward pointer at the end of the list to point to us.
 * set the end pointer to be us.
 * set our forward pointer to the terminator (NULL).
 */
#define SESS_INS( p, s ) \
{\
	(p)->p_sessb = (s)->s_pgrp->p_sessb;\
	(s)->s_pgrp->p_sessb->p_sessf = (p); \
	(s)->s_pgrp->p_sessb = (p); \
	(p)->p_sessf = NULL; \
}

struct ctty {
	pid_t	c_sid;			/* copy of the session ID */
	pid_t	c_pgrp;			/* foreground process group */
	struct session	*c_session;	/* pointer back to session */
};

/*
 * controlling terminal ctty_xxx return values.
 */
#define CTTY_OK		1
#define CTTY_SIG	2
#define CTTY_ERR	3
#define CTTY_SLEPT	4

#endif
