forked from OSchip/llvm-project
[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:
parent
8c94d616e1
commit
5793c84925
|
@ -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",
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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
|
||||
)
|
|
@ -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
|
|
@ -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
|
|
@ -7,3 +7,4 @@ add_subdirectory(stdlib)
|
|||
add_subdirectory(string)
|
||||
add_subdirectory(sys)
|
||||
add_subdirectory(threads)
|
||||
add_subdirectory(unistd)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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));
|
||||
}
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue