forked from OSchip/llvm-project
[libc] Add Linux implementation of GNU extension function sendfile.
Reviewed By: michaelrj Differential Revision: https://reviews.llvm.org/D132721
This commit is contained in:
parent
cb0644b1cc
commit
b8be3dabde
|
@ -100,6 +100,9 @@ set(TARGET_LIBC_ENTRYPOINTS
|
|||
libc.src.sys.mman.mmap
|
||||
libc.src.sys.mman.munmap
|
||||
|
||||
# sys/sendfile entrypoints
|
||||
libc.src.sys.sendfile.sendfile
|
||||
|
||||
# sys/stat.h entrypoints
|
||||
libc.src.sys.stat.chmod
|
||||
libc.src.sys.stat.fchmod
|
||||
|
|
|
@ -274,3 +274,7 @@ def UniStdAPI : PublicAPI<"unistd.h"> {
|
|||
def SysStatAPI : PublicAPI<"sys/stat.h"> {
|
||||
let Types = ["mode_t"];
|
||||
}
|
||||
|
||||
def SysSendfileAPI : PublicAPI<"sys/sendfile.h"> {
|
||||
let Types = ["off_t", "size_t", "ssize_t"];
|
||||
}
|
||||
|
|
|
@ -100,6 +100,9 @@ set(TARGET_LIBC_ENTRYPOINTS
|
|||
libc.src.sys.mman.mmap
|
||||
libc.src.sys.mman.munmap
|
||||
|
||||
# sys/sendfile entrypoints
|
||||
libc.src.sys.sendfile.sendfile
|
||||
|
||||
# sys/stat.h entrypoints
|
||||
libc.src.sys.stat.chmod
|
||||
libc.src.sys.stat.fchmod
|
||||
|
|
|
@ -212,6 +212,16 @@ add_gen_header(
|
|||
.llvm-libc-types.mode_t
|
||||
)
|
||||
|
||||
add_gen_header(
|
||||
sys_sendfile
|
||||
DEF_FILE sys/sendfile.h.def
|
||||
GEN_HDR sys/sendfile.h
|
||||
DEPENDS
|
||||
.llvm_libc_common_h
|
||||
.llvm-libc-types.off_t
|
||||
.llvm-libc-types.ssize_t
|
||||
)
|
||||
|
||||
add_gen_header(
|
||||
sys_syscall
|
||||
DEF_FILE sys/syscall.h.def
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
//===-- Linux sys/sendfile.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_SYS_SENDFILE_H
|
||||
#define LLVM_LIBC_SYS_SENDFILE_H
|
||||
|
||||
#include <__llvm-libc-common.h>
|
||||
|
||||
%%public_api()
|
||||
|
||||
#endif // LLVM_LIBC_SYS_SENDFILE_H
|
|
@ -130,11 +130,26 @@ def GnuExtensions : StandardSpec<"GNUExtensions"> {
|
|||
]
|
||||
>;
|
||||
|
||||
HeaderSpec SendFile = HeaderSpec<
|
||||
"sys/sendfile.h",
|
||||
[], // Macros
|
||||
[OffTType, SizeTType, SSizeTType,], // Types
|
||||
[], // Enumerations
|
||||
[
|
||||
FunctionSpec<
|
||||
"sendfile",
|
||||
RetValSpec<SSizeTType>,
|
||||
[ArgSpec<IntType>, ArgSpec<IntType>, ArgSpec<OffTPtr>, ArgSpec<SizeTType>]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
let Headers = [
|
||||
CType,
|
||||
FEnv,
|
||||
Math,
|
||||
PThread,
|
||||
SendFile,
|
||||
StdIO,
|
||||
String,
|
||||
];
|
||||
|
|
|
@ -32,8 +32,6 @@ def POSIX : StandardSpec<"POSIX"> {
|
|||
ConstType ConstRestrictedCharPtr = ConstType<RestrictedCharPtr>;
|
||||
|
||||
NamedType ModeTType = NamedType<"mode_t">;
|
||||
NamedType OffTType = NamedType<"off_t">;
|
||||
NamedType SSizeTType = NamedType<"ssize_t">;
|
||||
|
||||
NamedType PThreadAttrTType = NamedType<"pthread_attr_t">;
|
||||
PtrType PThreadAttrTPtr = PtrType<PThreadAttrTType>;
|
||||
|
|
|
@ -63,6 +63,10 @@ def LongDoublePtr : PtrType<LongDoubleType>;
|
|||
def IntMaxTType : NamedType<"intmax_t">;
|
||||
def UIntMaxTType : NamedType<"uintmax_t">;
|
||||
|
||||
def OffTType : NamedType<"off_t">;
|
||||
def OffTPtr : PtrType<OffTType>;
|
||||
def SSizeTType : NamedType<"ssize_t">;
|
||||
|
||||
// _Noreturn is really not a type, but it is convenient to treat it as a type.
|
||||
def NoReturn : NamedType<"_Noreturn void">;
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(mman)
|
||||
add_subdirectory(sendfile)
|
||||
add_subdirectory(stat)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
|
||||
endif()
|
||||
|
||||
add_entrypoint_object(
|
||||
sendfile
|
||||
ALIAS
|
||||
DEPENDS
|
||||
.${LIBC_TARGET_OS}.sendfile
|
||||
)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
add_entrypoint_object(
|
||||
sendfile
|
||||
SRCS
|
||||
sendfile.cpp
|
||||
HDRS
|
||||
../sendfile.h
|
||||
DEPENDS
|
||||
libc.include.sys_sendfile
|
||||
libc.include.sys_syscall
|
||||
libc.src.__support.OSUtil.osutil
|
||||
libc.src.errno.errno
|
||||
)
|
|
@ -0,0 +1,30 @@
|
|||
//===-- Linux implementation of sendfile ----------------------------------===//
|
||||
//
|
||||
// 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/sys/sendfile/sendfile.h"
|
||||
|
||||
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
|
||||
#include "src/__support/common.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/syscall.h> // For syscall numbers.
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
LLVM_LIBC_FUNCTION(ssize_t, sendfile,
|
||||
(int out_fd, int in_fd, off_t *offset, size_t count)) {
|
||||
long ret = __llvm_libc::syscall(SYS_sendfile, in_fd, out_fd, offset, count);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
|||
//===-- Implementation header for sendfile ----------------------*- 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_SYS_STAT_SENDFILE_H
|
||||
#define LLVM_LIBC_SRC_SYS_STAT_SENDFILE_H
|
||||
|
||||
#include <sys/sendfile.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
ssize_t sendfile(int, int, off_t *, size_t);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_SYS_STAT_SENDFILE_H
|
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(mman)
|
||||
add_subdirectory(sendfile)
|
||||
add_subdirectory(stat)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
add_libc_testsuite(libc_sys_sendfile_unittests)
|
||||
|
||||
add_subdirectory(testdata)
|
||||
|
||||
add_libc_unittest(
|
||||
sendfile_test
|
||||
SUITE
|
||||
libc_sys_sendfile_unittests
|
||||
SRCS
|
||||
sendfile_test.cpp
|
||||
DEPENDS
|
||||
libc.include.errno
|
||||
libc.include.fcntl
|
||||
libc.include.sys_stat
|
||||
libc.src.fcntl.open
|
||||
libc.src.sys.sendfile.sendfile
|
||||
libc.src.unistd.close
|
||||
libc.src.unistd.read
|
||||
libc.src.unistd.unlink
|
||||
libc.src.unistd.write
|
||||
)
|
|
@ -0,0 +1,67 @@
|
|||
//===-- Unittests for sendfile --------------------------------------------===//
|
||||
//
|
||||
// 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/__support/CPP/string_view.h"
|
||||
#include "src/fcntl/open.h"
|
||||
#include "src/sys/sendfile/sendfile.h"
|
||||
#include "src/unistd/close.h"
|
||||
#include "src/unistd/read.h"
|
||||
#include "src/unistd/unlink.h"
|
||||
#include "src/unistd/write.h"
|
||||
#include "test/ErrnoSetterMatcher.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
#include "utils/testutils/FDReader.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace cpp = __llvm_libc::cpp;
|
||||
|
||||
TEST(LlvmLibcSendfileTest, CreateAndTransfer) {
|
||||
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
|
||||
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
|
||||
|
||||
// The test strategy is to
|
||||
// 1. Create a temporary file with known data.
|
||||
// 2. Use sendfile to copy it to another file.
|
||||
// 3. Make sure that the data was actually copied.
|
||||
// 4. Clean up the temporary files.
|
||||
constexpr const char *IN_FILE = "testdata/sendfile_in.test";
|
||||
constexpr const char *OUT_FILE = "testdata/sendfile_out.test";
|
||||
const char IN_DATA[] = "sendfile test";
|
||||
constexpr ssize_t IN_SIZE = ssize_t(sizeof(IN_DATA));
|
||||
errno = 0;
|
||||
|
||||
int in_fd = __llvm_libc::open(IN_FILE, O_CREAT | O_WRONLY, S_IRWXU);
|
||||
ASSERT_GT(in_fd, 0);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(__llvm_libc::write(in_fd, IN_DATA, IN_SIZE), IN_SIZE);
|
||||
ASSERT_THAT(__llvm_libc::close(in_fd), Succeeds(0));
|
||||
|
||||
in_fd = __llvm_libc::open(IN_FILE, O_RDONLY);
|
||||
ASSERT_GT(in_fd, 0);
|
||||
ASSERT_EQ(errno, 0);
|
||||
int out_fd = __llvm_libc::open(OUT_FILE, O_CREAT | O_WRONLY, S_IRWXU);
|
||||
ASSERT_GT(out_fd, 0);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ssize_t size = __llvm_libc::sendfile(in_fd, out_fd, nullptr, IN_SIZE);
|
||||
ASSERT_EQ(size, IN_SIZE);
|
||||
ASSERT_THAT(__llvm_libc::close(in_fd), Succeeds(0));
|
||||
ASSERT_THAT(__llvm_libc::close(out_fd), Succeeds(0));
|
||||
|
||||
out_fd = __llvm_libc::open(OUT_FILE, O_RDONLY);
|
||||
ASSERT_GT(out_fd, 0);
|
||||
ASSERT_EQ(errno, 0);
|
||||
char buf[IN_SIZE];
|
||||
ASSERT_EQ(IN_SIZE, __llvm_libc::read(out_fd, buf, IN_SIZE));
|
||||
ASSERT_EQ(cpp::string_view(buf), cpp::string_view(IN_DATA));
|
||||
|
||||
ASSERT_THAT(__llvm_libc::unlink(IN_FILE), Succeeds(0));
|
||||
ASSERT_THAT(__llvm_libc::unlink(OUT_FILE), Succeeds(0));
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
# Directory to hold temporary files created by tests.
|
Loading…
Reference in New Issue