/*
 * $RCSfile: upi_inline.h,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Log: upi_inline.h,v $
 * Revision 1.2  1996/01/29 20:25:55  slm
 * Updated copyright and version.
 *
 * Revision 1.1  1995/07/28  21:29:10  slm
 * Initial revision
 *
 * Revision 1.22.1.1  1994/10/27  20:48:19  hkaram
 * New branch
 *
 * Revision 1.22  1994/08/10  16:30:14  davidm
 * xGetDown() now checks s->numdown before accessing the variable length
 * array.  The common case where i < STD_DOWN is as efficient as before.
 *
 * Revision 1.21  1994/08/10  05:34:56  davidm
 * xGetDown is now an inlinable function.  FUNC_TYPE renamed into
 * FUNC_SCLASS as it only specifies the storage class, not the
 * full type anymore (because xGetDown returns XObj, not XkReturn).
 * Also added "#undef FUNC_SCLASS" at end of include file.
 *
 * Revision 1.20  1994/03/13  03:33:42  davidm
 * Pointers are now printed as "%lx" and cast to (u_long).
 *
 * Revision 1.19  1993/12/12  05:07:20  menze
 * Previous merge was botched
 *
 * Revision 1.18  1993/12/11  01:17:09  menze
 * Fixed trace deadlock problem with msgLen() inside of xTrace macro.
 * [93/06/21	erich]
 */

#ifndef upi_inline_h
#define upi_inline_h

#include "platform.h"

/*
 * definitions of xPop and xCallPop
 *
 * If XK_USE_INLINE is defined, these are inline functions.  If not, these are
 * the prototypes for regular functions.  One source file should define
 * UPI_INLINE_INSTANTIATE before including this file.  This will cause the
 * actual functions to be instantiated in that source file.
 */

#ifdef XK_USE_INLINE
#define FUNC_SCLASS static __inline__
#else
#define FUNC_SCLASS
#endif /* XK_USE_INLINE */

#ifdef __STDC__

FUNC_SCLASS Protl    xGetProtlDown(Protl, int);
FUNC_SCLASS Sessn    xGetSessnDown(Sessn, int);
FUNC_SCLASS XkReturn xPop(Sessn, Sessn, Msg *, void *);
FUNC_SCLASS XkReturn xCallPop(Sessn, Sessn, Msg *, void *, Msg *);

#else

FUNC_SCLASS Protl    xGetProtlDown();
FUNC_SCLASS Sessn    xGetSessnDown();
FUNC_SCLASS XkReturn xPop();
FUNC_SCLASS XkReturn xCallPop();

#endif /* __STDC__ */

#if defined(XK_USE_INLINE) || defined(UPI_INLINE_INSTANTIATE)

/*
 * OP_COUNTS controls whether session reference counts are raised and lowered
 * around each operation in order to count the number of operations
 * "outstanding" on that session
 */
#define OP_COUNTS

#ifdef OP_COUNTS
#define INC_REF_COUNT(sessn, func) {                                       \
    (sessn)->rcnt++;                                                       \
    xTrace4(protocol, TR_MORE_EVENTS,                                      \
	    "%s increased ref count of %lx[%s] to %d",                     \
	    (func), (u_long)sessn, (sessn)->myprotl->name, (sessn)->rcnt); \
}
#else
#define INC_REF_COUNT(s, func) 1
#endif

#define DEC_REF_COUNT_UNCOND(sessn, func) {                                    \
    if (--(sessn)->rcnt <= 0) {                                                \
	xTrace4(protocol, TR_MORE_EVENTS,                                      \
		"%s -- ref count of %lx[%s] is %d, calling close",             \
		(func), (u_long)sessn, (sessn)->myprotl->name, (sessn)->rcnt); \
	(*(sessn)->close)(sessn);                                              \
    } else {                                                                   \
	xTrace4(protocol, TR_MORE_EVENTS,                                      \
		"%s -- decreased ref count of %lx[%s] to %d",                  \
		(func), (u_long)sessn, (sessn)->myprotl->name, (sessn)->rcnt); \
    }                                                                          \
}

#ifdef OP_COUNTS
#define DEC_REF_COUNT(sessn, func) DEC_REF_COUNT_UNCOND((sessn), (func))
#else
#define DEC_REF_COUNT(sessn, func) 1
#endif

FUNC_SCLASS Protl
xGetProtlDown(protl, indx)
Protl protl;
int   indx;
{
    xAssert(xIsProtl(protl));
    if (indx < STD_DOWN)
	return protl->down[indx];
    if (indx < protl->numdown)
	return protl->downlist[indx - STD_DOWN];
    else
	return ERR_PROTL;
}

FUNC_SCLASS Sessn
xGetSessnDown(sessn, indx)
Sessn sessn;
int   indx;
{
    xAssert(xIsSessn(sessn));
    if (indx < STD_DOWN)
	return sessn->down[indx];
    if (indx < sessn->numdown)
	return sessn->downlist[indx - STD_DOWN];
    else
	return ERR_SESSN;
}

FUNC_SCLASS XkReturn
xPop(self, lls, message, hdr)
Sessn self, lls;
Msg   *message;
void  *hdr;
{
    XkReturn retVal;
    int      len;

    xAssert(!lls || xIsSessn(lls));
    INC_REF_COUNT(self, "xPop");
    xIfTrace(protocol, TR_EVENTS) { len = msgLength(message); }
    xTrace2(protocol, TR_EVENTS, "Calling pop[%s], %d bytes",
	    self->myprotl->name, len);
    retVal = (*self->pop)(self, lls, message, hdr);
    DEC_REF_COUNT(self, "xPop");
    return retVal;
}

FUNC_SCLASS XkReturn
xCallPop(self, lls, request, hdr, reply)
Sessn self, lls;
Msg   *request, *reply;
void  *hdr;
{
    XkReturn retVal;
    int      len;

    xAssert(!lls || xIsSessn(lls));
    INC_REF_COUNT(self, "xCallPop");
    xIfTrace(protocol, TR_EVENTS) { len = msgLength(request); }
    xTrace2(protocol, TR_EVENTS, "Calling callpop[%s], %d bytes",
	    self->myprotl->name, len);
    retVal =  (*self->callpop)(self, lls, request, hdr, reply);
    xIfTrace(protocol, TR_EVENTS) { len = msgLength(reply); }
    xTrace2(protocol, TR_EVENTS, "callpop[%s] returns %d bytes",
	    self->myprotl->name, len);
    DEC_REF_COUNT(self, "xCallPop");
    return retVal;
}

#endif /* defined(XK_USE_INLINE) || defined(UPI_INLINE_INSTANTIATE) */

#undef FUNC_SCLASS

#endif /* ! upi_inline_h */
