Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ NM ?= $(patsubst %clang,%llvm-nm,$(filter-out ccache sccache,$(CC)))
ifeq ($(origin AR), default)
AR = $(patsubst %clang,%llvm-ar,$(filter-out ccache sccache,$(CC)))
endif
ifeq ($(DEBUG), true)
EXTRA_CFLAGS ?= -O0 -g
else
EXTRA_CFLAGS ?= -O2 -DNDEBUG
endif
# The directory where we build the sysroot.
SYSROOT ?= $(CURDIR)/sysroot
# A directory to install to for "make install".
Expand Down
3 changes: 3 additions & 0 deletions expected/wasm32-wasip2/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ ctime_r
descriptor_table_get_ref
descriptor_table_insert
descriptor_table_remove
descriptor_table_update
difftime
dirfd
dirname
Expand All @@ -575,6 +576,8 @@ dprintf
drand48
drem
dremf
drop_directory_stream
drop_file_handle
drop_tcp_socket
drop_udp_socket
drop_udp_socket_streams
Expand Down
28 changes: 28 additions & 0 deletions libc-bottom-half/clocks/clock.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
#define _WASI_EMULATED_PROCESS_CLOCKS
#include <time.h>
#ifdef __wasilibc_use_wasip2
#include <wasi/wasip2.h>
#else
#include <wasi/api.h>
#endif
#include <common/time.h>

_Static_assert(
CLOCKS_PER_SEC == NSEC_PER_SEC,
"This implementation assumes that `clock` is in nanoseconds"
);

#ifdef __wasilibc_use_wasip2
// Snapshot of the monotonic clock at the start of the program.
static monotonic_clock_instant_t start;

// Use a priority of 10 to run fairly early in the implementation-reserved
// constructor priority range.
__attribute__((constructor(10)))
static void init(void) {
start = monotonic_clock_now();
}

// Define the libc symbol as `__clock` so that we can reliably call it
// from elsewhere in libc.
clock_t __clock(void) {
// Use `MONOTONIC` instead of `PROCESS_CPUTIME_ID` since WASI doesn't have
// an inherent concept of a process. Note that this means we'll incorrectly
// include time from other processes, so this function is only declared by
// the headers if `_WASI_EMULATED_PROCESS_CLOCKS` is defined.
monotonic_clock_instant_t now = monotonic_clock_now();
return now - start;
}
#else

// Snapshot of the monotonic clock at the start of the program.
static __wasi_timestamp_t start;

Expand All @@ -29,6 +56,7 @@ clock_t __clock(void) {
(void)__wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, &now);
return now - start;
}
#endif

// Define a user-visible alias as a weak symbol.
__attribute__((__weak__, __alias__("__clock")))
Expand Down
11 changes: 11 additions & 0 deletions libc-bottom-half/clocks/getrusage.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
#include <sys/resource.h>
#include <errno.h>
#include <time.h>
#ifdef __wasilibc_use_wasip2
#include <wasi/wasip2.h>
#else
#include <wasi/api.h>
#endif
#include <common/time.h>

// `clock` is a weak symbol so that application code can override it.
Expand All @@ -12,10 +16,17 @@ clock_t __clock(void);
int getrusage(int who, struct rusage *r_usage) {
switch (who) {
case RUSAGE_SELF: {
#ifdef __wasilibc_use_wasip2
clock_t usertime = __clock();
*r_usage = (struct rusage) {
.ru_utime = instant_to_timeval(usertime)
};
#else
__wasi_timestamp_t usertime = __clock();
*r_usage = (struct rusage) {
.ru_utime = timestamp_to_timeval(usertime)
};
#endif
return 0;
}
case RUSAGE_CHILDREN:
Expand Down
16 changes: 16 additions & 0 deletions libc-bottom-half/clocks/times.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#define _WASI_EMULATED_PROCESS_CLOCKS
#include <time.h>
#include <sys/times.h>
#ifdef __wasilibc_use_wasip2
#include <wasi/wasip2.h>
#else
#include <wasi/api.h>
#endif
#include <common/time.h>

_Static_assert(
Expand All @@ -14,6 +18,17 @@ _Static_assert(
clock_t __clock(void);

clock_t times(struct tms *buffer) {
#ifdef __wasilibc_use_wasip2
clock_t user = __clock();
*buffer = (struct tms){
.tms_utime = user,
// WASI doesn't provide a way to spawn a new process, so always 0.
.tms_cutime = 0
};

monotonic_clock_instant_t realtime = monotonic_clock_now();
#else

__wasi_timestamp_t user = __clock();
*buffer = (struct tms){
.tms_utime = user,
Expand All @@ -23,5 +38,6 @@ clock_t times(struct tms *buffer) {

__wasi_timestamp_t realtime = 0;
(void)__wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, &realtime);
#endif
return realtime;
}
122 changes: 122 additions & 0 deletions libc-bottom-half/cloudlibc/src/common/errors.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#ifdef __wasilibc_use_wasip2
#include <wasi/wasip2.h>
#include <errno.h>

static void translate_error(filesystem_error_code_t error) {
switch (error) {
case FILESYSTEM_ERROR_CODE_ACCESS:
errno = __WASI_ERRNO_ACCES;
break;
case FILESYSTEM_ERROR_CODE_WOULD_BLOCK:
errno = __WASI_ERRNO_AGAIN;
break;
case FILESYSTEM_ERROR_CODE_ALREADY:
errno = __WASI_ERRNO_ALREADY;
break;
case FILESYSTEM_ERROR_CODE_BAD_DESCRIPTOR:
errno = __WASI_ERRNO_BADF;
break;
case FILESYSTEM_ERROR_CODE_BUSY:
errno = __WASI_ERRNO_BUSY;
break;
case FILESYSTEM_ERROR_CODE_DEADLOCK:
errno = __WASI_ERRNO_DEADLK;
break;
case FILESYSTEM_ERROR_CODE_QUOTA:
errno = __WASI_ERRNO_DQUOT;
break;
case FILESYSTEM_ERROR_CODE_EXIST:
errno = __WASI_ERRNO_EXIST;
break;
case FILESYSTEM_ERROR_CODE_FILE_TOO_LARGE:
errno = __WASI_ERRNO_FBIG;
break;
case FILESYSTEM_ERROR_CODE_ILLEGAL_BYTE_SEQUENCE:
errno = __WASI_ERRNO_ILSEQ;
break;
case FILESYSTEM_ERROR_CODE_IN_PROGRESS:
errno = __WASI_ERRNO_INPROGRESS;
break;
case FILESYSTEM_ERROR_CODE_INTERRUPTED:
errno = __WASI_ERRNO_INTR;
break;
case FILESYSTEM_ERROR_CODE_INVALID:
errno = __WASI_ERRNO_INVAL;
break;
case FILESYSTEM_ERROR_CODE_IO:
errno = __WASI_ERRNO_IO;
break;
case FILESYSTEM_ERROR_CODE_IS_DIRECTORY:
errno = __WASI_ERRNO_ISDIR;
break;
case FILESYSTEM_ERROR_CODE_LOOP:
errno = __WASI_ERRNO_LOOP;
break;
case FILESYSTEM_ERROR_CODE_TOO_MANY_LINKS:
errno = __WASI_ERRNO_MLINK;
break;
case FILESYSTEM_ERROR_CODE_MESSAGE_SIZE:
errno = __WASI_ERRNO_MSGSIZE;
break;
case FILESYSTEM_ERROR_CODE_NAME_TOO_LONG:
errno = __WASI_ERRNO_NAMETOOLONG;
break;
case FILESYSTEM_ERROR_CODE_NO_DEVICE:
errno = __WASI_ERRNO_NODEV;
break;
case FILESYSTEM_ERROR_CODE_NO_ENTRY:
errno = __WASI_ERRNO_NOENT;
break;
case FILESYSTEM_ERROR_CODE_NO_LOCK:
errno = __WASI_ERRNO_NOLCK;
break;
case FILESYSTEM_ERROR_CODE_INSUFFICIENT_MEMORY:
errno = __WASI_ERRNO_NOMEM;
break;
case FILESYSTEM_ERROR_CODE_INSUFFICIENT_SPACE:
errno = __WASI_ERRNO_NOSPC;
break;
case FILESYSTEM_ERROR_CODE_NOT_DIRECTORY:
errno = __WASI_ERRNO_NOTDIR;
break;
case FILESYSTEM_ERROR_CODE_NOT_EMPTY:
errno = __WASI_ERRNO_NOTEMPTY;
break;
case FILESYSTEM_ERROR_CODE_NOT_RECOVERABLE:
errno = __WASI_ERRNO_NOTRECOVERABLE;
break;
case FILESYSTEM_ERROR_CODE_UNSUPPORTED:
errno = __WASI_ERRNO_NOTSUP;
break;
case FILESYSTEM_ERROR_CODE_NO_TTY:
errno = __WASI_ERRNO_NOTTY;
break;
case FILESYSTEM_ERROR_CODE_NO_SUCH_DEVICE:
errno = __WASI_ERRNO_NXIO;
break;
case FILESYSTEM_ERROR_CODE_OVERFLOW:
errno = __WASI_ERRNO_OVERFLOW;
break;
case FILESYSTEM_ERROR_CODE_NOT_PERMITTED:
errno = __WASI_ERRNO_PERM;
break;
case FILESYSTEM_ERROR_CODE_PIPE:
errno = __WASI_ERRNO_PIPE;
break;
case FILESYSTEM_ERROR_CODE_READ_ONLY:
errno = __WASI_ERRNO_ROFS;
break;
case FILESYSTEM_ERROR_CODE_INVALID_SEEK:
errno = __WASI_ERRNO_SPIPE;
break;
case FILESYSTEM_ERROR_CODE_TEXT_FILE_BUSY:
errno = __WASI_ERRNO_TXTBSY;
break;
case FILESYSTEM_ERROR_CODE_CROSS_DEVICE:
errno = __WASI_ERRNO_XDEV;
break;
default:
abort(); // Unreachable
}
}
#endif
67 changes: 61 additions & 6 deletions libc-bottom-half/cloudlibc/src/common/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@

#include <sys/time.h>

#ifdef __wasilibc_use_wasip2
#include <wasi/wasip2.h>
#else
#include <wasi/api.h>
#endif
#include <stdbool.h>
#include <time.h>

#define NSEC_PER_SEC 1000000000

static inline bool timespec_to_timestamp_exact(
const struct timespec *timespec, __wasi_timestamp_t *timestamp) {
#ifdef __wasilibc_use_wasip2
const struct timespec *timespec, wall_clock_datetime_t *timestamp) {
#else
const struct timespec *timespec, __wasi_timestamp_t *timestamp) {
#endif
// Invalid nanoseconds field.
if (timespec->tv_nsec < 0 || timespec->tv_nsec >= NSEC_PER_SEC)
return false;
Expand All @@ -25,39 +33,86 @@ static inline bool timespec_to_timestamp_exact(
if (timespec->tv_sec < 0)
return false;

#ifdef __wasilibc_use_wasip2
timestamp->seconds = timespec->tv_sec;
timestamp->nanoseconds = timespec->tv_nsec;
return true;
#else
// Make sure our timestamp does not overflow.
return !__builtin_mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) &&
!__builtin_add_overflow(*timestamp, timespec->tv_nsec, timestamp);
#endif
}

static inline bool timespec_to_timestamp_clamp(
const struct timespec *timespec, __wasi_timestamp_t *timestamp) {
#ifdef __wasilibc_use_wasip2
const struct timespec *timespec, wall_clock_datetime_t *timestamp) {
#else
const struct timespec *timespec, __wasi_timestamp_t *timestamp) {
#endif
// Invalid nanoseconds field.
if (timespec->tv_nsec < 0 || timespec->tv_nsec >= NSEC_PER_SEC)
return false;

if (timespec->tv_sec < 0) {
// Timestamps before the Epoch are not supported.
*timestamp = 0;
#if __wasilibc_use_wasip2
timestamp->seconds = 0;
timestamp->nanoseconds = 0;
} else {
timestamp->seconds = timespec->tv_sec;
timestamp->nanoseconds = timespec->tv_nsec;
#else
*timestamp = 0;
} else if (__builtin_mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) ||
__builtin_add_overflow(*timestamp, timespec->tv_nsec, timestamp)) {
// Make sure our timestamp does not overflow.
*timestamp = NUMERIC_MAX(__wasi_timestamp_t);
#endif
}
return true;
}

#ifdef __wasilibc_use_wasip2
static inline struct timespec timestamp_to_timespec(
wall_clock_datetime_t *timestamp) {
return (struct timespec){.tv_sec = timestamp->seconds,
.tv_nsec = timestamp->nanoseconds};
}
#else
static inline struct timespec timestamp_to_timespec(
__wasi_timestamp_t timestamp) {
__wasi_timestamp_t timestamp) {
// Decompose timestamp into seconds and nanoseconds.
return (struct timespec){.tv_sec = timestamp / NSEC_PER_SEC,
.tv_nsec = timestamp % NSEC_PER_SEC};
}
#endif

#ifdef __wasilibc_use_wasip2
static inline struct timespec instant_to_timespec(
monotonic_clock_instant_t ns) {
// Decompose instant into seconds and nanoseconds
return (struct timespec){.tv_sec = ns / NSEC_PER_SEC,
.tv_nsec = ns % NSEC_PER_SEC};
}

static inline struct timeval instant_to_timeval(
monotonic_clock_instant_t ns) {
// Decompose instant into seconds and microoseconds
return (struct timeval){.tv_sec = ns / NSEC_PER_SEC,
.tv_usec = (ns % NSEC_PER_SEC) / 1000};
}

static inline struct timeval timestamp_to_timeval(
__wasi_timestamp_t timestamp) {
wall_clock_datetime_t *timestamp) {
return (struct timeval){.tv_sec = timestamp->seconds,
.tv_usec = timestamp->nanoseconds / 1000};
}
#else
static inline struct timeval timestamp_to_timeval(
__wasi_timestamp_t timestamp) {
struct timespec ts = timestamp_to_timespec(timestamp);
return (struct timeval){.tv_sec = ts.tv_sec, ts.tv_nsec / 1000};
}

#endif
#endif
Loading
Loading