ca: fix android KitKat 4.4 support
authorHauke Mehrtens <hauke.mehrtens@lantiq.com>
Tue, 15 Sep 2015 13:47:44 +0000 (15:47 +0200)
committerPatrick Lankswert <patrick.lankswert@intel.com>
Wed, 23 Sep 2015 19:43:19 +0000 (19:43 +0000)
pthread_condattr_setclock() was added in Android 5.0 and IoTivity used
it unconditionally which cause linkage errors on older android versions.
With this patch pthread_condattr_setclock() is only accessed when it is
available with a weak reference. In addition android < 5.0 provides a
private function __pthread_cond_timedwait_relative() which is similar
to pthread_cond_timedwait() use that when available instead.

This should make IoTivity compatible with KitKat devices.

This was tested backported to IoTivity 0.9.2 on an Intel based Android
4.4 Phone and an Arm based Android 5.0 Phone.

Change-Id: Ibae6613a4ae52e230b7850ef1a2bad0b5fd530df
Signed-off-by: Hauke Mehrtens <hauke.mehrtens@lantiq.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2565
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Patrick Lankswert <patrick.lankswert@intel.com>
resource/csdk/connectivity/common/src/camutex_pthreads.c

index fea62f2..7132f42 100644 (file)
  */
 #define TAG PCF("UMUTEX")
 
+#ifdef __ANDROID__
+/**
+ * Android has pthread_condattr_setclock() only in version >= 5.0, older
+ * version do have a function called __pthread_cond_timedwait_relative()
+ * which waits *for* the given timespec, this function is not visible in
+ * android version >= 5.0 anymore. This is the same way as it is handled in
+ * QT 5.5.0 in
+ * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
+ */
+static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
+        __attribute__ ((weakref("pthread_condattr_setclock")));
+
+static int camutex_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t*, const struct timespec*)
+        __attribute__ ((weakref("__pthread_cond_timedwait_relative")));
+#endif /* __ANDROID__ */
+
 static const uint64_t USECS_PER_SEC         = 1000000;
 static const uint64_t NANOSECS_PER_USECS    = 1000;
 static const uint64_t NANOSECS_PER_SEC      = 1000000000L;
@@ -206,17 +222,23 @@ ca_cond ca_cond_new(void)
         }
 
 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
-        ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
-
-        if(0 != ret)
+#ifdef __ANDROID__
+        if (camutex_condattr_setclock) {
+            ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
+#else
         {
-            OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
-                    __func__, ret);
-            pthread_condattr_destroy(&(eventInfo->condattr));
-            OICFree(eventInfo);
-            return retVal;
+            ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
+#endif /*  __ANDROID__ */
+            if(0 != ret)
+            {
+                OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
+                        __func__, ret);
+                pthread_condattr_destroy(&(eventInfo->condattr));
+                OICFree(eventInfo);
+                return retVal;
+            }
         }
-#endif
+#endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
         if (0 == ret)
         {
@@ -342,11 +364,25 @@ CAWaitResult_t ca_cond_wait_for(ca_cond cond, ca_mutex mutex, uint64_t microseco
 
     if (microseconds > 0)
     {
-        struct timespec abstime = ca_get_current_time();
-        ca_add_microseconds_to_timespec(&abstime, microseconds);
+        int ret;
+        struct timespec abstime;
+
+#ifdef __ANDROID__
+        if (camutex_cond_timedwait_relative) {
+            abstime.tv_sec = microseconds / USECS_PER_SEC;
+            abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
+            //Wait for the given time
+            ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
+        } else
+#endif
+        {
+             abstime = ca_get_current_time();
+            ca_add_microseconds_to_timespec(&abstime, microseconds);
+
+            //Wait for the given time
+            ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
+        }
 
-        //Wait for the given time
-        int ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
         switch (ret)
         {
             case 0: