diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -271,6 +271,10 @@ let Types = ["off_t", "size_t", "ssize_t"]; } +def SysResourceAPI : PublicAPI<"sys/resource.h"> { + let Types = ["rlim_t", "struct rlimit_t"]; +} + def SysStatAPI : PublicAPI<"sys/stat.h"> { let Types = ["mode_t"]; } diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -101,6 +101,10 @@ libc.src.sys.mman.mmap libc.src.sys.mman.munmap + # sys/resource.h entrypoints + libc.src.sys.resource.getrlimit + libc.src.sys.resource.setrlimit + # sys/sendfile entrypoints libc.src.sys.sendfile.sendfile diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -203,6 +203,17 @@ .llvm-libc-types.ssize_t ) +add_gen_header( + sys_resource + DEF_FILE sys/resource.h.def + GEN_HDR sys/resource.h + DEPENDS + .llvm_libc_common_h + .llvm-libc-macros.sys_resource_macros + .llvm-libc-types.rlim_t + .llvm-libc-types.struct_rlimit_t +) + add_gen_header( sys_stat DEF_FILE sys/stat.h.def diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -22,6 +22,14 @@ .linux.sys_stat_macros ) +add_header( + sys_resource_macros + HDR + sys-resource-macros.h + DEPENDS + .linux.sys_resource_macros +) + add_header( unistd_macros HDR diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt --- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt @@ -10,6 +10,12 @@ sys-stat-macros.h ) +add_header( + sys_resource_macros + HDR + sys-resource-macros.h +) + add_header( unistd_macros HDR diff --git a/libc/include/llvm-libc-macros/linux/sys-resource-macros.h b/libc/include/llvm-libc-macros/linux/sys-resource-macros.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-macros/linux/sys-resource-macros.h @@ -0,0 +1,26 @@ +//===-- Macros defined in sys/resource.h header file ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_RTTIME 15 + +#define RLIM_INFINITY (~0UL) diff --git a/libc/include/llvm-libc-macros/sys-resource-macros.h b/libc/include/llvm-libc-macros/sys-resource-macros.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-macros/sys-resource-macros.h @@ -0,0 +1,16 @@ +//===-- Macros defined in sys/resource.h header file ----------------------===// +// +// 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_MACROS_SYS_RESOURCE_MACROS_H +#define __LLVM_LIBC_MACROS_SYS_RESOURCE_MACROS_H + +#ifdef __unix__ +#include "linux/sys-resource-macros.h" +#endif + +#endif // __LLVM_LIBC_MACROS_SYS_RESOURCE_MACROS_H diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -31,6 +31,8 @@ add_header(pthread_mutex_t HDR pthread_mutex_t.h DEPENDS .__futex_word .__mutex_type) add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type) add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h) +add_header(rlim_t HDR rlim_t.h) +add_header(struct_rlimit_t HDR struct_rlimit_t.h DEPENDS .rlim_t) add_header(ssize_t HDR ssize_t.h) add_header(struct_dirent HDR struct_dirent.h DEPENDS .ino_t .off_t) add_header(struct_sigaction HDR struct_sigaction.h) diff --git a/libc/include/llvm-libc-types/rlim_t.h b/libc/include/llvm-libc-types/rlim_t.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/rlim_t.h @@ -0,0 +1,14 @@ +//===-- Definition of type rlim_t -----------------------------------------===// +// +// 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_TYPES_RLIM_T_H__ +#define __LLVM_LIBC_TYPES_RLIM_T_H__ + +typedef unsigned long rlim_t; + +#endif // __LLVM_LIBC_TYPES_RLIM_T_H__ diff --git a/libc/include/llvm-libc-types/struct_rlimit_t.h b/libc/include/llvm-libc-types/struct_rlimit_t.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/struct_rlimit_t.h @@ -0,0 +1,19 @@ +//===-- Definition of type rlimit_t ---------------------------------------===// +// +// 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_TYPES_RLIMIT_T_H__ +#define __LLVM_LIBC_TYPES_RLIMIT_T_H__ + +#include + +struct rlimit_t { + rlim_t rlim_cur; + rlim_t rlim_max; +}; + +#endif // __LLVM_LIBC_TYPES_RLIMIT_T_H__ diff --git a/libc/include/sys/resource.h.def b/libc/include/sys/resource.h.def new file mode 100644 --- /dev/null +++ b/libc/include/sys/resource.h.def @@ -0,0 +1,18 @@ +//===-- POSIX header resource.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_RESOURCE_H +#define LLVM_LIBC_SYS_RESOURCE_H + +#include <__llvm-libc-common.h> + +#include + +%%public_api() + +#endif // LLVM_LIBC_SYS_RESOURCE_H diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -465,6 +465,16 @@ ] >; + NamedType RLimTType = NamedType<"rlim_t">; + NamedType StructRLimitTType = NamedType<"struct rlimit_t">; + HeaderSpec SysResource = HeaderSpec< + "sys/resource.h", + [], // Macros + [RLimTType, StructRLimitTType], // Types + [], // Enumerations + [] // Functions + >; + HeaderSpec SysStat = HeaderSpec< "sys/stat.h", [], // Macros @@ -764,6 +774,7 @@ StdIO, StdLib, SysMMan, + SysResource, SysStat, UniStd, String diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(mman) +add_subdirectory(resource) add_subdirectory(sendfile) add_subdirectory(stat) diff --git a/libc/src/sys/resource/CMakeLists.txt b/libc/src/sys/resource/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/sys/resource/CMakeLists.txt @@ -0,0 +1,17 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) +endif() + +add_entrypoint_object( + getrlimit + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.getrlimit +) + +add_entrypoint_object( + setrlimit + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.setrlimit +) diff --git a/libc/src/sys/resource/getrlimit.h b/libc/src/sys/resource/getrlimit.h new file mode 100644 --- /dev/null +++ b/libc/src/sys/resource/getrlimit.h @@ -0,0 +1,20 @@ +//===-- Implementation header for getrlimit ---------------------*- 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_GETRLIMIT_H +#define LLVM_LIBC_SRC_SYS_STAT_GETRLIMIT_H + +#include + +namespace __llvm_libc { + +int getrlimit(int resource, struct rlimit_t *lim); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_GETRLIMIT_H diff --git a/libc/src/sys/resource/linux/CMakeLists.txt b/libc/src/sys/resource/linux/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/sys/resource/linux/CMakeLists.txt @@ -0,0 +1,25 @@ +add_entrypoint_object( + getrlimit + SRCS + getrlimit.cpp + HDRS + ../getrlimit.h + DEPENDS + libc.include.sys_resource + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + setrlimit + SRCS + setrlimit.cpp + HDRS + ../setrlimit.h + DEPENDS + libc.include.sys_resource + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) diff --git a/libc/src/sys/resource/linux/getrlimit.cpp b/libc/src/sys/resource/linux/getrlimit.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sys/resource/linux/getrlimit.cpp @@ -0,0 +1,29 @@ +//===-- Linux implementation of getrlimit ---------------------------------===// +// +// 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/resource/getrlimit.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include +#include // For struct rlimit_t +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, getrlimit, (int res, struct rlimit_t *limits)) { + long ret = __llvm_libc::syscall(SYS_prlimit64, 0, res, nullptr, limits); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sys/resource/linux/setrlimit.cpp b/libc/src/sys/resource/linux/setrlimit.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sys/resource/linux/setrlimit.cpp @@ -0,0 +1,29 @@ +//===-- Linux implementation of setrlimit ---------------------------------===// +// +// 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/resource/setrlimit.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include +#include // For struct rlimit_t +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, setrlimit, (int res, const struct rlimit_t *limits)) { + long ret = __llvm_libc::syscall(SYS_prlimit64, 0, res, limits, nullptr); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sys/resource/setrlimit.h b/libc/src/sys/resource/setrlimit.h new file mode 100644 --- /dev/null +++ b/libc/src/sys/resource/setrlimit.h @@ -0,0 +1,20 @@ +//===-- Implementation header for setrlimit ---------------------*- 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_SETRLIMIT_H +#define LLVM_LIBC_SRC_SYS_STAT_SETRLIMIT_H + +#include + +namespace __llvm_libc { + +int setrlimit(int resource, const struct rlimit_t *lim); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_SETRLIMIT_H diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(mman) +add_subdirectory(resource) add_subdirectory(sendfile) add_subdirectory(stat) diff --git a/libc/test/src/sys/resource/CMakeLists.txt b/libc/test/src/sys/resource/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/resource/CMakeLists.txt @@ -0,0 +1,20 @@ +add_libc_testsuite(libc_sys_resource_unittests) + +add_subdirectory(testdata) + +add_libc_unittest( + getrlimit_setrlimit_test + SUITE + libc_sys_resource_unittests + SRCS + getrlimit_setrlimit_test.cpp + DEPENDS + libc.include.errno + libc.include.fcntl + libc.include.sys_resource + libc.src.fcntl.open + libc.src.sys.resource.getrlimit + libc.src.sys.resource.setrlimit + libc.src.unistd.close + libc.src.unistd.unlink +) diff --git a/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp b/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp @@ -0,0 +1,71 @@ +//===-- Unittests for getrlimit and setrlimit -----------------------------===// +// +// 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/resource/getrlimit.h" +#include "src/sys/resource/setrlimit.h" +#include "src/unistd/close.h" +#include "src/unistd/unlink.h" +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" + +#include +#include + +TEST(LlvmLibcResourceLimitsTest, SetNoFileLimit) { + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + + // The test strategy is to first create initialize two file descriptors + // successfully. Next, close the files and set the file descriptor limit + // to 4. This will allow us to open one of those file but not the other. + + constexpr const char *TEST_FILE1 = "testdata/resource_limits1.test"; + constexpr const char *TEST_FILE2 = "testdata/resource_limits2.test"; + errno = 0; + + int fd1 = __llvm_libc::open(TEST_FILE1, O_CREAT | O_WRONLY, S_IRWXU); + ASSERT_GT(fd1, 0); + ASSERT_EQ(errno, 0); + int fd2 = __llvm_libc::open(TEST_FILE2, O_CREAT | O_WRONLY, S_IRWXU); + ASSERT_GT(fd2, 0); + ASSERT_EQ(errno, 0); + + ASSERT_THAT(__llvm_libc::close(fd1), Succeeds(0)); + ASSERT_THAT(__llvm_libc::close(fd2), Succeeds(0)); + + struct rlimit_t limits { + 4, 4 + }; + ASSERT_THAT(__llvm_libc::setrlimit(RLIMIT_NOFILE, &limits), Succeeds(0)); + + // One can now only open one of the files successfully. + fd1 = __llvm_libc::open(TEST_FILE1, O_RDONLY); + ASSERT_GT(fd1, 0); + ASSERT_EQ(errno, 0); + fd2 = __llvm_libc::open(TEST_FILE2, O_RDONLY); + ASSERT_LT(fd2, 0); + ASSERT_NE(errno, 0); + + errno = 0; + ASSERT_THAT(__llvm_libc::close(fd1), Succeeds(0)); + + fd2 = __llvm_libc::open(TEST_FILE2, O_RDONLY); + ASSERT_GT(fd2, 0); + ASSERT_EQ(errno, 0); + fd1 = __llvm_libc::open(TEST_FILE1, O_RDONLY); + ASSERT_LT(fd1, 0); + ASSERT_NE(errno, 0); + + errno = 0; + ASSERT_THAT(__llvm_libc::close(fd2), Succeeds(0)); + + ASSERT_THAT(__llvm_libc::unlink(TEST_FILE1), Succeeds(0)); + ASSERT_THAT(__llvm_libc::unlink(TEST_FILE2), Succeeds(0)); +} diff --git a/libc/test/src/sys/resource/testdata/CMakeLists.txt b/libc/test/src/sys/resource/testdata/CMakeLists.txt new file mode 100644