aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2011-09-30 03:45:16 +0200
committerDavid 'Digit' Turner <digit@google.com>2011-09-30 16:12:11 +0200
commit26cc9e3109d9df4dd7726edcb02982c26c207d20 (patch)
tree9e12425e9740d07639ba35f32244d2b04292f567
parent1322b9f426ef6aca8b6ce569411cdd3443c1caf4 (diff)
downloadndk-26cc9e3109d9df4dd7726edcb02982c26c207d20.tar.gz
GAbi++: Add one time construction support
This patch adds sources/cxx-stl/gabi++/src/one_time_construction.cc and removes the dependency on libstdc++ from GAbi++ The implementation is based on pthread which is always provided by the C library on Android (the latter is always linked to generated binaries, so there is no need to list it in LOCAL_EXPORT_LDLIBS). + Add unit test to check that one-time-construction works properly. Change-Id: Ic4af9f19814cf9efd7caa60bc84e9c03fc4bf656
-rwxr-xr-xbuild/tools/build-gabi++.sh2
-rwxr-xr-xbuild/tools/build-stlport.sh2
-rw-r--r--sources/cxx-stl/gabi++/Android.mk4
-rw-r--r--sources/cxx-stl/gabi++/sources.mk1
-rw-r--r--sources/cxx-stl/gabi++/src/one_time_construction.cc115
-rw-r--r--tests/device/test-gabi++-guard/jni/Android.mk6
-rw-r--r--tests/device/test-gabi++-guard/jni/Application.mk3
-rw-r--r--tests/device/test-gabi++-guard/jni/test_guard.cpp76
8 files changed, 203 insertions, 6 deletions
diff --git a/build/tools/build-gabi++.sh b/build/tools/build-gabi++.sh
index 9d1d68040..f5c4a702b 100755
--- a/build/tools/build-gabi++.sh
+++ b/build/tools/build-gabi++.sh
@@ -96,7 +96,7 @@ GABIXX_SRCDIR=$ANDROID_NDK_ROOT/$GABIXX_SUBDIR
GABIXX_CFLAGS="-fPIC -O2 -DANDROID -D__ANDROID__"
GABIXX_CFLAGS=$GABIXX_CFLAGS" -I$GABIXX_SRCDIR/include"
GABIXX_CXXFLAGS="-fuse-cxa-atexit -fno-exceptions -frtti"
-GABIXX_LDFLAGS="-lstdc++"
+GABIXX_LDFLAGS=
# List of sources to compile
GABIXX_SOURCES=$(cd $GABIXX_SUBDIR && ls src/*.cc)
diff --git a/build/tools/build-stlport.sh b/build/tools/build-stlport.sh
index 37544fe29..d5a04ef2a 100755
--- a/build/tools/build-stlport.sh
+++ b/build/tools/build-stlport.sh
@@ -93,7 +93,7 @@ GABIXX_SRCDIR=$ANDROID_NDK_ROOT/$GABIXX_SUBDIR
GABIXX_CFLAGS="-O2 -DANDROID -D__ANDROID__ -I$GABIXX_SRCDIR/include"
GABIXX_CXXFLAGS="-fno-exceptions -frtti"
GABIXX_SOURCES=$(cd $ANDROID_NDK_ROOT/$GABIXX_SUBDIR && ls src/*.cc)
-GABIXX_LDFLAGS="-lstdc++"
+GABIXX_LDFLAGS=
# Location of the STLPort source tree
STLPORT_SRCDIR=$ANDROID_NDK_ROOT/$STLPORT_SUBDIR
diff --git a/sources/cxx-stl/gabi++/Android.mk b/sources/cxx-stl/gabi++/Android.mk
index a4a1fed5e..09333dc9c 100644
--- a/sources/cxx-stl/gabi++/Android.mk
+++ b/sources/cxx-stl/gabi++/Android.mk
@@ -8,7 +8,6 @@ ifeq (,$(GABIXX_FORCE_REBUILD))
LOCAL_MODULE:= gabi++_shared
LOCAL_SRC_FILES:= libs/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).so
LOCAL_EXPORT_C_INCLUDES := $(libgabi++_c_includes)
- LOCAL_EXPORT_LDLIBS := -lstdc++
LOCAL_CPP_FEATURES := rtti
include $(PREBUILT_SHARED_LIBRARY)
@@ -16,7 +15,6 @@ ifeq (,$(GABIXX_FORCE_REBUILD))
LOCAL_MODULE:= gabi++_static
LOCAL_SRC_FILES:= libs/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
LOCAL_EXPORT_C_INCLUDES := $(libgabi++_c_includes)
- LOCAL_EXPORT_LDLIBS := -lstdc++
LOCAL_CPP_FEATURES := rtti
include $(PREBUILT_STATIC_LIBRARY)
@@ -31,7 +29,6 @@ else # ! GABIXX_FORCE_REBUILD
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES:= $(libgabi++_src_files)
LOCAL_EXPORT_C_INCLUDES := $(libgabi++_c_includes)
- LOCAL_EXPORT_LDLIBS := -lstdc++
LOCAL_C_INCLUDES := $(libgabi++_c_includes)
LOCAL_CPP_FEATURES := rtti
include $(BUILD_SHARED_LIBRARY)
@@ -43,7 +40,6 @@ else # ! GABIXX_FORCE_REBUILD
LOCAL_SRC_FILES:= $(libgabi++_src_files)
LOCAL_CPP_EXTENSION := .cc
LOCAL_EXPORT_C_INCLUDES := $(libgabi++_c_includes)
- LOCAL_EXPORT_LDLIBS := -lstdc++
LOCAL_C_INCLUDES := $(libgabi++_c_includes)
LOCAL_CPP_FEATURES := rtti
include $(BUILD_STATIC_LIBRARY)
diff --git a/sources/cxx-stl/gabi++/sources.mk b/sources/cxx-stl/gabi++/sources.mk
index bc419f2d8..8210ee7e6 100644
--- a/sources/cxx-stl/gabi++/sources.mk
+++ b/sources/cxx-stl/gabi++/sources.mk
@@ -8,6 +8,7 @@ libgabi++_src_files := \
src/enum_type_info.cc \
src/function_type_info.cc \
src/new.cc \
+ src/one_time_construction.cc \
src/pbase_type_info.cc \
src/pointer_type_info.cc \
src/pointer_to_member_type_info.cc \
diff --git a/sources/cxx-stl/gabi++/src/one_time_construction.cc b/sources/cxx-stl/gabi++/src/one_time_construction.cc
new file mode 100644
index 000000000..c0b54be7c
--- /dev/null
+++ b/sources/cxx-stl/gabi++/src/one_time_construction.cc
@@ -0,0 +1,115 @@
+// Copyright (C) 2011 The Android Open Source Project
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the project nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// One-time construction C++ runtime support
+// See "3.3.2 One-time Construction API" of the Itanium C++ ABI reference
+// And "3.2.3 Guard variables and the one-time construction API" in the ARM C++ ABI reference.
+
+/* Note that the ARM C++ ABI defines the size of each guard variable
+ * as 32-bit, while the generic/Itanium one defines it as 64-bit.
+ *
+ * Also the ARM C++ ABI uses the least-significant bit to indicate
+ * completion, while the generic/Itanium one uses the least-significant
+ * byte. In all cases the corresponding item is set to value '1'
+ *
+ * We will treat guard variables here as 32-bit values, even on x86,
+ * given that this representation is compatible with compiler-generated
+ * variables that are 64-bits on little-endian systems. This makes the
+ * code simpler and slightly more efficient
+ */
+
+#include <stddef.h>
+#include <pthread.h>
+
+/* In this implementation, we use a single global mutex+condvar pair.
+ *
+ * Pros: portable and doesn't require playing with futexes, atomics
+ * and memory barriers.
+ *
+ * Cons: Slower than necessary.
+ */
+static pthread_mutex_t sMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+static pthread_cond_t sCond = PTHREAD_COND_INITIALIZER;
+
+
+extern "C" int __cxa_guard_acquire(int volatile * gv)
+{
+ pthread_mutex_lock(&sMutex);
+ for (;;) {
+ // while gv points to a volatile value, we use the
+ // previous pthread_mutex_lock or pthread_cond_wait
+ // as a trivial memory barrier
+ int guard = *gv;
+ if ((guard & 1) != 0) {
+ /* already initialized - return 0 */
+ pthread_mutex_unlock(&sMutex);
+ return 0;
+ }
+
+ // we use bit 8 to indicate that the guard value is being
+ // initialized, and bit 9 to indicate that there is another
+ // thread waiting for its completion.
+ if ((guard & 0x100) == 0) {
+ // nobody is initializing this yet, so mark the guard value
+ // first. and allow initialization to proceed.
+ *gv = 0x100;
+ pthread_mutex_unlock(&sMutex);
+ return 1;
+ }
+
+ // already being initialized by amother thread,
+ // we must indicate that there is a waiter, then
+ // wait to be woken up before trying again.
+ *gv = guard | 0x200;
+ pthread_cond_wait(&sCond, &sMutex);
+ }
+}
+
+extern "C" void __cxa_guard_release(int volatile * gv)
+{
+ pthread_mutex_lock(&sMutex);
+
+ int guard = *gv;
+ // this indicates initialization for our two ABIs.
+ *gv = 0x1;
+ if ((guard & 0x200) != 0)
+ pthread_cond_broadcast(&sCond);
+
+ pthread_mutex_unlock(&sMutex);
+}
+
+extern "C" void __cxa_guard_abort(int volatile * gv)
+{
+ pthread_mutex_lock(&sMutex);
+
+ int guard = *gv;
+ *gv = 0;
+ if ((guard & 0x200) != 0)
+ pthread_cond_broadcast(&sCond);
+
+ pthread_mutex_unlock(&sMutex);
+}
diff --git a/tests/device/test-gabi++-guard/jni/Android.mk b/tests/device/test-gabi++-guard/jni/Android.mk
new file mode 100644
index 000000000..5287f5e3a
--- /dev/null
+++ b/tests/device/test-gabi++-guard/jni/Android.mk
@@ -0,0 +1,6 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_guard_variables
+LOCAL_SRC_FILES := test_guard.cpp
+include $(BUILD_EXECUTABLE)
diff --git a/tests/device/test-gabi++-guard/jni/Application.mk b/tests/device/test-gabi++-guard/jni/Application.mk
new file mode 100644
index 000000000..4ae2f6520
--- /dev/null
+++ b/tests/device/test-gabi++-guard/jni/Application.mk
@@ -0,0 +1,3 @@
+APP_STL := gabi++_shared
+APP_ABI := all
+
diff --git a/tests/device/test-gabi++-guard/jni/test_guard.cpp b/tests/device/test-gabi++-guard/jni/test_guard.cpp
new file mode 100644
index 000000000..047d6ac33
--- /dev/null
+++ b/tests/device/test-gabi++-guard/jni/test_guard.cpp
@@ -0,0 +1,76 @@
+/* This program is used to test that one-time-construction
+ * works correctly, even in the presence of several threads.
+ */
+
+#include <new>
+#include <pthread.h>
+#include <stdio.h>
+
+#define MAX_THREADS 100
+
+class Foo {
+public:
+ Foo() { mValue++; }
+ int getValue() { return mValue; }
+private:
+ static int mValue;
+};
+
+int Foo::mValue;
+
+static Foo* getInstance(void)
+{
+ // This construct forces the static creation of _instance
+ // the first time that getInstance() is called, in a thread-safe
+ // way.
+ static Foo _instance;
+ return &_instance;
+}
+
+static Foo* sInstances[MAX_THREADS];
+static pthread_t sThreads[MAX_THREADS];
+
+static void* thread_run(void* arg)
+{
+ int index = reinterpret_cast<int>(arg);
+ sInstances[index] = getInstance();
+ return NULL;
+}
+
+int main(void)
+{
+ /* Create all the threads */
+ for (int nn = 0; nn < MAX_THREADS; nn++) {
+ pthread_create( &sThreads[nn], NULL, thread_run, reinterpret_cast<void*>(nn) );
+ }
+ /* Wait for their completion */
+ for (int nn = 0; nn < MAX_THREADS; nn++) {
+ void* dummy;
+ pthread_join( sThreads[nn], &dummy );
+ }
+ /* Get the instance */
+ Foo* foo = getInstance();
+
+ if (foo == NULL) {
+ fprintf(stderr, "ERROR: Foo instance is NULL!\n");
+ return 1;
+ }
+
+ if (foo->getValue() != 1) {
+ fprintf(stderr, "ERROR: Foo constructor called %d times (1 expected)\n",
+ foo->getValue());
+ return 2;
+ }
+
+ int count = 0;
+ for (int nn = 0; nn < MAX_THREADS; nn++) {
+ if (sInstances[nn] != foo)
+ count++;
+ }
+
+ if (count != 0) {
+ fprintf(stderr, "ERROR: There are %d invalid instance pointers!\n", count);
+ return 3;
+ }
+ return 0;
+}