Merge "Support _FILE_OFFSET_BITS=64 for most of <stdio.h>."
diff --git a/libc/Android.mk b/libc/Android.mk
index 0923939..bcb4afc 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -159,6 +159,7 @@
bionic/libgen.cpp \
bionic/link.cpp \
bionic/locale.cpp \
+ bionic/lockf.cpp \
bionic/lstat.cpp \
bionic/malloc_info.cpp \
bionic/mbrtoc16.cpp \
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/lockf.cpp b/libc/bionic/lockf.cpp
new file mode 100644
index 0000000..1510b3d
--- /dev/null
+++ b/libc/bionic/lockf.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 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:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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.
+ */
+
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+int lockf64(int fd, int cmd, off64_t length) {
+ // Translate POSIX lockf into fcntl.
+ struct flock fl;
+ memset(&fl, 0, sizeof(fl));
+ fl.l_whence = SEEK_CUR;
+ fl.l_start = 0;
+ fl.l_len = length;
+
+ if (cmd == F_ULOCK) {
+ fl.l_type = F_UNLCK;
+ cmd = F_SETLK64;
+ return fcntl(fd, F_SETLK64, &fl);
+ }
+
+ if (cmd == F_LOCK) {
+ fl.l_type = F_WRLCK;
+ return fcntl(fd, F_SETLKW64, &fl);
+ }
+
+ if (cmd == F_TLOCK) {
+ fl.l_type = F_WRLCK;
+ return fcntl(fd, F_SETLK64, &fl);
+ }
+
+ if (cmd == F_TEST) {
+ fl.l_type = F_RDLCK;
+ if (fcntl(fd, F_GETLK64, &fl) == -1) return -1;
+ if (fl.l_type == F_UNLCK || fl.l_pid == getpid()) return 0;
+ errno = EACCES;
+ return -1;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+int lockf(int fd, int cmd, off_t length) {
+ return lockf64(fd, cmd, length);
+}
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/include/machine/wchar_limits.h b/libc/include/bits/lockf.h
similarity index 77%
copy from libc/include/machine/wchar_limits.h
copy to libc/include/bits/lockf.h
index 94cbd7e..d814807 100644
--- a/libc/include/machine/wchar_limits.h
+++ b/libc/include/bits/lockf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,17 +26,25 @@
* SUCH DAMAGE.
*/
-#ifndef _MACHINE_WCHAR_LIMITS_H_
-#define _MACHINE_WCHAR_LIMITS_H_
+#ifndef _BITS_LOCKF_H_
+#define _BITS_LOCKF_H_
-/* Both GCC and clang define __WCHAR_MAX__. */
-#define WCHAR_MAX __WCHAR_MAX__
+#include <sys/cdefs.h>
-/* As of 3.4, clang still doesn't define __WCHAR_MIN__. */
-#if defined(__WCHAR_UNSIGNED__)
-# define WCHAR_MIN L'\0'
+#define F_ULOCK 0
+#define F_LOCK 1
+#define F_TLOCK 2
+#define F_TEST 3
+
+__BEGIN_DECLS
+
+#if defined(__USE_FILE_OFFSET64)
+int lockf(int, int, off_t) __RENAME(lockf64);
#else
-# define WCHAR_MIN (-(WCHAR_MAX) - 1)
+int lockf(int, int, off_t);
#endif
+int lockf64(int, int, off64_t);
-#endif /* _MACHINE_WCHAR_LIMITS_H_ */
+__END_DECLS
+
+#endif
diff --git a/libc/include/machine/posix_limits.h b/libc/include/bits/posix_limits.h
similarity index 98%
rename from libc/include/machine/posix_limits.h
rename to libc/include/bits/posix_limits.h
index 787af5c..31016a8 100644
--- a/libc/include/machine/posix_limits.h
+++ b/libc/include/bits/posix_limits.h
@@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
-#ifndef _POSIX_LIMITS_H_
-#define _POSIX_LIMITS_H_
+#ifndef _BITS_POSIX_LIMITS_H_
+#define _BITS_POSIX_LIMITS_H_
/* Any constant values here other than -1 or 200809L are explicitly specified by POSIX.1-2008. */
@@ -154,4 +154,4 @@
#define _XOPEN_SHM -1
#define _XOPEN_UNIX 1
-#endif /* _POSIX_LIMITS_H_ */
+#endif
diff --git a/libc/include/machine/pthread_types.h b/libc/include/bits/pthread_types.h
similarity index 93%
rename from libc/include/machine/pthread_types.h
rename to libc/include/bits/pthread_types.h
index 900541c..6ac1c68 100644
--- a/libc/include/machine/pthread_types.h
+++ b/libc/include/bits/pthread_types.h
@@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
-#ifndef _MACHINE_PTHREAD_TYPES_H_
-#define _MACHINE_PTHREAD_TYPES_H_
+#ifndef _BITS_PTHREAD_TYPES_H_
+#define _BITS_PTHREAD_TYPES_H_
#include <sys/types.h>
@@ -45,4 +45,4 @@
#endif
} pthread_attr_t;
-#endif /* _MACHINE_PTHREAD_TYPES_H_ */
+#endif
diff --git a/libc/include/machine/timespec.h b/libc/include/bits/timespec.h
similarity index 94%
rename from libc/include/machine/timespec.h
rename to libc/include/bits/timespec.h
index 11779ae..046d898 100644
--- a/libc/include/machine/timespec.h
+++ b/libc/include/bits/timespec.h
@@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
-#ifndef _MACHINE_TIMESPEC_H_
-#define _MACHINE_TIMESPEC_H_
+#ifndef _BITS_TIMESPEC_H_
+#define _BITS_TIMESPEC_H_
#include <sys/types.h>
@@ -43,4 +43,4 @@
};
#endif
-#endif /* _MACHINE_TIMESPEC_H_ */
+#endif
diff --git a/libc/include/machine/wchar_limits.h b/libc/include/bits/wchar_limits.h
similarity index 93%
rename from libc/include/machine/wchar_limits.h
rename to libc/include/bits/wchar_limits.h
index 94cbd7e..f779c1a 100644
--- a/libc/include/machine/wchar_limits.h
+++ b/libc/include/bits/wchar_limits.h
@@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
-#ifndef _MACHINE_WCHAR_LIMITS_H_
-#define _MACHINE_WCHAR_LIMITS_H_
+#ifndef _BITS_WCHAR_LIMITS_H_
+#define _BITS_WCHAR_LIMITS_H_
/* Both GCC and clang define __WCHAR_MAX__. */
#define WCHAR_MAX __WCHAR_MAX__
@@ -39,4 +39,4 @@
# define WCHAR_MIN (-(WCHAR_MAX) - 1)
#endif
-#endif /* _MACHINE_WCHAR_LIMITS_H_ */
+#endif
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 0f016d7..6e2ad51 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -36,6 +36,10 @@
#include <linux/stat.h>
#include <linux/uio.h>
+#if defined(__USE_GNU) || defined(__USE_BSD)
+#include <bits/lockf.h>
+#endif
+
__BEGIN_DECLS
#ifdef __LP64__
diff --git a/libc/include/limits.h b/libc/include/limits.h
index 67c7719..342217b 100644
--- a/libc/include/limits.h
+++ b/libc/include/limits.h
@@ -84,7 +84,7 @@
#define SEM_VALUE_MAX 0x3fffffff
/* POSIX says these belong in <unistd.h> but BSD has some in <limits.h>. */
-#include <machine/posix_limits.h>
+#include <bits/posix_limits.h>
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
#endif /* !_LIMITS_H_ */
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 21d34fb..50f2024 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -30,7 +30,7 @@
#define _PTHREAD_H_
#include <limits.h>
-#include <machine/pthread_types.h>
+#include <bits/pthread_types.h>
#include <sched.h>
#include <sys/cdefs.h>
#include <sys/types.h>
diff --git a/libc/include/sched.h b/libc/include/sched.h
index 930dd7c..0b9235b 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -28,8 +28,8 @@
#ifndef _SCHED_H_
#define _SCHED_H_
+#include <bits/timespec.h>
#include <linux/sched.h>
-#include <machine/timespec.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 7a171b4..85c46c0 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -30,9 +30,9 @@
#define _SIGNAL_H_
#include <asm/sigcontext.h>
+#include <bits/pthread_types.h>
+#include <bits/timespec.h>
#include <limits.h>
-#include <machine/pthread_types.h>
-#include <machine/timespec.h>
#include <sys/cdefs.h>
#include <sys/types.h>
diff --git a/libc/include/stdint.h b/libc/include/stdint.h
index a6f8505..a66e21e 100644
--- a/libc/include/stdint.h
+++ b/libc/include/stdint.h
@@ -29,8 +29,8 @@
#ifndef _STDINT_H
#define _STDINT_H
+#include <bits/wchar_limits.h>
#include <stddef.h>
-#include <machine/wchar_limits.h>
typedef __signed char __int8_t;
typedef unsigned char __uint8_t;
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index 65aa190..257ded0 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -29,8 +29,8 @@
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_
+#include <bits/timespec.h>
#include <linux/stat.h>
-#include <machine/timespec.h>
#include <sys/cdefs.h>
#include <sys/types.h>
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 23b47a3..5045267 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -35,7 +35,8 @@
#include <sys/select.h>
#include <sys/sysconf.h>
-#include <machine/posix_limits.h>
+#include <bits/lockf.h>
+#include <bits/posix_limits.h>
__BEGIN_DECLS
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index ea6aca0..0a94cee 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -36,7 +36,7 @@
#include <time.h>
#include <xlocale.h>
-#include <machine/wchar_limits.h>
+#include <bits/wchar_limits.h>
__BEGIN_DECLS
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 9c31f8f..d8d5033 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1238,6 +1238,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index adb7a65..df8030f 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1238,6 +1238,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index a3308bd..838a978 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1162,6 +1162,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
pthread_barrierattr_destroy;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 3ebb4ab..9317f81 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1265,6 +1265,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index a5b5376..683fb24 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1223,6 +1223,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 5b2cc3d..f72d84f 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1223,6 +1223,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index a3308bd..838a978 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1162,6 +1162,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
pthread_barrierattr_destroy;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index c28d35a..090d5c5 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1222,6 +1222,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 37fbba1..f3bda0b 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1222,6 +1222,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
prlimit; # arm mips x86
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index a3308bd..838a978 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1162,6 +1162,8 @@
getifaddrs;
if_freenameindex;
if_nameindex;
+ lockf;
+ lockf64;
preadv;
preadv64;
pthread_barrierattr_destroy;
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));
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 5f412ce..5ef54a4 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -872,3 +872,132 @@
ASSERT_EQ(-1, dup2(fd, fd));
ASSERT_EQ(EBADF, errno);
}
+
+static void WaitForChildExit() {
+ int status;
+ wait(&status);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(UNISTD_TEST, lockf_smoke) {
+ constexpr off64_t file_size = 32*1024LL;
+
+ TemporaryFile tf;
+ ASSERT_EQ(0, ftruncate(tf.fd, file_size));
+
+ // Lock everything.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size));
+
+ // Try-lock everything, this should succeed too.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size));
+
+ // Check status.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TEST, file_size));
+
+ // Unlock file.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_ULOCK, file_size));
+}
+
+TEST(UNISTD_TEST, lockf_zero) {
+ constexpr off64_t file_size = 32*1024LL;
+
+ TemporaryFile tf;
+ ASSERT_EQ(0, ftruncate(tf.fd, file_size));
+
+ // Lock everything by specifying a size of 0 (meaning "to the end, even if it changes").
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, 0));
+
+ // Check that it's locked.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TEST, file_size));
+
+ // Move the end.
+ ASSERT_EQ(0, ftruncate(tf.fd, 2*file_size));
+
+ // Check that the new section is locked too.
+ ASSERT_EQ(file_size, lseek64(tf.fd, file_size, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TEST, 2*file_size));
+}
+
+TEST(UNISTD_TEST, lockf_negative) {
+ constexpr off64_t file_size = 32*1024LL;
+
+ TemporaryFile tf;
+ ASSERT_EQ(0, ftruncate(tf.fd, file_size));
+
+ // Lock everything, but specifying the range in reverse.
+ ASSERT_EQ(file_size, lseek64(tf.fd, file_size, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, -file_size));
+
+ // Check that it's locked.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TEST, file_size));
+}
+
+TEST(UNISTD_TEST, lockf_with_child) {
+ constexpr off64_t file_size = 32*1024LL;
+
+ TemporaryFile tf;
+ ASSERT_EQ(0, ftruncate(tf.fd, file_size));
+
+ // Lock everything.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size));
+
+ // Fork a child process
+ pid_t pid = fork();
+ ASSERT_NE(-1, pid);
+ if (pid == 0) {
+ // Check that the child cannot lock the file.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(-1, lockf64(tf.fd, F_TLOCK, file_size));
+ ASSERT_EQ(EAGAIN, errno);
+ // Check also that it reports itself as locked.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size));
+ ASSERT_EQ(EACCES, errno);
+ _exit(0);
+ }
+ WaitForChildExit();
+}
+
+TEST(UNISTD_TEST, lockf_partial_with_child) {
+ constexpr off64_t file_size = 32*1024LL;
+
+ TemporaryFile tf;
+ ASSERT_EQ(0, ftruncate(tf.fd, file_size));
+
+ // Lock the first half of the file.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size/2));
+
+ // Fork a child process.
+ pid_t pid = fork();
+ ASSERT_NE(-1, pid);
+ if (pid == 0) {
+ // Check that the child can lock the other half.
+ ASSERT_EQ(file_size/2, lseek64(tf.fd, file_size/2, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size/2));
+ // Check that the child cannot lock the first half.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
+ ASSERT_EQ(EACCES, errno);
+ // Check also that it reports itself as locked.
+ ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
+ ASSERT_EQ(EACCES, errno);
+ _exit(0);
+ }
+ WaitForChildExit();
+
+ // The second half was locked by the child, but the lock disappeared
+ // when the process exited, so check it can be locked now.
+ ASSERT_EQ(file_size/2, lseek64(tf.fd, file_size/2, SEEK_SET));
+ ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size/2));
+}