diff --git a/lib/libc/include/wasm-wasi-musl/__macro_PAGESIZE.h b/lib/libc/include/wasm-wasi-musl/__macro_PAGESIZE.h index d89222050ca6..fbeff8d0020a 100644 --- a/lib/libc/include/wasm-wasi-musl/__macro_PAGESIZE.h +++ b/lib/libc/include/wasm-wasi-musl/__macro_PAGESIZE.h @@ -2,15 +2,23 @@ #define __wasilibc___macro_PAGESIZE_h /* - * 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. + * Without custom-page-sizes proposal, the page size in WebAssembly + * is fixed at 64 KiB. + * + * The LLVM versions with a support of custom-page-sizes proposal + * provides __wasm_first_page_end global to allow page-size-agnostic + * objects. * * 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. */ +#if __clang_major__ >= 22 +extern char __wasm_first_page_end; +#define PAGESIZE ((unsigned long)&__wasm_first_page_end) +#else #define PAGESIZE (0x10000) +#endif #endif diff --git a/lib/libc/include/wasm-wasi-musl/__wasi_snapshot.h b/lib/libc/include/wasm-wasi-musl/__wasi_snapshot.h index e69de29bb2d1..9a1007805977 100644 --- a/lib/libc/include/wasm-wasi-musl/__wasi_snapshot.h +++ b/lib/libc/include/wasm-wasi-musl/__wasi_snapshot.h @@ -0,0 +1,5 @@ +/* This file is (practically) empty by default. The Makefile will replace it + with a non-empty version that defines `__wasilibc_use_wasip2` if targeting + `wasm32-wasip2`. + */ + diff --git a/lib/libc/include/wasm-wasi-musl/arpa/nameser.h b/lib/libc/include/wasm-wasi-musl/arpa/nameser.h deleted file mode 100644 index 581925a43367..000000000000 --- a/lib/libc/include/wasm-wasi-musl/arpa/nameser.h +++ /dev/null @@ -1,455 +0,0 @@ -#ifndef _ARPA_NAMESER_H -#define _ARPA_NAMESER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define __NAMESER 19991006 -#define NS_PACKETSZ 512 -#define NS_MAXDNAME 1025 -#define NS_MAXMSG 65535 -#define NS_MAXCDNAME 255 -#define NS_MAXLABEL 63 -#define NS_HFIXEDSZ 12 -#define NS_QFIXEDSZ 4 -#define NS_RRFIXEDSZ 10 -#define NS_INT32SZ 4 -#define NS_INT16SZ 2 -#define NS_INT8SZ 1 -#define NS_INADDRSZ 4 -#define NS_IN6ADDRSZ 16 -#define NS_CMPRSFLGS 0xc0 -#define NS_DEFAULTPORT 53 - -typedef enum __ns_sect { - ns_s_qd = 0, - ns_s_zn = 0, - ns_s_an = 1, - ns_s_pr = 1, - ns_s_ns = 2, - ns_s_ud = 2, - ns_s_ar = 3, - ns_s_max = 4 -} ns_sect; - -typedef struct __ns_msg { - const unsigned char *_msg, *_eom; - uint16_t _id, _flags, _counts[ns_s_max]; - const unsigned char *_sections[ns_s_max]; - ns_sect _sect; - int _rrnum; - const unsigned char *_msg_ptr; -} ns_msg; - -struct _ns_flagdata { int mask, shift; }; -extern const struct _ns_flagdata _ns_flagdata[]; - -#define ns_msg_id(handle) ((handle)._id + 0) -#define ns_msg_base(handle) ((handle)._msg + 0) -#define ns_msg_end(handle) ((handle)._eom + 0) -#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) -#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) -#define ns_msg_getflag(handle, flag) \ - (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) - -typedef struct __ns_rr { - char name[NS_MAXDNAME]; - uint16_t type; - uint16_t rr_class; - uint32_t ttl; - uint16_t rdlength; - const unsigned char *rdata; -} ns_rr; - -#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") -#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) -#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) -#define ns_rr_ttl(rr) ((rr).ttl + 0) -#define ns_rr_rdlen(rr) ((rr).rdlength + 0) -#define ns_rr_rdata(rr) ((rr).rdata + 0) - -typedef enum __ns_flag { - ns_f_qr, - ns_f_opcode, - ns_f_aa, - ns_f_tc, - ns_f_rd, - ns_f_ra, - ns_f_z, - ns_f_ad, - ns_f_cd, - ns_f_rcode, - ns_f_max -} ns_flag; - -typedef enum __ns_opcode { - ns_o_query = 0, - ns_o_iquery = 1, - ns_o_status = 2, - ns_o_notify = 4, - ns_o_update = 5, - ns_o_max = 6 -} ns_opcode; - -typedef enum __ns_rcode { - ns_r_noerror = 0, - ns_r_formerr = 1, - ns_r_servfail = 2, - ns_r_nxdomain = 3, - ns_r_notimpl = 4, - ns_r_refused = 5, - ns_r_yxdomain = 6, - ns_r_yxrrset = 7, - ns_r_nxrrset = 8, - ns_r_notauth = 9, - ns_r_notzone = 10, - ns_r_max = 11, - ns_r_badvers = 16, - ns_r_badsig = 16, - ns_r_badkey = 17, - ns_r_badtime = 18 -} ns_rcode; - -typedef enum __ns_update_operation { - ns_uop_delete = 0, - ns_uop_add = 1, - ns_uop_max = 2 -} ns_update_operation; - -struct ns_tsig_key { - char name[NS_MAXDNAME], alg[NS_MAXDNAME]; - unsigned char *data; - int len; -}; -typedef struct ns_tsig_key ns_tsig_key; - -struct ns_tcp_tsig_state { - int counter; - struct dst_key *key; - void *ctx; - unsigned char sig[NS_PACKETSZ]; - int siglen; -}; -typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; - -#define NS_TSIG_FUDGE 300 -#define NS_TSIG_TCP_COUNT 100 -#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" - -#define NS_TSIG_ERROR_NO_TSIG -10 -#define NS_TSIG_ERROR_NO_SPACE -11 -#define NS_TSIG_ERROR_FORMERR -12 - -typedef enum __ns_type { - ns_t_invalid = 0, - ns_t_a = 1, - ns_t_ns = 2, - ns_t_md = 3, - ns_t_mf = 4, - ns_t_cname = 5, - ns_t_soa = 6, - ns_t_mb = 7, - ns_t_mg = 8, - ns_t_mr = 9, - ns_t_null = 10, - ns_t_wks = 11, - ns_t_ptr = 12, - ns_t_hinfo = 13, - ns_t_minfo = 14, - ns_t_mx = 15, - ns_t_txt = 16, - ns_t_rp = 17, - ns_t_afsdb = 18, - ns_t_x25 = 19, - ns_t_isdn = 20, - ns_t_rt = 21, - ns_t_nsap = 22, - ns_t_nsap_ptr = 23, - ns_t_sig = 24, - ns_t_key = 25, - ns_t_px = 26, - ns_t_gpos = 27, - ns_t_aaaa = 28, - ns_t_loc = 29, - ns_t_nxt = 30, - ns_t_eid = 31, - ns_t_nimloc = 32, - ns_t_srv = 33, - ns_t_atma = 34, - ns_t_naptr = 35, - ns_t_kx = 36, - ns_t_cert = 37, - ns_t_a6 = 38, - ns_t_dname = 39, - ns_t_sink = 40, - ns_t_opt = 41, - ns_t_apl = 42, - ns_t_tkey = 249, - ns_t_tsig = 250, - ns_t_ixfr = 251, - ns_t_axfr = 252, - ns_t_mailb = 253, - ns_t_maila = 254, - ns_t_any = 255, - ns_t_zxfr = 256, - ns_t_max = 65536 -} ns_type; - -#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ - (t) == ns_t_mailb || (t) == ns_t_maila) -#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) -#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) -#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) -#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ - (t) == ns_t_zxfr) - -typedef enum __ns_class { - ns_c_invalid = 0, - ns_c_in = 1, - ns_c_2 = 2, - ns_c_chaos = 3, - ns_c_hs = 4, - ns_c_none = 254, - ns_c_any = 255, - ns_c_max = 65536 -} ns_class; - -typedef enum __ns_key_types { - ns_kt_rsa = 1, - ns_kt_dh = 2, - ns_kt_dsa = 3, - ns_kt_private = 254 -} ns_key_types; - -typedef enum __ns_cert_types { - cert_t_pkix = 1, - cert_t_spki = 2, - cert_t_pgp = 3, - cert_t_url = 253, - cert_t_oid = 254 -} ns_cert_types; - -#define NS_KEY_TYPEMASK 0xC000 -#define NS_KEY_TYPE_AUTH_CONF 0x0000 -#define NS_KEY_TYPE_CONF_ONLY 0x8000 -#define NS_KEY_TYPE_AUTH_ONLY 0x4000 -#define NS_KEY_TYPE_NO_KEY 0xC000 -#define NS_KEY_NO_AUTH 0x8000 -#define NS_KEY_NO_CONF 0x4000 -#define NS_KEY_RESERVED2 0x2000 -#define NS_KEY_EXTENDED_FLAGS 0x1000 -#define NS_KEY_RESERVED4 0x0800 -#define NS_KEY_RESERVED5 0x0400 -#define NS_KEY_NAME_TYPE 0x0300 -#define NS_KEY_NAME_USER 0x0000 -#define NS_KEY_NAME_ENTITY 0x0200 -#define NS_KEY_NAME_ZONE 0x0100 -#define NS_KEY_NAME_RESERVED 0x0300 -#define NS_KEY_RESERVED8 0x0080 -#define NS_KEY_RESERVED9 0x0040 -#define NS_KEY_RESERVED10 0x0020 -#define NS_KEY_RESERVED11 0x0010 -#define NS_KEY_SIGNATORYMASK 0x000F -#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ - NS_KEY_RESERVED4 | \ - NS_KEY_RESERVED5 | \ - NS_KEY_RESERVED8 | \ - NS_KEY_RESERVED9 | \ - NS_KEY_RESERVED10 | \ - NS_KEY_RESERVED11 ) -#define NS_KEY_RESERVED_BITMASK2 0xFFFF -#define NS_ALG_MD5RSA 1 -#define NS_ALG_DH 2 -#define NS_ALG_DSA 3 -#define NS_ALG_DSS NS_ALG_DSA -#define NS_ALG_EXPIRE_ONLY 253 -#define NS_ALG_PRIVATE_OID 254 - -#define NS_KEY_PROT_TLS 1 -#define NS_KEY_PROT_EMAIL 2 -#define NS_KEY_PROT_DNSSEC 3 -#define NS_KEY_PROT_IPSEC 4 -#define NS_KEY_PROT_ANY 255 - -#define NS_MD5RSA_MIN_BITS 512 -#define NS_MD5RSA_MAX_BITS 4096 -#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) -#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) -#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) -#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) - -#define NS_DSA_SIG_SIZE 41 -#define NS_DSA_MIN_SIZE 213 -#define NS_DSA_MAX_BYTES 405 - -#define NS_SIG_TYPE 0 -#define NS_SIG_ALG 2 -#define NS_SIG_LABELS 3 -#define NS_SIG_OTTL 4 -#define NS_SIG_EXPIR 8 -#define NS_SIG_SIGNED 12 -#define NS_SIG_FOOT 16 -#define NS_SIG_SIGNER 18 -#define NS_NXT_BITS 8 -#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_MAX 127 - -#define NS_OPT_DNSSEC_OK 0x8000U -#define NS_OPT_NSID 3 - -#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp)+=2)-2)) -#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp)+=4)-4)) -#define NS_PUT16(s, cp) ns_put16((s), ((cp)+=2)-2) -#define NS_PUT32(l, cp) ns_put32((l), ((cp)+=4)-4) - -unsigned ns_get16(const unsigned char *); -unsigned long ns_get32(const unsigned char *); -void ns_put16(unsigned, unsigned char *); -void ns_put32(unsigned long, unsigned char *); - -int ns_initparse(const unsigned char *, int, ns_msg *); -int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); -int ns_skiprr(const unsigned char *, const unsigned char *, ns_sect, int); -int ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); - - -#define __BIND 19950621 - -typedef struct { - unsigned id :16; -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned qr: 1; - unsigned opcode: 4; - unsigned aa: 1; - unsigned tc: 1; - unsigned rd: 1; - unsigned ra: 1; - unsigned unused :1; - unsigned ad: 1; - unsigned cd: 1; - unsigned rcode :4; -#else - unsigned rd :1; - unsigned tc :1; - unsigned aa :1; - unsigned opcode :4; - unsigned qr :1; - unsigned rcode :4; - unsigned cd: 1; - unsigned ad: 1; - unsigned unused :1; - unsigned ra :1; -#endif - unsigned qdcount :16; - unsigned ancount :16; - unsigned nscount :16; - unsigned arcount :16; -} HEADER; - -#define PACKETSZ NS_PACKETSZ -#define MAXDNAME NS_MAXDNAME -#define MAXCDNAME NS_MAXCDNAME -#define MAXLABEL NS_MAXLABEL -#define HFIXEDSZ NS_HFIXEDSZ -#define QFIXEDSZ NS_QFIXEDSZ -#define RRFIXEDSZ NS_RRFIXEDSZ -#define INT32SZ NS_INT32SZ -#define INT16SZ NS_INT16SZ -#define INT8SZ NS_INT8SZ -#define INADDRSZ NS_INADDRSZ -#define IN6ADDRSZ NS_IN6ADDRSZ -#define INDIR_MASK NS_CMPRSFLGS -#define NAMESERVER_PORT NS_DEFAULTPORT - -#define S_ZONE ns_s_zn -#define S_PREREQ ns_s_pr -#define S_UPDATE ns_s_ud -#define S_ADDT ns_s_ar - -#define QUERY ns_o_query -#define IQUERY ns_o_iquery -#define STATUS ns_o_status -#define NS_NOTIFY_OP ns_o_notify -#define NS_UPDATE_OP ns_o_update - -#define NOERROR ns_r_noerror -#define FORMERR ns_r_formerr -#define SERVFAIL ns_r_servfail -#define NXDOMAIN ns_r_nxdomain -#define NOTIMP ns_r_notimpl -#define REFUSED ns_r_refused -#define YXDOMAIN ns_r_yxdomain -#define YXRRSET ns_r_yxrrset -#define NXRRSET ns_r_nxrrset -#define NOTAUTH ns_r_notauth -#define NOTZONE ns_r_notzone - -#define DELETE ns_uop_delete -#define ADD ns_uop_add - -#define T_A ns_t_a -#define T_NS ns_t_ns -#define T_MD ns_t_md -#define T_MF ns_t_mf -#define T_CNAME ns_t_cname -#define T_SOA ns_t_soa -#define T_MB ns_t_mb -#define T_MG ns_t_mg -#define T_MR ns_t_mr -#define T_NULL ns_t_null -#define T_WKS ns_t_wks -#define T_PTR ns_t_ptr -#define T_HINFO ns_t_hinfo -#define T_MINFO ns_t_minfo -#define T_MX ns_t_mx -#define T_TXT ns_t_txt -#define T_RP ns_t_rp -#define T_AFSDB ns_t_afsdb -#define T_X25 ns_t_x25 -#define T_ISDN ns_t_isdn -#define T_RT ns_t_rt -#define T_NSAP ns_t_nsap -#define T_NSAP_PTR ns_t_nsap_ptr -#define T_SIG ns_t_sig -#define T_KEY ns_t_key -#define T_PX ns_t_px -#define T_GPOS ns_t_gpos -#define T_AAAA ns_t_aaaa -#define T_LOC ns_t_loc -#define T_NXT ns_t_nxt -#define T_EID ns_t_eid -#define T_NIMLOC ns_t_nimloc -#define T_SRV ns_t_srv -#define T_ATMA ns_t_atma -#define T_NAPTR ns_t_naptr -#define T_A6 ns_t_a6 -#define T_DNAME ns_t_dname -#define T_TSIG ns_t_tsig -#define T_IXFR ns_t_ixfr -#define T_AXFR ns_t_axfr -#define T_MAILB ns_t_mailb -#define T_MAILA ns_t_maila -#define T_ANY ns_t_any - -#define C_IN ns_c_in -#define C_CHAOS ns_c_chaos -#define C_HS ns_c_hs -#define C_NONE ns_c_none -#define C_ANY ns_c_any - -#define GETSHORT NS_GET16 -#define GETLONG NS_GET32 -#define PUTSHORT NS_PUT16 -#define PUTLONG NS_PUT32 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libc/include/wasm-wasi-musl/fcntl.h b/lib/libc/include/wasm-wasi-musl/fcntl.h index 15bef28854b3..eef21db1dcbe 100644 --- a/lib/libc/include/wasm-wasi-musl/fcntl.h +++ b/lib/libc/include/wasm-wasi-musl/fcntl.h @@ -203,7 +203,6 @@ struct f_owner_ex { #endif #ifdef __wasilibc_unmodified_upstream /* WASI has no fallocate */ int fallocate(int, int, off_t, off_t); -#define fallocate64 fallocate #endif #ifdef __wasilibc_unmodified_upstream /* WASI has no name_to_handle_at */ int name_to_handle_at(int, const char *, struct file_handle *, int *, int); @@ -237,6 +236,11 @@ ssize_t tee(int, int, size_t, unsigned); #define posix_fadvise64 posix_fadvise #define posix_fallocate64 posix_fallocate #define off64_t off_t +#ifdef __wasilibc_unmodified_upstream /* WASI has no fallocate */ +#if defined(_GNU_SOURCE) +#define fallocate64 fallocate +#endif +#endif #endif #ifdef __cplusplus diff --git a/lib/libc/include/wasm-wasi-musl/fts.h b/lib/libc/include/wasm-wasi-musl/fts.h new file mode 100644 index 000000000000..aef9e0038b9c --- /dev/null +++ b/lib/libc/include/wasm-wasi-musl/fts.h @@ -0,0 +1,155 @@ +/* $NetBSD: fts.h,v 1.19 2009/08/16 19:33:38 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + */ + +#ifndef _FTS_H_ +#define _FTS_H_ + +#include +#include + +#ifndef __fts_stat_t +#define __fts_stat_t struct stat +#endif +#ifndef __fts_nlink_t +#define __fts_nlink_t nlink_t +#endif +#ifndef __fts_ino_t +#define __fts_ino_t ino_t +#endif +#ifndef __fts_length_t +#define __fts_length_t unsigned int +#endif +#ifndef __fts_number_t +#define __fts_number_t int64_t +#endif +#ifndef __fts_dev_t +#define __fts_dev_t dev_t +#endif +#ifndef __fts_level_t +#define __fts_level_t int +#endif + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + dev_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + unsigned int fts_pathlen; /* sizeof(path) */ + unsigned int fts_nitems; /* elements in the sort array */ + int (*fts_compar) /* compare function */ + (const struct _ftsent **, const struct _ftsent **); + +#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ +#define FTS_LOGICAL 0x002 /* logical walk */ +#define FTS_NOCHDIR 0x004 /* don't change directories */ +#define FTS_NOSTAT 0x008 /* don't get stat info */ +#define FTS_PHYSICAL 0x010 /* physical walk */ +#define FTS_SEEDOT 0x020 /* return dot and dot-dot */ +#define FTS_XDEV 0x040 /* don't cross devices */ +#define FTS_WHITEOUT 0x080 /* return whiteout information */ +#define FTS_OPTIONMASK 0x0ff /* valid user option mask */ + +#define FTS_NAMEONLY 0x100 /* (private) child names only */ +#define FTS_STOP 0x200 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + __fts_number_t fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + __fts_length_t fts_pathlen; /* strlen(fts_path) */ + __fts_length_t fts_namelen; /* strlen(fts_name) */ + + __fts_ino_t fts_ino; /* inode */ + __fts_dev_t fts_dev; /* device */ + __fts_nlink_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 + __fts_level_t fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ +#define FTS_SLNONE 13 /* symbolic link without target */ +#define FTS_W 14 /* whiteout object */ + unsigned short fts_info; /* user flags for FTSENT structure */ + +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ +#define FTS_ISW 0x04 /* this is a whiteout object */ + unsigned short fts_flags; /* private flags for FTSENT structure */ + +#define FTS_AGAIN 1 /* read node again */ +#define FTS_FOLLOW 2 /* follow symbolic link */ +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + unsigned short fts_instr; /* fts_set() instructions */ + + __fts_stat_t *fts_statp; /* stat(2) information */ + char fts_name[1]; /* file name */ +} FTSENT; + +#ifdef __cplusplus +extern "C" { +#endif +FTSENT *fts_children(FTS *, int); +int fts_close(FTS *); +FTS *fts_open(char * const *, int, + int (*)(const FTSENT **, const FTSENT **)); +FTSENT *fts_read(FTS *); +int fts_set(FTS *, FTSENT *, int); +#ifdef __cplusplus +} +#endif + + +#endif /* !_FTS_H_ */ diff --git a/lib/libc/include/wasm-wasi-musl/limits.h b/lib/libc/include/wasm-wasi-musl/limits.h index 2fc0d2a38afa..c160568cdece 100644 --- a/lib/libc/include/wasm-wasi-musl/limits.h +++ b/lib/libc/include/wasm-wasi-musl/limits.h @@ -65,11 +65,9 @@ /* Implementation choices... */ -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #define PTHREAD_KEYS_MAX 128 #define PTHREAD_STACK_MIN 2048 #define PTHREAD_DESTRUCTOR_ITERATIONS 4 -#endif #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #define SEM_VALUE_MAX 0x7fffffff #define SEM_NSEMS_MAX 256 diff --git a/lib/libc/include/wasm-wasi-musl/poll.h b/lib/libc/include/wasm-wasi-musl/poll.h index cdbd29a2102e..00e2537ae082 100644 --- a/lib/libc/include/wasm-wasi-musl/poll.h +++ b/lib/libc/include/wasm-wasi-musl/poll.h @@ -48,7 +48,7 @@ struct pollfd { int poll (struct pollfd *, nfds_t, int); -#ifdef _GNU_SOURCE +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) #define __NEED_time_t #define __NEED_struct_timespec #define __NEED_sigset_t @@ -57,7 +57,7 @@ int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *); #endif #if _REDIR_TIME64 -#ifdef _GNU_SOURCE +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) __REDIR(ppoll, __ppoll_time64); #endif #endif diff --git a/lib/libc/include/wasm-wasi-musl/pthread.h b/lib/libc/include/wasm-wasi-musl/pthread.h new file mode 100644 index 000000000000..111c1fbf8c1c --- /dev/null +++ b/lib/libc/include/wasm-wasi-musl/pthread.h @@ -0,0 +1,267 @@ +#ifndef _PTHREAD_H +#define _PTHREAD_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_time_t +#define __NEED_clockid_t +#define __NEED_struct_timespec +#define __NEED_sigset_t +#define __NEED_pthread_t +#define __NEED_pthread_attr_t +#define __NEED_pthread_mutexattr_t +#define __NEED_pthread_condattr_t +#define __NEED_pthread_rwlockattr_t +#define __NEED_pthread_barrierattr_t +#define __NEED_pthread_mutex_t +#define __NEED_pthread_cond_t +#define __NEED_pthread_rwlock_t +#define __NEED_pthread_barrier_t +#define __NEED_pthread_spinlock_t +#define __NEED_pthread_key_t +#define __NEED_pthread_once_t +#define __NEED_size_t + +#include + +#include +#include + +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_DEFAULT 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_ERRORCHECK 2 + +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + +#define PTHREAD_PRIO_NONE 0 +#define PTHREAD_PRIO_INHERIT 1 +#define PTHREAD_PRIO_PROTECT 2 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + + +#define PTHREAD_MUTEX_INITIALIZER {{{0}}} +#define PTHREAD_RWLOCK_INITIALIZER {{{0}}} +#define PTHREAD_COND_INITIALIZER {{{0}}} +#define PTHREAD_ONCE_INIT 0 + + +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +#define PTHREAD_CANCELED ((void *)-1) + + +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) + + +#define PTHREAD_NULL ((pthread_t)0) + + +#ifdef __wasilibc_unmodified_upstream +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); +int pthread_detach(pthread_t); +_Noreturn void pthread_exit(void *); +int pthread_join(pthread_t, void **); +#else +#if defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); +int pthread_detach(pthread_t); +int pthread_join(pthread_t, void **); +#else +#define pthread_create(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#define pthread_detach(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#define pthread_join(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#endif +#endif + +#ifdef __GNUC__ +__attribute__((const)) +#endif +pthread_t pthread_self(void); + +int pthread_equal(pthread_t, pthread_t); +#ifndef __cplusplus +#define pthread_equal(x,y) ((x)==(y)) +#endif + +int pthread_setcancelstate(int, int *); +int pthread_setcanceltype(int, int *); +void pthread_testcancel(void); +#ifdef __wasilibc_unmodified_upstream /* WASI has no cancellation support. */ +int pthread_cancel(pthread_t); +#endif + +#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)); + +int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); +int pthread_mutex_lock(pthread_mutex_t *); +int pthread_mutex_unlock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); +int pthread_mutex_timedlock(pthread_mutex_t *__restrict, const struct timespec *__restrict); +int pthread_mutex_destroy(pthread_mutex_t *); +int pthread_mutex_consistent(pthread_mutex_t *); + +int pthread_mutex_getprioceiling(const pthread_mutex_t *__restrict, int *__restrict); +int pthread_mutex_setprioceiling(pthread_mutex_t *__restrict, int, int *__restrict); + +int pthread_cond_init(pthread_cond_t *__restrict, const pthread_condattr_t *__restrict); +int pthread_cond_destroy(pthread_cond_t *); +int pthread_cond_wait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict); +int pthread_cond_timedwait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict, const struct timespec *__restrict); +int pthread_cond_broadcast(pthread_cond_t *); +int pthread_cond_signal(pthread_cond_t *); + +int pthread_rwlock_init(pthread_rwlock_t *__restrict, const pthread_rwlockattr_t *__restrict); +int pthread_rwlock_destroy(pthread_rwlock_t *); +int pthread_rwlock_rdlock(pthread_rwlock_t *); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *); +int pthread_rwlock_timedrdlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +int pthread_rwlock_wrlock(pthread_rwlock_t *); +int pthread_rwlock_trywrlock(pthread_rwlock_t *); +int pthread_rwlock_timedwrlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +int pthread_rwlock_unlock(pthread_rwlock_t *); + +int pthread_spin_init(pthread_spinlock_t *, int); +int pthread_spin_destroy(pthread_spinlock_t *); +int pthread_spin_lock(pthread_spinlock_t *); +int pthread_spin_trylock(pthread_spinlock_t *); +int pthread_spin_unlock(pthread_spinlock_t *); + +int pthread_barrier_init(pthread_barrier_t *__restrict, const pthread_barrierattr_t *__restrict, unsigned); +int pthread_barrier_destroy(pthread_barrier_t *); +int pthread_barrier_wait(pthread_barrier_t *); + +int pthread_key_create(pthread_key_t *, void (*)(void *)); +int pthread_key_delete(pthread_key_t); +void *pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void *); + +int pthread_attr_init(pthread_attr_t *); +int pthread_attr_destroy(pthread_attr_t *); + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setguardsize(pthread_attr_t *, size_t); +int pthread_attr_getstacksize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setstacksize(pthread_attr_t *, size_t); +int pthread_attr_getdetachstate(const pthread_attr_t *, int *); +int pthread_attr_setdetachstate(pthread_attr_t *, int); +int pthread_attr_getstack(const pthread_attr_t *__restrict, void **__restrict, size_t *__restrict); +int pthread_attr_setstack(pthread_attr_t *, void *, size_t); +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); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_init(pthread_mutexattr_t *); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); +int pthread_mutexattr_settype(pthread_mutexattr_t *, int); + +int pthread_condattr_init(pthread_condattr_t *); +int pthread_condattr_destroy(pthread_condattr_t *); +int pthread_condattr_setclock(pthread_condattr_t *, clockid_t); +int pthread_condattr_setpshared(pthread_condattr_t *, int); +int pthread_condattr_getclock(const pthread_condattr_t *__restrict, clockid_t *__restrict); +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict, int *__restrict); + +int pthread_rwlockattr_init(pthread_rwlockattr_t *); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict, int *__restrict); + +int pthread_barrierattr_destroy(pthread_barrierattr_t *); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict, int *__restrict); +int pthread_barrierattr_init(pthread_barrierattr_t *); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); + +int pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); + +int pthread_getconcurrency(void); +int pthread_setconcurrency(int); + +int pthread_getcpuclockid(pthread_t, clockid_t *); + +struct __ptcb { + void (*__f)(void *); + void *__x; + struct __ptcb *__next; +}; + +void _pthread_cleanup_push(struct __ptcb *, void (*)(void *), void *); +void _pthread_cleanup_pop(struct __ptcb *, int); + +#define pthread_cleanup_push(f, x) do { struct __ptcb __cb; _pthread_cleanup_push(&__cb, f, x); +#define pthread_cleanup_pop(r) _pthread_cleanup_pop(&__cb, (r)); } while(0) + +#ifdef _GNU_SOURCE +struct cpu_set_t; +int pthread_getaffinity_np(pthread_t, size_t, struct cpu_set_t *); +int pthread_setaffinity_np(pthread_t, size_t, const struct cpu_set_t *); +int pthread_getattr_np(pthread_t, pthread_attr_t *); +int pthread_setname_np(pthread_t, const char *); +int pthread_getname_np(pthread_t, char *, size_t); +int pthread_getattr_default_np(pthread_attr_t *); +int pthread_setattr_default_np(const pthread_attr_t *); +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) +int pthread_tryjoin_np(pthread_t, void **); +int pthread_timedjoin_np(pthread_t, void **, const struct timespec *); +#else +#define pthread_tryjoin_np(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#define pthread_timedjoin_np(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#endif +#endif + +#if _REDIR_TIME64 +__REDIR(pthread_mutex_timedlock, __pthread_mutex_timedlock_time64); +__REDIR(pthread_cond_timedwait, __pthread_cond_timedwait_time64); +__REDIR(pthread_rwlock_timedrdlock, __pthread_rwlock_timedrdlock_time64); +__REDIR(pthread_rwlock_timedwrlock, __pthread_rwlock_timedwrlock_time64); +#ifdef _GNU_SOURCE +__REDIR(pthread_timedjoin_np, __pthread_timedjoin_np_time64); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/libc/include/wasm-wasi-musl/sched.h b/lib/libc/include/wasm-wasi-musl/sched.h index a3a7f569d9d8..407d604af3be 100644 --- a/lib/libc/include/wasm-wasi-musl/sched.h +++ b/lib/libc/include/wasm-wasi-musl/sched.h @@ -16,7 +16,6 @@ extern "C" { #include -#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */ struct sched_param { int sched_priority; int __reserved1; @@ -31,6 +30,7 @@ struct sched_param { int __reserved3; }; +#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */ int sched_get_priority_max(int); int sched_get_priority_min(int); int sched_getparam(pid_t, struct sched_param *); @@ -127,7 +127,7 @@ __CPU_op_func_S(XOR, ^) #define CPU_ALLOC(n) ((cpu_set_t *)calloc(1,CPU_ALLOC_SIZE(n))) #define CPU_FREE(set) free(set) -#define CPU_SETSIZE 128 +#define CPU_SETSIZE 1024 #define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set) #define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set) diff --git a/lib/libc/include/wasm-wasi-musl/stdc-predef.h b/lib/libc/include/wasm-wasi-musl/stdc-predef.h deleted file mode 100644 index af1a27998f90..000000000000 --- a/lib/libc/include/wasm-wasi-musl/stdc-predef.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _STDC_PREDEF_H -#define _STDC_PREDEF_H - -#define __STDC_ISO_10646__ 201206L - -#if !defined(__GCC_IEC_559) || __GCC_IEC_559 > 0 -#define __STDC_IEC_559__ 1 -#endif - -#define __STDC_UTF_16__ 1 -#define __STDC_UTF_32__ 1 - -#endif diff --git a/lib/libc/include/wasm-wasi-musl/stdlib.h b/lib/libc/include/wasm-wasi-musl/stdlib.h index 553e9aeabff7..c5b6cd2d980a 100644 --- a/lib/libc/include/wasm-wasi-musl/stdlib.h +++ b/lib/libc/include/wasm-wasi-musl/stdlib.h @@ -108,7 +108,7 @@ size_t __ctype_get_mb_cur_max(void); #define WTERMSIG(s) ((s) & 0x7f) #define WSTOPSIG(s) WEXITSTATUS(s) #define WIFEXITED(s) (!WTERMSIG(s)) -#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00) +#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00) #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu) #endif @@ -190,7 +190,7 @@ long double strtold_l(const char *__restrict, char **__restrict, struct __locale #endif #ifdef __wasilibc_unmodified_upstream /* WASI has no temp directories */ -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define mkstemp64 mkstemp #define mkostemp64 mkostemp #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) diff --git a/lib/libc/include/wasm-wasi-musl/string.h b/lib/libc/include/wasm-wasi-musl/string.h index dc47b7aee028..7b3c3b9415f2 100644 --- a/lib/libc/include/wasm-wasi-musl/string.h +++ b/lib/libc/include/wasm-wasi-musl/string.h @@ -92,6 +92,7 @@ char *strsignal(int); char *strerror_l (int, locale_t); int strcoll_l (const char *, const char *, locale_t); size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t); +void *memmem(const void *, size_t, const void *, size_t); #endif #if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ @@ -111,14 +112,8 @@ void explicit_bzero (void *, size_t); int strverscmp (const char *, const char *); char *strchrnul(const char *, int); char *strcasestr(const char *, const char *); -void *memmem(const void *, size_t, const void *, size_t); void *memrchr(const void *, int, size_t); void *mempcpy(void *, const void *, size_t); -#ifdef __wasilibc_unmodified_upstream /* avoid unprototyped decls; use */ -#ifndef __cplusplus -char *basename(); -#endif -#endif #endif #ifdef __cplusplus diff --git a/lib/libc/include/wasm-wasi-musl/strings.h b/lib/libc/include/wasm-wasi-musl/strings.h deleted file mode 100644 index db0960b4eb87..000000000000 --- a/lib/libc/include/wasm-wasi-musl/strings.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _STRINGS_H -#define _STRINGS_H - -#ifdef __cplusplus -extern "C" { -#endif - - -#define __NEED_size_t -#define __NEED_locale_t -#include - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_POSIX_SOURCE) \ - || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE+0 < 200809L) \ - || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 < 700) -int bcmp (const void *, const void *, size_t); -void bcopy (const void *, void *, size_t); -void bzero (void *, size_t); -char *index (const char *, int); -char *rindex (const char *, int); -#endif - -#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) -int ffs (int); -int ffsl (long); -int ffsll (long long); -#endif - -int strcasecmp (const char *, const char *); -int strncasecmp (const char *, const char *, size_t); - -int strcasecmp_l (const char *, const char *, locale_t); -int strncasecmp_l (const char *, const char *, size_t, locale_t); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libc/include/wasm-wasi-musl/sys/stat.h b/lib/libc/include/wasm-wasi-musl/sys/stat.h index c0090f7509fb..01d30ddaf3d2 100644 --- a/lib/libc/include/wasm-wasi-musl/sys/stat.h +++ b/lib/libc/include/wasm-wasi-musl/sys/stat.h @@ -18,6 +18,13 @@ extern "C" { #define __NEED_blkcnt_t #define __NEED_struct_timespec +#ifdef _GNU_SOURCE +#define __NEED_int64_t +#define __NEED_uint64_t +#define __NEED_uint32_t +#define __NEED_uint16_t +#endif + #include #include @@ -112,6 +119,56 @@ int lchmod(const char *, mode_t); #define S_IEXEC S_IXUSR #endif +#ifdef __wasilibc_unmodified_upstream /* WASI has no statx */ +#if defined(_GNU_SOURCE) +#define STATX_TYPE 1U +#define STATX_MODE 2U +#define STATX_NLINK 4U +#define STATX_UID 8U +#define STATX_GID 0x10U +#define STATX_ATIME 0x20U +#define STATX_MTIME 0x40U +#define STATX_CTIME 0x80U +#define STATX_INO 0x100U +#define STATX_SIZE 0x200U +#define STATX_BLOCKS 0x400U +#define STATX_BASIC_STATS 0x7ffU +#define STATX_BTIME 0x800U +#define STATX_ALL 0xfffU + +struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec, __pad; +}; + +struct statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __pad0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t __pad1[14]; +}; + +int statx(int, const char *__restrict, int, unsigned, struct statx *__restrict); +#endif +#endif + #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) #define stat64 stat #define fstat64 fstat diff --git a/lib/libc/include/wasm-wasi-musl/sys/statvfs.h b/lib/libc/include/wasm-wasi-musl/sys/statvfs.h index 793490b6dc8c..6cf35c5941b7 100644 --- a/lib/libc/include/wasm-wasi-musl/sys/statvfs.h +++ b/lib/libc/include/wasm-wasi-musl/sys/statvfs.h @@ -23,7 +23,8 @@ struct statvfs { unsigned long f_fsid; #endif unsigned long f_flag, f_namemax; - int __reserved[6]; + unsigned int f_type; + int __reserved[5]; }; int statvfs (const char *__restrict, struct statvfs *__restrict); diff --git a/lib/libc/include/wasm-wasi-musl/sys/uio.h b/lib/libc/include/wasm-wasi-musl/sys/uio.h index 00f73a2f0525..f102d5a56e42 100644 --- a/lib/libc/include/wasm-wasi-musl/sys/uio.h +++ b/lib/libc/include/wasm-wasi-musl/sys/uio.h @@ -36,9 +36,18 @@ ssize_t pwritev (int, const struct iovec *, int, off_t); #endif #endif +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have these Linux-specific functions #ifdef _GNU_SOURCE ssize_t process_vm_writev(pid_t, const struct iovec *, unsigned long, const struct iovec *, unsigned long, unsigned long); ssize_t process_vm_readv(pid_t, const struct iovec *, unsigned long, const struct iovec *, unsigned long, unsigned long); +ssize_t preadv2 (int, const struct iovec *, int, off_t, int); +ssize_t pwritev2 (int, const struct iovec *, int, off_t, int); +#define RWF_HIPRI 0x00000001 +#define RWF_DSYNC 0x00000002 +#define RWF_SYNC 0x00000004 +#define RWF_NOWAIT 0x00000008 +#define RWF_APPEND 0x00000010 +#endif #endif #ifdef __cplusplus diff --git a/lib/libc/include/wasm-wasi-musl/unistd.h b/lib/libc/include/wasm-wasi-musl/unistd.h index 0be83e368c4c..c3158e6e6492 100644 --- a/lib/libc/include/wasm-wasi-musl/unistd.h +++ b/lib/libc/include/wasm-wasi-musl/unistd.h @@ -336,15 +336,21 @@ pid_t gettid(void); #endif #define _POSIX_VDISABLE 0 -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) #define _POSIX_THREADS _POSIX_VERSION -#endif #define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION #define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#endif +#if defined(__wasilibc_unmodified_upstream) /* wasi-libc doesn't provide pthread_attr_{get,set}stackaddr */ #define _POSIX_THREAD_ATTR_STACKADDR _POSIX_VERSION +#endif +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) #define _POSIX_THREAD_ATTR_STACKSIZE _POSIX_VERSION +#endif +#if defined(__wasilibc_unmodified_upstream) /* WASI has no scheduling control, and wasi-libc doesn't provide pthread_getcpuclockid */ #define _POSIX_THREAD_PRIORITY_SCHEDULING _POSIX_VERSION #define _POSIX_THREAD_CPUTIME _POSIX_VERSION +#endif #define _POSIX_TIMERS _POSIX_VERSION #define _POSIX_TIMEOUTS _POSIX_VERSION #define _POSIX_MONOTONIC_CLOCK _POSIX_VERSION @@ -529,6 +535,8 @@ pid_t gettid(void); #define _SC_XOPEN_STREAMS 246 #define _SC_THREAD_ROBUST_PRIO_INHERIT 247 #define _SC_THREAD_ROBUST_PRIO_PROTECT 248 +#define _SC_MINSIGSTKSZ 249 +#define _SC_SIGSTKSZ 250 #define _CS_PATH 0 #define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 @@ -571,6 +579,8 @@ pid_t gettid(void); #define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 #define _CS_V6_ENV 1148 #define _CS_V7_ENV 1149 +#define _CS_POSIX_V7_THREADS_CFLAGS 1150 +#define _CS_POSIX_V7_THREADS_LDFLAGS 1151 #ifdef __cplusplus } diff --git a/lib/libc/include/wasm-wasi-musl/wasi/libc-busywait.h b/lib/libc/include/wasm-wasi-musl/wasi/libc-busywait.h new file mode 100644 index 000000000000..c90017b8e03f --- /dev/null +++ b/lib/libc/include/wasm-wasi-musl/wasi/libc-busywait.h @@ -0,0 +1,15 @@ +#ifndef __wasi_libc_busywait_h +#define __wasi_libc_busywait_h + +#ifdef __cplusplus +extern "C" { +#endif + +/// Enable busywait in futex on current thread. +void __wasilibc_enable_futex_busywait_on_current_thread(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/include/wasm-wasi-musl/wasi/libc.h b/lib/libc/include/wasm-wasi-musl/wasi/libc.h index 6acb672ad0b2..e280f0e42169 100644 --- a/lib/libc/include/wasm-wasi-musl/wasi/libc.h +++ b/lib/libc/include/wasm-wasi-musl/wasi/libc.h @@ -3,6 +3,7 @@ #include <__typedef_off_t.h> #include <__struct_timespec.h> +#include #ifdef __cplusplus extern "C" { @@ -17,10 +18,6 @@ struct timespec; /// afterward, you should call this before doing so. void __wasilibc_populate_preopens(void); -/// Reset the preopens table to an uninitialized state, forcing it to be -/// reinitialized next time it is needed. -void __wasilibc_reset_preopens(void); - /// Register the given pre-opened file descriptor under the given path. /// /// This function does not take ownership of `prefix` (it makes its own copy). @@ -68,6 +65,13 @@ int __wasilibc_rename_oldat(int olddirfd, const char *oldpath, const char *newpa int __wasilibc_rename_newat(const char *oldpath, int newdirfd, const char *newpath) __attribute__((__warn_unused_result__)); +/// Enable busywait in futex on current thread. +void __wasilibc_enable_futex_busywait_on_current_thread(void); + +/// Fill a buffer with random bytes +int __wasilibc_random(void* buffer, size_t len) + __attribute__((__warn_unused_result__)); + #ifdef __cplusplus } #endif diff --git a/lib/libc/wasi/fts/config.h b/lib/libc/wasi/fts/config.h new file mode 100644 index 000000000000..abdd30401202 --- /dev/null +++ b/lib/libc/wasi/fts/config.h @@ -0,0 +1,7 @@ +#define HAVE_DECL_MAX 1 + +#define HAVE_DECL_UINTMAX_MAX 0 + +#define HAVE_DIRFD 1 + +#define HAVE_FCHDIR 0 diff --git a/lib/libc/wasi/fts/musl-fts/COPYING b/lib/libc/wasi/fts/musl-fts/COPYING new file mode 100644 index 000000000000..f06eb044ea89 --- /dev/null +++ b/lib/libc/wasi/fts/musl-fts/COPYING @@ -0,0 +1,26 @@ +Copyright (c) 1989, 1993 + The Regents of the University of California. All rights reserved. + +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. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. diff --git a/lib/libc/wasi/fts/musl-fts/fts.c b/lib/libc/wasi/fts/musl-fts/fts.c new file mode 100644 index 000000000000..da4bc0875641 --- /dev/null +++ b/lib/libc/wasi/fts/musl-fts/fts.c @@ -0,0 +1,1279 @@ +/* $NetBSD: fts.c,v 1.48 2015/01/29 15:55:21 manu Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; +#else +__RCSID("$NetBSD: fts.c,v 1.48 2015/01/29 15:55:21 manu Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include "config.h" + +#include +#include + +#include +#define _DIAGASSERT(e) +#include +#include +#include +#include +#include +#include +#include + +#if !defined(HAVE_DECL_MAX) || (HAVE_DECL_MAX==0) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +#if !defined(UINT_MAX) && (HAVE_DECL_UINTMAX_MAX==1) +#define UINT_MAX UINTMAX_MAX +#endif + +#if !defined(HAVE_DIRFD) +#if defined(HAVE_DIR_DD_FD) +#define dirfd(dirp) ((dirp)->dd_fd) +#endif +#if defined(HAVE_DIR_D_FD) +#define dirfd(dirp) ((dirp)->d_fd) +#endif +#endif + +static FTSENT *fts_alloc(FTS *, const char *, size_t); +static FTSENT *fts_build(FTS *, int); +static void fts_free(FTSENT *); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static size_t fts_pow2(size_t); +static int fts_palloc(FTS *, size_t); +static void fts_padjust(FTS *, FTSENT *); +static FTSENT *fts_sort(FTS *, FTSENT *, size_t); +static unsigned short fts_stat(FTS *, FTSENT *, int); +static int fts_safe_changedir(const FTS *, const FTSENT *, int, + const char *); + +#if defined(ALIGNBYTES) && defined(ALIGN) +#define FTS_ALLOC_ALIGNED 1 +#else +#undef FTS_ALLOC_ALIGNED +#endif + +#ifndef ftsent_namelen_truncate +#define ftsent_namelen_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif +#ifndef ftsent_pathlen_truncate +#define ftsent_pathlen_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif +#ifndef fts_pathlen_truncate +#define fts_pathlen_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif +#ifndef fts_nitems_truncate +#define fts_nitems_truncate(a) \ + ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a)) +#endif + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#if HAVE_FCHDIR +#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) +#else +/* If we don't have fchdir, pretend that !ISSET(FTS_NOCHDIR) is always false in + * the above macros, and do not reference chdir or fchdir. */ +#define CHDIR(sp, path) 0 +#define FCHDIR(sp, fd) 0 +#endif + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +#ifndef DTF_HIDEW +#undef FTS_WHITEOUT +#endif + +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + FTS *sp; + FTSENT *p, *root; + size_t nitems; + FTSENT *parent, *tmp = NULL; /* pacify gcc */ + size_t len; + + _DIAGASSERT(argv != NULL); + +#if !HAVE_FCHDIR + /* If we don't have fchdir, pretend that FTS_NOCHDIR is always set. */ + options |= FTS_NOCHDIR; +#endif + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = malloc(sizeof(FTS))) == NULL) + return (NULL); + memset(sp, 0, sizeof(FTS)); + sp->fts_compar = compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + if ((len = strlen(*argv)) == 0) { + errno = ENOENT; + goto mem3; + } + + if ((p = fts_alloc(sp, *argv, len)) == NULL) + goto mem3; + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + if (!ISSET(FTS_NOCHDIR)) { + if ((sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) + SET(FTS_NOCHDIR); + } + + if (nitems == 0) + fts_free(parent); + + return (sp); + +mem3: fts_lfree(root); + fts_free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + char *cp; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = ftsent_namelen_truncate(len); + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + FTSENT *freep, *p; + int saved_errno = 0; + + _DIAGASSERT(sp != NULL); + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + if (sp->fts_cur->fts_flags & FTS_SYMFOLLOW) + (void)close(sp->fts_cur->fts_symfd); + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link ? p->fts_link : p->fts_parent; + fts_free(freep); + } + fts_free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + #if HAVE_FCHDIR + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + if (fchdir(sp->fts_rfd) == -1) + saved_errno = errno; + (void)close(sp->fts_rfd); + } + #endif + + /* Free up the stream pointer. */ + free(sp); + if (saved_errno) { + errno = saved_errno; + return -1; + } + + return 0; +} + +#if !defined(__FTS_COMPAT_TAILINGSLASH) + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +#else /* !defined(__FTS_COMPAT_TAILINGSLASH) */ + +/* + * compatibility with the old behaviour. + * + * Special case a root of "/" so that slashes aren't appended which would + * cause paths to be written as "//foo". + */ + +#define NAPPEND(p) \ + (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ + p->fts_path[0] == '/' ? 0 : p->fts_pathlen) + +#endif /* !defined(__FTS_COMPAT_TAILINGSLASH) */ + +FTSENT * +fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + int saved_errno; + + _DIAGASSERT(sp != NULL); + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY | O_CLOEXEC, 0)) + == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p; p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + +next: + /* Move to the next node on this level. */ + tmp = p; + + /* + * We are going to free sp->fts_cur, set it to NULL so + * that fts_close() does not attempt to free it again + * if we exit without setting it to a new value because + * FCHDIR() failed below. + */ + assert(tmp == sp->fts_cur); + sp->fts_cur = NULL; + + if ((p = p->fts_link) != NULL) { + fts_free(tmp); + + /* + * If reached the top, return to the original directory, and + * load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1)); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + fts_free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + fts_free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(FTS *sp, FTSENT *p, int instr) +{ + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(FTS *sp, int instr) +{ + FTSENT *p; + int fd; + + _DIAGASSERT(sp != NULL); + + if (instr && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + #if HAVE_FCHDIR + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) + return (sp->fts_child = NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) { + (void)close(fd); + return (NULL); + } + (void)close(fd); + return (sp->fts_child); + #else + /* If not using chdir, just build the list. */ + return (sp->fts_child = fts_build(sp, instr)); + #endif +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + struct dirent *dp; + FTSENT *p, *head; + size_t nitems; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + size_t dnamlen; + int cderrno, descend, level, nlinks, saved_errno, nostat, doadjust; + size_t len, maxlen; +#ifdef FTS_WHITEOUT + int oflag; +#endif + char *cp = NULL; /* pacify gcc */ + + _DIAGASSERT(sp != NULL); + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#ifdef FTS_WHITEOUT + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP|DTF_REWIND; + else + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; +#else +#define __opendir2(path, flag) opendir(path) +#endif + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + nostat = 1; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } + len++; + maxlen = sp->fts_pathlen - len; + +#if defined(__FTS_COMPAT_LEVEL) + if (cur->fts_level == SHRT_MAX) { + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } +#endif + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) { + + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + +#if defined(HAVE_STRUCT_DIRENT_D_NAMLEN) + dnamlen = dp->d_namlen; +#else + dnamlen = strlen(dp->d_name); +#endif + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + fts_free(p); + fts_lfree(head); + (void)closedir(dirp); + errno = saved_errno; + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + +#if defined(__FTS_COMPAT_LENGTH) + if (len + dnamlen >= USHRT_MAX) { + /* + * In an FTSENT, fts_pathlen is an unsigned short + * so it is possible to wraparound here. + * If we do, free up the current structure and the + * structures already allocated, then error out + * with ENAMETOOLONG. + */ + fts_free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } +#endif + p->fts_level = level; + p->fts_pathlen = ftsent_pathlen_truncate(len + dnamlen); + p->fts_parent = sp->fts_cur; + +#ifdef FTS_WHITEOUT + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, + (size_t)(p->fts_namelen + 1)); + } else + p->fts_accpath = p->fts_name; + /* Stat it. */ + p->fts_info = fts_stat(sp, p, 0); + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + (void)closedir(dirp); + + /* + * If had to realloc the path, adjust the addresses for the rest + * of the tree. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static unsigned short +fts_stat(FTS *sp, FTSENT *p, int follow) +{ + FTSENT *t; + dev_t dev; + __fts_ino_t ino; + __fts_stat_t *sbp, sb; + int saved_errno; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#ifdef FTS_WHITEOUT + /* check for whiteout */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof (*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (stat(p->fts_accpath, sbp)) { + saved_errno = errno; + if (!lstat(p->fts_accpath, sbp)) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(*sbp)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, size_t nitems) +{ + FTSENT **ap, *p; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(head != NULL); + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + FTSENT **new; + + new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40)); + if (new == 0) + return (head); + sp->fts_array = new; + sp->fts_nitems = fts_nitems_truncate(nitems + 40); + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), + (int (*)(const void *, const void *))sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, const char *name, size_t namelen) +{ + FTSENT *p; +#if defined(FTS_ALLOC_ALIGNED) + size_t len; +#endif + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(name != NULL); + +#if defined(FTS_ALLOC_ALIGNED) + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof(FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof(*(p->fts_statp)) + ALIGNBYTES; + if ((p = malloc(len)) == NULL) + return (NULL); + + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (__fts_stat_t *)ALIGN( + (unsigned long)(p->fts_name + namelen + 2)); +#else + if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL) + return (NULL); + + if (!ISSET(FTS_NOSTAT)) + if ((p->fts_statp = malloc(sizeof(*(p->fts_statp)))) == NULL) { + free(p); + return (NULL); + } +#endif + + if (ISSET(FTS_NOSTAT)) + p->fts_statp = NULL; + + /* Copy the name plus the trailing NULL. */ + memmove(p->fts_name, name, namelen + 1); + + p->fts_namelen = ftsent_namelen_truncate(namelen); + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + return (p); +} + +static void +fts_free(FTSENT *p) +{ +#if !defined(FTS_ALLOC_ALIGNED) + if (p->fts_statp) + free(p->fts_statp); +#endif + free(p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* XXX: head may be NULL ? */ + + /* Free a linked list of structures. */ + while ((p = head) != NULL) { + head = head->fts_link; + fts_free(p); + } +} + +static size_t +fts_pow2(size_t x) +{ + + x--; + x |= x>>1; + x |= x>>2; + x |= x>>4; + x |= x>>8; + x |= x>>16; +#if LONG_BIT > 32 + x |= x>>32; +#endif +#if LONG_BIT > 64 + x |= x>>64; +#endif + x++; + return (x); +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Round up the new size to a power of 2, + * so we don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t size) +{ + char *new; + + _DIAGASSERT(sp != NULL); + +#ifdef __FTS_COMPAT_LENGTH + /* Protect against fts_pathlen overflow. */ + if (size > USHRT_MAX + 1) { + errno = ENAMETOOLONG; + return (1); + } +#endif + size = fts_pow2(size); + new = realloc(sp->fts_path, size); + if (new == 0) + return (1); + sp->fts_path = new; + sp->fts_pathlen = fts_pathlen_truncate(size); + return (0); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr; + + _DIAGASSERT(sp != NULL); + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) \ + (p)->fts_accpath = \ + addr + ((p)->fts_accpath - (p)->fts_path); \ + (p)->fts_path = addr; \ +} while (/*CONSTCOND*/0) + + addr = sp->fts_path; + + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + _DIAGASSERT(argv != NULL); + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(const FTS *sp, const FTSENT *p, int fd, const char *path) +{ +#if HAVE_FCHDIR + int oldfd = fd, ret = -1; + __fts_stat_t sb; + + if (ISSET(FTS_NOCHDIR)) + return 0; + + if (oldfd < 0 && (fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) + return -1; + + if (fstat(fd, &sb) == -1) + goto bail; + + if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) { + errno = ENOENT; + goto bail; + } + + ret = fchdir(fd); + +bail: + if (oldfd < 0) { + int save_errno = errno; + (void)close(fd); + errno = save_errno; + } + return ret; +#else + /* If we can't do fchdir, pretend as if ISSET(FTS_NOCHDIR) is set. */ + return 0; +#endif +} diff --git a/lib/libc/wasi/libc-bottom-half/clocks/times.c b/lib/libc/wasi/libc-bottom-half/clocks/times.c index e245569a4f50..48fa07baa7f0 100644 --- a/lib/libc/wasi/libc-bottom-half/clocks/times.c +++ b/lib/libc/wasi/libc-bottom-half/clocks/times.c @@ -17,7 +17,8 @@ clock_t times(struct tms *buffer) { __wasi_timestamp_t user = __clock(); *buffer = (struct tms){ .tms_utime = user, - .tms_cutime = user + // WASI doesn't provide a way to spawn a new process, so always 0. + .tms_cutime = 0 }; __wasi_timestamp_t realtime = 0; diff --git a/lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/stdlib/_Exit.c b/lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/stdlib/_Exit.c index 5e266f0b985d..a2c4e0bd2716 100644 --- a/lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/stdlib/_Exit.c +++ b/lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/stdlib/_Exit.c @@ -2,13 +2,22 @@ // // SPDX-License-Identifier: BSD-2-Clause +#ifdef __wasilibc_use_wasip2 +#include +#else #include +#endif #include <_/cdefs.h> #include #include noreturn void _Exit(int status) { +#ifdef __wasilibc_use_wasip2 + exit_result_void_void_t exit_status = { .is_err = status != 0 }; + exit_exit(&exit_status); +#else __wasi_proc_exit(status); +#endif } __strong_reference(_Exit, _exit); diff --git a/lib/libc/wasi/libc-bottom-half/crt/crt1-command.c b/lib/libc/wasi/libc-bottom-half/crt/crt1-command.c index d2030cb7805a..1639dec13642 100644 --- a/lib/libc/wasi/libc-bottom-half/crt/crt1-command.c +++ b/lib/libc/wasi/libc-bottom-half/crt/crt1-command.c @@ -2,7 +2,11 @@ #include extern void __wasi_init_tp(void); #endif +#ifdef __wasilibc_use_wasip2 +#include +#else #include +#endif extern void __wasm_call_ctors(void); extern int __main_void(void); extern void __wasm_call_dtors(void); @@ -47,7 +51,14 @@ void _start(void) { // If main exited successfully, just return, otherwise call // `__wasi_proc_exit`. +#ifdef __wasilibc_use_wasip2 + if (r != 0) { + exit_result_void_void_t status = { .is_err = true }; + exit_exit(&status); + } +#else if (r != 0) { __wasi_proc_exit(r); } +#endif } diff --git a/lib/libc/wasi/libc-bottom-half/headers/private/wasi/sockets_utils.h b/lib/libc/wasi/libc-bottom-half/headers/private/wasi/sockets_utils.h index 93cf1f45d605..354664d9caa4 100644 --- a/lib/libc/wasi/libc-bottom-half/headers/private/wasi/sockets_utils.h +++ b/lib/libc/wasi/libc-bottom-half/headers/private/wasi/sockets_utils.h @@ -26,6 +26,17 @@ typedef struct { }; } output_sockaddr_t; +typedef struct { + char *s_name; + uint16_t port; + uint16_t protocol; +} service_entry_t; + +typedef enum { + SERVICE_PROTOCOL_TCP = 1, + SERVICE_PROTOCOL_UDP = 2 +} service_protocol_e; + network_borrow_network_t __wasi_sockets_utils__borrow_network(); int __wasi_sockets_utils__map_error(network_error_code_t wasi_error); bool __wasi_sockets_utils__parse_address( @@ -49,5 +60,8 @@ bool __wasi_sockets_utils__stream(udp_socket_t *socket, udp_socket_streams_t *result, network_error_code_t *error); void __wasi_sockets_utils__drop_streams(udp_socket_streams_t streams); +int __wasi_sockets_utils__parse_port(const char *port); +const service_entry_t *__wasi_sockets_utils__get_service_entry_by_name(const char *name); +const service_entry_t *__wasi_sockets_utils__get_service_entry_by_port(const uint16_t port); #endif diff --git a/lib/libc/wasi/libc-bottom-half/mman/mman.c b/lib/libc/wasi/libc-bottom-half/mman/mman.c index f02b136cd248..6f672e2896b7 100644 --- a/lib/libc/wasi/libc-bottom-half/mman/mman.c +++ b/lib/libc/wasi/libc-bottom-half/mman/mman.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -122,3 +123,35 @@ int munmap(void *addr, size_t length) { // Success! return 0; } + +int mprotect(void *addr, size_t length, int prot) { + // Address must be page-aligned. + size_t begin = (size_t)addr; + if ((begin & (PAGESIZE - 1)) != 0) { + errno = EINVAL; + return -1; + } + + // Length must not be big enough to wrap around. + size_t end; + if (__builtin_add_overflow(begin, length, &end)) { + errno = ENOMEM; + return -1; + } + + // Range must be in bounds of linear memory. + size_t memory_size = __builtin_wasm_memory_size(0) * PAGESIZE; + if (end > memory_size) { + errno = ENOMEM; + return -1; + } + + // Can only protect memory as read/write (which is a no-op). + if (prot != (PROT_READ | PROT_WRITE)) { + errno = ENOTSUP; + return -1; + } + + // Success! + return 0; +} diff --git a/lib/libc/wasi/libc-bottom-half/sources/__main_void.c b/lib/libc/wasi/libc-bottom-half/sources/__main_void.c index cdb95c6bbacc..c40241fa3e5a 100644 --- a/lib/libc/wasi/libc-bottom-half/sources/__main_void.c +++ b/lib/libc/wasi/libc-bottom-half/sources/__main_void.c @@ -1,19 +1,19 @@ +#ifdef __wasilibc_use_wasip2 +#include +#else #include +#endif #include #include -int __wasilibc_main(int argc, char *argv[]) asm("main"); - // The user's `main` function, expecting arguments. // // Note that we make this a weak symbol so that it will have a // `WASM_SYM_BINDING_WEAK` flag in libc.so, which tells the dynamic linker that // it need not be defined (e.g. in reactor-style apps with no main function). // See also the TODO comment on `__main_void` below. -__attribute__((__weak__, nodebug)) -int __main_argc_argv(int argc, char *argv[]) { - return __wasilibc_main(argc, argv); -} +__attribute__((__weak__)) +int __main_argc_argv(int argc, char *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 @@ -25,6 +25,46 @@ int __main_argc_argv(int argc, char *argv[]) { // (e.g. crt0.o or crtend.o) and teach Clang to use it when needed. __attribute__((__weak__, nodebug)) int __main_void(void) { +#ifdef __wasilibc_use_wasip2 + wasip2_list_string_t argument_list; + + environment_get_arguments(&argument_list); + + // Add 1 for the NULL pointer to mark the end, and check for overflow. + size_t argc = argument_list.len; + size_t num_ptrs = argc + 1; + if (num_ptrs == 0) { + wasip2_list_string_free(&argument_list); + _Exit(EX_SOFTWARE); + } + + // Allocate memory for the array of pointers. This uses `calloc` both to + // handle overflow and to initialize the NULL pointer at the end. + char **argv = calloc(num_ptrs, sizeof(char *)); + if (argv == NULL) { + wasip2_list_string_free(&argument_list); + _Exit(EX_SOFTWARE); + } + + // Copy the arguments + for (size_t i = 0; i < argc; i++) { + wasip2_string_t wasi_string = argument_list.ptr[i]; + size_t len = wasi_string.len; + argv[i] = malloc(len + 1); + if (!argv[i]) { + wasip2_list_string_free(&argument_list); + _Exit(EX_SOFTWARE); + } + memcpy(argv[i], wasi_string.ptr, len); + argv[i][len] = '\0'; + } + + // Free the WASI argument list + wasip2_list_string_free(&argument_list); + + // Call `__main_argc_argv` with the arguments! + return __main_argc_argv(argc, argv); +#else __wasi_errno_t err; // Get the sizes of the arrays we'll have to create to copy in the args. @@ -66,4 +106,5 @@ int __main_void(void) { // Call `__main_argc_argv` with the arguments! return __main_argc_argv(argc, argv); +#endif } diff --git a/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_initialize_environ.c b/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_initialize_environ.c index 2d31c5d03a92..9eddb4b5ff6c 100644 --- a/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_initialize_environ.c +++ b/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_initialize_environ.c @@ -1,7 +1,11 @@ #include #include #include +#ifdef __wasilibc_use_wasip2 +#include +#else #include +#endif #include #include @@ -26,6 +30,55 @@ static char *empty_environ[1] = { NULL }; // See the comments in libc-environ.h. void __wasilibc_initialize_environ(void) { +#ifdef __wasilibc_use_wasip2 + // Get the environment + wasip2_list_tuple2_string_string_t wasi_environment; + environment_get_environment(&wasi_environment); + + size_t environ_count = wasi_environment.len; + if (environ_count == 0) { + __wasilibc_environ = empty_environ; + return; + } + + // Add 1 for the NULL pointer to mark the end, and check for overflow. + size_t num_ptrs = environ_count + 1; + if (num_ptrs == 0) { + goto software; + } + + // Allocate memory for the array of pointers. This uses `calloc` both to + // handle overflow and to initialize the NULL pointer at the end. + char **environ_ptrs = calloc(num_ptrs, sizeof(char *)); + + // Copy the environment variables + for (size_t i = 0; i < environ_count; i++) { + wasip2_tuple2_string_string_t pair = wasi_environment.ptr[i]; + // 1 extra character for the null terminator, 1 for the '=' character + environ_ptrs[i] = malloc(pair.f0.len + pair.f1.len + 2); + if (!environ_ptrs[i]) { + for (size_t j = 0; j < i; j++) + free(environ_ptrs[j]); + free(environ_ptrs); + goto software; + } + memcpy(environ_ptrs[i], pair.f0.ptr, pair.f0.len); + environ_ptrs[i][pair.f0.len] = '='; + memcpy(environ_ptrs[i] + pair.f0.len + 1, pair.f1.ptr, pair.f1.len); + environ_ptrs[i][pair.f0.len + pair.f1.len + 1] = '\0'; + } + + // Free the WASI environment list + wasip2_list_tuple2_string_string_free(&wasi_environment); + + // Initialize the environment from the created array + __wasilibc_environ = environ_ptrs; + return; +software: + wasip2_list_tuple2_string_string_free(&wasi_environment); + _Exit(EX_SOFTWARE); + +#else // Get the sizes of the arrays we'll have to create to copy in the environment. size_t environ_count; size_t environ_buf_size; @@ -74,6 +127,7 @@ void __wasilibc_initialize_environ(void) { _Exit(EX_OSERR); software: _Exit(EX_SOFTWARE); +#endif } // See the comments in libc-environ.h. diff --git a/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_random.c b/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_random.c new file mode 100644 index 000000000000..8232c44e3825 --- /dev/null +++ b/lib/libc/wasi/libc-bottom-half/sources/__wasilibc_random.c @@ -0,0 +1,29 @@ +#include +#include +#ifdef __wasilibc_use_wasip2 +#include +#include + +int __wasilibc_random(void *buffer, size_t len) { + + // Set up a WASI byte list to receive the results + wasip2_list_u8_t wasi_list; + + // Get random bytes + random_get_random_bytes(len, &wasi_list); + + // The spec for get-random-bytes specifies that wasi_list.len + // will be equal to len. + if (wasi_list.len != len) + _Exit(EX_OSERR); + else { + // Copy the result + memcpy(buffer, wasi_list.ptr, len); + } + + // Free the WASI byte list + wasip2_list_u8_free(&wasi_list); + + return 0; +} +#endif diff --git a/lib/libc/wasi/libc-bottom-half/sources/getentropy.c b/lib/libc/wasi/libc-bottom-half/sources/getentropy.c index e540e7e319d6..3d6ff05c79d7 100644 --- a/lib/libc/wasi/libc-bottom-half/sources/getentropy.c +++ b/lib/libc/wasi/libc-bottom-half/sources/getentropy.c @@ -1,6 +1,10 @@ #include #include +#ifdef __wasilibc_use_wasip2 +#include +#else #include +#endif int __getentropy(void *buffer, size_t len) { if (len > 256) { @@ -8,13 +12,15 @@ int __getentropy(void *buffer, size_t len) { return -1; } +#ifdef __wasilibc_use_wasip2 + int r = __wasilibc_random(buffer, len); +#else int r = __wasi_random_get(buffer, len); - +#endif if (r != 0) { errno = r; return -1; } - return 0; } weak_alias(__getentropy, getentropy); diff --git a/lib/libc/wasi/libc-bottom-half/sources/preopens.c b/lib/libc/wasi/libc-bottom-half/sources/preopens.c index a7ebe646b902..ccd65e892f73 100644 --- a/lib/libc/wasi/libc-bottom-half/sources/preopens.c +++ b/lib/libc/wasi/libc-bottom-half/sources/preopens.c @@ -59,7 +59,6 @@ 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; @@ -67,7 +66,6 @@ static int resize(void) { preopen *old_preopens = preopens; preopen *new_preopens = calloc(sizeof(preopen), new_capacity); if (new_preopens == NULL) { - UNLOCK(lock); return -1; } @@ -77,7 +75,6 @@ static int resize(void) { free(old_preopens); assert_invariants(); - UNLOCK(lock); return 0; } @@ -101,8 +98,7 @@ static const char *strip_prefixes(const char *path) { return path; } -/// Similar to `internal_register_preopened_fd_unlocked` but does not -/// take a lock. +/// Similar to `internal_register_preopened_fd` but does not take a lock. static int internal_register_preopened_fd_unlocked(__wasi_fd_t fd, const char *relprefix) { // Check preconditions. assert_invariants(); @@ -184,7 +180,7 @@ int __wasilibc_find_abspath(const char *path, const char **relative_path) { __wasilibc_populate_preopens(); - // Strip leading `/` characters, the prefixes we're mataching won't have + // Strip leading `/` characters, the prefixes we're matching won't have // them. while (*path == '/') path++; @@ -231,6 +227,7 @@ int __wasilibc_find_abspath(const char *path, return fd; } +/* zig patch: initialize preopens early so zig code doesn't have to call __wasilibc_populate_preopens */ __attribute__((constructor(51))) void __wasilibc_populate_preopens(void) { // Fast path: If the preopens are already initialized, do nothing. diff --git a/lib/libc/wasi/libc-top-half/musl/include/aio.h b/lib/libc/wasi/libc-top-half/musl/include/aio.h new file mode 100644 index 000000000000..453c41b7489f --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/include/aio.h @@ -0,0 +1,73 @@ +#ifndef _AIO_H +#define _AIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define __NEED_ssize_t +#define __NEED_off_t + +#include + +struct aiocb { + int aio_fildes, aio_lio_opcode, aio_reqprio; + volatile void *aio_buf; + size_t aio_nbytes; + struct sigevent aio_sigevent; + void *__td; + int __lock[2]; + volatile int __err; + ssize_t __ret; + off_t aio_offset; + void *__next, *__prev; + char __dummy4[32-2*sizeof(void *)]; +}; + +#define AIO_CANCELED 0 +#define AIO_NOTCANCELED 1 +#define AIO_ALLDONE 2 + +#define LIO_READ 0 +#define LIO_WRITE 1 +#define LIO_NOP 2 + +#define LIO_WAIT 0 +#define LIO_NOWAIT 1 + +int aio_read(struct aiocb *); +int aio_write(struct aiocb *); +int aio_error(const struct aiocb *); +ssize_t aio_return(struct aiocb *); +int aio_cancel(int, struct aiocb *); +int aio_suspend(const struct aiocb *const [], int, const struct timespec *); +int aio_fsync(int, struct aiocb *); + +int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sigevent *__restrict); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define aiocb64 aiocb +#define aio_read64 aio_read +#define aio_write64 aio_write +#define aio_error64 aio_error +#define aio_return64 aio_return +#define aio_cancel64 aio_cancel +#define aio_suspend64 aio_suspend +#define aio_fsync64 aio_fsync +#define lio_listio64 lio_listio +#define off64_t off_t +#endif + +#if _REDIR_TIME64 +__REDIR(aio_suspend, __aio_suspend_time64); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/arpa/nameser.h b/lib/libc/wasi/libc-top-half/musl/include/arpa/nameser.h deleted file mode 100644 index 581925a43367..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/include/arpa/nameser.h +++ /dev/null @@ -1,455 +0,0 @@ -#ifndef _ARPA_NAMESER_H -#define _ARPA_NAMESER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define __NAMESER 19991006 -#define NS_PACKETSZ 512 -#define NS_MAXDNAME 1025 -#define NS_MAXMSG 65535 -#define NS_MAXCDNAME 255 -#define NS_MAXLABEL 63 -#define NS_HFIXEDSZ 12 -#define NS_QFIXEDSZ 4 -#define NS_RRFIXEDSZ 10 -#define NS_INT32SZ 4 -#define NS_INT16SZ 2 -#define NS_INT8SZ 1 -#define NS_INADDRSZ 4 -#define NS_IN6ADDRSZ 16 -#define NS_CMPRSFLGS 0xc0 -#define NS_DEFAULTPORT 53 - -typedef enum __ns_sect { - ns_s_qd = 0, - ns_s_zn = 0, - ns_s_an = 1, - ns_s_pr = 1, - ns_s_ns = 2, - ns_s_ud = 2, - ns_s_ar = 3, - ns_s_max = 4 -} ns_sect; - -typedef struct __ns_msg { - const unsigned char *_msg, *_eom; - uint16_t _id, _flags, _counts[ns_s_max]; - const unsigned char *_sections[ns_s_max]; - ns_sect _sect; - int _rrnum; - const unsigned char *_msg_ptr; -} ns_msg; - -struct _ns_flagdata { int mask, shift; }; -extern const struct _ns_flagdata _ns_flagdata[]; - -#define ns_msg_id(handle) ((handle)._id + 0) -#define ns_msg_base(handle) ((handle)._msg + 0) -#define ns_msg_end(handle) ((handle)._eom + 0) -#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) -#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) -#define ns_msg_getflag(handle, flag) \ - (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) - -typedef struct __ns_rr { - char name[NS_MAXDNAME]; - uint16_t type; - uint16_t rr_class; - uint32_t ttl; - uint16_t rdlength; - const unsigned char *rdata; -} ns_rr; - -#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") -#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) -#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) -#define ns_rr_ttl(rr) ((rr).ttl + 0) -#define ns_rr_rdlen(rr) ((rr).rdlength + 0) -#define ns_rr_rdata(rr) ((rr).rdata + 0) - -typedef enum __ns_flag { - ns_f_qr, - ns_f_opcode, - ns_f_aa, - ns_f_tc, - ns_f_rd, - ns_f_ra, - ns_f_z, - ns_f_ad, - ns_f_cd, - ns_f_rcode, - ns_f_max -} ns_flag; - -typedef enum __ns_opcode { - ns_o_query = 0, - ns_o_iquery = 1, - ns_o_status = 2, - ns_o_notify = 4, - ns_o_update = 5, - ns_o_max = 6 -} ns_opcode; - -typedef enum __ns_rcode { - ns_r_noerror = 0, - ns_r_formerr = 1, - ns_r_servfail = 2, - ns_r_nxdomain = 3, - ns_r_notimpl = 4, - ns_r_refused = 5, - ns_r_yxdomain = 6, - ns_r_yxrrset = 7, - ns_r_nxrrset = 8, - ns_r_notauth = 9, - ns_r_notzone = 10, - ns_r_max = 11, - ns_r_badvers = 16, - ns_r_badsig = 16, - ns_r_badkey = 17, - ns_r_badtime = 18 -} ns_rcode; - -typedef enum __ns_update_operation { - ns_uop_delete = 0, - ns_uop_add = 1, - ns_uop_max = 2 -} ns_update_operation; - -struct ns_tsig_key { - char name[NS_MAXDNAME], alg[NS_MAXDNAME]; - unsigned char *data; - int len; -}; -typedef struct ns_tsig_key ns_tsig_key; - -struct ns_tcp_tsig_state { - int counter; - struct dst_key *key; - void *ctx; - unsigned char sig[NS_PACKETSZ]; - int siglen; -}; -typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; - -#define NS_TSIG_FUDGE 300 -#define NS_TSIG_TCP_COUNT 100 -#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" - -#define NS_TSIG_ERROR_NO_TSIG -10 -#define NS_TSIG_ERROR_NO_SPACE -11 -#define NS_TSIG_ERROR_FORMERR -12 - -typedef enum __ns_type { - ns_t_invalid = 0, - ns_t_a = 1, - ns_t_ns = 2, - ns_t_md = 3, - ns_t_mf = 4, - ns_t_cname = 5, - ns_t_soa = 6, - ns_t_mb = 7, - ns_t_mg = 8, - ns_t_mr = 9, - ns_t_null = 10, - ns_t_wks = 11, - ns_t_ptr = 12, - ns_t_hinfo = 13, - ns_t_minfo = 14, - ns_t_mx = 15, - ns_t_txt = 16, - ns_t_rp = 17, - ns_t_afsdb = 18, - ns_t_x25 = 19, - ns_t_isdn = 20, - ns_t_rt = 21, - ns_t_nsap = 22, - ns_t_nsap_ptr = 23, - ns_t_sig = 24, - ns_t_key = 25, - ns_t_px = 26, - ns_t_gpos = 27, - ns_t_aaaa = 28, - ns_t_loc = 29, - ns_t_nxt = 30, - ns_t_eid = 31, - ns_t_nimloc = 32, - ns_t_srv = 33, - ns_t_atma = 34, - ns_t_naptr = 35, - ns_t_kx = 36, - ns_t_cert = 37, - ns_t_a6 = 38, - ns_t_dname = 39, - ns_t_sink = 40, - ns_t_opt = 41, - ns_t_apl = 42, - ns_t_tkey = 249, - ns_t_tsig = 250, - ns_t_ixfr = 251, - ns_t_axfr = 252, - ns_t_mailb = 253, - ns_t_maila = 254, - ns_t_any = 255, - ns_t_zxfr = 256, - ns_t_max = 65536 -} ns_type; - -#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ - (t) == ns_t_mailb || (t) == ns_t_maila) -#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) -#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) -#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) -#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ - (t) == ns_t_zxfr) - -typedef enum __ns_class { - ns_c_invalid = 0, - ns_c_in = 1, - ns_c_2 = 2, - ns_c_chaos = 3, - ns_c_hs = 4, - ns_c_none = 254, - ns_c_any = 255, - ns_c_max = 65536 -} ns_class; - -typedef enum __ns_key_types { - ns_kt_rsa = 1, - ns_kt_dh = 2, - ns_kt_dsa = 3, - ns_kt_private = 254 -} ns_key_types; - -typedef enum __ns_cert_types { - cert_t_pkix = 1, - cert_t_spki = 2, - cert_t_pgp = 3, - cert_t_url = 253, - cert_t_oid = 254 -} ns_cert_types; - -#define NS_KEY_TYPEMASK 0xC000 -#define NS_KEY_TYPE_AUTH_CONF 0x0000 -#define NS_KEY_TYPE_CONF_ONLY 0x8000 -#define NS_KEY_TYPE_AUTH_ONLY 0x4000 -#define NS_KEY_TYPE_NO_KEY 0xC000 -#define NS_KEY_NO_AUTH 0x8000 -#define NS_KEY_NO_CONF 0x4000 -#define NS_KEY_RESERVED2 0x2000 -#define NS_KEY_EXTENDED_FLAGS 0x1000 -#define NS_KEY_RESERVED4 0x0800 -#define NS_KEY_RESERVED5 0x0400 -#define NS_KEY_NAME_TYPE 0x0300 -#define NS_KEY_NAME_USER 0x0000 -#define NS_KEY_NAME_ENTITY 0x0200 -#define NS_KEY_NAME_ZONE 0x0100 -#define NS_KEY_NAME_RESERVED 0x0300 -#define NS_KEY_RESERVED8 0x0080 -#define NS_KEY_RESERVED9 0x0040 -#define NS_KEY_RESERVED10 0x0020 -#define NS_KEY_RESERVED11 0x0010 -#define NS_KEY_SIGNATORYMASK 0x000F -#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ - NS_KEY_RESERVED4 | \ - NS_KEY_RESERVED5 | \ - NS_KEY_RESERVED8 | \ - NS_KEY_RESERVED9 | \ - NS_KEY_RESERVED10 | \ - NS_KEY_RESERVED11 ) -#define NS_KEY_RESERVED_BITMASK2 0xFFFF -#define NS_ALG_MD5RSA 1 -#define NS_ALG_DH 2 -#define NS_ALG_DSA 3 -#define NS_ALG_DSS NS_ALG_DSA -#define NS_ALG_EXPIRE_ONLY 253 -#define NS_ALG_PRIVATE_OID 254 - -#define NS_KEY_PROT_TLS 1 -#define NS_KEY_PROT_EMAIL 2 -#define NS_KEY_PROT_DNSSEC 3 -#define NS_KEY_PROT_IPSEC 4 -#define NS_KEY_PROT_ANY 255 - -#define NS_MD5RSA_MIN_BITS 512 -#define NS_MD5RSA_MAX_BITS 4096 -#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) -#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) -#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) -#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) - -#define NS_DSA_SIG_SIZE 41 -#define NS_DSA_MIN_SIZE 213 -#define NS_DSA_MAX_BYTES 405 - -#define NS_SIG_TYPE 0 -#define NS_SIG_ALG 2 -#define NS_SIG_LABELS 3 -#define NS_SIG_OTTL 4 -#define NS_SIG_EXPIR 8 -#define NS_SIG_SIGNED 12 -#define NS_SIG_FOOT 16 -#define NS_SIG_SIGNER 18 -#define NS_NXT_BITS 8 -#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_MAX 127 - -#define NS_OPT_DNSSEC_OK 0x8000U -#define NS_OPT_NSID 3 - -#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp)+=2)-2)) -#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp)+=4)-4)) -#define NS_PUT16(s, cp) ns_put16((s), ((cp)+=2)-2) -#define NS_PUT32(l, cp) ns_put32((l), ((cp)+=4)-4) - -unsigned ns_get16(const unsigned char *); -unsigned long ns_get32(const unsigned char *); -void ns_put16(unsigned, unsigned char *); -void ns_put32(unsigned long, unsigned char *); - -int ns_initparse(const unsigned char *, int, ns_msg *); -int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); -int ns_skiprr(const unsigned char *, const unsigned char *, ns_sect, int); -int ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); - - -#define __BIND 19950621 - -typedef struct { - unsigned id :16; -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned qr: 1; - unsigned opcode: 4; - unsigned aa: 1; - unsigned tc: 1; - unsigned rd: 1; - unsigned ra: 1; - unsigned unused :1; - unsigned ad: 1; - unsigned cd: 1; - unsigned rcode :4; -#else - unsigned rd :1; - unsigned tc :1; - unsigned aa :1; - unsigned opcode :4; - unsigned qr :1; - unsigned rcode :4; - unsigned cd: 1; - unsigned ad: 1; - unsigned unused :1; - unsigned ra :1; -#endif - unsigned qdcount :16; - unsigned ancount :16; - unsigned nscount :16; - unsigned arcount :16; -} HEADER; - -#define PACKETSZ NS_PACKETSZ -#define MAXDNAME NS_MAXDNAME -#define MAXCDNAME NS_MAXCDNAME -#define MAXLABEL NS_MAXLABEL -#define HFIXEDSZ NS_HFIXEDSZ -#define QFIXEDSZ NS_QFIXEDSZ -#define RRFIXEDSZ NS_RRFIXEDSZ -#define INT32SZ NS_INT32SZ -#define INT16SZ NS_INT16SZ -#define INT8SZ NS_INT8SZ -#define INADDRSZ NS_INADDRSZ -#define IN6ADDRSZ NS_IN6ADDRSZ -#define INDIR_MASK NS_CMPRSFLGS -#define NAMESERVER_PORT NS_DEFAULTPORT - -#define S_ZONE ns_s_zn -#define S_PREREQ ns_s_pr -#define S_UPDATE ns_s_ud -#define S_ADDT ns_s_ar - -#define QUERY ns_o_query -#define IQUERY ns_o_iquery -#define STATUS ns_o_status -#define NS_NOTIFY_OP ns_o_notify -#define NS_UPDATE_OP ns_o_update - -#define NOERROR ns_r_noerror -#define FORMERR ns_r_formerr -#define SERVFAIL ns_r_servfail -#define NXDOMAIN ns_r_nxdomain -#define NOTIMP ns_r_notimpl -#define REFUSED ns_r_refused -#define YXDOMAIN ns_r_yxdomain -#define YXRRSET ns_r_yxrrset -#define NXRRSET ns_r_nxrrset -#define NOTAUTH ns_r_notauth -#define NOTZONE ns_r_notzone - -#define DELETE ns_uop_delete -#define ADD ns_uop_add - -#define T_A ns_t_a -#define T_NS ns_t_ns -#define T_MD ns_t_md -#define T_MF ns_t_mf -#define T_CNAME ns_t_cname -#define T_SOA ns_t_soa -#define T_MB ns_t_mb -#define T_MG ns_t_mg -#define T_MR ns_t_mr -#define T_NULL ns_t_null -#define T_WKS ns_t_wks -#define T_PTR ns_t_ptr -#define T_HINFO ns_t_hinfo -#define T_MINFO ns_t_minfo -#define T_MX ns_t_mx -#define T_TXT ns_t_txt -#define T_RP ns_t_rp -#define T_AFSDB ns_t_afsdb -#define T_X25 ns_t_x25 -#define T_ISDN ns_t_isdn -#define T_RT ns_t_rt -#define T_NSAP ns_t_nsap -#define T_NSAP_PTR ns_t_nsap_ptr -#define T_SIG ns_t_sig -#define T_KEY ns_t_key -#define T_PX ns_t_px -#define T_GPOS ns_t_gpos -#define T_AAAA ns_t_aaaa -#define T_LOC ns_t_loc -#define T_NXT ns_t_nxt -#define T_EID ns_t_eid -#define T_NIMLOC ns_t_nimloc -#define T_SRV ns_t_srv -#define T_ATMA ns_t_atma -#define T_NAPTR ns_t_naptr -#define T_A6 ns_t_a6 -#define T_DNAME ns_t_dname -#define T_TSIG ns_t_tsig -#define T_IXFR ns_t_ixfr -#define T_AXFR ns_t_axfr -#define T_MAILB ns_t_mailb -#define T_MAILA ns_t_maila -#define T_ANY ns_t_any - -#define C_IN ns_c_in -#define C_CHAOS ns_c_chaos -#define C_HS ns_c_hs -#define C_NONE ns_c_none -#define C_ANY ns_c_any - -#define GETSHORT NS_GET16 -#define GETLONG NS_GET32 -#define PUTSHORT NS_PUT16 -#define PUTLONG NS_PUT32 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/fcntl.h b/lib/libc/wasi/libc-top-half/musl/include/fcntl.h index 15bef28854b3..eef21db1dcbe 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/fcntl.h +++ b/lib/libc/wasi/libc-top-half/musl/include/fcntl.h @@ -203,7 +203,6 @@ struct f_owner_ex { #endif #ifdef __wasilibc_unmodified_upstream /* WASI has no fallocate */ int fallocate(int, int, off_t, off_t); -#define fallocate64 fallocate #endif #ifdef __wasilibc_unmodified_upstream /* WASI has no name_to_handle_at */ int name_to_handle_at(int, const char *, struct file_handle *, int *, int); @@ -237,6 +236,11 @@ ssize_t tee(int, int, size_t, unsigned); #define posix_fadvise64 posix_fadvise #define posix_fallocate64 posix_fallocate #define off64_t off_t +#ifdef __wasilibc_unmodified_upstream /* WASI has no fallocate */ +#if defined(_GNU_SOURCE) +#define fallocate64 fallocate +#endif +#endif #endif #ifdef __cplusplus diff --git a/lib/libc/wasi/libc-top-half/musl/include/limits.h b/lib/libc/wasi/libc-top-half/musl/include/limits.h index 2fc0d2a38afa..c160568cdece 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/limits.h +++ b/lib/libc/wasi/libc-top-half/musl/include/limits.h @@ -65,11 +65,9 @@ /* Implementation choices... */ -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #define PTHREAD_KEYS_MAX 128 #define PTHREAD_STACK_MIN 2048 #define PTHREAD_DESTRUCTOR_ITERATIONS 4 -#endif #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) #define SEM_VALUE_MAX 0x7fffffff #define SEM_NSEMS_MAX 256 diff --git a/lib/libc/wasi/libc-top-half/musl/include/netdb.h b/lib/libc/wasi/libc-top-half/musl/include/netdb.h new file mode 100644 index 000000000000..35a9e0d15e98 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/include/netdb.h @@ -0,0 +1,162 @@ +#ifndef _NETDB_H +#define _NETDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_size_t +#include +#endif + +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; + +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_V4MAPPED 0x08 +#define AI_ALL 0x10 +#define AI_ADDRCONFIG 0x20 +#define AI_NUMERICSERV 0x400 + + +#define NI_NUMERICHOST 0x01 +#define NI_NUMERICSERV 0x02 +#define NI_NOFQDN 0x04 +#define NI_NAMEREQD 0x08 +#define NI_DGRAM 0x10 +#define NI_NUMERICSCOPE 0x100 + +#define EAI_BADFLAGS -1 +#define EAI_NONAME -2 +#define EAI_AGAIN -3 +#define EAI_FAIL -4 +#define EAI_NODATA -5 +#define EAI_FAMILY -6 +#define EAI_SOCKTYPE -7 +#define EAI_SERVICE -8 +#define EAI_MEMORY -10 +#define EAI_SYSTEM -11 +#define EAI_OVERFLOW -12 + +int getaddrinfo (const char *__restrict, const char *__restrict, const struct addrinfo *__restrict, struct addrinfo **__restrict); +void freeaddrinfo (struct addrinfo *); +int getnameinfo (const struct sockaddr *__restrict, socklen_t, char *__restrict, socklen_t, char *__restrict, socklen_t, int); +const char *gai_strerror(int); + + +/* Legacy functions follow (marked OBsolete in SUS) */ + +struct netent { + char *n_name; + char **n_aliases; + int n_addrtype; + uint32_t n_net; +}; + +struct hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; +#define h_addr h_addr_list[0] + +struct servent { + char *s_name; + char **s_aliases; + int s_port; + char *s_proto; +}; + +struct protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +void sethostent (int); +void endhostent (void); +struct hostent *gethostent (void); + +void setnetent (int); +void endnetent (void); +struct netent *getnetent (void); +struct netent *getnetbyaddr (uint32_t, int); +struct netent *getnetbyname (const char *); + +void setservent (int); +void endservent (void); +struct servent *getservent (void); +struct servent *getservbyname (const char *, const char *); +struct servent *getservbyport (int, const char *); + +void setprotoent (int); +void endprotoent (void); +struct protoent *getprotoent (void); +struct protoent *getprotobyname (const char *); +struct protoent *getprotobynumber (int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_POSIX_SOURCE) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE+0 < 200809L) \ + || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 < 700) +struct hostent *gethostbyname (const char *); +struct hostent *gethostbyaddr (const void *, socklen_t, int); +#ifdef __GNUC__ +__attribute__((const)) +#endif +#ifdef __wasilibc_unmodified_upstream +int *__h_errno_location(void); +#define h_errno (*__h_errno_location()) +#elif (defined __wasilibc_use_wasip2) +extern _Thread_local int h_errno; +#define h_errno h_errno +#endif +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 +#define NO_ADDRESS NO_DATA +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +void herror(const char *); +const char *hstrerror(int); +int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *); +int gethostbyname2_r(const char *, int, struct hostent *, char *, size_t, struct hostent **, int *); +struct hostent *gethostbyname2(const char *, int); +int gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, char *, size_t, struct hostent **, int *); +int getservbyport_r(int, const char *, struct servent *, char *, size_t, struct servent **); +int getservbyname_r(const char *, const char *, struct servent *, char *, size_t, struct servent **); +#define EAI_NODATA -5 +#define EAI_ADDRFAMILY -9 +#define EAI_INPROGRESS -100 +#define EAI_CANCELED -101 +#define EAI_NOTCANCELED -102 +#define EAI_ALLDONE -103 +#define EAI_INTR -104 +#define EAI_IDN_ENCODE -105 +#define NI_MAXHOST 255 +#define NI_MAXSERV 32 +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/poll.h b/lib/libc/wasi/libc-top-half/musl/include/poll.h index cdbd29a2102e..00e2537ae082 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/poll.h +++ b/lib/libc/wasi/libc-top-half/musl/include/poll.h @@ -48,7 +48,7 @@ struct pollfd { int poll (struct pollfd *, nfds_t, int); -#ifdef _GNU_SOURCE +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) #define __NEED_time_t #define __NEED_struct_timespec #define __NEED_sigset_t @@ -57,7 +57,7 @@ int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *); #endif #if _REDIR_TIME64 -#ifdef _GNU_SOURCE +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) __REDIR(ppoll, __ppoll_time64); #endif #endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/pthread.h b/lib/libc/wasi/libc-top-half/musl/include/pthread.h new file mode 100644 index 000000000000..111c1fbf8c1c --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/include/pthread.h @@ -0,0 +1,267 @@ +#ifndef _PTHREAD_H +#define _PTHREAD_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_time_t +#define __NEED_clockid_t +#define __NEED_struct_timespec +#define __NEED_sigset_t +#define __NEED_pthread_t +#define __NEED_pthread_attr_t +#define __NEED_pthread_mutexattr_t +#define __NEED_pthread_condattr_t +#define __NEED_pthread_rwlockattr_t +#define __NEED_pthread_barrierattr_t +#define __NEED_pthread_mutex_t +#define __NEED_pthread_cond_t +#define __NEED_pthread_rwlock_t +#define __NEED_pthread_barrier_t +#define __NEED_pthread_spinlock_t +#define __NEED_pthread_key_t +#define __NEED_pthread_once_t +#define __NEED_size_t + +#include + +#include +#include + +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_DEFAULT 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_ERRORCHECK 2 + +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + +#define PTHREAD_PRIO_NONE 0 +#define PTHREAD_PRIO_INHERIT 1 +#define PTHREAD_PRIO_PROTECT 2 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + + +#define PTHREAD_MUTEX_INITIALIZER {{{0}}} +#define PTHREAD_RWLOCK_INITIALIZER {{{0}}} +#define PTHREAD_COND_INITIALIZER {{{0}}} +#define PTHREAD_ONCE_INIT 0 + + +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +#define PTHREAD_CANCELED ((void *)-1) + + +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) + + +#define PTHREAD_NULL ((pthread_t)0) + + +#ifdef __wasilibc_unmodified_upstream +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); +int pthread_detach(pthread_t); +_Noreturn void pthread_exit(void *); +int pthread_join(pthread_t, void **); +#else +#if defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); +int pthread_detach(pthread_t); +int pthread_join(pthread_t, void **); +#else +#define pthread_create(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#define pthread_detach(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#define pthread_join(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#endif +#endif + +#ifdef __GNUC__ +__attribute__((const)) +#endif +pthread_t pthread_self(void); + +int pthread_equal(pthread_t, pthread_t); +#ifndef __cplusplus +#define pthread_equal(x,y) ((x)==(y)) +#endif + +int pthread_setcancelstate(int, int *); +int pthread_setcanceltype(int, int *); +void pthread_testcancel(void); +#ifdef __wasilibc_unmodified_upstream /* WASI has no cancellation support. */ +int pthread_cancel(pthread_t); +#endif + +#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)); + +int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); +int pthread_mutex_lock(pthread_mutex_t *); +int pthread_mutex_unlock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); +int pthread_mutex_timedlock(pthread_mutex_t *__restrict, const struct timespec *__restrict); +int pthread_mutex_destroy(pthread_mutex_t *); +int pthread_mutex_consistent(pthread_mutex_t *); + +int pthread_mutex_getprioceiling(const pthread_mutex_t *__restrict, int *__restrict); +int pthread_mutex_setprioceiling(pthread_mutex_t *__restrict, int, int *__restrict); + +int pthread_cond_init(pthread_cond_t *__restrict, const pthread_condattr_t *__restrict); +int pthread_cond_destroy(pthread_cond_t *); +int pthread_cond_wait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict); +int pthread_cond_timedwait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict, const struct timespec *__restrict); +int pthread_cond_broadcast(pthread_cond_t *); +int pthread_cond_signal(pthread_cond_t *); + +int pthread_rwlock_init(pthread_rwlock_t *__restrict, const pthread_rwlockattr_t *__restrict); +int pthread_rwlock_destroy(pthread_rwlock_t *); +int pthread_rwlock_rdlock(pthread_rwlock_t *); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *); +int pthread_rwlock_timedrdlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +int pthread_rwlock_wrlock(pthread_rwlock_t *); +int pthread_rwlock_trywrlock(pthread_rwlock_t *); +int pthread_rwlock_timedwrlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +int pthread_rwlock_unlock(pthread_rwlock_t *); + +int pthread_spin_init(pthread_spinlock_t *, int); +int pthread_spin_destroy(pthread_spinlock_t *); +int pthread_spin_lock(pthread_spinlock_t *); +int pthread_spin_trylock(pthread_spinlock_t *); +int pthread_spin_unlock(pthread_spinlock_t *); + +int pthread_barrier_init(pthread_barrier_t *__restrict, const pthread_barrierattr_t *__restrict, unsigned); +int pthread_barrier_destroy(pthread_barrier_t *); +int pthread_barrier_wait(pthread_barrier_t *); + +int pthread_key_create(pthread_key_t *, void (*)(void *)); +int pthread_key_delete(pthread_key_t); +void *pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void *); + +int pthread_attr_init(pthread_attr_t *); +int pthread_attr_destroy(pthread_attr_t *); + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setguardsize(pthread_attr_t *, size_t); +int pthread_attr_getstacksize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setstacksize(pthread_attr_t *, size_t); +int pthread_attr_getdetachstate(const pthread_attr_t *, int *); +int pthread_attr_setdetachstate(pthread_attr_t *, int); +int pthread_attr_getstack(const pthread_attr_t *__restrict, void **__restrict, size_t *__restrict); +int pthread_attr_setstack(pthread_attr_t *, void *, size_t); +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); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_init(pthread_mutexattr_t *); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); +int pthread_mutexattr_settype(pthread_mutexattr_t *, int); + +int pthread_condattr_init(pthread_condattr_t *); +int pthread_condattr_destroy(pthread_condattr_t *); +int pthread_condattr_setclock(pthread_condattr_t *, clockid_t); +int pthread_condattr_setpshared(pthread_condattr_t *, int); +int pthread_condattr_getclock(const pthread_condattr_t *__restrict, clockid_t *__restrict); +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict, int *__restrict); + +int pthread_rwlockattr_init(pthread_rwlockattr_t *); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict, int *__restrict); + +int pthread_barrierattr_destroy(pthread_barrierattr_t *); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict, int *__restrict); +int pthread_barrierattr_init(pthread_barrierattr_t *); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); + +int pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); + +int pthread_getconcurrency(void); +int pthread_setconcurrency(int); + +int pthread_getcpuclockid(pthread_t, clockid_t *); + +struct __ptcb { + void (*__f)(void *); + void *__x; + struct __ptcb *__next; +}; + +void _pthread_cleanup_push(struct __ptcb *, void (*)(void *), void *); +void _pthread_cleanup_pop(struct __ptcb *, int); + +#define pthread_cleanup_push(f, x) do { struct __ptcb __cb; _pthread_cleanup_push(&__cb, f, x); +#define pthread_cleanup_pop(r) _pthread_cleanup_pop(&__cb, (r)); } while(0) + +#ifdef _GNU_SOURCE +struct cpu_set_t; +int pthread_getaffinity_np(pthread_t, size_t, struct cpu_set_t *); +int pthread_setaffinity_np(pthread_t, size_t, const struct cpu_set_t *); +int pthread_getattr_np(pthread_t, pthread_attr_t *); +int pthread_setname_np(pthread_t, const char *); +int pthread_getname_np(pthread_t, char *, size_t); +int pthread_getattr_default_np(pthread_attr_t *); +int pthread_setattr_default_np(const pthread_attr_t *); +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) +int pthread_tryjoin_np(pthread_t, void **); +int pthread_timedjoin_np(pthread_t, void **, const struct timespec *); +#else +#define pthread_tryjoin_np(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#define pthread_timedjoin_np(...) ({ _Static_assert(0, "This function is not available on a single-threaded target; switch to a multi-threaded target with -pthread or enable a stub implementation by undefining _WASI_STRICT_PTHREAD"); 0;}) +#endif +#endif + +#if _REDIR_TIME64 +__REDIR(pthread_mutex_timedlock, __pthread_mutex_timedlock_time64); +__REDIR(pthread_cond_timedwait, __pthread_cond_timedwait_time64); +__REDIR(pthread_rwlock_timedrdlock, __pthread_rwlock_timedrdlock_time64); +__REDIR(pthread_rwlock_timedwrlock, __pthread_rwlock_timedwrlock_time64); +#ifdef _GNU_SOURCE +__REDIR(pthread_timedjoin_np, __pthread_timedjoin_np_time64); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/sched.h b/lib/libc/wasi/libc-top-half/musl/include/sched.h index a3a7f569d9d8..407d604af3be 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/sched.h +++ b/lib/libc/wasi/libc-top-half/musl/include/sched.h @@ -16,7 +16,6 @@ extern "C" { #include -#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */ struct sched_param { int sched_priority; int __reserved1; @@ -31,6 +30,7 @@ struct sched_param { int __reserved3; }; +#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */ int sched_get_priority_max(int); int sched_get_priority_min(int); int sched_getparam(pid_t, struct sched_param *); @@ -127,7 +127,7 @@ __CPU_op_func_S(XOR, ^) #define CPU_ALLOC(n) ((cpu_set_t *)calloc(1,CPU_ALLOC_SIZE(n))) #define CPU_FREE(set) free(set) -#define CPU_SETSIZE 128 +#define CPU_SETSIZE 1024 #define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set) #define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set) diff --git a/lib/libc/wasi/libc-top-half/musl/include/stdc-predef.h b/lib/libc/wasi/libc-top-half/musl/include/stdc-predef.h deleted file mode 100644 index af1a27998f90..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/include/stdc-predef.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _STDC_PREDEF_H -#define _STDC_PREDEF_H - -#define __STDC_ISO_10646__ 201206L - -#if !defined(__GCC_IEC_559) || __GCC_IEC_559 > 0 -#define __STDC_IEC_559__ 1 -#endif - -#define __STDC_UTF_16__ 1 -#define __STDC_UTF_32__ 1 - -#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/stdlib.h b/lib/libc/wasi/libc-top-half/musl/include/stdlib.h index 553e9aeabff7..c5b6cd2d980a 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/stdlib.h +++ b/lib/libc/wasi/libc-top-half/musl/include/stdlib.h @@ -108,7 +108,7 @@ size_t __ctype_get_mb_cur_max(void); #define WTERMSIG(s) ((s) & 0x7f) #define WSTOPSIG(s) WEXITSTATUS(s) #define WIFEXITED(s) (!WTERMSIG(s)) -#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00) +#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00) #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu) #endif @@ -190,7 +190,7 @@ long double strtold_l(const char *__restrict, char **__restrict, struct __locale #endif #ifdef __wasilibc_unmodified_upstream /* WASI has no temp directories */ -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define mkstemp64 mkstemp #define mkostemp64 mkostemp #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) diff --git a/lib/libc/wasi/libc-top-half/musl/include/string.h b/lib/libc/wasi/libc-top-half/musl/include/string.h index dc47b7aee028..7b3c3b9415f2 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/string.h +++ b/lib/libc/wasi/libc-top-half/musl/include/string.h @@ -92,6 +92,7 @@ char *strsignal(int); char *strerror_l (int, locale_t); int strcoll_l (const char *, const char *, locale_t); size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t); +void *memmem(const void *, size_t, const void *, size_t); #endif #if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ @@ -111,14 +112,8 @@ void explicit_bzero (void *, size_t); int strverscmp (const char *, const char *); char *strchrnul(const char *, int); char *strcasestr(const char *, const char *); -void *memmem(const void *, size_t, const void *, size_t); void *memrchr(const void *, int, size_t); void *mempcpy(void *, const void *, size_t); -#ifdef __wasilibc_unmodified_upstream /* avoid unprototyped decls; use */ -#ifndef __cplusplus -char *basename(); -#endif -#endif #endif #ifdef __cplusplus diff --git a/lib/libc/wasi/libc-top-half/musl/include/strings.h b/lib/libc/wasi/libc-top-half/musl/include/strings.h deleted file mode 100644 index db0960b4eb87..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/include/strings.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _STRINGS_H -#define _STRINGS_H - -#ifdef __cplusplus -extern "C" { -#endif - - -#define __NEED_size_t -#define __NEED_locale_t -#include - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_POSIX_SOURCE) \ - || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE+0 < 200809L) \ - || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 < 700) -int bcmp (const void *, const void *, size_t); -void bcopy (const void *, void *, size_t); -void bzero (void *, size_t); -char *index (const char *, int); -char *rindex (const char *, int); -#endif - -#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) -int ffs (int); -int ffsl (long); -int ffsll (long long); -#endif - -int strcasecmp (const char *, const char *); -int strncasecmp (const char *, const char *, size_t); - -int strcasecmp_l (const char *, const char *, locale_t); -int strncasecmp_l (const char *, const char *, size_t, locale_t); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/sys/sendfile.h b/lib/libc/wasi/libc-top-half/musl/include/sys/sendfile.h new file mode 100644 index 000000000000..e7570d8e5c4f --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/include/sys/sendfile.h @@ -0,0 +1,22 @@ +#ifndef _SYS_SENDFILE_H +#define _SYS_SENDFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +ssize_t sendfile(int, int, off_t *, size_t); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define sendfile64 sendfile +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/sys/stat.h b/lib/libc/wasi/libc-top-half/musl/include/sys/stat.h index c0090f7509fb..01d30ddaf3d2 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/sys/stat.h +++ b/lib/libc/wasi/libc-top-half/musl/include/sys/stat.h @@ -18,6 +18,13 @@ extern "C" { #define __NEED_blkcnt_t #define __NEED_struct_timespec +#ifdef _GNU_SOURCE +#define __NEED_int64_t +#define __NEED_uint64_t +#define __NEED_uint32_t +#define __NEED_uint16_t +#endif + #include #include @@ -112,6 +119,56 @@ int lchmod(const char *, mode_t); #define S_IEXEC S_IXUSR #endif +#ifdef __wasilibc_unmodified_upstream /* WASI has no statx */ +#if defined(_GNU_SOURCE) +#define STATX_TYPE 1U +#define STATX_MODE 2U +#define STATX_NLINK 4U +#define STATX_UID 8U +#define STATX_GID 0x10U +#define STATX_ATIME 0x20U +#define STATX_MTIME 0x40U +#define STATX_CTIME 0x80U +#define STATX_INO 0x100U +#define STATX_SIZE 0x200U +#define STATX_BLOCKS 0x400U +#define STATX_BASIC_STATS 0x7ffU +#define STATX_BTIME 0x800U +#define STATX_ALL 0xfffU + +struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec, __pad; +}; + +struct statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __pad0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t __pad1[14]; +}; + +int statx(int, const char *__restrict, int, unsigned, struct statx *__restrict); +#endif +#endif + #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) #define stat64 stat #define fstat64 fstat diff --git a/lib/libc/wasi/libc-top-half/musl/include/sys/statfs.h b/lib/libc/wasi/libc-top-half/musl/include/sys/statfs.h new file mode 100644 index 000000000000..6f4c6230f7a0 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/include/sys/statfs.h @@ -0,0 +1,32 @@ +#ifndef _SYS_STATFS_H +#define _SYS_STATFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +typedef struct __fsid_t { + int __val[2]; +} fsid_t; + +#include + +int statfs (const char *, struct statfs *); +int fstatfs (int, struct statfs *); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define statfs64 statfs +#define fstatfs64 fstatfs +#define fsblkcnt64_t fsblkcnt_t +#define fsfilcnt64_t fsfilcnt_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/include/sys/statvfs.h b/lib/libc/wasi/libc-top-half/musl/include/sys/statvfs.h index 793490b6dc8c..6cf35c5941b7 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/sys/statvfs.h +++ b/lib/libc/wasi/libc-top-half/musl/include/sys/statvfs.h @@ -23,7 +23,8 @@ struct statvfs { unsigned long f_fsid; #endif unsigned long f_flag, f_namemax; - int __reserved[6]; + unsigned int f_type; + int __reserved[5]; }; int statvfs (const char *__restrict, struct statvfs *__restrict); diff --git a/lib/libc/wasi/libc-top-half/musl/include/sys/uio.h b/lib/libc/wasi/libc-top-half/musl/include/sys/uio.h index 00f73a2f0525..f102d5a56e42 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/sys/uio.h +++ b/lib/libc/wasi/libc-top-half/musl/include/sys/uio.h @@ -36,9 +36,18 @@ ssize_t pwritev (int, const struct iovec *, int, off_t); #endif #endif +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have these Linux-specific functions #ifdef _GNU_SOURCE ssize_t process_vm_writev(pid_t, const struct iovec *, unsigned long, const struct iovec *, unsigned long, unsigned long); ssize_t process_vm_readv(pid_t, const struct iovec *, unsigned long, const struct iovec *, unsigned long, unsigned long); +ssize_t preadv2 (int, const struct iovec *, int, off_t, int); +ssize_t pwritev2 (int, const struct iovec *, int, off_t, int); +#define RWF_HIPRI 0x00000001 +#define RWF_DSYNC 0x00000002 +#define RWF_SYNC 0x00000004 +#define RWF_NOWAIT 0x00000008 +#define RWF_APPEND 0x00000010 +#endif #endif #ifdef __cplusplus diff --git a/lib/libc/wasi/libc-top-half/musl/include/unistd.h b/lib/libc/wasi/libc-top-half/musl/include/unistd.h index 0be83e368c4c..c3158e6e6492 100644 --- a/lib/libc/wasi/libc-top-half/musl/include/unistd.h +++ b/lib/libc/wasi/libc-top-half/musl/include/unistd.h @@ -336,15 +336,21 @@ pid_t gettid(void); #endif #define _POSIX_VDISABLE 0 -#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) #define _POSIX_THREADS _POSIX_VERSION -#endif #define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION #define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#endif +#if defined(__wasilibc_unmodified_upstream) /* wasi-libc doesn't provide pthread_attr_{get,set}stackaddr */ #define _POSIX_THREAD_ATTR_STACKADDR _POSIX_VERSION +#endif +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) || !defined(_WASI_STRICT_PTHREAD) #define _POSIX_THREAD_ATTR_STACKSIZE _POSIX_VERSION +#endif +#if defined(__wasilibc_unmodified_upstream) /* WASI has no scheduling control, and wasi-libc doesn't provide pthread_getcpuclockid */ #define _POSIX_THREAD_PRIORITY_SCHEDULING _POSIX_VERSION #define _POSIX_THREAD_CPUTIME _POSIX_VERSION +#endif #define _POSIX_TIMERS _POSIX_VERSION #define _POSIX_TIMEOUTS _POSIX_VERSION #define _POSIX_MONOTONIC_CLOCK _POSIX_VERSION @@ -529,6 +535,8 @@ pid_t gettid(void); #define _SC_XOPEN_STREAMS 246 #define _SC_THREAD_ROBUST_PRIO_INHERIT 247 #define _SC_THREAD_ROBUST_PRIO_PROTECT 248 +#define _SC_MINSIGSTKSZ 249 +#define _SC_SIGSTKSZ 250 #define _CS_PATH 0 #define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 @@ -571,6 +579,8 @@ pid_t gettid(void); #define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 #define _CS_V6_ENV 1148 #define _CS_V7_ENV 1149 +#define _CS_POSIX_V7_THREADS_CFLAGS 1150 +#define _CS_POSIX_V7_THREADS_LDFLAGS 1151 #ifdef __cplusplus } diff --git a/lib/libc/wasi/libc-top-half/musl/include/wasi/libc-busywait.h b/lib/libc/wasi/libc-top-half/musl/include/wasi/libc-busywait.h new file mode 100644 index 000000000000..c90017b8e03f --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/include/wasi/libc-busywait.h @@ -0,0 +1,15 @@ +#ifndef __wasi_libc_busywait_h +#define __wasi_libc_busywait_h + +#ifdef __cplusplus +extern "C" { +#endif + +/// Enable busywait in futex on current thread. +void __wasilibc_enable_futex_busywait_on_current_thread(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/conf/confstr.c b/lib/libc/wasi/libc-top-half/musl/src/conf/confstr.c deleted file mode 100644 index 02cb1aa252db..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/src/conf/confstr.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include - -size_t confstr(int name, char *buf, size_t len) -{ - const char *s = ""; - if (!name) { - s = "/bin:/usr/bin"; - } else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>33U) { - errno = EINVAL; - return 0; - } - // snprintf is overkill but avoid wasting code size to implement - // this completely useless function and its truncation semantics - return snprintf(buf, len, "%s", s) + 1; -} diff --git a/lib/libc/wasi/libc-top-half/musl/src/conf/sysconf.c b/lib/libc/wasi/libc-top-half/musl/src/conf/sysconf.c index c72174f27cb9..a935853cbd8b 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/conf/sysconf.c +++ b/lib/libc/wasi/libc-top-half/musl/src/conf/sysconf.c @@ -9,6 +9,7 @@ #endif #include #ifdef __wasilibc_unmodified_upstream +#include #include "syscall.h" #endif #include "libc.h" @@ -29,6 +30,8 @@ #define JT_AVPHYS_PAGES JT(9) #define JT_ZERO JT(10) #define JT_DELAYTIMER_MAX JT(11) +#define JT_MINSIGSTKSZ JT(12) +#define JT_SIGSTKSZ JT(13) #define RLIM(x) (-32768|(RLIMIT_ ## x)) @@ -211,6 +214,9 @@ long sysconf(int name) [_SC_XOPEN_STREAMS] = JT_ZERO, [_SC_THREAD_ROBUST_PRIO_INHERIT] = -1, [_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, + + [_SC_MINSIGSTKSZ] = JT_MINSIGSTKSZ, + [_SC_SIGSTKSZ] = JT_SIGSTKSZ, }; if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) { @@ -278,5 +284,14 @@ long sysconf(int name) case JT_ZERO & 255: return 0; } +#ifdef __wasilibc_unmodified_upstream // WASI has no auxv + case JT_MINSIGSTKSZ & 255: + case JT_SIGSTKSZ & 255: ; + long val = __getauxval(AT_MINSIGSTKSZ); + if (val < MINSIGSTKSZ) val = MINSIGSTKSZ; + if (values[name] == JT_SIGSTKSZ) + val += SIGSTKSZ - MINSIGSTKSZ; + return val; +#endif return values[name]; } diff --git a/lib/libc/wasi/libc-top-half/musl/src/env/__stack_chk_fail.c b/lib/libc/wasi/libc-top-half/musl/src/env/__stack_chk_fail.c index cb7a3f391191..7c39c22e680e 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/env/__stack_chk_fail.c +++ b/lib/libc/wasi/libc-top-half/musl/src/env/__stack_chk_fail.c @@ -38,12 +38,22 @@ hidden void __stack_chk_fail_local(void); weak_alias(__stack_chk_fail, __stack_chk_fail_local); #ifndef __wasilibc_unmodified_upstream +#ifdef __wasilibc_use_wasip2 +# include +#else # include +#endif __attribute__((constructor(60))) static void __wasilibc_init_ssp(void) { uintptr_t entropy; +#ifdef __wasilibc_use_wasip2 + int len = sizeof(uintptr_t); + + int r = __wasilibc_random(&entropy, len); +#else int r = __wasi_random_get((uint8_t *)&entropy, sizeof(uintptr_t)); +#endif __init_ssp(r ? NULL : &entropy); } #endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/include/pthread.h b/lib/libc/wasi/libc-top-half/musl/src/include/pthread.h new file mode 100644 index 000000000000..0aba813e9a47 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/include/pthread.h @@ -0,0 +1,31 @@ +#ifndef PTHREAD_H +#define PTHREAD_H + +#include "../../include/pthread.h" + +hidden int __pthread_once(pthread_once_t *, void (*)(void)); +hidden void __pthread_testcancel(void); +hidden int __pthread_setcancelstate(int, int *); +hidden int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict); +#ifdef __wasilibc_unmodified_upstream +hidden _Noreturn void __pthread_exit(void *); +#endif +hidden int __pthread_join(pthread_t, void **); +hidden int __pthread_mutex_lock(pthread_mutex_t *); +hidden int __pthread_mutex_trylock(pthread_mutex_t *); +hidden int __pthread_mutex_trylock_owner(pthread_mutex_t *); +hidden int __pthread_mutex_timedlock(pthread_mutex_t *restrict, const struct timespec *restrict); +hidden int __pthread_mutex_unlock(pthread_mutex_t *); +hidden int __private_cond_signal(pthread_cond_t *, int); +hidden int __pthread_cond_timedwait(pthread_cond_t *restrict, pthread_mutex_t *restrict, const struct timespec *restrict); +hidden int __pthread_key_create(pthread_key_t *, void (*)(void *)); +hidden int __pthread_key_delete(pthread_key_t); +hidden int __pthread_rwlock_rdlock(pthread_rwlock_t *); +hidden int __pthread_rwlock_tryrdlock(pthread_rwlock_t *); +hidden int __pthread_rwlock_timedrdlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +hidden int __pthread_rwlock_wrlock(pthread_rwlock_t *); +hidden int __pthread_rwlock_trywrlock(pthread_rwlock_t *); +hidden int __pthread_rwlock_timedwrlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +hidden int __pthread_rwlock_unlock(pthread_rwlock_t *); + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/include/time.h b/lib/libc/wasi/libc-top-half/musl/src/include/time.h new file mode 100644 index 000000000000..cbabde476790 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/include/time.h @@ -0,0 +1,15 @@ +#ifndef TIME_H +#define TIME_H + +#include "../../include/time.h" + +hidden int __clock_gettime(clockid_t, struct timespec *); +hidden int __clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *); + +hidden char *__asctime_r(const struct tm *, char *); +hidden struct tm *__gmtime_r(const time_t *restrict, struct tm *restrict); +hidden struct tm *__localtime_r(const time_t *restrict, struct tm *restrict); + +hidden size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t); + +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/internal/fork_impl.h b/lib/libc/wasi/libc-top-half/musl/src/internal/fork_impl.h index f6b3aa060e1b..16154e381ae8 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/internal/fork_impl.h +++ b/lib/libc/wasi/libc-top-half/musl/src/internal/fork_impl.h @@ -3,7 +3,6 @@ #ifdef __wasilibc_unmodified_upstream extern hidden volatile int *const __at_quick_exit_lockptr; extern hidden volatile int *const __atexit_lockptr; -extern hidden volatile int *const __dlerror_lockptr; extern hidden volatile int *const __gettext_lockptr; extern hidden volatile int *const __locale_lockptr; extern hidden volatile int *const __random_lockptr; @@ -18,4 +17,7 @@ extern hidden volatile int *const __vmlock_lockptr; hidden void __malloc_atfork(int); hidden void __ldso_atfork(int); +hidden void __pthread_key_atfork(int); + +hidden void __post_Fork(int); #endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/internal/ksigaction.h b/lib/libc/wasi/libc-top-half/musl/src/internal/ksigaction.h deleted file mode 100644 index 8ebd5938352e..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/src/internal/ksigaction.h +++ /dev/null @@ -1,13 +0,0 @@ -#include - -/* This is the structure used for the rt_sigaction syscall on most archs, - * but it can be overridden by a file with the same name in the top-level - * arch dir for a given arch, if necessary. */ -struct k_sigaction { - void (*handler)(int); - unsigned long flags; - void (*restorer)(void); - unsigned mask[2]; -}; - -hidden void __restore(), __restore_rt(); diff --git a/lib/libc/wasi/libc-top-half/musl/src/internal/locale_impl.h b/lib/libc/wasi/libc-top-half/musl/src/internal/locale_impl.h index 4649a43e090a..88f5dcf8f07c 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/internal/locale_impl.h +++ b/lib/libc/wasi/libc-top-half/musl/src/internal/locale_impl.h @@ -64,7 +64,7 @@ hidden char *__gettextdomain(void); &libc.current_locale; \ })) -#define CURRENT_UTF8 (!!libc.global_locale.cat[LC_CTYPE]) +#define CURRENT_UTF8 (!!CURRENT_LOCALE->cat[LC_CTYPE]) #endif #undef MB_CUR_MAX diff --git a/lib/libc/wasi/libc-top-half/musl/src/internal/pthread_impl.h b/lib/libc/wasi/libc-top-half/musl/src/internal/pthread_impl.h index 1e7b9741dba7..0106ac3855a2 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/internal/pthread_impl.h +++ b/lib/libc/wasi/libc-top-half/musl/src/internal/pthread_impl.h @@ -186,8 +186,10 @@ static inline void __wake(volatile void *addr, int cnt, int priv) __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); #else +#ifdef _REENTRANT __builtin_wasm_memory_atomic_notify((int*)addr, cnt); #endif +#endif } static inline void __futexwait(volatile void *addr, int val, int priv) { diff --git a/lib/libc/wasi/libc-top-half/musl/src/internal/syscall.h b/lib/libc/wasi/libc-top-half/musl/src/internal/syscall.h index 32e0e8ac3893..2665715aa9c9 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/internal/syscall.h +++ b/lib/libc/wasi/libc-top-half/musl/src/internal/syscall.h @@ -59,7 +59,7 @@ hidden long __syscall_ret(unsigned long), #define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__) #define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__)) -static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, long c, long d, long e, long f) +static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, syscall_arg_t b, syscall_arg_t c, syscall_arg_t d, syscall_arg_t e, syscall_arg_t f) { long r; if (cp) r = __syscall_cp(sys, a, b, c, d, e, f); @@ -72,9 +72,9 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l return r; } #define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \ - (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) + __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) #define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \ - (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) + __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) /* fixup legacy 16-bit junk */ @@ -202,43 +202,43 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l #define SYS_sendfile SYS_sendfile64 #endif -#ifndef SYS_timer_settime +#ifdef SYS_timer_settime32 #define SYS_timer_settime SYS_timer_settime32 #endif -#ifndef SYS_timer_gettime +#ifdef SYS_timer_gettime32 #define SYS_timer_gettime SYS_timer_gettime32 #endif -#ifndef SYS_timerfd_settime +#ifdef SYS_timerfd_settime32 #define SYS_timerfd_settime SYS_timerfd_settime32 #endif -#ifndef SYS_timerfd_gettime +#ifdef SYS_timerfd_gettime32 #define SYS_timerfd_gettime SYS_timerfd_gettime32 #endif -#ifndef SYS_clock_settime +#ifdef SYS_clock_settime32 #define SYS_clock_settime SYS_clock_settime32 #endif -#ifndef SYS_clock_gettime +#ifdef SYS_clock_gettime32 #define SYS_clock_gettime SYS_clock_gettime32 #endif -#ifndef SYS_clock_getres +#ifdef SYS_clock_getres_time32 #define SYS_clock_getres SYS_clock_getres_time32 #endif -#ifndef SYS_clock_nanosleep +#ifdef SYS_clock_nanosleep_time32 #define SYS_clock_nanosleep SYS_clock_nanosleep_time32 #endif -#ifndef SYS_gettimeofday +#ifdef SYS_gettimeofday_time32 #define SYS_gettimeofday SYS_gettimeofday_time32 #endif -#ifndef SYS_settimeofday +#ifdef SYS_settimeofday_time32 #define SYS_settimeofday SYS_settimeofday_time32 #endif @@ -392,6 +392,18 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l #define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__) #define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__)) +#ifdef SYS_wait4 +#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d) +#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d) +#else +hidden long __emulate_wait4(int, int *, int, void *, int); +#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0) +#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1) +#endif + +#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d)) +#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d)) + hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned); hidden void *__vdsosym(const char *, const char *); diff --git a/lib/libc/wasi/libc-top-half/musl/src/math/powl.c b/lib/libc/wasi/libc-top-half/musl/src/math/powl.c index c8463b7a51ef..25364d700c14 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/math/powl.c +++ b/lib/libc/wasi/libc-top-half/musl/src/math/powl.c @@ -216,25 +216,33 @@ long double powl(long double x, long double y) } if (x == 1.0) return 1.0; /* 1**y = 1, even if y is nan */ - if (x == -1.0 && !isfinite(y)) - return 1.0; /* -1**inf = 1 */ if (y == 0.0) return 1.0; /* x**0 = 1, even if x is nan */ if (y == 1.0) return x; - if (y >= LDBL_MAX) { - if (x > 1.0 || x < -1.0) - return INFINITY; - if (x != 0.0) - return 0.0; - } - if (y <= -LDBL_MAX) { - if (x > 1.0 || x < -1.0) + /* if y*log2(x) < log2(LDBL_TRUE_MIN)-1 then x^y uflows to 0 + if y*log2(x) > -log2(LDBL_TRUE_MIN)+1 > LDBL_MAX_EXP then x^y oflows + if |x|!=1 then |log2(x)| > |log(x)| > LDBL_EPSILON/2 so + x^y oflows/uflows if |y|*LDBL_EPSILON/2 > -log2(LDBL_TRUE_MIN)+1 */ + if (fabsl(y) > 2*(-LDBL_MIN_EXP+LDBL_MANT_DIG+1)/LDBL_EPSILON) { + /* y is not an odd int */ + if (x == -1.0) + return 1.0; + if (y == INFINITY) { + if (x > 1.0 || x < -1.0) + return INFINITY; return 0.0; - if (x != 0.0 || y == -INFINITY) + } + if (y == -INFINITY) { + if (x > 1.0 || x < -1.0) + return 0.0; return INFINITY; + } + if ((x > 1.0 || x < -1.0) == (y > 0)) + return huge * huge; + return twom10000 * twom10000; } - if (x >= LDBL_MAX) { + if (x == INFINITY) { if (y > 0.0) return INFINITY; return 0.0; @@ -257,7 +265,7 @@ long double powl(long double x, long double y) yoddint = 1; } - if (x <= -LDBL_MAX) { + if (x == -INFINITY) { if (y > 0.0) { if (yoddint) return -INFINITY; diff --git a/lib/libc/wasi/libc-top-half/musl/src/misc/nftw.c b/lib/libc/wasi/libc-top-half/musl/src/misc/nftw.c index ebfd61567adf..e32743b5ac63 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/misc/nftw.c +++ b/lib/libc/wasi/libc-top-half/musl/src/misc/nftw.c @@ -33,6 +33,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, int err; struct FTW lev; + st.st_dev = st.st_ino = 0; + if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st)) type = FTW_SLN; @@ -48,7 +50,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, type = FTW_F; } - if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) + if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev) return 0; new.chain = h; diff --git a/lib/libc/wasi/libc-top-half/musl/src/regex/glob.c b/lib/libc/wasi/libc-top-half/musl/src/regex/glob.c index 78063a469a70..435d12e43f68 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/regex/glob.c +++ b/lib/libc/wasi/libc-top-half/musl/src/regex/glob.c @@ -271,7 +271,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i if (append(&tail, pat, strlen(pat), 0)) return GLOB_NOSPACE; cnt++; - } else + } else if (!error) return GLOB_NOMATCH; } diff --git a/lib/libc/wasi/libc-top-half/musl/src/setjmp/wasm32/rt.c b/lib/libc/wasi/libc-top-half/musl/src/setjmp/wasm32/rt.c new file mode 100644 index 000000000000..24e4e3361844 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/setjmp/wasm32/rt.c @@ -0,0 +1,83 @@ +/* + * a runtime implementation for + * https://github.com/llvm/llvm-project/pull/84137 + * https://docs.google.com/document/d/1ZvTPT36K5jjiedF8MCXbEmYjULJjI723aOAks1IdLLg/edit + */ + +#include +#include + +/* + * function prototypes + */ +void __wasm_setjmp(void *env, uint32_t label, void *func_invocation_id); +uint32_t __wasm_setjmp_test(void *env, void *func_invocation_id); +void __wasm_longjmp(void *env, int val); + +/* + * jmp_buf should have large enough size and alignment to contain + * this structure. + */ +struct jmp_buf_impl { + void *func_invocation_id; + uint32_t label; + + /* + * this is a temorary storage used by the communication between + * __wasm_sjlj_longjmp and WebAssemblyLowerEmscriptenEHSjL-generated + * logic. + * ideally, this can be replaced with multivalue. + */ + struct arg { + void *env; + int val; + } arg; +}; + +void +__wasm_setjmp(void *env, uint32_t label, void *func_invocation_id) +{ + struct jmp_buf_impl *jb = env; + if (label == 0) { /* ABI contract */ + __builtin_trap(); + } + if (func_invocation_id == NULL) { /* sanity check */ + __builtin_trap(); + } + jb->func_invocation_id = func_invocation_id; + jb->label = label; +} + +uint32_t +__wasm_setjmp_test(void *env, void *func_invocation_id) +{ + struct jmp_buf_impl *jb = env; + if (jb->label == 0) { /* ABI contract */ + __builtin_trap(); + } + if (func_invocation_id == NULL) { /* sanity check */ + __builtin_trap(); + } + if (jb->func_invocation_id == func_invocation_id) { + return jb->label; + } + return 0; +} + +void +__wasm_longjmp(void *env, int val) +{ + struct jmp_buf_impl *jb = env; + struct arg *arg = &jb->arg; + /* + * C standard says: + * The longjmp function cannot cause the setjmp macro to return + * the value 0; if val is 0, the setjmp macro returns the value 1. + */ + if (val == 0) { + val = 1; + } + arg->env = env; + arg->val = val; + __builtin_wasm_throw(1, arg); /* 1 == C_LONGJMP */ +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/freopen.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/freopen.c index 5331db0d24fc..7c0ef085d9e0 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/freopen.c +++ b/lib/libc/wasi/libc-top-half/musl/src/stdio/freopen.c @@ -67,6 +67,8 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re fclose(f2); } + f->mode = 0; + f->locale = 0; FUNLOCK(f); return f; diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/open_wmemstream.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/open_wmemstream.c index 30ffcdfb6200..198d5d4390ad 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/open_wmemstream.c +++ b/lib/libc/wasi/libc-top-half/musl/src/stdio/open_wmemstream.c @@ -48,8 +48,12 @@ static off_t wms_seek(FILE *f, off_t off, int whence) static size_t wms_write(FILE *f, const unsigned char *buf, size_t len) { struct cookie *c = f->cookie; - size_t len2; + size_t len2 = f->wpos - f->wbase; wchar_t *newbuf; + if (len2) { + f->wpos = f->wbase; + if (wms_write(f, f->wbase, len2) < len2) return 0; + } if (len + c->pos >= c->space) { len2 = 2*c->space+1 | c->pos+len+1; if (len2 > SSIZE_MAX/4) return 0; diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/ungetc.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/ungetc.c deleted file mode 100644 index bc629d4ca511..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/ungetc.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "stdio_impl.h" - -int ungetc(int c, FILE *f) -{ - if (c == EOF) return c; - - FLOCK(f); - - if (!f->rpos) __toread(f); - if (!f->rpos || f->rpos <= f->buf - UNGET) { - FUNLOCK(f); - return EOF; - } - - *--f->rpos = c; - f->flags &= ~F_EOF; - - FUNLOCK(f); - return (unsigned char)c; -} diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/vfprintf.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/vfprintf.c index 7da2e50491ed..46a8a8c56ccb 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/vfprintf.c +++ b/lib/libc/wasi/libc-top-half/musl/src/stdio/vfprintf.c @@ -56,7 +56,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = CHAR, S('C') = INT, + S('c') = INT, S('C') = UINT, S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, @@ -66,7 +66,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = INT, S('s') = PTR, S('n') = PTR, + S('c') = UINT, S('s') = PTR, S('n') = PTR, S('l') = LLPRE, }, { /* 2: ll-prefixed */ S('d') = LLONG, S('i') = LLONG, @@ -152,7 +152,7 @@ static void pop_arg(union arg *arg, int type, va_list *ap) static void out(FILE *f, const char *s, size_t l) { - if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f); + if (!ferror(f)) __fwritex((void *)s, l, f); } static void pad(FILE *f, char c, int w, int l, int fl) @@ -476,7 +476,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, unsigned st, ps; int cnt=0, l=0; size_t i; - char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4]; + char buf[sizeof(uintmax_t)*3]; const char *prefix; int t, pl; wchar_t wc[2], *ws; @@ -517,8 +517,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, if (*s=='*') { if (isdigit(s[1]) && s[2]=='$') { l10n=1; - nl_type[s[1]-'0'] = INT; - w = nl_arg[s[1]-'0'].i; + if (!f) nl_type[s[1]-'0'] = INT, w = 0; + else w = nl_arg[s[1]-'0'].i; s+=3; } else if (!l10n) { w = f ? va_arg(*ap, int) : 0; @@ -530,8 +530,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, /* Read precision */ if (*s=='.' && s[1]=='*') { if (isdigit(s[2]) && s[3]=='$') { - nl_type[s[2]-'0'] = INT; - p = nl_arg[s[2]-'0'].i; + if (!f) nl_type[s[2]-'0'] = INT, p = 0; + else p = nl_arg[s[2]-'0'].i; s+=4; } else if (!l10n) { p = f ? va_arg(*ap, int) : 0; @@ -560,13 +560,18 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, if (st==NOARG) { if (argpos>=0) goto inval; } else { - if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; - else if (f) pop_arg(&arg, st, ap); + if (argpos>=0) { + if (!f) nl_type[argpos]=st; + else arg=nl_arg[argpos]; + } else if (f) pop_arg(&arg, st, ap); else return 0; } if (!f) continue; + /* Do not process any new directives once in error state. */ + if (ferror(f)) return -1; + z = buf + sizeof(buf); prefix = "-+ 0X0x"; pl = 0; @@ -622,6 +627,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, } p = MAX(p, z-a + !arg.i); break; + narrow_c: case 'c': *(a=z-(p=1))=arg.i; fl &= ~ZERO_PAD; @@ -636,6 +642,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, fl &= ~ZERO_PAD; break; case 'C': + if (!arg.i) goto narrow_c; wc[0] = arg.i; wc[1] = 0; arg.p = wc; @@ -713,7 +720,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) FLOCK(f); olderr = f->flags & F_ERR; - if (f->mode < 1) f->flags &= ~F_ERR; + f->flags &= ~F_ERR; if (!f->buf_size) { saved_buf = f->buf; f->buf = internal_buf; @@ -729,7 +736,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) f->buf_size = 0; f->wpos = f->wbase = f->wend = 0; } - if (f->flags & F_ERR) ret = -1; + if (ferror(f)) ret = -1; f->flags |= olderr; FUNLOCK(f); va_end(ap2); diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwprintf.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwprintf.c index e660fcc2fae3..ba64eeb053f2 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwprintf.c +++ b/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwprintf.c @@ -49,7 +49,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = CHAR, S('C') = INT, + S('c') = INT, S('C') = UINT, S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, @@ -59,7 +59,7 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, - S('c') = INT, S('s') = PTR, S('n') = PTR, + S('c') = UINT, S('s') = PTR, S('n') = PTR, S('l') = LLPRE, }, { /* 2: ll-prefixed */ S('d') = LLONG, S('i') = LLONG, @@ -144,7 +144,13 @@ static void pop_arg(union arg *arg, int type, va_list *ap) static void out(FILE *f, const wchar_t *s, size_t l) { - while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f); + while (l-- && !ferror(f)) fputwc(*s++, f); +} + +static void pad(FILE *f, int n, int fl) +{ + if ((fl & LEFT_ADJ) || !n || ferror(f)) return; + fprintf(f, "%*s", n, ""); } static int getint(wchar_t **s) { @@ -261,6 +267,10 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_ } if (!f) continue; + + /* Do not process any new directives once in error state. */ + if (ferror(f)) return -1; + t = s[-1]; if (ps && (t&15)==3) t&=~32; @@ -277,25 +287,22 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_ } continue; case 'c': + case 'C': if (w<1) w=1; - if (w>1 && !(fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, ""); - fputwc(btowc(arg.i), f); - if (w>1 && (fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, ""); + pad(f, w-1, fl); + out(f, &(wchar_t){t=='C' ? arg.i : btowc(arg.i)}, 1); + pad(f, w-1, fl^LEFT_ADJ); l = w; continue; - case 'C': - fputwc(arg.i, f); - l = 1; - continue; case 'S': a = arg.p; z = a + wcsnlen(a, p<0 ? INT_MAX : p); if (p<0 && *z) goto overflow; p = z-a; if (wflags & F_ERR; f->flags &= ~F_ERR; ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); - if (f->flags & F_ERR) ret = -1; + if (ferror(f)) ret = -1; f->flags |= olderr; FUNLOCK(f); va_end(ap2); diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwscanf.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwscanf.c deleted file mode 100644 index 82f4860441e5..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/vfwscanf.c +++ /dev/null @@ -1,332 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stdio_impl.h" -#include "shgetc.h" -#include "intscan.h" -#include "floatscan.h" - -#define SIZE_hh -2 -#define SIZE_h -1 -#define SIZE_def 0 -#define SIZE_l 1 -#define SIZE_L 2 -#define SIZE_ll 3 - -static void store_int(void *dest, int size, unsigned long long i) -{ - if (!dest) return; - switch (size) { - case SIZE_hh: - *(char *)dest = i; - break; - case SIZE_h: - *(short *)dest = i; - break; - case SIZE_def: - *(int *)dest = i; - break; - case SIZE_l: - *(long *)dest = i; - break; - case SIZE_ll: - *(long long *)dest = i; - break; - } -} - -static void *arg_n(va_list ap, unsigned int n) -{ - void *p; - unsigned int i; - va_list ap2; - va_copy(ap2, ap); - for (i=n; i>1; i--) va_arg(ap2, void *); - p = va_arg(ap2, void *); - va_end(ap2); - return p; -} - -static int in_set(const wchar_t *set, int c) -{ - int j; - const wchar_t *p = set; - if (*p == '-') { - if (c=='-') return 1; - p++; - } else if (*p == ']') { - if (c==']') return 1; - p++; - } - for (; *p && *p != ']'; p++) { - if (*p=='-' && p[1] && p[1] != ']') - for (j=p++[-1]; j<*p; j++) - if (c==j) return 1; - if (c==*p) return 1; - } - return 0; -} - -#if 1 -#undef getwc -#define getwc(f) \ - ((f)->rpos != (f)->rend && *(f)->rpos < 128 ? *(f)->rpos++ : (getwc)(f)) - -#undef ungetwc -#define ungetwc(c,f) \ - ((f)->rend && (c)<128U ? *--(f)->rpos : ungetwc((c),(f))) -#endif - -int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap) -{ - int width; - int size; - int alloc; - const wchar_t *p; - int c, t; - char *s; - wchar_t *wcs; - void *dest=NULL; - int invert; - int matches=0; - off_t pos = 0, cnt; - static const char size_pfx[][3] = { "hh", "h", "", "l", "L", "ll" }; - char tmp[3*sizeof(int)+10]; - const wchar_t *set; - size_t i, k; - - FLOCK(f); - - fwide(f, 1); - - for (p=fmt; *p; p++) { - - alloc = 0; - - if (iswspace(*p)) { - while (iswspace(p[1])) p++; - while (iswspace((c=getwc(f)))) pos++; - ungetwc(c, f); - continue; - } - if (*p != '%' || p[1] == '%') { - if (*p == '%') { - p++; - while (iswspace((c=getwc(f)))) pos++; - } else { - c = getwc(f); - } - if (c!=*p) { - ungetwc(c, f); - if (c<0) goto input_fail; - goto match_fail; - } - pos++; - continue; - } - - p++; - if (*p=='*') { - dest = 0; p++; - } else if (iswdigit(*p) && p[1]=='$') { - dest = arg_n(ap, *p-'0'); p+=2; - } else { - dest = va_arg(ap, void *); - } - - for (width=0; iswdigit(*p); p++) { - width = 10*width + *p - '0'; - } - - if (*p=='m') { - wcs = 0; - s = 0; - alloc = !!dest; - p++; - } else { - alloc = 0; - } - - size = SIZE_def; - switch (*p++) { - case 'h': - if (*p == 'h') p++, size = SIZE_hh; - else size = SIZE_h; - break; - case 'l': - if (*p == 'l') p++, size = SIZE_ll; - else size = SIZE_l; - break; - case 'j': - size = SIZE_ll; - break; - case 'z': - case 't': - size = SIZE_l; - break; - case 'L': - size = SIZE_L; - break; - case 'd': case 'i': case 'o': case 'u': case 'x': - case 'a': case 'e': case 'f': case 'g': - case 'A': case 'E': case 'F': case 'G': case 'X': - case 's': case 'c': case '[': - case 'S': case 'C': - case 'p': case 'n': - p--; - break; - default: - goto fmt_fail; - } - - t = *p; - - /* Transform S,C -> ls,lc */ - if ((t&0x2f)==3) { - size = SIZE_l; - t |= 32; - } - - if (t != 'n') { - if (t != '[' && (t|32) != 'c') - while (iswspace((c=getwc(f)))) pos++; - else - c=getwc(f); - if (c < 0) goto input_fail; - ungetwc(c, f); - } - - switch (t) { - case 'n': - store_int(dest, size, pos); - /* do not increment match count, etc! */ - continue; - - case 's': - case 'c': - case '[': - if (t == 'c') { - if (width<1) width = 1; - invert = 1; - set = L""; - } else if (t == 's') { - invert = 1; - static const wchar_t spaces[] = { - ' ', '\t', '\n', '\r', 11, 12, 0x0085, - 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, - 0x2006, 0x2008, 0x2009, 0x200a, - 0x2028, 0x2029, 0x205f, 0x3000, 0 }; - set = spaces; - } else { - if (*++p == '^') p++, invert = 1; - else invert = 0; - set = p; - if (*p==']') p++; - while (*p!=']') { - if (!*p) goto fmt_fail; - p++; - } - } - - s = (size == SIZE_def) ? dest : 0; - wcs = (size == SIZE_l) ? dest : 0; - - int gotmatch = 0; - - if (width < 1) width = -1; - - i = 0; - if (alloc) { - k = t=='c' ? width+1U : 31; - if (size == SIZE_l) { - wcs = malloc(k*sizeof(wchar_t)); - if (!wcs) goto alloc_fail; - } else { - s = malloc(k); - if (!s) goto alloc_fail; - } - } - while (width) { - if ((c=getwc(f))<0) break; - if (in_set(set, c) == invert) - break; - if (wcs) { - wcs[i++] = c; - if (alloc && i==k) { - k += k+1; - wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t)); - if (!tmp) goto alloc_fail; - wcs = tmp; - } - } else if (size != SIZE_l) { - int l = wctomb(s?s+i:tmp, c); - if (l<0) goto input_fail; - i += l; - if (alloc && i > k-4) { - k += k+1; - char *tmp = realloc(s, k); - if (!tmp) goto alloc_fail; - s = tmp; - } - } - pos++; - width-=(width>0); - gotmatch=1; - } - if (width) { - ungetwc(c, f); - if (t == 'c' || !gotmatch) goto match_fail; - } - - if (alloc) { - if (size == SIZE_l) *(wchar_t **)dest = wcs; - else *(char **)dest = s; - } - if (t != 'c') { - if (wcs) wcs[i] = 0; - if (s) s[i] = 0; - } - break; - - case 'd': case 'i': case 'o': case 'u': case 'x': - case 'a': case 'e': case 'f': case 'g': - case 'A': case 'E': case 'F': case 'G': case 'X': - case 'p': - if (width < 1) width = 0; - snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln", - 1+!dest, "%*", width, size_pfx[size+2], t); - cnt = 0; - if (fscanf(f, tmp, dest?dest:&cnt, &cnt) == -1) - goto input_fail; - else if (!cnt) - goto match_fail; - pos += cnt; - break; - default: - goto fmt_fail; - } - - if (dest) matches++; - } - if (0) { -fmt_fail: -alloc_fail: -input_fail: - if (!matches) matches--; -match_fail: - if (alloc) { - free(s); - free(wcs); - } - } - FUNLOCK(f); - return matches; -} - -weak_alias(vfwscanf,__isoc99_vfwscanf); diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/vsnprintf.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/vsnprintf.c index 08989d68ce9c..48c3aef7e706 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/vsnprintf.c +++ b/lib/libc/wasi/libc-top-half/musl/src/stdio/vsnprintf.c @@ -47,11 +47,6 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) .cookie = &c, }; - if (n > INT_MAX) { - errno = EOVERFLOW; - return -1; - } - *c.s = 0; return vfprintf(&f, fmt, ap); } diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdio/vswprintf.c b/lib/libc/wasi/libc-top-half/musl/src/stdio/vswprintf.c index bf9bcaf3a2a1..cab94cba7703 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/stdio/vswprintf.c +++ b/lib/libc/wasi/libc-top-half/musl/src/stdio/vswprintf.c @@ -18,6 +18,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l) if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1) return -1; while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) { + if (!i) i=1; s+=i; l-=i; c->l--; @@ -52,9 +53,6 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis if (!n) { return -1; - } else if (n > INT_MAX) { - errno = EOVERFLOW; - return -1; } r = vfwprintf(&f, fmt, ap); sw_write(&f, 0, 0); diff --git a/lib/libc/wasi/libc-top-half/musl/src/stdlib/strtol.c b/lib/libc/wasi/libc-top-half/musl/src/stdlib/strtol.c deleted file mode 100644 index bfefea69d1c4..000000000000 --- a/lib/libc/wasi/libc-top-half/musl/src/stdlib/strtol.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "stdio_impl.h" -#include "intscan.h" -#include "shgetc.h" -#include -#include -#include - -static unsigned long long strtox(const char *s, char **p, int base, unsigned long long lim) -{ - FILE f; - sh_fromstring(&f, s); - shlim(&f, 0); - unsigned long long y = __intscan(&f, base, 1, lim); - if (p) { - size_t cnt = shcnt(&f); - *p = (char *)s + cnt; - } - return y; -} - -unsigned long long strtoull(const char *restrict s, char **restrict p, int base) -{ - return strtox(s, p, base, ULLONG_MAX); -} - -long long strtoll(const char *restrict s, char **restrict p, int base) -{ - return strtox(s, p, base, LLONG_MIN); -} - -unsigned long strtoul(const char *restrict s, char **restrict p, int base) -{ - return strtox(s, p, base, ULONG_MAX); -} - -long strtol(const char *restrict s, char **restrict p, int base) -{ - return strtox(s, p, base, 0UL+LONG_MIN); -} - -intmax_t strtoimax(const char *restrict s, char **restrict p, int base) -{ - return strtoll(s, p, base); -} - -uintmax_t strtoumax(const char *restrict s, char **restrict p, int base) -{ - return strtoull(s, p, base); -} - -weak_alias(strtol, __strtol_internal); -weak_alias(strtoul, __strtoul_internal); -weak_alias(strtoll, __strtoll_internal); -weak_alias(strtoull, __strtoull_internal); -weak_alias(strtoimax, __strtoimax_internal); -weak_alias(strtoumax, __strtoumax_internal); diff --git a/lib/libc/wasi/libc-top-half/musl/src/string/memchr.c b/lib/libc/wasi/libc-top-half/musl/src/string/memchr.c new file mode 100644 index 000000000000..2825ac80b6be --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/string/memchr.c @@ -0,0 +1,89 @@ +#include +#include +#include + +#ifdef __wasm_simd128__ +#include +#endif + +#define SS (sizeof(size_t)) +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +void *memchr(const void *src, int c, size_t n) +{ +#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string) + // Skip Clang 19 and Clang 20 which have a bug (llvm/llvm-project#146574) + // which results in an ICE when inline assembly is used with a vector result. +#if __clang_major__ != 19 && __clang_major__ != 20 + // When n is zero, a function that locates a character finds no occurrence. + // Otherwise, decrement n to ensure sub_overflow overflows + // when n would go equal-to-or-below zero. + if (!n--) { + return NULL; + } + + // Note that reading before/after the allocation of a pointer is UB in + // C, so inline assembly is used to generate the exact machine + // instruction we want with opaque semantics to the compiler to avoid + // the UB. + uintptr_t align = (uintptr_t)src % sizeof(v128_t); + uintptr_t addr = (uintptr_t)src - align; + v128_t vc = wasm_i8x16_splat(c); + + for (;;) { + v128_t v; + __asm__ ( + "local.get %1\n" + "v128.load 0\n" + "local.set %0\n" + : "=r"(v) + : "r"(addr) + : "memory"); + v128_t cmp = wasm_i8x16_eq(v, vc); + // Bitmask is slow on AArch64, any_true is much faster. + if (wasm_v128_any_true(cmp)) { + // Clear the bits corresponding to align (little-endian) + // so we can count trailing zeros. + int mask = wasm_i8x16_bitmask(cmp) >> align << align; + // At least one bit will be set, unless align cleared them. + // Knowing this helps the compiler if it unrolls the loop. + __builtin_assume(mask || align); + // If the mask became zero because of align, + // it's as if we didn't find anything. + if (mask) { + // Find the offset of the first one bit (little-endian). + // That's a match, unless it is beyond the end of the object. + // Recall that we decremented n, so less-than-or-equal-to is correct. + size_t ctz = __builtin_ctz(mask); + return ctz - align <= n ? (char *)src + (addr + ctz - (uintptr_t)src) + : NULL; + } + } + // Decrement n; if it overflows we're done. + if (__builtin_sub_overflow(n, sizeof(v128_t) - align, &n)) { + return NULL; + } + align = 0; + addr += sizeof(v128_t); + } +#endif +#endif + + const unsigned char *s = src; + c = (unsigned char)c; +#ifdef __GNUC__ + for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--); + if (n && *s != c) { + typedef size_t __attribute__((__may_alias__)) word; + const word *w; + size_t k = ONES * c; + for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS); + s = (const void *)w; + } +#endif + for (; n && *s != c; s++, n--); + return n ? (void *)s : 0; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/string/memcmp.c b/lib/libc/wasi/libc-top-half/musl/src/string/memcmp.c new file mode 100644 index 000000000000..ce313049a9e4 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/string/memcmp.c @@ -0,0 +1,43 @@ +#include + +#ifdef __wasm_simd128__ +#include +#endif + +int memcmp(const void *vl, const void *vr, size_t n) +{ +#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string) + if (n >= sizeof(v128_t)) { + // memcmp is allowed to read up to n bytes from each object. + // Find the first different character in the objects. + // Unaligned loads handle the case where the objects + // have mismatching alignments. + const v128_t *v1 = (v128_t *)vl; + const v128_t *v2 = (v128_t *)vr; + while (n) { + const v128_t cmp = wasm_i8x16_eq(wasm_v128_load(v1), wasm_v128_load(v2)); + // Bitmask is slow on AArch64, all_true is much faster. + if (!wasm_i8x16_all_true(cmp)) { + // Find the offset of the first zero bit (little-endian). + size_t ctz = __builtin_ctz(~wasm_i8x16_bitmask(cmp)); + const unsigned char *u1 = (unsigned char *)v1 + ctz; + const unsigned char *u2 = (unsigned char *)v2 + ctz; + // This may help the compiler if the function is inlined. + __builtin_assume(*u1 - *u2 != 0); + return *u1 - *u2; + } + // This makes n a multiple of sizeof(v128_t) + // for every iteration except the first. + size_t align = (n - 1) % sizeof(v128_t) + 1; + v1 = (v128_t *)((char *)v1 + align); + v2 = (v128_t *)((char *)v2 + align); + n -= align; + } + return 0; + } +#endif + + const unsigned char *l=vl, *r=vr; + for (; n && *l == *r; n--, l++, r++); + return n ? *l-*r : 0; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/string/memrchr.c b/lib/libc/wasi/libc-top-half/musl/src/string/memrchr.c new file mode 100644 index 000000000000..69e9a2eff8f9 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/string/memrchr.c @@ -0,0 +1,33 @@ +#include + +#ifdef __wasm_simd128__ +#include +#endif + +void *__memrchr(const void *m, int c, size_t n) +{ +#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string) + // memrchr is allowed to read up to n bytes from the object. + // Search backward for the last matching character. + const v128_t *v = (v128_t *)((char *)m + n); + const v128_t vc = wasm_i8x16_splat(c); + for (; n >= sizeof(v128_t); n -= sizeof(v128_t)) { + const v128_t cmp = wasm_i8x16_eq(wasm_v128_load(--v), vc); + // Bitmask is slow on AArch64, any_true is much faster. + if (wasm_v128_any_true(cmp)) { + // Find the offset of the last one bit (little-endian). + // The leading 16 bits of the bitmask are always zero, + // and to be ignored. + size_t clz = __builtin_clz(wasm_i8x16_bitmask(cmp)) - 16; + return (char *)(v + 1) - (clz + 1); + } + } +#endif + + const unsigned char *s = m; + c = (unsigned char)c; + while (n--) if (s[n]==c) return (void *)(s+n); + return 0; +} + +weak_alias(__memrchr, memrchr); diff --git a/lib/libc/wasi/libc-top-half/musl/src/string/strchrnul.c b/lib/libc/wasi/libc-top-half/musl/src/string/strchrnul.c new file mode 100644 index 000000000000..07e058490c52 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/string/strchrnul.c @@ -0,0 +1,75 @@ +#include +#include +#include + +#ifdef __wasm_simd128__ +#include +#endif + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__strchrnul(const char *s, int c) +{ + c = (unsigned char)c; + if (!c) return (char *)s + strlen(s); + +#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string) + // Skip Clang 19 and Clang 20 which have a bug (llvm/llvm-project#146574) + // which results in an ICE when inline assembly is used with a vector result. +#if __clang_major__ != 19 && __clang_major__ != 20 + // Note that reading before/after the allocation of a pointer is UB in + // C, so inline assembly is used to generate the exact machine + // instruction we want with opaque semantics to the compiler to avoid + // the UB. + uintptr_t align = (uintptr_t)s % sizeof(v128_t); + uintptr_t addr = (uintptr_t)s - align; + v128_t vc = wasm_i8x16_splat(c); + + for (;;) { + v128_t v; + __asm__ ( + "local.get %1\n" + "v128.load 0\n" + "local.set %0\n" + : "=r"(v) + : "r"(addr) + : "memory"); + const v128_t cmp = wasm_i8x16_eq(v, (v128_t){}) | wasm_i8x16_eq(v, vc); + // Bitmask is slow on AArch64, any_true is much faster. + if (wasm_v128_any_true(cmp)) { + // Clear the bits corresponding to align (little-endian) + // so we can count trailing zeros. + int mask = wasm_i8x16_bitmask(cmp) >> align << align; + // At least one bit will be set, unless align cleared them. + // Knowing this helps the compiler if it unrolls the loop. + __builtin_assume(mask || align); + // If the mask became zero because of align, + // it's as if we didn't find anything. + if (mask) { + // Find the offset of the first one bit (little-endian). + return (char *)s + (addr - (uintptr_t)s + __builtin_ctz(mask)); + } + } + align = 0; + addr += sizeof(v128_t); + } +#endif +#endif + +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + const word *w; + for (; (uintptr_t)s % ALIGN; s++) + if (!*s || *(unsigned char *)s == c) return (char *)s; + size_t k = ONES * c; + for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++); + s = (void *)w; +#endif + for (; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +weak_alias(__strchrnul, strchrnul); diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_get.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_get.c new file mode 100644 index 000000000000..ab8d938c69f4 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_get.c @@ -0,0 +1,121 @@ +#include "pthread_impl.h" + +#ifndef __wasilibc_unmodified_upstream +#include +#endif + +int pthread_attr_getdetachstate(const pthread_attr_t *a, int *state) +{ + *state = a->_a_detach; + return 0; +} +int pthread_attr_getguardsize(const pthread_attr_t *restrict a, size_t *restrict size) +{ + *size = a->_a_guardsize; + return 0; +} + +#ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */ +int pthread_attr_getinheritsched(const pthread_attr_t *restrict a, int *restrict inherit) +{ + *inherit = a->_a_sched; + return 0; +} + +int pthread_attr_getschedparam(const pthread_attr_t *restrict a, struct sched_param *restrict param) +{ + param->sched_priority = a->_a_prio; + return 0; +} + +int pthread_attr_getschedpolicy(const pthread_attr_t *restrict a, int *restrict policy) +{ + *policy = a->_a_policy; + return 0; +} + +int pthread_attr_getscope(const pthread_attr_t *restrict a, int *restrict scope) +{ + *scope = PTHREAD_SCOPE_SYSTEM; + return 0; +} +#else +int pthread_attr_getschedparam(const pthread_attr_t *restrict a, struct sched_param *restrict param) +{ + param->sched_priority = 0; + return 0; +} +#endif + +int pthread_attr_getstack(const pthread_attr_t *restrict a, void **restrict addr, size_t *restrict size) +{ + if (!a->_a_stackaddr) + return EINVAL; + *size = a->_a_stacksize; + *addr = (void *)(a->_a_stackaddr - *size); + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t *restrict a, size_t *restrict size) +{ + *size = a->_a_stacksize; + return 0; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict a, int *restrict pshared) +{ + *pshared = !!a->__attr; + return 0; +} + +#ifdef __wasilibc_unmodified_upstream /* Forward declaration of WASI's `__clockid` type. */ +int pthread_condattr_getclock(const pthread_condattr_t *restrict a, clockid_t *restrict clk) +{ + *clk = a->__attr & 0x7fffffff; + return 0; +} +#else +int pthread_condattr_getclock(const pthread_condattr_t *restrict a, clockid_t *restrict clk) +{ + if (a->__attr & 0x7fffffff == __WASI_CLOCKID_REALTIME) + *clk = CLOCK_REALTIME; + if (a->__attr & 0x7fffffff == __WASI_CLOCKID_MONOTONIC) + *clk = CLOCK_MONOTONIC; + return 0; +} +#endif + +int pthread_condattr_getpshared(const pthread_condattr_t *restrict a, int *restrict pshared) +{ + *pshared = a->__attr>>31; + return 0; +} + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict a, int *restrict protocol) +{ + *protocol = a->__attr / 8U % 2; + return 0; +} +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict a, int *restrict pshared) +{ + *pshared = a->__attr / 128U % 2; + return 0; +} + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *restrict a, int *restrict robust) +{ + *robust = a->__attr / 4U % 2; + return 0; +} + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict a, int *restrict type) +{ + *type = a->__attr & 3; + return 0; +} + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict a, int *restrict pshared) +{ + *pshared = a->__attr[0]; + return 0; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_setguardsize.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_setguardsize.c new file mode 100644 index 000000000000..589ff676e87d --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_setguardsize.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_attr_setguardsize(pthread_attr_t *a, size_t size) +{ +#ifdef __wasilibc_unmodified_upstream + if (size > SIZE_MAX/8) return EINVAL; +#else + /* WASI doesn't have memory protection required for stack guards. */ + if (size > 0) return EINVAL; +#endif + a->_a_guardsize = size; + return 0; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_setschedparam.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_setschedparam.c new file mode 100644 index 000000000000..0a41f0d1a114 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_setschedparam.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int pthread_attr_setschedparam(pthread_attr_t *restrict a, const struct sched_param *restrict param) +{ +#ifdef __wasilibc_unmodified_upstream + a->_a_prio = param->sched_priority; +#else + if (param->sched_priority != 0) return ENOTSUP; +#endif + return 0; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_cancel.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_cancel.c new file mode 100644 index 000000000000..681827f8cc9f --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_cancel.c @@ -0,0 +1,113 @@ +#define _GNU_SOURCE +#include +#include "pthread_impl.h" +#include "syscall.h" + +#ifdef __wasilibc_unmodified_upstream +hidden long __cancel(), __syscall_cp_asm(), __syscall_cp_c(); + +long __cancel() +{ + pthread_t self = __pthread_self(); + if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync) + pthread_exit(PTHREAD_CANCELED); + self->canceldisable = PTHREAD_CANCEL_DISABLE; + return -ECANCELED; +} + +long __syscall_cp_asm(volatile void *, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t); + +long __syscall_cp_c(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + pthread_t self; + long r; + int st; + + if ((st=(self=__pthread_self())->canceldisable) + && (st==PTHREAD_CANCEL_DISABLE || nr==SYS_close)) + return __syscall(nr, u, v, w, x, y, z); + + r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); + if (r==-EINTR && nr!=SYS_close && self->cancel && + self->canceldisable != PTHREAD_CANCEL_DISABLE) + r = __cancel(); + return r; +} + +static void _sigaddset(sigset_t *set, int sig) +{ + unsigned s = sig-1; + set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1); +} + +extern hidden const char __cp_begin[1], __cp_end[1], __cp_cancel[1]; + +static void cancel_handler(int sig, siginfo_t *si, void *ctx) +{ + pthread_t self = __pthread_self(); + ucontext_t *uc = ctx; + uintptr_t pc = uc->uc_mcontext.MC_PC; + + a_barrier(); + if (!self->cancel || self->canceldisable == PTHREAD_CANCEL_DISABLE) return; + + _sigaddset(&uc->uc_sigmask, SIGCANCEL); + + if (self->cancelasync) { + pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0); + __cancel(); + } + + if (pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { + uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel; +#ifdef CANCEL_GOT + uc->uc_mcontext.MC_GOT = CANCEL_GOT; +#endif + return; + } + + __syscall(SYS_tkill, self->tid, SIGCANCEL); +} + +void __testcancel() +{ + pthread_t self = __pthread_self(); + if (self->cancel && !self->canceldisable) + __cancel(); +} + +static void init_cancellation() +{ + struct sigaction sa = { + .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK, + .sa_sigaction = cancel_handler + }; + memset(&sa.sa_mask, -1, _NSIG/8); + __libc_sigaction(SIGCANCEL, &sa, 0); +} + +int pthread_cancel(pthread_t t) +{ + static int init; + if (!init) { + init_cancellation(); + init = 1; + } + a_store(&t->cancel, 1); + if (t == pthread_self()) { + if (t->canceldisable == PTHREAD_CANCEL_ENABLE && t->cancelasync) + pthread_exit(PTHREAD_CANCELED); + return 0; + } + return pthread_kill(t, SIGCANCEL); +} +#else +int pthread_cancel(pthread_t t) +{ + return ENOTSUP; +} +#endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_condattr_setclock.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_condattr_setclock.c new file mode 100644 index 000000000000..21ca070c3ecd --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_condattr_setclock.c @@ -0,0 +1,21 @@ +#include "pthread_impl.h" + +#ifndef __wasilibc_unmodified_upstream +#include +#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; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_key_create.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_key_create.c new file mode 100644 index 000000000000..6325f9ba6d6d --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_key_create.c @@ -0,0 +1,105 @@ +#include "pthread_impl.h" +#include "fork_impl.h" + +volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; +void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 }; + +static void (*keys[PTHREAD_KEYS_MAX])(void *); + +static pthread_rwlock_t key_lock = PTHREAD_RWLOCK_INITIALIZER; + +static pthread_key_t next_key; + +static void nodtor(void *dummy) +{ +} + +static void dummy_0(void) +{ +} + +weak_alias(dummy_0, __tl_lock); +weak_alias(dummy_0, __tl_unlock); + +#ifdef __wasilibc_unmodified_upstream // WASI lacks fork +void __pthread_key_atfork(int who) +{ + if (who<0) __pthread_rwlock_rdlock(&key_lock); + else if (!who) __pthread_rwlock_unlock(&key_lock); + else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; +} +#endif + +int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) +{ + pthread_t self = __pthread_self(); + + /* This can only happen in the main thread before + * pthread_create has been called. */ + if (!self->tsd) self->tsd = __pthread_tsd_main; + + /* Purely a sentinel value since null means slot is free. */ + if (!dtor) dtor = nodtor; + + __pthread_rwlock_wrlock(&key_lock); + pthread_key_t j = next_key; + do { + if (!keys[j]) { + keys[next_key = *k = j] = dtor; + __pthread_rwlock_unlock(&key_lock); + return 0; + } + } while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key); + + __pthread_rwlock_unlock(&key_lock); + return EAGAIN; +} + +int __pthread_key_delete(pthread_key_t k) +{ + sigset_t set; + pthread_t self = __pthread_self(), td=self; + +#ifdef __wasilibc_unmodified_upstream + __block_app_sigs(&set); +#endif + __pthread_rwlock_wrlock(&key_lock); + + __tl_lock(); + do td->tsd[k] = 0; + while ((td=td->next)!=self); + __tl_unlock(); + + keys[k] = 0; + + __pthread_rwlock_unlock(&key_lock); +#ifdef __wasilibc_unmodified_upstream + __restore_sigs(&set); +#endif + + return 0; +} + +void __pthread_tsd_run_dtors() +{ + pthread_t self = __pthread_self(); + int i, j; + for (j=0; self->tsd_used && jtsd_used = 0; + for (i=0; itsd[i]; + void (*dtor)(void *) = keys[i]; + self->tsd[i] = 0; + if (val && dtor && dtor != nodtor) { + __pthread_rwlock_unlock(&key_lock); + dtor(val); + __pthread_rwlock_rdlock(&key_lock); + } + } + __pthread_rwlock_unlock(&key_lock); + } +} + +weak_alias(__pthread_key_create, pthread_key_create); +weak_alias(__pthread_key_delete, pthread_key_delete); diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutex_destroy.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutex_destroy.c new file mode 100644 index 000000000000..e53c39c684e7 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutex_destroy.c @@ -0,0 +1,18 @@ +#include "pthread_impl.h" + +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; +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setprotocol.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setprotocol.c new file mode 100644 index 000000000000..84b02ba130ef --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setprotocol.c @@ -0,0 +1,32 @@ +#include "pthread_impl.h" +#include "syscall.h" + +static volatile int check_pi_result = -1; + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int protocol) +{ + int r; + switch (protocol) { + case PTHREAD_PRIO_NONE: + a->__attr &= ~8; + return 0; + case PTHREAD_PRIO_INHERIT: +#ifdef __wasilibc_unmodified_upstream + r = check_pi_result; + if (r < 0) { + volatile int lk = 0; + r = -__syscall(SYS_futex, &lk, FUTEX_LOCK_PI, 0, 0); + a_store(&check_pi_result, r); + } + if (r) return r; + a->__attr |= 8; + return 0; +#else + return ENOTSUP; +#endif + case PTHREAD_PRIO_PROTECT: + return ENOTSUP; + default: + return EINVAL; + } +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setrobust.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setrobust.c new file mode 100644 index 000000000000..68c7d65d8176 --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setrobust.c @@ -0,0 +1,28 @@ +#include "pthread_impl.h" +#include "syscall.h" + +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; + if (r < 0) { + void *p; + size_t l; + r = -__syscall(SYS_get_robust_list, 0, &p, &l); + a_store(&check_robust_result, r); + } + if (r) return r; + a->__attr |= 4; + return 0; + } + a->__attr &= ~4; + return 0; +#else + if (robust) return EINVAL; + return 0; +#endif +} diff --git a/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_self.c b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_self.c new file mode 100644 index 000000000000..1ea2856d67cc --- /dev/null +++ b/lib/libc/wasi/libc-top-half/musl/src/thread/pthread_self.c @@ -0,0 +1,14 @@ +#include "pthread_impl.h" +#include + +#if !defined(__wasilibc_unmodified_upstream) && defined(__wasm__) +_Thread_local struct pthread __wasilibc_pthread_self; +#endif + +static pthread_t __pthread_self_internal() +{ + return __pthread_self(); +} + +weak_alias(__pthread_self_internal, pthread_self); +weak_alias(__pthread_self_internal, thrd_current); diff --git a/lib/libc/wasi/libc-top-half/musl/src/time/__tz.c b/lib/libc/wasi/libc-top-half/musl/src/time/__tz.c index 955150344880..7efb9a975716 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/time/__tz.c +++ b/lib/libc/wasi/libc-top-half/musl/src/time/__tz.c @@ -434,10 +434,14 @@ weak_alias(__tzset, tzset); void __secs_to_zone(long long t, int local, int *isdst, int *offset, long *oppoff, const char **zonename) { // Minimalist implementation for now. - *isdst = 0; - *offset = 0; - *oppoff = 0; - *zonename = __utc; + if (isdst) + *isdst = 0; + if (offset) + *offset = 0; + if (oppoff) + *oppoff = 0; + if (zonename) + *zonename = __utc; } #endif diff --git a/lib/libc/wasi/libc-top-half/musl/src/time/strftime.c b/lib/libc/wasi/libc-top-half/musl/src/time/strftime.c index a1db9cbd8e72..6efde91b05c4 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/time/strftime.c +++ b/lib/libc/wasi/libc-top-half/musl/src/time/strftime.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "locale_impl.h" @@ -237,7 +238,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st pad = 0; if (*f == '-' || *f == '_' || *f == '0') pad = *f++; if ((plus = (*f == '+'))) f++; - width = strtoul(f, &p, 10); + if (isdigit(*f)) { + width = strtoul(f, &p, 10); + } else { + width = 0; + p = (void *)f; + } if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { if (!width && p!=f) width = 1; } else { diff --git a/lib/libc/wasi/thread-stub/pthread_barrier_destroy.c b/lib/libc/wasi/thread-stub/pthread_barrier_destroy.c new file mode 100644 index 000000000000..2898c41a00f9 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_barrier_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_barrier_destroy(pthread_barrier_t *b) +{ + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_barrier_init.c b/lib/libc/wasi/thread-stub/pthread_barrier_init.c new file mode 100644 index 000000000000..42eb6451b70c --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_barrier_init.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_barrier_init(pthread_barrier_t *restrict b, const pthread_barrierattr_t *restrict a, unsigned count) +{ + if (count-1 > INT_MAX-1) return EINVAL; + *b = (pthread_barrier_t){ ._b_limit = count-1 }; + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_barrier_wait.c b/lib/libc/wasi/thread-stub/pthread_barrier_wait.c new file mode 100644 index 000000000000..c5a4afb73e81 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_barrier_wait.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_barrier_wait(pthread_barrier_t *b) +{ + if (!b->_b_limit) return PTHREAD_BARRIER_SERIAL_THREAD; + __builtin_trap(); +} diff --git a/lib/libc/wasi/thread-stub/pthread_cond_broadcast.c b/lib/libc/wasi/thread-stub/pthread_cond_broadcast.c new file mode 100644 index 000000000000..ce3180996594 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_cond_broadcast.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_broadcast(pthread_cond_t *c) +{ + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_cond_destroy.c b/lib/libc/wasi/thread-stub/pthread_cond_destroy.c new file mode 100644 index 000000000000..1d21a5a8bfc7 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_cond_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_destroy(pthread_cond_t *c) +{ + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_cond_init.c b/lib/libc/wasi/thread-stub/pthread_cond_init.c new file mode 100644 index 000000000000..c32903b6c715 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_cond_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_init(pthread_cond_t *restrict c, const pthread_condattr_t *restrict a) +{ + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_cond_signal.c b/lib/libc/wasi/thread-stub/pthread_cond_signal.c new file mode 100644 index 000000000000..4eb2774ae25b --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_cond_signal.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_signal(pthread_cond_t *c) +{ + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_cond_timedwait.c b/lib/libc/wasi/thread-stub/pthread_cond_timedwait.c new file mode 100644 index 000000000000..0e7f9f835acf --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_cond_timedwait.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts) +{ + /* Error check mutexes must detect if they're not locked (UB for others) */ + if (!m->_m_count) return EPERM; + int ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, ts, 0); + if (ret == 0) return ETIMEDOUT; + if (ret != EINTR) return ret; + return 0; +} + +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait); diff --git a/lib/libc/wasi/thread-stub/pthread_cond_wait.c b/lib/libc/wasi/thread-stub/pthread_cond_wait.c new file mode 100644 index 000000000000..84a44b7bc064 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_cond_wait.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_cond_wait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m) +{ + /* Because there is no other thread that can signal us, this is a deadlock immediately. + The other possible choice is to return immediately (spurious wakeup), but that is likely to + just result in the program spinning forever on a condition that cannot become true. */ + __builtin_trap(); +} diff --git a/lib/libc/wasi/thread-stub/pthread_create.c b/lib/libc/wasi/thread-stub/pthread_create.c new file mode 100644 index 000000000000..717564cd1bec --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_create.c @@ -0,0 +1,19 @@ +#include "pthread_impl.h" + +static void dummy_0() +{ +} +weak_alias(dummy_0, __acquire_ptc); +weak_alias(dummy_0, __release_ptc); + +int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) +{ + /* + "The system lacked the necessary resources to create another thread, + or the system-imposed limit on the total number of threads in a process + {PTHREAD_THREADS_MAX} would be exceeded." + */ + return EAGAIN; +} + +weak_alias(__pthread_create, pthread_create); diff --git a/lib/libc/wasi/thread-stub/pthread_detach.c b/lib/libc/wasi/thread-stub/pthread_detach.c new file mode 100644 index 000000000000..55953e1598b9 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_detach.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +static int __pthread_detach(pthread_t t) +{ + /* + If we are the only thread, when we exit the whole process exits. + So the storage will be reclaimed no matter what. + */ + return 0; +} + +weak_alias(__pthread_detach, pthread_detach); +weak_alias(__pthread_detach, thrd_detach); diff --git a/lib/libc/wasi/thread-stub/pthread_getattr_np.c b/lib/libc/wasi/thread-stub/pthread_getattr_np.c new file mode 100644 index 000000000000..d463de14349a --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_getattr_np.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int pthread_getattr_np(pthread_t t, pthread_attr_t *a) +{ + *a = (pthread_attr_t){0}; + /* Can't join main thread. */ + a->_a_detach = PTHREAD_CREATE_DETACHED; + /* WASI doesn't have memory protection required for stack guards. */ + a->_a_guardsize = 0; + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_join.c b/lib/libc/wasi/thread-stub/pthread_join.c new file mode 100644 index 000000000000..cbdcedd73325 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_join.c @@ -0,0 +1,32 @@ +#include "pthread_impl.h" + +static int __pthread_tryjoin_np(pthread_t t, void **res) +{ + /* + "The behavior is undefined if the value specified by the thread argument + to pthread_join() refers to the calling thread." + */ + return 0; +} + +static int __pthread_timedjoin_np(pthread_t t, void **res, const struct timespec *at) +{ + /* + "The behavior is undefined if the value specified by the thread argument + to pthread_join() refers to the calling thread." + */ + return 0; +} + +int __pthread_join(pthread_t t, void **res) +{ + /* + "The behavior is undefined if the value specified by the thread argument + to pthread_join() refers to the calling thread." + */ + return 0; +} + +weak_alias(__pthread_tryjoin_np, pthread_tryjoin_np); +weak_alias(__pthread_timedjoin_np, pthread_timedjoin_np); +weak_alias(__pthread_join, pthread_join); diff --git a/lib/libc/wasi/thread-stub/pthread_mutex_consistent.c b/lib/libc/wasi/thread-stub/pthread_mutex_consistent.c new file mode 100644 index 000000000000..639635361fb5 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_mutex_consistent.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_mutex_consistent(pthread_mutex_t *m) +{ + /* cannot be a robust mutex, as they're entirely unsupported in WASI */ + return EINVAL; + +} diff --git a/lib/libc/wasi/thread-stub/pthread_mutex_getprioceiling.c b/lib/libc/wasi/thread-stub/pthread_mutex_getprioceiling.c new file mode 100644 index 000000000000..8c75a6612c89 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_mutex_getprioceiling.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_mutex_getprioceiling(const pthread_mutex_t *restrict m, int *restrict ceiling) +{ + return EINVAL; +} diff --git a/lib/libc/wasi/thread-stub/pthread_mutex_lock.c b/lib/libc/wasi/thread-stub/pthread_mutex_lock.c new file mode 100644 index 000000000000..9b380c50ec1f --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_mutex_lock.c @@ -0,0 +1,21 @@ +#include "pthread_impl.h" + +int __pthread_mutex_lock(pthread_mutex_t *m) +{ + /* + _m_type[1:0] - type + 0 - normal + 1 - recursive + 2 - errorcheck + */ + if (m->_m_type&3 != PTHREAD_MUTEX_RECURSIVE) { + if (m->_m_count) return EDEADLK; + m->_m_count = 1; + } else { + if ((unsigned)m->_m_count >= INT_MAX) return EAGAIN; + m->_m_count++; + } + return 0; +} + +weak_alias(__pthread_mutex_lock, pthread_mutex_lock); diff --git a/lib/libc/wasi/thread-stub/pthread_mutex_timedlock.c b/lib/libc/wasi/thread-stub/pthread_mutex_timedlock.c new file mode 100644 index 000000000000..51f2606407e5 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_mutex_timedlock.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at) +{ + /* "The pthread_mutex_timedlock() function may fail if: A deadlock condition was detected." */ + /* This means that we don't have to wait and then return timeout, we can just detect deadlock. */ + return pthread_mutex_lock(m); +} + +weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock); diff --git a/lib/libc/wasi/thread-stub/pthread_mutex_trylock.c b/lib/libc/wasi/thread-stub/pthread_mutex_trylock.c new file mode 100644 index 000000000000..9f00f893fc91 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_mutex_trylock.c @@ -0,0 +1,21 @@ +#include "pthread_impl.h" + +int __pthread_mutex_trylock(pthread_mutex_t *m) +{ + /* + _m_type[1:0] - type + 0 - normal + 1 - recursive + 2 - errorcheck + */ + if (m->_m_type&3 != PTHREAD_MUTEX_RECURSIVE) { + if (m->_m_count) return EBUSY; + m->_m_count = 1; + } else { + if ((unsigned)m->_m_count >= INT_MAX) return EAGAIN; + m->_m_count++; + } + return 0; +} + +weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock); diff --git a/lib/libc/wasi/thread-stub/pthread_mutex_unlock.c b/lib/libc/wasi/thread-stub/pthread_mutex_unlock.c new file mode 100644 index 000000000000..33757864aab2 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_mutex_unlock.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int __pthread_mutex_unlock(pthread_mutex_t *m) +{ + if (!m->_m_count) return EPERM; + m->_m_count--; + return 0; +} + +weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock); diff --git a/lib/libc/wasi/thread-stub/pthread_once.c b/lib/libc/wasi/thread-stub/pthread_once.c new file mode 100644 index 000000000000..350342a1ef2a --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_once.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" + +int __pthread_once(pthread_once_t *control, void (*init)(void)) +{ + if (!*control) { + init(); + *control = 1; + } + return 0; +} + +weak_alias(__pthread_once, pthread_once); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_rdlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_rdlock.c new file mode 100644 index 000000000000..1b935da4ea73 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_rdlock.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_rdlock(pthread_rwlock_t *rw) +{ + if (rw->_rw_lock == 0x7fffffff) return EDEADLK; + if (rw->_rw_lock == 0x7ffffffe) return EAGAIN; + rw->_rw_lock++; + return 0; +} + +weak_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_timedrdlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_timedrdlock.c new file mode 100644 index 000000000000..44825643417f --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_timedrdlock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rw, const struct timespec *restrict at) +{ + return pthread_rwlock_rdlock(rw); +} + +weak_alias(__pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_timedwrlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_timedwrlock.c new file mode 100644 index 000000000000..1ee24500b3a9 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_timedwrlock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct timespec *restrict at) +{ + return pthread_rwlock_wrlock(rw); +} + +weak_alias(__pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_tryrdlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_tryrdlock.c new file mode 100644 index 000000000000..4753a60e069b --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_tryrdlock.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rw) +{ + if (rw->_rw_lock == 0x7fffffff) return EBUSY; + if (rw->_rw_lock == 0x7ffffffe) return EAGAIN; + rw->_rw_lock++; + return 0; +} + +weak_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_trywrlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_trywrlock.c new file mode 100644 index 000000000000..3077fdc31de0 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_trywrlock.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_trywrlock(pthread_rwlock_t *rw) +{ + if (rw->_rw_lock) return EBUSY; + rw->_rw_lock = 0x7fffffff; + return 0; +} + +weak_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_unlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_unlock.c new file mode 100644 index 000000000000..40f047ea962a --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_unlock.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_unlock(pthread_rwlock_t *rw) +{ + if (rw->_rw_lock == 0x7fffffff) + rw->_rw_lock = 0; + else + rw->_rw_lock--; + return 0; +} + +weak_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock); diff --git a/lib/libc/wasi/thread-stub/pthread_rwlock_wrlock.c b/lib/libc/wasi/thread-stub/pthread_rwlock_wrlock.c new file mode 100644 index 000000000000..ce9d2099bea4 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_rwlock_wrlock.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int __pthread_rwlock_wrlock(pthread_rwlock_t *rw) +{ + if (rw->_rw_lock) return EDEADLK; + rw->_rw_lock = 0x7fffffff; + return 0; +} + +weak_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock); diff --git a/lib/libc/wasi/thread-stub/pthread_spin_lock.c b/lib/libc/wasi/thread-stub/pthread_spin_lock.c new file mode 100644 index 000000000000..4a682a6b6ff8 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_spin_lock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_spin_lock(pthread_spinlock_t *s) +{ + if (*s) return EDEADLK; + *s = 1; + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_spin_trylock.c b/lib/libc/wasi/thread-stub/pthread_spin_trylock.c new file mode 100644 index 000000000000..5ef1b2a02a82 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_spin_trylock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_spin_trylock(pthread_spinlock_t *s) +{ + if (*s) return EBUSY; + *s = 1; + return 0; +} diff --git a/lib/libc/wasi/thread-stub/pthread_spin_unlock.c b/lib/libc/wasi/thread-stub/pthread_spin_unlock.c new file mode 100644 index 000000000000..f9d8a23dc644 --- /dev/null +++ b/lib/libc/wasi/thread-stub/pthread_spin_unlock.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_spin_unlock(pthread_spinlock_t *s) +{ + *s = 0; + return 0; +} diff --git a/lib/std/start.zig b/lib/std/start.zig index 30543ead8a65..c71aee529e7f 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -57,7 +57,7 @@ comptime { } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { if (builtin.link_libc and @hasDecl(root, "main")) { if (native_arch.isWasm()) { - @export(&mainWithoutEnv, .{ .name = "main" }); + @export(&mainWithoutEnv, .{ .name = "__main_argc_argv" }); } else if (!@typeInfo(@TypeOf(root.main)).@"fn".calling_convention.eql(.c)) { @export(&main, .{ .name = "main" }); } diff --git a/lib/std/zig/target.zig b/lib/std/zig/target.zig index 873aa646881e..651adfcfe2d1 100644 --- a/lib/std/zig/target.zig +++ b/lib/std/zig/target.zig @@ -361,6 +361,8 @@ pub fn isLibCLibName(target: *const std.Target, name: []const u8) bool { return true; if (target.os.tag == .wasi) { + if (eqlIgnoreCase(ignore_case, name, "setjmp")) + return true; if (eqlIgnoreCase(ignore_case, name, "wasi-emulated-getpid")) return true; if (eqlIgnoreCase(ignore_case, name, "wasi-emulated-mman")) diff --git a/src/Compilation.zig b/src/Compilation.zig index ed4d73c673bd..a318597db821 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1426,11 +1426,6 @@ pub const MiscTask = enum { @"wasi crt1-reactor.o", @"wasi crt1-command.o", @"wasi libc.a", - @"wasi libdl.a", - @"libwasi-emulated-process-clocks.a", - @"libwasi-emulated-getpid.a", - @"libwasi-emulated-mman.a", - @"libwasi-emulated-signal.a", @"glibc Scrt1.o", @"glibc libc_nonshared.a", diff --git a/src/libs/wasi_libc.zig b/src/libs/wasi_libc.zig index d71740e5e60c..4af86f28f25b 100644 --- a/src/libs/wasi_libc.zig +++ b/src/libs/wasi_libc.zig @@ -44,6 +44,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{}); try addLibcBottomHalfIncludes(comp, arena, &args); + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.dirs.zig_lib.join(arena, &.{ @@ -53,12 +54,14 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; + return comp.build_crt_file("crt1-reactor", .Obj, .@"wasi crt1-reactor.o", prog_node, &files, .{}); }, .crt1_command_o => { var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{}); try addLibcBottomHalfIncludes(comp, arena, &args); + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.dirs.zig_lib.join(arena, &.{ @@ -68,6 +71,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; + return comp.build_crt_file("crt1-command", .Obj, .@"wasi crt1-command.o", prog_node, &files, .{}); }, .libc_a => { @@ -77,6 +81,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre // Compile emmalloc. var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{ .want_O3 = true, .no_strict_aliasing = true }); + for (emmalloc_src_files) |file_path| { try libc_sources.append(.{ .src_path = try comp.dirs.zig_lib.join(arena, &.{ @@ -122,11 +127,52 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre } } + { + // Compile musl-fts. + var args = std.array_list.Managed([]const u8).init(arena); + try addCCArgs(comp, arena, &args, .{ .want_O3 = true }); + try args.appendSlice(&[_][]const u8{ + "-I", + try comp.dirs.zig_lib.join(arena, &.{ + "libc", + "wasi", + "fts", + }), + }); + + for (fts_src_files) |file_path| { + try libc_sources.append(.{ + .src_path = try comp.dirs.zig_lib.join(arena, &.{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + .owner = undefined, + }); + } + } + + if (comp.getTarget().cpu.has(.wasm, .exception_handling)) { + // Compile libsetjmp. + var args = std.array_list.Managed([]const u8).init(arena); + try addCCArgs(comp, arena, &args, .{ .want_O3 = true }); + try addLibcTopHalfIncludes(comp, arena, &args); + + for (setjmp_src_files) |file_path| { + try libc_sources.append(.{ + .src_path = try comp.dirs.zig_lib.join(arena, &.{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + .owner = undefined, + }); + } + } + { // Compile libdl. var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{ .want_O3 = true }); - try addLibcBottomHalfIncludes(comp, arena, &args); + try addLibcTopHalfIncludes(comp, arena, &args); for (emulated_dl_src_files) |file_path| { try libc_sources.append(.{ @@ -143,16 +189,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre // Compile libwasi-emulated-process-clocks. var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{ .want_O3 = true }); - try args.appendSlice(&.{ - "-I", - try comp.dirs.zig_lib.join(arena, &.{ - "libc", - "wasi", - "libc-bottom-half", - "cloudlibc", - "src", - }), - }); for (emulated_process_clocks_src_files) |file_path| { try libc_sources.append(.{ @@ -169,7 +205,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre // Compile libwasi-emulated-getpid. var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{ .want_O3 = true }); - try addLibcBottomHalfIncludes(comp, arena, &args); for (emulated_getpid_src_files) |file_path| { try libc_sources.append(.{ @@ -186,7 +221,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre // Compile libwasi-emulated-mman. var args = std.array_list.Managed([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{ .want_O3 = true }); - try addLibcBottomHalfIncludes(comp, arena, &args); for (emulated_mman_src_files) |file_path| { try libc_sources.append(.{ @@ -278,13 +312,18 @@ fn addCCArgs( "-mthread-model", "single", - "-isysroot", - "/", + "-I", + try comp.dirs.zig_lib.join(arena, &.{ + "libc", + "wasi", + "libc-bottom-half", + "cloudlibc", + "src", + }), - "-iwithsysroot", + "-isystem", try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", triple }), - - "-iwithsysroot", + "-isystem", try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", "generic-musl" }), "-DBULK_MEMORY_THRESHOLD=32", @@ -338,7 +377,6 @@ fn addLibcBottomHalfIncludes( "src", "include", }), - "-I", try comp.dirs.zig_lib.join(arena, &.{ "libc", @@ -346,8 +384,8 @@ fn addLibcBottomHalfIncludes( "src", "include", }), - "-I", + try comp.dirs.zig_lib.join(arena, &.{ "libc", "wasi", @@ -356,7 +394,6 @@ fn addLibcBottomHalfIncludes( "src", "internal", }), - "-I", try comp.dirs.zig_lib.join(arena, &.{ "libc", @@ -382,7 +419,6 @@ fn addLibcTopHalfIncludes( "src", "include", }), - "-I", try comp.dirs.zig_lib.join(arena, &.{ "libc", @@ -400,7 +436,6 @@ fn addLibcTopHalfIncludes( "src", "internal", }), - "-I", try comp.dirs.zig_lib.join(arena, &.{ "libc", @@ -418,7 +453,6 @@ fn addLibcTopHalfIncludes( "arch", "wasm32", }), - "-I", try comp.dirs.zig_lib.join(arena, &.{ "libc", @@ -469,8 +503,8 @@ const libc_bottom_half_src_files = [_][]const u8{ "wasi/libc-bottom-half/cloudlibc/src/libc/sys/socket/recv.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/socket/send.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/socket/shutdown.c", - "wasi/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c", + "wasi/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/stat/futimens.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c", @@ -479,11 +513,11 @@ const libc_bottom_half_src_files = [_][]const u8{ "wasi/libc-bottom-half/cloudlibc/src/libc/sys/uio/pwritev.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/uio/readv.c", "wasi/libc-bottom-half/cloudlibc/src/libc/sys/uio/writev.c", - "wasi/libc-bottom-half/cloudlibc/src/libc/time/CLOCK_MONOTONIC.c", - "wasi/libc-bottom-half/cloudlibc/src/libc/time/CLOCK_REALTIME.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/clock_getres.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/clock_gettime.c", + "wasi/libc-bottom-half/cloudlibc/src/libc/time/CLOCK_MONOTONIC.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c", + "wasi/libc-bottom-half/cloudlibc/src/libc/time/CLOCK_REALTIME.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/nanosleep.c", "wasi/libc-bottom-half/cloudlibc/src/libc/time/time.c", "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c", @@ -501,25 +535,18 @@ const libc_bottom_half_src_files = [_][]const u8{ "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/unlinkat.c", "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/usleep.c", "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/write.c", - "wasi/libc-bottom-half/sources/__errno_location.c", - "wasi/libc-bottom-half/sources/__main_void.c", - "wasi/libc-bottom-half/sources/__wasilibc_dt.c", - "wasi/libc-bottom-half/sources/__wasilibc_environ.c", - "wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c", - "wasi/libc-bottom-half/sources/__wasilibc_initialize_environ.c", - "wasi/libc-bottom-half/sources/__wasilibc_real.c", - "wasi/libc-bottom-half/sources/__wasilibc_rmdirat.c", - "wasi/libc-bottom-half/sources/__wasilibc_tell.c", - "wasi/libc-bottom-half/sources/__wasilibc_unlinkat.c", "wasi/libc-bottom-half/sources/abort.c", "wasi/libc-bottom-half/sources/accept-wasip1.c", "wasi/libc-bottom-half/sources/at_fdcwd.c", + "wasi/libc-bottom-half/sources/chdir.c", "wasi/libc-bottom-half/sources/complex-builtins.c", "wasi/libc-bottom-half/sources/environ.c", "wasi/libc-bottom-half/sources/errno.c", + "wasi/libc-bottom-half/sources/__errno_location.c", "wasi/libc-bottom-half/sources/getcwd.c", "wasi/libc-bottom-half/sources/getentropy.c", "wasi/libc-bottom-half/sources/isatty.c", + "wasi/libc-bottom-half/sources/__main_void.c", "wasi/libc-bottom-half/sources/math/fmin-fmax.c", "wasi/libc-bottom-half/sources/math/math-builtins.c", "wasi/libc-bottom-half/sources/posix.c", @@ -527,7 +554,15 @@ const libc_bottom_half_src_files = [_][]const u8{ "wasi/libc-bottom-half/sources/reallocarray.c", "wasi/libc-bottom-half/sources/sbrk.c", "wasi/libc-bottom-half/sources/truncate.c", - "wasi/libc-bottom-half/sources/chdir.c", + "wasi/libc-bottom-half/sources/__wasilibc_dt.c", + "wasi/libc-bottom-half/sources/__wasilibc_environ.c", + "wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c", + "wasi/libc-bottom-half/sources/__wasilibc_initialize_environ.c", + "wasi/libc-bottom-half/sources/__wasilibc_random.c", + "wasi/libc-bottom-half/sources/__wasilibc_real.c", + "wasi/libc-bottom-half/sources/__wasilibc_rmdirat.c", + "wasi/libc-bottom-half/sources/__wasilibc_tell.c", + "wasi/libc-bottom-half/sources/__wasilibc_unlinkat.c", }; const libc_top_half_src_files = [_][]const u8{ @@ -593,6 +628,7 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/complex/ctanhf.c", "musl/src/complex/ctanhl.c", "musl/src/complex/ctanl.c", + "musl/src/conf/confstr.c", "musl/src/conf/legacy.c", "musl/src/conf/pathconf.c", "musl/src/crypt/crypt_blowfish.c", @@ -971,8 +1007,10 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/stdio/__toread.c", "musl/src/stdio/__towrite.c", "musl/src/stdio/__uflow.c", + "musl/src/stdio/ungetc.c", "musl/src/stdio/ungetwc.c", "musl/src/stdio/vasprintf.c", + "musl/src/stdio/vfwscanf.c", "musl/src/stdio/vprintf.c", "musl/src/stdio/vscanf.c", "musl/src/stdio/vsprintf.c", @@ -994,23 +1032,20 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/stdlib/lldiv.c", "musl/src/stdlib/qsort.c", "musl/src/stdlib/qsort_nr.c", + "musl/src/stdlib/strtol.c", "musl/src/string/bcmp.c", "musl/src/string/bcopy.c", "musl/src/string/explicit_bzero.c", "musl/src/string/index.c", "musl/src/string/memccpy.c", - "musl/src/string/memchr.c", - "musl/src/string/memcmp.c", "musl/src/string/memmem.c", "musl/src/string/mempcpy.c", - "musl/src/string/memrchr.c", "musl/src/string/rindex.c", "musl/src/string/stpcpy.c", "musl/src/string/stpncpy.c", "musl/src/string/strcasestr.c", "musl/src/string/strcat.c", "musl/src/string/strchr.c", - "musl/src/string/strchrnul.c", "musl/src/string/strcpy.c", "musl/src/string/strcspn.c", "musl/src/string/strdup.c", @@ -1058,6 +1093,37 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/string/wmemcpy.c", "musl/src/string/wmemmove.c", "musl/src/string/wmemset.c", + "musl/src/thread/default_attr.c", + "musl/src/thread/pthread_attr_destroy.c", + "musl/src/thread/pthread_attr_init.c", + "musl/src/thread/pthread_attr_setdetachstate.c", + "musl/src/thread/pthread_attr_setstack.c", + "musl/src/thread/pthread_attr_setstacksize.c", + "musl/src/thread/pthread_barrierattr_destroy.c", + "musl/src/thread/pthread_barrierattr_init.c", + "musl/src/thread/pthread_barrierattr_setpshared.c", + "musl/src/thread/pthread_cleanup_push.c", + "musl/src/thread/pthread_condattr_destroy.c", + "musl/src/thread/pthread_condattr_init.c", + "musl/src/thread/pthread_condattr_setpshared.c", + "musl/src/thread/pthread_equal.c", + "musl/src/thread/pthread_getspecific.c", + "musl/src/thread/pthread_mutexattr_destroy.c", + "musl/src/thread/pthread_mutexattr_init.c", + "musl/src/thread/pthread_mutexattr_setpshared.c", + "musl/src/thread/pthread_mutexattr_settype.c", + "musl/src/thread/pthread_mutex_init.c", + "musl/src/thread/pthread_rwlockattr_destroy.c", + "musl/src/thread/pthread_rwlockattr_init.c", + "musl/src/thread/pthread_rwlockattr_setpshared.c", + "musl/src/thread/pthread_rwlock_destroy.c", + "musl/src/thread/pthread_rwlock_init.c", + "musl/src/thread/pthread_setcancelstate.c", + "musl/src/thread/pthread_setcanceltype.c", + "musl/src/thread/pthread_setspecific.c", + "musl/src/thread/pthread_spin_destroy.c", + "musl/src/thread/pthread_spin_init.c", + "musl/src/thread/pthread_testcancel.c", "musl/src/thread/thrd_sleep.c", "musl/src/time/asctime.c", "musl/src/time/asctime_r.c", @@ -1071,7 +1137,6 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/time/__year_to_secs.c", "musl/src/unistd/posix_close.c", - "wasi/libc-top-half/musl/src/conf/confstr.c", "wasi/libc-top-half/musl/src/conf/fpathconf.c", "wasi/libc-top-half/musl/src/conf/sysconf.c", "wasi/libc-top-half/musl/src/dirent/alphasort.c", @@ -1112,9 +1177,9 @@ const libc_top_half_src_files = [_][]const u8{ "wasi/libc-top-half/musl/src/misc/nftw.c", "wasi/libc-top-half/musl/src/misc/uname.c", "wasi/libc-top-half/musl/src/prng/random.c", + "wasi/libc-top-half/musl/src/regex/glob.c", "wasi/libc-top-half/musl/src/regex/regcomp.c", "wasi/libc-top-half/musl/src/regex/regexec.c", - "wasi/libc-top-half/musl/src/regex/glob.c", "wasi/libc-top-half/musl/src/regex/tre-mem.c", "wasi/libc-top-half/musl/src/stat/futimesat.c", "wasi/libc-top-half/musl/src/stdio/__fdopen.c", @@ -1144,21 +1209,32 @@ const libc_top_half_src_files = [_][]const u8{ "wasi/libc-top-half/musl/src/stdio/__stdio_write.c", "wasi/libc-top-half/musl/src/stdio/stdout.c", "wasi/libc-top-half/musl/src/stdio/__stdout_write.c", - "wasi/libc-top-half/musl/src/stdio/ungetc.c", "wasi/libc-top-half/musl/src/stdio/vdprintf.c", "wasi/libc-top-half/musl/src/stdio/vfprintf.c", "wasi/libc-top-half/musl/src/stdio/vfscanf.c", "wasi/libc-top-half/musl/src/stdio/vfwprintf.c", - "wasi/libc-top-half/musl/src/stdio/vfwscanf.c", "wasi/libc-top-half/musl/src/stdio/vsnprintf.c", "wasi/libc-top-half/musl/src/stdio/vsscanf.c", "wasi/libc-top-half/musl/src/stdio/vswprintf.c", "wasi/libc-top-half/musl/src/stdio/vswscanf.c", "wasi/libc-top-half/musl/src/stdlib/strtod.c", - "wasi/libc-top-half/musl/src/stdlib/strtol.c", "wasi/libc-top-half/musl/src/stdlib/wcstod.c", "wasi/libc-top-half/musl/src/stdlib/wcstol.c", + "wasi/libc-top-half/musl/src/string/memchr.c", + "wasi/libc-top-half/musl/src/string/memcmp.c", + "wasi/libc-top-half/musl/src/string/memrchr.c", "wasi/libc-top-half/musl/src/string/memset.c", + "wasi/libc-top-half/musl/src/string/strchrnul.c", + "wasi/libc-top-half/musl/src/thread/pthread_attr_get.c", + "wasi/libc-top-half/musl/src/thread/pthread_attr_setguardsize.c", + "wasi/libc-top-half/musl/src/thread/pthread_attr_setschedparam.c", + "wasi/libc-top-half/musl/src/thread/pthread_cancel.c", + "wasi/libc-top-half/musl/src/thread/pthread_condattr_setclock.c", + "wasi/libc-top-half/musl/src/thread/pthread_key_create.c", + "wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setprotocol.c", + "wasi/libc-top-half/musl/src/thread/pthread_mutexattr_setrobust.c", + "wasi/libc-top-half/musl/src/thread/pthread_mutex_destroy.c", + "wasi/libc-top-half/musl/src/thread/pthread_self.c", "wasi/libc-top-half/musl/src/time/getdate.c", "wasi/libc-top-half/musl/src/time/gmtime.c", "wasi/libc-top-half/musl/src/time/gmtime_r.c", @@ -1173,11 +1249,50 @@ const libc_top_half_src_files = [_][]const u8{ "wasi/libc-top-half/musl/src/time/wcsftime.c", "wasi/libc-top-half/sources/arc4random.c", + + "wasi/thread-stub/pthread_barrier_destroy.c", + "wasi/thread-stub/pthread_barrier_init.c", + "wasi/thread-stub/pthread_barrier_wait.c", + "wasi/thread-stub/pthread_cond_broadcast.c", + "wasi/thread-stub/pthread_cond_destroy.c", + "wasi/thread-stub/pthread_cond_init.c", + "wasi/thread-stub/pthread_cond_signal.c", + "wasi/thread-stub/pthread_cond_timedwait.c", + "wasi/thread-stub/pthread_cond_wait.c", + "wasi/thread-stub/pthread_create.c", + "wasi/thread-stub/pthread_detach.c", + "wasi/thread-stub/pthread_getattr_np.c", + "wasi/thread-stub/pthread_join.c", + "wasi/thread-stub/pthread_mutex_consistent.c", + "wasi/thread-stub/pthread_mutex_getprioceiling.c", + "wasi/thread-stub/pthread_mutex_lock.c", + "wasi/thread-stub/pthread_mutex_timedlock.c", + "wasi/thread-stub/pthread_mutex_trylock.c", + "wasi/thread-stub/pthread_mutex_unlock.c", + "wasi/thread-stub/pthread_once.c", + "wasi/thread-stub/pthread_rwlock_rdlock.c", + "wasi/thread-stub/pthread_rwlock_timedrdlock.c", + "wasi/thread-stub/pthread_rwlock_timedwrlock.c", + "wasi/thread-stub/pthread_rwlock_tryrdlock.c", + "wasi/thread-stub/pthread_rwlock_trywrlock.c", + "wasi/thread-stub/pthread_rwlock_unlock.c", + "wasi/thread-stub/pthread_rwlock_wrlock.c", + "wasi/thread-stub/pthread_spin_lock.c", + "wasi/thread-stub/pthread_spin_trylock.c", + "wasi/thread-stub/pthread_spin_unlock.c", }; const crt1_command_src_file = "wasi/libc-bottom-half/crt/crt1-command.c"; const crt1_reactor_src_file = "wasi/libc-bottom-half/crt/crt1-reactor.c"; +const fts_src_files = &[_][]const u8{ + "wasi/fts/musl-fts/fts.c", +}; + +const setjmp_src_files = &[_][]const u8{ + "wasi/libc-top-half/musl/src/setjmp/wasm32/rt.c", +}; + const emulated_dl_src_files = &[_][]const u8{ "wasi/libc-top-half/musl/src/misc/dl.c", };