1994 1995 1996 1997 <1998> 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 | Index | 1994 1995 1996 1997 <1998> 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 |
<== Date ==> | <== Thread ==> |
---|
Subject: | MPF - Message Passing Facility: A replacemnt for "Bare" Hideos |
From: | Marty Kraimer <[email protected]> |
To: | [email protected] |
Date: | Tue, 19 May 1998 11:31:40 -0500 |
I few months ago I sent a message proposing a replacement for "bare" Hideos that is built on top of vxWorks. Attached is an html document describing the current status. I have also made this document available via the APS WWW Epics documents. I am hoping to convert some of the APS/ASD systems to the new facility during a scheduled shutdown this coming July. Marty Kraimer
The most important goal is to provide a migration path for existing
HIDEOS applications. An EPICS Hideos application uses the following
hideos components:
Messages are sent through a router. Initially two routers will be provided: localRouter and tcpRouter. The localRouter passes messages between a clients and servers residing on the same processor. The tcpRouter sends messages between clients and servers on different processors.
typedef void (*clientCallback)(Message *message,void *clientPvt); class MessageClient { public: MessageClient(clientCallback,void *clientPvt); int bind(char *server, int location); int send(Message *message); private: ... }Any code that wants to use the message passing system must:
class MessageServer { public: MessageServer(const char* name); void waitForMessage(); Message *receive(); Message *allocReplyMessage(Message *clientMessage,messageType type); void queueMessage(Message *); int reply(Message *); private: ... }Ant code that wants to be a message server must
class Message { public: messageType getType(); virtual ~Message(); virtual void init() = 0; virtual int toBuffer(char **buffer); virtual int fromBuffer(const char **buffer); virtual int fromBufferSwitch(const char **buffer); virtual void print() const; static Message *allocate(messageType type); protected: Message(messageType type); .... }Client and server code normally only call new, delete, getType, and message specific methods. The other methods are called by MPF itself. A message is allocated via a call to new and released via a call to delete. When delete is called the message is placed on a free list rather than actually being deleted.
Most methods are virtual and must be implement by any class that derives from Message. The init method is called whenever a messages in allocated. The toBuffer and fromBuffer methods are called to put and take messages from a buffer that passes over a communication link.
typedef struct privateData { connectStatus connectState; int32 value; SEM_ID sem; }privateData; void myCallback(Message *message,void *clientPvt) { privateData *pprivateData = (privateData *)clientPvt; switch(message->getType()) { case messageTypeConnect: { ConnectMessage *pConnectMessage = (ConnectMessage *)message; pprivateData->connectState = pConnectMessage->status; delete pConnectMessage; semGive(pprivateData->sem); } break; case messageTypeInt32: { Int32Message *pInt32Message = (Int32Message *)message; pprivateData->value = pInt32Message->value; delete pInt32Message; semGive(pprivateData->sem); } break; default: printf("got illegal response message\n"); break; } } int clientExample(char *server,int location,int ntimes) { MessageClient *pMessageClient; privateData *pprivateData = new privateData; int status; Message *message; pprivateData->connectState = connectNo; pprivateData->value = -1; pMessageClient = new MessageClient(myCallback,pprivateData); pprivateData->sem = semBCreate(SEM_Q_PRIORITY,SEM_EMPTY); status = pMessageClient->bind(server,location); if(status) { printf("bind returned %d\n",status); return(status); } //wait for connect semTake(pprivateData->sem,WAIT_FOREVER); for(int i=0; i<ntimes; i++) { while(pprivateData->connectState!=connectYes) { printf("client connectState %d\n",pprivateData->connectState); taskDelay(60); } message = new Int32Message; status = pMessageClient->send(message); if(status) { printf("send returned %d\n",status); continue; } semTake(pprivateData->sem,WAIT_FOREVER); printf("new value is %ld message %p\n",pprivateData->value,message); } return(0); }
struct privateData { int32 counter; }; int serverExample(char *name) { privateData *pprivateData = new privateData; Message *message; Int32Message *pInt32Message; MessageServer *pMessageServer; pMessageServer = new MessageServer(name); pprivateData->counter = 0; while(TRUE) { pMessageServer->waitForMessage(); message = pMessageServer->receive(); if(message->getType()!=messageTypeInt32) { printf("serverExample got illegal message type\n"); } else { pInt32Message = (Int32Message *)message; pInt32Message->value = pprivateData->counter++; pMessageServer->reply(pInt32Message); } } return(0); }
routerInitIf local communication is desired then the following command must appear:
localMessageRouterStart(0)The parameter is the location of the local server. The above example sets the location to 0. Note that the client specifies a location when it binds to a server.
If tcp communication is desired then for each remote system the client must have the following command:
tcpMessageRouterClientStart(location,port,"address")
tcpMessageRouterServerStart(location,port,"address")
MPF provides a header file "mpfType.h" which defines typedefs for int16, uint16, int32, uint32, float32, and float64. MPF provides static methods to transfer the following to/from network buffers:
// xxxMessage.h #ifndef xxxMessageH #define xxxMessageH class Message; class DLList; class xxxMessage : public Message { public: xxxMessage(); virtual ~xxxMessage() {} virtual void init(); virtual int32 toBuffer(char **buffer) const; virtual int32 fromBuffer(const char **buffer); virtual int32 fromBufferSwitch(const char **buffer); virtual void print() const; static void *operator new(size_t size); void operator delete(void *p, size_t size); private: static DLList *pFreeList; // Disallow copy constructor, assignment operator xxxMessage(const xxxMessage&); xxxMessage& operator=(const xxxMessage&); }; inline xxxMessage:: xxxMessage() : Message(messageTypexxx), value(0) { init(); } #endif /*xxxMessageH*/
// xxxMessage.cc extern "C" { #include <stdlib.h> #include <stddef.h> #include <string.h> #include <stdio.h> } #include "Message.h" #include "xxxMessage.h" DLList* xxxMessage::pFreeList = 0; void xxxMessage::init() { value=0; } int32 xxxMessage:: toBuffer(char **buffer) const { int32 nbytes; nbytes = Message::toBuffer(buffer); //now transfer any values added by the message type // nbytes += MPF::toBuffer(buffer,???); return(nbytes); } int32 xxxMessage:: fromBuffer(const char **buffer) { int32 nbytes=0; nbytes = Message::fromBuffer(buffer); //now transfer any values added by the message type //nbytes += MPF::fromBuffer(buffer,&???); return(nbytes); } int32 xxxMessage:: fromBufferSwitch(const char **buffer) { int32 nbytes=0; nbytes = Message::fromBufferSwitch(buffer); //now transfer any values added by the message type //nbytes += MPF::fromBufferSwitch(buffer,&???); return(nbytes); } void xxxMessage:: print() const { Message::print(); //print any values added by the message type //printf("value %d\n",???); } void *xxxMessage:: operator new(size_t size) { if(size==sizeof(xxxMessage)) return MPF:: allocate(&pFreeList,size); printf("xxxMessage new size !=sizeof(xxxMessage)\n"); return(0); } void xxxMessage:: operator delete(void *p, size_t size) { if(size==sizeof(xxxMessage)) { MPF::free(pFreeList,p,size); return; } printf("xxxMessage delete size !=sizeof(xxxMessage)\n"); }
Joe Sullivan is currently developing mv167 and mv162 board support packages that allow a 162 to be booted via the VME backplane. this will be for vxWorks 5.3
The EPICS Hideos device support and the Hideas IP tasks have not been
modified to support the new Message Passing facility.