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 @@ -219,7 +219,7 @@ } def SysWaitAPI : PublicAPI<"sys/wait.h"> { - let Types = ["pid_t", "struct rusage"]; + let Types = ["pid_t", "struct rusage", "siginfo_t"]; } def SysSendfileAPI : PublicAPI<"sys/sendfile.h"> { diff --git a/libc/config/linux/syscall_numbers.h.inc b/libc/config/linux/syscall_numbers.h.inc --- a/libc/config/linux/syscall_numbers.h.inc +++ b/libc/config/linux/syscall_numbers.h.inc @@ -170,10 +170,18 @@ #define SYS_clock_gettime __NR_clock_gettime #endif +#ifdef __NR_clock_gettime64 +#define SYS_clock_gettime64 __NR_clock_gettime64 +#endif + #ifdef __NR_clock_nanosleep #define SYS_clock_nanosleep __NR_clock_nanosleep #endif +#ifdef __NR_clock_nanosleep_time64 +#define SYS_clock_nanosleep_time64 __NR_clock_nanosleep_time64 +#endif + #ifdef __NR_clock_settime #define SYS_clock_settime __NR_clock_settime #endif @@ -422,6 +430,10 @@ #define SYS_futex __NR_futex #endif +#ifdef __NR_futex_time64 +#define SYS_futex_time64 __NR_futex_time64 +#endif + #ifdef __NR_futimesat #define SYS_futimesat __NR_futimesat #endif @@ -1534,6 +1546,10 @@ #define SYS_pselect6 __NR_pselect6 #endif +#ifdef __NR_pselect6_time64 +#define SYS_pselect6_time64 __NR_pselect6_time64 +#endif + #ifdef __NR_ptrace #define SYS_ptrace __NR_ptrace #endif @@ -1730,6 +1746,10 @@ #define SYS_sched_rr_get_interval __NR_sched_rr_get_interval #endif +#ifdef __NR_sched_rr_get_interval_time64 +#define SYS_sched_rr_get_interval_time64 __NR_sched_rr_get_interval_time64 +#endif + #ifdef __NR_sched_set_affinity #define SYS_sched_set_affinity __NR_sched_set_affinity #endif @@ -2317,4 +2337,3 @@ #ifdef __NR_writev #define SYS_writev __NR_writev #endif - diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -467,6 +467,7 @@ .llvm-libc-macros.sys_wait_macros .llvm-libc-types.pid_t .llvm-libc-types.struct_rusage + .llvm-libc-types.siginfo_t ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/linux/signal-macros.h b/libc/include/llvm-libc-macros/linux/signal-macros.h --- a/libc/include/llvm-libc-macros/linux/signal-macros.h +++ b/libc/include/llvm-libc-macros/linux/signal-macros.h @@ -93,4 +93,12 @@ #define SIG_IGN ((__sighandler_t)1) #define SIG_ERR ((__sighandler_t)-1) +// SIGCHLD si_codes +#define CLD_EXITED 1 // child has exited +#define CLD_KILLED 2 // child was killed +#define CLD_DUMPED 3 // child terminated abnormally +#define CLD_TRAPPED 4 // traced child has trapped +#define CLD_STOPPED 5 // child has stopped +#define CLD_CONTINUED 6 // stopped child has continued + #endif // __LLVM_LIBC_MACROS_LINUX_SIGNUM_MACROS_H diff --git a/libc/include/llvm-libc-macros/linux/sys-wait-macros.h b/libc/include/llvm-libc-macros/linux/sys-wait-macros.h --- a/libc/include/llvm-libc-macros/linux/sys-wait-macros.h +++ b/libc/include/llvm-libc-macros/linux/sys-wait-macros.h @@ -12,13 +12,33 @@ // Wait flags #define WNOHANG 1 // Do not block #define WUNTRACED 2 // Report is a child has stopped even if untraced +#define WEXITED 4 // Report dead child #define WCONTINUED 8 // Report if a stopped child has been resumed by SIGCONT +#define WSTOPPED WUNTRACED // Wait status info macros -#define WTERMSIG(status) (((status)&0x7F)) -#define WIFEXITED(status) (WTERMSIG(status) == 0) -#define WEXITSTATUS(status) (((status)&0xFF00) >> 8) -#define WIFSIGNALED(status) \ - ((WTERMSIG(status) < 0x7F) && (WTERMSIG(status) > 0)) +#define __WEXITSTATUS(status) (((status)&0xff00) >> 8) +#define __WTERMSIG(status) ((status)&0x7f) +#define __WIFEXITED(status) (__WTERMSIG(status) == 0) + +// Macros for constructing status values. +#define __W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) +#define __W_STOPCODE(sig) ((sig) << 8 | 0x7f) +#define __W_CONTINUED 0xffff +#define __WCOREFLAG 0x80 + +#define WEXITSTATUS(status) __WEXITSTATUS(status) +#define WTERMSIG(status) __WTERMSIG(status) +#define WIFEXITED(status) __WIFEXITED(status) + +#define WCOREFLAG __WCOREFLAG +#define W_EXITCODE(ret, sig) __W_EXITCODE(ret, sig) +#define W_STOPCODE(sig) __W_STOPCODE(sig) + +// First argument to waitid: +#define P_ALL 0 +#define P_PID 1 +#define P_PGID 2 +#define P_PIDFD 3 #endif // __LLVM_LIBC_MACROS_LINUX_SYS_WAIT_MACROS_H diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -1200,7 +1200,7 @@ HeaderSpec SysWait = HeaderSpec< "sys/wait.h", [], // Macros - [PidT, StructRUsage], + [PidT, StructRUsage, SigInfoType], [], // Enumerations [ FunctionSpec< diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp --- a/libc/src/__support/File/linux/file.cpp +++ b/libc/src/__support/File/linux/file.cpp @@ -66,12 +66,16 @@ #ifdef SYS_lseek int ret = __llvm_libc::syscall_impl(SYS_lseek, lf->get_fd(), offset, whence); result = ret; +#elif defined(SYS_llseek) + int ret = __llvm_libc::syscall_impl(SYS_llseek, lf->get_fd(), + (long)(((uint64_t)(offset)) >> 32), + (long)offset, &result, whence); + result = ret; #elif defined(SYS__llseek) - long result; int ret = __llvm_libc::syscall_impl(SYS__llseek, lf->get_fd(), offset >> 32, offset, &result, whence); #else -#error "lseek and _llseek syscalls not available to perform a seek operation." +#error "lseek, llseek and _llseek syscalls not available." #endif if (ret < 0) diff --git a/libc/src/__support/threads/linux/callonce.cpp b/libc/src/__support/threads/linux/callonce.cpp --- a/libc/src/__support/threads/linux/callonce.cpp +++ b/libc/src/__support/threads/linux/callonce.cpp @@ -34,7 +34,8 @@ func(); auto status = futex_word->exchange(FINISH); if (status == WAITING) { - __llvm_libc::syscall_impl(SYS_futex, &futex_word->val, FUTEX_WAKE_PRIVATE, + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &futex_word->val, + FUTEX_WAKE_PRIVATE, INT_MAX, // Wake all waiters. 0, 0, 0); } @@ -45,7 +46,7 @@ if (futex_word->compare_exchange_strong(status, WAITING) || status == WAITING) { __llvm_libc::syscall_impl( - SYS_futex, &futex_word->val, FUTEX_WAIT_PRIVATE, + FUTEX_SYSCALL_ID, &futex_word->val, FUTEX_WAIT_PRIVATE, WAITING, // Block only if status is still |WAITING|. 0, 0, 0); } diff --git a/libc/src/__support/threads/linux/futex_word.h b/libc/src/__support/threads/linux/futex_word.h --- a/libc/src/__support/threads/linux/futex_word.h +++ b/libc/src/__support/threads/linux/futex_word.h @@ -10,12 +10,21 @@ #define LLVM_LIBC_SRC_SUPPORT_THREADS_LINUX_FUTEX_WORD_H #include +#include namespace __llvm_libc { // Futexes are 32 bits in size on all platforms, including 64-bit platforms. using FutexWordType = uint32_t; +#if SYS_futex +constexpr auto FUTEX_SYSCALL_ID = SYS_futex; +#elif defined(SYS_futex_time64) +constexpr auto FUTEX_SYSCALL_ID = SYS_futex_time64; +#else +#error "futex and futex_time64 syscalls not available." +#endif + } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_SUPPORT_THREADS_LINUX_FUTEX_WORD_H diff --git a/libc/src/__support/threads/linux/mutex.h b/libc/src/__support/threads/linux/mutex.h --- a/libc/src/__support/threads/linux/mutex.h +++ b/libc/src/__support/threads/linux/mutex.h @@ -76,7 +76,7 @@ // futex syscall will block if the futex data is still // `LockState::Waiting` (the 4th argument to the syscall function // below.) - __llvm_libc::syscall_impl(SYS_futex, &futex_word.val, + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &futex_word.val, FUTEX_WAIT_PRIVATE, FutexWordType(LockState::Waiting), 0, 0, 0); was_waiting = true; @@ -91,7 +91,8 @@ // we will wait for the futex to be woken up. Note again that the // following syscall will block only if the futex data is still // `LockState::Waiting`. - __llvm_libc::syscall_impl(SYS_futex, &futex_word, FUTEX_WAIT_PRIVATE, + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &futex_word, + FUTEX_WAIT_PRIVATE, FutexWordType(LockState::Waiting), 0, 0, 0); was_waiting = true; } @@ -109,8 +110,8 @@ if (futex_word.compare_exchange_strong(mutex_status, FutexWordType(LockState::Free))) { // If any thread is waiting to be woken up, then do it. - __llvm_libc::syscall_impl(SYS_futex, &futex_word, FUTEX_WAKE_PRIVATE, 1, - 0, 0, 0); + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &futex_word, + FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); return MutexError::NONE; } diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp --- a/libc/src/__support/threads/linux/thread.cpp +++ b/libc/src/__support/threads/linux/thread.cpp @@ -328,7 +328,7 @@ #else asm volatile("mov x29, sp"); #endif -#elif defined(LIBC_TARGET_ARCH_IS_RISCV64) +#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) asm volatile("mv fp, sp"); #endif start_thread(); @@ -379,7 +379,7 @@ while (clear_tid->load() != 0) { // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE. - __llvm_libc::syscall_impl(SYS_futex, &clear_tid->val, FUTEX_WAIT, + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &clear_tid->val, FUTEX_WAIT, CLEAR_TID_VALUE, nullptr); } } diff --git a/libc/src/sched/linux/sched_rr_get_interval.cpp b/libc/src/sched/linux/sched_rr_get_interval.cpp --- a/libc/src/sched/linux/sched_rr_get_interval.cpp +++ b/libc/src/sched/linux/sched_rr_get_interval.cpp @@ -12,13 +12,36 @@ #include "src/__support/common.h" #include "src/errno/libc_errno.h" +#include // For __kernel_timespec. #include // For syscall numbers. namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, sched_rr_get_interval, (pid_t tid, struct timespec *tp)) { +#ifdef SYS_sched_rr_get_interval long ret = __llvm_libc::syscall_impl(SYS_sched_rr_get_interval, tid, tp); +#elif defined(SYS_sched_rr_get_interval_time64) + // The difference between the and SYS_sched_rr_get_interval + // SYS_sched_rr_get_interval_time64 syscalls is the data type used for the + // time interval parameter: the latter takes a struct __kernel_timespec + long ret; + if (tp) { + struct __kernel_timespec ts32; + ret = + __llvm_libc::syscall_impl(SYS_sched_rr_get_interval_time64, tid, &ts32); + if (ret == 0) { + tp->tv_sec = ts32.tv_sec; + tp->tv_nsec = ts32.tv_nsec; + } + } else + // When tp is a nullptr, we still do the syscall to set ret and errno + ret = __llvm_libc::syscall_impl(SYS_sched_rr_get_interval_time64, tid, + nullptr); +#else +#error \ + "sched_rr_get_interval and sched_rr_get_interval_time64 syscalls not available." +#endif if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/sys/select/linux/select.cpp b/libc/src/sys/select/linux/select.cpp --- a/libc/src/sys/select/linux/select.cpp +++ b/libc/src/sys/select/linux/select.cpp @@ -53,8 +53,15 @@ } } pselect6_sigset_t pss{nullptr, sizeof(sigset_t)}; +#if SYS_pselect6 long ret = __llvm_libc::syscall_impl(SYS_pselect6, nfds, read_set, write_set, error_set, &ts, &pss); +#elif defined(SYS_pselect6_time64) + long ret = __llvm_libc::syscall_impl(SYS_pselect6_time64, nfds, read_set, + write_set, error_set, &ts, &pss); +#else +#error "SYS_pselect6 and SYS_pselect6_time64 syscalls not available." +#endif if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/sys/sendfile/linux/sendfile.cpp b/libc/src/sys/sendfile/linux/sendfile.cpp --- a/libc/src/sys/sendfile/linux/sendfile.cpp +++ b/libc/src/sys/sendfile/linux/sendfile.cpp @@ -19,8 +19,17 @@ LLVM_LIBC_FUNCTION(ssize_t, sendfile, (int out_fd, int in_fd, off_t *offset, size_t count)) { +#ifdef SYS_sendfile long ret = __llvm_libc::syscall_impl(SYS_sendfile, in_fd, out_fd, offset, count); +#elif defined(SYS_sendfile64) + // Same as sendfile but can handle large offsets + static_assert(sizeof(off_t) == 8); + long ret = + __llvm_libc::syscall_impl(SYS_sendfile64, in_fd, out_fd, offset, count); +#else +#error "sendfile and sendfile64 syscalls not available." +#endif if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/sys/wait/linux/wait.cpp b/libc/src/sys/wait/linux/wait.cpp --- a/libc/src/sys/wait/linux/wait.cpp +++ b/libc/src/sys/wait/linux/wait.cpp @@ -6,29 +6,21 @@ // //===----------------------------------------------------------------------===// -#include "src/sys/wait/wait.h" - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_assert.h" -#include "src/errno/libc_errno.h" -#include // For syscall numbers. -#include +#include "src/sys/wait/wait.h" +#include "src/sys/wait/wait4Impl.h" namespace __llvm_libc { -// The implementation of wait here is very minimal. We will add more -// functionality and standard compliance in future. - LLVM_LIBC_FUNCTION(pid_t, wait, (int *wait_status)) { - pid_t pid = __llvm_libc::syscall_impl(SYS_wait4, -1, wait_status, 0, 0); - if (pid < 0) { - // Error case, a child process was not created. - libc_errno = -pid; + auto result = internal::wait4impl(-1, wait_status, 0, 0); + if (!result.has_value()) { + libc_errno = result.error(); return -1; } - - return pid; + return result.value(); } } // namespace __llvm_libc diff --git a/libc/src/sys/wait/linux/wait4.cpp b/libc/src/sys/wait/linux/wait4.cpp --- a/libc/src/sys/wait/linux/wait4.cpp +++ b/libc/src/sys/wait/linux/wait4.cpp @@ -6,26 +6,23 @@ // //===----------------------------------------------------------------------===// -#include "src/sys/wait/wait4.h" - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_assert.h" -#include "src/errno/libc_errno.h" -#include // For syscall numbers. -#include +#include "src/sys/wait/wait4.h" +#include "src/sys/wait/wait4Impl.h" namespace __llvm_libc { LLVM_LIBC_FUNCTION(pid_t, wait4, (pid_t pid, int *wait_status, int options, struct rusage *usage)) { - pid = __llvm_libc::syscall_impl(SYS_wait4, pid, wait_status, options, usage); - if (pid < 0) { - libc_errno = -pid; + auto result = internal::wait4impl(pid, wait_status, options, usage); + if (!result.has_value()) { + libc_errno = result.error(); return -1; } - return pid; + return result.value(); } } // namespace __llvm_libc diff --git a/libc/src/sys/wait/linux/waitpid.cpp b/libc/src/sys/wait/linux/waitpid.cpp --- a/libc/src/sys/wait/linux/waitpid.cpp +++ b/libc/src/sys/wait/linux/waitpid.cpp @@ -6,24 +6,21 @@ // //===----------------------------------------------------------------------===// -#include "src/sys/wait/waitpid.h" - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/libc_assert.h" -#include "src/errno/libc_errno.h" -#include // For syscall numbers. -#include +#include "src/sys/wait/wait4Impl.h" +#include "src/sys/wait/waitpid.h" namespace __llvm_libc { LLVM_LIBC_FUNCTION(pid_t, waitpid, (pid_t pid, int *wait_status, int options)) { - pid = __llvm_libc::syscall_impl(SYS_wait4, pid, wait_status, options, 0); - if (pid < 0) { - libc_errno = -pid; + auto result = internal::wait4impl(pid, wait_status, options, 0); + if (!result.has_value()) { + libc_errno = result.error(); return -1; } - return pid; + return result.value(); } } // namespace __llvm_libc diff --git a/libc/src/sys/wait/wait4Impl.h b/libc/src/sys/wait/wait4Impl.h new file mode 100644 --- /dev/null +++ b/libc/src/sys/wait/wait4Impl.h @@ -0,0 +1,84 @@ +//===-- String to integer conversion utils ----------------------*- 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_WAIT_WAIT4IMPL_H +#define LLVM_LIBC_SRC_SYS_WAIT_WAIT4IMPL_H + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/errno/libc_errno.h" + +#include +#include // For syscall numbers. +#include + +namespace __llvm_libc { +namespace internal { + +// The implementation of wait here is very minimal. We will add more +// functionality and standard compliance in future. + +LIBC_INLINE ErrorOr wait4impl(pid_t pid, int *wait_status, int options, + struct rusage *usage) { +#if SYS_wait4 + pid = __llvm_libc::syscall_impl(SYS_wait4, pid, wait_status, options, usage); +#elif defined(SYS_waitid) + int idtype = P_PID; + if (pid == -1) { + idtype = P_ALL; + } else if (pid < -1) { + idtype = P_PGID; + pid *= -1; + } else if (pid == 0) { + idtype = P_PGID; + } + + options |= WEXITED; + + siginfo_t info; + pid = + __llvm_libc::syscall_impl(SYS_waitid, idtype, pid, &info, options, usage); + if (pid >= 0) + pid = info.si_pid; + + if (wait_status) { + switch (info.si_code) { + case CLD_EXITED: + *wait_status = W_EXITCODE(info.si_status, 0); + break; + case CLD_DUMPED: + *wait_status = info.si_status | WCOREFLAG; + break; + case CLD_KILLED: + *wait_status = info.si_status; + break; + case CLD_TRAPPED: + case CLD_STOPPED: + *wait_status = W_STOPCODE(info.si_status); + break; + case CLD_CONTINUED: + *wait_status = __W_CONTINUED; + break; + default: + *wait_status = 0; + break; + } + } +#else +#error "wait4 and waitid syscalls not available." +#endif + if (pid < 0) + return Error(-pid); + return pid; +} + +} // namespace internal +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_WAIT_WAIT4IMPL_H diff --git a/libc/src/threads/linux/CndVar.h b/libc/src/threads/linux/CndVar.h --- a/libc/src/threads/linux/CndVar.h +++ b/libc/src/threads/linux/CndVar.h @@ -84,8 +84,8 @@ } } - __llvm_libc::syscall_impl(SYS_futex, &waiter.futex_word.val, FUTEX_WAIT, - WS_Waiting, 0, 0, 0); + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &waiter.futex_word.val, + FUTEX_WAIT, WS_Waiting, 0, 0, 0); // At this point, if locking |m| fails, we can simply return as the // queued up waiter would have been removed from the queue. @@ -110,7 +110,7 @@ qmtx.futex_word = FutexWordType(Mutex::LockState::Free); __llvm_libc::syscall_impl( - SYS_futex, &qmtx.futex_word.val, FUTEX_WAKE_OP, 1, 1, + FUTEX_SYSCALL_ID, &qmtx.futex_word.val, FUTEX_WAKE_OP, 1, 1, &first->futex_word.val, FUTEX_OP(FUTEX_OP_SET, WS_Signalled, FUTEX_OP_CMP_EQ, WS_Waiting)); return thrd_success; @@ -127,7 +127,7 @@ // up the waiter. A dummy location is used for the other futex of // FUTEX_WAKE_OP. __llvm_libc::syscall_impl( - SYS_futex, &dummy_futex_word, FUTEX_WAKE_OP, 1, 1, + FUTEX_SYSCALL_ID, &dummy_futex_word, FUTEX_WAKE_OP, 1, 1, &waiter->futex_word.val, FUTEX_OP(FUTEX_OP_SET, WS_Signalled, FUTEX_OP_CMP_EQ, WS_Waiting)); waiter = waiter->next; diff --git a/libc/src/threads/linux/call_once.cpp b/libc/src/threads/linux/call_once.cpp --- a/libc/src/threads/linux/call_once.cpp +++ b/libc/src/threads/linux/call_once.cpp @@ -46,7 +46,8 @@ func(); auto status = futex_word->exchange(FINISH); if (status == WAITING) { - __llvm_libc::syscall_impl(SYS_futex, &futex_word->val, FUTEX_WAKE_PRIVATE, + __llvm_libc::syscall_impl(FUTEX_SYSCALL_ID, &futex_word->val, + FUTEX_WAKE_PRIVATE, INT_MAX, // Wake all waiters. 0, 0, 0); } @@ -57,7 +58,7 @@ if (futex_word->compare_exchange_strong(status, WAITING) || status == WAITING) { __llvm_libc::syscall_impl( - SYS_futex, &futex_word->val, FUTEX_WAIT_PRIVATE, + FUTEX_SYSCALL_ID, &futex_word->val, FUTEX_WAIT_PRIVATE, WAITING, // Block only if status is still |WAITING|. 0, 0, 0); } diff --git a/libc/src/time/clock_gettime.cpp b/libc/src/time/clock_gettime.cpp --- a/libc/src/time/clock_gettime.cpp +++ b/libc/src/time/clock_gettime.cpp @@ -20,9 +20,18 @@ // TODO(michaelrj): Move this into time/linux with the other syscalls. LLVM_LIBC_FUNCTION(int, clock_gettime, (clockid_t clockid, struct timespec *tp)) { +#if SYS_clock_gettime long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime, static_cast(clockid), reinterpret_cast(tp)); +#elif defined(SYS_clock_gettime64) + long ret_val = + __llvm_libc::syscall_impl(SYS_clock_gettime64, static_cast(clockid), + reinterpret_cast(tp)); +#else +#error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available." +#endif + // A negative return value indicates an error with the magnitude of the // value being the error code. if (ret_val < 0) { diff --git a/libc/src/time/gettimeofday.cpp b/libc/src/time/gettimeofday.cpp --- a/libc/src/time/gettimeofday.cpp +++ b/libc/src/time/gettimeofday.cpp @@ -22,9 +22,17 @@ if (tv == nullptr) return 0; struct timespec tp; +#if SYS_clock_gettime long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime, static_cast(CLOCK_REALTIME), reinterpret_cast(&tp)); +#elif defined(SYS_clock_gettime64) + long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime64, + static_cast(CLOCK_REALTIME), + reinterpret_cast(&tp)); +#else +#error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available." +#endif // A negative return value indicates an error with the magnitude of the // value being the error code. if (ret_val < 0) { diff --git a/libc/src/time/linux/clock.cpp b/libc/src/time/linux/clock.cpp --- a/libc/src/time/linux/clock.cpp +++ b/libc/src/time/linux/clock.cpp @@ -20,8 +20,16 @@ LLVM_LIBC_FUNCTION(clock_t, clock, ()) { struct timespec ts; +#if SYS_clock_gettime long ret_val = __llvm_libc::syscall_impl( SYS_clock_gettime, CLOCK_PROCESS_CPUTIME_ID, reinterpret_cast(&ts)); +#elif defined(SYS_clock_gettime64) + long ret_val = + __llvm_libc::syscall_impl(SYS_clock_gettime64, CLOCK_PROCESS_CPUTIME_ID, + reinterpret_cast(&ts)); +#else +#error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available." +#endif if (ret_val < 0) { libc_errno = -ret_val; return clock_t(-1); diff --git a/libc/src/time/linux/time.cpp b/libc/src/time/linux/time.cpp --- a/libc/src/time/linux/time.cpp +++ b/libc/src/time/linux/time.cpp @@ -20,8 +20,15 @@ LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) { // TODO: Use the Linux VDSO to fetch the time and avoid the syscall. struct timespec ts; +#if SYS_clock_gettime long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime, CLOCK_REALTIME, reinterpret_cast(&ts)); +#elif defined(SYS_clock_gettime64) + long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime64, CLOCK_REALTIME, + reinterpret_cast(&ts)); +#else +#error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available." +#endif if (ret_val < 0) { libc_errno = -ret_val; return -1; diff --git a/libc/src/time/nanosleep.cpp b/libc/src/time/nanosleep.cpp --- a/libc/src/time/nanosleep.cpp +++ b/libc/src/time/nanosleep.cpp @@ -19,7 +19,14 @@ // TODO(michaelrj): Move this into time/linux with the other syscalls. LLVM_LIBC_FUNCTION(int, nanosleep, (const struct timespec *req, struct timespec *rem)) { +#if SYS_nanosleep int ret = __llvm_libc::syscall_impl(SYS_nanosleep, req, rem); +#elif defined(SYS_clock_nanosleep_time64) + int ret = __llvm_libc::syscall_impl(SYS_clock_nanosleep_time64, req, rem); +#else +#error "SYS_nanosleep and SYS_clock_nanosleep_time64 syscalls not available." +#endif + if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/unistd/linux/dup2.cpp b/libc/src/unistd/linux/dup2.cpp --- a/libc/src/unistd/linux/dup2.cpp +++ b/libc/src/unistd/linux/dup2.cpp @@ -27,7 +27,15 @@ // separately before making the dup3 syscall. if (oldfd == newfd) { // Check if oldfd is actually a valid file descriptor. +#if SYS_fcntl long ret = __llvm_libc::syscall_impl(SYS_fcntl, oldfd, F_GETFD); +#elif defined(SYS_fcntl64) + // Same as fcntl but can handle large offsets + static_assert(sizeof(off_t) == 8); + long ret = __llvm_libc::syscall_impl(SYS_fcntl64, oldfd, F_GETFD); +#else +#error "SYS_fcntl and SYS_fcntl64 syscalls not available." +#endif if (ret >= 0) return oldfd; libc_errno = -ret; diff --git a/libc/src/unistd/linux/ftruncate.cpp b/libc/src/unistd/linux/ftruncate.cpp --- a/libc/src/unistd/linux/ftruncate.cpp +++ b/libc/src/unistd/linux/ftruncate.cpp @@ -12,13 +12,24 @@ #include "src/__support/common.h" #include "src/errno/libc_errno.h" +#include // For uint64_t. #include // For syscall numbers. #include namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, ftruncate, (int fd, off_t len)) { +#ifdef SYS_ftruncate int ret = __llvm_libc::syscall_impl(SYS_ftruncate, fd, len); +#elif defined(SYS_ftruncate64) + // Same as ftruncate but can handle large offsets + static_assert(sizeof(off_t) == 8); + int ret = __llvm_libc::syscall_impl(SYS_ftruncate64, fd, (long)len, + (long)(((uint64_t)(len)) >> 32)); +#else +#error "ftruncate and ftruncate64 syscalls not available." +#endif + if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/unistd/linux/lseek.cpp b/libc/src/unistd/linux/lseek.cpp --- a/libc/src/unistd/linux/lseek.cpp +++ b/libc/src/unistd/linux/lseek.cpp @@ -12,6 +12,7 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include #include // For syscall numbers. #include @@ -22,11 +23,16 @@ #ifdef SYS_lseek long ret = __llvm_libc::syscall_impl(SYS_lseek, fd, offset, whence); result = ret; +#elif defined(SYS_llseek) + long ret = __llvm_libc::syscall_impl(SYS_llseek, fd, + (long)(((uint64_t)(offset)) >> 32), + (long)offset, &result, whence); + result = ret; #elif defined(SYS__llseek) long ret = __llvm_libc::syscall_impl(SYS__llseek, fd, offset >> 32, offset, &result, whence); #else -#error "lseek and _llseek syscalls not available." +#error "lseek, llseek and _llseek syscalls not available." #endif if (ret < 0) { diff --git a/libc/src/unistd/linux/pread.cpp b/libc/src/unistd/linux/pread.cpp --- a/libc/src/unistd/linux/pread.cpp +++ b/libc/src/unistd/linux/pread.cpp @@ -12,13 +12,21 @@ #include "src/__support/common.h" #include "src/errno/libc_errno.h" +#include // For uint64_t. #include // For syscall numbers. namespace __llvm_libc { LLVM_LIBC_FUNCTION(ssize_t, pread, (int fd, void *buf, size_t count, off_t offset)) { +#ifdef LIBC_TARGET_ARCH_IS_RISCV32 + static_assert(sizeof(off_t) == 8); + long ret = + __llvm_libc::syscall_impl(SYS_pread64, fd, buf, count, (long)offset, + (long)(((uint64_t)(offset)) >> 32)); +#else long ret = __llvm_libc::syscall_impl(SYS_pread64, fd, buf, count, offset); +#endif if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/unistd/linux/pwrite.cpp b/libc/src/unistd/linux/pwrite.cpp --- a/libc/src/unistd/linux/pwrite.cpp +++ b/libc/src/unistd/linux/pwrite.cpp @@ -12,13 +12,21 @@ #include "src/__support/common.h" #include "src/errno/libc_errno.h" +#include // For uint64_t. #include // For syscall numbers. namespace __llvm_libc { LLVM_LIBC_FUNCTION(ssize_t, pwrite, (int fd, const void *buf, size_t count, off_t offset)) { +#ifdef LIBC_TARGET_ARCH_IS_RISCV32 + static_assert(sizeof(off_t) == 8); + long ret = + __llvm_libc::syscall_impl(SYS_pwrite64, fd, buf, count, (long)offset, + (long)(((uint64_t)(offset)) >> 32)); +#else long ret = __llvm_libc::syscall_impl(SYS_pwrite64, fd, buf, count, offset); +#endif if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/src/unistd/linux/truncate.cpp b/libc/src/unistd/linux/truncate.cpp --- a/libc/src/unistd/linux/truncate.cpp +++ b/libc/src/unistd/linux/truncate.cpp @@ -12,13 +12,23 @@ #include "src/__support/common.h" #include "src/errno/libc_errno.h" +#include // For uint64_t. #include // For syscall numbers. #include namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, truncate, (const char *path, off_t len)) { +#ifdef SYS_truncate int ret = __llvm_libc::syscall_impl(SYS_truncate, path, len); +#elif defined(SYS_truncate64) + // Same as truncate but can handle large offsets + static_assert(sizeof(off_t) == 8); + int ret = __llvm_libc::syscall_impl(SYS_truncate64, path, (long)len, + (long)(((uint64_t)(len)) >> 32)); +#else +#error "truncate and truncate64 syscalls not available." +#endif if (ret < 0) { libc_errno = -ret; return -1; diff --git a/libc/test/src/sched/sched_rr_get_interval_test.cpp b/libc/test/src/sched/sched_rr_get_interval_test.cpp --- a/libc/test/src/sched/sched_rr_get_interval_test.cpp +++ b/libc/test/src/sched/sched_rr_get_interval_test.cpp @@ -29,7 +29,8 @@ }; auto TimespecToNs = [](struct timespec t) { - return t.tv_sec * 1000UL * 1000UL * 1000UL + t.tv_nsec; + return static_cast(t.tv_sec * 1000UL * 1000UL * 1000UL + + t.tv_nsec); }; struct timespec ts;