Experimental Physics and
| |||||||||||||||
|
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 MPF: Message Passing FacilityMPF is a facility that passes messages between tasks located on the same or different processors. It requires vxWorks as the underlying operating system. The primary purpose is to pass messages between device support attacked to EPICS database records and tasks that access hardware. It is a replacement for "bare" Hideos.MPF will replace HIDEOSBackground:Experience has shown that "bare" Hideos is too hard to use and extend. It's debugging environment is not only different than vxWorks but more primitive. Porting Hideos to new architectures will be a major task because it requires generating a "board support package" for each architecture.Strategy:The basic strategy is to abandon "bare" hideos. Instead vxWorks will be required.The most important goal is to provide a migration path for existing
HIDEOS applications. An EPICS Hideos application uses the following
hideos components:
What hardware configurations do we want to support?
Message Passing OverviewThe new message passing system follows a client server model. A client creates a connection to a server. Once a connection is established either the client or server can send messages to the other.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. Message Client Classtypedef 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:
Message Server Classclass 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
Message Classclass 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. ExampleThe following example is a client that send an Int32Message to a server. The server receives the message, increments a private counter, sets the long value equal to the previous counter value, and sends the message back to the client.Clienttypedef 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); } Serverstruct 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); } ConfigurationEach vxWorks system using the message passing system needs the following command in the startup file: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") Architecture Independent Message PassingMPF supports message passing between different architectures, i.e. different byte orders and/or different padding requirements. It does, however only work on architectures with 32 bit addressing. It provides support for the following data types:
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:
Adding New Message TypesIn order to provide a new message type the following must be done:
These files contain instructions about what to add. This is a simple change. xxxMessage.h// 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// 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"); } DiscussionI claim that the proposed message passing system will provide all the features needed to support existing Hideos IP tasks and the Hideos EPICS device support. In addition it provides the following features not supported by Hideos.
StatusSimple messages have been sent between client and server via both a local router and via a tcp router. Connection managemt still needs work, i.e. neither client or server can survive a reboot of the partner.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.
| ||||||||||||||
ANJ, 10 Aug 2010 |
·
Home
·
News
·
About
·
Base
·
Modules
·
Extensions
·
Distributions
·
Download
·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing · |