Skip to content

Commit

Permalink
[libc] Add support to compile some syscalls on 32 bit platform
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mikhailramalho committed Aug 3, 2023
1 parent 1b5a3c9 commit c9783d2
Show file tree
Hide file tree
Showing 32 changed files with 329 additions and 63 deletions.
2 changes: 1 addition & 1 deletion libc/config/linux/api.td
Original file line number Diff line number Diff line change
Expand Up @@ -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"> {
Expand Down
21 changes: 20 additions & 1 deletion libc/config/linux/syscall_numbers.h.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2317,4 +2337,3 @@
#ifdef __NR_writev
#define SYS_writev __NR_writev
#endif

1 change: 1 addition & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
8 changes: 8 additions & 0 deletions libc/include/llvm-libc-macros/linux/signal-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
30 changes: 25 additions & 5 deletions libc/include/llvm-libc-macros/linux/sys-wait-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion libc/spec/posix.td
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,7 @@ def POSIX : StandardSpec<"POSIX"> {
HeaderSpec SysWait = HeaderSpec<
"sys/wait.h",
[], // Macros
[PidT, StructRUsage],
[PidT, StructRUsage, SigInfoType],
[], // Enumerations
[
FunctionSpec<
Expand Down
8 changes: 6 additions & 2 deletions libc/src/__support/File/linux/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions libc/src/__support/threads/linux/callonce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down
9 changes: 9 additions & 0 deletions libc/src/__support/threads/linux/futex_word.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 5 additions & 4 deletions libc/src/__support/threads/linux/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions libc/src/__support/threads/linux/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}
Expand Down
23 changes: 23 additions & 0 deletions libc/src/sched/linux/sched_rr_get_interval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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;
Expand Down
7 changes: 7 additions & 0 deletions libc/src/sys/select/linux/select.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions libc/src/sys/sendfile/linux/sendfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 7 additions & 15 deletions libc/src/sys/wait/linux/wait.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
17 changes: 7 additions & 10 deletions libc/src/sys/wait/linux/wait4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit c9783d2

Please sign in to comment.