#undef	Lock
#undef	lock
#undef	unlock
#undef	Ref
#undef	incref
#undef	decref
#undef	canlock
#undef	QLock
#undef	qlock
#undef	qunlock
#undef	canqlock
#undef	RWLock
#undef	runlock
#undef	wunlock
#undef	rlock
#undef	wlock
#undef	canrlock
#undef	canwlock
#undef	open
#undef	read
#undef	write
#undef	remove
#undef	wstat
#undef	sysname
#undef	Waitmsg
#undef	postnote
#undef	nsec

typedef struct Alarms	Alarms;
typedef struct Block	Block;
typedef struct Chan	Chan;
typedef struct Cmdbuf	Cmdbuf;
typedef struct Cmdtab	Cmdtab;
typedef struct Cname	Cname;
typedef struct Dev	Dev;
typedef struct Dirtab	Dirtab;
typedef struct Egrp	Egrp;
typedef struct Eiaport	Eiaport;
typedef struct Evalue	Evalue;
typedef struct Fgrp	Fgrp;
typedef struct DevConf	DevConf;
typedef struct Image	Image;
typedef struct Label	Label;
typedef struct List	List;
typedef struct Lock	Lock;
typedef struct Log	Log;
typedef struct Logflag	Logflag;
typedef struct Mntcache Mntcache;
typedef struct Mount	Mount;
typedef struct Mntrpc	Mntrpc;
typedef struct Mntwalk	Mntwalk;
typedef struct Mnt	Mnt;
typedef struct Mhead	Mhead;
typedef struct Note	Note;
typedef struct Page	Page;
typedef struct Pgrps	Pgrps;
typedef struct PhysUart	PhysUart;
typedef struct Pgrp	Pgrp;
typedef struct Physseg	Physseg;
typedef struct Proc	Proc;
typedef struct Procalloc	Procalloc;
typedef struct Pte	Pte;
typedef struct QLock	QLock;
typedef struct Queue	Queue;
typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct Rgrp	Rgrp;
typedef struct RWlock	RWlock;
typedef struct Systab	Systab;
typedef struct Talarm	Talarm;
typedef struct Uart	Uart;
typedef struct Waitq	Waitq;
typedef struct Walkqid	Walkqid;
typedef struct Waitmsg	Waitmsg;

typedef int	Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
typedef long	Syscall(ulong*);

enum
{
	KNAMELEN	= 28,
	MAXPROC		= 4096,
	HZ			= 1000,	/* not really, but it will do */
};

struct Lock
{
	ulong	key;			/* semaphore (non-zero = locked) */
	ulong	sr;
	ulong	pc;
	Proc	*p;
	ushort	isilock;
};

struct Ref
{
	Lock	lk;
	long	ref;
};

struct Rendez
{
	Lock	lk;
	Proc	*p;
};

struct QLock
{
	Lock	use;			/* to access Qlock structure */
	Proc	*head;			/* next process waiting for object */
	Proc	*tail;			/* last process waiting for object */
	int	locked;			/* flag */
};

struct RWlock
{
	Lock	use;
	Proc	*head;		/* list of waiting processes */
	Proc	*tail;
	ulong	wpc;		/* pc of writer */
	Proc	*wproc;		/* writing proc */
	int	readers;	/* number of readers */
	int	writer;		/* number of writers */
};

struct Talarm
{
	Lock	lk;
	Proc	*list;
};

struct Alarms
{
	QLock	lk;
	Proc	*head;
};

/*
 * Access types in namec & channel flags
 */
enum
{
	Aaccess,			/* as in stat, wstat */
	Abind,			/* for left-hand-side of bind */
	Atodir,				/* as in chdir */
	Aopen,				/* for i/o */
	Amount,				/* to be mounted or mounted upon */
	Acreate,			/* is to be created */
	Aremove,			/* will be removed by caller */

	COPEN	= 0x0001,		/* for i/o */
	CMSG	= 0x0002,		/* the message channel for a mount */
/*rsc	CCREATE	= 0x0004,		/* permits creation if c->mnt */
	CCEXEC	= 0x0008,		/* close on exec */
	CFREE	= 0x0010,		/* not in use */
	CRCLOSE	= 0x0020,		/* remove on close */
	CCACHE	= 0x0080,		/* client cache */
};

enum
{
	BINTR	=	(1<<0),
	BFREE	=	(1<<1),
};

struct Block
{
	Block*	next;
	Block*	list;
	uchar*	rp;			/* first unconsumed byte */
	uchar*	wp;			/* first empty byte */
	uchar*	lim;			/* 1 past the end of the buffer */
	uchar*	base;			/* start of the buffer */
	void	(*free)(Block*);
	ulong	flag;
};
#define BLEN(s)	((s)->wp - (s)->rp)
#define BALLOC(s) ((s)->lim - (s)->base)

struct Chan
{
	Ref	ref;
	Lock	lk;
	Chan*	next;			/* allocation */
	Chan*	link;
	vlong	offset;			/* in file */
	ushort	type;
	ulong	dev;
	ushort	mode;			/* read/write */
	ushort	flag;
	Qid	qid;
	int	fid;			/* for devmnt */
	ulong	iounit;	/* chunk size for i/o; 0==default */
	Mhead*	umh;			/* mount point that derived Chan; used in unionread */
	Chan*	umc;			/* channel in union; held for union read */
	QLock	umqlock;		/* serialize unionreads */
	int	uri;			/* union read index */
	int	dri;			/* devdirread index */
	ulong	mountid;
	Mnt		*mux;		/* Mnt for clients using me for messages */
	void*	aux;
	Qid	pgrpid;		/* for #p/notepg */
	ulong	mid;		/* for ns in devproc */
	Chan*	mchan;			/* channel to mounted server */
	Qid	mqid;			/* qid of root of mount point */
	Cname	*name;
};

struct Cname
{
	Ref	ref;
	int	alen;			/* allocated length */
	int	len;			/* strlen(s) */
	char	*s;
};

struct Dev
{
	int	dc;
	char*	name;

	void (*reset)(void);
	Chan*	(*attach)(char*);
	Walkqid*	(*walk)(Chan*, Chan*, char**, int);
	int	(*stat)(Chan*, uchar*, int);
	Chan*	(*open)(Chan*, int);
	void	(*create)(Chan*, char*, int, ulong);
	void	(*close)(Chan*);
	long	(*read)(Chan*, void*, long, vlong);
	Block*	(*bread)(Chan*, long, ulong);
	long	(*write)(Chan*, void*, long, vlong);
	long	(*bwrite)(Chan*, Block*, ulong);
	void	(*remove)(Chan*);
	int	(*wstat)(Chan*, uchar*, int);
};

struct Dirtab
{
	char	name[KNAMELEN];
	Qid	qid;
	vlong length;
	long	perm;
};

struct Label
{
	pm_jmp_buf jb;
};

enum
{
	NSMAX	=	1000,
	NSLOG	=	7,
	NSCACHE	=	(1<<NSLOG),
};

struct Mntwalk				/* state for /proc/#/ns */
{
	int		cddone;
	ulong	id;
	Mhead*	mh;
	Mount*	cm;
};

struct Mount
{
	ulong	mountid;
	Mount*	next;
	Mhead*	head;
	Mount*	copy;
	Mount*	order;
	Chan*	to;			/* channel replacing channel */
	int	mflag;
	char	*spec;
};

struct Mhead
{
	Ref	ref;
	RWlock	lk;
	Chan*	from;			/* channel mounted upon */
	Mount*	mount;			/* what's mounted upon it */
	Mhead*	hash;			/* Hash chain */
};

struct Mnt
{
	Lock	lk;
	/* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
	Chan	*c;		/* Channel to file service */
	Proc	*rip;		/* Reader in progress */
	Mntrpc	*queue;		/* Queue of pending requests on this channel */
	ulong	id;		/* Multiplexer id for channel check */
	Mnt	*list;		/* Free list */
	int	flags;		/* cache */
	int	msize;		/* data + IOHDRSZ */
	char	*version;			/* 9P version */
	Queue	*q;		/* input queue */
};

enum
{
	NUser,				/* note provided externally */
	NExit,				/* deliver note quietly */
	NDebug,				/* print debug message */
};

struct Note
{
	char	msg[ERRMAX];
	int	flag;			/* whether system posted it */
};

enum
{
	RENDLOG	=	5,
	RENDHASH =	1<<RENDLOG,		/* Hash to lookup rendezvous tags */
	MNTLOG	=	5,
	MNTHASH =	1<<MNTLOG,		/* Hash to walk mount table */
	NFD =		100,		/* per process file descriptors */
	PGHLOG  =	9,
	PGHSIZE	=	1<<PGHLOG,	/* Page hash for image lookup */
};
#define REND(p,s)	((p)->rendhash[(s)&((1<<RENDLOG)-1)])
#define MOUNTH(p,qid)	((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])

struct Pgrp
{
	Ref	ref;				/* also used as a lock when mounting */
	int	noattach;
	ulong	pgrpid;
	QLock	debug;			/* single access via devproc.c */
	RWlock	ns;			/* Namespace n read/one write lock */
	QLock	nsh;
	Mhead	*mnthash[MNTHASH];
};

struct Rgrp
{
	Ref	ref;
	Proc	*rendhash[RENDHASH];	/* Rendezvous tag hash */
};

struct Egrp
{
	Ref	ref;
	QLock	lk;
	Evalue	*entries;
	ulong	path;	/* qid.path of next Evalue to be allocated */
	ulong	vers;	/* of Egrp */
};

struct Evalue
{
	char	*name;
	char	*value;
	int	len;
	int	dirty;
	Evalue	*link;
	PmQid	qid;
};

struct Fgrp
{
	Lock	lk;
	Ref	ref;
	Chan	**fd;
	int	nfd;			/* number allocated */
	int	maxfd;			/* highest fd in use */
};

enum
{
	DELTAFD	= 20		/* incremental increase in Fgrp.fd's */
};

struct Waitmsg
{
	int	pid;	/* of loved one */
	ulong	time[3];	/* of loved one and descendants */
	char	msg[ERRMAX];	/* actually variable-size in user mode */
};

struct Waitq
{
	Waitmsg	w;
	Waitq	*next;
};

struct Walkqid
{
	Chan	*clone;
	int	nqid;
	Qid	qid[1];
};

enum
{
	Dead = 0,		/* Process states */
	Nascent,
	Moribund,
	Ready,
	Scheding,
	Running,
	Queueing,
	QueueingR,
	QueueingW,
	Wakeme,
	Broken,
	Stopped,
	Rendezvous,

	Proc_stopme = 1, 	/* devproc requests */
	Proc_exitme,
	Proc_traceme,
	Proc_exitbig,

	TUser = 0, 		/* Proc.time */
	TSys,
	TReal,
	TCUser,
	TCSys,
	TCReal,

	NERR = 15,
	NNOTE = 5,

	Nrq		= 20,	/* number of scheduler priority levels */
	PriLock		= 0,	/* priority for processes waiting on a lock */
	PriNormal	= 10,	/* base priority for normal processes */
	PriKproc	= 13,	/* base priority for kernel processes */
	PriRoot		= 13,	/* base priority for root processes */

};

struct Proc
{
	Label	sched;
	char *kstack;
	char	*text;
	char	*user;
	char	*args;
	int	nargs;		/* number of bytes of args */
	Proc	*rnext;		/* next process in run queue */
	Proc	*qnext;		/* next process on queue for a QLock */
	QLock	*qlock;		/* addr of qlock being queued for DEBUG */
	int	state;
	Lock	nascent;	/* locked to claim a nascent proc */
	char	*psstate;	/* What /proc/#/status reports */
	ulong	pid;
	ulong	noteid;		/* Equivalent of note group */
	Proc	*pidhash;	/* next proc in pid hash */

	Lock	exl;		/* Lock count and waitq */
	Waitq	*waitq;		/* Exited processes wait children */
	int	nchild;		/* Number of living children */
	int	nwait;		/* Number of uncollected wait records */
	QLock	qwaitr;
	Rendez	waitr;		/* Place to hang out in wait */
	Proc	*parent;

	Pgrp	*pgrp;		/* Process group for namespace */
	Egrp 	*egrp;		/* Environment group */
	Fgrp	*fgrp;		/* File descriptor group */
	Rgrp	*rgrp;		/* Rendez group */

	ulong	parentpid;
	ulong	time[6];	/* User, Sys, Real; child U, S, R */
	short	insyscall;
	int	fpstate;

	QLock	debug;		/* to access debugging elements of User */
	Proc	*pdbg;		/* the debugging process */
	ulong	procmode;	/* proc device file mode */
	ulong	privatemem;	/* proc does not let anyone read mem */
	int	hang;		/* hang at next exec for debug */
	int	procctl;	/* Control for /proc debugging */
	ulong	pc;		/* DEBUG only */

	Lock	rlock;		/* sync sleep/wakeup with postnote */
	Rendez	*r;		/* rendezvous point slept on */
	Rendez	sleep;		/* place for syssleep/debug */
	int	notepending;	/* note issued but not acted on */
	int	kp;		/* true if a kernel process */
	Proc	*palarm;	/* Next alarm time */
	ulong	alarm;		/* Time of call */
	int	newtlb;		/* Pager has changed my pte's, I must flush */

	ulong	rendtag;	/* Tag for rendezvous */
	ulong	rendval;	/* Value for rendezvous */
	Proc	*rendhash;	/* Hash list for tag values */

	ulong	twhen;
	Rendez	*trend;
	Proc	*tlink;
	int	(*tfn)(void*);
	void	(*kpfun)(void*);
	void	*kparg;

	Label errlab[16];
	int nerrlab;
	char *syserrstr;			/* last error from a system call, errbuf0 or 1 */
	char *errstr;			/* reason we're unwinding the error stack, errbuf1 or 0 */
	char errbuf0[ERRMAX];
	char errbuf1[ERRMAX];
	char	genbuf[128];	/* buffer used e.g. for last name element from namec */
	Chan	*slash;
	Chan	*dot;

	Note	note[NNOTE];
	short	nnote;
	short	notified;	/* sysnoted is due */
	Note	lastnote;
	int	(*notify)(void*, char*);

	int	lockwait;	/* waiting for lock to be released */

	Mach *mach;
	ulong	priority;	/* priority level */
	ulong	basepri;	/* base priority level */
	uchar	fixedpri;	/* priority level deson't change */
	ulong	rt;		/* # ticks used since last blocked */
	ulong	art;		/* avg # ticks used since last blocked */
	ulong	movetime;	/* last time process switched processors */
	ulong	readytime;	/* time process went ready */
	int	preempted;	/* true if this process hasn't finished the interrupt
				 *  that last preempted it
				 */
	ulong	qpc;		/* pc calling last blocking qlock */

	void	*ureg;		/* User registers for notes */
	void	*dbgreg;	/* User registers for devproc */

	int	bss;		/* process-reported memory in use */
	int	index;	/* into procalloc.arena */
	char	exitstatus[ERRMAX];
	void	(*die)(Proc*, char *exitstr);
	void *sysaux;
};

struct Procalloc
{
	Lock	lk;
	int 		nproc;
	Proc*	ht[128];
	Proc**	arena;
	Proc*	free;
};

enum
{
	PRINTSIZE =	256,
	MAXCRYPT = 	127,
	NUMSIZE	=	12,		/* size of formatted number */
	MB =		(1024*1024),
	READSTR =	1000,		/* temporary buffer size for device reads */
};

extern	Dev*	devtab[];
extern	char	*eve;
extern	char	hostdomain[];
extern	char	isfrog[];
extern	Queue*	kbdq;
extern	Queue*	kprintoq;
extern	Ref	noteidalloc;
extern	char*	statename[];
extern	char	*sysname;
extern	Talarm	talarm;
extern	uint	qiomaxatomic;

enum
{
	LRESPROF	= 3,
};

/*
 *  action log
 */
struct Log {
	Lock;
	int	opens;
	char*	buf;
	char	*end;
	char	*rptr;
	int	len;
	int	nlog;
	int	minread;

	int	logmask;	/* mask of things to debug */

	QLock	readq;
	Rendez	readr;
};

struct Logflag {
	char*	name;
	int	mask;
};

enum
{
	NCMDFIELD = 128
};

struct Cmdbuf
{
	char	*buf;
	char	**f;
	int	nf;
};

struct Cmdtab
{
	int	index;	/* used by client to switch on result */
	char	*cmd;	/* command name */
	int	narg;	/* expected #args; 0 ==> variadic */
};

struct Systab
{
	Syscall	*fn;
	char		*fmt;
	char		*psstate;
};

#define DEVDOTDOT -1

extern Dev*	devtab[];
extern Dev	devaudio;
extern Dev	devcons;
extern Dev	devdraw;
extern Dev	devdup;
extern Dev	deveia;
extern Dev	devenv;
extern Dev	devfs;
extern Dev	devip;
extern Dev	devmnt;
extern Dev	devmouse;
extern Dev	devpipe;
extern Dev	devproc;
extern Dev	devroot;
extern Dev	devsrv;
extern Dev	devssl;

extern Mach	*machp0;

extern Procalloc procalloc;
extern Systab	systab[Nsyscall];

extern char Enoerror[];		/* no error */
extern char Emount[];		/* inconsistent mount */
extern char Eunmount[];		/* not mounted */
extern char Eunion[];		/* not in union */
extern char Emountrpc[];		/* mount rpc error */
extern char Eshutdown[];		/* device shut down */
extern char Enocreate[];		/* mounted directory forbids creation */
extern char Enonexist[];		/* file does not exist */
extern char Eexist[];			/* file already exists */
extern char Ebadsharp[];		/* unknown device in # filename */
extern char Enotdir[];		/* not a directory */
extern char Eisdir[];			/* file is a directory */
extern char Ebadchar[];		/* bad character in file name */
extern char Efilename[];		/* file name syntax */
extern char Eperm[];			/* permission denied */
extern char Ebadusefd[];		/* inappropriate use of fd */
extern char Ebadarg[];		/* bad arg in system call */
extern char Einuse[];			/* device or object already in use */
extern char Eio[];			/* i/o error */
extern char Etoobig[];		/* read or write too large */
extern char Etoosmall[];		/* read or write too small */
extern char Enoport[];		/* network port not available */
extern char Ehungup[];		/* i/o on hungup channel */
extern char Ebadctl[];		/* bad process or channel control request */
extern char Enodev[];		/* no free devices */
extern char Eprocdied[];		/* process exited */
extern char Enochild[];		/* no living children */
extern char Eioload[];		/* i/o error in demand load */
extern char Enovmem[];		/* virtual memory allocation failed */
extern char Ebadfd[];		/* fd out of range or not open */
extern char Enofd[];			/* no free file descriptors */
extern char Eisstream[];		/* seek on a stream */
extern char Ebadexec[];		/* exec header invalid */
extern char Etimedout[];		/* connection timed out */
extern char Econrefused[];	/* connection refused */
extern char Econinuse[];		/* connection in use */
extern char Eintr[];			/* interrupted */
extern char Enomem[];		/* kernel allocate failed */
extern char Enoswap[];		/* swap space full */
extern char Esoverlap[];		/* segments overlap */
extern char Emouseset[];		/* mouse type already set */
extern char Eshort[];			/* i/o count too small */
extern char Egreg[];			/* ken has left the building */
extern char Ebadspec[];		/* bad attach specifier */
extern char Enoreg[];		/* process has no saved registers */
extern char Enoattach[];		/* mount/attach disallowed */
extern char Eshortstat[];		/* stat buffer too small */
extern char Ebadstat[];		/* malformed stat buffer */
extern char Enegoff[];		/* negative i/o offset */
extern char Ecmdargs[];		/* wrong #args in control message */

#define	M	getmach()
#define	up	(M->_up)
