mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-16 10:50:49 -08:00
message.c: rename MessageClocked() as MessageIsClocked() check.h: better name in future improvement comments Copied from Perforce Change: 166801 ServerID: perforce.ravenbrook.com
467 lines
11 KiB
C
467 lines
11 KiB
C
/* message.c: MPS/CLIENT MESSAGES
|
|
*
|
|
* $Id$
|
|
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
|
*
|
|
* DESIGN
|
|
*
|
|
* .design: See <design/message/> (it really exists).
|
|
*
|
|
* PURPOSE
|
|
*
|
|
* .purpose: Provide the generic part of the MPS / Client message
|
|
* interface. Messages are instances of Message Classes; much of the
|
|
* "real work" goes on in the modules that provide the actual messages.
|
|
*/
|
|
|
|
#include "bt.h"
|
|
#include "mpm.h"
|
|
|
|
SRCID(message, "$Id$");
|
|
|
|
|
|
/* Maps from a Ring pointer to the message */
|
|
#define MessageNodeMessage(node) \
|
|
PARENT(MessageStruct, queueRing, node)
|
|
|
|
|
|
/* forward declarations */
|
|
static Bool MessageTypeEnabled(Arena arena, MessageType type);
|
|
static void MessageDelete(Message message);
|
|
|
|
|
|
/* Internal (MPM) Interface -- functions for message originator
|
|
*
|
|
*/
|
|
|
|
|
|
Bool MessageTypeCheck(MessageType type)
|
|
{
|
|
CHECKL(type < MessageTypeLIMIT);
|
|
UNUSED(type); /* <code/mpm.c#check.unused> */
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* See .message.clocked. Currently finalization messages are the */
|
|
/* only ones that can be numerous. */
|
|
#define MessageIsClocked(message) ((message)->class->type \
|
|
!= MessageTypeFINALIZATION)
|
|
|
|
Bool MessageCheck(Message message)
|
|
{
|
|
CHECKS(Message, message);
|
|
CHECKU(Arena, message->arena);
|
|
CHECKD(MessageClass, message->class);
|
|
CHECKL(RingCheck(&message->queueRing));
|
|
/* postedClock is uncheckable for clocked message types, */
|
|
/* but must be 0 for unclocked message types: */
|
|
CHECKL(MessageIsClocked(message) || (message->postedClock == 0));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool MessageClassCheck(MessageClass class)
|
|
{
|
|
CHECKS(MessageClass, class);
|
|
CHECKL(class->name != NULL);
|
|
CHECKL(MessageTypeCheck(class->type));
|
|
CHECKL(FUNCHECK(class->delete));
|
|
CHECKL(FUNCHECK(class->finalizationRef));
|
|
CHECKL(FUNCHECK(class->gcLiveSize));
|
|
CHECKL(FUNCHECK(class->gcCondemnedSize));
|
|
CHECKL(FUNCHECK(class->gcNotCondemnedSize));
|
|
CHECKL(FUNCHECK(class->gcStartWhy));
|
|
CHECKL(class->endSig == MessageClassSig);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void MessageInit(Arena arena, Message message, MessageClass class,
|
|
MessageType type)
|
|
{
|
|
AVERT(Arena, arena);
|
|
AVER(message != NULL);
|
|
AVERT(MessageClass, class);
|
|
AVERT(MessageType, type);
|
|
|
|
message->arena = arena;
|
|
message->class = class;
|
|
RingInit(&message->queueRing);
|
|
message->postedClock = 0;
|
|
message->sig = MessageSig;
|
|
|
|
AVERT(Message, message);
|
|
AVER(MessageGetType(message) == type);
|
|
}
|
|
|
|
void MessageFinish(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
AVER(RingIsSingle(&message->queueRing));
|
|
|
|
message->sig = SigInvalid;
|
|
RingFinish(&message->queueRing);
|
|
}
|
|
|
|
Arena MessageArena(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
|
|
return message->arena;
|
|
}
|
|
|
|
Bool MessageOnQueue(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
|
|
/* message is on queue if and only if its ring is not a singleton. */
|
|
return !RingIsSingle(&message->queueRing);
|
|
}
|
|
|
|
/* Post a message to the arena's queue of pending messages */
|
|
void MessagePost(Arena arena, Message message)
|
|
{
|
|
AVERT(Arena, arena);
|
|
AVERT(Message, message);
|
|
|
|
/* queueRing field must be a singleton, see */
|
|
/* <design/message/#fun.post.singleton> */
|
|
AVER(!MessageOnQueue(message));
|
|
if(MessageTypeEnabled(arena, MessageGetType(message))) {
|
|
/* .message.clocked: Reading the clock with ClockNow() */
|
|
/* involves an mpslib call, so we avoid it for message */
|
|
/* types that may be numerous. */
|
|
if(MessageIsClocked(message)) {
|
|
message->postedClock = ClockNow();
|
|
}
|
|
RingAppend(&arena->messageRing, &message->queueRing);
|
|
} else {
|
|
/* discard message immediately if client hasn't enabled that type */
|
|
MessageDiscard(arena, message);
|
|
}
|
|
}
|
|
|
|
/* Return the message at the head of the arena's queue */
|
|
static Message MessageHead(Arena arena)
|
|
{
|
|
AVERT(Arena, arena);
|
|
AVER(!RingIsSingle(&arena->messageRing));
|
|
|
|
return MessageNodeMessage(RingNext(&arena->messageRing));
|
|
}
|
|
|
|
/* Delete the message at the head of the queue (helper function). */
|
|
static void MessageDeleteHead(Arena arena)
|
|
{
|
|
Message message;
|
|
|
|
AVERT(Arena, arena);
|
|
AVER(!RingIsSingle(&arena->messageRing));
|
|
|
|
message = MessageHead(arena);
|
|
AVERT(Message, message);
|
|
RingRemove(&message->queueRing);
|
|
MessageDelete(message);
|
|
}
|
|
|
|
/* Empty the queue by discarding all messages */
|
|
void MessageEmpty(Arena arena)
|
|
{
|
|
AVERT(Arena, arena);
|
|
|
|
while(!RingIsSingle(&arena->messageRing)) {
|
|
MessageDeleteHead(arena);
|
|
}
|
|
}
|
|
|
|
|
|
/* Delivery (Client) Interface -- functions for recipient
|
|
*
|
|
* Most of these functions are exposed through the external MPS
|
|
* interface.
|
|
*/
|
|
|
|
|
|
static Bool MessageTypeEnabled(Arena arena, MessageType type)
|
|
{
|
|
AVERT(Arena, arena);
|
|
AVER(MessageTypeCheck(type));
|
|
|
|
return BTGet(arena->enabledMessageTypes, type);
|
|
}
|
|
|
|
void MessageTypeEnable(Arena arena, MessageType type)
|
|
{
|
|
AVERT(Arena, arena);
|
|
AVER(MessageTypeCheck(type));
|
|
|
|
BTSet(arena->enabledMessageTypes, type);
|
|
}
|
|
|
|
void MessageTypeDisable(Arena arena, MessageType type)
|
|
{
|
|
Message message;
|
|
|
|
AVERT(Arena, arena);
|
|
AVER(MessageTypeCheck(type));
|
|
|
|
/* Flush existing messages of this type */
|
|
while(MessageGet(&message, arena, type)) {
|
|
MessageDelete(message);
|
|
}
|
|
|
|
BTRes(arena->enabledMessageTypes, type);
|
|
}
|
|
|
|
/* Any messages on the queue? */
|
|
Bool MessagePoll(Arena arena)
|
|
{
|
|
AVERT(Arena, arena);
|
|
|
|
if(RingIsSingle(&arena->messageRing)) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Return the type of the message at the head of the queue, if any */
|
|
Bool MessageQueueType(MessageType *typeReturn, Arena arena)
|
|
{
|
|
Message message;
|
|
MessageType type;
|
|
|
|
AVER(typeReturn != NULL);
|
|
AVERT(Arena, arena);
|
|
|
|
if(!MessagePoll(arena)) {
|
|
return FALSE;
|
|
}
|
|
message = MessageHead(arena);
|
|
type = MessageGetType(message);
|
|
*typeReturn = type;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Get next message of specified type, removing it from the queue */
|
|
Bool MessageGet(Message *messageReturn, Arena arena, MessageType type)
|
|
{
|
|
Ring node, next;
|
|
|
|
AVER(messageReturn != NULL);
|
|
AVERT(Arena, arena);
|
|
AVER(MessageTypeCheck(type));
|
|
|
|
RING_FOR(node, &arena->messageRing, next) {
|
|
Message message = RING_ELT(Message, queueRing, node);
|
|
if(MessageGetType(message) == type) {
|
|
RingRemove(&message->queueRing);
|
|
*messageReturn = message;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* Discard a message (recipient has finished using it). */
|
|
void MessageDiscard(Arena arena, Message message)
|
|
{
|
|
AVERT(Arena, arena);
|
|
AVERT(Message, message);
|
|
|
|
AVER(!MessageOnQueue(message));
|
|
|
|
MessageDelete(message);
|
|
}
|
|
|
|
|
|
/* Message Methods, Generic
|
|
*
|
|
* (Some of these dispatch on message->class).
|
|
*/
|
|
|
|
|
|
/* Return the type of a message */
|
|
MessageType MessageGetType(Message message)
|
|
{
|
|
MessageClass class;
|
|
AVERT(Message, message);
|
|
|
|
class = message->class;
|
|
AVERT(MessageClass, class);
|
|
|
|
return class->type;
|
|
}
|
|
|
|
/* Return the class of a message */
|
|
MessageClass MessageGetClass(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
|
|
return message->class;
|
|
}
|
|
|
|
Clock MessageGetClock(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
|
|
return message->postedClock;
|
|
}
|
|
|
|
static void MessageDelete(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
|
|
(*message->class->delete)(message);
|
|
}
|
|
|
|
|
|
/* Message Method Dispatchers, Type-specific
|
|
*
|
|
*/
|
|
|
|
|
|
void MessageFinalizationRef(Ref *refReturn, Arena arena,
|
|
Message message)
|
|
{
|
|
AVER(refReturn != NULL);
|
|
AVERT(Arena, arena);
|
|
AVERT(Message, message);
|
|
AVER(MessageGetType(message) == MessageTypeFINALIZATION);
|
|
|
|
(*message->class->finalizationRef)(refReturn, arena, message);
|
|
|
|
return;
|
|
}
|
|
|
|
Size MessageGCLiveSize(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
AVER(MessageGetType(message) == MessageTypeGC);
|
|
|
|
return (*message->class->gcLiveSize)(message);
|
|
}
|
|
|
|
Size MessageGCCondemnedSize(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
AVER(MessageGetType(message) == MessageTypeGC);
|
|
|
|
return (*message->class->gcCondemnedSize)(message);
|
|
}
|
|
|
|
Size MessageGCNotCondemnedSize(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
AVER(MessageGetType(message) == MessageTypeGC);
|
|
|
|
return (*message->class->gcNotCondemnedSize)(message);
|
|
}
|
|
|
|
const char *MessageGCStartWhy(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
AVER(MessageGetType(message) == MessageTypeGCSTART);
|
|
|
|
return (*message->class->gcStartWhy)(message);
|
|
}
|
|
|
|
|
|
/* Message Method Stubs, Type-specific
|
|
*
|
|
*/
|
|
|
|
|
|
void MessageNoFinalizationRef(Ref *refReturn, Arena arena,
|
|
Message message)
|
|
{
|
|
AVER(refReturn != NULL);
|
|
AVERT(Arena, arena);
|
|
AVERT(Message, message);
|
|
|
|
NOTREACHED;
|
|
}
|
|
|
|
Size MessageNoGCLiveSize(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
UNUSED(message);
|
|
|
|
NOTREACHED;
|
|
|
|
return (Size)0;
|
|
}
|
|
|
|
Size MessageNoGCCondemnedSize(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
UNUSED(message);
|
|
|
|
NOTREACHED;
|
|
|
|
return (Size)0;
|
|
}
|
|
|
|
Size MessageNoGCNotCondemnedSize(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
UNUSED(message);
|
|
|
|
NOTREACHED;
|
|
|
|
return (Size)0;
|
|
}
|
|
|
|
const char *MessageNoGCStartWhy(Message message)
|
|
{
|
|
AVERT(Message, message);
|
|
UNUSED(message);
|
|
|
|
NOTREACHED;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* C. COPYRIGHT AND LICENSE
|
|
*
|
|
* Copyright (C) 2001-2002, 2008 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
|
* All rights reserved. This is an open source license. Contact
|
|
* Ravenbrook for commercial licensing options.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Redistributions in any form must be accompanied by information on how
|
|
* to obtain complete source code for this software and any accompanying
|
|
* software that uses this software. The source code must either be
|
|
* included in the distribution or be available for no more than the cost
|
|
* of distribution plus a nominal fee, and must be freely redistributable
|
|
* under reasonable conditions. For an executable file, complete source
|
|
* code means the source code for all modules it contains. It does not
|
|
* include source code for modules or files that typically accompany the
|
|
* major components of the operating system on which the executable file
|
|
* runs.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|