Merge "Implement POSIX lockf."
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index c34daef..ab48fb8 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -108,3 +108,9 @@
 
   exit(slingshot(args.argc, args.argv, args.envp));
 }
+
+extern "C" uint32_t android_get_application_target_sdk_version();
+
+uint32_t bionic_get_application_target_sdk_version() {
+  return android_get_application_target_sdk_version();
+}
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 3cda1a2..d1494d7 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <android/api-level.h>
 #include <elf.h>
 #include <errno.h>
 #include <stddef.h>
@@ -106,3 +107,7 @@
 
   exit(slingshot(args.argc, args.argv, args.envp));
 }
+
+uint32_t bionic_get_application_target_sdk_version() {
+  return __ANDROID_API__;
+}
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index b30c0b0..1981647 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -41,6 +41,7 @@
 
 #include "private/bionic_constants.h"
 #include "private/bionic_futex.h"
+#include "private/bionic_sdk_version.h"
 #include "private/bionic_time_conversions.h"
 
 // In this implementation, a semaphore contains a
@@ -220,7 +221,13 @@
       return 0;
     }
 
-    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
+    int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
+    if (bionic_get_application_target_sdk_version() > 23) {
+      if (result ==-EINTR) {
+        errno = EINTR;
+        return -1;
+      }
+    }
   }
 }
 
diff --git a/libc/malloc_debug/Android.mk b/libc/malloc_debug/Android.mk
index 4c2c7f3..3eb0790 100644
--- a/libc/malloc_debug/Android.mk
+++ b/libc/malloc_debug/Android.mk
@@ -72,5 +72,6 @@
 LOCAL_CFLAGS := \
     -Wall \
     -Werror \
+    -Wno-error=format-zero-length \
 
 include $(BUILD_NATIVE_TEST)
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 0e8ca68..08731c2 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -111,14 +111,20 @@
 };
 
 MallocDispatch MallocDebugTest::dispatch = {
-  .calloc = calloc,
-  .free = free,
-  .mallinfo = mallinfo,
-  .malloc = malloc,
-  .malloc_usable_size = malloc_usable_size,
-  .memalign = memalign,
-  .posix_memalign = posix_memalign,
-  .realloc = realloc,
+  calloc,
+  free,
+  mallinfo,
+  malloc,
+  malloc_usable_size,
+  memalign,
+  posix_memalign,
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+  nullptr,
+#endif
+  realloc,
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+  nullptr,
+#endif
 };
 
 void VerifyAllocCalls() {
diff --git a/libc/private/bionic_sdk_version.h b/libc/private/bionic_sdk_version.h
new file mode 100644
index 0000000..871d25c
--- /dev/null
+++ b/libc/private/bionic_sdk_version.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_SDK_VERSION_H_
+#define _BIONIC_SDK_VERSION_H_
+
+#include <stdint.h>
+
+uint32_t bionic_get_application_target_sdk_version();
+
+#endif  // _BIONIC_SDK_VERSION_H_
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 84343da..7dc7225 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include "private/bionic_constants.h"
+#include "ScopedSignalHandler.h"
 
 TEST(semaphore, sem_init) {
   sem_t s;
@@ -158,3 +159,71 @@
   ASSERT_EQ(0, sem_getvalue(&s, &i));
   ASSERT_EQ(1, i);
 }
+
+extern "C" void android_set_application_target_sdk_version(uint32_t target);
+
+static void sem_wait_test_signal_handler(int) {
+}
+
+static void* SemWaitEINTRThreadFn(void* arg) {
+  sem_t* sem = reinterpret_cast<sem_t*>(arg);
+  uintptr_t have_eintr = 0;
+  uintptr_t have_error = 0;
+  while (true) {
+    int result = sem_wait(sem);
+    if (result == 0) {
+      break;
+    }
+    if (result == -1) {
+      if (errno == EINTR) {
+        have_eintr = 1;
+      } else {
+        have_error = 1;
+        break;
+      }
+    }
+  }
+  return reinterpret_cast<void*>((have_eintr << 1) | have_error);
+}
+
+TEST(semaphore, sem_wait_no_EINTR_in_sdk_less_equal_than_23) {
+#if defined(__BIONIC__)
+  android_set_application_target_sdk_version(23U);
+  sem_t s;
+  ASSERT_EQ(0, sem_init(&s, 0, 0));
+  ScopedSignalHandler handler(SIGUSR1, sem_wait_test_signal_handler);
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr, SemWaitEINTRThreadFn, &s));
+  // Give some time for the thread to run sem_wait.
+  usleep(500000);
+  ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
+  // Give some time for the thread to handle signal.
+  usleep(500000);
+  ASSERT_EQ(0, sem_post(&s));
+  void* result;
+  ASSERT_EQ(0, pthread_join(thread, &result));
+  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(result));
+#else
+  GTEST_LOG_(INFO) << "This test tests sem_wait's compatibility for old sdk versions";
+#endif
+}
+
+TEST(semaphore, sem_wait_EINTR_in_sdk_greater_than_23) {
+#if defined(__BIONIC__)
+  android_set_application_target_sdk_version(24U);
+#endif
+  sem_t s;
+  ASSERT_EQ(0, sem_init(&s, 0, 0));
+  ScopedSignalHandler handler(SIGUSR1, sem_wait_test_signal_handler);
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr, SemWaitEINTRThreadFn, &s));
+  // Give some time for the thread to run sem_wait.
+  usleep(500000);
+  ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
+  // Give some time for the thread to handle signal.
+  usleep(500000);
+  ASSERT_EQ(0, sem_post(&s));
+  void* result;
+  ASSERT_EQ(0, pthread_join(thread, &result));
+  ASSERT_EQ(2U, reinterpret_cast<uintptr_t>(result));
+}