javacommons/comms/src/commsendpoint.cpp
changeset 21 2a9601315dfc
child 50 023eef975703
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  This is an abstract base class for Comms endpoints.
       
    15 *
       
    16 */
       
    17 
       
    18 #include <errno.h>
       
    19 #include <utility>
       
    20 #include <sys/time.h>
       
    21 #include <unistd.h>
       
    22 #include <string.h>
       
    23 
       
    24 #include "logger.h"
       
    25 
       
    26 #include "commsendpoint.h"
       
    27 #include "commslistener.h"
       
    28 #include "commsmessage.h"
       
    29 
       
    30 #include "listeners.h"
       
    31 
       
    32 namespace java
       
    33 {
       
    34 namespace comms
       
    35 {
       
    36 using java::util::ScopedLock;
       
    37 
       
    38 OS_EXPORT CommsEndpoint::CommsEndpoint() : mDefaultListener(0), mMessageRefCounter(0), mVm(0), mJNIEnv(0)
       
    39 {
       
    40 //    JELOG2(EJavaComms);
       
    41     pthread_mutex_init(&mSendReceiveMutex, 0);
       
    42     pthread_cond_init(&mSendReceiveCondition, 0);
       
    43 }
       
    44 
       
    45 OS_EXPORT CommsEndpoint::~CommsEndpoint()
       
    46 {
       
    47 //    JELOG2(EJavaComms);
       
    48 
       
    49     for (listeners_t::iterator it = mListeners.begin(); it != mListeners.end(); it++)
       
    50     {
       
    51         delete it->second;
       
    52     }
       
    53     mListeners.clear();
       
    54 
       
    55     delete mDefaultListener;
       
    56 
       
    57     pthread_mutex_destroy(&mSendReceiveMutex);
       
    58     pthread_cond_destroy(&mSendReceiveCondition);
       
    59 }
       
    60 
       
    61 OS_EXPORT void CommsEndpoint::handleIpcMessage(CommsMessage& aMessage)
       
    62 {
       
    63 //    JELOG2(EJavaComms);
       
    64 
       
    65     /* Message routing is done in following steps:
       
    66      *  1. check if received message is reply to sendReceive method call
       
    67      *  2. use moduleId to find correct listener
       
    68      * */
       
    69     if (! isSendReceiveMessage(aMessage))
       
    70     {
       
    71         handleMessage(aMessage);
       
    72     }
       
    73 }
       
    74 
       
    75 
       
    76 OS_EXPORT int CommsEndpoint::handleMessage(CommsMessage& aMessage)
       
    77 {
       
    78 //    JELOG2(EJavaComms);
       
    79     ScopedLock lock(mListenersMutex);
       
    80 
       
    81 
       
    82     if (mVm && !mJNIEnv)
       
    83     {
       
    84         // attach to VM
       
    85         mVm->AttachCurrentThread((void**)&mJNIEnv, (void *)NULL);
       
    86     }
       
    87 
       
    88 
       
    89     listeners_t::iterator it = mListeners.find(aMessage.getModuleId());
       
    90 
       
    91     if (it != mListeners.end())
       
    92     {
       
    93         (it->second)->processMessage(aMessage, mJNIEnv);
       
    94     }
       
    95     else
       
    96     {
       
    97         if (mDefaultListener)
       
    98         {
       
    99             mDefaultListener->processMessage(aMessage, mJNIEnv);
       
   100         }
       
   101         else
       
   102         {
       
   103             WLOG3(EJavaComms, "CommsEndpoint::handleMessage: No handlers found, msgId=%d, moduleId=%d, messageRef=%d",
       
   104                   aMessage.getMessageId(),
       
   105                   aMessage.getModuleId(),
       
   106                   aMessage.getMessageRef());
       
   107         }
       
   108     }
       
   109     return 0;
       
   110 }
       
   111 
       
   112 OS_EXPORT int CommsEndpoint::registerListener(int aModuleId, CommsListener* aListener)
       
   113 {
       
   114 //    JELOG2(EJavaComms);
       
   115     ScopedLock lock(mListenersMutex);
       
   116     if (!aListener) return EINVAL;
       
   117 
       
   118     int rc = 0;
       
   119 
       
   120     if (mListeners.find(aModuleId) != mListeners.end())
       
   121     {
       
   122         rc = EEXIST; // already exists
       
   123         ELOG2(EJavaComms, "%s failed, listener already exists %d", __PRETTY_FUNCTION__, aModuleId);
       
   124     }
       
   125     else
       
   126     {
       
   127         mListeners.insert(std::make_pair(aModuleId, new ListenerWrapper(aListener)));
       
   128         LOG1(EJavaComms, EInfo, "Registered listener for module id %d", aModuleId);
       
   129     }
       
   130 
       
   131     return rc;
       
   132 }
       
   133 
       
   134 OS_EXPORT int CommsEndpoint::unregisterListener(int aModuleId, CommsListener* /*aListener*/)
       
   135 {
       
   136 //    JELOG2(EJavaComms);
       
   137     ScopedLock lock(mListenersMutex);
       
   138     int rc = 0;
       
   139 
       
   140     listeners_t::iterator it = mListeners.find(aModuleId);
       
   141     if (it != mListeners.end() /*&& it->second == aListener*/)
       
   142     {
       
   143         delete it->second;
       
   144         mListeners.erase(it);
       
   145         LOG1(EJavaComms, EInfo, "Unregistered listener for module id %d", aModuleId);
       
   146     }
       
   147     else
       
   148     {
       
   149         rc = ENOENT; // not found
       
   150         ELOG2(EJavaComms, "%s failed, listener does not exists %d", __PRETTY_FUNCTION__, aModuleId);
       
   151     }
       
   152 
       
   153     return rc;
       
   154 }
       
   155 
       
   156 OS_EXPORT int CommsEndpoint::registerDefaultListener(CommsListener* aListener)
       
   157 {
       
   158 //    JELOG2(EJavaComms);
       
   159     ScopedLock lock(mListenersMutex);
       
   160     if (!aListener) return EINVAL;
       
   161 
       
   162     int rc = 0;
       
   163 
       
   164     if (!mDefaultListener)
       
   165     {
       
   166         mDefaultListener = new ListenerWrapper(aListener);
       
   167         LOG(EJavaComms, EInfo, "Default listener registered");
       
   168     }
       
   169     else
       
   170     {
       
   171         rc = EEXIST; // already exists
       
   172         ELOG1(EJavaComms, "%s failed, default listener already exists", __PRETTY_FUNCTION__);
       
   173     }
       
   174     return rc;
       
   175 }
       
   176 
       
   177 OS_EXPORT int CommsEndpoint::unregisterDefaultListener(CommsListener* aListener)
       
   178 {
       
   179 //    JELOG2(EJavaComms);
       
   180     ScopedLock lock(mListenersMutex);
       
   181 
       
   182     int rc = 0;
       
   183 
       
   184     if (mDefaultListener && mDefaultListener->getListener() == aListener)
       
   185     {
       
   186         delete mDefaultListener;
       
   187         mDefaultListener = 0;
       
   188         LOG(EJavaComms, EInfo, "Default listener unregistered");
       
   189     }
       
   190     else
       
   191     {
       
   192         rc = ENOENT; // not found
       
   193         ELOG2(EJavaComms, "%s failed, errno = %d", __PRETTY_FUNCTION__, rc);
       
   194     }
       
   195 
       
   196     return rc;
       
   197 }
       
   198 
       
   199 int CommsEndpoint::isSendReceiveMessage(CommsMessage& aMessage)
       
   200 {
       
   201 //    JELOG2(EJavaComms);
       
   202 
       
   203     pthread_mutex_lock(&mSendReceiveMutex);
       
   204 
       
   205     int handled = 0;
       
   206     sendReceiveListeners_t::iterator it = mSendReceiveListeners.find(aMessage.getMessageRef());
       
   207 
       
   208     if (it != mSendReceiveListeners.end())
       
   209     {
       
   210         sendReceiveMessage_t sync = (it->second);
       
   211 
       
   212         *sync.p_message = aMessage;
       
   213         *sync.p_done = 1;
       
   214         *sync.p_result = 0;
       
   215 
       
   216         pthread_cond_broadcast(&mSendReceiveCondition); // wake sendReceive threads
       
   217         handled = 1;
       
   218     }
       
   219 
       
   220     pthread_mutex_unlock(&mSendReceiveMutex);
       
   221 
       
   222     return handled;
       
   223 }
       
   224 
       
   225 OS_EXPORT int CommsEndpoint::sendReceive(CommsMessage& aMessage, CommsMessage& aReceivedMessage, int aTimeoutInSecs)
       
   226 {
       
   227 #ifdef __SYMBIAN32__
       
   228     // Workaround for OpenC max timeout value limitation.
       
   229     // If OpenC limit is exceeded then EINVAL would be returned from pthread_cond_timedwait()
       
   230     const int MAX_TIME = 2148;
       
   231     if (aTimeoutInSecs > MAX_TIME)
       
   232     {
       
   233         WLOG3(EJavaComms, "%s timeout value too big, changing %d to %d", __PRETTY_FUNCTION__, aTimeoutInSecs, MAX_TIME);
       
   234         aTimeoutInSecs = MAX_TIME;
       
   235     }
       
   236 #endif // __SYMBIAN32__
       
   237 
       
   238 //    JELOG2(EJavaComms);
       
   239     if (aTimeoutInSecs < 1 && aTimeoutInSecs != WAIT_FOR_EVER)
       
   240     {
       
   241         ELOG2(EJavaComms, "%s failed, invalid timeout value = %d", __PRETTY_FUNCTION__, aTimeoutInSecs);
       
   242         return EINVAL;
       
   243     }
       
   244 
       
   245     pthread_mutex_lock(&mSendReceiveMutex);
       
   246 
       
   247     int messageRef = generateMessageReference();
       
   248     aMessage.setMessageRef(messageRef);
       
   249     int rc = send(aMessage);
       
   250 
       
   251     if (rc != 0)
       
   252     {
       
   253         pthread_mutex_unlock(&mSendReceiveMutex);
       
   254         ELOG2(EJavaComms, "%s failed, errno = %d", __PRETTY_FUNCTION__, rc);
       
   255         return rc;
       
   256     }
       
   257 
       
   258     int done = 0;
       
   259     int result = 0;
       
   260     sendReceiveMessage_t msg;
       
   261     msg.p_message   = &aReceivedMessage;
       
   262     msg.p_done      = &done;
       
   263     msg.p_result    = &result;
       
   264 
       
   265     mSendReceiveListeners.insert(std::make_pair(messageRef, msg));
       
   266 
       
   267     // specify duration for timeout
       
   268     timeval  curtime;
       
   269     rc = gettimeofday(&curtime, 0);
       
   270 
       
   271     timespec timeout;
       
   272     timeout.tv_sec  = curtime.tv_sec;
       
   273     timeout.tv_nsec = curtime.tv_usec * 1000;
       
   274     timeout.tv_sec += aTimeoutInSecs;
       
   275 
       
   276     // loop used, since signal might stop the wait before the timeout
       
   277     while (!done)
       
   278     {
       
   279         if (aTimeoutInSecs == WAIT_FOR_EVER)
       
   280         {
       
   281             rc = pthread_cond_wait(&mSendReceiveCondition, &mSendReceiveMutex);
       
   282         }
       
   283         else
       
   284         {
       
   285             rc = pthread_cond_timedwait(&mSendReceiveCondition, &mSendReceiveMutex, &timeout);
       
   286         }
       
   287         switch (rc)
       
   288         {
       
   289         case 0: // cond. variable being signaled
       
   290             if (done)
       
   291             {
       
   292                 mSendReceiveListeners.erase(messageRef);
       
   293                 rc = result;
       
   294             }
       
   295             break;
       
   296 
       
   297         case ETIMEDOUT:
       
   298             mSendReceiveListeners.erase(messageRef);
       
   299             done = 1;
       
   300             break;
       
   301 
       
   302         default:
       
   303             ELOG2(EJavaComms, "pthread_cond_timedwait failed %d - %s", rc, strerror(rc));
       
   304             break;
       
   305         }
       
   306     }
       
   307 
       
   308     if (rc)
       
   309     {
       
   310         ELOG3(EJavaComms, "%s failed %d - %s", __PRETTY_FUNCTION__ , rc, strerror(rc));
       
   311     }
       
   312 
       
   313     pthread_mutex_unlock(&mSendReceiveMutex);
       
   314     return rc;
       
   315 }
       
   316 
       
   317 OS_EXPORT int CommsEndpoint::generateMessageReference()
       
   318 {
       
   319 //    JELOG2(EJavaComms);
       
   320     ScopedLock lock(mMessageRefMutex);
       
   321     if (mMessageRefCounter == 0)
       
   322     {
       
   323         // valid msgRef can't be zero, CommsMessage used zero as default value
       
   324         mMessageRefCounter++;
       
   325     }
       
   326     int messageRef = mMessageRefCounter++;
       
   327     return messageRef;
       
   328 }
       
   329 
       
   330 OS_EXPORT void CommsEndpoint::processMessage(const ipcMessage_t* aMsg)
       
   331 {
       
   332     CommsMessage msg(aMsg);
       
   333     handleIpcMessage(msg);
       
   334 }
       
   335 
       
   336 OS_EXPORT void CommsEndpoint::onStart()
       
   337 {
       
   338 }
       
   339 
       
   340 OS_EXPORT void CommsEndpoint::onExit()
       
   341 {
       
   342     pthread_mutex_lock(&mSendReceiveMutex);
       
   343     for (sendReceiveListeners_t::iterator iter = mSendReceiveListeners.begin(); iter != mSendReceiveListeners.end(); iter++)
       
   344     {
       
   345         sendReceiveMessage_t sync = (iter->second);
       
   346         CommsMessage empty;
       
   347 
       
   348         *sync.p_message = empty;
       
   349         *sync.p_done = 1;
       
   350         *sync.p_result = EINTR;
       
   351     }
       
   352 
       
   353     pthread_cond_broadcast(&mSendReceiveCondition); // wake sendReceive threads
       
   354     pthread_mutex_unlock(&mSendReceiveMutex);
       
   355 
       
   356     // wait here until all sendReceive threads are done
       
   357     while (true)
       
   358     {
       
   359         pthread_mutex_lock(&mSendReceiveMutex);
       
   360         int listenerCount = mSendReceiveListeners.size();
       
   361         pthread_mutex_unlock(&mSendReceiveMutex);
       
   362 
       
   363         if (listenerCount!=0)
       
   364         {
       
   365             WLOG1(EJavaComms, "waiting for sendReceive listeners - count=%d", listenerCount);
       
   366             usleep(50); // 0.05s
       
   367         }
       
   368         else
       
   369         {
       
   370             break;
       
   371         }
       
   372     }
       
   373 
       
   374     if (mVm)
       
   375     {
       
   376         mVm->DetachCurrentThread();
       
   377         mVm=0;
       
   378         mJNIEnv=0;
       
   379     }
       
   380 }
       
   381 
       
   382 OS_EXPORT int CommsEndpoint::registerJavaListener(int aModuleId, jobject aListener, JNIEnv* aEnv)
       
   383 {
       
   384 //    JELOG2(EJavaComms);
       
   385     ScopedLock lock(mListenersMutex);
       
   386     int rc = 0;
       
   387 
       
   388     if (mListeners.find(aModuleId) != mListeners.end())
       
   389     {
       
   390         rc = EEXIST; // already exists
       
   391         ELOG2(EJavaComms, "%s failed, listener already exists %d", __PRETTY_FUNCTION__, aModuleId);
       
   392     }
       
   393     else
       
   394     {
       
   395         ListenerWrapper* listener = new ListenerWrapper(aListener, aEnv);
       
   396         mListeners.insert(std::make_pair(aModuleId, listener));
       
   397         LOG1(EJavaComms, EInfo, "Registered java listener for module id %d", aModuleId);
       
   398     }
       
   399 
       
   400     return rc;
       
   401 }
       
   402 
       
   403 OS_EXPORT int CommsEndpoint::unregisterJavaListener(int aModuleId, jobject, JNIEnv* aEnv)
       
   404 {
       
   405 //    JELOG2(EJavaComms);
       
   406     ScopedLock lock(mListenersMutex);
       
   407     int rc = 0;
       
   408 
       
   409     listeners_t::iterator it = mListeners.find(aModuleId);
       
   410     if (it != mListeners.end())
       
   411     {
       
   412         (it->second)->release(aEnv);
       
   413         delete it->second;
       
   414         mListeners.erase(it);
       
   415         LOG1(EJavaComms, EInfo, "Unregistered java listener for module id %d", aModuleId);
       
   416     }
       
   417     else
       
   418     {
       
   419         rc = ENOENT; // not found
       
   420         ELOG2(EJavaComms, "%s failed, listener does not exists %d", __PRETTY_FUNCTION__, aModuleId);
       
   421     }
       
   422 
       
   423     return rc;
       
   424 }
       
   425 
       
   426 OS_EXPORT int CommsEndpoint::registerDefaultJavaListener(jobject aListener, JNIEnv* aEnv)
       
   427 {
       
   428     ScopedLock lock(mListenersMutex);
       
   429     int rc = 0;
       
   430 
       
   431     if (!mDefaultListener)
       
   432     {
       
   433         mDefaultListener = new ListenerWrapper(aListener, aEnv);
       
   434         LOG(EJavaComms, EInfo, "Registered default java listener");
       
   435     }
       
   436     else
       
   437     {
       
   438         rc = EEXIST; // already exists
       
   439         ELOG1(EJavaComms, "%s failed, default listener already exists", __PRETTY_FUNCTION__);
       
   440     }
       
   441     return rc;
       
   442 }
       
   443 
       
   444 OS_EXPORT int CommsEndpoint::unregisterDefaultJavaListener(jobject, JNIEnv*)
       
   445 {
       
   446     ScopedLock lock(mListenersMutex);
       
   447     int rc = 0;
       
   448 
       
   449     if (mDefaultListener && mDefaultListener->getListener() == 0)
       
   450     {
       
   451         delete mDefaultListener;
       
   452         mDefaultListener = 0;
       
   453         LOG(EJavaComms, EInfo, "Unregistered default java listener");
       
   454     }
       
   455     else
       
   456     {
       
   457         rc = ENOENT; // not found
       
   458         ELOG2(EJavaComms, "%s failed, errno = %d", __PRETTY_FUNCTION__, rc);
       
   459     }
       
   460     return rc;
       
   461 }
       
   462 
       
   463 
       
   464 OS_EXPORT int CommsEndpoint::attachToVm(JNIEnv* aEnv)
       
   465 {
       
   466 //    JELOG2(EJavaComms);
       
   467     ScopedLock lock(mListenersMutex);
       
   468 
       
   469     int rc = aEnv->GetJavaVM(&mVm);
       
   470     if (rc != 0)
       
   471     {
       
   472         ELOG2(EJavaComms, "%s failed, rc = %d", __PRETTY_FUNCTION__, rc);
       
   473     }
       
   474 
       
   475     return rc;
       
   476 }
       
   477 
       
   478 OS_EXPORT int CommsEndpoint::detachFromVm()
       
   479 {
       
   480 //    JELOG2(EJavaComms);
       
   481     ScopedLock lock(mListenersMutex);
       
   482 
       
   483     // remove java listeners
       
   484     if (mDefaultListener && mDefaultListener->getListener() == 0)
       
   485     {
       
   486         delete mDefaultListener;
       
   487         mDefaultListener = 0;
       
   488         LOG(EJavaComms, EInfo, "Removed default java listener (detach)");
       
   489     }
       
   490 
       
   491     for (listeners_t::iterator it = mListeners.begin(); it != mListeners.end();)
       
   492     {
       
   493         if ((it->second)->getListener() == 0)
       
   494         {
       
   495             LOG1(EJavaComms, EInfo, "Removed java listener for module id %d (detach)", it->first);
       
   496 
       
   497             (it->second)->release(mJNIEnv);
       
   498             delete it->second;
       
   499             mListeners.erase(it);
       
   500             it = mListeners.begin();
       
   501         }
       
   502         else
       
   503         {
       
   504             it++;
       
   505         }
       
   506     }
       
   507     return 0;
       
   508 }
       
   509 
       
   510 } // namespace comms
       
   511 } // namespace java
       
   512