OSDN Git Service

Revert "Enable kernel wakelocks and timers"
[android-x86/system-bt.git] / osi / src / alarm.c
index 3e7115f..aca2c79 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <assert.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <inttypes.h>
 #include <malloc.h>
 #include <pthread.h>
@@ -61,6 +60,7 @@ struct alarm_t {
   void *data;
 };
 
+extern bt_os_callouts_t *bt_os_callouts;
 
 // If the next wakeup time is less than this threshold, we should acquire
 // a wakelock instead of setting a wake alarm so we're not bouncing in
@@ -68,14 +68,7 @@ struct alarm_t {
 // unit tests to run faster. It should not be modified by production code.
 int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
 static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
-static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
-static const char *WAKE_LOCK_ID = "bluetooth_timer";
-static const char *WAKE_LOCK_PATH = "/sys/power/wake_lock";
-static const char *WAKE_UNLOCK_PATH = "/sys/power/wake_unlock";
-static ssize_t locked_id_len = -1;
-static pthread_once_t wake_fds_initialized = PTHREAD_ONCE_INIT;
-static int wake_lock_fd = INVALID_FD;
-static int wake_unlock_fd = INVALID_FD;
+static const char *WAKE_LOCK_ID = "bluedroid_timer";
 
 // This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
 // functions execute serially and not concurrently. As a result, this mutex also
@@ -83,7 +76,6 @@ static int wake_unlock_fd = INVALID_FD;
 static pthread_mutex_t monitor;
 static list_t *alarms;
 static timer_t timer;
-static timer_t wakeup_timer;
 static bool timer_set;
 
 // All alarm callbacks are dispatched from |callback_thread|
@@ -98,17 +90,11 @@ static void schedule_next_instance(alarm_t *alarm, bool force_reschedule);
 static void reschedule_root_alarm(void);
 static void timer_callback(void *data);
 static void callback_dispatch(void *context);
-static bool timer_create_internal(const clockid_t clock_id, timer_t *timer);
-static void initialize_wake_fds(void);
-static bool acquire_wake_lock(void);
-static bool release_wake_lock(void);
 
 alarm_t *alarm_new(void) {
   // Make sure we have a list we can insert alarms into.
-  if (!alarms && !lazy_initialize()) {
-    assert(false); // if initialization failed, we should not continue
+  if (!alarms && !lazy_initialize())
     return NULL;
-  }
 
   pthread_mutexattr_t attr;
   pthread_mutexattr_init(&attr);
@@ -235,65 +221,40 @@ void alarm_cleanup(void) {
 static bool lazy_initialize(void) {
   assert(alarms == NULL);
 
-  // timer_t doesn't have an invalid value so we must track whether
-  // the |timer| variable is valid ourselves.
-  bool timer_initialized = false;
-  bool wakeup_timer_initialized = false;
-
   pthread_mutex_init(&monitor, NULL);
 
   alarms = list_new(NULL);
   if (!alarms) {
     LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__);
-    goto error;
+    return false;
   }
 
-  if (!timer_create_internal(CLOCK_ID, &timer))
-    goto error;
-  timer_initialized = true;
-
-  if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer))
-    goto error;
-  wakeup_timer_initialized = true;
+  struct sigevent sigevent;
+  memset(&sigevent, 0, sizeof(sigevent));
+  sigevent.sigev_notify = SIGEV_THREAD;
+  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
+  if (timer_create(CLOCK_ID, &sigevent, &timer) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to create timer: %s", __func__,
+              strerror(errno));
+    return false;
+  }
 
   alarm_expired = semaphore_new(0);
   if (!alarm_expired) {
     LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__);
-    goto error;
+    return false;
   }
 
   callback_thread_active = true;
   callback_thread = thread_new("alarm_callbacks");
   if (!callback_thread) {
     LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
-    goto error;
+    return false;
   }
 
   thread_set_priority(callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
   thread_post(callback_thread, callback_dispatch, NULL);
   return true;
-
-error:
-  thread_free(callback_thread);
-  callback_thread = NULL;
-
-  callback_thread_active = false;
-
-  semaphore_free(alarm_expired);
-  alarm_expired = NULL;
-
-  if (wakeup_timer_initialized)
-    timer_delete(wakeup_timer);
-
-  if (timer_initialized)
-    timer_delete(timer);
-
-  list_free(alarms);
-  alarms = NULL;
-
-  pthread_mutex_destroy(&monitor);
-
-  return false;
 }
 
 static period_ms_t now(void) {
@@ -340,67 +301,41 @@ static void schedule_next_instance(alarm_t *alarm, bool force_reschedule) {
 
 // NOTE: must be called with monitor lock.
 static void reschedule_root_alarm(void) {
+  bool timer_was_set = timer_set;
   assert(alarms != NULL);
 
-  const bool timer_was_set = timer_set;
-
-  // If used in a zeroed state, disarms the timer.
-  struct itimerspec timer_time;
-  memset(&timer_time, 0, sizeof(timer_time));
+  // If used in a zeroed state, disarms the timer
+  struct itimerspec wakeup_time;
+  memset(&wakeup_time, 0, sizeof(wakeup_time));
 
   if (list_is_empty(alarms))
     goto done;
 
-  const alarm_t *next = list_front(alarms);
-  const int64_t next_expiration = next->deadline - now();
+  alarm_t *next = list_front(alarms);
+  int64_t next_expiration = next->deadline - now();
   if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
     if (!timer_set) {
-      if (!acquire_wake_lock()) {
-        LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__);
+      int status = bt_os_callouts->acquire_wake_lock(WAKE_LOCK_ID);
+      if (status != BT_STATUS_SUCCESS) {
+        LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock: %d", __func__, status);
         goto done;
       }
     }
 
-    timer_time.it_value.tv_sec = (next->deadline / 1000);
-    timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
-
-    // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec for
-    // timers with *_ALARM clock IDs. Although the man page states that the timer
-    // would be canceled, the current behavior (as of Linux kernel 3.17) is that
-    // the callback is issued immediately. The only way to cancel an *_ALARM timer
-    // is to delete the timer. But unfortunately, deleting and re-creating a timer
-    // is rather expensive; every timer_create(2) spawns a new thread. So we simply
-    // set the timer to fire at the largest possible time.
-    //
-    // If we've reached this code path, we're going to grab a wake lock and wait for
-    // the next timer to fire. In that case, there's no reason to have a pending wakeup
-    // timer so we simply cancel it.
-    struct itimerspec end_of_time;
-    memset(&end_of_time, 0, sizeof(end_of_time));
-    end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2));
-    timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
-  } else {
-    // WARNING: do not attempt to use relative timers with *_ALARM clock IDs
-    // in kernels before 3.17 unless you have the following patch:
-    // https://lkml.org/lkml/2014/7/7/576
-    struct itimerspec wakeup_time;
-    memset(&wakeup_time, 0, sizeof(wakeup_time));
-
-
     wakeup_time.it_value.tv_sec = (next->deadline / 1000);
     wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
-    if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
-      LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s",
-                __func__, strerror(errno));
+  } else {
+    if (!bt_os_callouts->set_wake_alarm(next_expiration, true, timer_callback, NULL))
+      LOG_ERROR(LOG_TAG, "%s unable to set wake alarm for %" PRId64 "ms.", __func__, next_expiration);
   }
 
 done:
-  timer_set = timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0;
+  timer_set = wakeup_time.it_value.tv_sec != 0 || wakeup_time.it_value.tv_nsec != 0;
   if (timer_was_set && !timer_set) {
-    release_wake_lock();
+    bt_os_callouts->release_wake_lock(WAKE_LOCK_ID);
   }
 
-  if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
+  if (timer_settime(timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
     LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno));
 
   // If next expiration was in the past (e.g. short timer that got context switched)
@@ -474,81 +409,3 @@ static void callback_dispatch(UNUSED_ATTR void *context) {
 
   LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__);
 }
-
-static void initialize_wake_fds(void) {
-  LOG_DEBUG(LOG_TAG, "%s opening wake locks", __func__);
-
-  wake_lock_fd = open(WAKE_LOCK_PATH, O_RDWR | O_CLOEXEC);
-  if (wake_lock_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s can't open wake lock %s: %s",
-              __func__, WAKE_LOCK_PATH, strerror(errno));
-  }
-
-  wake_unlock_fd = open(WAKE_UNLOCK_PATH, O_RDWR | O_CLOEXEC);
-  if (wake_unlock_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s can't open wake unlock %s: %s",
-              __func__, WAKE_UNLOCK_PATH, strerror(errno));
-  }
-}
-
-static bool acquire_wake_lock(void) {
-  pthread_once(&wake_fds_initialized, initialize_wake_fds);
-
-  if (wake_lock_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s lock not acquired, invalid fd", __func__);
-    return false;
-  }
-
-  if (wake_unlock_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s not acquiring lock: can't release lock", __func__);
-    return false;
-  }
-
-  long lock_name_len = strlen(WAKE_LOCK_ID);
-  locked_id_len = write(wake_lock_fd, WAKE_LOCK_ID, lock_name_len);
-  if (locked_id_len == -1) {
-    LOG_ERROR(LOG_TAG, "%s wake lock not acquired: %s",
-              __func__, strerror(errno));
-    return false;
-  } else if (locked_id_len < lock_name_len) {
-    // TODO (jamuraa): this is weird. maybe we should release and retry.
-    LOG_WARN(LOG_TAG, "%s wake lock truncated to %zd chars",
-             __func__, locked_id_len);
-  }
-  return true;
-}
-
-static bool release_wake_lock(void) {
-  pthread_once(&wake_fds_initialized, initialize_wake_fds);
-
-  if (wake_unlock_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s lock not released, invalid fd", __func__);
-    return false;
-  }
-
-  ssize_t wrote_name_len = write(wake_unlock_fd, WAKE_LOCK_ID, locked_id_len);
-  if (wrote_name_len == -1) {
-    LOG_ERROR(LOG_TAG, "%s can't release wake lock: %s",
-              __func__, strerror(errno));
-  } else if (wrote_name_len < locked_id_len) {
-    LOG_ERROR(LOG_TAG, "%s lock release only wrote %zd, assuming released",
-              __func__, wrote_name_len);
-  }
-  return true;
-}
-
-static bool timer_create_internal(const clockid_t clock_id, timer_t *timer) {
-  assert(timer != NULL);
-
-  struct sigevent sigevent;
-  memset(&sigevent, 0, sizeof(sigevent));
-  sigevent.sigev_notify = SIGEV_THREAD;
-  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
-  if (timer_create(clock_id, &sigevent, timer) == -1) {
-    LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s",
-              __func__, clock_id, strerror(errno));
-    return false;
-  }
-
-  return true;
-}