17 changes: 7 additions & 10 deletions libc/src/sys/wait/linux/waitpid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
84 changes: 84 additions & 0 deletions libc/src/sys/wait/wait4Impl.h
Original file line number Diff line number Diff line change
@@ -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
8 changes: 4 additions & 4 deletions libc/src/threads/linux/CndVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand All @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions libc/src/threads/linux/call_once.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down
9 changes: 9 additions & 0 deletions libc/src/time/clock_gettime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 8 additions & 0 deletions libc/src/time/gettimeofday.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 8 additions & 0 deletions libc/src/time/linux/clock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions libc/src/time/linux/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions libc/src/time/nanosleep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions libc/src/unistd/linux/dup2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions libc/src/unistd/linux/ftruncate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion libc/src/unistd/linux/lseek.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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) {
Expand Down
8 changes: 8 additions & 0 deletions libc/src/unistd/linux/pread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions libc/src/unistd/linux/pwrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions libc/src/unistd/linux/truncate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions libc/test/src/sched/sched_rr_get_interval_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down