[libc-commits] [libc] 5793c84 - [libc] Add write(2) implementation for Linux and FDReader test utility
Alex Brachet via libc-commits
libc-commits at lists.llvm.org
Fri Apr 17 10:21:54 PDT 2020
Author: Alex Brachet
Date: 2020-04-17T13:21:05-04:00
New Revision: 5793c84925fa98f00dbc57f476448babc5ee3aaa
URL: https://github.com/llvm/llvm-project/commit/5793c84925fa98f00dbc57f476448babc5ee3aaa
DIFF: https://github.com/llvm/llvm-project/commit/5793c84925fa98f00dbc57f476448babc5ee3aaa.diff
LOG: [libc] Add write(2) implementation for Linux and FDReader test utility
Summary: Adds `write` for Linux and FDReader utility which should be useful for some stdio tests as well.
Reviewers: sivachandra, PaulkaToast
Reviewed By: sivachandra
Subscribers: mgorny, tschuett, libc-commits
Differential Revision: https://reviews.llvm.org/D78184
Added:
libc/include/unistd.h.def
libc/src/unistd/CMakeLists.txt
libc/src/unistd/linux/CMakeLists.txt
libc/src/unistd/linux/write.cpp
libc/src/unistd/write.h
libc/test/src/unistd/CMakeLists.txt
libc/test/src/unistd/write_test.cpp
libc/utils/testutils/FDReader.h
libc/utils/testutils/FDReaderUnix.cpp
Modified:
libc/config/linux/api.td
libc/include/CMakeLists.txt
libc/include/__posix-types.h
libc/lib/CMakeLists.txt
libc/spec/posix.td
libc/spec/spec.td
libc/src/CMakeLists.txt
libc/test/src/CMakeLists.txt
libc/utils/testutils/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index f176caee6a4e..741899abcca8 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -12,6 +12,13 @@ def SizeT : TypeDecl<"size_t"> {
}];
}
+def SSizeT : TypeDecl<"ssize_t"> {
+ let Decl = [{
+ #define __need_ssize_t
+ #include <__posix-types.h>
+ }];
+}
+
def OffT : TypeDecl<"off_t"> {
let Decl = [{
#define __need_off_t
@@ -308,3 +315,14 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
"thrd_join",
];
}
+
+def UniStdAPI : PublicAPI<"unistd.h"> {
+ let TypeDeclarations = [
+ SSizeT,
+ SizeT,
+ ];
+
+ let Functions = [
+ "write",
+ ];
+}
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 6cd192c1a52e..f9564b323494 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -91,6 +91,14 @@ add_gen_header(
.llvm_libc_common_h
)
+add_gen_header(
+ unistd
+ DEF_FILE unistd.h.def
+ GEN_HDR unistd.h
+ DEPENDS
+ .llvm_libc_common_h
+)
+
# TODO: Not all platforms will have a include/sys directory. Add the sys
# directory and the targets for sys/*.h files conditional to the OS requiring
# them.
diff --git a/libc/include/__posix-types.h b/libc/include/__posix-types.h
index d891ab9a63e3..30844728633b 100644
--- a/libc/include/__posix-types.h
+++ b/libc/include/__posix-types.h
@@ -14,3 +14,8 @@
typedef __INT64_TYPE__ off_t;
#define __llvm_libc_off_t_defined
#endif // __need_off_t
+
+#if defined(__need_ssize_t) && !defined(__llvm_libc_ssize_t_defined)
+typedef __INT64_TYPE__ ssize_t;
+#define __llvm_libc_ssize_t_defined
+#endif // __need_ssize_t
diff --git a/libc/include/unistd.h.def b/libc/include/unistd.h.def
new file mode 100644
index 000000000000..42bab396b2d6
--- /dev/null
+++ b/libc/include/unistd.h.def
@@ -0,0 +1,16 @@
+//===-- C standard library header unistd.h --------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_UNISTD_H
+#define LLVM_LIBC_UNISTD_H
+
+#include <__llvm-libc-common.h>
+
+%%public_api()
+
+#endif // LLVM_LIBC_UNISTD_H
diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index bc245cdb481e..39654d8b2267 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -35,6 +35,9 @@ add_entrypoint_library(
libc.src.threads.mtx_unlock
libc.src.threads.thrd_create
libc.src.threads.thrd_join
+
+ # unistd.h entrypoints
+ libc.src.unistd.write
)
add_entrypoint_library(
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 172b0c30fede..dfde4d1d114a 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -12,6 +12,7 @@ def ConstRestrictStructSigactionPtr : ConstType<RestrictStructSigactionPtr>;
def POSIX : StandardSpec<"POSIX"> {
NamedType OffTType = NamedType<"off_t">;
+ NamedType SSizeTType = NamedType<"ssize_t">;
HeaderSpec Errno = HeaderSpec<
"errno.h",
@@ -174,9 +175,27 @@ def POSIX : StandardSpec<"POSIX"> {
]
>;
+ HeaderSpec UniStd = HeaderSpec<
+ "unistd.h",
+ [], // Macros
+ [
+ SSizeTType,
+ SizeTType,
+ ],
+ [], // Enumerations
+ [
+ FunctionSpec<
+ "write",
+ RetValSpec<SSizeTType>,
+ [ArgSpec<IntType>, ArgSpec<ConstVoidPtr>, ArgSpec<SizeTType>]
+ >,
+ ]
+ >;
+
let Headers = [
Errno,
SysMMan,
Signal,
+ UniStd,
];
}
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index ee04cef277b4..3dd339b435c4 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -46,6 +46,7 @@ def CharType : NamedType<"char">;
// Common types
def VoidPtr : PtrType<VoidType>;
+def ConstVoidPtr : ConstType<VoidPtr>;
def SizeTType : NamedType<"size_t">;
def FloatPtr : PtrType<FloatType>;
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 72b4bca34af2..88d2829d656a 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -8,5 +8,6 @@ add_subdirectory(string)
# TODO: Add this target conditional to the target OS.
add_subdirectory(sys)
add_subdirectory(threads)
+add_subdirectory(unistd)
add_subdirectory(__support)
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
new file mode 100644
index 000000000000..d0e5b14d6fd9
--- /dev/null
+++ b/libc/src/unistd/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+ write
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.write
+)
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
new file mode 100644
index 000000000000..bd2cba708e69
--- /dev/null
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+ write
+ SRCS
+ write.cpp
+ HDRS
+ ../write.h
+ DEPENDS
+ libc.include.unistd
+ libc.config.linux.linux_syscall_h
+ libc.include.sys_syscall
+ libc.src.errno.__errno_location
+)
diff --git a/libc/src/unistd/linux/write.cpp b/libc/src/unistd/linux/write.cpp
new file mode 100644
index 000000000000..2778346fa5b5
--- /dev/null
+++ b/libc/src/unistd/linux/write.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of write -------------------------------------===//
+//
+// 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 "src/unistd/write.h"
+
+#include "config/linux/syscall.h" // For internal syscall function.
+#include "include/sys/syscall.h" // For syscall numbers.
+#include "src/__support/common.h"
+#include "src/errno/llvmlibc_errno.h"
+
+namespace __llvm_libc {
+
+ssize_t LLVM_LIBC_ENTRYPOINT(write)(int fd, const void *buf, size_t count) {
+ long ret = __llvm_libc::syscall(SYS_write, fd, buf, count);
+ if (ret < 0) {
+ llvmlibc_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/write.h b/libc/src/unistd/write.h
new file mode 100644
index 000000000000..d69c10a66f0f
--- /dev/null
+++ b/libc/src/unistd/write.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for write -------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_WRITE_H
+#define LLVM_LIBC_SRC_UNISTD_WRITE_H
+
+#include "include/unistd.h"
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+ssize_t write(int fd, const void *buf, size_t count);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_WRITE_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index f92a0463b359..d333108aa02b 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -7,3 +7,4 @@ add_subdirectory(stdlib)
add_subdirectory(string)
add_subdirectory(sys)
add_subdirectory(threads)
+add_subdirectory(unistd)
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
new file mode 100644
index 000000000000..7aaa50d0b11b
--- /dev/null
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_libc_testsuite(libc_unistd_unittests)
+
+add_libc_unittest(
+ write_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ write_test.cpp
+ DEPENDS
+ libc.src.unistd.write
+ libc.include.errno
+ # TODO(sivachandra): Remove redundant deps.
+ libc.src.errno.__errno_location
+ libc.include.unistd
+)
diff --git a/libc/test/src/unistd/write_test.cpp b/libc/test/src/unistd/write_test.cpp
new file mode 100644
index 000000000000..2a91ef6fc277
--- /dev/null
+++ b/libc/test/src/unistd/write_test.cpp
@@ -0,0 +1,29 @@
+//===-- Unittests for write -----------------------------------------------===//
+//
+// 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 "include/errno.h"
+#include "src/unistd/write.h"
+#include "utils/UnitTest/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+#include "utils/testutils/FDReader.h"
+
+TEST(UniStd, WriteBasic) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *hello = "hello";
+ __llvm_libc::testutils::FDReader reader;
+ EXPECT_THAT(__llvm_libc::write(reader.getWriteFD(), hello, 5), Succeeds(5));
+ EXPECT_TRUE(reader.matchWritten(hello));
+}
+
+TEST(UniStd, WriteFails) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+
+ EXPECT_THAT(__llvm_libc::write(-1, "", 1), Fails(EBADF));
+ EXPECT_THAT(__llvm_libc::write(1, reinterpret_cast<const void *>(-1), 1),
+ Fails(EFAULT));
+}
diff --git a/libc/utils/testutils/CMakeLists.txt b/libc/utils/testutils/CMakeLists.txt
index 9ee03e18c66b..80c23f4b0769 100644
--- a/libc/utils/testutils/CMakeLists.txt
+++ b/libc/utils/testutils/CMakeLists.txt
@@ -1,5 +1,6 @@
if(CMAKE_HOST_UNIX)
set(EFFile ExecuteFunctionUnix.cpp)
+ set(FDReaderFile FDReaderUnix.cpp)
endif()
add_llvm_library(
@@ -8,6 +9,8 @@ add_llvm_library(
StreamWrapper.h
${EFFile}
ExecuteFunction.h
+ ${FDReaderFile}
+ FDReader.h
LINK_COMPONENTS
Support
)
diff --git a/libc/utils/testutils/FDReader.h b/libc/utils/testutils/FDReader.h
new file mode 100644
index 000000000000..e25dcea290a6
--- /dev/null
+++ b/libc/utils/testutils/FDReader.h
@@ -0,0 +1,29 @@
+//===-- FDReader.h ----------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_UTILS_TESTUTILS_FDREADER_H
+#define LLVM_LIBC_UTILS_TESTUTILS_FDREADER_H
+
+namespace __llvm_libc {
+namespace testutils {
+
+class FDReader {
+ int pipefd[2];
+
+public:
+ FDReader();
+ ~FDReader();
+
+ int getWriteFD() { return pipefd[1]; }
+ bool matchWritten(const char *);
+};
+
+} // namespace testutils
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_UTILS_TESTUTILS_FDREADER_H
diff --git a/libc/utils/testutils/FDReaderUnix.cpp b/libc/utils/testutils/FDReaderUnix.cpp
new file mode 100644
index 000000000000..943d3eb5356e
--- /dev/null
+++ b/libc/utils/testutils/FDReaderUnix.cpp
@@ -0,0 +1,41 @@
+//===-- FDReader.cpp ------------------------------------------------------===//
+//
+// 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 "FDReader.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cassert>
+#include <cstring>
+#include <unistd.h>
+
+namespace __llvm_libc {
+namespace testutils {
+
+FDReader::FDReader() {
+ int err = ::pipe(pipefd);
+ assert(!err && "pipe(2) failed");
+}
+
+FDReader::~FDReader() {
+ ::close(pipefd[0]);
+ ::close(pipefd[1]);
+}
+
+bool FDReader::matchWritten(const char *str) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> bufOrErr =
+ llvm::MemoryBuffer::getOpenFile(pipefd[0], "<pipe>",
+ /* FileSize (irrelevant) */ 0);
+ if (!bufOrErr) {
+ assert(0 && "Error reading from pipe");
+ return false;
+ }
+ const llvm::MemoryBuffer &buf = **bufOrErr;
+ return !std::strncmp(buf.getBufferStart(), str, buf.getBufferSize());
+}
+
+} // namespace testutils
+} // namespace __llvm_libc
More information about the libc-commits
mailing list