Examples for Open C Libraries |
This example illustrates how to simulate Symbian active object functionality using pthread and message queue. Here, each thread registers an async handler with Asynchronous handler thread. Once the Async Handler thread receives any event, it calls the corresponding register handler. Users can follow this pattern for the following situations:
Events are basically different triggers to the system. For example, one thread creates one buffer and passes the same to other thread. At the same time these threads are also doing some other activity. When buffer is full, the other thread can send one event and async event handler will call the corresponding registered handler to handle the buffer.
TARGET simulateactiveobject.exe TARGETTYPE exe UID 0 0xA000131C CAPABILITY NONE VENDORID 0 SOURCEPATH ..\data START RESOURCE simulateactiveobject_reg.rss #ifdef WINSCW TARGETPATH \private\10003a3f\apps #else TARGETPATH \private\10003a3f\import\apps #endif END //RESOURCE SOURCEPATH ..\src SOURCE simulateactiveobject.c USERINCLUDE ..\inc SYSTEMINCLUDE \Epoc32\include SYSTEMINCLUDE \epoc32\include\stdapis STATICLIBRARY libcrt0.lib LIBRARY libc.lib LIBRARY libpthread.lib LIBRARY euser.lib
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/fcntl.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <errno.h> #include <sys/time.h> #include <sys/select.h> #include <errno.h> #include <sys/msg.h> #include <assert.h> // GCCE specific header file #include <staticlibinit_gcce.h> typedef unsigned char bool; #define true 1 #define false 0 // Event handler thread message queue key #define EVENT_HANDLER_MSG_QUEUE_KEY 1000 #define EVENT_MSG_LEN 1 typedef enum { E_TERMINATE = 0x01, E_SOUND_EVENT, E_KEY_EVENT }TAsyncEvent; // Asynchronous callback typedef void (*AsyncCallBackFuncPtr)(void* aArg); // structure used to pass the parameters while registering typedef struct { int iEventId; AsyncCallBackFuncPtr iAsyncFuncPtr; void* iArg; }SAsyncParameter; // Async paramer link list node typedef struct SAsyncContainerNode { SAsyncParameter *iCallbackParameter; struct SAsyncContainerNode *iNext; }SAsyncContainerNode; // Containter to store the callback information typedef struct { int iRegisterCount; SAsyncContainerNode *iAsyncContainerNode; }SAsyncContainer; // message structure typedef struct { int mtype; char mtext[EVENT_MSG_LEN]; }SEventMsg; /** * global variable to store the the callback information */ static SAsyncContainer gAsyncContainer; /** * Flag to indicate that main thread is terminating */ bool exitMainThreadFlag; // Forward declaration int CreateMsgQueue(int aMsgKey); void SendNotification(int msg_id, int msg_no); // Debug message #ifdef _DEBUG /** * Define this macro to enable file based logging. */ /** * Use to get execution trace * @param aMessagePtr pointer to the message * @param ... Variable parameters like printf * */ inline int Trace(char* aMessagePtr, ...) { va_list marker; int printChar; va_start(marker, aMessagePtr); printChar = vprintf(aMessagePtr, marker); va_end(marker); return printChar; } #define DEBUG Trace #else // On target inline int Trace(char* aMessagePtr, ...) { return 0; } #define DEBUG 0 & Trace #endif /** * Asynchronous callback because of sound message * @param aArg pointer to the registered argument */ void AsyncSoundCallback(void * aArg) { (void) aArg; DEBUG("sound async handler.\n"); } /** * Asynchronous callback because of key message * @param aArg pointer to the registered argument */ void AsyncKeyCallback(void * aArg) { (void) aArg; DEBUG("key async handler.\n"); } /** * this method is used to register the callback * @param aAsyncParameter Asynchronous parameters * @return 0 if successfull else -1 */ int RegisterCallback(SAsyncParameter* aAsyncParameter) { bool registerFlag = true; SAsyncContainerNode* asyncContainerNode = gAsyncContainer.iAsyncContainerNode; SAsyncContainerNode* asyncBackContainerNode = asyncContainerNode; SAsyncParameter* asyncParameter = NULL; // Check whether the message is already registered or not int count = 0; for(count = 0; count < gAsyncContainer.iRegisterCount; count++) { asyncBackContainerNode = asyncContainerNode; if(asyncContainerNode == NULL) { break; } else { asyncParameter = asyncContainerNode->iCallbackParameter; if(asyncParameter != NULL) { if(asyncParameter->iEventId == aAsyncParameter->iEventId) { // already registered registerFlag = false; errno = EINVAL; DEBUG("Event is already registered. Errno - %d\n", errno); } } else { registerFlag = false; errno = EINVAL; DEBUG("Async Container node is NULL. Errno - %d\n", errno); } } // end of else asyncContainerNode = asyncContainerNode->iNext; } // end of for if(registerFlag) { // okay for registration asyncContainerNode = (SAsyncContainerNode*)malloc(sizeof(SAsyncContainerNode)); asyncContainerNode->iCallbackParameter = (SAsyncParameter*)malloc(sizeof(SAsyncParameter)); asyncContainerNode->iCallbackParameter->iEventId = aAsyncParameter->iEventId; asyncContainerNode->iCallbackParameter->iAsyncFuncPtr = aAsyncParameter->iAsyncFuncPtr; asyncContainerNode->iCallbackParameter->iArg = aAsyncParameter->iArg; asyncContainerNode->iNext = NULL; if(!gAsyncContainer.iRegisterCount) gAsyncContainer.iAsyncContainerNode = asyncContainerNode; else asyncBackContainerNode->iNext = asyncContainerNode; gAsyncContainer.iRegisterCount++; } return registerFlag ? 0 : -1; } /** * this method is used to deregister the callback * @param aEventId event number * @return 0 if successful else -1 */ int DeregisterCallback(int aEventId) { int retVal = -1; SAsyncContainerNode* asyncContainerNode = gAsyncContainer.iAsyncContainerNode; SAsyncContainerNode* backAsyncContainerNode = asyncContainerNode; SAsyncParameter* asyncParameter = NULL; // Check whether the message is already registered or not int count = 0; for(count = 0; count < gAsyncContainer.iRegisterCount; count++) { if(asyncContainerNode == NULL) { break; } else { asyncParameter = asyncContainerNode->iCallbackParameter; if(asyncParameter != NULL) { if(asyncParameter->iEventId == aEventId) { // event is registered // delete the container node. if(gAsyncContainer.iAsyncContainerNode == asyncContainerNode) gAsyncContainer.iAsyncContainerNode = asyncContainerNode->iNext; else backAsyncContainerNode->iNext = asyncContainerNode->iNext; free(asyncContainerNode->iCallbackParameter); free(asyncContainerNode); retVal = 0; gAsyncContainer.iRegisterCount --; assert(gAsyncContainer.iRegisterCount >= 0); break; } } else { errno = EINVAL; DEBUG("Async Container node is NULL. Errno - %d\n", errno); } } // end of else backAsyncContainerNode = asyncContainerNode; asyncContainerNode = asyncContainerNode->iNext; } // end of for return retVal; } /** * thread entry point for the async message handling loop * @param args Pointer to the argument passed to the thread * @return NULL */ void* AsyncEventHandleThreadEntry(void * args) { int msqId = -1; int msgLen = EVENT_MSG_LEN + sizeof(int);//sizeof(SEventMsg); int msgType = 0; /* Any type of message */ SEventMsg msgBuf; (void) args; /* * Get the message queue id for the given key */ msqId = CreateMsgQueue(EVENT_HANDLER_MSG_QUEUE_KEY); if (msqId == -1) { DEBUG("Unable to create the message queue. Errno - %d\n", errno); return NULL; } /* * Get the message from the queue */ while(!exitMainThreadFlag) { if (msgrcv(msqId, (struct msgbuf *)&msgBuf, msgLen, msgType, 0) == -1) { DEBUG("Message Q recv failed. Errno - %d\n", errno); break; } else { // received some message // Search the container for the event handler SAsyncContainerNode* asyncContainerNode = gAsyncContainer.iAsyncContainerNode; int count = 0; if(msgBuf.mtype == E_TERMINATE) break; DEBUG("Received message type - %d\n", msgBuf.mtype); for(count = 0; asyncContainerNode && count < gAsyncContainer.iRegisterCount; count++) { if(asyncContainerNode->iCallbackParameter->iEventId == msgBuf.mtype) { // found the container node if(asyncContainerNode->iCallbackParameter != NULL) { // call the async method DEBUG("Found aync callback at index - %d\n", count); asyncContainerNode->iCallbackParameter->iAsyncFuncPtr (asyncContainerNode->iCallbackParameter->iArg); } else { DEBUG("Callback parameter is non NULL., Errno - %d\n", errno); } } // end of if asyncContainerNode = asyncContainerNode->iNext; } // end of for } // end of else } // end of while /* * Remove the message queue */ if (msgctl(msqId, IPC_RMID, NULL) == -1) { DEBUG("Failed to delte Message Q. Errno - %d\n", errno); } DEBUG("Async thread finished.\n"); return NULL; } /** * Used to creat async event handler thread * @return 0 for success else -1 */ int CreateAsyncEventHandlerThread() { unsigned int threadId; int err = pthread_create(&threadId,(pthread_attr_t *)NULL,AsyncEventHandleThreadEntry,NULL); if(err == 0) { DEBUG("Async Thread is created successfully\n"); } else { DEBUG("Unable to creat async thread. Errno - %d\n", errno); } return threadId; } /** * thread entry point for Key handling thread. * @param args Pointer to the argument passed to the thread * @return NULL */ void* KeyhandlingThreadEntry(void * args) { int msg_id = CreateMsgQueue(EVENT_HANDLER_MSG_QUEUE_KEY); (void) args; if(msg_id == -1) { DEBUG("Unable to create the message queue. Errno - %d\n", errno); } else { SAsyncParameter asyncParameter; asyncParameter.iEventId = E_KEY_EVENT; asyncParameter.iAsyncFuncPtr = AsyncKeyCallback; asyncParameter.iArg = NULL; if(RegisterCallback(&asyncParameter) != -1) { while(!exitMainThreadFlag) { // do something and then send notification for key event. // async handler will call the callback method DEBUG("Within key thread.\n"); SendNotification(msg_id, E_KEY_EVENT); // just to schedule others. sleep(1); } } } DeregisterCallback(E_KEY_EVENT); DEBUG("key thread finished.\n"); return NULL; } /** * Used to creat key handler thread * @return 0 for success else -1 */ int CreateKeyhandlingThread() { unsigned int threadId; int err = pthread_create(&thread,(pthread_attr_t *)NULL,KeyhandlingThreadEntry,NULL); if(err == 0) { DEBUG("Thread is created successfully.\n"); } else { DEBUG("Unable to creat key thread. Errno - %d\n", errno); } return threadId; } /** * thread entry point for sound handling thread. * @param args Pointer to the argument passed to the thread * @return NULL */ void* SoundhandlingThreadEntry(void * args) { int msg_id = CreateMsgQueue(EVENT_HANDLER_MSG_QUEUE_KEY); (void) args; if(msg_id == -1) { DEBUG("Unable to create the message queue. Errno - %d\n", errno); } else { SAsyncParameter asyncParameter; asyncParameter.iEventId = E_SOUND_EVENT; asyncParameter.iAsyncFuncPtr = AsyncSoundCallback; asyncParameter.iArg = NULL; if(RegisterCallback(&asyncparameter) != -1) { while(!exitMainThreadFlag) { // do something and then send notification for key event. // async handler will call the callback method DEBUG("within sound thread.\n"); SendNotification(msg_id, E_SOUND_EVENT); // just to schedule others. sleep(1); } } } DeregisterCallback(E_SOUND_EVENT); DEBUG("sound thread finished.\n"); return NULL; }
NOTE: This code has been tested on Carbide.