Update wasi-libc to a00bf321eeeca836ee2a0d2d25aeb8524107b8cc (#13626)

* Update wasi-libc to a00bf321eeeca836ee2a0d2d25aeb8524107b8cc

It includes a port of emscripten's allocator that performs
performs much better than the old one.

Most importantly, it includes the prerequisites to later add
support for POSIX threads.
This commit is contained in:
Frank Denis
2022-11-28 19:58:03 +01:00
committed by GitHub
parent 4e078941d0
commit da9c530d99
101 changed files with 2410 additions and 7381 deletions

View File

@@ -11,6 +11,12 @@
#define DT_REG __WASI_FILETYPE_REGULAR_FILE
#define DT_UNKNOWN __WASI_FILETYPE_UNKNOWN
#define IFTODT(x) (__wasilibc_iftodt(x))
#define DTTOIF(x) (__wasilibc_dttoif(x))
int __wasilibc_iftodt(int x);
int __wasilibc_dttoif(int x);
#include <__struct_dirent.h>
#include <__typedef_DIR.h>

View File

@@ -16,12 +16,8 @@
extern const struct __clockid _CLOCK_MONOTONIC;
#define CLOCK_MONOTONIC (&_CLOCK_MONOTONIC)
extern const struct __clockid _CLOCK_PROCESS_CPUTIME_ID;
#define CLOCK_PROCESS_CPUTIME_ID (&_CLOCK_PROCESS_CPUTIME_ID)
extern const struct __clockid _CLOCK_REALTIME;
#define CLOCK_REALTIME (&_CLOCK_REALTIME)
extern const struct __clockid _CLOCK_THREAD_CPUTIME_ID;
#define CLOCK_THREAD_CPUTIME_ID (&_CLOCK_THREAD_CPUTIME_ID)
/*
* TIME_UTC is the only standardized time base value.

View File

@@ -5,6 +5,11 @@
* The page size in WebAssembly is fixed at 64 KiB. If this ever changes,
* it's expected that applications will need to opt in, so we can change
* this.
*
* If this ever needs to be a value outside the range of an `int`, the
* `getpagesize` function which returns this value will need special
* consideration. POSIX has deprecated `getpagesize` in favor of
* `sysconf(_SC_PAGESIZE)` which does not have this problem.
*/
#define PAGESIZE (0x10000)

View File

@@ -7,7 +7,7 @@
#include <__typedef_sa_family_t.h>
struct sockaddr {
_Alignas(max_align_t) sa_family_t sa_family;
__attribute__((aligned(__BIGGEST_ALIGNMENT__))) sa_family_t sa_family;
char sa_data[0];
};

View File

@@ -64,7 +64,9 @@ int isascii(int);
int toascii(int);
#define _tolower(a) ((a)|0x20)
#define _toupper(a) ((a)&0x5f)
#ifndef __cplusplus
#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128)
#endif
#endif

View File

@@ -70,7 +70,7 @@
#define PTHREAD_STACK_MIN 2048
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
#endif
#ifdef __wasilibc_unmodified_upstream /* WASI has no semaphores */
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#define SEM_VALUE_MAX 0x7fffffff
#define SEM_NSEMS_MAX 256
#endif

View File

@@ -8,7 +8,9 @@ extern "C" {
#include <features.h>
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)

View File

@@ -60,6 +60,7 @@ struct ipv6_mreq {
#define INADDR_BROADCAST ((in_addr_t) 0xffffffff)
#define INADDR_NONE ((in_addr_t) 0xffffffff)
#define INADDR_LOOPBACK ((in_addr_t) 0x7f000001)
#define INADDR_DUMMY ((in_addr_t) 0xc0000008)
#define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000)
#define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001)

View File

@@ -80,6 +80,8 @@ enum {
TCP_NLA_SRTT,
TCP_NLA_TIMEOUT_REHASH,
TCP_NLA_BYTES_NOTSENT,
TCP_NLA_EDT,
TCP_NLA_TTL,
};
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
@@ -281,12 +283,21 @@ struct tcp_repair_window {
uint32_t rcv_wup;
};
#define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
struct tcp_zerocopy_receive {
uint64_t address;
uint32_t length;
uint32_t recv_skip_hint;
uint32_t inq;
int32_t err;
uint64_t copybuf_address;
int32_t copybuf_len;
uint32_t flags;
uint64_t msg_control;
uint64_t msg_controllen;
uint32_t msg_flags;
uint32_t reserved;
};
#endif

View File

@@ -82,6 +82,8 @@ typedef struct sigaltstack stack_t;
#define SEGV_ACCERR 2
#define SEGV_BNDERR 3
#define SEGV_PKUERR 4
#define SEGV_MTEAERR 8
#define SEGV_MTESERR 9
#define BUS_ADRALN 1
#define BUS_ADRERR 2
@@ -183,6 +185,9 @@ struct sigaction {
#define sa_handler __sa_handler.sa_handler
#define sa_sigaction __sa_handler.sa_sigaction
#define SA_UNSUPPORTED 0x00000400
#define SA_EXPOSE_TAGBITS 0x00000800
struct sigevent {
union sigval sigev_value;
int sigev_signo;
@@ -277,6 +282,9 @@ void (*sigset(int, void (*)(int)))(int);
#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
#define NSIG _NSIG
typedef void (*sig_t)(int);
#define SYS_SECCOMP 1
#define SYS_USER_DISPATCH 2
#endif
#ifdef _GNU_SOURCE

View File

@@ -7,4 +7,7 @@
#define __STDC_IEC_559__ 1
#endif
#define __STDC_UTF_16__ 1
#define __STDC_UTF_32__ 1
#endif

View File

@@ -28,7 +28,9 @@ extern "C" {
#include <bits/alltypes.h>
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)

View File

@@ -13,7 +13,9 @@ extern "C" {
#include <features.h>
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
@@ -171,6 +173,7 @@ int clearenv(void);
#define WCOREDUMP(s) ((s) & 0x80)
#define WIFCONTINUED(s) ((s) == 0xffff)
void *reallocarray (void *, size_t, size_t);
void qsort_r (void *, size_t, size_t, int (*)(const void *, const void *, void *), void *);
#endif
#endif

View File

@@ -12,7 +12,9 @@ extern "C" {
#include <features.h>
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)

View File

@@ -44,6 +44,7 @@ extern "C" {
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
#define MAP_HUGE_16KB (14 << 26)
#define MAP_HUGE_64KB (16 << 26)
#define MAP_HUGE_512KB (19 << 26)
#define MAP_HUGE_1MB (20 << 26)

View File

@@ -298,6 +298,8 @@ struct linger {
#define SCM_TXTIME SO_TXTIME
#define SO_BINDTOIFINDEX 62
#define SO_DETACH_REUSEPORT_BPF 68
#define SO_PREFER_BUSY_POLL 69
#define SO_BUSY_POLL_BUDGET 70
#ifndef SOL_SOCKET
#define SOL_SOCKET 1
@@ -404,9 +406,10 @@ int shutdown (int, int);
int bind (int, const struct sockaddr *, socklen_t);
int connect (int, const struct sockaddr *, socklen_t);
int listen (int, int);
#endif
int accept (int, struct sockaddr *__restrict, socklen_t *__restrict);
int accept4(int, struct sockaddr *__restrict, socklen_t *__restrict, int);
#endif
#ifdef __wasilibc_unmodified_upstream /* WASI has no getsockname/getpeername */
int getsockname (int, struct sockaddr *__restrict, socklen_t *__restrict);

View File

@@ -23,9 +23,7 @@ struct itimerval {
int getitimer (int, struct itimerval *);
int setitimer (int, const struct itimerval *__restrict, struct itimerval *__restrict);
#endif
#ifdef __wasilibc_unmodified_upstream /* WASI libc doesn't build the legacy functions */
int utimes (const char *, const struct timeval [2]);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
struct timezone {
@@ -34,7 +32,9 @@ struct timezone {
};
#ifdef __wasilibc_unmodified_upstream /* WASI libc doesn't build the legacy functions */
int futimes(int, const struct timeval [2]);
#endif
int futimesat(int, const char *, const struct timeval [2]);
#ifdef __wasilibc_unmodified_upstream /* WASI libc doesn't build the legacy functions */
int lutimes(const char *, const struct timeval [2]);
#endif
#ifdef __wasilibc_unmodified_upstream /* WASI has no way to set the time */

View File

@@ -8,7 +8,9 @@ extern "C" {
#include <features.h>
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)

View File

@@ -15,12 +15,16 @@ extern "C" {
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_DATA 3
#define SEEK_HOLE 4
#else
#include <__header_unistd.h>
#endif
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
@@ -240,7 +244,9 @@ void *sbrk(intptr_t);
pid_t vfork(void);
int vhangup(void);
int chroot(const char *);
#endif
int getpagesize(void);
#ifdef __wasilibc_unmodified_upstream /* WASI has no processes */
int getdtablesize(void);
int sethostname(const char *, size_t);
int getdomainname(char *, size_t);

View File

@@ -1,13 +1,9 @@
/**
* THIS FILE IS AUTO-GENERATED from the following files:
* wasi_snapshot_preview1.witx
*
* To regenerate this file execute:
*
* cargo run --manifest-path tools/wasi-headers/Cargo.toml generate-libc
*
* Modifications to this file will cause CI to fail, the code generator tool
* must be modified to change this file.
* <wasi/api.h>. This file contains declarations describing the WASI ABI
* as of "snapshot preview1". It was originally auto-generated from
* wasi_snapshot_preview1.witx, however WASI is in the process of
* transitioning to a new IDL and header file generator, and this file
* is temporarily being manually maintained.
*
* @file
* This file describes the [WASI] interface, consisting of functions, types,
@@ -661,6 +657,11 @@ typedef uint64_t __wasi_rights_t;
*/
#define __WASI_RIGHTS_SOCK_SHUTDOWN ((__wasi_rights_t)(1 << 28))
/**
* The right to invoke `sock_accept`.
*/
#define __WASI_RIGHTS_SOCK_ACCEPT ((__wasi_rights_t)(1 << 29))
/**
* A file descriptor handle.
*/
@@ -1300,200 +1301,6 @@ typedef uint32_t __wasi_exitcode_t;
_Static_assert(sizeof(__wasi_exitcode_t) == 4, "witx calculated size");
_Static_assert(_Alignof(__wasi_exitcode_t) == 4, "witx calculated align");
/**
* Signal condition.
*/
typedef uint8_t __wasi_signal_t;
/**
* No signal. Note that POSIX has special semantics for `kill(pid, 0)`,
* so this value is reserved.
*/
#define __WASI_SIGNAL_NONE (UINT8_C(0))
/**
* Hangup.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_HUP (UINT8_C(1))
/**
* Terminate interrupt signal.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_INT (UINT8_C(2))
/**
* Terminal quit signal.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_QUIT (UINT8_C(3))
/**
* Illegal instruction.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_ILL (UINT8_C(4))
/**
* Trace/breakpoint trap.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_TRAP (UINT8_C(5))
/**
* Process abort signal.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_ABRT (UINT8_C(6))
/**
* Access to an undefined portion of a memory object.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_BUS (UINT8_C(7))
/**
* Erroneous arithmetic operation.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_FPE (UINT8_C(8))
/**
* Kill.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_KILL (UINT8_C(9))
/**
* User-defined signal 1.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_USR1 (UINT8_C(10))
/**
* Invalid memory reference.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_SEGV (UINT8_C(11))
/**
* User-defined signal 2.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_USR2 (UINT8_C(12))
/**
* Write on a pipe with no one to read it.
* Action: Ignored.
*/
#define __WASI_SIGNAL_PIPE (UINT8_C(13))
/**
* Alarm clock.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_ALRM (UINT8_C(14))
/**
* Termination signal.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_TERM (UINT8_C(15))
/**
* Child process terminated, stopped, or continued.
* Action: Ignored.
*/
#define __WASI_SIGNAL_CHLD (UINT8_C(16))
/**
* Continue executing, if stopped.
* Action: Continues executing, if stopped.
*/
#define __WASI_SIGNAL_CONT (UINT8_C(17))
/**
* Stop executing.
* Action: Stops executing.
*/
#define __WASI_SIGNAL_STOP (UINT8_C(18))
/**
* Terminal stop signal.
* Action: Stops executing.
*/
#define __WASI_SIGNAL_TSTP (UINT8_C(19))
/**
* Background process attempting read.
* Action: Stops executing.
*/
#define __WASI_SIGNAL_TTIN (UINT8_C(20))
/**
* Background process attempting write.
* Action: Stops executing.
*/
#define __WASI_SIGNAL_TTOU (UINT8_C(21))
/**
* High bandwidth data is available at a socket.
* Action: Ignored.
*/
#define __WASI_SIGNAL_URG (UINT8_C(22))
/**
* CPU time limit exceeded.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_XCPU (UINT8_C(23))
/**
* File size limit exceeded.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_XFSZ (UINT8_C(24))
/**
* Virtual timer expired.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_VTALRM (UINT8_C(25))
/**
* Profiling timer expired.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_PROF (UINT8_C(26))
/**
* Window changed.
* Action: Ignored.
*/
#define __WASI_SIGNAL_WINCH (UINT8_C(27))
/**
* I/O possible.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_POLL (UINT8_C(28))
/**
* Power failure.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_PWR (UINT8_C(29))
/**
* Bad system call.
* Action: Terminates the process.
*/
#define __WASI_SIGNAL_SYS (UINT8_C(30))
_Static_assert(sizeof(__wasi_signal_t) == 1, "witx calculated size");
_Static_assert(_Alignof(__wasi_signal_t) == 1, "witx calculated align");
/**
* Flags provided to `sock_recv`.
*/
@@ -1592,7 +1399,8 @@ _Static_assert(_Alignof(__wasi_prestat_t) == 4, "witx calculated align");
/**
* Read command-line argument data.
* The size of the array should match that returned by `args_sizes_get`
* The size of the array should match that returned by `args_sizes_get`.
* Each argument is expected to be `\0` terminated.
*/
__wasi_errno_t __wasi_args_get(
uint8_t * * argv,
@@ -1611,6 +1419,7 @@ __wasi_errno_t __wasi_args_sizes_get(
/**
* Read environment variable data.
* The sizes of the buffers should match that returned by `environ_sizes_get`.
* Key/value pairs are expected to be joined with `=`s, and terminated with `\0`s.
*/
__wasi_errno_t __wasi_environ_get(
uint8_t * * environ,
@@ -2181,16 +1990,6 @@ _Noreturn void __wasi_proc_exit(
*/
__wasi_exitcode_t rval
);
/**
* Send a signal to the process of the calling thread.
* Note: This is similar to `raise` in POSIX.
*/
__wasi_errno_t __wasi_proc_raise(
/**
* The signal condition to trigger.
*/
__wasi_signal_t sig
) __attribute__((__warn_unused_result__));
/**
* Temporarily yield execution of the calling thread.
* Note: This is similar to `sched_yield` in POSIX.
@@ -2213,6 +2012,23 @@ __wasi_errno_t __wasi_random_get(
uint8_t * buf,
__wasi_size_t buf_len
) __attribute__((__warn_unused_result__));
/**
* Accept a new incoming connection.
* Note: This is similar to `accept` in POSIX.
* @return
* New socket connection
*/
__wasi_errno_t __wasi_sock_accept(
/**
* The listening socket.
*/
__wasi_fd_t fd,
/**
* The desired values of the file descriptor flags.
*/
__wasi_fdflags_t flags,
__wasi_fd_t *retptr0
) __attribute__((__warn_unused_result__));
/**
* Receive a message from a socket.
* Note: This is similar to `recv` in POSIX, though it also supports reading
@@ -2273,6 +2089,25 @@ __wasi_errno_t __wasi_sock_shutdown(
) __attribute__((__warn_unused_result__));
/** @} */
#ifdef _REENTRANT
/**
* Request a new thread to be created by the host.
*
* The host will create a new instance of the current module sharing its
* memory, find an exported entry function--`wasi_thread_start`--, and call the
* entry function with `start_arg` in the new thread.
*
* @see https://github.com/WebAssembly/wasi-threads/#readme
*/
__wasi_errno_t __wasi_thread_spawn(
/**
* A pointer to an opaque struct to be passed to the module's entry
* function.
*/
void *start_arg
) __attribute__((__warn_unused_result__));
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,10 @@
#ifndef __wasi_libc_environ_h
#define __wasi_libc_environ_h
/// This header file is a WASI-libc-specific interface, and is not needed by
/// most programs. Most programs should just use the standard `getenv` and
/// related APIs, which take care of all of the details automatically.
#ifdef __cplusplus
extern "C" {
#endif
@@ -12,6 +16,19 @@ void __wasilibc_initialize_environ(void);
/// If `__wasilibc_initialize_environ` has not yet been called, call it.
void __wasilibc_ensure_environ(void);
/// De-initialize the global environment variable state, so that subsequent
/// calls to `__wasilibc_ensure_environ` call `__wasilibc_initialize_environ`.
void __wasilibc_deinitialize_environ(void);
/// Call `__wasilibc_initialize_environ` only if `environ` and `_environ` are
/// referenced in the program.
void __wasilibc_maybe_reinitialize_environ_eagerly(void);
/// Return the value of the `environ` variable. Using `environ` directly
/// requires eager initialization of the environment variables. Using this
/// function instead of `environ` allows initialization to happen lazily.
char **__wasilibc_get_environ(void);
#ifdef __cplusplus
}
#endif

View File

@@ -70,7 +70,7 @@ int __wasilibc_find_relpath_alloc(
char **relative,
size_t *relative_len,
int can_realloc
) __attribute__((weak));
) __attribute__((__weak__));
#ifdef __cplusplus
}

View File

@@ -41,7 +41,9 @@ extern "C" {
#endif
#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)

View File

@@ -7,6 +7,7 @@ Portions of this software are derived from third-party works covered by
their own licenses:
dlmalloc/ - CC0; see the notice in malloc.c for details
emmalloc/ - MIT; see the notice in emmalloc.c for details
libc-bottom-half/cloudlibc/ - BSD-2-Clause; see the LICENSE file for details
libc-top-half/musl/ - MIT; see the COPYRIGHT file for details

View File

@@ -1,10 +0,0 @@
/* Stub include file to support dlmalloc. */
#include <stdint.h>
#include <__macro_PAGESIZE.h>
#define sysconf(name) PAGESIZE
#define _SC_PAGESIZE
/* Declare sbrk. */
void *sbrk(intptr_t increment) __attribute__((__warn_unused_result__));

View File

@@ -1,98 +0,0 @@
// This file is a wrapper around malloc.c, which is the upstream source file.
// It sets configuration flags and controls which symbols are exported.
#include <stddef.h>
#include <malloc.h>
// Define configuration macros for dlmalloc.
// WebAssembly doesn't have mmap-style memory allocation.
#define HAVE_MMAP 0
// WebAssembly doesn't support shrinking linear memory.
#define MORECORE_CANNOT_TRIM 1
// Disable sanity checks to reduce code size.
#define ABORT __builtin_unreachable()
// If threads are enabled, enable support for threads.
#ifdef _REENTRANT
#define USE_LOCKS 1
#endif
// Make malloc deterministic.
#define LACKS_TIME_H 1
// Disable malloc statistics generation to reduce code size.
#define NO_MALLINFO 1
#define NO_MALLOC_STATS 1
// Align malloc regions to 16, to avoid unaligned SIMD accesses.
#define MALLOC_ALIGNMENT 16
// Declare errno values used by dlmalloc. We define them like this to avoid
// putting specific errno values in the ABI.
extern const int __ENOMEM;
#define ENOMEM __ENOMEM
extern const int __EINVAL;
#define EINVAL __EINVAL
// Define USE_DL_PREFIX so that we leave dlmalloc's names prefixed with 'dl'.
// We define them as "static", and we wrap them with public names below. This
// serves two purposes:
//
// One is to make it easy to control which symbols are exported; dlmalloc
// defines several non-standard functions and we wish to explicitly control
// which functions are part of our public-facing interface.
//
// The other is to protect against compilers optimizing based on the assumption
// that they know what functions with names like "malloc" do. Code in the
// implementation will call functions like "dlmalloc" and assume it can use
// the resulting pointers to access the metadata outside of the nominally
// allocated objects. However, if the function were named "malloc", compilers
// might see code like that and assume it has undefined behavior and can be
// optimized away. By using "dlmalloc" in the implementation, we don't need
// -fno-builtin to avoid this problem.
#define USE_DL_PREFIX 1
#define DLMALLOC_EXPORT static inline
// This isn't declared with DLMALLOC_EXPORT so make it static explicitly.
static size_t dlmalloc_usable_size(void*);
// Include the upstream dlmalloc's malloc.c.
#include "malloc.c"
// Export the public names.
void *malloc(size_t size) {
return dlmalloc(size);
}
void free(void *ptr) {
dlfree(ptr);
}
void *calloc(size_t nmemb, size_t size) {
return dlcalloc(nmemb, size);
}
void *realloc(void *ptr, size_t size) {
return dlrealloc(ptr, size);
}
int posix_memalign(void **memptr, size_t alignment, size_t size) {
return dlposix_memalign(memptr, alignment, size);
}
void* aligned_alloc(size_t alignment, size_t bytes) {
return dlmemalign(alignment, bytes);
}
size_t malloc_usable_size(void *ptr) {
return dlmalloc_usable_size(ptr);
}
// Define these to satisfy musl references.
void *__libc_malloc(size_t) __attribute__((alias("malloc")));
void __libc_free(void *) __attribute__((alias("free")));
void *__libc_calloc(size_t nmemb, size_t size) __attribute__((alias("calloc")));

File diff suppressed because it is too large Load Diff

1535
lib/libc/wasi/emmalloc/emmalloc.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
//
// SPDX-License-Identifier: BSD-2-Clause
#ifndef COMMON_ERRNO_H
#define COMMON_ERRNO_H
#include <wasi/api.h>
// WASI syscalls should just return ENOTDIR if that's what the problem is.
static inline __wasi_errno_t errno_fixup_directory(__wasi_fd_t fd,
__wasi_errno_t error) {
return error;
}
// WASI syscalls should just return ENOTSOCK if that's what the problem is.
static inline __wasi_errno_t errno_fixup_socket(__wasi_fd_t fd,
__wasi_errno_t error) {
return error;
}
#endif

View File

@@ -1,15 +0,0 @@
// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
//
// SPDX-License-Identifier: BSD-2-Clause
#ifndef COMMON_OVERFLOW_H
#define COMMON_OVERFLOW_H
// Performs an addition, subtraction or multiplication operation,
// returning whether the computation caused an overflow. These
// intrinsics are available as of Clang 3.8 and GCC 5.
#define add_overflow(x, y, out) __builtin_add_overflow(x, y, out)
#define sub_overflow(x, y, out) __builtin_sub_overflow(x, y, out)
#define mul_overflow(x, y, out) __builtin_mul_overflow(x, y, out)
#endif

View File

@@ -6,7 +6,6 @@
#define COMMON_TIME_H
#include <common/limits.h>
#include <common/overflow.h>
#include <sys/time.h>
@@ -16,43 +15,6 @@
#define NSEC_PER_SEC 1000000000
// Timezone agnostic conversion routines.
int __localtime_utc(time_t, struct tm *);
void __mktime_utc(const struct tm *, struct timespec *);
static inline bool is_leap(time_t year) {
year %= 400;
if (year < 0)
year += 400;
return ((year % 4) == 0 && (year % 100) != 0) || year == 100;
}
// Gets the length of the months in a year.
static inline const char *get_months(time_t year) {
static const char leap[12] = {
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
};
static const char common[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
};
return is_leap(year) ? leap : common;
}
// Gets the cumulative length of the months in a year.
static inline const short *get_months_cumulative(time_t year) {
static const short leap[13] = {
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366,
};
static const short common[13] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
};
return is_leap(year) ? leap : common;
}
static inline short get_ydays(time_t year) {
return is_leap(year) ? 366 : 365;
}
static inline bool timespec_to_timestamp_exact(
const struct timespec *timespec, __wasi_timestamp_t *timestamp) {
// Invalid nanoseconds field.
@@ -64,8 +26,8 @@ static inline bool timespec_to_timestamp_exact(
return false;
// Make sure our timestamp does not overflow.
return !mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) &&
!add_overflow(*timestamp, timespec->tv_nsec, timestamp);
return !__builtin_mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) &&
!__builtin_add_overflow(*timestamp, timespec->tv_nsec, timestamp);
}
static inline bool timespec_to_timestamp_clamp(
@@ -77,8 +39,8 @@ static inline bool timespec_to_timestamp_clamp(
if (timespec->tv_sec < 0) {
// Timestamps before the Epoch are not supported.
*timestamp = 0;
} else if (mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) ||
add_overflow(*timestamp, timespec->tv_nsec, timestamp)) {
} 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);
}

View File

@@ -24,126 +24,13 @@
#ifndef ___CDEFS_H_
#define ___CDEFS_H_
// Version information.
#define __cloudlibc__ 1
#define __cloudlibc_major__ 0
#define __cloudlibc_minor__ 102
#ifdef __cplusplus
#define __BEGIN_DECLS extern "C" {
#define __END_DECLS }
#else
#define __BEGIN_DECLS
#define __END_DECLS
#endif
// Whether we should provide inline versions of functions. Due to C++'s
// support for namespaces, it is generally a bad idea to declare
// function macros.
#ifdef __cplusplus
#define _CLOUDLIBC_INLINE_FUNCTIONS 0
#else
#define _CLOUDLIBC_INLINE_FUNCTIONS 1
#endif
// Compiler-independent annotations.
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef __has_extension
#define __has_extension(x) __has_feature(x)
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#define __offsetof(type, member) __builtin_offsetof(type, member)
#define __containerof(ptr, type, member) \
((type *)((char *)(ptr)-__offsetof(type, member)))
#define __extname(x) __asm__(x)
#define __malloc_like __attribute__((__malloc__))
#define __pure2 __attribute__((__const__))
#define __pure __attribute__((__pure__))
#define __section(x) __attribute__((__section__(x)))
#define __unused __attribute__((__unused__))
#define __used __attribute__((__used__))
#define __weak_symbol __attribute__((__weak__))
// Format string argument type checking.
#define __printflike(format, va) \
__attribute__((__format__(__printf__, format, va)))
#define __scanflike(format, va) \
__attribute__((__format__(__scanf__, format, va)))
// TODO(ed): Enable this once supported by LLVM:
// https://llvm.org/bugs/show_bug.cgi?id=16810
#define __wprintflike(format, va)
#define __wscanflike(format, va)
#define __strong_reference(oldsym, newsym) \
extern __typeof__(oldsym) newsym __attribute__((__alias__(#oldsym)))
// Convenience macros.
#define __arraycount(x) (sizeof(x) / sizeof((x)[0]))
#define __howmany(x, y) (((x) + (y)-1) / (y))
#define __rounddown(x, y) (((x) / (y)) * (y))
#define __roundup(x, y) ((((x) + (y)-1) / (y)) * (y))
// Lock annotations.
#if __has_extension(c_thread_safety_attributes)
#define __lock_annotate(x) __attribute__((x))
#else
#define __lock_annotate(x)
#endif
#define __lockable __lock_annotate(lockable)
#define __locks_exclusive(...) \
__lock_annotate(exclusive_lock_function(__VA_ARGS__))
#define __locks_shared(...) __lock_annotate(shared_lock_function(__VA_ARGS__))
#define __trylocks_exclusive(...) \
__lock_annotate(exclusive_trylock_function(__VA_ARGS__))
#define __trylocks_shared(...) \
__lock_annotate(shared_trylock_function(__VA_ARGS__))
#define __unlocks(...) __lock_annotate(unlock_function(__VA_ARGS__))
#define __asserts_exclusive(...) \
__lock_annotate(assert_exclusive_lock(__VA_ARGS__))
#define __asserts_shared(...) __lock_annotate(assert_shared_lock(__VA_ARGS__))
#define __requires_exclusive(...) \
__lock_annotate(exclusive_locks_required(__VA_ARGS__))
#define __requires_shared(...) \
__lock_annotate(shared_locks_required(__VA_ARGS__))
#define __requires_unlocked(...) __lock_annotate(locks_excluded(__VA_ARGS__))
#define __no_lock_analysis __lock_annotate(no_thread_safety_analysis)
#define __guarded_by(x) __lock_annotate(guarded_by(x))
#define __pt_guarded_by(x) __lock_annotate(pt_guarded_by(x))
// Const preservation.
//
// Functions like strchr() allow you to silently discard a const
// qualifier from a string. This macro can be used to wrap such
// functions to propagate the const keyword where possible.
//
// This macro has many limitations, such as only being able to detect
// constness for void, char and wchar_t. For Clang, it also doesn't seem
// to work on string literals.
#define __preserve_const(type, name, arg, ...) \
_Generic(arg, \
const void *: (const type *)name(__VA_ARGS__), \
const char *: (const type *)name(__VA_ARGS__), \
const signed char *: (const type *)name(__VA_ARGS__), \
const unsigned char *: (const type *)name(__VA_ARGS__), \
const __wchar_t *: (const type *)name(__VA_ARGS__), \
default: name(__VA_ARGS__))
#endif

View File

@@ -1,241 +0,0 @@
// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// <stdlib.h> - standard library definitions
//
// Extensions:
// - MB_CUR_MAX_L(), mblen_l(), mbstowcs_l(), mbtowc_l(), wcstombs_l()
// and wctomb_l():
// Regular functions always use the C locale. Available on many other
// operating systems.
// - alloca():
// Present on most other operating systems.
// - arc4random(), arc4random_buf() and arc4random_uniform():
// Secure random number generator. Available on many other operating
// systems.
// - l64a_r():
// Thread-safe replacement for l64a(). Part of the SVID, 4th edition.
// - qsort_r():
// Available on many other operating systems, although the prototype
// is not consistent. This implementation is compatible with glibc.
// It is expected that this version will be standardized in the future.
// - reallocarray():
// Allows for reallocation of buffers without integer overflows.
//
// Features missing:
// - initstate(), lcong48(), seed48(), setstate(), srand(), srand48()
// and srandom():
// Randomizer is seeded securely by default. There is no need to seed
// manually.
// - WEXITSTATUS(), WIFEXITED(), WIFSIGNALED(), WIFSTOPPED(), WNOHANG,
// WSTOPSIG(), WTERMSIG(), WUNTRACED:
// Only useful if system() would actually work.
// - l64a():
// Not thread-safe. Use l64a_r() instead.
// - putenv(), setenv() and unsetenv():
// Environment variables are not available.
// - grantpt(), posix_openpt(), ptsname() and unlockpt():
// Pseudo-terminals are not available.
// - mkdtemp(), mkstemp() and realpath():
// Requires global filesystem namespace.
// - setkey():
// Password database and encryption schemes not available.
// - system():
// Requires a command shell.
#ifndef _STDLIB_H_
#define _STDLIB_H_
#include <_/limits.h>
#include <_/types.h>
__BEGIN_DECLS
_Noreturn void _Exit(int);
_Noreturn void abort(void);
void *calloc(size_t, size_t);
_Noreturn void exit(int);
void free(void *);
void *malloc(size_t);
void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
void *realloc(void *, size_t);
__END_DECLS
#if _CLOUDLIBC_INLINE_FUNCTIONS
// qsort_r() implementation from Bentley and McIlroy's
// "Engineering a Sort Function".
//
// This sorting function is inlined into this header, so that the
// compiler can create an optimized version that takes the alignment and
// size of the elements into account. It also reduces the overhead of
// indirect function calls.
static __inline void __qsort_r(void *, size_t, size_t,
int (*)(const void *, const void *, void *),
void *);
static __inline size_t __qsort_min(size_t __a, size_t __b) {
return __a < __b ? __a : __b;
}
// Swaps the contents of two buffers.
static __inline void __qsort_swap(char *__a, char *__b, size_t __n) {
char __t;
while (__n-- > 0) {
__t = *__a;
*__a++ = *__b;
*__b++ = __t;
}
}
// Implementation of insertionsort for small lists.
static __inline void __qsort_insertionsort(
char *__a, size_t __nel, size_t __width,
int (*__cmp)(const void *, const void *, void *), void *__thunk) {
char *__pm, *__pl;
for (__pm = __a + __width; __pm < __a + __nel * __width; __pm += __width)
for (__pl = __pm; __pl > __a && __cmp(__pl - __width, __pl, __thunk) > 0;
__pl -= __width)
__qsort_swap(__pl, __pl - __width, __width);
}
// Returns the median of three elements.
static __inline char *__qsort_med3(char *__a, char *__b, char *__c,
int (*__cmp)(const void *, const void *,
void *),
void *__thunk) {
return __cmp(__a, __b, __thunk) < 0
? (__cmp(__b, __c, __thunk) < 0
? __b
: __cmp(__a, __c, __thunk) < 0 ? __c : __a)
: (__cmp(__b, __c, __thunk) > 0
? __b
: __cmp(__a, __c, __thunk) > 0 ? __c : __a);
}
// Picks a pivot based on a pseudo-median of three or nine.
// TODO(ed): Does this still guarantee an O(n log n) running time?
static __inline char *__qsort_pickpivot(char *__a, size_t __nel, size_t __width,
int (*__cmp)(const void *, const void *,
void *),
void *__thunk) {
char *__pl, *__pm, *__pn;
size_t __s;
__pl = __a;
__pm = __a + (__nel / 2) * __width;
__pn = __a + (__nel - 1) * __width;
if (__nel > 40) {
__s = (__nel / 8) * __width;
__pl = __qsort_med3(__pl, __pl + __s, __pl + 2 * __s, __cmp, __thunk);
__pm = __qsort_med3(__pm - __s, __pm, __pm + __s, __cmp, __thunk);
__pn = __qsort_med3(__pn - 2 * __s, __pn - __s, __pn, __cmp, __thunk);
}
return __qsort_med3(__pl, __pm, __pn, __cmp, __thunk);
}
// Implementation of quicksort for larger lists.
static __inline void __qsort_quicksort(char *__a, size_t __nel, size_t __width,
int (*__cmp)(const void *, const void *,
void *),
void *__thunk) {
char *__pa, *__pb, *__pc, *__pd, *__pn;
int __r;
size_t __s;
// Select pivot and move it to the head of the list.
__qsort_swap(__a, __qsort_pickpivot(__a, __nel, __width, __cmp, __thunk),
__width);
// Perform partitioning.
__pa = __pb = __a;
__pc = __pd = __a + (__nel - 1) * __width;
for (;;) {
while (__pb <= __pc && (__r = __cmp(__pb, __a, __thunk)) <= 0) {
if (__r == 0) {
__qsort_swap(__pa, __pb, __width);
__pa += __width;
}
__pb += __width;
}
while (__pc >= __pb && (__r = __cmp(__pc, __a, __thunk)) >= 0) {
if (__r == 0) {
__qsort_swap(__pc, __pd, __width);
__pd -= __width;
}
__pc -= __width;
}
if (__pb > __pc)
break;
__qsort_swap(__pb, __pc, __width);
__pb += __width;
__pc -= __width;
}
// Store pivot between the two partitions.
__pn = __a + __nel * __width;
__s = __qsort_min((size_t)(__pa - __a), (size_t)(__pb - __pa));
__qsort_swap(__a, __pb - __s, __s);
__s = __qsort_min((size_t)(__pd - __pc), (size_t)(__pn - __pd) - __width);
__qsort_swap(__pb, __pn - __s, __s);
// Sort the two partitions.
__s = (size_t)(__pb - __pa);
__qsort_r(__a, __s / __width, __width, __cmp, __thunk);
__s = (size_t)(__pd - __pc);
__qsort_r(__pn - __s, __s / __width, __width, __cmp, __thunk);
}
static __inline void __qsort_r(void *__base, size_t __nel, size_t __width,
int (*__cmp)(const void *, const void *, void *),
void *__thunk) {
char *__a;
__a = (char *)__base;
if (__nel < 8) {
__qsort_insertionsort(__a, __nel, __width, __cmp, __thunk);
} else {
__qsort_quicksort(__a, __nel, __width, __cmp, __thunk);
}
}
#define qsort_r(base, nel, width, compar, thunk) \
__qsort_r(base, nel, width, compar, thunk)
// qsort(): Call into qsort_r(), providing the callback as the thunk.
// We assume that the optimizer is smart enough to simplify.
static __inline int __qsort_cmp(const void *__a, const void *__b,
void *__thunk) {
return ((int (*)(const void *, const void *))__thunk)(__a, __b);
}
static __inline void __qsort(void *__base, size_t __nel, size_t __width,
int (*__cmp)(const void *, const void *)) {
qsort_r(__base, __nel, __width, __qsort_cmp, (void *)__cmp);
}
#define qsort(base, nel, width, compar) __qsort(base, nel, width, compar)
#endif
#endif

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <dirent.h>
#include <errno.h>
@@ -31,7 +29,7 @@ DIR *fdopendir(int fd) {
if (error != 0) {
free(dirp->buffer);
free(dirp);
errno = errno_fixup_directory(fd, error);
errno = error;
return NULL;
}

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <assert.h>
#include <wasi/api.h>
#include <wasi/libc.h>
@@ -75,7 +73,7 @@ int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) {
fs_rights_base, fs_rights_inheriting, fs_flags,
&newfd);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
return newfd;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <errno.h>
#include <stdio.h>
@@ -12,7 +10,7 @@
int __wasilibc_nocwd_renameat(int oldfd, const char *old, int newfd, const char *new) {
__wasi_errno_t error = __wasi_path_rename(oldfd, old, newfd, new);
if (error != 0) {
errno = errno_fixup_directory(oldfd, errno_fixup_directory(newfd, error));
errno = error;
return -1;
}
return 0;

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: BSD-2-Clause
#include <wasi/api.h>
#include <stdlib.h>
#include <_/cdefs.h>
#include <stdnoreturn.h>
#include <unistd.h>

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <sys/socket.h>
#include <assert.h>
@@ -35,7 +33,7 @@ ssize_t recv(int socket, void *restrict buffer, size_t length, int flags) {
&ro_datalen,
&ro_flags);
if (error != 0) {
errno = errno_fixup_socket(socket, error);
errno = error;
return -1;
}
return ro_datalen;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <sys/socket.h>
#include <assert.h>
@@ -27,7 +25,7 @@ ssize_t send(int socket, const void *buffer, size_t length, int flags) {
size_t so_datalen;
__wasi_errno_t error = __wasi_sock_send(socket, si_data, si_data_len, si_flags, &so_datalen);
if (error != 0) {
errno = errno_fixup_socket(socket, error);
errno = error;
return -1;
}
return so_datalen;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <sys/socket.h>
#include <assert.h>
@@ -22,7 +20,7 @@ int shutdown(int socket, int how) {
__wasi_errno_t error = __wasi_sock_shutdown(socket, how);
if (error != 0) {
errno = errno_fixup_socket(socket, error);
errno = error;
return -1;
}
return error;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <sys/stat.h>
#include <wasi/api.h>
@@ -25,7 +23,7 @@ int __wasilibc_nocwd_fstatat(int fd, const char *restrict path, struct stat *res
__wasi_errno_t error =
__wasi_path_filestat_get(fd, lookup_flags, path, &internal_stat);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
to_public_stat(&internal_stat, buf);

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <sys/stat.h>
#include <wasi/api.h>
@@ -13,7 +11,7 @@
int __wasilibc_nocwd_mkdirat_nomode(int fd, const char *path) {
__wasi_errno_t error = __wasi_path_create_directory(fd, path);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
return 0;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <sys/stat.h>
#include <wasi/api.h>
@@ -33,7 +31,7 @@ int __wasilibc_nocwd_utimensat(int fd, const char *path, const struct timespec t
__wasi_errno_t error =
__wasi_path_filestat_set_times(fd, lookup_flags, path, st_atim, st_mtim, flags);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
return 0;

View File

@@ -1,12 +0,0 @@
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/clock.h>
#include <wasi/api.h>
#include <time.h>
const struct __clockid _CLOCK_PROCESS_CPUTIME_ID = {
.id = __WASI_CLOCKID_PROCESS_CPUTIME_ID,
};

View File

@@ -1,12 +0,0 @@
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/clock.h>
#include <wasi/api.h>
#include <time.h>
const struct __clockid _CLOCK_THREAD_CPUTIME_ID = {
.id = __WASI_CLOCKID_THREAD_CPUTIME_ID,
};

View File

@@ -19,4 +19,4 @@ int __clock_gettime(clockid_t clock_id, struct timespec *tp) {
*tp = timestamp_to_timespec(ts);
return 0;
}
extern __typeof(__clock_gettime) clock_gettime __attribute__((weak, alias("__clock_gettime")));
weak_alias(__clock_gettime, clock_gettime);

View File

@@ -33,3 +33,5 @@ int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
__wasi_errno_t error = __wasi_poll_oneoff(&sub, &ev, 1, &nevents);
return error == 0 && ev.error == 0 ? 0 : ENOTSUP;
}
weak_alias(clock_nanosleep, __clock_nanosleep);

View File

@@ -3,7 +3,6 @@
// SPDX-License-Identifier: BSD-2-Clause
#include <errno.h>
#include <threads.h>
#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rem) {
@@ -14,7 +13,3 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rem) {
}
return 0;
}
#if defined(_REENTRANT)
__strong_reference(nanosleep, thrd_sleep);
#endif

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <errno.h>
#include <fcntl.h>
@@ -24,7 +22,7 @@ int __wasilibc_nocwd_faccessat(int fd, const char *path, int amode, int flag) {
__wasi_errno_t error =
__wasi_path_filestat_get(fd, lookup_flags, path, &file);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <errno.h>
#include <fcntl.h>
@@ -19,7 +17,7 @@ int __wasilibc_nocwd_linkat(int fd1, const char *path1, int fd2, const char *pat
// Perform system call.
__wasi_errno_t error = __wasi_path_link(fd1, lookup1_flags, path1, fd2, path2);
if (error != 0) {
errno = errno_fixup_directory(fd1, errno_fixup_directory(fd2, error));
errno = error;
return -1;
}
return 0;

View File

@@ -22,4 +22,4 @@ off_t __lseek(int fildes, off_t offset, int whence) {
return new_offset;
}
extern __typeof(__lseek) lseek __attribute__((weak, alias("__lseek")));
weak_alias(__lseek, lseek);

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <errno.h>
#include <string.h>
@@ -16,7 +14,7 @@ ssize_t __wasilibc_nocwd_readlinkat(int fd, const char *restrict path, char *res
__wasi_errno_t error = __wasi_path_readlink(fd, path,
(uint8_t*)buf, bufsize, &bufused);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
return bufused;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <errno.h>
#include <string.h>
@@ -12,7 +10,7 @@
int __wasilibc_nocwd_symlinkat(const char *path1, int fd, const char *path2) {
__wasi_errno_t error = __wasi_path_symlink(path1, fd, path2);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
return 0;

View File

@@ -2,8 +2,6 @@
//
// SPDX-License-Identifier: BSD-2-Clause
#include <common/errno.h>
#include <wasi/api.h>
#include <wasi/libc.h>
#include <errno.h>

View File

@@ -1,18 +1,53 @@
#ifdef _REENTRANT
#include <stdatomic.h>
extern void __wasi_init_tp(void);
#endif
#include <wasi/api.h>
#include <stdlib.h>
extern void __wasm_call_ctors(void);
extern int __original_main(void);
extern int __main_void(void);
extern void __wasm_call_dtors(void);
__attribute__((export_name("_start")))
void _start(void) {
// Call `__original_main` which will either be the application's zero-argument
// `__original_main` function or a libc routine which calls `__main_void`.
// TODO: Call `main` directly once we no longer have to support old compilers.
int r = __original_main();
// Commands should only be called once per instance. This simple check
// ensures that the `_start` function isn't started more than once.
//
// We use `volatile` here to prevent the store to `started` from being
// sunk past any subsequent code, and to prevent any compiler from
// optimizing based on the knowledge that `_start` is the program
// entrypoint.
#ifdef _REENTRANT
static volatile _Atomic int started = 0;
int expected = 0;
if (!atomic_compare_exchange_strong(&started, &expected, 1)) {
__builtin_trap();
}
#else
static volatile int started = 0;
if (started != 0) {
__builtin_trap();
}
started = 1;
#endif
// If main exited successfully, just return, otherwise call `exit`.
#ifdef _REENTRANT
__wasi_init_tp();
#endif
// The linker synthesizes this to call constructors.
__wasm_call_ctors();
// Call `__main_void` which will either be the application's zero-argument
// `__main_void` function or a libc routine which obtains the command-line
// arguments and calls `__main_argv_argc`.
int r = __main_void();
// Call atexit functions, destructors, stdio cleanup, etc.
__wasm_call_dtors();
// If main exited successfully, just return, otherwise call
// `__wasi_proc_exit`.
if (r != 0) {
exit(r);
__wasi_proc_exit(r);
}
}

View File

@@ -4,3 +4,5 @@
#include <stddef.h>
#include_next <stdlib.h>
int clearenv(void);

View File

@@ -24,7 +24,7 @@ void __SIG_ERR(int sig) {
_Noreturn
static void core_handler(int sig) {
fprintf(stderr, "Program recieved fatal signal: %s\n", strsignal(sig));
fprintf(stderr, "Program received fatal signal: %s\n", strsignal(sig));
abort();
}
@@ -138,5 +138,5 @@ void (*signal(int sig, void (*func)(int)))(int) {
return old;
}
extern __typeof(signal) bsd_signal __attribute__((weak, alias("signal")));
extern __typeof(signal) __sysv_signal __attribute__((weak, alias("signal")));
extern __typeof(signal) bsd_signal __attribute__((__weak__, alias("signal")));
extern __typeof(signal) __sysv_signal __attribute__((__weak__, alias("signal")));

View File

@@ -1,10 +0,0 @@
// New compilers define `__main_argc_argv`. If that doesn't exist, we
// may get called here. Old compilers define `main` expecting an
// argv/argc, so call that.
// TODO: Remove this layer when we no longer have to support old compilers.
int __wasilibc_main(int argc, char *argv[]) asm("main");
__attribute__((weak, nodebug))
int __main_argc_argv(int argc, char *argv[]) {
return __wasilibc_main(argc, argv);
}

View File

@@ -2,13 +2,18 @@
#include <stdlib.h>
#include <sysexits.h>
int __wasilibc_main(int argc, char *argv[]) asm("main");
// The user's `main` function, expecting arguments.
int __main_argc_argv(int argc, char *argv[]);
__attribute__((__weak__, nodebug))
int __main_argc_argv(int argc, char *argv[]) {
return __wasilibc_main(argc, argv);
}
// If the user's `main` function expects arguments, the compiler will rename
// it to `__main_argc_argv`, and this version will get linked in, which
// initializes the argument data and calls `__main_argc_argv`.
__attribute__((weak, nodebug))
__attribute__((__weak__, nodebug))
int __main_void(void) {
__wasi_errno_t err;

View File

@@ -1,10 +0,0 @@
// Old compilers define `__original_main`. If that doesn't exist, we
// get called here. New compilers define `__main_void`. If that doesn't
// exist, we'll try something else.
// TODO: Remove this layer when we no longer have to support old compilers.
int __main_void(void);
__attribute__((weak))
int __original_main(void) {
return __main_void();
}

View File

@@ -0,0 +1,34 @@
#include <__header_dirent.h>
#include <__mode_t.h>
int __wasilibc_iftodt(int x) {
switch (x) {
case S_IFDIR: return DT_DIR;
case S_IFCHR: return DT_CHR;
case S_IFBLK: return DT_BLK;
case S_IFREG: return DT_REG;
case S_IFIFO: return DT_FIFO;
case S_IFLNK: return DT_LNK;
#ifdef DT_SOCK
case S_IFSOCK: return DT_SOCK;
#endif
default: return DT_UNKNOWN;
}
}
int __wasilibc_dttoif(int x) {
switch (x) {
case DT_DIR: return S_IFDIR;
case DT_CHR: return S_IFCHR;
case DT_BLK: return S_IFBLK;
case DT_REG: return S_IFREG;
case DT_FIFO: return S_IFIFO;
case DT_LNK: return S_IFLNK;
#ifdef DT_SOCK
case DT_SOCK: return S_IFSOCK;
#endif
case DT_UNKNOWN:
default:
return S_IFSOCK;
}
}

View File

@@ -0,0 +1,14 @@
#include <wasi/libc-environ.h>
extern char **__wasilibc_environ;
// See the comments in libc-environ.h.
char **__wasilibc_get_environ(void) {
// Perform lazy initialization if needed.
__wasilibc_ensure_environ();
// Return `environ`. Use the `__wasilibc_`-prefixed name so that we don't
// pull in the `environ` symbol directly, which would lead to eager
// initialization being done instead.
return __wasilibc_environ;
}

View File

@@ -11,7 +11,7 @@
/// Statically-initialize it to an invalid pointer value so that we can
/// detect if it's been explicitly initialized (we can't use `NULL` because
/// `clearenv` sets it to NULL.
char **__wasilibc_environ __attribute__((weak)) = (char **)-1;
weak char **__wasilibc_environ = (char **)-1;
// See the comments in libc-environ.h.
void __wasilibc_ensure_environ(void) {
@@ -75,3 +75,19 @@ oserr:
software:
_Exit(EX_SOFTWARE);
}
// See the comments in libc-environ.h.
void __wasilibc_deinitialize_environ(void) {
if (__wasilibc_environ != (char **)-1) {
// Let libc-top-half clear the old environment-variable strings.
clearenv();
// Set the pointer to the special init value.
__wasilibc_environ = (char **)-1;
}
}
// See the comments in libc-environ.h.
weak void __wasilibc_maybe_reinitialize_environ_eagerly(void) {
// This version does nothing. It may be overridden by a version which does
// something if `environ` is used.
}

View File

@@ -599,6 +599,20 @@ __wasi_errno_t __wasi_random_get(
return (uint16_t) ret;
}
int32_t __imported_wasi_snapshot_preview1_sock_accept(int32_t arg0, int32_t arg1, int32_t arg2) __attribute__((
__import_module__("wasi_snapshot_preview1"),
__import_name__("sock_accept")
));
__wasi_errno_t __wasi_sock_accept(
__wasi_fd_t fd,
__wasi_fdflags_t flags,
__wasi_fd_t *retptr0
){
int32_t ret = __imported_wasi_snapshot_preview1_sock_accept((int32_t) fd, flags, (int32_t) retptr0);
return (uint16_t) ret;
}
int32_t __imported_wasi_snapshot_preview1_sock_recv(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5) __attribute__((
__import_module__("wasi_snapshot_preview1"),
__import_name__("sock_recv")
@@ -645,3 +659,14 @@ __wasi_errno_t __wasi_sock_shutdown(
return (uint16_t) ret;
}
#ifdef _REENTRANT
int32_t __imported_wasi_thread_spawn(int32_t arg0) __attribute__((
__import_module__("wasi"),
__import_name__("thread_spawn")
));
__wasi_errno_t __wasi_thread_spawn(void* start_arg) {
int32_t ret = __imported_wasi_thread_spawn((int32_t) start_arg);
return (uint16_t) ret;
}
#endif

View File

@@ -1,4 +1,3 @@
#include <common/errno.h>
#include <wasi/api.h>
#include <wasi/libc.h>
#include <errno.h>
@@ -6,7 +5,7 @@
int __wasilibc_nocwd___wasilibc_rmdirat(int fd, const char *path) {
__wasi_errno_t error = __wasi_path_remove_directory(fd, path);
if (error != 0) {
errno = errno_fixup_directory(fd, error);
errno = error;
return -1;
}
return 0;

View File

@@ -1,4 +1,3 @@
#include <common/errno.h>
#include <wasi/api.h>
#include <wasi/libc.h>
#include <errno.h>

View File

@@ -9,9 +9,12 @@
#include <wasi/libc.h>
#ifdef _REENTRANT
#error "chdir doesn't yet support multiple threads"
void __wasilibc_cwd_lock(void);
void __wasilibc_cwd_unlock(void);
#else
#define __wasilibc_cwd_lock() (void)0
#define __wasilibc_cwd_unlock() (void)0
#endif
extern char *__wasilibc_cwd;
static int __wasilibc_cwd_mallocd = 0;
@@ -43,10 +46,10 @@ int chdir(const char *path)
//
// If `relative_buf` is equal to "." or `abs` is equal to the empty string,
// however, we skip that part and the middle slash.
size_t len = strlen(abs) + 1;
size_t abs_len = strlen(abs);
int copy_relative = strcmp(relative_buf, ".") != 0;
int mid = copy_relative && abs[0] != 0;
char *new_cwd = malloc(len + (copy_relative ? strlen(relative_buf) + mid: 0)+1);
char *new_cwd = malloc(1 + abs_len + mid + (copy_relative ? strlen(relative_buf) : 0) + 1);
if (new_cwd == NULL) {
errno = ENOMEM;
return -1;
@@ -54,14 +57,16 @@ int chdir(const char *path)
new_cwd[0] = '/';
strcpy(new_cwd + 1, abs);
if (mid)
new_cwd[len] = '/';
new_cwd[1 + abs_len] = '/';
if (copy_relative)
strcpy(new_cwd + 1 + mid + strlen(abs), relative_buf);
strcpy(new_cwd + 1 + abs_len + mid, relative_buf);
// And set our new malloc'd buffer into the global cwd, freeing the
// previous one if necessary.
__wasilibc_cwd_lock();
char *prev_cwd = __wasilibc_cwd;
__wasilibc_cwd = new_cwd;
__wasilibc_cwd_unlock();
if (__wasilibc_cwd_mallocd)
free(prev_cwd);
__wasilibc_cwd_mallocd = 1;
@@ -77,11 +82,13 @@ static const char *make_absolute(const char *path) {
return path;
}
#ifndef _REENTRANT
// If the path is empty, or points to the current directory, then return
// the current directory.
if (path[0] == 0 || !strcmp(path, ".") || !strcmp(path, "./")) {
return __wasilibc_cwd;
}
#endif
// If the path starts with `./` then we won't be appending that to the cwd.
if (path[0] == '.' && path[1] == '/')
@@ -90,18 +97,30 @@ static const char *make_absolute(const char *path) {
// Otherwise we'll take the current directory, add a `/`, and then add the
// input `path`. Note that this doesn't do any normalization (like removing
// `/./`).
__wasilibc_cwd_lock();
size_t cwd_len = strlen(__wasilibc_cwd);
size_t path_len = strlen(path);
size_t path_len = path ? strlen(path) : 0;
__wasilibc_cwd_unlock();
int need_slash = __wasilibc_cwd[cwd_len - 1] == '/' ? 0 : 1;
size_t alloc_len = cwd_len + path_len + 1 + need_slash;
if (alloc_len > make_absolute_len) {
char *tmp = realloc(make_absolute_buf, alloc_len);
if (tmp == NULL)
if (tmp == NULL) {
__wasilibc_cwd_unlock();
return NULL;
}
make_absolute_buf = tmp;
make_absolute_len = alloc_len;
}
strcpy(make_absolute_buf, __wasilibc_cwd);
__wasilibc_cwd_unlock();
#ifdef _REENTRANT
if (path[0] == 0 || !strcmp(path, ".") || !strcmp(path, "./")) {
return make_absolute_buf;
}
#endif
if (need_slash)
strcpy(make_absolute_buf + cwd_len, "/");
strcpy(make_absolute_buf + cwd_len + need_slash, path);

View File

@@ -9,10 +9,8 @@
// `__wasilibc_environ`, which is initialized with a constructor function, so
// that it's initialized whenever user code might want to access it.
char **__wasilibc_environ;
extern __typeof(__wasilibc_environ) _environ
__attribute__((weak, alias("__wasilibc_environ")));
extern __typeof(__wasilibc_environ) environ
__attribute__((weak, alias("__wasilibc_environ")));
weak_alias(__wasilibc_environ, _environ);
weak_alias(__wasilibc_environ, environ);
// We define this function here in the same source file as
// `__wasilibc_environ`, so that this function is called in iff environment
@@ -24,3 +22,10 @@ __attribute__((constructor(50)))
static void __wasilibc_initialize_environ_eagerly(void) {
__wasilibc_initialize_environ();
}
// See the comments in libc-environ.h.
void __wasilibc_maybe_reinitialize_environ_eagerly(void) {
// This translation unit is linked in if `environ` is used, meaning we need
// to eagerly reinitialize the environment variables.
__wasilibc_initialize_environ();
}

View File

@@ -1,30 +1,39 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
// For threads this needs to synchronize with chdir
#ifdef _REENTRANT
#error "getcwd doesn't yet support multiple threads"
#endif
#include "lock.h"
char *__wasilibc_cwd = "/";
#ifdef _REENTRANT
static volatile int lock[1];
void __wasilibc_cwd_lock(void) { LOCK(lock); }
void __wasilibc_cwd_unlock(void) { UNLOCK(lock); }
#else
#define __wasilibc_cwd_lock() (void)0
#define __wasilibc_cwd_unlock() (void)0
#endif
char *getcwd(char *buf, size_t size)
{
__wasilibc_cwd_lock();
if (!buf) {
buf = strdup(__wasilibc_cwd);
if (!buf) {
errno = ENOMEM;
__wasilibc_cwd_unlock();
return NULL;
}
} else {
size_t len = strlen(__wasilibc_cwd);
if (size < len + 1) {
errno = ERANGE;
__wasilibc_cwd_unlock();
return NULL;
}
strcpy(buf, __wasilibc_cwd);
}
__wasilibc_cwd_unlock();
return buf;
}

View File

@@ -1,10 +1,6 @@
#include <wasi/api.h>
#include <errno.h>
#include <unistd.h>
#ifdef _REENTRANT
#error With threads support, getentropy is not intended to be a cancellation point.
#endif
#include <wasi/api.h>
int __getentropy(void *buffer, size_t len) {
if (len > 256) {
@@ -21,4 +17,4 @@ int __getentropy(void *buffer, size_t len) {
return 0;
}
extern __typeof(__getentropy) getentropy __attribute__((weak, alias("__getentropy")));
weak_alias(__getentropy, getentropy);

View File

@@ -19,4 +19,4 @@ int __isatty(int fd) {
return 1;
}
extern __typeof(__isatty) isatty __attribute__((weak, alias("__isatty")));
extern __typeof(__isatty) isatty __attribute__((__weak__, alias("__isatty")));

View File

@@ -2,14 +2,11 @@
//! environment, with associated path prefixes, which can be used to map
//! absolute paths to capabilities with relative paths.
#ifdef _REENTRANT
#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads"
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <lock.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -32,6 +29,12 @@ static preopen *preopens;
static size_t num_preopens;
static size_t preopen_capacity;
/// Access to the the above preopen must be protected in the presence of
/// threads.
#ifdef _REENTRANT
static volatile int lock[1];
#endif
#ifdef NDEBUG
#define assert_invariants() // assertions disabled
#else
@@ -55,14 +58,17 @@ static void assert_invariants(void) {
/// Allocate space for more preopens. Returns 0 on success and -1 on failure.
static int resize(void) {
LOCK(lock);
size_t start_capacity = 4;
size_t old_capacity = preopen_capacity;
size_t new_capacity = old_capacity == 0 ? start_capacity : old_capacity * 2;
preopen *old_preopens = preopens;
preopen *new_preopens = calloc(sizeof(preopen), new_capacity);
if (new_preopens == NULL)
if (new_preopens == NULL) {
UNLOCK(lock);
return -1;
}
memcpy(new_preopens, old_preopens, num_preopens * sizeof(preopen));
preopens = new_preopens;
@@ -70,6 +76,7 @@ static int resize(void) {
free(old_preopens);
assert_invariants();
UNLOCK(lock);
return 0;
}
@@ -97,21 +104,28 @@ static const char *strip_prefixes(const char *path) {
///
/// This function takes ownership of `prefix`.
static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) {
LOCK(lock);
// Check preconditions.
assert_invariants();
assert(fd != AT_FDCWD);
assert(fd != -1);
assert(relprefix != NULL);
if (num_preopens == preopen_capacity && resize() != 0)
if (num_preopens == preopen_capacity && resize() != 0) {
UNLOCK(lock);
return -1;
}
char *prefix = strdup(strip_prefixes(relprefix));
if (prefix == NULL)
if (prefix == NULL) {
UNLOCK(lock);
return -1;
}
preopens[num_preopens++] = (preopen) { prefix, fd, };
assert_invariants();
UNLOCK(lock);
return 0;
}
@@ -166,6 +180,7 @@ int __wasilibc_find_abspath(const char *path,
// recently added preopens take precedence over less recently addded ones.
size_t match_len = 0;
int fd = -1;
LOCK(lock);
for (size_t i = num_preopens; i > 0; --i) {
const preopen *pre = &preopens[i - 1];
const char *prefix = pre->prefix;
@@ -182,6 +197,7 @@ int __wasilibc_find_abspath(const char *path,
*abs_prefix = prefix;
}
}
UNLOCK(lock);
if (fd == -1) {
errno = ENOENT;

View File

@@ -1,7 +1,3 @@
#ifdef _REENTRANT
#error "multiple threads not supported in musl yet"
#endif
#define a_barrier() (__sync_synchronize())
#define a_cas(p, t, s) (__sync_val_compare_and_swap((p), (t), (s)))
#define a_crash() (__builtin_trap())

View File

@@ -1,12 +1,5 @@
#ifdef _REENTRANT
#error "multiple threads not supported in musl yet"
#endif
extern _Thread_local struct __pthread __wasilibc_pthread_self;
static inline struct pthread *__pthread_self(void)
{
return (struct pthread *)-1;
static inline uintptr_t __get_tp() {
return (uintptr_t)&__wasilibc_pthread_self;
}
#define TP_ADJ(p) (p)
#define tls_mod_off_t unsigned long long

View File

@@ -70,7 +70,7 @@
#define PTHREAD_STACK_MIN 2048
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
#endif
#ifdef __wasilibc_unmodified_upstream /* WASI has no semaphores */
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#define SEM_VALUE_MAX 0x7fffffff
#define SEM_NSEMS_MAX 256
#endif

View File

@@ -103,8 +103,10 @@ int pthread_setcanceltype(int, int *);
void pthread_testcancel(void);
int pthread_cancel(pthread_t);
#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */
int pthread_getschedparam(pthread_t, int *__restrict, struct sched_param *__restrict);
int pthread_setschedparam(pthread_t, int, const struct sched_param *);
#endif
int pthread_setschedprio(pthread_t, int);
int pthread_once(pthread_once_t *, void (*)(void));
@@ -167,8 +169,10 @@ int pthread_attr_getscope(const pthread_attr_t *__restrict, int *__restrict);
int pthread_attr_setscope(pthread_attr_t *, int);
int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict, int *__restrict);
int pthread_attr_setschedpolicy(pthread_attr_t *, int);
#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */
int pthread_attr_getschedparam(const pthread_attr_t *__restrict, struct sched_param *__restrict);
int pthread_attr_setschedparam(pthread_attr_t *__restrict, const struct sched_param *__restrict);
#endif
int pthread_attr_getinheritsched(const pthread_attr_t *__restrict, int *__restrict);
int pthread_attr_setinheritsched(pthread_attr_t *, int);

View File

@@ -244,7 +244,9 @@ void *sbrk(intptr_t);
pid_t vfork(void);
int vhangup(void);
int chroot(const char *);
#endif
int getpagesize(void);
#ifdef __wasilibc_unmodified_upstream /* WASI has no processes */
int getdtablesize(void);
int sethostname(const char *, size_t);
int getdomainname(char *, size_t);

View File

@@ -251,7 +251,7 @@ long sysconf(int name)
return DELAYTIMER_MAX;
case JT_NPROCESSORS_CONF & 255:
case JT_NPROCESSORS_ONLN & 255: ;
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#ifdef __wasilibc_unmodified_upstream
unsigned char set[128] = {1};
int i, cnt;
__syscall(SYS_sched_getaffinity, 0, sizeof set, set);
@@ -259,7 +259,7 @@ long sysconf(int name)
for (; set[i]; set[i]&=set[i]-1, cnt++);
return cnt;
#else
// With no thread support, just say there's 1 processor.
// WASI has no way to query the processor count
return 1;
#endif
#ifdef __wasilibc_unmodified_upstream // WASI has no sysinfo

View File

@@ -1,7 +1,11 @@
#ifdef __wasilibc_unmodified_upstream
#define SYSCALL_NO_TLS 1
#include <elf.h>
#endif
#include <limits.h>
#ifdef __wasilibc_unmodified_upstream
#include <sys/mman.h>
#endif
#include <string.h>
#include <stddef.h>
#include "pthread_impl.h"
@@ -11,15 +15,23 @@
volatile int __thread_list_lock;
#ifndef __wasilibc_unmodified_upstream
void __wasi_init_tp() {
__init_tp((void *)__get_tp());
}
#endif
int __init_tp(void *p)
{
pthread_t td = p;
td->self = td;
#ifdef __wasilibc_unmodified_upstream
int r = __set_thread_area(TP_ADJ(p));
if (r < 0) return -1;
if (!r) libc.can_do_threads = 1;
td->detach_state = DT_JOINABLE;
td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
#endif
td->locale = &libc.global_locale;
td->robust_list.head = &td->robust_list.head;
td->sysinfo = __sysinfo;
@@ -27,6 +39,8 @@ int __init_tp(void *p)
return 0;
}
#ifdef __wasilibc_unmodified_upstream
static struct builtin_tls {
char c;
struct pthread pt;
@@ -35,9 +49,15 @@ static struct builtin_tls {
#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)
static struct tls_module main_tls;
#endif
#ifndef __wasilibc_unmodified_upstream
extern void __wasm_init_tls(void*);
#endif
void *__copy_tls(unsigned char *mem)
{
#ifdef __wasilibc_unmodified_upstream
pthread_t td;
struct tls_module *p;
size_t i;
@@ -69,8 +89,20 @@ void *__copy_tls(unsigned char *mem)
dtv[0] = libc.tls_cnt;
td->dtv = dtv;
return td;
#else
size_t tls_align = __builtin_wasm_tls_align();
volatile void* tls_base = __builtin_wasm_tls_base();
mem += tls_align;
mem -= (uintptr_t)mem & (tls_align-1);
__wasm_init_tls(mem);
__asm__("local.get %0\n"
"global.set __tls_base\n"
:: "r"(tls_base));
return mem;
#endif
}
#ifdef __wasilibc_unmodified_upstream
#if ULONG_MAX == 0xffffffff
typedef Elf32_Phdr Phdr;
#else
@@ -151,3 +183,4 @@ static void static_init_tls(size_t *aux)
}
weak_alias(static_init_tls, __init_tls);
#endif

View File

@@ -18,8 +18,10 @@ struct tls_module {
};
struct __libc {
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#ifdef __wasilibc_unmodified_upstream
char can_do_threads;
#endif
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
char threaded;
#endif
#ifdef __wasilibc_unmodified_upstream // WASI doesn't currently use any code that needs "secure" mode
@@ -32,7 +34,7 @@ struct __libc {
#ifdef __wasilibc_unmodified_upstream // WASI has no auxv
size_t *auxv;
#endif
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#ifdef __wasilibc_unmodified_upstream // WASI use different TLS implement
struct tls_module *tls_head;
size_t tls_size, tls_align, tls_cnt;
#endif

View File

@@ -2,12 +2,18 @@
#define _PTHREAD_IMPL_H
#include <pthread.h>
#ifdef __wasilibc_unmodified_upstream
#include <signal.h>
#endif
#include <errno.h>
#include <limits.h>
#ifdef __wasilibc_unmodified_upstream
#include <sys/mman.h>
#endif
#include "libc.h"
#ifdef __wasilibc_unmodified_upstream
#include "syscall.h"
#endif
#include "atomic.h"
#include "futex.h"
@@ -19,8 +25,10 @@ struct pthread {
/* Part 1 -- these fields may be external or
* internal (accessed via asm) ABI. Do not change. */
struct pthread *self;
#ifdef __wasilibc_unmodified_upstream
#ifndef TLS_ABOVE_TP
uintptr_t *dtv;
#endif
#endif
struct pthread *prev, *next; /* non-ABI */
uintptr_t sysinfo;
@@ -159,9 +167,14 @@ extern hidden volatile int __eintr_valid_flag;
hidden int __clone(int (*)(void *), void *, int, void *, ...);
hidden int __set_thread_area(void *);
#ifdef __wasilibc_unmodified_upstream /* WASI has no sigaction */
hidden int __libc_sigaction(int, const struct sigaction *, struct sigaction *);
#endif
hidden void __unmapself(void *, size_t);
#ifndef __wasilibc_unmodified_upstream
hidden int __wasilibc_futex_wait(volatile void *, int, int, int64_t);
#endif
hidden int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int);
hidden int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int);
hidden void __wait(volatile int *, volatile int *, int, int);
@@ -169,14 +182,22 @@ static inline void __wake(volatile void *addr, int cnt, int priv)
{
if (priv) priv = FUTEX_PRIVATE;
if (cnt<0) cnt = INT_MAX;
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS ||
__syscall(SYS_futex, addr, FUTEX_WAKE, cnt);
#else
__builtin_wasm_memory_atomic_notify((int*)addr, cnt);
#endif
}
static inline void __futexwait(volatile void *addr, int val, int priv)
{
#ifdef __wasilibc_unmodified_upstream
if (priv) priv = FUTEX_PRIVATE;
__syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS ||
__syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
#else
__wait(addr, NULL, val, priv);
#endif
}
hidden void __acquire_ptc(void);

View File

@@ -1,3 +1,4 @@
#ifdef __wasilibc_unmodified_upstream
#ifndef _INTERNAL_SYSCALL_H
#define _INTERNAL_SYSCALL_H
@@ -396,3 +397,4 @@ hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned);
hidden void *__vdsosym(const char *, const char *);
#endif
#endif

View File

@@ -23,7 +23,7 @@ static int n = 31;
static int i = 3;
static int j = 0;
static uint32_t *x = init+1;
#ifdef __wasilibc_unmodified_upstream
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
static volatile int lock[1];
volatile int *const __random_lockptr = lock;
#endif

View File

@@ -4,6 +4,10 @@
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
{
#if defined(__wasm_bulk_memory__)
if (n > BULK_MEMORY_THRESHOLD)
return __builtin_memcpy(dest, src, n);
#endif
unsigned char *d = dest;
const unsigned char *s = src;

View File

@@ -8,6 +8,10 @@ typedef __attribute__((__may_alias__)) size_t WT;
void *memmove(void *dest, const void *src, size_t n)
{
#if defined(__wasm_bulk_memory__)
if (n > BULK_MEMORY_THRESHOLD)
return __builtin_memmove(dest, src, n);
#endif
char *d = dest;
const char *s = src;

View File

@@ -3,6 +3,10 @@
void *memset(void *dest, int c, size_t n)
{
#if defined(__wasm_bulk_memory__)
if (n > BULK_MEMORY_THRESHOLD)
return __builtin_memset(dest, c, n);
#endif
unsigned char *s = dest;
size_t k;

View File

@@ -5,6 +5,7 @@
#include "syscall.h"
#include "pthread_impl.h"
#ifdef __wasilibc_unmodified_upstream
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
@@ -28,6 +29,16 @@ static int __futex4_cp(volatile void *addr, int op, int val, const struct timesp
static volatile int dummy = 0;
weak_alias(dummy, __eintr_valid_flag);
#else
static int __futex4_cp(volatile void *addr, int op, int val, const struct timespec *to)
{
int64_t max_wait_ns = -1;
if (to) {
max_wait_ns = (int64_t)(to->tv_sec * 1000000000 + to->tv_nsec);
}
return __wasilibc_futex_wait(addr, op, val, max_wait_ns);
}
#endif
int __timedwait_cp(volatile int *addr, int val,
clockid_t clk, const struct timespec *at, int priv)
@@ -51,11 +62,13 @@ int __timedwait_cp(volatile int *addr, int val,
r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top);
if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
#ifdef __wasilibc_unmodified_upstream
/* Mitigate bug in old kernels wrongly reporting EINTR for non-
* interrupting (SA_RESTART) signal handlers. This is only practical
* when NO interrupting signal handlers have been installed, and
* works by sigaction tracking whether that's the case. */
if (r == EINTR && !__eintr_valid_flag) r = 0;
#endif
return r;
}

View File

@@ -1,4 +1,38 @@
#include "pthread_impl.h"
#ifndef __wasilibc_unmodified_upstream
#include "assert.h"
#endif
#ifndef __wasilibc_unmodified_upstream
// Use WebAssembly's `wait` instruction to implement a futex. Note that `op` is
// unused but retained as a parameter to match the original signature of the
// syscall and that, for `max_wait_ns`, -1 (or any negative number) means wait
// indefinitely.
//
// Adapted from Emscripten: see
// https://github.com/emscripten-core/emscripten/blob/058a9fff/system/lib/pthread/emscripten_futex_wait.c#L111-L150.
int __wasilibc_futex_wait(volatile void *addr, int op, int val, int64_t max_wait_ns)
{
if ((((intptr_t)addr) & 3) != 0) {
return -EINVAL;
}
int ret = __builtin_wasm_memory_atomic_wait32((int *)addr, val, max_wait_ns);
// memory.atomic.wait32 returns:
// 0 => "ok", woken by another agent.
// 1 => "not-equal", loaded value != expected value
// 2 => "timed-out", the timeout expired
if (ret == 1) {
return -EWOULDBLOCK;
}
if (ret == 2) {
return -ETIMEDOUT;
}
assert(ret == 0);
return 0;
}
#endif
void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
{
@@ -10,8 +44,12 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
}
if (waiters) a_inc(waiters);
while (*addr==val) {
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS
|| __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
#else
__wasilibc_futex_wait(addr, FUTEX_WAIT, val, 0);
#endif
}
if (waiters) a_dec(waiters);
}

View File

@@ -1,5 +1,9 @@
#include "pthread_impl.h"
#ifndef __wasilibc_unmodified_upstream
#include <common/clock.h>
#endif
/*
* struct waiter
*
@@ -48,9 +52,15 @@ static inline void unlock(volatile int *l)
static inline void unlock_requeue(volatile int *l, volatile int *r, int w)
{
a_store(l, 0);
#ifdef __wasilibc_unmodified_upstream
if (w) __wake(l, 1, 1);
else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS
|| __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r);
#else
// Always wake due to lack of requeue system call in WASI
// This can impact the performance, so we might need to re-visit that decision
__wake(l, 1, 1);
#endif
}
enum {
@@ -63,6 +73,9 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
{
struct waiter node = { 0 };
int e, seq, clock = c->_c_clock, cs, shared=0, oldstate, tmp;
#ifndef __wasilibc_unmodified_upstream
struct __clockid clock_id = { .id = clock };
#endif
volatile int *fut;
if ((m->_m_type&15) && (m->_m_lock&INT_MAX) != __pthread_self()->tid)
@@ -97,7 +110,11 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
__pthread_setcancelstate(PTHREAD_CANCEL_MASKED, &cs);
if (cs == PTHREAD_CANCEL_DISABLE) __pthread_setcancelstate(cs, 0);
#ifdef __wasilibc_unmodified_upstream
do e = __timedwait_cp(fut, seq, clock, ts, !shared);
#else
do e = __timedwait_cp(fut, seq, &clock_id, ts, !shared);
#endif
while (*fut==seq && (!e || e==EINTR));
if (e == EINTR) e = 0;

View File

@@ -1,9 +1,21 @@
#include "pthread_impl.h"
#ifndef __wasilibc_unmodified_upstream
#include <common/clock.h>
#endif
int pthread_condattr_setclock(pthread_condattr_t *a, clockid_t clk)
{
#ifdef __wasilibc_unmodified_upstream
if (clk < 0 || clk-2U < 2) return EINVAL;
#else
if (clk->id < 0 || clk->id-2U < 2) return EINVAL;
#endif
a->__attr &= 0x80000000;
#ifdef __wasilibc_unmodified_upstream
a->__attr |= clk;
#else
a->__attr |= clk->id;
#endif
return 0;
}

View File

@@ -3,9 +3,16 @@
#include "stdio_impl.h"
#include "libc.h"
#include "lock.h"
#ifdef __wasilibc_unmodified_upstream
#include <sys/mman.h>
#endif
#include <string.h>
#include <stddef.h>
#ifndef __wasilibc_unmodified_upstream
#include <stdatomic.h>
#endif
#include <stdalign.h>
static void dummy_0()
{
@@ -14,8 +21,10 @@ weak_alias(dummy_0, __acquire_ptc);
weak_alias(dummy_0, __release_ptc);
weak_alias(dummy_0, __pthread_tsd_run_dtors);
weak_alias(dummy_0, __do_orphaned_stdio_locks);
#ifdef __wasilibc_unmodified_upstream
weak_alias(dummy_0, __dl_thread_cleanup);
weak_alias(dummy_0, __membarrier_init);
#endif
static int tl_lock_count;
static int tl_lock_waiters;
@@ -69,7 +78,9 @@ _Noreturn void __pthread_exit(void *result)
__pthread_tsd_run_dtors();
#ifdef __wasilibc_unmodified_upstream
__block_app_sigs(&set);
#endif
/* This atomic potentially competes with a concurrent pthread_detach
* call; the loser is responsible for freeing thread resources. */
@@ -80,7 +91,9 @@ _Noreturn void __pthread_exit(void *result)
* explicitly wait for vmlock holders first. This must be
* done before any locks are taken, to avoid lock ordering
* issues that could lead to deadlock. */
#ifdef __wasilibc_unmodified_upstream
__vm_wait();
#endif
}
/* Access to target the exiting thread with syscalls that use
@@ -101,16 +114,20 @@ _Noreturn void __pthread_exit(void *result)
__tl_unlock();
UNLOCK(self->killlock);
self->detach_state = state;
#ifdef __wasilibc_unmodified_upstream
__restore_sigs(&set);
#endif
exit(0);
}
/* At this point we are committed to thread termination. */
#ifdef __wasilibc_unmodified_upstream
/* Process robust list in userspace to handle non-pshared mutexes
* and the detached thread case where the robust list head will
* be invalid when the kernel would process it. */
__vm_lock();
#endif
volatile void *volatile *rp;
while ((rp=self->robust_list.head) && rp != &self->robust_list.head) {
pthread_mutex_t *m = (void *)((char *)rp
@@ -124,10 +141,14 @@ _Noreturn void __pthread_exit(void *result)
if (cont < 0 || waiters)
__wake(&m->_m_lock, 1, priv);
}
#ifdef __wasilibc_unmodified_upstream
__vm_unlock();
#endif
__do_orphaned_stdio_locks();
#ifdef __wasilibc_unmodified_upstream
__dl_thread_cleanup();
#endif
/* Last, unlink thread from the list. This change will not be visible
* until the lock is released, which only happens after SYS_exit
@@ -139,6 +160,15 @@ _Noreturn void __pthread_exit(void *result)
self->prev->next = self->next;
self->prev = self->next = self;
#ifndef __wasilibc_unmodified_upstream
/* On Linux, the thread is created with CLONE_CHILD_CLEARTID,
* and this lock will unlock by kernel when this thread terminates.
* So we should unlock it here in WebAssembly.
* See also set_tid_address(2) */
__tl_unlock();
#endif
#ifdef __wasilibc_unmodified_upstream
if (state==DT_DETACHED && self->map_base) {
/* Detached threads must block even implementation-internal
* signals, since they will not have a stack in their last
@@ -154,6 +184,16 @@ _Noreturn void __pthread_exit(void *result)
* and then exits without touching the stack. */
__unmapself(self->map_base, self->map_size);
}
#else
if (state==DT_DETACHED && self->map_base) {
// __syscall(SYS_exit) would unlock the thread, list
// do it manually here
__tl_unlock();
free(self->map_base);
// Can't use `exit()` here, because it is too high level
for (;;) __wasi_proc_exit(0);
}
#endif
/* Wake any joiner. */
a_store(&self->detach_state, DT_EXITED);
@@ -165,7 +205,15 @@ _Noreturn void __pthread_exit(void *result)
self->tid = 0;
UNLOCK(self->killlock);
#ifdef __wasilibc_unmodified_upstream
for (;;) __syscall(SYS_exit, 0);
#else
// __syscall(SYS_exit) would unlock the thread, list
// do it manually here
__tl_unlock();
// Can't use `exit()` here, because it is too high level
for (;;) __wasi_proc_exit(0);
#endif
}
void __do_cleanup_push(struct __ptcb *cb)
@@ -181,12 +229,19 @@ void __do_cleanup_pop(struct __ptcb *cb)
}
struct start_args {
#ifdef __wasilibc_unmodified_upstream
void *(*start_func)(void *);
void *start_arg;
volatile int control;
unsigned long sig_mask[_NSIG/8/sizeof(long)];
#else
void *(*start_func)(void *);
void *start_arg;
void *tls_base;
#endif
};
#ifdef __wasilibc_unmodified_upstream
static int start(void *p)
{
struct start_args *args = p;
@@ -195,11 +250,15 @@ static int start(void *p)
if (a_cas(&args->control, 1, 2)==1)
__wait(&args->control, 0, 2, 1);
if (args->control) {
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_set_tid_address, &args->control);
for (;;) __syscall(SYS_exit, 0);
#endif
}
}
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8);
#endif
__pthread_exit(args->start_func(args->start_arg));
return 0;
}
@@ -211,6 +270,31 @@ static int start_c11(void *p)
__pthread_exit((void *)(uintptr_t)start(args->start_arg));
return 0;
}
#else
__attribute__((export_name("wasi_thread_start")))
_Noreturn void wasi_thread_start(int tid, void *p)
{
struct start_args *args = p;
__asm__(".globaltype __tls_base, i32\n"
"local.get %0\n"
"global.set __tls_base\n"
:: "r"(args->tls_base));
pthread_t self = __pthread_self();
// Set the thread ID (TID) on the pthread structure. The TID is stored
// atomically since it is also stored by the parent thread; this way,
// whichever thread (parent or child) reaches this point first can proceed
// without waiting.
atomic_store((atomic_int *) &(self->tid), tid);
// Set the stack pointer.
__asm__(".globaltype __stack_pointer, i32\n"
"local.get %0\n"
"global.set __stack_pointer\n"
:: "r"(self->stack));
// Execute the user's start function.
int (*start)(void*) = (int(*)(void*)) args->start_func;
__pthread_exit((void *)(uintptr_t)start(args->start_arg));
}
#endif
#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
@@ -236,13 +320,25 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
size_t size, guard;
struct pthread *self, *new;
unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit;
#ifdef __wasilibc_unmodified_upstream
unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
| CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
| CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED;
#endif
pthread_attr_t attr = { 0 };
sigset_t set;
#ifndef __wasilibc_unmodified_upstream
size_t tls_size = __builtin_wasm_tls_size();
size_t tls_align = __builtin_wasm_tls_align();
void* tls_base = __builtin_wasm_tls_base();
void* new_tls_base;
size_t tls_offset;
tls_size += tls_align;
#endif
#ifdef __wasilibc_unmodified_upstream
if (!libc.can_do_threads) return ENOSYS;
#endif
self = __pthread_self();
if (!libc.threaded) {
for (FILE *f=*__ofl_lock(); f; f=f->next)
@@ -251,9 +347,13 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
init_file_lock(__stdin_used);
init_file_lock(__stdout_used);
init_file_lock(__stderr_used);
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8);
#endif
self->tsd = (void **)__pthread_tsd_main;
#ifdef __wasilibc_unmodified_upstream
__membarrier_init();
#endif
libc.threaded = 1;
}
if (attrp && !c11) attr = *attrp;
@@ -265,7 +365,11 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
}
if (attr._a_stackaddr) {
#ifdef __wasilibc_unmodified_upstream
size_t need = libc.tls_size + __pthread_tsd_size;
#else
size_t need = tls_size + __pthread_tsd_size;
#endif
size = attr._a_stacksize;
stack = (void *)(attr._a_stackaddr & -16);
stack_limit = (void *)(attr._a_stackaddr - size);
@@ -274,7 +378,11 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
* application's stack space. */
if (need < size/8 && need < 2048) {
tsd = stack - __pthread_tsd_size;
#ifdef __wasilibc_unmodified_upstream
stack = tsd - libc.tls_size;
#else
stack = tsd - tls_size;
#endif
memset(stack, 0, need);
} else {
size = ROUND(need);
@@ -283,10 +391,15 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
} else {
guard = ROUND(attr._a_guardsize);
size = guard + ROUND(attr._a_stacksize
#ifdef __wasilibc_unmodified_upstream
+ libc.tls_size + __pthread_tsd_size);
#else
+ tls_size + __pthread_tsd_size);
#endif
}
if (!tsd) {
#ifdef __wasilibc_unmodified_upstream
if (guard) {
map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
if (map == MAP_FAILED) goto fail;
@@ -299,14 +412,28 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
if (map == MAP_FAILED) goto fail;
}
#else
map = malloc(size);
if (!map) goto fail;
#endif
tsd = map + size - __pthread_tsd_size;
if (!stack) {
#ifdef __wasilibc_unmodified_upstream
stack = tsd - libc.tls_size;
#else
stack = tsd - tls_size;
#endif
stack_limit = map + guard;
}
}
#ifdef __wasilibc_unmodified_upstream
new = __copy_tls(tsd - libc.tls_size);
#else
new_tls_base = __copy_tls(tsd - tls_size);
tls_offset = new_tls_base - tls_base;
new = (void*)((uintptr_t)self + tls_offset);
#endif
new->map_base = map;
new->map_size = size;
new->stack = stack;
@@ -327,6 +454,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
/* Setup argument structure for the new thread on its stack.
* It's safe to access from the caller only until the thread
* list is unlocked. */
#ifdef __wasilibc_unmodified_upstream
stack -= (uintptr_t)stack % sizeof(uintptr_t);
stack -= sizeof(struct start_args);
struct start_args *args = (void *)stack;
@@ -345,11 +473,35 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
memcpy(&args->sig_mask, &set, sizeof args->sig_mask);
args->sig_mask[(SIGCANCEL-1)/8/sizeof(long)] &=
~(1UL<<((SIGCANCEL-1)%(8*sizeof(long))));
#else
/* Align the stack to struct start_args */
stack -= sizeof(struct start_args);
stack -= (uintptr_t)stack % alignof(struct start_args);
struct start_args *args = (void *)stack;
/* Align the stack to 16 and store it */
new->stack = (void *)((uintptr_t) stack & -16);
/* Correct the stack size */
new->stack_size = stack - stack_limit;
args->start_func = entry;
args->start_arg = arg;
args->tls_base = (void*)new_tls_base;
#endif
__tl_lock();
if (!libc.threads_minus_1++) libc.need_locks = 1;
#ifdef __wasilibc_unmodified_upstream
ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock);
#else
/* Instead of `__clone`, WASI uses a host API to instantiate a new version
* of the current module and start executing the entry function. The
* wasi-threads specification requires the module to export a
* `wasi_thread_start` function, which is invoked with `args`. */
ret = __wasi_thread_spawn((void *) args);
#endif
#ifdef __wasilibc_unmodified_upstream
/* All clone failures translate to EAGAIN. If explicit scheduling
* was requested, attempt it before unlocking the thread list so
* that the failed thread is never exposed and so that we can
@@ -364,6 +516,20 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
if (ret)
__wait(&args->control, 0, 3, 0);
}
#else
/* `wasi_thread_spawn` will either return a host-provided thread ID (TID)
* (`>= 0`) or an error code (`< 0`). As in the unmodified version, all
* spawn failures translate to EAGAIN; unlike the modified version, there is
* no need to "start up" the child thread--the host does this. If the spawn
* did succeed, then we store the TID atomically, since this parent thread
* is racing with the child thread to set this field; this way, whichever
* thread reaches this point first can continue without waiting. */
if (ret < 0) {
ret = -EAGAIN;
} else {
atomic_store((atomic_int *) &(new->tid), ret);
}
#endif
if (ret >= 0) {
new->next = self->next;
@@ -374,11 +540,17 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
if (!--libc.threads_minus_1) libc.need_locks = 0;
}
__tl_unlock();
#ifdef __wasilibc_unmodified_upstream
__restore_sigs(&set);
#endif
__release_ptc();
if (ret < 0) {
#ifdef __wasilibc_unmodified_upstream
if (map) __munmap(map, size);
#else
free(map);
#endif
return -ret;
}

View File

@@ -1,6 +1,8 @@
#define _GNU_SOURCE
#include "pthread_impl.h"
#ifdef __wasilibc_unmodified_upstream
#include <sys/mman.h>
#endif
static void dummy1(pthread_t t)
{
@@ -21,7 +23,11 @@ static int __pthread_timedjoin_np(pthread_t t, void **res, const struct timespec
if (r == ETIMEDOUT || r == EINVAL) return r;
__tl_sync(t);
if (res) *res = t->result;
#ifdef __wasilibc_unmodified_upstream
if (t->map_base) __munmap(t->map_base, t->map_size);
#else
if (t->map_base) free(t->map_base);
#endif
return 0;
}

View File

@@ -2,9 +2,17 @@
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
#ifdef __wasilibc_unmodified_upstream
/* If the mutex being destroyed is process-shared and has nontrivial
* type (tracking ownership), it might be in the pending slot of a
* robust_list; wait for quiescence. */
if (mutex->_m_type > 128) __vm_wait();
#else
/* For now, wasi-libc chooses to avoid implementing robust mutex support
* though this could be added later. The error code indicates that the
* mutex was an invalid type, but it would be more accurate as
* "unimplemented". */
if (mutex->_m_type > 128) return EINVAL;
#endif
return 0;
}

View File

@@ -1,5 +1,6 @@
#include "pthread_impl.h"
#ifdef __wasilibc_unmodified_upstream
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
@@ -52,6 +53,7 @@ static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct
while (e != ETIMEDOUT);
return e;
}
#endif
int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at)
{
@@ -65,8 +67,10 @@ int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec
r = __pthread_mutex_trylock(m);
if (r != EBUSY) return r;
#ifdef __wasilibc_unmodified_upstream
if (type&8) return pthread_mutex_timedlock_pi(m, at);
#endif
int spins = 100;
while (spins-- && m->_m_lock && !m->_m_waiters) a_spin();

View File

@@ -27,7 +27,9 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m)
if (type & 128) {
if (!self->robust_list.off) {
self->robust_list.off = (char*)&m->_m_lock-(char *)&m->_m_next;
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_set_robust_list, &self->robust_list, 3*sizeof(long));
#endif
}
if (m->_m_waiters) tid |= 0x80000000;
self->robust_list.pending = &m->_m_next;
@@ -43,7 +45,9 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m)
success:
if ((type&8) && m->_m_waiters) {
int priv = (type & 128) ^ 128;
#ifdef __wasilibc_unmodified_upstream
__syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv);
#endif
self->robust_list.pending = 0;
return (type&4) ? ENOTRECOVERABLE : EBUSY;
}

View File

@@ -22,7 +22,9 @@ int __pthread_mutex_unlock(pthread_mutex_t *m)
new = 0x7fffffff;
if (!priv) {
self->robust_list.pending = &m->_m_next;
#ifdef __wasilibc_unmodified_upstream
__vm_lock();
#endif
}
volatile void *prev = m->_m_prev;
volatile void *next = m->_m_next;
@@ -30,6 +32,7 @@ int __pthread_mutex_unlock(pthread_mutex_t *m)
if (next != &self->robust_list.head) *(volatile void *volatile *)
((char *)next - sizeof(void *)) = prev;
}
#ifdef __wasilibc_unmodified_upstream
if (type&8) {
if (old<0 || a_cas(&m->_m_lock, old, new)!=old) {
if (new) a_store(&m->_m_waiters, -1);
@@ -40,9 +43,14 @@ int __pthread_mutex_unlock(pthread_mutex_t *m)
} else {
cont = a_swap(&m->_m_lock, new);
}
#else
cont = a_swap(&m->_m_lock, new);
#endif
if (type != PTHREAD_MUTEX_NORMAL && !priv) {
self->robust_list.pending = 0;
#ifdef __wasilibc_unmodified_upstream
__vm_unlock();
#endif
}
if (waiters || cont<0)
__wake(&m->_m_lock, 1, priv);

View File

@@ -11,6 +11,7 @@ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int protocol)
a->__attr &= ~8;
return 0;
case PTHREAD_PRIO_INHERIT:
#ifdef __wasilibc_unmodified_upstream
r = check_pi_result;
if (r < 0) {
volatile int lk = 0;
@@ -20,6 +21,9 @@ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int protocol)
if (r) return r;
a->__attr |= 8;
return 0;
#else
return ENOTSUP;
#endif
case PTHREAD_PRIO_PROTECT:
return ENOTSUP;
default:

View File

@@ -5,6 +5,7 @@ static volatile int check_robust_result = -1;
int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int robust)
{
#ifdef __wasilibc_unmodified_upstream
if (robust > 1U) return EINVAL;
if (robust) {
int r = check_robust_result;
@@ -20,4 +21,7 @@ int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int robust)
}
a->__attr &= ~4;
return 0;
#else
return EINVAL;
#endif
}

View File

@@ -1,6 +1,11 @@
#include "pthread_impl.h"
#include <threads.h>
#if !defined(__wasilibc_unmodified_upstream) && defined(__wasm__) && \
defined(_REENTRANT)
_Thread_local struct pthread __wasilibc_pthread_self;
#endif
static pthread_t __pthread_self_internal()
{
return __pthread_self();

View File

@@ -2,10 +2,12 @@
int __pthread_setcancelstate(int new, int *old)
{
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
if (new > 2U) return EINVAL;
struct pthread *self = __pthread_self();
if (old) *old = self->canceldisable;
self->canceldisable = new;
#endif
return 0;
}

Some files were not shown because too many files have changed in this diff Show More