S60 Open C
Examples for Open C Libraries

Examples for Open C Libraries

Table of Contents

Simulate Active Object
MMP File for Simulate Active Object
Source Code for Simulate Active Object

 


Simulate Active Object

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:

  • To do something specific to some events, where events are sent by threads within the same process or by different processes. Only restriction is, async handler should not do any time consuming activities.
  • Symbian developers can treat each thread as an Active Ojbect (AO) and Async event handling thread as Active Schedular (AS). Here, the installation for message event done through registration.
  • Can register multiple async event handlers.
  • Specifically, this model can be used where threads/processes are doing something but these entities do something specific based on events where, events may be generated by some other entities.

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.

 


MMP File for Simulate Active Object

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

 


Source Code for Simulate Active Object

#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.

Give feedback of this article


Back to top

Copyright ©2008 Nokia Corporation. All rights reserved. This documentation can be used in the connection with this Product to help and support the user.