[libc-commits] [libc] c9783d2 - [libc] Add support to compile some syscalls on 32 bit platform

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Thu Aug 3 06:08:17 PDT 2023


Author: Mikhail R. Gadelha
Date: 2023-08-03T10:08:01-03:00
New Revision: c9783d2bda95ec6921b3ca2df930b17af3a6c7b1

URL: https://github.com/llvm/llvm-project/commit/c9783d2bda95ec6921b3ca2df930b17af3a6c7b1
DIFF: https://github.com/llvm/llvm-project/commit/c9783d2bda95ec6921b3ca2df930b17af3a6c7b1.diff

LOG: [libc] Add support to compile some syscalls on 32 bit platform

This patch adds a bunch of ifdefs to handle the 32 bit versions of
some syscalls, which often only append a 64 to the name of the syscall
(with exception of SYS_lseek -> SYS_llseek and SYS_futex ->
SYS_futex_time64)

This patch also tries to handle cases where wait4 is not available
(as in riscv32): to implement wait, wait4 and waitpid when wait4 is
not available, we check for alternative wait calls and ultimately rely
on waitid to implement them all.

In riscv32, only waitid is available, so we need it to support this
platform.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D148371

Added: 
    libc/src/sys/wait/wait4Impl.h

Modified: 
    libc/config/linux/api.td
    libc/config/linux/syscall_numbers.h.inc
    libc/include/CMakeLists.txt
    libc/include/llvm-libc-macros/linux/signal-macros.h
    libc/include/llvm-libc-macros/linux/sys-wait-macros.h
    libc/spec/posix.td
    libc/src/__support/File/linux/file.cpp
    libc/src/__support/threads/linux/callonce.cpp
    libc/src/__support/threads/linux/futex_word.h
    libc/src/__support/threads/linux/mutex.h
    libc/src/__support/threads/linux/thread.cpp
    libc/src/sched/linux/sched_rr_get_interval.cpp
    libc/src/sys/select/linux/select.cpp
    libc/src/sys/sendfile/linux/sendfile.cpp
    libc/src/sys/wait/linux/wait.cpp
    libc/src/sys/wait/linux/wait4.cpp
    libc/src/sys/wait/linux/waitpid.cpp
    libc/src/threads/linux/CndVar.h
    libc/src/threads/linux/call_once.cpp
    libc/src/time/clock_gettime.cpp
    libc/src/time/gettimeofday.cpp
    libc/src/time/linux/clock.cpp
    libc/src/time/linux/time.cpp
    libc/src/time/nanosleep.cpp
    libc/src/unistd/linux/dup2.cpp
    libc/src/unistd/linux/ftruncate.cpp
    libc/src/unistd/linux/lseek.cpp
    libc/src/unistd/linux/pread.cpp
    libc/src/unistd/linux/pwrite.cpp
    libc/src/unistd/linux/truncate.cpp
    libc/test/src/sched/sched_rr_get_interval_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 73cc5be1623baf..377763b97cfd95 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -219,7 +219,7 @@ def SysStatAPI : PublicAPI<"sys/stat.h"> {
 }
 
 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
index c5d49b80f51d8b..5bbb08878ef9df 100644
--- 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
index 94dc65356dabfa..ab04b8d2e5ca8c 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -467,6 +467,7 @@ add_gen_header(
     .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
index 4dc39dec47de87..deb190ec375998 100644
--- 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
index ad66d050334f1f..3e6c6f53cc7171 100644
--- 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
index 54c6eb5f4c2420..d09c7228549dfc 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -1200,7 +1200,7 @@ def POSIX : StandardSpec<"POSIX"> {
   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
index caa7bae36a9eb5..5a6723dcf745be 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -66,12 +66,16 @@ ErrorOr<long> seek_func(File *f, long offset, int whence) {
 #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
index 7dc957f0129cda..a1294182423ec0 100644
--- a/libc/src/__support/threads/linux/callonce.cpp
+++ b/libc/src/__support/threads/linux/callonce.cpp
@@ -34,7 +34,8 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) {
     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 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) {
   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
index 12a07329ae8d21..dc9af96f0a667c 100644
--- 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 <stdint.h>
+#include <sys/syscall.h>
 
 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
index 19221c97aeffb0..f8b9af40818732 100644
--- a/libc/src/__support/threads/linux/mutex.h
+++ b/libc/src/__support/threads/linux/mutex.h
@@ -76,7 +76,7 @@ struct Mutex {
         // 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 @@ struct Mutex {
           // 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 @@ struct Mutex {
       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
index 994057aa949ab5..84122d5537b3f8 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -328,7 +328,7 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack,
 #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 @@ void Thread::wait() {
   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
index 418c3fdacdb350..b79e96d08a6ecf 100644
--- 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 <linux/time_types.h> // For __kernel_timespec.
 #include <sys/syscall.h> // 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 
diff erence 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
index e77aafeb902984..b9147fa2ad1674 100644
--- a/libc/src/sys/select/linux/select.cpp
+++ b/libc/src/sys/select/linux/select.cpp
@@ -53,8 +53,15 @@ LLVM_LIBC_FUNCTION(int, select,
     }
   }
   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
index d54100dfe57d29..49e4424200dff6 100644
--- a/libc/src/sys/sendfile/linux/sendfile.cpp
+++ b/libc/src/sys/sendfile/linux/sendfile.cpp
@@ -19,8 +19,17 @@ namespace __llvm_libc {
 
 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
index 497d3e1754df31..855d45242741cc 100644
--- 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 <sys/syscall.h> // For syscall numbers.
-#include <sys/wait.h>
+#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
index 157aa991d66e4a..f73f57be7b18e7 100644
--- 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 <sys/syscall.h> // For syscall numbers.
-#include <sys/wait.h>
+#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
index 9b9538aef77dc2..0ad83ae0d72ea7 100644
--- 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 <sys/syscall.h> // For syscall numbers.
-#include <sys/wait.h>
+#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
index 00000000000000..1fa7066641149f
--- /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 <sys/signal.h>
+#include <sys/syscall.h> // For syscall numbers.
+#include <sys/wait.h>
+
+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<pid_t> 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
index c6b0ea63280a42..e3585ae38d3ba6 100644
--- a/libc/src/threads/linux/CndVar.h
+++ b/libc/src/threads/linux/CndVar.h
@@ -84,8 +84,8 @@ struct CndVar {
       }
     }
 
-    __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 @@ struct CndVar {
     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 @@ struct CndVar {
       // 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
index ac87a0d877d3b0..6a9c819b7853b6 100644
--- a/libc/src/threads/linux/call_once.cpp
+++ b/libc/src/threads/linux/call_once.cpp
@@ -46,7 +46,8 @@ LLVM_LIBC_FUNCTION(void, call_once,
     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 @@ LLVM_LIBC_FUNCTION(void, call_once,
   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
index 0bd14a11493637..9b50dd2fc87d99 100644
--- a/libc/src/time/clock_gettime.cpp
+++ b/libc/src/time/clock_gettime.cpp
@@ -20,9 +20,18 @@ namespace __llvm_libc {
 // 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<long>(clockid),
                                 reinterpret_cast<long>(tp));
+#elif defined(SYS_clock_gettime64)
+  long ret_val =
+      __llvm_libc::syscall_impl(SYS_clock_gettime64, static_cast<long>(clockid),
+                                reinterpret_cast<long>(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
index 914b5826e9cfb8..e636d9fd0bffeb 100644
--- a/libc/src/time/gettimeofday.cpp
+++ b/libc/src/time/gettimeofday.cpp
@@ -22,9 +22,17 @@ LLVM_LIBC_FUNCTION(int, gettimeofday,
   if (tv == nullptr)
     return 0;
   struct timespec tp;
+#if SYS_clock_gettime
   long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime,
                                            static_cast<long>(CLOCK_REALTIME),
                                            reinterpret_cast<long>(&tp));
+#elif defined(SYS_clock_gettime64)
+  long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime64,
+                                           static_cast<long>(CLOCK_REALTIME),
+                                           reinterpret_cast<long>(&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
index f72e4fcf372967..881b2bf429a29a 100644
--- a/libc/src/time/linux/clock.cpp
+++ b/libc/src/time/linux/clock.cpp
@@ -20,8 +20,16 @@ namespace __llvm_libc {
 
 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<long>(&ts));
+#elif defined(SYS_clock_gettime64)
+  long ret_val =
+      __llvm_libc::syscall_impl(SYS_clock_gettime64, CLOCK_PROCESS_CPUTIME_ID,
+                                reinterpret_cast<long>(&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
index 02b55a2f4c0267..d2e9a4f07265de 100644
--- a/libc/src/time/linux/time.cpp
+++ b/libc/src/time/linux/time.cpp
@@ -20,8 +20,15 @@ namespace __llvm_libc {
 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<long>(&ts));
+#elif defined(SYS_clock_gettime64)
+  long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime64, CLOCK_REALTIME,
+                                           reinterpret_cast<long>(&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
index bd812692917c95..46f3199ad4baf4 100644
--- a/libc/src/time/nanosleep.cpp
+++ b/libc/src/time/nanosleep.cpp
@@ -19,7 +19,14 @@ namespace __llvm_libc {
 // 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
index 5cdd5d10b07754..b03d282389678d 100644
--- a/libc/src/unistd/linux/dup2.cpp
+++ b/libc/src/unistd/linux/dup2.cpp
@@ -27,7 +27,15 @@ LLVM_LIBC_FUNCTION(int, dup2, (int oldfd, int newfd)) {
   // 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
index b1e170dd378c48..b534bbdff78e9a 100644
--- 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 <stdint.h>      // For uint64_t.
 #include <sys/syscall.h> // For syscall numbers.
 #include <unistd.h>
 
 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
index aef3ffbcd48808..c1d3c360ac3fd3 100644
--- 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 <stdint.h>
 #include <sys/syscall.h> // For syscall numbers.
 #include <unistd.h>
 
@@ -22,11 +23,16 @@ LLVM_LIBC_FUNCTION(off_t, lseek, (int fd, off_t offset, int whence)) {
 #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
index d308e96fc22a55..624028f35ce4eb 100644
--- 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 <stdint.h>      // For uint64_t.
 #include <sys/syscall.h> // 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
index 71f287ae39275a..194117dfd0ec99 100644
--- 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 <stdint.h>      // For uint64_t.
 #include <sys/syscall.h> // 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
index 60b4c5395cbbb7..0ddff787eaec35 100644
--- 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 <stdint.h>      // For uint64_t.
 #include <sys/syscall.h> // For syscall numbers.
 #include <unistd.h>
 
 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
index 3315bf945db298..160ccd5025967e 100644
--- 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 @@ TEST(LlvmLibcSchedRRGetIntervalTest, SmokeTest) {
   };
 
   auto TimespecToNs = [](struct timespec t) {
-    return t.tv_sec * 1000UL * 1000UL * 1000UL + t.tv_nsec;
+    return static_cast<uint64_t>(t.tv_sec * 1000UL * 1000UL * 1000UL +
+                                 t.tv_nsec);
   };
 
   struct timespec ts;
@@ -49,8 +50,10 @@ TEST(LlvmLibcSchedRRGetIntervalTest, SmokeTest) {
     ASSERT_EQ(libc_errno, 0);
 
     // Check that numbers make sense (liberal bound of 10ns - 30sec)
-    ASSERT_GT(TimespecToNs(ts), 10UL);
-    ASSERT_LT(TimespecToNs(ts), 30UL * 1000UL * 1000UL * 1000UL);
+    constexpr uint64_t tenNs = 10UL;
+    ASSERT_GT(TimespecToNs(ts), tenNs);
+    constexpr uint64_t thirstyS = 30UL * 1000UL * 1000UL * 1000UL;
+    ASSERT_LT(TimespecToNs(ts), thirstyS);
 
     // Null timespec
     ASSERT_EQ(__llvm_libc::sched_rr_get_interval(0, nullptr), -1);


        


More information about the libc-commits mailing list