[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
This commit is contained in:
Alex Brachet 2020-04-17 13:21:05 -04:00
parent 8c94d616e1
commit 5793c84925
18 changed files with 259 additions and 0 deletions

View File

@ -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",
];
}

View File

@ -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.

View File

@ -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

16
libc/include/unistd.h.def Normal file
View File

@ -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

View File

@ -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(

View File

@ -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,
];
}

View File

@ -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>;

View File

@ -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)

View File

@ -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
)

View File

@ -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
)

View File

@ -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

21
libc/src/unistd/write.h Normal file
View File

@ -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

View File

@ -7,3 +7,4 @@ add_subdirectory(stdlib)
add_subdirectory(string)
add_subdirectory(sys)
add_subdirectory(threads)
add_subdirectory(unistd)

View File

@ -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
)

View File

@ -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));
}

View File

@ -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
)

View File

@ -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

View File

@ -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