vxWorks消息队列源码

文章目录

msgQLib.h

/* msgQLib.h - message queue library header file */

/* Copyright 1984-2001 Wind River Systems, Inc. */

/*
modification history
--------------------
02m,19oct01,bwa  Added MSG_Q_EVENTSEND_ERR_NOTIFY option.
02l,17apr98,rlp  canceled MSG_Q_INFO modification for backward compatibility.
02k,04nov97,rlp  modified MSG_Q_INFO structure for tracking messages sent.
02j,13jul93,wmd  use MEM_ROUND_UP to determine MSG_NODE_SIZE.
02i,22sep92,rrr  added support for c++
02h,04jul92,jcf  cleaned up.
01g,26may92,rrr  the tree shuffle
01f,04oct91,rrr  passed through the ansification filter
		  -changed copyright notice
01e,05oct90,dnw  changed MSG_Q_INFO structure.
01d,05oct90,dnw  changed function declarations for new interface.
01c,05oct90,shl  added ANSI function prototypes.
                 made #endif ANSI style.
                 added copyright notice.
01b,07aug90,shl  moved function declarations to end of file.
01a,10may90,dnw  written
*/

#ifndef __INCmsgQLibh
#define __INCmsgQLibh

#ifdef __cplusplus
extern "C" {
#endif

#include "vxWorks.h"
#include "vwModNum.h"


/* generic status codes */

#define S_msgQLib_INVALID_MSG_LENGTH		(M_msgQLib | 1)
#define S_msgQLib_NON_ZERO_TIMEOUT_AT_INT_LEVEL	(M_msgQLib | 2)
#define S_msgQLib_INVALID_QUEUE_TYPE		(M_msgQLib | 3)

/* message queue options */

#define MSG_Q_TYPE_MASK	0x01	/* mask for pend queue type in options */
#define MSG_Q_FIFO	0x00	/* tasks wait in FIFO order */
#define MSG_Q_PRIORITY	0x01	/* tasks wait in PRIORITY order */
#define MSG_Q_EVENTSEND_ERR_NOTIFY 0x02 /* notify when eventRsrcSend fails */


/* message send priorities */

#define MSG_PRI_NORMAL	0	/* normal priority message */
#define MSG_PRI_URGENT	1	/* urgent priority message */

/* message queue typedefs */

typedef struct msg_q *MSG_Q_ID;	/* message queue ID */

typedef struct			/* MSG_Q_INFO */
    {
    int     numMsgs;		/* OUT: number of messages queued */
    int     numTasks;		/* OUT: number of tasks waiting on msg q */

    int     sendTimeouts;	/* OUT: count of send timeouts */
    int     recvTimeouts;	/* OUT: count of receive timeouts */

    int     options;		/* OUT: options with which msg q was created */
    int     maxMsgs;		/* OUT: max messages that can be queued */
    int     maxMsgLength;	/* OUT: max byte length of each message */

    int     taskIdListMax;	/* IN: max tasks to fill in taskIdList */
    int *   taskIdList;		/* PTR: array of task ids waiting on msg q */

    int     msgListMax;		/* IN: max msgs to fill in msg lists */
    char ** msgPtrList;		/* PTR: array of msg ptrs queued to msg q */
    int *   msgLenList;		/* PTR: array of lengths of msgs */

    } MSG_Q_INFO;

/* macros */

/* The following macro determines the number of bytes needed to buffer
 * a message of the specified length.  The node size is rounded up for
 * efficiency.  The total buffer space required for a pool for
 * <maxMsgs> messages each of up to <maxMsgLength> bytes is:
 *
 *    maxMsgs * MSG_NODE_SIZE (maxMsgLength)
 */

#define MSG_NODE_SIZE(msgLength) \
	(MEM_ROUND_UP((sizeof (MSG_NODE) + msgLength)))

/* function declarations */

#if defined(__STDC__) || defined(__cplusplus)

extern STATUS 	msgQLibInit (void);
extern MSG_Q_ID msgQCreate (int maxMsgs, int maxMsgLength, int options);
extern STATUS 	msgQDelete (MSG_Q_ID msgQId);
extern STATUS 	msgQSend (MSG_Q_ID msgQId, char *buffer, UINT nBytes,
			  int timeout, int priority);
extern int 	msgQReceive (MSG_Q_ID msgQId, char *buffer, UINT maxNBytes,
			     int timeout);
extern STATUS 	msgQInfoGet (MSG_Q_ID msgQId, MSG_Q_INFO *pInfo);
extern int 	msgQNumMsgs (MSG_Q_ID msgQId);
extern void 	msgQShowInit (void);
extern STATUS 	msgQShow (MSG_Q_ID msgQId, int level);

#else	/* __STDC__ */

extern STATUS 	msgQLibInit ();
extern MSG_Q_ID 	msgQCreate ();
extern STATUS 	msgQDelete ();
extern STATUS 	msgQSend ();
extern int 	msgQReceive ();
extern STATUS 	msgQInfoGet ();
extern int 	msgQNumMsgs ();
extern void 	msgQShowInit ();
extern STATUS 	msgQShow ();

#endif	/* __STDC__ */

#ifdef __cplusplus
}
#endif

#endif /* __INCmsgQLibh */

msgQLib.c

/* msgQLib.c - message queue library */

/* Copyright 1990-2001 Wind River Systems, Inc. */
#include "copyright_wrs.h"

/*
modification history
--------------------
02n,10dec01,bwa  Added comment about MSG_Q_EVENTSEND_ERR_NOTIFY msgQCreate
                 option (SPR 72058).
02m,26oct01,bwa  Added msgQEvLib and eventLib to the list of 'SEE ALSO'
                 modules.
02l,12oct01,cjj  Added documentation regarding S_eventLib_EVENTSEND_FAILED
                 error
02k,09oct01,gls  merged in 02j, 02i, 02h, 02g below from AE.
02j,22feb01,ahm  ensured errno does'nt change if msgQDelete() is successful
                 (SPR#34643)
02i,19sep00,bwa  passed extra argument (msgQid) to calls to qJobGet()
                 added errnoSet after calls to qJobGet()(SPR #34057) 
02h,06sep00,aeg  doc: mentioned INCLUDE_MSG_Q component name.
02g,11aug00,aeg  fixed updating of timeout stats in msgQSend/Receive (SPR 33683)
02f,07sep01,bwa  Added VxWorks events support. Fixed SPR #31241 (corrected
		 msgQReceive comment for NO_WAIT).
02e,18dec00,pes  Correct compiler warnings
02d,19may98,drm  merged code from 3rd party to add distributed message queue 
                 support.
                 - merged code was originally based on version 02a 
02c,11may98,cjtc fix problem with problem fix!! Multiple calls to object
                 instrumentation in msgQDestroy
02b,11may98,nps  fixed msgQDestroy instrumentation anomaly.
02c,17apr98,rlp  canceled msgQInit and msgQSend modifications for backward
                 compatibility.
02b,04nov97,rlp  modified msgQInit and msgQSend for tracking messages sent.
02a,24jun96,sbs  made windview instrumentation conditionally compiled
01z,22oct95,jdi  doc: added bit values for options (SPR 4276).
02d,14apr94,smb  fixed class dereferencing for instrumentation macros
02c,15mar94,smb  modified instrumentation macros
02b,24jan94,smb  added instrumentation macros
02a,18jan94,smb  added instrumentation corrections for msgQDelete
01z,10dec93,smb  added instrumentation
01y,30jun93,jmm  changed msgQDestroy to look at msgQ as well as freeQ (spr 2070)
01x,02feb93,jdi  documentation cleanup for 5.1.
01w,13nov92,jcf  package init called with object creation.
01v,19oct92,pme  added reference to shared message queue documentation.
01u,23aug92,jcf  balanced taskSafe with taskUnsafe.
01t,11aug92,jcf  fixed msgQDestroy safety problem.
01s,30jul92,rrr  added restart and msgQ fix
01r,29jul92,pme  added NULL function pointer check for smObj routines.
01q,29jul92,jcf  package init called with object initialization.
01p,22jul92,pme  made msgQDestroy return S_smObjLib_NO_OBJECT_DESTROY when
		 trying to destroy a shared message queue.
01o,19jul92,pme  added shared message queue support.
01n,18jul92,smb  Changed errno.h to errnoLib.h.
01m,04jul92,jcf	 show routine removed.
01l,26may92,rrr  the tree shuffle
01k,13dec91,gae  ANSI fixes.  
01j,19nov91,rrr  shut up some ansi warnings.
01i,04oct91,rrr  passed through the ansification filter
                  -changed functions to ansi style
		  -changed includes to have absolute path from h/
		  -changed VOID to void
		  -changed copyright notice
01h,10aug91,del  changed interface to qInit to pass all "optional" args.
01g,05apr91,jdi	 documentation -- removed header parens and x-ref numbers;
		 doc review by dnw.
01f,22jan91,jaa	 documentation.
01e,08oct90,dnw  lint
01d,01oct90,dnw  fixed bug of msgQSend() not returning ERROR on timeout.
		 removed msgQSendArgs()/ReceiveArgs().
		 reordered parameters of msgQ{Send,Receive}().
		 simplified msgQInfoGet() interface.
		 added msgQNumMsgs().
		 made msgQDestroy() LOCAL.
		 made msgQ{LibInit,Init,Terminate}() be NOMANUAL.
		 finished documentation.
01c,19jul90,dnw  added VARARGS to msgQ{Send,Receive}Args()
01b,19jul90,dnw  changed call to objAlloc() to objAllocExtra()
		 made msgQShow() prettier
		 lint
01a,10may90,dnw  written
*/

/*
DESCRIPTION
This library contains routines  for creating and using message queues, the 
primary intertask communication mechanism within a single CPU.  Message
queues allow a variable number of messages (varying in length) to be
queued in first-in-first-out (FIFO) order.  Any task or interrupt service
routine can send messages to a message queue.  Any task can receive
messages from a message queue.  Multiple tasks can send to and receive
from the same message queue.  Full-duplex communication between two tasks
generally requires two message queues, one for each direction.

To provide message queue support for a system, VxWorks must be configured
with the INCLUDE_MSG_Q component.

CREATING AND USING MESSAGE QUEUES
A message queue is created with msgQCreate().  Its parameters specify the
maximum number of messages that can be queued to that message queue and 
the maximum length in bytes of each message.  Enough buffer space will 
be pre-allocated to accommodate the specified number of messages of 
specified length.

A task or interrupt service routine sends a message to a message queue
with msgQSend().  If no tasks are waiting for messages on the message queue,
the message is simply added to the buffer of messages for that queue.
If any tasks are already waiting to receive a message from the message
queue, the message is immediately delivered to the first waiting task.

A task receives a message from a message queue with msgQReceive().
If any messages are already available in the message queue's buffer,
the first message is immediately dequeued and returned to the caller.
If no messages are available, the calling task will block and be added to
a queue of tasks waiting for messages.  This queue of waiting tasks can
be ordered either by task priority or FIFO, as specified in an option
parameter when the queue is created.

TIMEOUTS
Both msgQSend() and msgQReceive() take timeout parameters.  When sending a
message, if no buffer space is available to queue the message, the timeout
specifies how many ticks to wait for space to become available.  When
receiving a message, the timeout specifies how many ticks to wait if no
message is immediately available.  The <timeout> parameter can
have the special values NO_WAIT (0) or WAIT_FOREVER (-1).  NO_WAIT 
means the routine should return immediately; WAIT_FOREVER means the routine
should never time out.

URGENT MESSAGES
The msgQSend() routine allows the priority of a message to be specified
as either normal or urgent, MSG_PRI_NORMAL (0) and MSG_PRI_URGENT (1),
respectively.  Normal priority messages are added to the tail of the list
of queued messages, while urgent priority messages are added to the head
of the list.

VXWORKS EVENTS
If a task has registered with a message queue via msgQEvStart(), events will
be sent to that task when a message arrives on that message queue, on the
condition that no other task is pending on the queue.

INTERNAL:
	WINDVIEW INSTRUMENTATION
Level 1:
	msgQCreate() causes EVENT_MSGQCREATE
	msgQDestroy() causes EVENT_MSGQDELETE
	msgQSend() causes EVENT_MSGQSEND
	msgQReceive() causes EVENT_MSGQRECEIVE

Level 2:
	N/A

Level 3:
	N/A

INCLUDE FILES: msgQLib.h

SEE ALSO: pipeDrv, msgQSmLib, msgQEvLib, eventLib,
.pG "Basic OS"
*/

#include "vxWorks.h"
#include "stdlib.h"
#include "string.h"
#include "taskLib.h"
#include "intLib.h"
#include "smObjLib.h"
#include "errnoLib.h"
#include "private/eventLibP.h"
#include "private/classLibP.h"
#include "private/objLibP.h"
#include "private/msgQLibP.h"
#include "private/msgQSmLibP.h"
#include "private/distObjTypeP.h"
#include "private/sigLibP.h"
#include "private/eventP.h"
#include "private/windLibP.h"
#include "private/kernelLibP.h"


/* locals */

LOCAL OBJ_CLASS msgQClass;

/* globals */

CLASS_ID msgQClassId = &msgQClass;

/* Instrumentation locals and globals */

#ifdef WV_INSTRUMENTATION
LOCAL OBJ_CLASS msgQInstClass;
CLASS_ID msgQInstClassId = &msgQInstClass;
#endif

/* shared memory objects function pointers */

FUNCPTR  msgQSmSendRtn;
FUNCPTR  msgQSmReceiveRtn;
FUNCPTR  msgQSmNumMsgsRtn;

/* distributed objects function pointers */

FUNCPTR  msgQDistSendRtn;
FUNCPTR  msgQDistReceiveRtn;
FUNCPTR  msgQDistNumMsgsRtn;

/* forward declarations */

LOCAL STATUS msgQDestroy (MSG_Q_ID msgQId, BOOL dealloc);

/* locals */

LOCAL BOOL msgQLibInstalled;	/* protect from muliple inits */


/*******************************************************************************
*
* msgQLibInit - initialize message queue library
*
* This routine initializes message queue facility.
* It is called once in kernelInit().
*
* RETURNS: OK or ERROR
*
* NOMANUAL
*/

STATUS msgQLibInit (void)
    {
    /* initialize shared memory objects function pointers */

    if (!msgQLibInstalled)
	{
	if (classInit (msgQClassId, sizeof (MSG_Q), OFFSET (MSG_Q, objCore),
		       (FUNCPTR)msgQCreate, (FUNCPTR)msgQInit,
		       (FUNCPTR)msgQDestroy) == OK)
	    {

#ifdef WV_INSTRUMENTATION
	    /* Instrumented class for windview */
	    msgQClassId->initRtn = msgQInstClassId;
            classInstrument (msgQClassId,msgQInstClassId);
#endif

	    msgQEvLibInit (); /* pull msgQLib in kernel */

	    msgQLibInstalled = TRUE;
	    }
	}

    return ((msgQLibInstalled) ? OK : ERROR);
    }

/*******************************************************************************
*
* msgQCreate - create and initialize a message queue
*
* This routine creates a message queue capable of holding up to <maxMsgs>
* messages, each up to <maxMsgLength> bytes long.  The routine returns 
* a message queue ID used to identify the created message queue in all 
* subsequent calls to routines in this library.  The queue can be created 
* with the following options:
* .iP "MSG_Q_FIFO  (0x00)" 8
* queue pended tasks in FIFO order.
* .iP "MSG_Q_PRIORITY  (0x01)"
* queue pended tasks in priority order.
* .iP "MSG_Q_EVENTSEND_ERR_NOTIFY (0x02)"
* When a message is sent, if a task is registered for events and the
* actual sending of events fails, a value of ERROR is returned and the errno
* is set accordingly. This option is off by default.
* .LP
*
* RETURNS:
* MSG_Q_ID, or NULL if error.
*
* ERRNO: S_memLib_NOT_ENOUGH_MEMORY, S_intLib_NOT_ISR_CALLABLE
*
* SEE ALSO: msgQSmLib
*/

MSG_Q_ID msgQCreate
    (
    int         maxMsgs,        /* max messages that can be queued */
    int         maxMsgLength,   /* max bytes in a message */
    int         options         /* message queue options */
    )
    {
    MSG_Q_ID	msgQId;
    void *	pPool;		/* pointer to memory for messages */
    UINT	size = (UINT) maxMsgs * MSG_NODE_SIZE (maxMsgLength);

    if (INT_RESTRICT () != OK)		/* restrict ISR from calling */
	return (NULL);

    if ((!msgQLibInstalled) && (msgQLibInit () != OK))
	return (NULL);			/* package init problem */

    if ((msgQId = (MSG_Q_ID)objAllocExtra (msgQClassId, size, &pPool)) == NULL)
	return (NULL);

    if (msgQInit (msgQId, maxMsgs, maxMsgLength, options, pPool) != OK)
	{
	objFree (msgQClassId, (char *) msgQId);
	return (NULL);
	}

#ifdef WV_INSTRUMENTATION
    /* windview - level 1 event logging routine */
    EVT_OBJ_4 (OBJ, msgQId, msgQClassId, EVENT_MSGQCREATE, 
		msgQId, maxMsgs, maxMsgLength, options);
#endif

    return ((MSG_Q_ID) msgQId);
    }

/*******************************************************************************
*
* msgQInit - initialize a message queue
*
* This routine initializes a message queue data structure.  Like msgQCreate()
* the resulting message queue is capable of holding up to <maxMsgs> messages,
* each of up to <maxMsgLength> bytes long.
* However, instead of dynamically allocating the MSG_Q data structure,
* this routine takes a pointer <pMsgQ> to the MSG_Q data structure to be
* initialized, and a pointer <pMsgPool> to the buffer to be use to hold
* queued messages.  <pMsgPool> must point to a 4 byte aligned buffer
* that is (<maxMsgs> * MSG_NODE_SIZE (<maxMsgLength>)).
*
* The queue can be created with the following options:
*
*	MSG_Q_FIFO	queue pended tasks in FIFO order
*	MSG_Q_PRIORITY	queue pended tasks in priority order
*
* RETURNS: OK or ERROR.
*
* ERRNO: S_msgQLib_INVALID_QUEUE_TYPE
*
* SEE ALSO: msgQCreate()
*
* NOMANUAL
*/

STATUS msgQInit
    (
    FAST MSG_Q *pMsgQ,          /* pointer to msg queue to initialize */
    int         maxMsgs,        /* max messages that can be queued */
    int         maxMsgLength,   /* max bytes in a message */
    int         options,        /* message queue options */
    void *      pMsgPool        /* pointer to memory for messages */
    )
    {
    FAST int		nodeSize = MSG_NODE_SIZE (maxMsgLength);
    FAST int		ix;
    FAST Q_CLASS_ID	msgQType;

    if ((!msgQLibInstalled) && (msgQLibInit () != OK))
	return (ERROR);				/* package init problem */

    bzero ((char *) pMsgQ, sizeof (*pMsgQ));	/* clear out msg q structure */

    /* initialize internal job queues */

    switch (options & MSG_Q_TYPE_MASK)
        {
        case MSG_Q_FIFO:	msgQType = Q_FIFO;	break;
        case MSG_Q_PRIORITY:	msgQType = Q_PRI_LIST;	break;

        default:
            errnoSet (S_msgQLib_INVALID_QUEUE_TYPE);
	    return (ERROR);
        }

    if ((qInit ((Q_HEAD *) &pMsgQ->msgQ, qJobClassId, msgQType,
	 0, 0, 0, 0, 0, 0, 0, 0, 0) != OK) ||
	(qInit ((Q_HEAD *) &pMsgQ->freeQ, qJobClassId, msgQType,
	 0, 0, 0, 0, 0, 0, 0, 0, 0) != OK))
	return (ERROR);


    /* put msg nodes on free list */

    for (ix = 0; ix < maxMsgs; ix++)
	{
	qJobPut (pMsgQ, &pMsgQ->freeQ, (Q_JOB_NODE *) pMsgPool,
		 Q_JOB_PRI_DONT_CARE);
	pMsgPool = (void *) (((char *) pMsgPool) + nodeSize);
	}


    /* initialize rest of msg q */

    pMsgQ->options	= options;
    pMsgQ->maxMsgs	= maxMsgs;
    pMsgQ->maxMsgLength	= maxMsgLength;

    eventInit (&pMsgQ->events);

#ifdef WV_INSTRUMENTATION
    if (wvObjIsEnabled)
    {
    /* windview - connect level 1 event logging routine */
    objCoreInit (&pMsgQ->objCore, msgQInstClassId);
    }
    else
#endif
    objCoreInit (&pMsgQ->objCore, msgQClassId);

    return (OK);
    }

/******************************************************************************
*
* msgQTerminate - terminate message queue
*
* This routine terminates a static message queue that was initialized with
* msgQInit.
*
* RETURNS: OK or ERROR.
*
* NOMANUAL
*/

STATUS msgQTerminate
    (
    MSG_Q_ID msgQId     /* message queue id to terminate */
    )
    {
    return (msgQDestroy (msgQId, FALSE));
    }

/*******************************************************************************
*
* msgQDelete - delete a message queue
*
* This routine deletes a message queue.  All tasks pending on either
* msgQSend(), msgQReceive() or pending for the reception of events
* meant to be sent from the message queue will unblock and return
* ERROR.  When this function returns, <msgQId> is no longer a valid 
* message queue ID.
*
* RETURNS: OK on success or ERROR otherwise.
*
* ERRNO:
* .iP "S_objLib_OBJ_ID_ERROR"
* Message queue ID is invalid
* .iP "S_intLib_NOT_ISR_CALLABLE"
* Routine cannot be called from ISR
* .iP "S_distLib_NO_OBJECT_DESTROY"
* Deleting a distributed message queue is not permitted
* .iP "S_smObjLib_NO_OBJECT_DESTROY"
* Deleting a shared message queue is not permitted
* SEE ALSO: msgQSmLib
*/

STATUS msgQDelete
    (
    MSG_Q_ID msgQId     /* message queue to delete */
    )
    {
    return (msgQDestroy (msgQId, TRUE));
    }

/*******************************************************************************
*
* msgQDestroy - destroy message queue
*
* RETURNS: OK or ERROR.
*
* ERRNO: S_distLib_NO_OBJECT_DESTROY
*
*/

LOCAL STATUS msgQDestroy
    (
    MSG_Q_ID msgQId,    /* message queue to destroy */
    BOOL     dealloc    /* deallocate memory associated with message queue */
    )
    {
    Q_JOB_NODE *pNode;
    FAST int	timeout;
    FAST int	nMsgs;

    int errnoCopy;

    if (ID_IS_SHARED (msgQId))  		/* message Q is shared?*/
	{
		if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
			{
			errno = S_distLib_NO_OBJECT_DESTROY;
		 	return (ERROR);             /* cannot delete distributed msgQ */
			}
	
		errno = S_smObjLib_NO_OBJECT_DESTROY;
        return (ERROR);				/* cannot delete sm. msgQ */
	}

    if (INT_RESTRICT () != OK)			/* restrict isr use */
	return (ERROR);

    TASK_SAFE ();				/* TASK SAFE */
    TASK_LOCK ();				/* LOCK PREEMPTION */

#ifdef WV_INSTRUMENTATION

    /* Indicate that msgQDelete has been initiated */

    /* windview - level 1 event logging routine */
    EVT_OBJ_1 (OBJ, msgQId, msgQClassId, EVENT_MSGQDELETE, msgQId);
#endif

    if (OBJ_VERIFY (msgQId, msgQClassId) != OK)	/* validate message queue id */
	{
	TASK_UNLOCK ();				/* UNLOCK PREEMPTION */
	TASK_UNSAFE ();				/* TASK UNSAFE */
	return (ERROR);
	}

    objCoreTerminate (&msgQId->objCore);	/* INVALIDATE */

#ifdef WV_INSTRUMENTATION

    /*  Indicate that the msgQDelete has succeeded (before TASK_UNLOCK, as
     *  that causes unnecessary WV parser confusion).
     */

    /* windview - level 2 instrumentation
     * EVENT_OBJ_MSGDELETE needs to return the msgQId so MSG_OFFSET is
     * used to calulate the msgQId from the pQHead
     */
    EVT_TASK_1 (EVENT_OBJ_MSGDELETE, msgQId);
#endif

    TASK_UNLOCK ();				/* UNLOCK PREEMPTION */


    /* gobble up all messages in the message and free queues */

    timeout = NO_WAIT;		/* first time through gobble without waiting */
    nMsgs = 0;

    errnoCopy = errnoGet ();

    while (nMsgs < msgQId->maxMsgs)
	{
	while (((pNode = qJobGet (msgQId, &msgQId->freeQ, timeout)) != NULL) &&
	       (pNode != (Q_JOB_NODE *) NONE))
	    nMsgs++;

	while (((pNode = qJobGet (msgQId, &msgQId->msgQ, timeout)) != NULL) &&
	       (pNode != (Q_JOB_NODE *) NONE))
	    nMsgs++;

	timeout = 1;		/* after first time, wait a bit */
	}

    errnoSet (errnoCopy);

    /* terminate both the queues */

    /*
     * Since eventTerminate() can wake up a task, we want to put all tasks
     * in the ready queue before doing a windExit(), so that it is sure that
     * the task of highest priority runs first. To achieve that, the
     * statements 'kernelState = TRUE;' and 'windExit();' have been moved
     * from qJobTerminate() to here. This is the only place that qJobTerminate
     * is called.
     */

    kernelState = TRUE;

    qJobTerminate (&msgQId->msgQ);
    qJobTerminate (&msgQId->freeQ);

    eventTerminate (&msgQId->events);/* free task waiting for events if any */

    windExit ();

    if (dealloc)
	objFree (msgQClassId, (char *) msgQId);

    TASK_UNSAFE ();				/* TASK UNSAFE */

    return (OK);
    }

/*******************************************************************************
*
* msgQSend - send a message to a message queue
*
* This routine sends the message in <buffer> of length <nBytes> to the message
* queue <msgQId>.  If any tasks are already waiting to receive messages
* on the queue, the message will immediately be delivered to the first
* waiting task.  If no task is waiting to receive messages, the message
* is saved in the message queue and if a task has previously registered to 
* receive events from the message queue, these events are sent in the context 
* of this call.  This may result in the unpending of the task waiting for 
* the events.  If the message queue fails to send events and if it was 
* created using the MSG_Q_EVENTSEND_ERR_NOTIFY option, ERROR is returned 
* even though the send operation was successful.
*
* The <timeout> parameter specifies the number of ticks to wait for free
* space if the message queue is full.  The <timeout> parameter can also have 
* the following special values:
* .iP "NO_WAIT  (0)" 8
* return immediately, even if the message has not been sent.  
* .iP "WAIT_FOREVER  (-1)"
* never time out.
* .LP
*
* The <priority> parameter specifies the priority of the message being sent.
* The possible values are:
* .iP "MSG_PRI_NORMAL  (0)" 8
* normal priority; add the message to the tail of the list of queued 
* messages.
* .iP "MSG_PRI_URGENT  (1)"
* urgent priority; add the message to the head of the list of queued messages.
* .LP
*
* USE BY INTERRUPT SERVICE ROUTINES
* This routine can be called by interrupt service routines as well as
* by tasks.  This is one of the primary means of communication
* between an interrupt service routine and a task.  When called from an
* interrupt service routine, <timeout> must be NO_WAIT.
*
* RETURNS: OK on success or ERROR otherwise.
*
* ERRNO:
* .iP "S_distLib_NOT_INITIALIZED"
* Distributed objects message queue library (VxFusion) not initialized.
* .iP "S_smObjLib_NOT_INITIALIZED"
* Shared memory message queue library (VxMP Option) not initialized.
* .iP "S_objLib_OBJ_ID_ERROR"
* Invalid message queue ID.
* .iP "S_objLib_OBJ_DELETED"
* Message queue deleted while calling task was pended.
* .iP "S_objLib_OBJ_UNAVAILABLE"
* No free buffer space when NO_WAIT timeout specified.
* .iP "S_objLib_OBJ_TIMEOUT"
* Timeout occurred while waiting for buffer space.
* .iP "S_msgQLib_INVALID_MSG_LENGTH"
* Message length exceeds limit.
* .iP "S_msgQLib_NON_ZERO_TIMEOUT_AT_INT_LEVEL"
* Called from ISR with non-zero timeout.
* .iP "S_eventLib_EVENTSEND_FAILED"
* Message queue failed to send events to registered task.  This errno 
* value can only exist if the message queue was created with the 
* MSG_Q_EVENTSEND_ERR_NOTIFY option.
* .LP
*
* SEE ALSO: msgQSmLib, msgQEvStart
*/

STATUS msgQSend
    (
    FAST MSG_Q_ID       msgQId,         /* message queue on which to send */
    char *              buffer,         /* message to send */
    FAST UINT           nBytes,         /* length of message */
    int                 timeout,        /* ticks to wait */
    int                 priority        /* MSG_PRI_NORMAL or MSG_PRI_URGENT */
    )
    {
    FAST MSG_NODE *	pMsg;

    if (ID_IS_SHARED (msgQId))			/* message Q is shared? */
        {
		if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
			{
			if (msgQDistSendRtn == NULL)
				{
				errno = S_distLib_NOT_INITIALIZED; 
				return (ERROR);
				}
		 	return ((*msgQDistSendRtn) (msgQId, buffer, nBytes,
			 	timeout, WAIT_FOREVER, priority));
			}

        if (msgQSmSendRtn == NULL)
            {
            errno = S_smObjLib_NOT_INITIALIZED;
            return (ERROR);
            }

        return ((*msgQSmSendRtn) (SM_OBJ_ID_TO_ADRS (msgQId), buffer, nBytes,
				  timeout, priority));
	}

    /* message queue is local */

    if (!INT_CONTEXT ())
	TASK_LOCK ();
    else
	{
	if (timeout != 0)
	    {
	    errnoSet (S_msgQLib_NON_ZERO_TIMEOUT_AT_INT_LEVEL);
	    return (ERROR);
	    }
	}

restart:
    if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
	{
	if (!INT_CONTEXT ())
	    TASK_UNLOCK ();
	return (ERROR);
	}

#ifdef WV_INSTRUMENTATION
    /* windview - level 1 event logging routine */
    EVT_OBJ_5 (OBJ, msgQId, msgQClassId, EVENT_MSGQSEND, msgQId, 
	       buffer, nBytes, timeout, priority);
#endif

    if (nBytes > msgQId->maxMsgLength)
	{
	if (!INT_CONTEXT ())
	    TASK_UNLOCK ();
	errnoSet (S_msgQLib_INVALID_MSG_LENGTH);
	return (ERROR);
	}

    pMsg = (MSG_NODE *) qJobGet (msgQId, &msgQId->freeQ, timeout);

    if (pMsg == (MSG_NODE *) NONE)
	{
	timeout = SIG_TIMEOUT_RECALC(timeout);
	goto restart;
	}

    if (pMsg == NULL)
	{
#if FALSE
	msgQId->sendTimeouts++;
#else

	/*
	 * The timeout stat should only be updated if a timeout has occured.
	 * An OBJ_VERIFY needs to be performed to catch the case where a 
	 * timeout indeed occured, but the message queue is subsequently 
	 * deleted before the current task is rescheduled.
	 */

	if (errnoGet() == S_objLib_OBJ_TIMEOUT) 
            {
	    if (OBJ_VERIFY (msgQId, msgQClassId) == OK)
	        msgQId->sendTimeouts++;
            else
                errnoSet(S_objLib_OBJ_DELETED);
            }

#endif /* FALSE */

	if (!INT_CONTEXT ())
	    TASK_UNLOCK ();
	return (ERROR);
	}

    pMsg->msgLength = nBytes;
    bcopy (buffer, MSG_NODE_DATA (pMsg), (int) nBytes);

    if (qJobPut (msgQId, &msgQId->msgQ, &pMsg->node, priority) != OK)
	{
	if (!INT_CONTEXT ())
	    TASK_UNLOCK ();

	return (ERROR); /* errno set by qJobPut() */
	}

    if (!INT_CONTEXT ())
	TASK_UNLOCK ();

    return (OK);
    }

/*******************************************************************************
*
* msgQReceive - receive a message from a message queue
*
* This routine receives a message from the message queue <msgQId>.
* The received message is copied into the specified <buffer>, which is
* <maxNBytes> in length.  If the message is longer than <maxNBytes>,
* the remainder of the message is discarded (no error indication
* is returned).
*
* The <timeout> parameter specifies the number of ticks to wait for 
* a message to be sent to the queue, if no message is available when
* msgQReceive() is called.  The <timeout> parameter can also have 
* the following special values: 
* .iP "NO_WAIT  (0)" 8
* return immediately, whether a message has been received or not.  
* .iP "WAIT_FOREVER  (-1)"
* never time out.
* .LP
*
* WARNING: This routine must not be called by interrupt service routines.
*
* RETURNS:
* The number of bytes copied to <buffer>, or ERROR.
*
* ERRNO: S_distLib_NOT_INITIALIZED, S_smObjLib_NOT_INITIALIZED,
*        S_objLib_OBJ_ID_ERROR, S_objLib_OBJ_DELETED,
*        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_TIMEOUT,
*        S_msgQLib_INVALID_MSG_LENGTH, S_intLib_NOT_ISR_CALLABLE
*
* SEE ALSO: msgQSmLib
*/

int msgQReceive
    (
    FAST MSG_Q_ID       msgQId,         /* message queue from which to receive */
    char *              buffer,         /* buffer to receive message */
    UINT                maxNBytes,      /* length of buffer */
    int                 timeout         /* ticks to wait */
    )
    {
    FAST MSG_NODE *	pMsg;
    FAST int		bytesReturned;

    if (INT_RESTRICT() != OK) /* errno set by INT_RESTRICT() */
	return ERROR;

    if (ID_IS_SHARED (msgQId))			/* message Q is shared? */
        {
		if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
			{
			if (msgQDistReceiveRtn == NULL)
				{
				errno = S_distLib_NOT_INITIALIZED;
			 	return (ERROR);
				}
			return ((*msgQDistReceiveRtn) (msgQId, buffer,
				maxNBytes, timeout, WAIT_FOREVER));
			}

        if (msgQSmReceiveRtn == NULL)
            {
            errno = S_smObjLib_NOT_INITIALIZED;
            return (ERROR);
            }

        return ((*msgQSmReceiveRtn) (SM_OBJ_ID_TO_ADRS (msgQId), buffer,
				     maxNBytes, timeout));
	}

    /* message queue is local */

    /* even though maxNBytes is unsigned, check for < 0 to catch possible
     * caller errors
     */
    if ((int) maxNBytes < 0)
	{
	errnoSet (S_msgQLib_INVALID_MSG_LENGTH);
	return (ERROR);
	}

    TASK_LOCK ();

restart:
    if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
	{
	TASK_UNLOCK ();
	return (ERROR);
	}

#ifdef WV_INSTRUMENTATION
    /* windview - level 1 event logging routine */
    EVT_OBJ_4 (OBJ, msgQId, msgQClassId, EVENT_MSGQRECEIVE, msgQId, 
	       buffer, maxNBytes, timeout);
#endif

    pMsg = (MSG_NODE *) qJobGet (msgQId, &msgQId->msgQ, timeout);

    if (pMsg == (MSG_NODE *) NONE)
	{
	timeout = SIG_TIMEOUT_RECALC(timeout);
	goto restart;
	}

    if (pMsg == NULL)
	{
#if FALSE
	msgQId->recvTimeouts++;
#else
	/*
	 * The timeout stat should only be updated if a timeout has occured.
	 * An OBJ_VERIFY needs to be performed to catch the case where a 
	 * timeout indeed occured, but the message queue is subsequently 
	 * deleted before the current task is rescheduled.
	 */

	if (errnoGet() == S_objLib_OBJ_TIMEOUT) 
            {
	    if (OBJ_VERIFY (msgQId, msgQClassId) == OK)
	        msgQId->sendTimeouts++;
            else
                errnoSet(S_objLib_OBJ_DELETED);
            }

#endif /* FALSE */

	TASK_UNLOCK ();
	return (ERROR);
	}

    bytesReturned = min (pMsg->msgLength, maxNBytes);
    bcopy (MSG_NODE_DATA (pMsg), buffer, bytesReturned);

    qJobPut (msgQId, &msgQId->freeQ, &pMsg->node, Q_JOB_PRI_DONT_CARE);

    TASK_UNLOCK ();

    return (bytesReturned);
    }

/*******************************************************************************
*
* msgQNumMsgs - get the number of messages queued to a message queue
*
* This routine returns the number of messages currently queued to a specified
* message queue.
*
* RETURNS:
* The number of messages queued, or ERROR.
*
* ERRNO:  S_distLib_NOT_INITIALIZED, S_smObjLib_NOT_INITIALIZED,
*         S_objLib_OBJ_ID_ERROR
*
* SEE ALSO: msgQSmLib
*/

int msgQNumMsgs
    (
    FAST MSG_Q_ID       msgQId          /* message queue to examine */
    )
    {
    if (ID_IS_SHARED (msgQId))			/* message Q is shared? */
        {
		if (ID_IS_DISTRIBUTED (msgQId)) /* message queue is distributed? */
			{
			if (msgQDistNumMsgsRtn == NULL)
				{
				errno = S_distLib_NOT_INITIALIZED;
				return (ERROR);
				}
			return ((*msgQDistNumMsgsRtn) (msgQId, WAIT_FOREVER));
			}

        if (msgQSmNumMsgsRtn == NULL)
            {
            errno = S_smObjLib_NOT_INITIALIZED;
            return (ERROR);
            }

        return ((*msgQSmNumMsgsRtn) (SM_OBJ_ID_TO_ADRS (msgQId)));
	}

    /* message queue is local */

    if (OBJ_VERIFY (msgQId, msgQClassId) != OK)
	return (ERROR);

    return (msgQId->msgQ.count);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ai_Sj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值