[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