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:
@@ -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>
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
|
||||
2
lib/libc/include/wasm-wasi-musl/ctype.h
vendored
2
lib/libc/include/wasm-wasi-musl/ctype.h
vendored
@@ -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
|
||||
|
||||
|
||||
2
lib/libc/include/wasm-wasi-musl/limits.h
vendored
2
lib/libc/include/wasm-wasi-musl/limits.h
vendored
@@ -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
|
||||
|
||||
4
lib/libc/include/wasm-wasi-musl/locale.h
vendored
4
lib/libc/include/wasm-wasi-musl/locale.h
vendored
@@ -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)
|
||||
|
||||
1
lib/libc/include/wasm-wasi-musl/netinet/in.h
vendored
1
lib/libc/include/wasm-wasi-musl/netinet/in.h
vendored
@@ -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)
|
||||
|
||||
11
lib/libc/include/wasm-wasi-musl/netinet/tcp.h
vendored
11
lib/libc/include/wasm-wasi-musl/netinet/tcp.h
vendored
@@ -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
|
||||
|
||||
8
lib/libc/include/wasm-wasi-musl/signal.h
vendored
8
lib/libc/include/wasm-wasi-musl/signal.h
vendored
@@ -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
|
||||
|
||||
@@ -7,4 +7,7 @@
|
||||
#define __STDC_IEC_559__ 1
|
||||
#endif
|
||||
|
||||
#define __STDC_UTF_16__ 1
|
||||
#define __STDC_UTF_32__ 1
|
||||
|
||||
#endif
|
||||
|
||||
4
lib/libc/include/wasm-wasi-musl/stdio.h
vendored
4
lib/libc/include/wasm-wasi-musl/stdio.h
vendored
@@ -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)
|
||||
|
||||
5
lib/libc/include/wasm-wasi-musl/stdlib.h
vendored
5
lib/libc/include/wasm-wasi-musl/stdlib.h
vendored
@@ -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
|
||||
|
||||
|
||||
4
lib/libc/include/wasm-wasi-musl/string.h
vendored
4
lib/libc/include/wasm-wasi-musl/string.h
vendored
@@ -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)
|
||||
|
||||
1
lib/libc/include/wasm-wasi-musl/sys/mman.h
vendored
1
lib/libc/include/wasm-wasi-musl/sys/mman.h
vendored
@@ -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)
|
||||
|
||||
5
lib/libc/include/wasm-wasi-musl/sys/socket.h
vendored
5
lib/libc/include/wasm-wasi-musl/sys/socket.h
vendored
@@ -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);
|
||||
|
||||
4
lib/libc/include/wasm-wasi-musl/sys/time.h
vendored
4
lib/libc/include/wasm-wasi-musl/sys/time.h
vendored
@@ -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 */
|
||||
|
||||
4
lib/libc/include/wasm-wasi-musl/time.h
vendored
4
lib/libc/include/wasm-wasi-musl/time.h
vendored
@@ -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)
|
||||
|
||||
8
lib/libc/include/wasm-wasi-musl/unistd.h
vendored
8
lib/libc/include/wasm-wasi-musl/unistd.h
vendored
@@ -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);
|
||||
|
||||
263
lib/libc/include/wasm-wasi-musl/wasi/api.h
vendored
263
lib/libc/include/wasm-wasi-musl/wasi/api.h
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -70,7 +70,7 @@ int __wasilibc_find_relpath_alloc(
|
||||
char **relative,
|
||||
size_t *relative_len,
|
||||
int can_realloc
|
||||
) __attribute__((weak));
|
||||
) __attribute__((__weak__));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
4
lib/libc/include/wasm-wasi-musl/wchar.h
vendored
4
lib/libc/include/wasm-wasi-musl/wchar.h
vendored
@@ -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)
|
||||
|
||||
1
lib/libc/wasi/LICENSE
vendored
1
lib/libc/wasi/LICENSE
vendored
@@ -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
|
||||
|
||||
|
||||
10
lib/libc/wasi/dlmalloc/include/unistd.h
vendored
10
lib/libc/wasi/dlmalloc/include/unistd.h
vendored
@@ -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__));
|
||||
98
lib/libc/wasi/dlmalloc/src/dlmalloc.c
vendored
98
lib/libc/wasi/dlmalloc/src/dlmalloc.c
vendored
@@ -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")));
|
||||
6352
lib/libc/wasi/dlmalloc/src/malloc.c
vendored
6352
lib/libc/wasi/dlmalloc/src/malloc.c
vendored
File diff suppressed because it is too large
Load Diff
1535
lib/libc/wasi/emmalloc/emmalloc.c
vendored
Normal file
1535
lib/libc/wasi/emmalloc/emmalloc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,3 +4,5 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include_next <stdlib.h>
|
||||
|
||||
int clearenv(void);
|
||||
|
||||
@@ -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")));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
34
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_dt.c
vendored
Normal file
34
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_dt.c
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
14
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_environ.c
vendored
Normal file
14
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_environ.c
vendored
Normal 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;
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <common/errno.h>
|
||||
#include <wasi/api.h>
|
||||
#include <wasi/libc.h>
|
||||
#include <errno.h>
|
||||
|
||||
35
lib/libc/wasi/libc-bottom-half/sources/chdir.c
vendored
35
lib/libc/wasi/libc-bottom-half/sources/chdir.c
vendored
@@ -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);
|
||||
|
||||
13
lib/libc/wasi/libc-bottom-half/sources/environ.c
vendored
13
lib/libc/wasi/libc-bottom-half/sources/environ.c
vendored
@@ -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();
|
||||
}
|
||||
|
||||
19
lib/libc/wasi/libc-bottom-half/sources/getcwd.c
vendored
19
lib/libc/wasi/libc-bottom-half/sources/getcwd.c
vendored
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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")));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user