Change on handling of SIGEV_THREAD timers.

1. Don't prevent calling callback when SIGEV_THREAD timers are disarmed by timer_settime.
As in POSIX standard: The effect of disarming or resetting a timer with pending
expiration notifications is unspecified. And glibc didn't prevent in this situation, so I
think it is fine to remove the support.
2. Still prevent calling callback when SIGEV_THREAD timers are deleted by timer_delete.
As in POSIX standard: The disposition of pending signals for the deleted timer is unspecified.
However, glibc handles this (although that is not perfect). And some of our tests in
time_test.cpp depend on this feature as described in b/18039727. so I retain the support.
3. Fix some flaky test in time_test.cpp, and make "time*" test pass on bionic-unit-tests-glibcxx.

Bug: 18263854

Change-Id: I8ced184eacdbfcf433fd81b0c69c38824beb8ebc
diff --git a/libc/bionic/posix_timers.cpp b/libc/bionic/posix_timers.cpp
index 9991573..bc3aeb2 100644
--- a/libc/bionic/posix_timers.cpp
+++ b/libc/bionic/posix_timers.cpp
@@ -26,14 +26,15 @@
  * SUCH DAMAGE.
  */
 
-#include "pthread_internal.h"
-#include "private/bionic_futex.h"
 #include "private/kernel_sigset_t.h"
 
 #include <errno.h>
 #include <malloc.h>
+#include <pthread.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 
 // System calls.
 extern "C" int __rt_sigtimedwait(const sigset_t*, siginfo_t*, const struct timespec*, size_t);
@@ -59,11 +60,11 @@
 
   int sigev_notify;
 
-  // These fields are only needed for a SIGEV_THREAD timer.
+  // The fields below are only needed for a SIGEV_THREAD timer.
   pthread_t callback_thread;
   void (*callback)(sigval_t);
   sigval_t callback_argument;
-  volatile bool armed;
+  atomic_bool deleted;  // Set when the timer is deleted, to prevent further calling of callback.
 };
 
 static __kernel_timer_t to_kernel_timer_id(timer_t timer) {
@@ -85,8 +86,13 @@
       continue;
     }
 
-    if (si.si_code == SI_TIMER && timer->armed) {
+    if (si.si_code == SI_TIMER) {
       // This signal was sent because a timer fired, so call the callback.
+
+      // All events to the callback will be ignored when the timer is deleted.
+      if (atomic_load(&timer->deleted) == true) {
+        continue;
+      }
       timer->callback(timer->callback_argument);
     } else if (si.si_code == SI_TKILL) {
       // This signal was sent because someone wants us to exit.
@@ -97,9 +103,7 @@
 }
 
 static void __timer_thread_stop(PosixTimer* timer) {
-  // Immediately mark the timer as disarmed so even if some events
-  // continue to happen, the callback won't be called.
-  timer->armed = false;
+  atomic_store(&timer->deleted, true);
   pthread_kill(timer->callback_thread, TIMER_SIGNAL);
 }
 
@@ -126,7 +130,7 @@
   // Otherwise, this must be SIGEV_THREAD timer...
   timer->callback = evp->sigev_notify_function;
   timer->callback_argument = evp->sigev_value;
-  timer->armed = false;
+  atomic_init(&timer->deleted, false);
 
   // Check arguments that the kernel doesn't care about but we do.
   if (timer->callback == NULL) {
@@ -199,25 +203,19 @@
   return 0;
 }
 
-// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html
+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_gettime.html
 int timer_gettime(timer_t id, itimerspec* ts) {
   return __timer_gettime(to_kernel_timer_id(id), ts);
 }
 
-// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html
+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_settime.html
+// When using timer_settime to disarm a repeatable SIGEV_THREAD timer with a very small
+// period (like below 1ms), the kernel may continue to send events to the callback thread
+// for a few extra times. This behavior is fine because in POSIX standard: The effect of
+// disarming or resetting a timer with pending expiration notifications is unspecified.
 int timer_settime(timer_t id, int flags, const itimerspec* ts, itimerspec* ots) {
   PosixTimer* timer= reinterpret_cast<PosixTimer*>(id);
-  int rc = __timer_settime(timer->kernel_timer_id, flags, ts, ots);
-  if (rc == 0) {
-    // Mark the timer as either being armed or disarmed. This avoids the
-    // callback being called after the disarm for SIGEV_THREAD timers only.
-    if (ts->it_value.tv_sec != 0 || ts->it_value.tv_nsec != 0) {
-      timer->armed = true;
-    } else {
-      timer->armed = false;
-    }
-  }
-  return rc;
+  return __timer_settime(timer->kernel_timer_id, flags, ts, ots);
 }
 
 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html