[libc-commits] [libc] [libc] Implement lockf in unistd (#230856) (PR #231145)
Aman Maurya via libc-commits
libc-commits at lists.llvm.org
Tue Oct 13 08:00:11 PDT 2026
https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/231145
>From 82bd60345cd1e132cd5f3c9bcf6f29bd0f82dd7b Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Mon, 12 Oct 2026 18:00:51 +0530
Subject: [PATCH 1/2] [libc] Implement lockf in unistd (#230856)
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/arm/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/hdr/CMakeLists.txt | 1 +
libc/hdr/unistd_macros.h | 1 +
.../llvm-libc-macros/linux/unistd-macros.h | 6 +
libc/include/unistd.yaml | 16 +++
libc/src/unistd/CMakeLists.txt | 7 ++
libc/src/unistd/linux/CMakeLists.txt | 19 ++++
libc/src/unistd/linux/lockf.cpp | 81 ++++++++++++++
libc/src/unistd/lockf.h | 26 +++++
libc/test/src/unistd/CMakeLists.txt | 19 ++++
libc/test/src/unistd/lockf_test.cpp | 103 ++++++++++++++++++
14 files changed, 283 insertions(+)
create mode 100644 libc/src/unistd/linux/lockf.cpp
create mode 100644 libc/src/unistd/lockf.h
create mode 100644 libc/test/src/unistd/lockf_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b76cc76c30bcde..38c6166dca757d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -486,6 +486,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.isatty
libc.src.unistd.link
libc.src.unistd.linkat
+ libc.src.unistd.lockf
libc.src.unistd.lseek
libc.src.unistd.nice
libc.src.unistd.pathconf
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 4e535fe5111d67..4438d0de335912 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -282,6 +282,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.isatty
libc.src.unistd.link
libc.src.unistd.linkat
+ libc.src.unistd.lockf
libc.src.unistd.lseek
libc.src.unistd.nice
libc.src.unistd.pause
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 0a0932bcb3e426..4399c0514fcfbb 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -506,6 +506,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.isatty
libc.src.unistd.link
libc.src.unistd.linkat
+ libc.src.unistd.lockf
libc.src.unistd.lseek
libc.src.unistd.nice
libc.src.unistd.pathconf
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 85bb01f416219e..026648e21438fb 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -526,6 +526,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.isatty
libc.src.unistd.link
libc.src.unistd.linkat
+ libc.src.unistd.lockf
libc.src.unistd.lseek
libc.src.unistd.nice
libc.src.unistd.pathconf
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index cf8b1f36d349ec..10ac84340523d2 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -320,6 +320,7 @@ add_proxy_header_library(
DEPENDS
.unistd_overlay
FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-macros.file_seek_macros
libc.include.llvm-libc-macros.unistd_macros
)
diff --git a/libc/hdr/unistd_macros.h b/libc/hdr/unistd_macros.h
index bda16224608bf6..b1a63b2dd1e7d2 100644
--- a/libc/hdr/unistd_macros.h
+++ b/libc/hdr/unistd_macros.h
@@ -11,6 +11,7 @@
#ifdef LIBC_FULL_BUILD
+#include "include/llvm-libc-macros/file-seek-macros.h"
#include "include/llvm-libc-macros/unistd-macros.h"
#else // Overlay mode
diff --git a/libc/include/llvm-libc-macros/linux/unistd-macros.h b/libc/include/llvm-libc-macros/linux/unistd-macros.h
index 0a9facd82fcb22..e14d44960de0e5 100644
--- a/libc/include/llvm-libc-macros/linux/unistd-macros.h
+++ b/libc/include/llvm-libc-macros/linux/unistd-macros.h
@@ -20,6 +20,12 @@
#define W_OK 2
#define R_OK 4
+// Values for command argument to the lockf(...) function.
+#define F_ULOCK 0
+#define F_LOCK 1
+#define F_TLOCK 2
+#define F_TEST 3
+
#define _SC_ARG_MAX 0
#define _SC_CLK_TCK 2
#define _SC_OPEN_MAX 4
diff --git a/libc/include/unistd.yaml b/libc/include/unistd.yaml
index 160b909f3af7b4..3f7a362fa5def4 100644
--- a/libc/include/unistd.yaml
+++ b/libc/include/unistd.yaml
@@ -88,6 +88,14 @@ macros:
macro_header: unistd-macros.h
- macro_name: _POSIX_THREAD_SPORADIC_SERVER
macro_header: unistd-macros.h
+ - macro_name: F_ULOCK
+ macro_header: unistd-macros.h
+ - macro_name: F_LOCK
+ macro_header: unistd-macros.h
+ - macro_name: F_TLOCK
+ macro_header: unistd-macros.h
+ - macro_name: F_TEST
+ macro_header: unistd-macros.h
types:
- type_name: uid_t
- type_name: gid_t
@@ -414,6 +422,14 @@ functions:
- type: int
- type: const char *
- type: int
+ - name: lockf
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: int
+ - type: int
+ - type: off_t
- name: lseek
standards:
- posix
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 795224f0e9df48..91a6b55c28aefe 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -294,6 +294,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.linkat
)
+add_entrypoint_object(
+ lockf
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.lockf
+)
+
add_entrypoint_object(
lseek
ALIAS
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 3624f4e1891f2f..6921a468e295d0 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -482,6 +482,25 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ lockf
+ SRCS
+ lockf.cpp
+ HDRS
+ ../lockf.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fcntl_macros
+ libc.hdr.types.off_t
+ libc.hdr.types.struct_flock
+ libc.hdr.unistd_macros
+ libc.src.__support.OSUtil.linux.syscall_wrappers.fcntl
+ libc.src.__support.OSUtil.linux.syscall_wrappers.getpid
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+)
+
add_entrypoint_object(
lseek
SRCS
diff --git a/libc/src/unistd/linux/lockf.cpp b/libc/src/unistd/linux/lockf.cpp
new file mode 100644
index 00000000000000..ecfed291ab59ef
--- /dev/null
+++ b/libc/src/unistd/linux/lockf.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of lockf.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/lockf.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/fcntl_macros.h"
+#include "hdr/types/off_t.h"
+#include "hdr/types/struct_flock.h"
+#include "hdr/unistd_macros.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getpid.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, lockf, (int fd, int cmd, off_t len)) {
+ struct flock fl = {};
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_CUR;
+ fl.l_start = 0;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ switch (cmd) {
+ case F_TEST: {
+ fl.l_type = F_RDLCK;
+ auto result = linux_syscalls::fcntl(fd, F_GETLK, &fl);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+ if (fl.l_type == F_UNLCK || fl.l_pid == linux_syscalls::getpid())
+ return 0;
+ libc_errno = EACCES;
+ return -1;
+ }
+ case F_ULOCK: {
+ fl.l_type = F_UNLCK;
+ auto result = linux_syscalls::fcntl(fd, F_SETLK, &fl);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return 0;
+ }
+ case F_LOCK: {
+ auto result = linux_syscalls::fcntl(fd, F_SETLKW, &fl);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return 0;
+ }
+ case F_TLOCK: {
+ auto result = linux_syscalls::fcntl(fd, F_SETLK, &fl);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return 0;
+ }
+ default:
+ libc_errno = EINVAL;
+ return -1;
+ }
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/unistd/lockf.h b/libc/src/unistd/lockf.h
new file mode 100644
index 00000000000000..27a9949753fe5a
--- /dev/null
+++ b/libc/src/unistd/lockf.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for lockf.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_LOCKF_H
+#define LLVM_LIBC_SRC_UNISTD_LOCKF_H
+
+#include "hdr/types/off_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int lockf(int fd, int cmd, off_t len);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_UNISTD_LOCKF_H
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index 89d6dcece5e108..bab290eccccfa3 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -972,6 +972,25 @@ add_libc_test(
libc.test.UnitTest.ErrnoSetterMatcher
)
+add_libc_test(
+ lockf_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ lockf_test.cpp
+ DEPENDS
+ libc.hdr.fcntl_macros
+ libc.hdr.sys_stat_macros
+ libc.hdr.unistd_macros
+ libc.src.errno.errno
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.lockf
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
if(LLVM_LIBC_FULL_BUILD)
add_libc_test(
_exit_test
diff --git a/libc/test/src/unistd/lockf_test.cpp b/libc/test/src/unistd/lockf_test.cpp
new file mode 100644
index 00000000000000..a2b14c6e6ad863
--- /dev/null
+++ b/libc/test/src/unistd/lockf_test.cpp
@@ -0,0 +1,103 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittest for lockf.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/fcntl_macros.h"
+#include "hdr/sys_stat_macros.h"
+#include "hdr/unistd_macros.h"
+#include "src/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/lockf.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcLockfTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcLockfTest, BadFd) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(-1, F_LOCK, 0), Fails(EBADF));
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(-1, F_TLOCK, 0), Fails(EBADF));
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(-1, F_ULOCK, 0), Fails(EBADF));
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(-1, F_TEST, 0), Fails(EBADF));
+}
+
+TEST_F(LlvmLibcLockfTest, InvalidCmd) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE_NAME = "testdata/lockf_invalid_cmd.test";
+ auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, 999, 0), Fails(EINVAL));
+
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+}
+
+TEST_F(LlvmLibcLockfTest, LockUnlockAndTest) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE_NAME = "testdata/lockf_basic.test";
+ auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+
+ // Section is not locked: F_TEST should succeed (return 0).
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_TEST, 0), Succeeds(0));
+
+ // Lock the entire file: F_LOCK should succeed.
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_LOCK, 0), Succeeds(0));
+
+ // When locked by calling process, F_TEST still succeeds (POSIX requirement).
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_TEST, 0), Succeeds(0));
+
+ // Unlock the entire file: F_ULOCK should succeed.
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_ULOCK, 0), Succeeds(0));
+
+ // Non-blocking lock: F_TLOCK should succeed.
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_TLOCK, 100), Succeeds(0));
+
+ // Unlock the section: F_ULOCK should succeed.
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_ULOCK, 100), Succeeds(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+}
+
+TEST_F(LlvmLibcLockfTest, ReadOnlyFd) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE_NAME = "testdata/lockf_rdonly.test";
+ auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
+
+ // Create the file first so we can open it read-only.
+ int create_fd =
+ LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(create_fd, 0);
+ EXPECT_THAT(LIBC_NAMESPACE::close(create_fd), Succeeds(0));
+
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_RDONLY, 0);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+
+ // F_LOCK on a read-only fd should fail with EBADF.
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_LOCK, 0), Fails(EBADF));
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_TLOCK, 0), Fails(EBADF));
+
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+}
>From 1406f52da0babd5aa56587a0bc2666064b04c734 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Tue, 13 Oct 2026 20:20:37 +0530
Subject: [PATCH 2/2] [libc] Address review feedback on lockf (#230856)
---
libc/src/unistd/linux/CMakeLists.txt | 1 +
libc/src/unistd/linux/lockf.cpp | 60 +++++++--------
.../integration/src/unistd/CMakeLists.txt | 22 ++++++
.../integration/src/unistd/lockf_test.cpp | 74 +++++++++++++++++++
libc/test/src/unistd/CMakeLists.txt | 1 +
libc/test/src/unistd/lockf_test.cpp | 34 ++++-----
6 files changed, 141 insertions(+), 51 deletions(-)
create mode 100644 libc/test/integration/src/unistd/lockf_test.cpp
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 6921a468e295d0..27d9cf9d9cec54 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -497,6 +497,7 @@ add_entrypoint_object(
libc.src.__support.OSUtil.linux.syscall_wrappers.fcntl
libc.src.__support.OSUtil.linux.syscall_wrappers.getpid
libc.src.__support.common
+ libc.src.__support.error_or
libc.src.__support.libc_errno
libc.src.__support.macros.config
)
diff --git a/libc/src/unistd/linux/lockf.cpp b/libc/src/unistd/linux/lockf.cpp
index ecfed291ab59ef..81dcb52fdcb104 100644
--- a/libc/src/unistd/linux/lockf.cpp
+++ b/libc/src/unistd/linux/lockf.cpp
@@ -21,61 +21,53 @@
#include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/getpid.h"
#include "src/__support/common.h"
+#include "src/__support/error_or.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(int, lockf, (int fd, int cmd, off_t len)) {
+namespace {
+
+LIBC_INLINE ErrorOr<int> lockf_impl(int fd, int cmd, off_t len) {
struct flock fl = {};
- fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
fl.l_start = 0;
fl.l_len = len;
- fl.l_pid = 0;
switch (cmd) {
case F_TEST: {
fl.l_type = F_RDLCK;
auto result = linux_syscalls::fcntl(fd, F_GETLK, &fl);
- if (!result.has_value()) {
- libc_errno = result.error();
- return -1;
- }
+ if (!result.has_value())
+ return Error(result.error());
if (fl.l_type == F_UNLCK || fl.l_pid == linux_syscalls::getpid())
return 0;
- libc_errno = EACCES;
- return -1;
+ return Error(EACCES);
}
- case F_ULOCK: {
+ case F_ULOCK:
fl.l_type = F_UNLCK;
- auto result = linux_syscalls::fcntl(fd, F_SETLK, &fl);
- if (!result.has_value()) {
- libc_errno = result.error();
- return -1;
- }
- return 0;
- }
- case F_LOCK: {
- auto result = linux_syscalls::fcntl(fd, F_SETLKW, &fl);
- if (!result.has_value()) {
- libc_errno = result.error();
- return -1;
- }
- return 0;
- }
- case F_TLOCK: {
- auto result = linux_syscalls::fcntl(fd, F_SETLK, &fl);
- if (!result.has_value()) {
- libc_errno = result.error();
- return -1;
- }
- return 0;
- }
+ return linux_syscalls::fcntl(fd, F_SETLK, &fl);
+ case F_LOCK:
+ fl.l_type = F_WRLCK;
+ return linux_syscalls::fcntl(fd, F_SETLKW, &fl);
+ case F_TLOCK:
+ fl.l_type = F_WRLCK;
+ return linux_syscalls::fcntl(fd, F_SETLK, &fl);
default:
- libc_errno = EINVAL;
+ return Error(EINVAL);
+ }
+}
+
+} // anonymous namespace
+
+LLVM_LIBC_FUNCTION(int, lockf, (int fd, int cmd, off_t len)) {
+ auto result = lockf_impl(fd, cmd, len);
+ if (!result.has_value()) {
+ libc_errno = result.error();
return -1;
}
+ return 0;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt
index 069385a5325436..5d42ce8753f2c8 100644
--- a/libc/test/integration/src/unistd/CMakeLists.txt
+++ b/libc/test/integration/src/unistd/CMakeLists.txt
@@ -38,6 +38,28 @@ add_integration_test(
libc.include.sys_syscall
)
+add_integration_test(
+ lockf_test
+ SUITE
+ unistd-integration-tests
+ SRCS
+ lockf_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fcntl_macros
+ libc.hdr.sys_stat_macros
+ libc.hdr.sys_wait_macros
+ libc.hdr.unistd_macros
+ libc.src.errno.errno
+ libc.src.fcntl.open
+ libc.src.stdlib.exit
+ libc.src.sys.wait.waitpid
+ libc.src.unistd.close
+ libc.src.unistd.fork
+ libc.src.unistd.lockf
+ libc.src.unistd.unlink
+)
+
if((${LIBC_TARGET_OS} STREQUAL "linux") AND (${LIBC_TARGET_ARCHITECTURE_IS_X86}))
add_integration_test(
stack_smashing_test
diff --git a/libc/test/integration/src/unistd/lockf_test.cpp b/libc/test/integration/src/unistd/lockf_test.cpp
new file mode 100644
index 00000000000000..ebd35f4781f3fa
--- /dev/null
+++ b/libc/test/integration/src/unistd/lockf_test.cpp
@@ -0,0 +1,74 @@
+//===-- Integration test for lockf ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/fcntl_macros.h"
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_wait_macros.h"
+#include "hdr/unistd_macros.h"
+#include "src/fcntl/open.h"
+#include "src/stdlib/exit.h"
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/close.h"
+#include "src/unistd/fork.h"
+#include "src/unistd/lockf.h"
+#include "src/unistd/unlink.h"
+
+#include "test/IntegrationTest/test.h"
+
+#include <errno.h>
+
+TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv,
+ [[maybe_unused]] char **envp) {
+ constexpr const char TEST_FILE[] = "lockf_integration.test";
+
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+ ASSERT_TRUE(fd > 0);
+
+ // Acquire an exclusive lock on the file in the parent process.
+ ASSERT_EQ(LIBC_NAMESPACE::lockf(fd, F_LOCK, 0), 0);
+
+ pid_t pid = LIBC_NAMESPACE::fork();
+ ASSERT_TRUE(pid >= 0);
+
+ if (pid == 0) {
+ // Child process:
+ int child_fd = LIBC_NAMESPACE::open(TEST_FILE, O_RDWR, 0);
+ if (child_fd < 0)
+ LIBC_NAMESPACE::exit(1);
+
+ // F_TEST should fail because the section is locked by another process (parent).
+ if (LIBC_NAMESPACE::lockf(child_fd, F_TEST, 0) == 0)
+ LIBC_NAMESPACE::exit(2);
+ if (errno != EACCES && errno != EAGAIN)
+ LIBC_NAMESPACE::exit(3);
+
+ // F_TLOCK should fail because non-blocking lock cannot be acquired.
+ if (LIBC_NAMESPACE::lockf(child_fd, F_TLOCK, 0) == 0)
+ LIBC_NAMESPACE::exit(4);
+ if (errno != EACCES && errno != EAGAIN)
+ LIBC_NAMESPACE::exit(5);
+
+ LIBC_NAMESPACE::close(child_fd);
+ LIBC_NAMESPACE::exit(0);
+ }
+
+ // Parent process waits for child.
+ int status = 0;
+ pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(WEXITSTATUS(status), 0);
+
+ // Release lock and clean up file.
+ ASSERT_EQ(LIBC_NAMESPACE::lockf(fd, F_ULOCK, 0), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::close(fd), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::unlink(TEST_FILE), 0);
+
+ return 0;
+}
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index bab290eccccfa3..77f69bb238569e 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -982,6 +982,7 @@ add_libc_test(
libc.hdr.fcntl_macros
libc.hdr.sys_stat_macros
libc.hdr.unistd_macros
+ libc.src.__support.CPP.scope
libc.src.errno.errno
libc.src.fcntl.open
libc.src.unistd.close
diff --git a/libc/test/src/unistd/lockf_test.cpp b/libc/test/src/unistd/lockf_test.cpp
index a2b14c6e6ad863..d2b264c71c5b66 100644
--- a/libc/test/src/unistd/lockf_test.cpp
+++ b/libc/test/src/unistd/lockf_test.cpp
@@ -14,6 +14,7 @@
#include "hdr/fcntl_macros.h"
#include "hdr/sys_stat_macros.h"
#include "hdr/unistd_macros.h"
+#include "src/__support/CPP/scope.h"
#include "src/fcntl/open.h"
#include "src/unistd/close.h"
#include "src/unistd/lockf.h"
@@ -41,10 +42,12 @@ TEST_F(LlvmLibcLockfTest, InvalidCmd) {
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);
- EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, 999, 0), Fails(EINVAL));
+ LIBC_NAMESPACE::cpp::scope_exit cleanup([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ });
- EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, 999, 0), Fails(EINVAL));
}
TEST_F(LlvmLibcLockfTest, LockUnlockAndTest) {
@@ -55,6 +58,11 @@ TEST_F(LlvmLibcLockfTest, LockUnlockAndTest) {
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);
+ LIBC_NAMESPACE::cpp::scope_exit cleanup([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ });
+
// Section is not locked: F_TEST should succeed (return 0).
EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_TEST, 0), Succeeds(0));
@@ -72,9 +80,6 @@ TEST_F(LlvmLibcLockfTest, LockUnlockAndTest) {
// Unlock the section: F_ULOCK should succeed.
EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_ULOCK, 100), Succeeds(0));
-
- EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
}
TEST_F(LlvmLibcLockfTest, ReadOnlyFd) {
@@ -83,21 +88,16 @@ TEST_F(LlvmLibcLockfTest, ReadOnlyFd) {
constexpr const char *TEST_FILE_NAME = "testdata/lockf_rdonly.test";
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
- // Create the file first so we can open it read-only.
- int create_fd =
- LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_GT(create_fd, 0);
- EXPECT_THAT(LIBC_NAMESPACE::close(create_fd), Succeeds(0));
-
- int fd = LIBC_NAMESPACE::open(TEST_FILE, O_RDONLY, 0);
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_RDONLY, S_IRWXU);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);
+ LIBC_NAMESPACE::cpp::scope_exit cleanup([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ });
+
// F_LOCK on a read-only fd should fail with EBADF.
EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_LOCK, 0), Fails(EBADF));
EXPECT_THAT(LIBC_NAMESPACE::lockf(fd, F_TLOCK, 0), Fails(EBADF));
-
- EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
}
More information about the libc-commits
mailing list