Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Cross-Platform IPC Event Manager for Interaction with Service Providers

4.40/5 (5 votes)
6 May 2009LGPL35 min read 39.1K   713  
This article shows you how to send or post events among processes using shared memory queues for the Windows and Linux platforms.

Introduction

Event-driven programming or event-based programming is a programming paradigm in which the flow of the program is determined by events, i.e., sensor outputs or user actions (mouse clicks, key presses) or messages from other programs or threads.

Event-driven applications usually are organized as in state machine modes due to complicated event interaction. An IPC event queue manager is required to support event-based programming.

Interactive with Service Providers

Event-driven applications may operate with lower layer software modules or hardware interfaces, which are called service providers. A service is formally specified by a set of primitives (operations) available to service users (applications). These primitives tell the service to perform some action or report on an action taken by a peer component/entity. The service primitives are classified into four categories:

  • Request
  • Indication
  • Response
  • Confirm

[Computer Networks, Andrew S.Tanenbaum]. The request and confirm primitives can be implemented in the form of service calls. The indication and response primitives can be implemented in the form of external event posting.

Active state machine objects can communicate with service providers using one of the following mechanisms for exchanging information:

  1. Synchronous service calls. These synchronous service calls may block, returning control to the application when the operation completes. Since most real-time systems must respond to external events in a predetermined amount of time, synchronous service calls are not used. 
  2. Asynchronous service calls. Asynchronous functions do not block, continuing execution and returning before the operation is completed. 
  3. Pro-active event indications. These events are posted from a service component to a client component without any request. An example might be an event posted by a hardware interrupt service routine.
Image 1

Platform-Independent Application Development

There are many different Operation Systems or hardware in the embedded system market. Each different OS provides a different API to access a set of common system services. The OS Virtual Layer provides a platform independent adapter layer allowing state machine portability between different operating systems.

IPC Event Manager

The IPC Shared Memory can be used to share information between different processes. However, in practical engineering, a source process may request to send an event to a destination process and not return until the event is received by the destination process. Or, post an event to a destination process, which just leaves the event at a queue, and returns immediately. The destination process then queries the available events and takes specific actions based on event types.

An IPC event queue manager is required to support synchronous event handling and asynchronous event handling.

Using the Code

Class XSharedMemoryQueue

This manages a set of shared memory queues. Each queue is a double linked list. The class contains a set of queue headers pointing to these queues. When an instance of the class is created, all queue nodes are linked at the first queues. Other queues are empty.

C++
class XSharedMemoryQueue 
{
  public:
      XSharedMemoryQueue();
      ~XSharedMemoryQueue();

      bool Initialize (const char* strMapName, int iNodeSize, 
                       int iNodeCount, int iQueueCount);
      void Release ();

      void* CreateSharedMemoryQueue ();
      void DeleteSharedMemoryQueue ();
      void* OpenSharedMemoryQueue ();
      void CloseSharedMemoryQueue ();

      void* GetAt(int iIndex);
      int GetIndex(void* pNode);

      void* GetQueueHead(int iQueue);
      void* GetQueueTail(int iQueue);
      void* GetNext(void* pNode);
      void* GetPrev(void* pNode);

      bool MoveToDestQueueTail(void* pNode, int iDestQueue);
      int LocateQueue(void* pNode);

      void DumpQueue (int iQueue, bool bDumpNode);
      void DumpNode (void* pNode);

  private: 
      char* m_strMapName;
      int m_iNodeSize;    // the size of internal node which contains
                          // additional pointers besides user data.
      int m_iNodeCount;   // the node count 
      int m_iQueueCount;  // the number of queues
      int* m_pQueueArray; // the queue array 
      shared_memory_t m_hMapMem;
      void* m_pMappedPointer;
};
  • C++
    bool XSharedMemoryQueue:: Initialize (const char* strMapName, 
    	int iNodeSize, int iNodeCount, int iQueueCount);
  • Initializes a set of shared memory queues. Initialize() defines the object name, the shared memory queue count, the queue node size, and the number.

  • C++
    void*XSharedMemoryQueue::CreateSharedMemoryQueue ();
  • Creates a set of shared memory queues. The function in the Windows edition creates a named file mapping object. The function in the Linux edition creates a shared memory object. For inter-process communication, the master process calls this function to create a set of shared memory queues.

  • C++
    void XSharedMemoryQueue::OpenSharedMemoryQueue ();
  • Opens a set of shared memory queues. The function in the Windows edition opens an existing named file mapping object. The function in the Linux edition opens an existing shared memory object. For inter-process communication, the slave processes call this function to create a set of shared memory queues.

  • C++
    void XSharedMemoryQueue::DeleteSharedMemoryQueue ();
  • Deletes a set of shared memory queues. The function in the Windows edition deletes a named file mapping object. The function in the Linux edition deletes a shared memory object. For inter-process communication, the master process calls this function to delete a set of shared memory queues.

  • C++
    void XSharedMemoryQueue::CloseSharedMemoryQueue ();
  • Closes a set of shared memory queues. The function in the Windows edition closes an existing named file mapping object. The function in the Linux edition closes an existing shared memory object. For inter-process communication, the slave processes call this function to close a set of shared memory queues.

  • C++
    void * XSharedMemoryQueue::GetQueueHead(int iQueue);
  • Returns the header of a given queue.

  • C++
    void * XSharedMemoryQueue::GetQueueTail(int iQueue);
  • Returns the tail of a given queue.

  • C++
    void * XSharedMemoryQueue::GetNext(void* pNode);
  • Returns the next item of a queue node.

  • C++
    void * XSharedMemoryQueue::GetPrev(void* pNode);
  • Returns the previous item of a queue node.

  • C++
    bool MoveToDestQueueTail(void* pNode, int iDestQueue);
  • Removes the given node from the source queue and adds this node to the destination queue. If the destination queue is empty, the node is added as the head of the queue. If the destination queue is not empty, the node is appended to the destination queue.

Structure IPCEventInfo

Defines the structure of an inter-process communication event information.

Class XExtIPCEvent

Manipulates a set of shared memory queues to send or post an event to a destination process.

There are three shared memory queues defined in the enum.

C++
{IPC_QUEUE_RESOURCE=0,IPC_QUEUE_SENDING=1,IPC_QUEUE_POSTING=2};

IPC_QUEUE_RESOURCE is an IPC event block pool. IPC_QUEUE_SENDING is an IPC event queue where events in the queue are in the process of sending. IPC_QUEUE_POSTING is an IPC event queue where events in the queue are going to be posted.

C++
struct IPCEventInfo 
{
    int SourceProcessID;
    int DestProcessID;
    int IPCEventStatus;
    int EventID;
    unsigned long ulParameter1;
    unsigned long ulParameter2;
};

typedef int (*SME_IPC_EVENT_CALLBACK_T)(void* pInEventInfo);

class XExtIPCEvent 
{
  public:
      XExtIPCEvent();
      ~XExtIPCEvent();

    enum {IPC_EVENT_BUFFER_SIZE=1024};
    enum {IPC_QUEUE_NUMBER=4};
    enum {IPC_QUEUE_RESOURCE=0,IPC_QUEUE_SENDING=1,IPC_QUEUE_POSTING=2};

      //Four queues: empty, send queue, wait for sending, and post

    enum TmCommandStatus
    {
        EVENT_STATUS_UNUSED = 0, EVENT_STATUS_SENDING, 
                              EVENT_STATUS_POSTING, 
                              EVENT_STATUS_CONSUMED
    };

      static XExtIPCEvent* GetInstance ();

      int Initialize (int ProcessID, bool bIsMasterProcess = false);
      void Release (bool bIsMasterProcess = false);

      int SendIPCEvent(IPCEventInfo* pInEventInfo, 
                       IPCEventInfo* pOutEventInfo, 
                       int nTimeout = -1);
      int PostIPCEvent(IPCEventInfo* pInEventInfo);
      int QueryIPCEvent(IPCEventInfo* pOutEventInfo, 
                        SME_IPC_EVENT_CALLBACK_T pfnCallbak);

      void RecycleEvent(int idProcess);
      bool DumpInfo ();

  private:

      int Lock ();
      int UnLock();

  private: 

      XSharedMemoryQueue* m_pSMQueue;
      XSemaphore* m_pSem;
      int m_idProcess;
};
  • C++
    int XExtIPCEvent::Create (int ProcessID, bool bIsMasterProcess = false);
  • Creates an instance of XSharedMemoryQueue with the process ID and master process information.

  • C++
    int XExtIPCEvent::SendIPCEvent(IPCEventInfo* pInEventInfo, 
    		IPCEventInfo* pOutEventInfo, int nTimeout = -1);
  • Sends an IPC event to a destination process. The function will not return until the event is received by the destination process.

  • C++
    int XExtIPCEvent::PostIPCEvent(IPCEventInfo* pInEventInfo);
  • Posts an IPC event to the post queue and returns immediately.

  • C++
    int XExtIPCEvent::QueryIPCEvent(IPCEventInfo* pOutEventInfo, 
    		SME_IPC_EVENT_CALLBACK_T pfnCallbak);
  • The IPC event recipient process calls this function to query the IPC event.

  • C++
    void XExtIPCEvent::RecycleEvent(int idProcess);
  • Recycles events to the event pool which are sent by the given process, or when the destination process is the given process.

Points of Interest

This is a component of the Open Source project, StateWizard, a ClassWizard-like round-trip UML dynamic modeling/development tool. You may download other components at http://www.intelliwizard.com/.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)