/* 
 * msg.h
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 */

#ifndef __msg_h__
#define __msg_h__

#include "xtype.h"
#include "xk_assert.h"
#include "msg_p.h"
#include "trace.h"
#include "xk_debug.h"
#include "platform.h"

typedef enum {
    MA_LLC_HEADER,	/* used to pass LLC header between driver and protl */
    MA_CHAN_INFO	/* information for CHAN protocol */
} MsgAttribute;

#if defined(__STDC__) || defined(__GNUC__)

extern void     *msgInit(Msg *, int, void *, MsgDeallocator);
extern void     msgInitWithMsg(Msg *, Msg *);
extern void     *msgRefresh(Msg *, int);

static
#ifdef __GNUC__
inline
#endif
void msgDestroy(Msg *);

extern void     msgToughDestroy(MsgNode n);

extern void     msgDiscard(Msg *, int);
extern void     msgTruncate(Msg *, int);
extern void     msgAssign(Msg *, Msg *);
extern void     msgJoin(Msg *, Msg *, Msg *);
extern void     msgBreak(Msg *, Msg *, int);

extern void     *msgPush(Msg *, int);
extern void     *msgPop(Msg *, int);
extern void     *msgPeek(Msg *, int);

extern void     msgWalkInit(MsgWalk *, Msg *);

static
#ifdef __GNUC__
inline
#endif
void *msgWalkNext(MsgWalk *, int *);

extern void     *msgWalkToughNext(MsgWalk *, int *);

static
#ifdef __GNUC__
inline
#endif
void msgWalkDone(MsgWalk *);

extern XkReturn msgSetAttr(Msg *, int, void *, int);
extern void     *msgGetAttr(Msg *, int);

extern void     msgCleanUp(Msg *);
extern void     msgShow(Msg *);
extern void     msgStats(void);

#else	/* __STDC__ || __GNUC__ */

extern void     *msgInit();
extern void     msgInitWithMsg();
extern void     *msgRefresh();
static void     msgDestroy();
extern void     msgToughDestroy();

extern void     msgDiscard();
extern void     msgTruncate();
extern void     msgAssign();
extern void     msgJoin();
extern void     msgBreak();

extern void     *msgPush();
extern void     *msgPop();
extern void     *msgPeek();

extern void     msgWalkInit();
static void     *msgWalkNext();
extern void     *msgWalkToughNext();
static void     msgWalkDone();

extern XkReturn msgSetAttr();
extern void     *msgGetAttr();

extern void     msgCleanUp();
extern void     msgShow();
extern void     msgStats();

#endif	/* __STDC__ */

#define msgConstructEmpty(_m)                   msgInit(_m, 0, NULL, NULL)
#define msgConstructBuffer(_m,_buf,_len)        msgInit(_m, _len, _buf, NULL)
#define msgConstructAllocate(_m,_len)           msgInit(_m, _len, NULL, NULL)
#define msgConstructInplace(_m,_buf,_len,_free) msgInit(_m, _len, _buf, _free)
#define msgConstructCopy(_m1,_m2)               msgInitWithMsg(_m1, _m2)

/* performance-concessions */

/*
 * Notice that m->tail as a pointer is meaningful only for leaf nodes.
 * However, to avoid maintaining a separate "length" field, the
 * invariant is maintained that "m->tail - m->stackHead" gives the
 * length of the message.
 */
#define msgLength(message) ((message)->f.tail - (message)->f.head)

/*
 * This is an inlined function so that detecting the end of iteration
 * does not require a function call.
 */
static
#ifdef __GNUC__
inline
#endif
void *
msgWalkNext(MsgWalk *w, int *lenp)
{
    MsgNode next;
    void    *buf;

    next = w->f.tree;
    if (!next)
	return 0;
    else {
	if (next->c.type == MSG_NODE_PAIR || w->stack.tos > w->stack.bottom
	        /* PREDICT_FALSE */)
	    return msgWalkToughNext(w, lenp);
	else {
	    /* common case: last frag in the message: */
	    buf = ((MsgNodeLeaf)next)->leaf.buf + w->f.head;
	    *lenp = w->f.tail - w->f.head;
	    w->f.tree = 0;
	    return buf;
	}
    }
}

static
#ifdef __GNUC__
inline
#endif
void
msgWalkDone(MsgWalk *w)
{
    if (w->stack.bottom /* PREDICT_FALSE */)
	xFree((char *)w->stack.bottom);
}

static
#ifdef __GNUC__
inline
#endif
void
msgDestroy(Msg *m)
{
    MsgNode n;

    n = m->f.tree;
    xAssert(n && n->c.refCnt >= 1);

    /* xTrace3(msg, TR_MAJOR_EVENTS, "msgDestroy(n=%p,refCnt=%d,type=%d)",
	    n, n->c.refCnt, n->c.type); */
    if (--n->c.refCnt == 0)
	msgToughDestroy(n);
    /* xTrace1(msg, TR_FUNCTIONAL_TRACE, "msgDestroy: done %p", n); */
}

#endif /* __msg_h__ */
