Merge "Remove PROP_PATH_SYSTEM_DEFAULT."
diff --git a/libc/Android.mk b/libc/Android.mk
index e632ee7..e06a860 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -63,6 +63,7 @@
stdio/sprintf.c \
stdio/stdio.c \
stdio/stdio_ext.cpp \
+ stdlib/exit.c \
# Fortify implementations of libc functions.
libc_common_src_files += \
@@ -480,7 +481,6 @@
upstream-openbsd/lib/libc/stdlib/atoi.c \
upstream-openbsd/lib/libc/stdlib/atol.c \
upstream-openbsd/lib/libc/stdlib/atoll.c \
- upstream-openbsd/lib/libc/stdlib/exit.c \
upstream-openbsd/lib/libc/stdlib/getenv.c \
upstream-openbsd/lib/libc/stdlib/insque.c \
upstream-openbsd/lib/libc/stdlib/lsearch.c \
@@ -1007,7 +1007,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libc_thread_atexit_impl_src_files)
-LOCAL_CFLAGS := $(libc_common_cflags) -fno-data-sections -Wframe-larger-than=2048
+LOCAL_CFLAGS := $(libc_common_cflags) -Wframe-larger-than=2048
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index 9ae6dfd..0e427d3 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -22,7 +22,7 @@
thread_local_dtor* next;
};
-__thread thread_local_dtor* thread_local_dtors = nullptr;
+static __thread thread_local_dtor* thread_local_dtors = nullptr;
extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
thread_local_dtor* dtor = new thread_local_dtor();
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
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 414d171..30dc0eb 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -97,14 +97,8 @@
#define LIBC_PTHREAD_KEY_RESERVED_COUNT 12
#if defined(USE_JEMALLOC)
-/* Following are current pthread keys used internally by jemalloc:
- * je_thread_allocated_tsd jemalloc
- * je_arenas_tsd jemalloc
- * je_tcache_tsd jemalloc
- * je_tcache_enabled_tsd jemalloc
- * je_quarantine_tsd jemalloc
- */
-#define JEMALLOC_PTHREAD_KEY_RESERVED_COUNT 5
+/* Internally, jemalloc uses a single key for per thread data. */
+#define JEMALLOC_PTHREAD_KEY_RESERVED_COUNT 1
#define BIONIC_PTHREAD_KEY_RESERVED_COUNT (LIBC_PTHREAD_KEY_RESERVED_COUNT + JEMALLOC_PTHREAD_KEY_RESERVED_COUNT)
#else
#define BIONIC_PTHREAD_KEY_RESERVED_COUNT LIBC_PTHREAD_KEY_RESERVED_COUNT
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/exit.c b/libc/stdlib/exit.c
similarity index 88%
rename from libc/upstream-openbsd/lib/libc/stdlib/exit.c
rename to libc/stdlib/exit.c
index 83fe3d2..10ce674 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/exit.c
+++ b/libc/stdlib/exit.c
@@ -32,8 +32,6 @@
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
-#include "atexit.h"
-#include "thread_private.h"
/*
* This variable is zero until a process has created a thread.
@@ -44,12 +42,21 @@
*/
int __isthreaded = 0;
+/* BEGIN android-added: using __cxa_finalize and __cxa_thread_finalize */
+extern void __cxa_finalize(void* dso_handle);
+extern void __cxa_thread_finalize();
+/* END android-added */
+
/*
* Exit, flushing stdio buffers if necessary.
*/
void
exit(int status)
{
+ /* BEGIN android-added: call thread_local d-tors */
+ __cxa_thread_finalize();
+ /* END android-added */
+
/*
* Call functions registered by atexit() or _cxa_atexit()
* (including the stdio cleanup routine) and then _exit().
diff --git a/tests/__cxa_thread_atexit_test.cpp b/tests/__cxa_thread_atexit_test.cpp
index fea60b7..e388f3b 100644
--- a/tests/__cxa_thread_atexit_test.cpp
+++ b/tests/__cxa_thread_atexit_test.cpp
@@ -35,7 +35,7 @@
std::string message;
};
-thread_local ClassWithDtor class_with_dtor;
+static thread_local ClassWithDtor class_with_dtor;
static void* thread_nop(void* arg) {
class_with_dtor.set_message(*static_cast<std::string*>(arg));
@@ -50,6 +50,29 @@
ASSERT_EQ("dtor called.", class_with_dtor_output);
}
+class ClassWithDtorForMainThread {
+ public:
+ void set_message(const std::string& msg) {
+ message = msg;
+ }
+
+ ~ClassWithDtorForMainThread() {
+ fprintf(stderr, "%s", message.c_str());
+ }
+ private:
+ std::string message;
+};
+
+static void thread_atexit_main() {
+ static thread_local ClassWithDtorForMainThread class_with_dtor_for_main_thread;
+ class_with_dtor_for_main_thread.set_message("d-tor for main thread called.");
+ exit(0);
+}
+
+TEST(thread_local, dtor_for_main_thread) {
+ ASSERT_EXIT(thread_atexit_main(), testing::ExitedWithCode(0), "d-tor for main thread called.");
+}
+
extern "C" int __cxa_thread_atexit_impl(void (*fn)(void*), void* arg, void* dso_handle);
static void thread_atexit_fn1(void* arg) {
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 691d8ff..a0b0209 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <atomic>
#include "ScopedSignalHandler.h"
@@ -197,7 +198,7 @@
ASSERT_EQ(0, timer_delete(timer_id));
}
-static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
+static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) {
++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
ASSERT_EQ(SIGUSR1, signal_number);
@@ -212,6 +213,7 @@
timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
+ timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler);
ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
@@ -228,25 +230,26 @@
}
struct Counter {
- volatile int value;
+ private:
+ std::atomic<int> value;
timer_t timer_id;
sigevent_t se;
bool timer_valid;
- Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) {
- memset(&se, 0, sizeof(se));
- se.sigev_notify = SIGEV_THREAD;
- se.sigev_notify_function = fn;
- se.sigev_value.sival_ptr = this;
- Create();
- }
-
void Create() {
ASSERT_FALSE(timer_valid);
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
timer_valid = true;
}
+ public:
+ Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) {
+ memset(&se, 0, sizeof(se));
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_notify_function = fn;
+ se.sigev_value.sival_ptr = this;
+ Create();
+ }
void DeleteTimer() {
ASSERT_TRUE(timer_valid);
ASSERT_EQ(0, timer_delete(timer_id));
@@ -259,12 +262,16 @@
}
}
+ int Value() const {
+ return value;
+ }
+
void SetTime(time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns);
}
bool ValueUpdated() {
- volatile int current_value = value;
+ int current_value = value;
time_t start = time(NULL);
while (current_value == value && (time(NULL) - start) < 5) {
}
@@ -287,30 +294,29 @@
TEST(time, timer_settime_0) {
Counter counter(Counter::CountAndDisarmNotifyFunction);
- ASSERT_TRUE(counter.timer_valid);
-
- ASSERT_EQ(0, counter.value);
+ ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 1, 0);
usleep(500000);
// The count should just be 1 because we disarmed the timer the first time it fired.
- ASSERT_EQ(1, counter.value);
+ ASSERT_EQ(1, counter.Value());
}
TEST(time, timer_settime_repeats) {
Counter counter(Counter::CountNotifyFunction);
- ASSERT_TRUE(counter.timer_valid);
-
- ASSERT_EQ(0, counter.value);
+ ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 0, 10);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
+ counter.DeleteTimer();
+ // Add a sleep as other threads may be calling the callback function when the timer is deleted.
+ usleep(500000);
}
-static int timer_create_NULL_signal_handler_invocation_count = 0;
+static int timer_create_NULL_signal_handler_invocation_count;
static void timer_create_NULL_signal_handler(int signal_number) {
++timer_create_NULL_signal_handler_invocation_count;
ASSERT_EQ(SIGALRM, signal_number);
@@ -321,6 +327,7 @@
timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
+ timer_create_NULL_signal_handler_invocation_count = 0;
ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler);
ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
@@ -367,22 +374,59 @@
TEST(time, timer_create_multiple) {
Counter counter1(Counter::CountNotifyFunction);
- ASSERT_TRUE(counter1.timer_valid);
Counter counter2(Counter::CountNotifyFunction);
- ASSERT_TRUE(counter2.timer_valid);
Counter counter3(Counter::CountNotifyFunction);
- ASSERT_TRUE(counter3.timer_valid);
- ASSERT_EQ(0, counter1.value);
- ASSERT_EQ(0, counter2.value);
- ASSERT_EQ(0, counter3.value);
+ ASSERT_EQ(0, counter1.Value());
+ ASSERT_EQ(0, counter2.Value());
+ ASSERT_EQ(0, counter3.Value());
counter2.SetTime(0, 1, 0, 0);
usleep(500000);
- EXPECT_EQ(0, counter1.value);
- EXPECT_EQ(1, counter2.value);
- EXPECT_EQ(0, counter3.value);
+ EXPECT_EQ(0, counter1.Value());
+ EXPECT_EQ(1, counter2.Value());
+ EXPECT_EQ(0, counter3.Value());
+}
+
+// Test to verify that disarming a repeatable timer disables the callbacks.
+TEST(time, timer_disarm_terminates) {
+ Counter counter(Counter::CountNotifyFunction);
+ ASSERT_EQ(0, counter.Value());
+
+ counter.SetTime(0, 1, 0, 1);
+ ASSERT_TRUE(counter.ValueUpdated());
+ ASSERT_TRUE(counter.ValueUpdated());
+ ASSERT_TRUE(counter.ValueUpdated());
+
+ counter.SetTime(0, 0, 0, 0);
+ // Add a sleep as the kernel may have pending events when the timer is disarmed.
+ usleep(500000);
+ int value = counter.Value();
+ usleep(500000);
+
+ // Verify the counter has not been incremented.
+ ASSERT_EQ(value, counter.Value());
+}
+
+// Test to verify that deleting a repeatable timer disables the callbacks.
+TEST(time, timer_delete_terminates) {
+ Counter counter(Counter::CountNotifyFunction);
+ ASSERT_EQ(0, counter.Value());
+
+ counter.SetTime(0, 1, 0, 1);
+ ASSERT_TRUE(counter.ValueUpdated());
+ ASSERT_TRUE(counter.ValueUpdated());
+ ASSERT_TRUE(counter.ValueUpdated());
+
+ counter.DeleteTimer();
+ // Add a sleep as other threads may be calling the callback function when the timer is deleted.
+ usleep(500000);
+ int value = counter.Value();
+ usleep(500000);
+
+ // Verify the counter has not been incremented.
+ ASSERT_EQ(value, counter.Value());
}
struct TimerDeleteData {
@@ -499,45 +543,3 @@
timespec out;
ASSERT_EQ(EINVAL, clock_nanosleep(-1, 0, &in, &out));
}
-
-// Test to verify that disarming a repeatable timer disables the
-// callbacks.
-TEST(time, timer_disarm_terminates) {
- Counter counter(Counter::CountNotifyFunction);
- ASSERT_TRUE(counter.timer_valid);
-
- ASSERT_EQ(0, counter.value);
-
- counter.SetTime(0, 1, 0, 1);
- ASSERT_TRUE(counter.ValueUpdated());
- ASSERT_TRUE(counter.ValueUpdated());
- ASSERT_TRUE(counter.ValueUpdated());
-
- counter.SetTime(0, 0, 1, 0);
- volatile int value = counter.value;
- usleep(500000);
-
- // Verify the counter has not been incremented.
- ASSERT_EQ(value, counter.value);
-}
-
-// Test to verify that deleting a repeatable timer disables the
-// callbacks.
-TEST(time, timer_delete_terminates) {
- Counter counter(Counter::CountNotifyFunction);
- ASSERT_TRUE(counter.timer_valid);
-
- ASSERT_EQ(0, counter.value);
-
- counter.SetTime(0, 1, 0, 1);
- ASSERT_TRUE(counter.ValueUpdated());
- ASSERT_TRUE(counter.ValueUpdated());
- ASSERT_TRUE(counter.ValueUpdated());
-
- counter.DeleteTimer();
- volatile int value = counter.value;
- usleep(500000);
-
- // Verify the counter has not been incremented.
- ASSERT_EQ(value, counter.value);
-}