/*
 *	Queue manipulation macros
 *	Allows the encapsulation and isolation of the implementation of priorities.
 *	Copyright (C) 1998 Jim Moores
 *	Modifications (C) 2002-2005 Fred Barnes
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#ifndef _QUEUES_H
#define _QUEUES_H

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sched_consts.h>

#if defined(CAN_DO_SCHEDSTRUCT)
extern sched_vars_type svars;
#endif


#ifdef PROCESS_PRIORITY
/* FIXME: keeping these separate for now -- gcc issues ? */
#if 0 && defined(CAN_DO_SCHEDSTRUCT)
#define Fptr_q svars.fptrq
#define Bptr_q svars.bptrq
#define PPriority svars.ppriority
#define PState svars.pstate

#else	/* !CAN_DO_SCHEDSTRUCT */
extern word *Fptr_q[MAX_PRIORITY_LEVELS];
extern word *Bptr_q[MAX_PRIORITY_LEVELS];
extern word PPriority;
extern word PState;
#endif	/* !CAN_DO_SCHEDSTRUCT */

#if defined(PROCESS_GROUPS)
#define MaskedPPriority (PPriority & PRIORITY_MASK)
#define MaskedPGroup (PPriority & PGROUP_MASK)
#define PriMasked(X) ((X) & PRIORITY_MASK)

#define PGroupOf(X) ((pgrpinfo_t *)(((X) & PGROUP_MASK) ? ((X) & PGROUP_MASK) : (int)&default_pgroup))
#define SetPGroup(X,G) (X) = (((X) & ~PGROUP_MASK) | ((word)(G) & PGROUP_MASK))

#else	/* !defined(PROCESS_GROUPS) */
#define MaskedPPriority PPriority
#define MaskedPGroup 0
#define PriMasked(X) (X)

#endif	/* !defined(PROCESS_GROUPS) */


#define SAVE_PRIORITY_QUEUE(L) \
	{ Fptr_q[L] = Fptr; Bptr_q[L] = Bptr; }
#define LOAD_PRIORITY_QUEUE(L) \
	{ Fptr = Fptr_q[L]; Bptr = Bptr_q[L]; }

#define PQUEUE(L,P) \
	if (Fptr_q[L] == NotProcess_p) { \
		Fptr_q[L] = P; \
	} else {\
		(Bptr_q[L])[Link] = (word)P; \
	} \
	Bptr_q[L] = P; \
	(Bptr_q[L])[Link] = NotProcess_p; \
	PState |= (1 << L)

#define SHOW_QUEUES(F) \
	{	int i; \
		for (i = 0; i < MAX_PRIORITY_LEVELS; i++) fprintf (F, "i:%-2d  Fptr_q[i] = 0x%8.8x    Bptr_q[i] = 0x%8.8x\n", i, Fptr_q[i], Bptr_q[i]); \
	}

#endif


/* put the process P on the run queue */
#define QUEUE(P) \
  if (Fptr == NotProcess_p) { \
    Fptr = P; \
  } else {\
    Bptr[Link] = (word)P; \
  } \
  Bptr = P; \
  Bptr[Link] = NotProcess_p
#define QUEUE_Q(F,B) \
  if (Fptr == NotProcess_p) { \
    Fptr = F; \
  } else { \
    Bptr[Link] = (word)F;\
  } \
  Bptr = B; \
  Bptr[Link] = NotProcess_p

#if 1
#define QUEUE_VQ(F,B) \
  if (Fptr == NotProcess_p) { \
    (volatile word *)Fptr = F; \
  } else { \
    (volatile word)(Bptr[Link]) = (volatile word)F; \
  } \
  (volatile word *)Bptr = B; \
  (volatile word)(Bptr[Link]) = NotProcess_p
#else
#define QUEUE_VQ(F,B) \
  if (Fptr == NotProcess_p) { \
    Bptr = B; \
  } else { \
    B[Link] = Fptr; \
  } \
  Fptr = F; \
  (volatile word)(Bptr[Link]) = NotProcess_p
#endif


/* returns the first process on the run queue.  This assumes that the
 * run queue is non-empty because this function has the contraint that
 * processes must have been added before calling it (for efficiency
 * reasons).
 */
#define GetNextProcess_NonEmptyQ() Fptr;Fptr = (word *)Fptr[Link]

/* This returns the first process on the run queue, but does not assume
 * that the queue is non-empty.
 */
#define GetNextProcess() \
    Fptr; \
/*    if (Fptr == Bptr) { \
      Fptr = NotProcess_p; \
      Bptr = NotProcess_p; \
    } else \ */ \
    Fptr = (word *)Fptr[Link]

/* returns true if the run queue is empty */
#define NoProcesses() (Fptr==NotProcess_p)


#endif /* !_QUEUES_H */



