From cabdb42f39a7c571b6f84cdd649f7d28ff9a2cdb Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 1 Jul 2021 15:12:55 -0400 Subject: [PATCH 01/41] Add Wasm32 LibC (based on musl) --- src/lib_c/wasm32-wasi/c/arpa/inet.cr | 9 ++ src/lib_c/wasm32-wasi/c/dirent.cr | 22 +++++ src/lib_c/wasm32-wasi/c/dlfcn.cr | 21 +++++ src/lib_c/wasm32-wasi/c/elf.cr | 24 +++++ src/lib_c/wasm32-wasi/c/errno.cr | 83 ++++++++++++++++ src/lib_c/wasm32-wasi/c/fcntl.cr | 32 +++++++ src/lib_c/wasm32-wasi/c/grp.cr | 11 +++ src/lib_c/wasm32-wasi/c/iconv.cr | 9 ++ src/lib_c/wasm32-wasi/c/link.cr | 13 +++ src/lib_c/wasm32-wasi/c/netdb.cr | 39 ++++++++ src/lib_c/wasm32-wasi/c/netinet/in.cr | 68 ++++++++++++++ src/lib_c/wasm32-wasi/c/netinet/tcp.cr | 6 ++ src/lib_c/wasm32-wasi/c/pthread.cr | 30 ++++++ src/lib_c/wasm32-wasi/c/pwd.cr | 14 +++ src/lib_c/wasm32-wasi/c/sched.cr | 3 + src/lib_c/wasm32-wasi/c/signal.cr | 86 +++++++++++++++++ src/lib_c/wasm32-wasi/c/stdarg.cr | 3 + src/lib_c/wasm32-wasi/c/stddef.cr | 3 + src/lib_c/wasm32-wasi/c/stdint.cr | 10 ++ src/lib_c/wasm32-wasi/c/stdio.cr | 9 ++ src/lib_c/wasm32-wasi/c/stdlib.cr | 25 +++++ src/lib_c/wasm32-wasi/c/string.cr | 9 ++ src/lib_c/wasm32-wasi/c/sys/file.cr | 11 +++ src/lib_c/wasm32-wasi/c/sys/mman.cr | 31 ++++++ src/lib_c/wasm32-wasi/c/sys/resource.cr | 25 +++++ src/lib_c/wasm32-wasi/c/sys/select.cr | 14 +++ src/lib_c/wasm32-wasi/c/sys/socket.cr | 65 +++++++++++++ src/lib_c/wasm32-wasi/c/sys/stat.cr | 56 +++++++++++ src/lib_c/wasm32-wasi/c/sys/syscall.cr | 3 + src/lib_c/wasm32-wasi/c/sys/time.cr | 16 ++++ src/lib_c/wasm32-wasi/c/sys/types.cr | 61 ++++++++++++ src/lib_c/wasm32-wasi/c/sys/un.cr | 8 ++ src/lib_c/wasm32-wasi/c/sys/wait.cr | 8 ++ src/lib_c/wasm32-wasi/c/termios.cr | 120 ++++++++++++++++++++++++ src/lib_c/wasm32-wasi/c/time.cr | 37 ++++++++ src/lib_c/wasm32-wasi/c/unistd.cr | 47 ++++++++++ 36 files changed, 1031 insertions(+) create mode 100644 src/lib_c/wasm32-wasi/c/arpa/inet.cr create mode 100644 src/lib_c/wasm32-wasi/c/dirent.cr create mode 100644 src/lib_c/wasm32-wasi/c/dlfcn.cr create mode 100644 src/lib_c/wasm32-wasi/c/elf.cr create mode 100644 src/lib_c/wasm32-wasi/c/errno.cr create mode 100644 src/lib_c/wasm32-wasi/c/fcntl.cr create mode 100644 src/lib_c/wasm32-wasi/c/grp.cr create mode 100644 src/lib_c/wasm32-wasi/c/iconv.cr create mode 100644 src/lib_c/wasm32-wasi/c/link.cr create mode 100644 src/lib_c/wasm32-wasi/c/netdb.cr create mode 100644 src/lib_c/wasm32-wasi/c/netinet/in.cr create mode 100644 src/lib_c/wasm32-wasi/c/netinet/tcp.cr create mode 100644 src/lib_c/wasm32-wasi/c/pthread.cr create mode 100644 src/lib_c/wasm32-wasi/c/pwd.cr create mode 100644 src/lib_c/wasm32-wasi/c/sched.cr create mode 100644 src/lib_c/wasm32-wasi/c/signal.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdarg.cr create mode 100644 src/lib_c/wasm32-wasi/c/stddef.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdint.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdio.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdlib.cr create mode 100644 src/lib_c/wasm32-wasi/c/string.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/file.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/mman.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/resource.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/select.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/socket.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/stat.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/syscall.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/time.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/types.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/un.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/wait.cr create mode 100644 src/lib_c/wasm32-wasi/c/termios.cr create mode 100644 src/lib_c/wasm32-wasi/c/time.cr create mode 100644 src/lib_c/wasm32-wasi/c/unistd.cr diff --git a/src/lib_c/wasm32-wasi/c/arpa/inet.cr b/src/lib_c/wasm32-wasi/c/arpa/inet.cr new file mode 100644 index 000000000000..afac8795f66f --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/arpa/inet.cr @@ -0,0 +1,9 @@ +require "../netinet/in" +require "../stdint" + +lib LibC + fun htons(x0 : UInt16T) : UInt16T + fun ntohs(x0 : UInt16T) : UInt16T + fun inet_ntop(x0 : Int, x1 : Void*, x2 : Char*, x3 : SocklenT) : Char* + fun inet_pton(x0 : Int, x1 : Char*, x2 : Void*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/dirent.cr b/src/lib_c/wasm32-wasi/c/dirent.cr new file mode 100644 index 000000000000..124a1f760ffa --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/dirent.cr @@ -0,0 +1,22 @@ +require "./sys/types" + +lib LibC + type DIR = Void + + DT_UNKNOWN = 0 + DT_DIR = 4 + DT_LINK = 10 + + struct Dirent + d_ino : InoT + d_off : OffT + d_reclen : UShort + d_type : Char + d_name : StaticArray(Char, 256) + end + + fun closedir(x0 : DIR*) : Int + fun opendir(x0 : Char*) : DIR* + fun readdir(x0 : DIR*) : Dirent* + fun rewinddir(x0 : DIR*) : Void +end diff --git a/src/lib_c/wasm32-wasi/c/dlfcn.cr b/src/lib_c/wasm32-wasi/c/dlfcn.cr new file mode 100644 index 000000000000..2f48a19e8092 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/dlfcn.cr @@ -0,0 +1,21 @@ +lib LibC + RTLD_LAZY = 1 + RTLD_NOW = 2 + RTLD_GLOBAL = 256 + RTLD_LOCAL = 0 + RTLD_DEFAULT = Pointer(Void).new(0) + RTLD_NEXT = Pointer(Void).new(-1) + + struct DlInfo + dli_fname : Char* + dli_fbase : Void* + dli_sname : Char* + dli_saddr : Void* + end + + fun dlclose(x0 : Void*) : Int + fun dlerror : Char* + fun dlopen(x0 : Char*, x1 : Int) : Void* + fun dlsym(x0 : Void*, x1 : Char*) : Void* + fun dladdr(x0 : Void*, x1 : DlInfo*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/elf.cr b/src/lib_c/wasm32-wasi/c/elf.cr new file mode 100644 index 000000000000..32a0dc3152d1 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/elf.cr @@ -0,0 +1,24 @@ +require "./sys/types" + +lib LibC + alias Elf_Half = UInt16T + alias Elf_Word = UInt32T + alias Elf_Sword = Int32T + alias Elf_Xword = UInt64T + alias Elf_Sxword = Int64T + alias Elf_Addr = UInt32T + alias Elf_Off = UInt32T + alias Elf_Section = UInt16T + alias Elf_Versym = Elf_Half + + struct Elf_Phdr + type : Elf_Word # Segment type + offset : Elf_Off # Segment file offset + vaddr : Elf_Addr # Segment virtual address + paddr : Elf_Addr # Segment physical address + filesz : Elf_Word # Segment size in file + memsz : Elf_Word # Segment size in memory + flags : Elf_Word # Segment flags + align : Elf_Word # Segment alignment + end +end diff --git a/src/lib_c/wasm32-wasi/c/errno.cr b/src/lib_c/wasm32-wasi/c/errno.cr new file mode 100644 index 000000000000..8b528cc5bb71 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/errno.cr @@ -0,0 +1,83 @@ +lib LibC + E2BIG = 7 + EACCES = 13 + EADDRINUSE = 98 + EADDRNOTAVAIL = 99 + EAFNOSUPPORT = 97 + EAGAIN = 11 + EALREADY = 114 + EBADF = 9 + EBADMSG = 74 + EBUSY = 16 + ECANCELED = 125 + ECHILD = 10 + ECONNABORTED = 103 + ECONNREFUSED = 111 + ECONNRESET = 104 + EDEADLK = 35 + EDESTADDRREQ = 89 + EDOM = 33 + EDQUOT = 122 + EEXIST = 17 + EFAULT = 14 + EFBIG = 27 + EHOSTUNREACH = 113 + EIDRM = 43 + EILSEQ = 84 + EINPROGRESS = 115 + EINTR = 4 + EINVAL = 22 + EIO = 5 + EISCONN = 106 + EISDIR = 21 + ELOOP = 40 + EMFILE = 24 + EMLINK = 31 + EMSGSIZE = 90 + EMULTIHOP = 72 + ENAMETOOLONG = 36 + ENETDOWN = 100 + ENETRESET = 102 + ENETUNREACH = 101 + ENFILE = 23 + ENOBUFS = 105 + ENODEV = 19 + ENOENT = 2 + ENOEXEC = 8 + ENOLCK = 37 + ENOLINK = 67 + ENOMEM = 12 + ENOMSG = 42 + ENOPROTOOPT = 92 + ENOSPC = 28 + ENOSYS = 38 + ENOTCONN = 107 + ENOTDIR = 20 + ENOTEMPTY = 39 + ENOTRECOVERABLE = 131 + ENOTSOCK = 88 + ENOTSUP = LibC::EOPNOTSUPP + ENOTTY = 25 + ENXIO = 6 + EOPNOTSUPP = 95 + EOVERFLOW = 75 + EOWNERDEAD = 130 + EPERM = 1 + EPIPE = 32 + EPROTO = 71 + EPROTONOSUPPORT = 93 + EPROTOTYPE = 91 + ERANGE = 34 + EROFS = 30 + ESPIPE = 29 + ESRCH = 3 + ESTALE = 116 + ETIMEDOUT = 110 + ETXTBSY = 26 + EWOULDBLOCK = LibC::EAGAIN + EXDEV = 18 + ENODATA = 61 + ENOSR = 63 + ENOSTR = 60 + ETIME = 62 +end diff --git a/src/lib_c/wasm32-wasi/c/fcntl.cr b/src/lib_c/wasm32-wasi/c/fcntl.cr new file mode 100644 index 000000000000..6beab0d6de74 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/fcntl.cr @@ -0,0 +1,32 @@ +require "./sys/types" +require "./sys/stat" +require "./unistd" + +lib LibC + F_GETFD = 1 + F_SETFD = 2 + F_GETFL = 3 + F_SETFL = 4 + FD_CLOEXEC = 1 + O_CLOEXEC = 0o2000000 + O_CREAT = 0o100 + O_NOFOLLOW = 0o400000 + O_TRUNC = 0o1000 + O_APPEND = 0o2000 + O_NONBLOCK = 0o4000 + O_SYNC = 0o4010000 + O_RDONLY = 0o0 + O_RDWR = 0o2 + O_WRONLY = 0o1 + + struct Flock + l_type : Short + l_whence : Short + l_start : OffT + l_len : OffT + l_pid : PidT + end + + fun fcntl(x0 : Int, x1 : Int, ...) : Int + fun open(x0 : Char*, x1 : Int, ...) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/grp.cr b/src/lib_c/wasm32-wasi/c/grp.cr new file mode 100644 index 000000000000..2fc351260b20 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/grp.cr @@ -0,0 +1,11 @@ +lib LibC + struct Group + gr_name : Char* + gr_passwd : Char* + gr_gid : GidT + gr_mem : Char** + end + + fun getgrnam_r(name : Char*, grp : Group*, buf : Char*, bufsize : SizeT, result : Group**) : Int + fun getgrgid_r(gid : GidT, grp : Group*, buf : Char*, bufsize : SizeT, result : Group**) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/iconv.cr b/src/lib_c/wasm32-wasi/c/iconv.cr new file mode 100644 index 000000000000..6496b957ed24 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/iconv.cr @@ -0,0 +1,9 @@ +require "./stddef" + +lib LibC + type IconvT = Void* + + fun iconv(x0 : IconvT, x1 : Char**, x2 : SizeT*, x3 : Char**, x4 : SizeT*) : SizeT + fun iconv_close(x0 : IconvT) : Int + fun iconv_open(x0 : Char*, x1 : Char*) : IconvT +end diff --git a/src/lib_c/wasm32-wasi/c/link.cr b/src/lib_c/wasm32-wasi/c/link.cr new file mode 100644 index 000000000000..a29bd3030a42 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/link.cr @@ -0,0 +1,13 @@ +require "./elf" + +lib LibC + struct DlPhdrInfo + addr : Elf_Addr + name : Char* + phdr : Elf_Phdr* + phnum : Elf_Half + end + + alias DlPhdrCallback = (DlPhdrInfo*, LibC::SizeT, Void*) -> LibC::Int + fun dl_iterate_phdr(callback : DlPhdrCallback, data : Void*) +end diff --git a/src/lib_c/wasm32-wasi/c/netdb.cr b/src/lib_c/wasm32-wasi/c/netdb.cr new file mode 100644 index 000000000000..a5ac97843811 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/netdb.cr @@ -0,0 +1,39 @@ +require "./netinet/in" +require "./sys/socket" +require "./stdint" + +lib LibC + AI_PASSIVE = 0x01 + AI_CANONNAME = 0x02 + AI_NUMERICHOST = 0x04 + AI_NUMERICSERV = 0x400 + AI_V4MAPPED = 0x08 + AI_ALL = 0x10 + AI_ADDRCONFIG = 0x20 + EAI_AGAIN = -3 + EAI_BADFLAGS = -1 + EAI_FAIL = -4 + EAI_FAMILY = -6 + EAI_MEMORY = -10 + EAI_NONAME = -2 + EAI_SERVICE = -8 + EAI_SOCKTYPE = -7 + EAI_SYSTEM = -11 + EAI_OVERFLOW = -12 + + struct Addrinfo + ai_flags : Int + ai_family : Int + ai_socktype : Int + ai_protocol : Int + ai_addrlen : SocklenT + ai_addr : Sockaddr* + ai_canonname : Char* + ai_next : Addrinfo* + end + + fun freeaddrinfo(x0 : Addrinfo*) : Void + fun gai_strerror(x0 : Int) : Char* + fun getaddrinfo(x0 : Char*, x1 : Char*, x2 : Addrinfo*, x3 : Addrinfo**) : Int + fun getnameinfo(x0 : Sockaddr*, x1 : SocklenT, x2 : Char*, x3 : SocklenT, x4 : Char*, x5 : SocklenT, x6 : Int) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/netinet/in.cr b/src/lib_c/wasm32-wasi/c/netinet/in.cr new file mode 100644 index 000000000000..c497075effaf --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/netinet/in.cr @@ -0,0 +1,68 @@ +require "../sys/socket" +require "../stdint" + +lib LibC + IPPROTO_IP = 0 + IPPROTO_IPV6 = 41 + IPPROTO_ICMP = 1 + IPPROTO_RAW = 255 + IPPROTO_TCP = 6 + IPPROTO_UDP = 17 + + alias InPortT = UInt16T + alias InAddrT = UInt32T + + struct InAddr + s_addr : InAddrT + end + + union In6AddrIn6Union + __s6_addr : StaticArray(UInt8T, 16) + __s6_addr16 : StaticArray(UInt16T, 8) + __s6_addr32 : StaticArray(UInt32T, 4) + end + + struct In6Addr + __in6_union : In6AddrIn6Union + end + + struct SockaddrIn + sin_family : SaFamilyT + sin_port : InPortT + sin_addr : InAddr + sin_zero : StaticArray(UInt8T, 8) + end + + struct SockaddrIn6 + sin6_family : SaFamilyT + sin6_port : InPortT + sin6_flowinfo : UInt32T + sin6_addr : In6Addr + sin6_scope_id : UInt32T + end + + IP_MULTICAST_IF = 32 + IPV6_MULTICAST_IF = 17 + + IP_MULTICAST_TTL = 33 + IPV6_MULTICAST_HOPS = 18 + + IP_MULTICAST_LOOP = 34 + IPV6_MULTICAST_LOOP = 19 + + IP_ADD_MEMBERSHIP = 35 + IPV6_JOIN_GROUP = 20 + + IP_DROP_MEMBERSHIP = 36 + IPV6_LEAVE_GROUP = 21 + + struct IpMreq + imr_multiaddr : InAddr + imr_interface : InAddr + end + + struct Ipv6Mreq + ipv6mr_multiaddr : In6Addr + ipv6mr_interface : UInt + end +end diff --git a/src/lib_c/wasm32-wasi/c/netinet/tcp.cr b/src/lib_c/wasm32-wasi/c/netinet/tcp.cr new file mode 100644 index 000000000000..beed1db6e081 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/netinet/tcp.cr @@ -0,0 +1,6 @@ +lib LibC + TCP_NODELAY = 1 + TCP_KEEPIDLE = 4 + TCP_KEEPINTVL = 5 + TCP_KEEPCNT = 6 +end diff --git a/src/lib_c/wasm32-wasi/c/pthread.cr b/src/lib_c/wasm32-wasi/c/pthread.cr new file mode 100644 index 000000000000..c318bb5f4357 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/pthread.cr @@ -0,0 +1,30 @@ +require "./sys/types" + +lib LibC + PTHREAD_MUTEX_ERRORCHECK = 2 + + fun pthread_attr_destroy(x0 : PthreadAttrT*) : Int + fun pthread_attr_getstack(x0 : PthreadAttrT*, x1 : Void**, x2 : SizeT*) : Int + fun pthread_condattr_destroy(x0 : PthreadCondattrT*) : Int + fun pthread_condattr_init(x0 : PthreadCondattrT*) : Int + fun pthread_condattr_setclock(x0 : PthreadCondattrT*, x1 : ClockidT) : Int + fun pthread_cond_broadcast(x0 : PthreadCondT*) : Int + fun pthread_cond_destroy(x0 : PthreadCondT*) : Int + fun pthread_cond_init(x0 : PthreadCondT*, x1 : PthreadCondattrT*) : Int + fun pthread_cond_signal(x0 : PthreadCondT*) : Int + fun pthread_cond_timedwait(x0 : PthreadCondT*, x1 : PthreadMutexT*, x2 : Timespec*) : Int + fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int + fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int + fun pthread_detach(x0 : PthreadT) : Int + fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int + fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int + fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int + fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int + fun pthread_mutex_destroy(x0 : PthreadMutexT*) : Int + fun pthread_mutex_init(x0 : PthreadMutexT*, x1 : PthreadMutexattrT*) : Int + fun pthread_mutex_lock(x0 : PthreadMutexT*) : Int + fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int + fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int + fun pthread_self : PthreadT +end diff --git a/src/lib_c/wasm32-wasi/c/pwd.cr b/src/lib_c/wasm32-wasi/c/pwd.cr new file mode 100644 index 000000000000..dc2e53d4a53a --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/pwd.cr @@ -0,0 +1,14 @@ +lib LibC + struct Passwd + pw_name : Char* + pw_passwd : Char* + pw_uid : UidT + pw_gid : GidT + pw_gecos : Char* + pw_dir : Char* + pw_shell : Char* + end + + fun getpwnam_r(login : Char*, pwstore : Passwd*, buf : Char*, bufsize : SizeT, result : Passwd**) : Int + fun getpwuid_r(uid : UidT, pwstore : Passwd*, buf : Char*, bufsize : SizeT, result : Passwd**) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sched.cr b/src/lib_c/wasm32-wasi/c/sched.cr new file mode 100644 index 000000000000..9d83ed18504e --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sched.cr @@ -0,0 +1,3 @@ +lib LibC + fun sched_yield : Int +end diff --git a/src/lib_c/wasm32-wasi/c/signal.cr b/src/lib_c/wasm32-wasi/c/signal.cr new file mode 100644 index 000000000000..d822d82b9d27 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/signal.cr @@ -0,0 +1,86 @@ +require "./sys/types" +require "./time" + +lib LibC + SIGHUP = 1 + SIGINT = 2 + SIGQUIT = 3 + SIGILL = 4 + SIGTRAP = 5 + SIGIOT = LibC::SIGABRT + SIGABRT = 6 + SIGFPE = 8 + SIGKILL = 9 + SIGBUS = 7 + SIGSEGV = 11 + SIGSYS = 31 + SIGPIPE = 13 + SIGALRM = 14 + SIGTERM = 15 + SIGURG = 23 + SIGSTOP = 19 + SIGTSTP = 20 + SIGCONT = 18 + SIGCHLD = 17 + SIGTTIN = 21 + SIGTTOU = 22 + SIGIO = 29 + SIGXCPU = 24 + SIGXFSZ = 25 + SIGVTALRM = 26 + SIGUSR1 = 10 + SIGUSR2 = 12 + SIGWINCH = 28 + SIGPWR = 30 + SIGSTKFLT = 16 + SIGUNUSED = LibC::SIGSYS + + SIGSTKSZ = 8192 + + SIG_SETMASK = 2 + + alias SighandlerT = Int -> + SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) + SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null) + + struct SigsetT + bits : ULong[32] # 128 / sizeof(long) + end + + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + + fun kill(x0 : PidT, x1 : Int) : Int + fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int + fun sigemptyset(SigsetT*) : Int + fun sigfillset(SigsetT*) : Int + fun sigaddset(SigsetT*, Int) : Int + fun sigdelset(SigsetT*, Int) : Int + fun sigismember(SigsetT*, Int) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/stdarg.cr b/src/lib_c/wasm32-wasi/c/stdarg.cr new file mode 100644 index 000000000000..882d4f51d35c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdarg.cr @@ -0,0 +1,3 @@ +lib LibC + type VaList = Void* +end diff --git a/src/lib_c/wasm32-wasi/c/stddef.cr b/src/lib_c/wasm32-wasi/c/stddef.cr new file mode 100644 index 000000000000..5939010b0538 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stddef.cr @@ -0,0 +1,3 @@ +lib LibC + alias SizeT = UInt +end diff --git a/src/lib_c/wasm32-wasi/c/stdint.cr b/src/lib_c/wasm32-wasi/c/stdint.cr new file mode 100644 index 000000000000..5cb258eccd2c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdint.cr @@ -0,0 +1,10 @@ +lib LibC + alias Int8T = SChar + alias Int16T = Short + alias Int32T = Int + alias Int64T = LongLong + alias UInt8T = Char + alias UInt16T = UShort + alias UInt32T = UInt + alias UInt64T = ULongLong +end diff --git a/src/lib_c/wasm32-wasi/c/stdio.cr b/src/lib_c/wasm32-wasi/c/stdio.cr new file mode 100644 index 000000000000..44fb5b8a1e74 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdio.cr @@ -0,0 +1,9 @@ +require "./sys/types" +require "./stddef" + +lib LibC + fun printf(x0 : Char*, ...) : Int + fun dprintf(fd : Int, format : Char*, ...) : Int + fun rename(x0 : Char*, x1 : Char*) : Int + fun snprintf(x0 : Char*, x1 : SizeT, x2 : Char*, ...) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/stdlib.cr b/src/lib_c/wasm32-wasi/c/stdlib.cr new file mode 100644 index 000000000000..d3325e2defd0 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdlib.cr @@ -0,0 +1,25 @@ +require "./stddef" +require "./sys/wait" + +lib LibC + struct DivT + quot : Int + rem : Int + end + + fun atof(x0 : Char*) : Double + fun div(x0 : Int, x1 : Int) : DivT + fun exit(x0 : Int) : NoReturn + fun free(x0 : Void*) : Void + fun getenv(x0 : Char*) : Char* + fun malloc(x0 : SizeT) : Void* + fun mkstemp(x0 : Char*) : Int + fun mkstemps(x0 : Char*, x1 : Int) : Int + fun putenv(x0 : Char*) : Int + fun realloc(x0 : Void*, x1 : SizeT) : Void* + fun realpath(x0 : Char*, x1 : Char*) : Char* + fun setenv(x0 : Char*, x1 : Char*, x2 : Int) : Int + fun strtof(x0 : Char*, x1 : Char**) : Float + fun strtod(x0 : Char*, x1 : Char**) : Double + fun unsetenv(x0 : Char*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/string.cr b/src/lib_c/wasm32-wasi/c/string.cr new file mode 100644 index 000000000000..02e025ae4880 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/string.cr @@ -0,0 +1,9 @@ +require "./stddef" + +lib LibC + fun memchr(x0 : Void*, c : Int, n : SizeT) : Void* + fun memcmp(x0 : Void*, x1 : Void*, x2 : SizeT) : Int + fun strcmp(x0 : Char*, x1 : Char*) : Int + fun strerror(x0 : Int) : Char* + fun strlen(x0 : Char*) : SizeT +end diff --git a/src/lib_c/wasm32-wasi/c/sys/file.cr b/src/lib_c/wasm32-wasi/c/sys/file.cr new file mode 100644 index 000000000000..e2bd3fd4b816 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/file.cr @@ -0,0 +1,11 @@ +lib LibC + @[Flags] + enum FlockOp + SH = 0x1 + EX = 0x2 + NB = 0x4 + UN = 0x8 + end + + fun flock(fd : Int, op : FlockOp) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/mman.cr b/src/lib_c/wasm32-wasi/c/sys/mman.cr new file mode 100644 index 000000000000..4dd11dad0918 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/mman.cr @@ -0,0 +1,31 @@ +require "./types" + +lib LibC + PROT_EXEC = 4 + PROT_NONE = 0 + PROT_READ = 1 + PROT_WRITE = 2 + MAP_FIXED = 0x10 + MAP_PRIVATE = 0x02 + MAP_SHARED = 0x01 + MAP_ANON = 0x20 + MAP_ANONYMOUS = LibC::MAP_ANON + MAP_FAILED = Pointer(Void).new(-1) + POSIX_MADV_DONTNEED = 0 + POSIX_MADV_NORMAL = 0 + POSIX_MADV_RANDOM = 1 + POSIX_MADV_SEQUENTIAL = 2 + POSIX_MADV_WILLNEED = 3 + MADV_DONTNEED = 4 + MADV_NORMAL = 0 + MADV_RANDOM = 1 + MADV_SEQUENTIAL = 2 + MADV_WILLNEED = 3 + MADV_HUGEPAGE = 14 + MADV_NOHUGEPAGE = 15 + + fun mmap(x0 : Void*, x1 : SizeT, x2 : Int, x3 : Int, x4 : Int, x5 : OffT) : Void* + fun mprotect(x0 : Void*, x1 : SizeT, x2 : Int) : Int + fun munmap(x0 : Void*, x1 : SizeT) : Int + fun madvise(x0 : Void*, x1 : SizeT, x2 : Int) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/resource.cr b/src/lib_c/wasm32-wasi/c/sys/resource.cr new file mode 100644 index 000000000000..7f550c37a622 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/resource.cr @@ -0,0 +1,25 @@ +lib LibC + struct RUsage + ru_utime : Timeval + ru_stime : Timeval + ru_maxrss : Long + ru_ix_rss : Long + ru_idrss : Long + ru_isrss : Long + ru_minflt : Long + ru_majflt : Long + ru_nswap : Long + ru_inblock : Long + ru_oublock : Long + ru_msgsnd : Long + ru_msgrcv : Long + ru_nsignals : Long + ru_nvcsw : Long + ru_nivcsw : Long + end + + RUSAGE_SELF = 0 + RUSAGE_CHILDREN = -1 + + fun getrusage(who : Int, usage : RUsage*) : Int16 +end diff --git a/src/lib_c/wasm32-wasi/c/sys/select.cr b/src/lib_c/wasm32-wasi/c/sys/select.cr new file mode 100644 index 000000000000..5e6970e6e20c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/select.cr @@ -0,0 +1,14 @@ +require "./types" +require "./time" +require "../time" +require "../signal" + +lib LibC + alias FdMask = ULong + + struct FdSet + fds_bits : StaticArray(ULong, 16) + end + + fun select(x0 : Int, x1 : FdSet*, x2 : FdSet*, x3 : FdSet*, x4 : Timeval*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/socket.cr b/src/lib_c/wasm32-wasi/c/sys/socket.cr new file mode 100644 index 000000000000..361e5b8040d6 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/socket.cr @@ -0,0 +1,65 @@ +require "./types" + +lib LibC + SOCK_DGRAM = 2 + SOCK_RAW = 3 + SOCK_SEQPACKET = 5 + SOCK_STREAM = 1 + SOL_SOCKET = 1 + SO_BROADCAST = 6 + SO_KEEPALIVE = 9 + SO_LINGER = 13 + SO_RCVBUF = 8 + SO_REUSEADDR = 2 + SO_REUSEPORT = 15 + SO_SNDBUF = 7 + PF_INET = 2 + PF_INET6 = 10 + PF_UNIX = LibC::PF_LOCAL + PF_UNSPEC = 0 + PF_LOCAL = 1 + AF_INET = LibC::PF_INET + AF_INET6 = LibC::PF_INET6 + AF_UNIX = LibC::AF_LOCAL + AF_UNSPEC = LibC::PF_UNSPEC + AF_LOCAL = LibC::PF_LOCAL + SHUT_RD = 0 + SHUT_RDWR = 2 + SHUT_WR = 1 + SOCK_CLOEXEC = 0o2000000 + + alias SocklenT = UInt + alias SaFamilyT = UShort + + struct Sockaddr + sa_family : SaFamilyT + sa_data : StaticArray(Char, 14) + end + + struct SockaddrStorage + ss_family : SaFamilyT + __ss_align : ULong + __ss_padding : StaticArray(Char, 112) + end + + struct Linger + l_onoff : Int + l_linger : Int + end + + fun accept(x0 : Int, x1 : Sockaddr*, x2 : SocklenT*) : Int + fun bind(x0 : Int, x1 : Sockaddr*, x2 : SocklenT) : Int + fun connect(x0 : Int, x1 : Sockaddr*, x2 : SocklenT) : Int + fun getpeername(x0 : Int, x1 : Sockaddr*, x2 : SocklenT*) : Int + fun getsockname(x0 : Int, x1 : Sockaddr*, x2 : SocklenT*) : Int + fun getsockopt(x0 : Int, x1 : Int, x2 : Int, x3 : Void*, x4 : SocklenT*) : Int + fun listen(x0 : Int, x1 : Int) : Int + fun recv(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int) : SSizeT + fun recvfrom(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int, x4 : Sockaddr*, x5 : SocklenT*) : SSizeT + fun send(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int) : SSizeT + fun sendto(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int, x4 : Sockaddr*, x5 : SocklenT) : SSizeT + fun setsockopt(x0 : Int, x1 : Int, x2 : Int, x3 : Void*, x4 : SocklenT) : Int + fun shutdown(x0 : Int, x1 : Int) : Int + fun socket(x0 : Int, x1 : Int, x2 : Int) : Int + fun socketpair(x0 : Int, x1 : Int, x2 : Int, x3 : StaticArray(Int, 2)) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/stat.cr b/src/lib_c/wasm32-wasi/c/sys/stat.cr new file mode 100644 index 000000000000..e86ed5d144f7 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/stat.cr @@ -0,0 +1,56 @@ +require "./types" +require "../time" + +lib LibC + S_IFMT = 0o170000 + S_IFBLK = 0o060000 + S_IFCHR = 0o020000 + S_IFIFO = 0o010000 + S_IFREG = 0o100000 + S_IFDIR = 0o040000 + S_IFLNK = 0o120000 + S_IFSOCK = 0o140000 + S_IRUSR = 0o400 + S_IWUSR = 0o200 + S_IXUSR = 0o100 + S_IRWXU = 0o700 + S_IRGRP = 0o040 + S_IWGRP = 0o020 + S_IXGRP = 0o010 + S_IRWXG = 0o070 + S_IROTH = 0o004 + S_IWOTH = 0o002 + S_IXOTH = 0o001 + S_IRWXO = 0o007 + S_ISUID = 0o4000 + S_ISGID = 0o2000 + S_ISVTX = 0o1000 + + struct Stat + st_dev : DevT + __st_dev_padding : Int + __st_ino_truncated : Long + st_mode : ModeT + st_nlink : NlinkT + st_uid : UidT + st_gid : GidT + st_rdev : DevT + __st_rdev_padding : Int + st_size : OffT + st_blksize : BlksizeT + st_blocks : BlkcntT + st_atim : Timespec + st_mtim : Timespec + st_ctim : Timespec + st_ino : InoT + end + + fun chmod(x0 : Char*, x1 : ModeT) : Int + fun fstat(x0 : Int, x1 : Stat*) : Int + fun lstat(x0 : Char*, x1 : Stat*) : Int + fun mkdir(x0 : Char*, x1 : ModeT) : Int + fun mkfifo(x0 : Char*, x1 : ModeT) : Int + fun mknod(x0 : Char*, x1 : ModeT, x2 : DevT) : Int + fun stat(x0 : Char*, x1 : Stat*) : Int + fun umask(x0 : ModeT) : ModeT +end diff --git a/src/lib_c/wasm32-wasi/c/sys/syscall.cr b/src/lib_c/wasm32-wasi/c/sys/syscall.cr new file mode 100644 index 000000000000..ceb04c887181 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/syscall.cr @@ -0,0 +1,3 @@ +lib LibC + SYS_getrandom = 318 +end diff --git a/src/lib_c/wasm32-wasi/c/sys/time.cr b/src/lib_c/wasm32-wasi/c/sys/time.cr new file mode 100644 index 000000000000..dbe23bac4c86 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/time.cr @@ -0,0 +1,16 @@ +require "./types" + +lib LibC + struct Timeval + tv_sec : TimeT + tv_usec : SusecondsT + end + + struct Timezone + tz_minuteswest : Int + tz_dsttime : Int + end + + fun gettimeofday(x0 : Timeval*, x1 : Void*) : Int + fun utimes(path : Char*, times : Timeval[2]) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/types.cr b/src/lib_c/wasm32-wasi/c/sys/types.cr new file mode 100644 index 000000000000..e8a6362b52fe --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/types.cr @@ -0,0 +1,61 @@ +require "../stddef" +require "../stdint" + +lib LibC + alias BlkcntT = LongLong + alias BlksizeT = Long + alias ClockT = Long + alias ClockidT = Int + alias DevT = ULongLong + alias GidT = UInt + alias IdT = UInt + alias InoT = ULongLong + alias ModeT = UInt + alias NlinkT = UInt + alias OffT = LongLong + alias PidT = Int + + union PthreadAttrTU + __i : StaticArray(Int, 9) + __vi : StaticArray(Int, 9) + __s : StaticArray(UInt, 9) + end + + struct PthreadAttrT + __u : PthreadAttrTU + end + + union PthreadCondTU + __i : StaticArray(Int, 12) + __vi : StaticArray(Int, 12) + __p : StaticArray(Void*, 12) + end + + struct PthreadCondT + __u : PthreadCondTU + end + + struct PthreadCondattrT + __attr : UInt + end + + union PthreadMutexTU + __i : StaticArray(Int, 6) + __vi : StaticArray(Int, 6) + __p : StaticArray(Void*, 6) + end + + struct PthreadMutexT + __u : PthreadMutexTU + end + + struct PthreadMutexattrT + __attr : UInt + end + + type PthreadT = Void* + alias SSizeT = Int + alias SusecondsT = Long + alias TimeT = Long + alias UidT = UInt +end diff --git a/src/lib_c/wasm32-wasi/c/sys/un.cr b/src/lib_c/wasm32-wasi/c/sys/un.cr new file mode 100644 index 000000000000..7f5bd705a4dd --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/un.cr @@ -0,0 +1,8 @@ +require "./socket" + +lib LibC + struct SockaddrUn + sun_family : SaFamilyT + sun_path : StaticArray(Char, 108) + end +end diff --git a/src/lib_c/wasm32-wasi/c/sys/wait.cr b/src/lib_c/wasm32-wasi/c/sys/wait.cr new file mode 100644 index 000000000000..e9c185b5ac9c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/wait.cr @@ -0,0 +1,8 @@ +require "./types" +require "../signal" + +lib LibC + WNOHANG = 1 + + fun waitpid(x0 : PidT, x1 : Int*, x2 : Int) : PidT +end diff --git a/src/lib_c/wasm32-wasi/c/termios.cr b/src/lib_c/wasm32-wasi/c/termios.cr new file mode 100644 index 000000000000..49da2c3d0751 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/termios.cr @@ -0,0 +1,120 @@ +require "./sys/types" + +lib LibC + VEOF = 4 + VEOL = 11 + VERASE = 2 + VINTR = 0 + VKILL = 3 + VMIN = 6 + VQUIT = 1 + VSTART = 8 + VSTOP = 9 + VSUSP = 10 + BRKINT = 0o000002 + ICRNL = 0o000400 + IGNBRK = 0o000001 + IGNCR = 0o000200 + IGNPAR = 0o000004 + INLCR = 0o000100 + INPCK = 0o000020 + ISTRIP = 0o000040 + IXANY = 0o004000 + IXOFF = 0o010000 + IXON = 0o002000 + PARMRK = 0o000010 + OPOST = 0o000001 + ONLCR = 0o000004 + OCRNL = 0o000010 + ONOCR = 0o000020 + ONLRET = 0o000040 + OFDEL = 0o000200 + OFILL = 0o000100 + CRDLY = 0o003000 + CR0 = 0o000000 + CR1 = 0o001000 + CR2 = 0o002000 + CR3 = 0o003000 + TABDLY = 0o014000 + TAB0 = 0o000000 + TAB1 = 0o004000 + TAB2 = 0o010000 + TAB3 = 0o014000 + BSDLY = 0o020000 + BS0 = 0o000000 + BS1 = 0o020000 + VTDLY = 0o040000 + VT0 = 0o000000 + VT1 = 0o040000 + FFDLY = 0o100000 + FF0 = 0o000000 + FF1 = 0o100000 + NLDLY = 0o000400 + NL0 = 0o000000 + NL1 = 0o000400 + B0 = 0o000000 + B50 = 0o000001 + B75 = 0o000002 + B110 = 0o000003 + B134 = 0o000004 + B150 = 0o000005 + B200 = 0o000006 + B300 = 0o000007 + B600 = 0o000010 + B1200 = 0o000011 + B1800 = 0o000012 + B2400 = 0o000013 + B4800 = 0o000014 + B9600 = 0o000015 + B19200 = 0o000016 + B38400 = 0o000017 + CSIZE = 0o000060 + CS5 = 0o000000 + CS6 = 0o000020 + CS7 = 0o000040 + CS8 = 0o000060 + CSTOPB = 0o000100 + CREAD = 0o000200 + PARENB = 0o000400 + PARODD = 0o001000 + HUPCL = 0o002000 + CLOCAL = 0o004000 + ECHO = 0o000010 + ECHOE = 0o000020 + ECHOK = 0o000040 + ECHONL = 0o000100 + ICANON = 0o000002 + IEXTEN = 0o100000 + ISIG = 0o000001 + NOFLSH = 0o000200 + TOSTOP = 0o000400 + TCSANOW = 0 + TCSADRAIN = 1 + TCSAFLUSH = 2 + TCIFLUSH = 0 + TCIOFLUSH = 2 + TCOFLUSH = 1 + TCIOFF = 2 + TCION = 3 + TCOOFF = 0 + TCOON = 1 + + alias CcT = Char + alias SpeedT = UInt + alias TcflagT = UInt + + struct Termios + c_iflag : TcflagT + c_oflag : TcflagT + c_cflag : TcflagT + c_lflag : TcflagT + c_line : CcT + c_cc : StaticArray(CcT, 32) + __c_ispeed : SpeedT + __c_ospeed : SpeedT + end + + fun tcgetattr(x0 : Int, x1 : Termios*) : Int + fun tcsetattr(x0 : Int, x1 : Int, x2 : Termios*) : Int + fun cfmakeraw(x0 : Termios*) : Void +end diff --git a/src/lib_c/wasm32-wasi/c/time.cr b/src/lib_c/wasm32-wasi/c/time.cr new file mode 100644 index 000000000000..22fdf7a86ebf --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/time.cr @@ -0,0 +1,37 @@ +require "./sys/types" + +lib LibC + CLOCK_MONOTONIC = 1 + CLOCK_REALTIME = 0 + + struct Tm + tm_sec : Int + tm_min : Int + tm_hour : Int + tm_mday : Int + tm_mon : Int + tm_year : Int + tm_wday : Int + tm_yday : Int + tm_isdst : Int + tm_gmtoff : Long + tm_zone : Char* + end + + struct Timespec + tv_sec : TimeT + tv_nsec : Long + end + + fun clock_gettime(x0 : ClockidT, x1 : Timespec*) : Int + fun clock_settime(x0 : ClockidT, x1 : Timespec*) : Int + fun gmtime_r(x0 : TimeT*, x1 : Tm*) : Tm* + fun localtime_r(x0 : TimeT*, x1 : Tm*) : Tm* + fun mktime(x0 : Tm*) : TimeT + fun tzset : Void + fun timegm(x0 : Tm*) : TimeT + + $daylight : Int + $timezone : Long + $tzname : StaticArray(Char*, 2) +end diff --git a/src/lib_c/wasm32-wasi/c/unistd.cr b/src/lib_c/wasm32-wasi/c/unistd.cr new file mode 100644 index 000000000000..a7e4be16e1f9 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/unistd.cr @@ -0,0 +1,47 @@ +require "./sys/types" +require "./stdint" + +lib LibC + F_OK = 0 + R_OK = 4 + W_OK = 2 + X_OK = 1 + SC_CLK_TCK = 2 + SC_NPROCESSORS_ONLN = 84 + SC_PAGESIZE = 30 + + fun chroot(path : Char*) : Int + fun access(x0 : Char*, x1 : Int) : Int + fun chdir(x0 : Char*) : Int + fun chown(x0 : Char*, x1 : UidT, x2 : GidT) : Int + fun close(x0 : Int) : Int + fun dup2(x0 : Int, x1 : Int) : Int + fun _exit(x0 : Int) : NoReturn + fun execvp(x0 : Char*, x1 : Char**) : Int + fun fdatasync(x0 : Int) : Int + @[ReturnsTwice] + fun fork : PidT + fun fsync(x0 : Int) : Int + fun ftruncate(x0 : Int, x1 : OffT) : Int + fun getcwd(x0 : Char*, x1 : SizeT) : Char* + fun gethostname(x0 : Char*, x1 : SizeT) : Int + fun getpgid(x0 : PidT) : PidT + fun getpid : PidT + fun getppid : PidT + fun isatty(x0 : Int) : Int + fun ttyname_r(fd : Int, buf : Char*, buffersize : SizeT) : Int + fun lchown(x0 : Char*, x1 : UidT, x2 : GidT) : Int + fun link(x0 : Char*, x1 : Char*) : Int + fun lockf(x0 : Int, x1 : Int, x2 : OffT) : Int + fun lseek(x0 : Int, x1 : OffT, x2 : Int) : OffT + fun pipe(x0 : StaticArray(Int, 2)) : Int + fun read(x0 : Int, x1 : Void*, x2 : SizeT) : SSizeT + fun pread(x0 : Int, x1 : Void*, x2 : SizeT, x3 : OffT) : SSizeT + fun rmdir(x0 : Char*) : Int + fun symlink(x0 : Char*, x1 : Char*) : Int + fun readlink(path : Char*, buf : Char*, size : SizeT) : SSizeT + fun syscall(x0 : Long, ...) : Long + fun sysconf(x0 : Int) : Long + fun unlink(x0 : Char*) : Int + fun write(x0 : Int, x1 : Void*, x2 : SizeT) : SSizeT +end From 76d5e22246e11ec2a5121cd5d4741165cd189496 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 1 Jul 2021 15:14:25 -0400 Subject: [PATCH 02/41] Add Basic Wasm32 support --- src/compiler/crystal/codegen/target.cr | 8 +- src/crystal/system/event_loop.cr | 4 +- src/crystal/system/random.cr | 2 + .../system/unix/event_loop_libevent_wasm32.cr | 40 +++++++ src/crystal/system/unix/file_descriptor.cr | 38 +++--- src/crystal/system/unix/getentropy.cr | 74 ++++++++++++ src/crystal/system/unix/pthread.cr | 9 +- src/crystal/system/unix/pthread_mutex.cr | 108 +++++++++++------- src/errno.cr | 4 + src/exception/call_stack.cr | 104 +++++++++-------- src/exception/call_stack/dwarf.cr | 22 ++-- src/fiber/context/wasm32.cr | 13 +++ src/gc.cr | 2 +- src/kernel.cr | 2 +- src/lib_c.cr | 2 +- src/llvm.cr | 17 +++ src/llvm/abi/wasm32.cr | 64 +++++++++++ src/llvm/lib_llvm.cr | 5 + src/llvm/target_machine.cr | 2 + src/prelude.cr | 2 +- src/raise.cr | 28 ++++- src/regex/lib_pcre.cr | 6 +- 22 files changed, 430 insertions(+), 126 deletions(-) create mode 100644 src/crystal/system/unix/event_loop_libevent_wasm32.cr create mode 100644 src/crystal/system/unix/getentropy.cr create mode 100644 src/fiber/context/wasm32.cr create mode 100644 src/llvm/abi/wasm32.cr diff --git a/src/compiler/crystal/codegen/target.cr b/src/compiler/crystal/codegen/target.cr index 4ab099e1a193..ed466646b33f 100644 --- a/src/compiler/crystal/codegen/target.cr +++ b/src/compiler/crystal/codegen/target.cr @@ -96,12 +96,16 @@ class Crystal::Codegen::Target @environment.starts_with?("linux") end + def wasm? + @architecture.starts_with?("wasm") + end + def bsd? freebsd? || netbsd? || openbsd? || dragonfly? end def unix? - macos? || bsd? || linux? + macos? || bsd? || linux? || wasm? end def gnu? @@ -144,6 +148,8 @@ class Crystal::Codegen::Target if cpu.empty? && !features.includes?("fp") && armhf? features += "+vfp2" end + when "wasm32" + LLVM.init_webassembly else raise Target::Error.new("Unsupported architecture for target triple: #{self}") end diff --git a/src/crystal/system/event_loop.cr b/src/crystal/system/event_loop.cr index 0ca574ce82a1..e71fd8f513b6 100644 --- a/src/crystal/system/event_loop.cr +++ b/src/crystal/system/event_loop.cr @@ -28,7 +28,9 @@ struct Crystal::Event # def add(time_span : Time::Span?) : Nil end -{% if flag?(:unix) %} +{% if flag?(:wasm32) %} + require "./unix/event_loop_libevent_wasm32" +{% elsif flag?(:unix) %} require "./unix/event_loop_libevent" {% elsif flag?(:win32) %} require "./win32/event_loop_iocp" diff --git a/src/crystal/system/random.cr b/src/crystal/system/random.cr index 4581a3011f33..e22de27179e0 100644 --- a/src/crystal/system/random.cr +++ b/src/crystal/system/random.cr @@ -12,6 +12,8 @@ end {% if flag?(:linux) %} require "./unix/getrandom" +{% elsif flag?(:wasm32) %} + require "./unix/getentropy" {% elsif flag?(:openbsd) || flag?(:netbsd) %} require "./unix/arc4random" {% elsif flag?(:unix) %} diff --git a/src/crystal/system/unix/event_loop_libevent_wasm32.cr b/src/crystal/system/unix/event_loop_libevent_wasm32.cr new file mode 100644 index 000000000000..95be1badee39 --- /dev/null +++ b/src/crystal/system/unix/event_loop_libevent_wasm32.cr @@ -0,0 +1,40 @@ +# :nodoc: +module Crystal::EventLoop + # Runs the event loop. + def self.run_once + end + + # Create a new resume event for a fiber. + def self.create_resume_event(fiber : Fiber) : Crystal::Event + Crystal::Event.new + end + + # Creates a timeout_event. + def self.create_timeout_event(fiber) : Crystal::Event + Crystal::Event.new + end + + # Creates a write event for a file descriptor. + def self.create_fd_write_event(io : IO::Evented, edge_triggered : Bool = false) : Crystal::Event + Crystal::Event.new + end + + # Creates a read event for a file descriptor. + def self.create_fd_read_event(io : IO::Evented, edge_triggered : Bool = false) : Crystal::Event + Crystal::Event.new + end +end + +struct Crystal::Event + def add(timeout : LibC::Timeval? = nil) + end + + def add(timeout : Time::Span) + end + + def free + end + + def delete + end +end diff --git a/src/crystal/system/unix/file_descriptor.cr b/src/crystal/system/unix/file_descriptor.cr index 68a4fb2ce3b9..3b5ac228496c 100644 --- a/src/crystal/system/unix/file_descriptor.cr +++ b/src/crystal/system/unix/file_descriptor.cr @@ -163,22 +163,26 @@ module Crystal::System::FileDescriptor end def self.from_stdio(fd) - # If we have a TTY for stdin/out/err, it is possibly a shared terminal. - # We need to reopen it to use O_NONBLOCK without causing other programs to break - - # Figure out the terminal TTY name. If ttyname fails we have a non-tty, or something strange. - # For non-tty we set flush_on_newline to true for reasons described in STDOUT and STDERR docs. - path = uninitialized UInt8[256] - ret = LibC.ttyname_r(fd, path, 256) - return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) unless ret == 0 - - clone_fd = LibC.open(path, LibC::O_RDWR) - return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) if clone_fd == -1 - - # We don't buffer output for TTY devices to see their output right away - io = IO::FileDescriptor.new(clone_fd) - io.close_on_exec = true - io.sync = true - io + {% if flag?(:wasm32) %} + return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) + {% else %} + # If we have a TTY for stdin/out/err, it is possibly a shared terminal. + # We need to reopen it to use O_NONBLOCK without causing other programs to break + + # Figure out the terminal TTY name. If ttyname fails we have a non-tty, or something strange. + # For non-tty we set flush_on_newline to true for reasons described in STDOUT and STDERR docs. + path = uninitialized UInt8[256] + ret = LibC.ttyname_r(fd, path, 256) + return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) unless ret == 0 + + clone_fd = LibC.open(path, LibC::O_RDWR) + return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) if clone_fd == -1 + + # We don't buffer output for TTY devices to see their output right away + io = IO::FileDescriptor.new(clone_fd) + io.close_on_exec = true + io.sync = true + io + {% end %} end end diff --git a/src/crystal/system/unix/getentropy.cr b/src/crystal/system/unix/getentropy.cr new file mode 100644 index 000000000000..34a785b578b1 --- /dev/null +++ b/src/crystal/system/unix/getentropy.cr @@ -0,0 +1,74 @@ +{% skip_file unless flag?(:wasm32) %} + +require "c/unistd" + +lib LibC + fun getentropy(buffer : Void*, len : SizeT) : Int +end + +module Crystal::System::Random + @@initialized = false + @@getentropy_available = false + @@urandom : ::File? + + private def self.init + @@initialized = true + + if LibC.getentropy(Bytes.new(16), 16) >= 0 + @@getentropy_available = true + else + urandom = ::File.open("/dev/urandom", "r") + return unless urandom.info.type.character_device? + + urandom.close_on_exec = true + urandom.sync = true # don't buffer bytes + @@urandom = urandom + end + end + + # Reads n random bytes using the Linux `getentropy(2)` syscall. + def self.random_bytes(buf : Bytes) : Nil + init unless @@initialized + + if @@getentropy_available + getentropy(buf) + elsif urandom = @@urandom + urandom.read_fully(buf) + else + raise "Failed to access secure source to generate random bytes!" + end + end + + def self.next_u : UInt8 + init unless @@initialized + + if @@getentropy_available + buf = uninitialized UInt8[1] + getentropy(buf.to_slice) + buf.unsafe_as(UInt8) + elsif urandom = @@urandom + urandom.read_byte.not_nil! + else + raise "Failed to access secure source to generate random bytes!" + end + end + + # Reads n random bytes using the Linux `getentropy(2)` syscall. + private def self.getentropy(buf) + # getentropy(2) may only read up to 256 bytes at once without being + # interrupted or returning early + chunk_size = 256 + + while buf.size > 0 + if buf.size < chunk_size + chunk_size = buf.size + end + + ret = LibC.getentropy(buf, chunk_size) + + raise RuntimeError.from_errno("getentropy") if ret == -1 + + buf += chunk_size + end + end +end diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index 4af585abe272..c0e1ca9eb18b 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -34,11 +34,18 @@ class Thread end end + @th : LibC::PthreadT + # Used once to initialize the thread object representing the main thread of # the process (that already exists). def initialize @func = ->{} - @th = LibC.pthread_self + @th = + {% if flag?(:wasm32) %} + Pointer(Void).null.as(LibC::PthreadT) + {% else %} + LibC.pthread_self + {% end %} @main_fiber = Fiber.new(stack_address, self) Thread.threads.push(self) diff --git a/src/crystal/system/unix/pthread_mutex.cr b/src/crystal/system/unix/pthread_mutex.cr index 41069c02b561..f0635b000057 100644 --- a/src/crystal/system/unix/pthread_mutex.cr +++ b/src/crystal/system/unix/pthread_mutex.cr @@ -1,55 +1,83 @@ require "c/pthread" -# :nodoc: -class Thread +{% if flag?(:wasm32) %} # :nodoc: - class Mutex - def initialize - attributes = uninitialized LibC::PthreadMutexattrT - LibC.pthread_mutexattr_init(pointerof(attributes)) - LibC.pthread_mutexattr_settype(pointerof(attributes), LibC::PTHREAD_MUTEX_ERRORCHECK) + class Thread + # :nodoc: + class Mutex + def initialize + end - ret = LibC.pthread_mutex_init(out @mutex, pointerof(attributes)) - raise RuntimeError.from_os_error("pthread_mutex_init", Errno.new(ret)) unless ret == 0 + def lock : Nil + end - LibC.pthread_mutexattr_destroy(pointerof(attributes)) - end + def try_lock : Bool + true + end - def lock : Nil - ret = LibC.pthread_mutex_lock(self) - raise RuntimeError.from_os_error("pthread_mutex_lock", Errno.new(ret)) unless ret == 0 - end + def unlock : Nil + end - def try_lock : Bool - case ret = Errno.new(LibC.pthread_mutex_trylock(self)) - when .none? - true - when Errno::EBUSY - false - else - raise RuntimeError.from_os_error("pthread_mutex_trylock", ret) + def synchronize + lock + yield self + ensure + unlock end end + end +{% else %} + # :nodoc: + class Thread + # :nodoc: + class Mutex + def initialize + attributes = uninitialized LibC::PthreadMutexattrT + LibC.pthread_mutexattr_init(pointerof(attributes)) + LibC.pthread_mutexattr_settype(pointerof(attributes), LibC::PTHREAD_MUTEX_ERRORCHECK) - def unlock : Nil - ret = LibC.pthread_mutex_unlock(self) - raise RuntimeError.from_os_error("pthread_mutex_unlock", Errno.new(ret)) unless ret == 0 - end + ret = LibC.pthread_mutex_init(out @mutex, pointerof(attributes)) + raise RuntimeError.from_os_error("pthread_mutex_init", Errno.new(ret)) unless ret == 0 - def synchronize - lock - yield self - ensure - unlock - end + LibC.pthread_mutexattr_destroy(pointerof(attributes)) + end - def finalize - ret = LibC.pthread_mutex_destroy(self) - raise RuntimeError.from_os_error("pthread_mutex_destroy", Errno.new(ret)) unless ret == 0 - end + def lock : Nil + ret = LibC.pthread_mutex_lock(self) + raise RuntimeError.from_os_error("pthread_mutex_lock", Errno.new(ret)) unless ret == 0 + end + + def try_lock : Bool + case ret = Errno.new(LibC.pthread_mutex_trylock(self)) + when .none? + true + when Errno::EBUSY + false + else + raise RuntimeError.from_os_error("pthread_mutex_trylock", ret) + end + end + + def unlock : Nil + ret = LibC.pthread_mutex_unlock(self) + raise RuntimeError.from_os_error("pthread_mutex_unlock", Errno.new(ret)) unless ret == 0 + end + + def synchronize + lock + yield self + ensure + unlock + end - def to_unsafe - pointerof(@mutex) + def finalize + ret = LibC.pthread_mutex_destroy(self) + raise RuntimeError.from_os_error("pthread_mutex_destroy", Errno.new(ret)) unless ret == 0 + end + + def to_unsafe + pointerof(@mutex) + end end end -end +{% end %} diff --git a/src/errno.cr b/src/errno.cr index 9a3afe5b5899..8b3134967ce7 100644 --- a/src/errno.cr +++ b/src/errno.cr @@ -4,6 +4,8 @@ require "c/string" lib LibC {% if flag?(:linux) || flag?(:dragonfly) %} fun __errno_location : Int* + {% elsif flag?(:wasm32) %} + $errno : Int {% elsif flag?(:darwin) || flag?(:freebsd) %} fun __error : Int* {% elsif flag?(:netbsd) || flag?(:openbsd) %} @@ -43,6 +45,8 @@ enum Errno def self.value : self {% if flag?(:linux) || flag?(:dragonfly) %} Errno.new LibC.__errno_location.value + {% elsif flag?(:wasm32) %} + Errno.new LibC.errno {% elsif flag?(:darwin) || flag?(:bsd) %} Errno.new LibC.__error.value {% elsif flag?(:win32) %} diff --git a/src/exception/call_stack.cr b/src/exception/call_stack.cr index f154dfe6f600..312ea26a8d59 100644 --- a/src/exception/call_stack.cr +++ b/src/exception/call_stack.cr @@ -5,7 +5,7 @@ require "c/stdio" require "c/string" require "./lib_unwind" -{% if flag?(:darwin) || flag?(:bsd) || flag?(:linux) %} +{% if flag?(:darwin) || flag?(:bsd) || flag?(:linux) || flag?(:wasm32) %} require "./call_stack/dwarf" {% else %} require "./call_stack/null" @@ -68,29 +68,31 @@ struct Exception::CallStack protected def self.unwind callstack = [] of Void* - backtrace_fn = ->(context : LibUnwind::Context, data : Void*) do - bt = data.as(typeof(callstack)) - - ip = {% if flag?(:arm) %} - Pointer(Void).new(__crystal_unwind_get_ip(context)) - {% else %} - Pointer(Void).new(LibUnwind.get_ip(context)) - {% end %} - bt << ip - - {% if flag?(:gnu) && flag?(:i386) %} - # This is a workaround for glibc bug: https://sourceware.org/bugzilla/show_bug.cgi?id=18635 - # The unwind info is corrupted when `makecontext` is used. - # Stop the backtrace here. There is nothing interest beyond this point anyway. - if CallStack.makecontext_range.includes?(ip) - return LibUnwind::ReasonCode::END_OF_STACK - end - {% end %} + {% unless flag?(:wasm32) %} + backtrace_fn = ->(context : LibUnwind::Context, data : Void*) do + bt = data.as(typeof(callstack)) + + ip = {% if flag?(:arm) %} + Pointer(Void).new(__crystal_unwind_get_ip(context)) + {% else %} + Pointer(Void).new(LibUnwind.get_ip(context)) + {% end %} + bt << ip + + {% if flag?(:gnu) && flag?(:i386) %} + # This is a workaround for glibc bug: https://sourceware.org/bugzilla/show_bug.cgi?id=18635 + # The unwind info is corrupted when `makecontext` is used. + # Stop the backtrace here. There is nothing interest beyond this point anyway. + if CallStack.makecontext_range.includes?(ip) + return LibUnwind::ReasonCode::END_OF_STACK + end + {% end %} - LibUnwind::ReasonCode::NO_REASON - end + LibUnwind::ReasonCode::NO_REASON + end - LibUnwind.backtrace(backtrace_fn, callstack.as(Void*)) + LibUnwind.backtrace(backtrace_fn, callstack.as(Void*)) + {% end %} callstack end @@ -107,27 +109,29 @@ struct Exception::CallStack end def self.print_backtrace - backtrace_fn = ->(context : LibUnwind::Context, data : Void*) do - last_frame = data.as(RepeatedFrame*) - - ip = {% if flag?(:arm) %} - Pointer(Void).new(__crystal_unwind_get_ip(context)) - {% else %} - Pointer(Void).new(LibUnwind.get_ip(context)) - {% end %} - - if last_frame.value.ip == ip - last_frame.value.incr - else - print_frame(last_frame.value) unless last_frame.value.ip.address == 0 - last_frame.value = RepeatedFrame.new ip + {% unless flag?(:wasm32) %} + backtrace_fn = ->(context : LibUnwind::Context, data : Void*) do + last_frame = data.as(RepeatedFrame*) + + ip = {% if flag?(:arm) %} + Pointer(Void).new(__crystal_unwind_get_ip(context)) + {% else %} + Pointer(Void).new(LibUnwind.get_ip(context)) + {% end %} + + if last_frame.value.ip == ip + last_frame.value.incr + else + print_frame(last_frame.value) unless last_frame.value.ip.address == 0 + last_frame.value = RepeatedFrame.new ip + end + LibUnwind::ReasonCode::NO_REASON end - LibUnwind::ReasonCode::NO_REASON - end - rf = RepeatedFrame.new(Pointer(Void).null) - LibUnwind.backtrace(backtrace_fn, pointerof(rf).as(Void*)) - print_frame(rf) + rf = RepeatedFrame.new(Pointer(Void).null) + LibUnwind.backtrace(backtrace_fn, pointerof(rf).as(Void*)) + print_frame(rf) + {% end %} end private def self.print_frame(repeated_frame) @@ -213,16 +217,18 @@ struct Exception::CallStack end protected def self.decode_frame(ip, original_ip = ip) - if LibC.dladdr(ip, out info) != 0 - offset = original_ip - info.dli_saddr + {% unless flag?(:wasm32) %} + if LibC.dladdr(ip, out info) != 0 + offset = original_ip - info.dli_saddr - if offset == 0 - return decode_frame(ip - 1, original_ip) - end + if offset == 0 + return decode_frame(ip - 1, original_ip) + end - unless info.dli_sname.null? - {offset, info.dli_sname} + unless info.dli_sname.null? + {offset, info.dli_sname} + end end - end + {% end %} end end diff --git a/src/exception/call_stack/dwarf.cr b/src/exception/call_stack/dwarf.cr index e30e3e5b5dcd..a210d48e5127 100644 --- a/src/exception/call_stack/dwarf.cr +++ b/src/exception/call_stack/dwarf.cr @@ -12,17 +12,19 @@ struct Exception::CallStack # :nodoc: def self.load_dwarf - unless @@dwarf_loaded - @@dwarf_loaded = true - begin - return if ENV["CRYSTAL_LOAD_DWARF"]? == "0" - load_dwarf_impl - rescue ex - @@dwarf_line_numbers = nil - @@dwarf_function_names = nil - Crystal::System.print_exception "Unable to load dwarf information", ex + {% unless flag?(:wasm32) %} + unless @@dwarf_loaded + @@dwarf_loaded = true + begin + return if ENV["CRYSTAL_LOAD_DWARF"]? == "0" + load_dwarf_impl + rescue ex + @@dwarf_line_numbers = nil + @@dwarf_function_names = nil + Crystal::System.print_exception "Unable to load dwarf information", ex + end end - end + {% end %} end protected def self.decode_line_number(pc) diff --git a/src/fiber/context/wasm32.cr b/src/fiber/context/wasm32.cr new file mode 100644 index 000000000000..6c9102079e0d --- /dev/null +++ b/src/fiber/context/wasm32.cr @@ -0,0 +1,13 @@ +{% skip_file unless flag?(:wasm32) %} + +class Fiber + # :nodoc: + def makecontext(stack_ptr, fiber_main) + end + + # :nodoc: + @[NoInline] + @[Naked] + def self.swapcontext(current_context, new_context) : Nil + end +end diff --git a/src/gc.cr b/src/gc.cr index 238c99c1b574..4bf29345a6b6 100644 --- a/src/gc.cr +++ b/src/gc.cr @@ -98,7 +98,7 @@ module GC end end -{% if flag?(:gc_none) %} +{% if flag?(:gc_none) || flag?(:wasm32) %} require "gc/none" {% else %} require "gc/boehm" diff --git a/src/kernel.cr b/src/kernel.cr index 27df6cbe5798..5032e663ded1 100644 --- a/src/kernel.cr +++ b/src/kernel.cr @@ -523,7 +523,7 @@ end end {% end %} -{% unless flag?(:win32) %} +{% unless flag?(:win32) || flag?(:wasm32) %} # Background loop to cleanup unused fiber stacks. spawn(name: "Fiber Clean Loop") do loop do diff --git a/src/lib_c.cr b/src/lib_c.cr index d487c1fd1a10..5268f2b9b1e7 100644 --- a/src/lib_c.cr +++ b/src/lib_c.cr @@ -10,7 +10,7 @@ lib LibC alias Int = Int32 alias UInt = UInt32 - {% if flag?(:win32) || flag?(:i386) || flag?(:arm) %} + {% if flag?(:win32) || flag?(:i386) || flag?(:arm) || flag?(:wasm32) %} alias Long = Int32 alias ULong = UInt32 {% elsif flag?(:x86_64) || flag?(:aarch64) %} diff --git a/src/llvm.cr b/src/llvm.cr index c546540f8165..89cfec3cd1dd 100644 --- a/src/llvm.cr +++ b/src/llvm.cr @@ -55,6 +55,23 @@ module LLVM {% end %} end + def self.init_webassembly : Nil + return if @@initialized_webassembly + @@initialized_webassembly = true + + {% if LibLLVM::BUILT_TARGETS.includes?(:webassembly) %} + LibLLVM.initialize_webassembly_target_info + LibLLVM.initialize_webassembly_target + LibLLVM.initialize_webassembly_target_mc + LibLLVM.initialize_webassembly_asm_printer + LibLLVM.initialize_webassembly_asm_parser + # LibLLVM.link_in_jit + LibLLVM.link_in_mc_jit + {% else %} + raise "ERROR: LLVM was built without WebAssembly target" + {% end %} + end + def self.start_multithreaded : Bool if multithreaded? true diff --git a/src/llvm/abi/wasm32.cr b/src/llvm/abi/wasm32.cr new file mode 100644 index 000000000000..2a3d3ca43874 --- /dev/null +++ b/src/llvm/abi/wasm32.cr @@ -0,0 +1,64 @@ +require "../abi" + +class LLVM::ABI::WebAssembly32 < LLVM::ABI + def abi_info(atys : Array(Type), rty : Type, ret_def : Bool, context : Context) : LLVM::ABI::FunctionType + ret_ty = compute_return_type(rty, ret_def, context) + arg_tys = compute_arg_types(atys, context) + FunctionType.new(arg_tys, ret_ty) + end + + def align(type : Type) : Int32 + align(type, 4) + end + + def size(type : Type) : Int32 + size(type, 4) + end + + def register?(type) : Bool + case type.kind + when Type::Kind::Integer, Type::Kind::Float, Type::Kind::Double, Type::Kind::Pointer + true + else + false + end + end + + private def compute_return_type(rty, ret_def, context) + if !ret_def + ArgType.direct(context.void) + elsif register?(rty) + non_struct(rty, context) + else + case size(rty) + when 1 + ArgType.direct(rty, context.int8) + when 2 + ArgType.direct(rty, context.int16) + when 3, 4 + ArgType.direct(rty, context.int32) + else + ArgType.indirect(rty, LLVM::Attribute::StructRet) + end + end + end + + private def compute_arg_types(atys, context) + atys.map do |aty| + if register?(aty) + non_struct(aty, context) + else + if align(aty) <= 4 + ArgType.direct(aty, context.int32.array(((size(aty) + 3) // 4).to_u64)) + else + ArgType.direct(aty, context.int64.array(((size(aty) + 7) // 8).to_u64)) + end + end + end + end + + private def non_struct(type, context) + attr = type == context.int1 ? LLVM::Attribute::ZExt : nil + ArgType.direct(type, attr: attr) + end +end diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr index 857987d0a36e..176203a8bb2e 100644 --- a/src/llvm/lib_llvm.cr +++ b/src/llvm/lib_llvm.cr @@ -214,6 +214,11 @@ lib LibLLVM fun initialize_arm_target = LLVMInitializeARMTarget fun initialize_arm_target_info = LLVMInitializeARMTargetInfo fun initialize_arm_target_mc = LLVMInitializeARMTargetMC + fun initialize_webassembly_asm_printer = LLVMInitializeWebAssemblyAsmPrinter + fun initialize_webassembly_asm_parser = LLVMInitializeWebAssemblyAsmParser + fun initialize_webassembly_target = LLVMInitializeWebAssemblyTarget + fun initialize_webassembly_target_info = LLVMInitializeWebAssemblyTargetInfo + fun initialize_webassembly_target_mc = LLVMInitializeWebAssemblyTargetMC fun initialize_native_target = LLVMInitializeNativeTarget fun is_constant = LLVMIsConstant(val : ValueRef) : Int32 fun is_function_var_arg = LLVMIsFunctionVarArg(ty : TypeRef) : Int32 diff --git a/src/llvm/target_machine.cr b/src/llvm/target_machine.cr index ee7a413df959..d01cf1e00be4 100644 --- a/src/llvm/target_machine.cr +++ b/src/llvm/target_machine.cr @@ -57,6 +57,8 @@ class LLVM::TargetMachine ABI::AArch64.new(self) when /arm/ ABI::ARM.new(self) + when /wasm32/ + ABI::WebAssembly32.new(self) else raise "Unsupported ABI for target triple: #{triple}" end diff --git a/src/prelude.cr b/src/prelude.cr index f391f0386ac2..fd21dad87aa3 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -70,7 +70,7 @@ require "range" require "reference" require "regex" require "set" -{% unless flag?(:win32) %} +{% unless flag?(:win32) || flag?(:wasm32) %} require "signal" {% end %} require "slice" diff --git a/src/raise.cr b/src/raise.cr index b017e6a0b981..2cca702862a0 100644 --- a/src/raise.cr +++ b/src/raise.cr @@ -169,6 +169,32 @@ end __crystal_continue_unwind end +{% elsif flag?(:wasm32) %} + # :nodoc: + fun __crystal_personality(version : Int32, actions : LibUnwind::Action, exception_class : UInt64, exception_object : LibUnwind::Exception*, context : Void*) : LibUnwind::ReasonCode + LibC.printf("EXITING: __crystal_personality called") + LibC.exit(1) + end + + # :nodoc: + @[Raises] + fun __crystal_raise(unwind_ex : LibUnwind::Exception*) : NoReturn + LibC.printf("EXITING: __crystal_raise called") + LibC.exit(1) + end + + # :nodoc: + fun __crystal_get_exception(unwind_ex : LibUnwind::Exception*) : UInt64 + LibC.printf("EXITING: __crystal_get_exception called") + LibC.exit(1) + end + + def raise(exception : Exception) : NoReturn + STDERR.puts + STDERR.puts "EXITING: Attempting to raise: " + exception.inspect_with_backtrace(STDERR) + LibC.exit(1) + end {% else %} # :nodoc: fun __crystal_personality(version : Int32, actions : LibUnwind::Action, exception_class : UInt64, exception_object : LibUnwind::Exception*, context : Void*) : LibUnwind::ReasonCode @@ -188,7 +214,7 @@ end end {% end %} -{% unless flag?(:win32) %} +{% unless flag?(:win32) || flag?(:wasm32) %} # :nodoc: @[Raises] fun __crystal_raise(unwind_ex : LibUnwind::Exception*) : NoReturn diff --git a/src/regex/lib_pcre.cr b/src/regex/lib_pcre.cr index 156e82dd73f8..94543442743f 100644 --- a/src/regex/lib_pcre.cr +++ b/src/regex/lib_pcre.cr @@ -24,5 +24,7 @@ lib LibPCRE $pcre_free : Free end -LibPCRE.pcre_malloc = ->GC.malloc(LibC::SizeT) -LibPCRE.pcre_free = ->GC.free(Void*) +{% unless flag?(:wasm32) %} + LibPCRE.pcre_malloc = ->GC.malloc(LibC::SizeT) + LibPCRE.pcre_free = ->GC.free(Void*) +{% end %} From 98c5447eb212a551fdcad0e0db7d033e8e91f031 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 1 Jul 2021 15:39:54 -0400 Subject: [PATCH 03/41] Add LibC as a symbolic link --- src/lib_c/wasm32-wasi | 1 + src/lib_c/wasm32-wasi/c/arpa/inet.cr | 9 -- src/lib_c/wasm32-wasi/c/dirent.cr | 22 ----- src/lib_c/wasm32-wasi/c/dlfcn.cr | 21 ----- src/lib_c/wasm32-wasi/c/elf.cr | 24 ----- src/lib_c/wasm32-wasi/c/errno.cr | 83 ---------------- src/lib_c/wasm32-wasi/c/fcntl.cr | 32 ------- src/lib_c/wasm32-wasi/c/grp.cr | 11 --- src/lib_c/wasm32-wasi/c/iconv.cr | 9 -- src/lib_c/wasm32-wasi/c/link.cr | 13 --- src/lib_c/wasm32-wasi/c/netdb.cr | 39 -------- src/lib_c/wasm32-wasi/c/netinet/in.cr | 68 -------------- src/lib_c/wasm32-wasi/c/netinet/tcp.cr | 6 -- src/lib_c/wasm32-wasi/c/pthread.cr | 30 ------ src/lib_c/wasm32-wasi/c/pwd.cr | 14 --- src/lib_c/wasm32-wasi/c/sched.cr | 3 - src/lib_c/wasm32-wasi/c/signal.cr | 86 ----------------- src/lib_c/wasm32-wasi/c/stdarg.cr | 3 - src/lib_c/wasm32-wasi/c/stddef.cr | 3 - src/lib_c/wasm32-wasi/c/stdint.cr | 10 -- src/lib_c/wasm32-wasi/c/stdio.cr | 9 -- src/lib_c/wasm32-wasi/c/stdlib.cr | 25 ----- src/lib_c/wasm32-wasi/c/string.cr | 9 -- src/lib_c/wasm32-wasi/c/sys/file.cr | 11 --- src/lib_c/wasm32-wasi/c/sys/mman.cr | 31 ------ src/lib_c/wasm32-wasi/c/sys/resource.cr | 25 ----- src/lib_c/wasm32-wasi/c/sys/select.cr | 14 --- src/lib_c/wasm32-wasi/c/sys/socket.cr | 65 ------------- src/lib_c/wasm32-wasi/c/sys/stat.cr | 56 ----------- src/lib_c/wasm32-wasi/c/sys/syscall.cr | 3 - src/lib_c/wasm32-wasi/c/sys/time.cr | 16 ---- src/lib_c/wasm32-wasi/c/sys/types.cr | 61 ------------ src/lib_c/wasm32-wasi/c/sys/un.cr | 8 -- src/lib_c/wasm32-wasi/c/sys/wait.cr | 8 -- src/lib_c/wasm32-wasi/c/termios.cr | 120 ------------------------ src/lib_c/wasm32-wasi/c/time.cr | 37 -------- src/lib_c/wasm32-wasi/c/unistd.cr | 47 ---------- 37 files changed, 1 insertion(+), 1031 deletions(-) create mode 120000 src/lib_c/wasm32-wasi delete mode 100644 src/lib_c/wasm32-wasi/c/arpa/inet.cr delete mode 100644 src/lib_c/wasm32-wasi/c/dirent.cr delete mode 100644 src/lib_c/wasm32-wasi/c/dlfcn.cr delete mode 100644 src/lib_c/wasm32-wasi/c/elf.cr delete mode 100644 src/lib_c/wasm32-wasi/c/errno.cr delete mode 100644 src/lib_c/wasm32-wasi/c/fcntl.cr delete mode 100644 src/lib_c/wasm32-wasi/c/grp.cr delete mode 100644 src/lib_c/wasm32-wasi/c/iconv.cr delete mode 100644 src/lib_c/wasm32-wasi/c/link.cr delete mode 100644 src/lib_c/wasm32-wasi/c/netdb.cr delete mode 100644 src/lib_c/wasm32-wasi/c/netinet/in.cr delete mode 100644 src/lib_c/wasm32-wasi/c/netinet/tcp.cr delete mode 100644 src/lib_c/wasm32-wasi/c/pthread.cr delete mode 100644 src/lib_c/wasm32-wasi/c/pwd.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sched.cr delete mode 100644 src/lib_c/wasm32-wasi/c/signal.cr delete mode 100644 src/lib_c/wasm32-wasi/c/stdarg.cr delete mode 100644 src/lib_c/wasm32-wasi/c/stddef.cr delete mode 100644 src/lib_c/wasm32-wasi/c/stdint.cr delete mode 100644 src/lib_c/wasm32-wasi/c/stdio.cr delete mode 100644 src/lib_c/wasm32-wasi/c/stdlib.cr delete mode 100644 src/lib_c/wasm32-wasi/c/string.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/file.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/mman.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/resource.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/select.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/socket.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/stat.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/syscall.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/time.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/types.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/un.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/wait.cr delete mode 100644 src/lib_c/wasm32-wasi/c/termios.cr delete mode 100644 src/lib_c/wasm32-wasi/c/time.cr delete mode 100644 src/lib_c/wasm32-wasi/c/unistd.cr diff --git a/src/lib_c/wasm32-wasi b/src/lib_c/wasm32-wasi new file mode 120000 index 000000000000..dc756741ff87 --- /dev/null +++ b/src/lib_c/wasm32-wasi @@ -0,0 +1 @@ +i386-linux-musl \ No newline at end of file diff --git a/src/lib_c/wasm32-wasi/c/arpa/inet.cr b/src/lib_c/wasm32-wasi/c/arpa/inet.cr deleted file mode 100644 index afac8795f66f..000000000000 --- a/src/lib_c/wasm32-wasi/c/arpa/inet.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "../netinet/in" -require "../stdint" - -lib LibC - fun htons(x0 : UInt16T) : UInt16T - fun ntohs(x0 : UInt16T) : UInt16T - fun inet_ntop(x0 : Int, x1 : Void*, x2 : Char*, x3 : SocklenT) : Char* - fun inet_pton(x0 : Int, x1 : Char*, x2 : Void*) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/dirent.cr b/src/lib_c/wasm32-wasi/c/dirent.cr deleted file mode 100644 index 124a1f760ffa..000000000000 --- a/src/lib_c/wasm32-wasi/c/dirent.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "./sys/types" - -lib LibC - type DIR = Void - - DT_UNKNOWN = 0 - DT_DIR = 4 - DT_LINK = 10 - - struct Dirent - d_ino : InoT - d_off : OffT - d_reclen : UShort - d_type : Char - d_name : StaticArray(Char, 256) - end - - fun closedir(x0 : DIR*) : Int - fun opendir(x0 : Char*) : DIR* - fun readdir(x0 : DIR*) : Dirent* - fun rewinddir(x0 : DIR*) : Void -end diff --git a/src/lib_c/wasm32-wasi/c/dlfcn.cr b/src/lib_c/wasm32-wasi/c/dlfcn.cr deleted file mode 100644 index 2f48a19e8092..000000000000 --- a/src/lib_c/wasm32-wasi/c/dlfcn.cr +++ /dev/null @@ -1,21 +0,0 @@ -lib LibC - RTLD_LAZY = 1 - RTLD_NOW = 2 - RTLD_GLOBAL = 256 - RTLD_LOCAL = 0 - RTLD_DEFAULT = Pointer(Void).new(0) - RTLD_NEXT = Pointer(Void).new(-1) - - struct DlInfo - dli_fname : Char* - dli_fbase : Void* - dli_sname : Char* - dli_saddr : Void* - end - - fun dlclose(x0 : Void*) : Int - fun dlerror : Char* - fun dlopen(x0 : Char*, x1 : Int) : Void* - fun dlsym(x0 : Void*, x1 : Char*) : Void* - fun dladdr(x0 : Void*, x1 : DlInfo*) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/elf.cr b/src/lib_c/wasm32-wasi/c/elf.cr deleted file mode 100644 index 32a0dc3152d1..000000000000 --- a/src/lib_c/wasm32-wasi/c/elf.cr +++ /dev/null @@ -1,24 +0,0 @@ -require "./sys/types" - -lib LibC - alias Elf_Half = UInt16T - alias Elf_Word = UInt32T - alias Elf_Sword = Int32T - alias Elf_Xword = UInt64T - alias Elf_Sxword = Int64T - alias Elf_Addr = UInt32T - alias Elf_Off = UInt32T - alias Elf_Section = UInt16T - alias Elf_Versym = Elf_Half - - struct Elf_Phdr - type : Elf_Word # Segment type - offset : Elf_Off # Segment file offset - vaddr : Elf_Addr # Segment virtual address - paddr : Elf_Addr # Segment physical address - filesz : Elf_Word # Segment size in file - memsz : Elf_Word # Segment size in memory - flags : Elf_Word # Segment flags - align : Elf_Word # Segment alignment - end -end diff --git a/src/lib_c/wasm32-wasi/c/errno.cr b/src/lib_c/wasm32-wasi/c/errno.cr deleted file mode 100644 index 8b528cc5bb71..000000000000 --- a/src/lib_c/wasm32-wasi/c/errno.cr +++ /dev/null @@ -1,83 +0,0 @@ -lib LibC - E2BIG = 7 - EACCES = 13 - EADDRINUSE = 98 - EADDRNOTAVAIL = 99 - EAFNOSUPPORT = 97 - EAGAIN = 11 - EALREADY = 114 - EBADF = 9 - EBADMSG = 74 - EBUSY = 16 - ECANCELED = 125 - ECHILD = 10 - ECONNABORTED = 103 - ECONNREFUSED = 111 - ECONNRESET = 104 - EDEADLK = 35 - EDESTADDRREQ = 89 - EDOM = 33 - EDQUOT = 122 - EEXIST = 17 - EFAULT = 14 - EFBIG = 27 - EHOSTUNREACH = 113 - EIDRM = 43 - EILSEQ = 84 - EINPROGRESS = 115 - EINTR = 4 - EINVAL = 22 - EIO = 5 - EISCONN = 106 - EISDIR = 21 - ELOOP = 40 - EMFILE = 24 - EMLINK = 31 - EMSGSIZE = 90 - EMULTIHOP = 72 - ENAMETOOLONG = 36 - ENETDOWN = 100 - ENETRESET = 102 - ENETUNREACH = 101 - ENFILE = 23 - ENOBUFS = 105 - ENODEV = 19 - ENOENT = 2 - ENOEXEC = 8 - ENOLCK = 37 - ENOLINK = 67 - ENOMEM = 12 - ENOMSG = 42 - ENOPROTOOPT = 92 - ENOSPC = 28 - ENOSYS = 38 - ENOTCONN = 107 - ENOTDIR = 20 - ENOTEMPTY = 39 - ENOTRECOVERABLE = 131 - ENOTSOCK = 88 - ENOTSUP = LibC::EOPNOTSUPP - ENOTTY = 25 - ENXIO = 6 - EOPNOTSUPP = 95 - EOVERFLOW = 75 - EOWNERDEAD = 130 - EPERM = 1 - EPIPE = 32 - EPROTO = 71 - EPROTONOSUPPORT = 93 - EPROTOTYPE = 91 - ERANGE = 34 - EROFS = 30 - ESPIPE = 29 - ESRCH = 3 - ESTALE = 116 - ETIMEDOUT = 110 - ETXTBSY = 26 - EWOULDBLOCK = LibC::EAGAIN - EXDEV = 18 - ENODATA = 61 - ENOSR = 63 - ENOSTR = 60 - ETIME = 62 -end diff --git a/src/lib_c/wasm32-wasi/c/fcntl.cr b/src/lib_c/wasm32-wasi/c/fcntl.cr deleted file mode 100644 index 6beab0d6de74..000000000000 --- a/src/lib_c/wasm32-wasi/c/fcntl.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "./sys/types" -require "./sys/stat" -require "./unistd" - -lib LibC - F_GETFD = 1 - F_SETFD = 2 - F_GETFL = 3 - F_SETFL = 4 - FD_CLOEXEC = 1 - O_CLOEXEC = 0o2000000 - O_CREAT = 0o100 - O_NOFOLLOW = 0o400000 - O_TRUNC = 0o1000 - O_APPEND = 0o2000 - O_NONBLOCK = 0o4000 - O_SYNC = 0o4010000 - O_RDONLY = 0o0 - O_RDWR = 0o2 - O_WRONLY = 0o1 - - struct Flock - l_type : Short - l_whence : Short - l_start : OffT - l_len : OffT - l_pid : PidT - end - - fun fcntl(x0 : Int, x1 : Int, ...) : Int - fun open(x0 : Char*, x1 : Int, ...) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/grp.cr b/src/lib_c/wasm32-wasi/c/grp.cr deleted file mode 100644 index 2fc351260b20..000000000000 --- a/src/lib_c/wasm32-wasi/c/grp.cr +++ /dev/null @@ -1,11 +0,0 @@ -lib LibC - struct Group - gr_name : Char* - gr_passwd : Char* - gr_gid : GidT - gr_mem : Char** - end - - fun getgrnam_r(name : Char*, grp : Group*, buf : Char*, bufsize : SizeT, result : Group**) : Int - fun getgrgid_r(gid : GidT, grp : Group*, buf : Char*, bufsize : SizeT, result : Group**) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/iconv.cr b/src/lib_c/wasm32-wasi/c/iconv.cr deleted file mode 100644 index 6496b957ed24..000000000000 --- a/src/lib_c/wasm32-wasi/c/iconv.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "./stddef" - -lib LibC - type IconvT = Void* - - fun iconv(x0 : IconvT, x1 : Char**, x2 : SizeT*, x3 : Char**, x4 : SizeT*) : SizeT - fun iconv_close(x0 : IconvT) : Int - fun iconv_open(x0 : Char*, x1 : Char*) : IconvT -end diff --git a/src/lib_c/wasm32-wasi/c/link.cr b/src/lib_c/wasm32-wasi/c/link.cr deleted file mode 100644 index a29bd3030a42..000000000000 --- a/src/lib_c/wasm32-wasi/c/link.cr +++ /dev/null @@ -1,13 +0,0 @@ -require "./elf" - -lib LibC - struct DlPhdrInfo - addr : Elf_Addr - name : Char* - phdr : Elf_Phdr* - phnum : Elf_Half - end - - alias DlPhdrCallback = (DlPhdrInfo*, LibC::SizeT, Void*) -> LibC::Int - fun dl_iterate_phdr(callback : DlPhdrCallback, data : Void*) -end diff --git a/src/lib_c/wasm32-wasi/c/netdb.cr b/src/lib_c/wasm32-wasi/c/netdb.cr deleted file mode 100644 index a5ac97843811..000000000000 --- a/src/lib_c/wasm32-wasi/c/netdb.cr +++ /dev/null @@ -1,39 +0,0 @@ -require "./netinet/in" -require "./sys/socket" -require "./stdint" - -lib LibC - AI_PASSIVE = 0x01 - AI_CANONNAME = 0x02 - AI_NUMERICHOST = 0x04 - AI_NUMERICSERV = 0x400 - AI_V4MAPPED = 0x08 - AI_ALL = 0x10 - AI_ADDRCONFIG = 0x20 - EAI_AGAIN = -3 - EAI_BADFLAGS = -1 - EAI_FAIL = -4 - EAI_FAMILY = -6 - EAI_MEMORY = -10 - EAI_NONAME = -2 - EAI_SERVICE = -8 - EAI_SOCKTYPE = -7 - EAI_SYSTEM = -11 - EAI_OVERFLOW = -12 - - struct Addrinfo - ai_flags : Int - ai_family : Int - ai_socktype : Int - ai_protocol : Int - ai_addrlen : SocklenT - ai_addr : Sockaddr* - ai_canonname : Char* - ai_next : Addrinfo* - end - - fun freeaddrinfo(x0 : Addrinfo*) : Void - fun gai_strerror(x0 : Int) : Char* - fun getaddrinfo(x0 : Char*, x1 : Char*, x2 : Addrinfo*, x3 : Addrinfo**) : Int - fun getnameinfo(x0 : Sockaddr*, x1 : SocklenT, x2 : Char*, x3 : SocklenT, x4 : Char*, x5 : SocklenT, x6 : Int) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/netinet/in.cr b/src/lib_c/wasm32-wasi/c/netinet/in.cr deleted file mode 100644 index c497075effaf..000000000000 --- a/src/lib_c/wasm32-wasi/c/netinet/in.cr +++ /dev/null @@ -1,68 +0,0 @@ -require "../sys/socket" -require "../stdint" - -lib LibC - IPPROTO_IP = 0 - IPPROTO_IPV6 = 41 - IPPROTO_ICMP = 1 - IPPROTO_RAW = 255 - IPPROTO_TCP = 6 - IPPROTO_UDP = 17 - - alias InPortT = UInt16T - alias InAddrT = UInt32T - - struct InAddr - s_addr : InAddrT - end - - union In6AddrIn6Union - __s6_addr : StaticArray(UInt8T, 16) - __s6_addr16 : StaticArray(UInt16T, 8) - __s6_addr32 : StaticArray(UInt32T, 4) - end - - struct In6Addr - __in6_union : In6AddrIn6Union - end - - struct SockaddrIn - sin_family : SaFamilyT - sin_port : InPortT - sin_addr : InAddr - sin_zero : StaticArray(UInt8T, 8) - end - - struct SockaddrIn6 - sin6_family : SaFamilyT - sin6_port : InPortT - sin6_flowinfo : UInt32T - sin6_addr : In6Addr - sin6_scope_id : UInt32T - end - - IP_MULTICAST_IF = 32 - IPV6_MULTICAST_IF = 17 - - IP_MULTICAST_TTL = 33 - IPV6_MULTICAST_HOPS = 18 - - IP_MULTICAST_LOOP = 34 - IPV6_MULTICAST_LOOP = 19 - - IP_ADD_MEMBERSHIP = 35 - IPV6_JOIN_GROUP = 20 - - IP_DROP_MEMBERSHIP = 36 - IPV6_LEAVE_GROUP = 21 - - struct IpMreq - imr_multiaddr : InAddr - imr_interface : InAddr - end - - struct Ipv6Mreq - ipv6mr_multiaddr : In6Addr - ipv6mr_interface : UInt - end -end diff --git a/src/lib_c/wasm32-wasi/c/netinet/tcp.cr b/src/lib_c/wasm32-wasi/c/netinet/tcp.cr deleted file mode 100644 index beed1db6e081..000000000000 --- a/src/lib_c/wasm32-wasi/c/netinet/tcp.cr +++ /dev/null @@ -1,6 +0,0 @@ -lib LibC - TCP_NODELAY = 1 - TCP_KEEPIDLE = 4 - TCP_KEEPINTVL = 5 - TCP_KEEPCNT = 6 -end diff --git a/src/lib_c/wasm32-wasi/c/pthread.cr b/src/lib_c/wasm32-wasi/c/pthread.cr deleted file mode 100644 index c318bb5f4357..000000000000 --- a/src/lib_c/wasm32-wasi/c/pthread.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "./sys/types" - -lib LibC - PTHREAD_MUTEX_ERRORCHECK = 2 - - fun pthread_attr_destroy(x0 : PthreadAttrT*) : Int - fun pthread_attr_getstack(x0 : PthreadAttrT*, x1 : Void**, x2 : SizeT*) : Int - fun pthread_condattr_destroy(x0 : PthreadCondattrT*) : Int - fun pthread_condattr_init(x0 : PthreadCondattrT*) : Int - fun pthread_condattr_setclock(x0 : PthreadCondattrT*, x1 : ClockidT) : Int - fun pthread_cond_broadcast(x0 : PthreadCondT*) : Int - fun pthread_cond_destroy(x0 : PthreadCondT*) : Int - fun pthread_cond_init(x0 : PthreadCondT*, x1 : PthreadCondattrT*) : Int - fun pthread_cond_signal(x0 : PthreadCondT*) : Int - fun pthread_cond_timedwait(x0 : PthreadCondT*, x1 : PthreadMutexT*, x2 : Timespec*) : Int - fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int - fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int - fun pthread_detach(x0 : PthreadT) : Int - fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int - fun pthread_join(x0 : PthreadT, x1 : Void**) : Int - fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int - fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int - fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int - fun pthread_mutex_destroy(x0 : PthreadMutexT*) : Int - fun pthread_mutex_init(x0 : PthreadMutexT*, x1 : PthreadMutexattrT*) : Int - fun pthread_mutex_lock(x0 : PthreadMutexT*) : Int - fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int - fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int - fun pthread_self : PthreadT -end diff --git a/src/lib_c/wasm32-wasi/c/pwd.cr b/src/lib_c/wasm32-wasi/c/pwd.cr deleted file mode 100644 index dc2e53d4a53a..000000000000 --- a/src/lib_c/wasm32-wasi/c/pwd.cr +++ /dev/null @@ -1,14 +0,0 @@ -lib LibC - struct Passwd - pw_name : Char* - pw_passwd : Char* - pw_uid : UidT - pw_gid : GidT - pw_gecos : Char* - pw_dir : Char* - pw_shell : Char* - end - - fun getpwnam_r(login : Char*, pwstore : Passwd*, buf : Char*, bufsize : SizeT, result : Passwd**) : Int - fun getpwuid_r(uid : UidT, pwstore : Passwd*, buf : Char*, bufsize : SizeT, result : Passwd**) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sched.cr b/src/lib_c/wasm32-wasi/c/sched.cr deleted file mode 100644 index 9d83ed18504e..000000000000 --- a/src/lib_c/wasm32-wasi/c/sched.cr +++ /dev/null @@ -1,3 +0,0 @@ -lib LibC - fun sched_yield : Int -end diff --git a/src/lib_c/wasm32-wasi/c/signal.cr b/src/lib_c/wasm32-wasi/c/signal.cr deleted file mode 100644 index d822d82b9d27..000000000000 --- a/src/lib_c/wasm32-wasi/c/signal.cr +++ /dev/null @@ -1,86 +0,0 @@ -require "./sys/types" -require "./time" - -lib LibC - SIGHUP = 1 - SIGINT = 2 - SIGQUIT = 3 - SIGILL = 4 - SIGTRAP = 5 - SIGIOT = LibC::SIGABRT - SIGABRT = 6 - SIGFPE = 8 - SIGKILL = 9 - SIGBUS = 7 - SIGSEGV = 11 - SIGSYS = 31 - SIGPIPE = 13 - SIGALRM = 14 - SIGTERM = 15 - SIGURG = 23 - SIGSTOP = 19 - SIGTSTP = 20 - SIGCONT = 18 - SIGCHLD = 17 - SIGTTIN = 21 - SIGTTOU = 22 - SIGIO = 29 - SIGXCPU = 24 - SIGXFSZ = 25 - SIGVTALRM = 26 - SIGUSR1 = 10 - SIGUSR2 = 12 - SIGWINCH = 28 - SIGPWR = 30 - SIGSTKFLT = 16 - SIGUNUSED = LibC::SIGSYS - - SIGSTKSZ = 8192 - - SIG_SETMASK = 2 - - alias SighandlerT = Int -> - SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) - SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null) - - struct SigsetT - bits : ULong[32] # 128 / sizeof(long) - end - - SA_ONSTACK = 0x08000000 - SA_SIGINFO = 0x00000004 - - struct SiginfoT - si_signo : Int - si_errno : Int - si_code : Int - si_addr : Void* # Assuming the sigfault form of siginfo_t - __pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25 - end - - alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> - - struct Sigaction - sa_sigaction : SigactionHandlerT - sa_mask : SigsetT - sa_flags : Int - sa_restorer : Void* - end - - struct StackT - ss_sp : Void* - ss_flags : Int - ss_size : SizeT - end - - fun kill(x0 : PidT, x1 : Int) : Int - fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int - fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void - fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int - fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int - fun sigemptyset(SigsetT*) : Int - fun sigfillset(SigsetT*) : Int - fun sigaddset(SigsetT*, Int) : Int - fun sigdelset(SigsetT*, Int) : Int - fun sigismember(SigsetT*, Int) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/stdarg.cr b/src/lib_c/wasm32-wasi/c/stdarg.cr deleted file mode 100644 index 882d4f51d35c..000000000000 --- a/src/lib_c/wasm32-wasi/c/stdarg.cr +++ /dev/null @@ -1,3 +0,0 @@ -lib LibC - type VaList = Void* -end diff --git a/src/lib_c/wasm32-wasi/c/stddef.cr b/src/lib_c/wasm32-wasi/c/stddef.cr deleted file mode 100644 index 5939010b0538..000000000000 --- a/src/lib_c/wasm32-wasi/c/stddef.cr +++ /dev/null @@ -1,3 +0,0 @@ -lib LibC - alias SizeT = UInt -end diff --git a/src/lib_c/wasm32-wasi/c/stdint.cr b/src/lib_c/wasm32-wasi/c/stdint.cr deleted file mode 100644 index 5cb258eccd2c..000000000000 --- a/src/lib_c/wasm32-wasi/c/stdint.cr +++ /dev/null @@ -1,10 +0,0 @@ -lib LibC - alias Int8T = SChar - alias Int16T = Short - alias Int32T = Int - alias Int64T = LongLong - alias UInt8T = Char - alias UInt16T = UShort - alias UInt32T = UInt - alias UInt64T = ULongLong -end diff --git a/src/lib_c/wasm32-wasi/c/stdio.cr b/src/lib_c/wasm32-wasi/c/stdio.cr deleted file mode 100644 index 44fb5b8a1e74..000000000000 --- a/src/lib_c/wasm32-wasi/c/stdio.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "./sys/types" -require "./stddef" - -lib LibC - fun printf(x0 : Char*, ...) : Int - fun dprintf(fd : Int, format : Char*, ...) : Int - fun rename(x0 : Char*, x1 : Char*) : Int - fun snprintf(x0 : Char*, x1 : SizeT, x2 : Char*, ...) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/stdlib.cr b/src/lib_c/wasm32-wasi/c/stdlib.cr deleted file mode 100644 index d3325e2defd0..000000000000 --- a/src/lib_c/wasm32-wasi/c/stdlib.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "./stddef" -require "./sys/wait" - -lib LibC - struct DivT - quot : Int - rem : Int - end - - fun atof(x0 : Char*) : Double - fun div(x0 : Int, x1 : Int) : DivT - fun exit(x0 : Int) : NoReturn - fun free(x0 : Void*) : Void - fun getenv(x0 : Char*) : Char* - fun malloc(x0 : SizeT) : Void* - fun mkstemp(x0 : Char*) : Int - fun mkstemps(x0 : Char*, x1 : Int) : Int - fun putenv(x0 : Char*) : Int - fun realloc(x0 : Void*, x1 : SizeT) : Void* - fun realpath(x0 : Char*, x1 : Char*) : Char* - fun setenv(x0 : Char*, x1 : Char*, x2 : Int) : Int - fun strtof(x0 : Char*, x1 : Char**) : Float - fun strtod(x0 : Char*, x1 : Char**) : Double - fun unsetenv(x0 : Char*) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/string.cr b/src/lib_c/wasm32-wasi/c/string.cr deleted file mode 100644 index 02e025ae4880..000000000000 --- a/src/lib_c/wasm32-wasi/c/string.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "./stddef" - -lib LibC - fun memchr(x0 : Void*, c : Int, n : SizeT) : Void* - fun memcmp(x0 : Void*, x1 : Void*, x2 : SizeT) : Int - fun strcmp(x0 : Char*, x1 : Char*) : Int - fun strerror(x0 : Int) : Char* - fun strlen(x0 : Char*) : SizeT -end diff --git a/src/lib_c/wasm32-wasi/c/sys/file.cr b/src/lib_c/wasm32-wasi/c/sys/file.cr deleted file mode 100644 index e2bd3fd4b816..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/file.cr +++ /dev/null @@ -1,11 +0,0 @@ -lib LibC - @[Flags] - enum FlockOp - SH = 0x1 - EX = 0x2 - NB = 0x4 - UN = 0x8 - end - - fun flock(fd : Int, op : FlockOp) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/mman.cr b/src/lib_c/wasm32-wasi/c/sys/mman.cr deleted file mode 100644 index 4dd11dad0918..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/mman.cr +++ /dev/null @@ -1,31 +0,0 @@ -require "./types" - -lib LibC - PROT_EXEC = 4 - PROT_NONE = 0 - PROT_READ = 1 - PROT_WRITE = 2 - MAP_FIXED = 0x10 - MAP_PRIVATE = 0x02 - MAP_SHARED = 0x01 - MAP_ANON = 0x20 - MAP_ANONYMOUS = LibC::MAP_ANON - MAP_FAILED = Pointer(Void).new(-1) - POSIX_MADV_DONTNEED = 0 - POSIX_MADV_NORMAL = 0 - POSIX_MADV_RANDOM = 1 - POSIX_MADV_SEQUENTIAL = 2 - POSIX_MADV_WILLNEED = 3 - MADV_DONTNEED = 4 - MADV_NORMAL = 0 - MADV_RANDOM = 1 - MADV_SEQUENTIAL = 2 - MADV_WILLNEED = 3 - MADV_HUGEPAGE = 14 - MADV_NOHUGEPAGE = 15 - - fun mmap(x0 : Void*, x1 : SizeT, x2 : Int, x3 : Int, x4 : Int, x5 : OffT) : Void* - fun mprotect(x0 : Void*, x1 : SizeT, x2 : Int) : Int - fun munmap(x0 : Void*, x1 : SizeT) : Int - fun madvise(x0 : Void*, x1 : SizeT, x2 : Int) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/resource.cr b/src/lib_c/wasm32-wasi/c/sys/resource.cr deleted file mode 100644 index 7f550c37a622..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/resource.cr +++ /dev/null @@ -1,25 +0,0 @@ -lib LibC - struct RUsage - ru_utime : Timeval - ru_stime : Timeval - ru_maxrss : Long - ru_ix_rss : Long - ru_idrss : Long - ru_isrss : Long - ru_minflt : Long - ru_majflt : Long - ru_nswap : Long - ru_inblock : Long - ru_oublock : Long - ru_msgsnd : Long - ru_msgrcv : Long - ru_nsignals : Long - ru_nvcsw : Long - ru_nivcsw : Long - end - - RUSAGE_SELF = 0 - RUSAGE_CHILDREN = -1 - - fun getrusage(who : Int, usage : RUsage*) : Int16 -end diff --git a/src/lib_c/wasm32-wasi/c/sys/select.cr b/src/lib_c/wasm32-wasi/c/sys/select.cr deleted file mode 100644 index 5e6970e6e20c..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/select.cr +++ /dev/null @@ -1,14 +0,0 @@ -require "./types" -require "./time" -require "../time" -require "../signal" - -lib LibC - alias FdMask = ULong - - struct FdSet - fds_bits : StaticArray(ULong, 16) - end - - fun select(x0 : Int, x1 : FdSet*, x2 : FdSet*, x3 : FdSet*, x4 : Timeval*) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/socket.cr b/src/lib_c/wasm32-wasi/c/sys/socket.cr deleted file mode 100644 index 361e5b8040d6..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/socket.cr +++ /dev/null @@ -1,65 +0,0 @@ -require "./types" - -lib LibC - SOCK_DGRAM = 2 - SOCK_RAW = 3 - SOCK_SEQPACKET = 5 - SOCK_STREAM = 1 - SOL_SOCKET = 1 - SO_BROADCAST = 6 - SO_KEEPALIVE = 9 - SO_LINGER = 13 - SO_RCVBUF = 8 - SO_REUSEADDR = 2 - SO_REUSEPORT = 15 - SO_SNDBUF = 7 - PF_INET = 2 - PF_INET6 = 10 - PF_UNIX = LibC::PF_LOCAL - PF_UNSPEC = 0 - PF_LOCAL = 1 - AF_INET = LibC::PF_INET - AF_INET6 = LibC::PF_INET6 - AF_UNIX = LibC::AF_LOCAL - AF_UNSPEC = LibC::PF_UNSPEC - AF_LOCAL = LibC::PF_LOCAL - SHUT_RD = 0 - SHUT_RDWR = 2 - SHUT_WR = 1 - SOCK_CLOEXEC = 0o2000000 - - alias SocklenT = UInt - alias SaFamilyT = UShort - - struct Sockaddr - sa_family : SaFamilyT - sa_data : StaticArray(Char, 14) - end - - struct SockaddrStorage - ss_family : SaFamilyT - __ss_align : ULong - __ss_padding : StaticArray(Char, 112) - end - - struct Linger - l_onoff : Int - l_linger : Int - end - - fun accept(x0 : Int, x1 : Sockaddr*, x2 : SocklenT*) : Int - fun bind(x0 : Int, x1 : Sockaddr*, x2 : SocklenT) : Int - fun connect(x0 : Int, x1 : Sockaddr*, x2 : SocklenT) : Int - fun getpeername(x0 : Int, x1 : Sockaddr*, x2 : SocklenT*) : Int - fun getsockname(x0 : Int, x1 : Sockaddr*, x2 : SocklenT*) : Int - fun getsockopt(x0 : Int, x1 : Int, x2 : Int, x3 : Void*, x4 : SocklenT*) : Int - fun listen(x0 : Int, x1 : Int) : Int - fun recv(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int) : SSizeT - fun recvfrom(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int, x4 : Sockaddr*, x5 : SocklenT*) : SSizeT - fun send(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int) : SSizeT - fun sendto(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int, x4 : Sockaddr*, x5 : SocklenT) : SSizeT - fun setsockopt(x0 : Int, x1 : Int, x2 : Int, x3 : Void*, x4 : SocklenT) : Int - fun shutdown(x0 : Int, x1 : Int) : Int - fun socket(x0 : Int, x1 : Int, x2 : Int) : Int - fun socketpair(x0 : Int, x1 : Int, x2 : Int, x3 : StaticArray(Int, 2)) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/stat.cr b/src/lib_c/wasm32-wasi/c/sys/stat.cr deleted file mode 100644 index e86ed5d144f7..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/stat.cr +++ /dev/null @@ -1,56 +0,0 @@ -require "./types" -require "../time" - -lib LibC - S_IFMT = 0o170000 - S_IFBLK = 0o060000 - S_IFCHR = 0o020000 - S_IFIFO = 0o010000 - S_IFREG = 0o100000 - S_IFDIR = 0o040000 - S_IFLNK = 0o120000 - S_IFSOCK = 0o140000 - S_IRUSR = 0o400 - S_IWUSR = 0o200 - S_IXUSR = 0o100 - S_IRWXU = 0o700 - S_IRGRP = 0o040 - S_IWGRP = 0o020 - S_IXGRP = 0o010 - S_IRWXG = 0o070 - S_IROTH = 0o004 - S_IWOTH = 0o002 - S_IXOTH = 0o001 - S_IRWXO = 0o007 - S_ISUID = 0o4000 - S_ISGID = 0o2000 - S_ISVTX = 0o1000 - - struct Stat - st_dev : DevT - __st_dev_padding : Int - __st_ino_truncated : Long - st_mode : ModeT - st_nlink : NlinkT - st_uid : UidT - st_gid : GidT - st_rdev : DevT - __st_rdev_padding : Int - st_size : OffT - st_blksize : BlksizeT - st_blocks : BlkcntT - st_atim : Timespec - st_mtim : Timespec - st_ctim : Timespec - st_ino : InoT - end - - fun chmod(x0 : Char*, x1 : ModeT) : Int - fun fstat(x0 : Int, x1 : Stat*) : Int - fun lstat(x0 : Char*, x1 : Stat*) : Int - fun mkdir(x0 : Char*, x1 : ModeT) : Int - fun mkfifo(x0 : Char*, x1 : ModeT) : Int - fun mknod(x0 : Char*, x1 : ModeT, x2 : DevT) : Int - fun stat(x0 : Char*, x1 : Stat*) : Int - fun umask(x0 : ModeT) : ModeT -end diff --git a/src/lib_c/wasm32-wasi/c/sys/syscall.cr b/src/lib_c/wasm32-wasi/c/sys/syscall.cr deleted file mode 100644 index ceb04c887181..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/syscall.cr +++ /dev/null @@ -1,3 +0,0 @@ -lib LibC - SYS_getrandom = 318 -end diff --git a/src/lib_c/wasm32-wasi/c/sys/time.cr b/src/lib_c/wasm32-wasi/c/sys/time.cr deleted file mode 100644 index dbe23bac4c86..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/time.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "./types" - -lib LibC - struct Timeval - tv_sec : TimeT - tv_usec : SusecondsT - end - - struct Timezone - tz_minuteswest : Int - tz_dsttime : Int - end - - fun gettimeofday(x0 : Timeval*, x1 : Void*) : Int - fun utimes(path : Char*, times : Timeval[2]) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/types.cr b/src/lib_c/wasm32-wasi/c/sys/types.cr deleted file mode 100644 index e8a6362b52fe..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/types.cr +++ /dev/null @@ -1,61 +0,0 @@ -require "../stddef" -require "../stdint" - -lib LibC - alias BlkcntT = LongLong - alias BlksizeT = Long - alias ClockT = Long - alias ClockidT = Int - alias DevT = ULongLong - alias GidT = UInt - alias IdT = UInt - alias InoT = ULongLong - alias ModeT = UInt - alias NlinkT = UInt - alias OffT = LongLong - alias PidT = Int - - union PthreadAttrTU - __i : StaticArray(Int, 9) - __vi : StaticArray(Int, 9) - __s : StaticArray(UInt, 9) - end - - struct PthreadAttrT - __u : PthreadAttrTU - end - - union PthreadCondTU - __i : StaticArray(Int, 12) - __vi : StaticArray(Int, 12) - __p : StaticArray(Void*, 12) - end - - struct PthreadCondT - __u : PthreadCondTU - end - - struct PthreadCondattrT - __attr : UInt - end - - union PthreadMutexTU - __i : StaticArray(Int, 6) - __vi : StaticArray(Int, 6) - __p : StaticArray(Void*, 6) - end - - struct PthreadMutexT - __u : PthreadMutexTU - end - - struct PthreadMutexattrT - __attr : UInt - end - - type PthreadT = Void* - alias SSizeT = Int - alias SusecondsT = Long - alias TimeT = Long - alias UidT = UInt -end diff --git a/src/lib_c/wasm32-wasi/c/sys/un.cr b/src/lib_c/wasm32-wasi/c/sys/un.cr deleted file mode 100644 index 7f5bd705a4dd..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/un.cr +++ /dev/null @@ -1,8 +0,0 @@ -require "./socket" - -lib LibC - struct SockaddrUn - sun_family : SaFamilyT - sun_path : StaticArray(Char, 108) - end -end diff --git a/src/lib_c/wasm32-wasi/c/sys/wait.cr b/src/lib_c/wasm32-wasi/c/sys/wait.cr deleted file mode 100644 index e9c185b5ac9c..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/wait.cr +++ /dev/null @@ -1,8 +0,0 @@ -require "./types" -require "../signal" - -lib LibC - WNOHANG = 1 - - fun waitpid(x0 : PidT, x1 : Int*, x2 : Int) : PidT -end diff --git a/src/lib_c/wasm32-wasi/c/termios.cr b/src/lib_c/wasm32-wasi/c/termios.cr deleted file mode 100644 index 49da2c3d0751..000000000000 --- a/src/lib_c/wasm32-wasi/c/termios.cr +++ /dev/null @@ -1,120 +0,0 @@ -require "./sys/types" - -lib LibC - VEOF = 4 - VEOL = 11 - VERASE = 2 - VINTR = 0 - VKILL = 3 - VMIN = 6 - VQUIT = 1 - VSTART = 8 - VSTOP = 9 - VSUSP = 10 - BRKINT = 0o000002 - ICRNL = 0o000400 - IGNBRK = 0o000001 - IGNCR = 0o000200 - IGNPAR = 0o000004 - INLCR = 0o000100 - INPCK = 0o000020 - ISTRIP = 0o000040 - IXANY = 0o004000 - IXOFF = 0o010000 - IXON = 0o002000 - PARMRK = 0o000010 - OPOST = 0o000001 - ONLCR = 0o000004 - OCRNL = 0o000010 - ONOCR = 0o000020 - ONLRET = 0o000040 - OFDEL = 0o000200 - OFILL = 0o000100 - CRDLY = 0o003000 - CR0 = 0o000000 - CR1 = 0o001000 - CR2 = 0o002000 - CR3 = 0o003000 - TABDLY = 0o014000 - TAB0 = 0o000000 - TAB1 = 0o004000 - TAB2 = 0o010000 - TAB3 = 0o014000 - BSDLY = 0o020000 - BS0 = 0o000000 - BS1 = 0o020000 - VTDLY = 0o040000 - VT0 = 0o000000 - VT1 = 0o040000 - FFDLY = 0o100000 - FF0 = 0o000000 - FF1 = 0o100000 - NLDLY = 0o000400 - NL0 = 0o000000 - NL1 = 0o000400 - B0 = 0o000000 - B50 = 0o000001 - B75 = 0o000002 - B110 = 0o000003 - B134 = 0o000004 - B150 = 0o000005 - B200 = 0o000006 - B300 = 0o000007 - B600 = 0o000010 - B1200 = 0o000011 - B1800 = 0o000012 - B2400 = 0o000013 - B4800 = 0o000014 - B9600 = 0o000015 - B19200 = 0o000016 - B38400 = 0o000017 - CSIZE = 0o000060 - CS5 = 0o000000 - CS6 = 0o000020 - CS7 = 0o000040 - CS8 = 0o000060 - CSTOPB = 0o000100 - CREAD = 0o000200 - PARENB = 0o000400 - PARODD = 0o001000 - HUPCL = 0o002000 - CLOCAL = 0o004000 - ECHO = 0o000010 - ECHOE = 0o000020 - ECHOK = 0o000040 - ECHONL = 0o000100 - ICANON = 0o000002 - IEXTEN = 0o100000 - ISIG = 0o000001 - NOFLSH = 0o000200 - TOSTOP = 0o000400 - TCSANOW = 0 - TCSADRAIN = 1 - TCSAFLUSH = 2 - TCIFLUSH = 0 - TCIOFLUSH = 2 - TCOFLUSH = 1 - TCIOFF = 2 - TCION = 3 - TCOOFF = 0 - TCOON = 1 - - alias CcT = Char - alias SpeedT = UInt - alias TcflagT = UInt - - struct Termios - c_iflag : TcflagT - c_oflag : TcflagT - c_cflag : TcflagT - c_lflag : TcflagT - c_line : CcT - c_cc : StaticArray(CcT, 32) - __c_ispeed : SpeedT - __c_ospeed : SpeedT - end - - fun tcgetattr(x0 : Int, x1 : Termios*) : Int - fun tcsetattr(x0 : Int, x1 : Int, x2 : Termios*) : Int - fun cfmakeraw(x0 : Termios*) : Void -end diff --git a/src/lib_c/wasm32-wasi/c/time.cr b/src/lib_c/wasm32-wasi/c/time.cr deleted file mode 100644 index 22fdf7a86ebf..000000000000 --- a/src/lib_c/wasm32-wasi/c/time.cr +++ /dev/null @@ -1,37 +0,0 @@ -require "./sys/types" - -lib LibC - CLOCK_MONOTONIC = 1 - CLOCK_REALTIME = 0 - - struct Tm - tm_sec : Int - tm_min : Int - tm_hour : Int - tm_mday : Int - tm_mon : Int - tm_year : Int - tm_wday : Int - tm_yday : Int - tm_isdst : Int - tm_gmtoff : Long - tm_zone : Char* - end - - struct Timespec - tv_sec : TimeT - tv_nsec : Long - end - - fun clock_gettime(x0 : ClockidT, x1 : Timespec*) : Int - fun clock_settime(x0 : ClockidT, x1 : Timespec*) : Int - fun gmtime_r(x0 : TimeT*, x1 : Tm*) : Tm* - fun localtime_r(x0 : TimeT*, x1 : Tm*) : Tm* - fun mktime(x0 : Tm*) : TimeT - fun tzset : Void - fun timegm(x0 : Tm*) : TimeT - - $daylight : Int - $timezone : Long - $tzname : StaticArray(Char*, 2) -end diff --git a/src/lib_c/wasm32-wasi/c/unistd.cr b/src/lib_c/wasm32-wasi/c/unistd.cr deleted file mode 100644 index a7e4be16e1f9..000000000000 --- a/src/lib_c/wasm32-wasi/c/unistd.cr +++ /dev/null @@ -1,47 +0,0 @@ -require "./sys/types" -require "./stdint" - -lib LibC - F_OK = 0 - R_OK = 4 - W_OK = 2 - X_OK = 1 - SC_CLK_TCK = 2 - SC_NPROCESSORS_ONLN = 84 - SC_PAGESIZE = 30 - - fun chroot(path : Char*) : Int - fun access(x0 : Char*, x1 : Int) : Int - fun chdir(x0 : Char*) : Int - fun chown(x0 : Char*, x1 : UidT, x2 : GidT) : Int - fun close(x0 : Int) : Int - fun dup2(x0 : Int, x1 : Int) : Int - fun _exit(x0 : Int) : NoReturn - fun execvp(x0 : Char*, x1 : Char**) : Int - fun fdatasync(x0 : Int) : Int - @[ReturnsTwice] - fun fork : PidT - fun fsync(x0 : Int) : Int - fun ftruncate(x0 : Int, x1 : OffT) : Int - fun getcwd(x0 : Char*, x1 : SizeT) : Char* - fun gethostname(x0 : Char*, x1 : SizeT) : Int - fun getpgid(x0 : PidT) : PidT - fun getpid : PidT - fun getppid : PidT - fun isatty(x0 : Int) : Int - fun ttyname_r(fd : Int, buf : Char*, buffersize : SizeT) : Int - fun lchown(x0 : Char*, x1 : UidT, x2 : GidT) : Int - fun link(x0 : Char*, x1 : Char*) : Int - fun lockf(x0 : Int, x1 : Int, x2 : OffT) : Int - fun lseek(x0 : Int, x1 : OffT, x2 : Int) : OffT - fun pipe(x0 : StaticArray(Int, 2)) : Int - fun read(x0 : Int, x1 : Void*, x2 : SizeT) : SSizeT - fun pread(x0 : Int, x1 : Void*, x2 : SizeT, x3 : OffT) : SSizeT - fun rmdir(x0 : Char*) : Int - fun symlink(x0 : Char*, x1 : Char*) : Int - fun readlink(path : Char*, buf : Char*, size : SizeT) : SSizeT - fun syscall(x0 : Long, ...) : Long - fun sysconf(x0 : Int) : Long - fun unlink(x0 : Char*) : Int - fun write(x0 : Int, x1 : Void*, x2 : SizeT) : SSizeT -end From fa5077ad2a4aaa4a89874c3fe61b101e23e893e8 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 14 Jul 2021 17:29:03 -0400 Subject: [PATCH 04/41] Move wasm to a Crystal::System implementation --- src/compiler/crystal/codegen/target.cr | 2 +- src/crystal/system.cr | 3 + src/crystal/system/dir.cr | 2 +- src/crystal/system/env.cr | 6 +- src/crystal/system/event_loop.cr | 2 +- src/crystal/system/fiber.cr | 2 + src/crystal/system/file.cr | 2 +- src/crystal/system/file_descriptor.cr | 8 +- src/crystal/system/file_info.cr | 2 +- src/crystal/system/group.cr | 2 + src/crystal/system/mime.cr | 2 + src/crystal/system/process.cr | 2 + src/crystal/system/random.cr | 2 +- src/crystal/system/socket.cr | 2 +- src/crystal/system/thread.cr | 2 + src/crystal/system/thread_mutex.cr | 2 + src/crystal/system/time.cr | 6 +- src/crystal/system/unix/file_descriptor.cr | 38 +++--- src/crystal/system/unix/pthread.cr | 7 +- src/crystal/system/unix/pthread_mutex.cr | 108 +++++++----------- src/crystal/system/user.cr | 2 + src/crystal/system/wasm/cpucount.cr | 5 + .../event_loop.cr} | 0 src/crystal/system/wasm/fiber.cr | 10 ++ src/crystal/system/wasm/file_descriptor.cr | 8 ++ .../system/{unix => wasm}/getentropy.cr | 2 - src/crystal/system/wasm/group.cr | 9 ++ src/crystal/system/wasm/hostname.cr | 5 + src/crystal/system/wasm/mime.cr | 4 + src/crystal/system/wasm/process.cr | 79 +++++++++++++ src/crystal/system/wasm/thread.cr | 95 +++++++++++++++ src/crystal/system/wasm/thread_mutex.cr | 17 +++ src/crystal/system/wasm/user.cr | 9 ++ src/kernel.cr | 2 +- src/prelude.cr | 2 +- src/signal.cr | 10 +- src/socket/address.cr | 2 +- 37 files changed, 345 insertions(+), 118 deletions(-) create mode 100644 src/crystal/system/wasm/cpucount.cr rename src/crystal/system/{unix/event_loop_libevent_wasm32.cr => wasm/event_loop.cr} (100%) create mode 100644 src/crystal/system/wasm/fiber.cr create mode 100644 src/crystal/system/wasm/file_descriptor.cr rename src/crystal/system/{unix => wasm}/getentropy.cr (97%) create mode 100644 src/crystal/system/wasm/group.cr create mode 100644 src/crystal/system/wasm/hostname.cr create mode 100644 src/crystal/system/wasm/mime.cr create mode 100644 src/crystal/system/wasm/process.cr create mode 100644 src/crystal/system/wasm/thread.cr create mode 100644 src/crystal/system/wasm/thread_mutex.cr create mode 100644 src/crystal/system/wasm/user.cr diff --git a/src/compiler/crystal/codegen/target.cr b/src/compiler/crystal/codegen/target.cr index ed466646b33f..bc73199c68c8 100644 --- a/src/compiler/crystal/codegen/target.cr +++ b/src/compiler/crystal/codegen/target.cr @@ -105,7 +105,7 @@ class Crystal::Codegen::Target end def unix? - macos? || bsd? || linux? || wasm? + macos? || bsd? || linux? end def gnu? diff --git a/src/crystal/system.cr b/src/crystal/system.cr index 88827a3f6552..a3837350d6dd 100644 --- a/src/crystal/system.cr +++ b/src/crystal/system.cr @@ -19,6 +19,9 @@ end {% elsif flag?(:win32) %} require "./system/win32/hostname" require "./system/win32/cpucount" +{% elsif flag?(:wasm32) %} + require "./system/wasm/hostname" + require "./system/wasm/cpucount" {% else %} {% raise "No Crystal::System implementation available" %} {% end %} diff --git a/src/crystal/system/dir.cr b/src/crystal/system/dir.cr index 33d983c8e411..7354aecfa616 100644 --- a/src/crystal/system/dir.cr +++ b/src/crystal/system/dir.cr @@ -51,7 +51,7 @@ module Crystal::System::Dir # def self.delete(path : String) : Nil end -{% if flag?(:unix) %} +{% if flag?(:unix) || flag?(:wasm32) %} require "./unix/dir" {% elsif flag?(:win32) %} require "./win32/dir" diff --git a/src/crystal/system/env.cr b/src/crystal/system/env.cr index 6c6b5cf375e6..cd5dfd1e6f98 100644 --- a/src/crystal/system/env.cr +++ b/src/crystal/system/env.cr @@ -12,8 +12,10 @@ module Crystal::System::Env # def self.each(&block : String, String ->) end -{% if flag?(:win32) %} +{% if flag?(:unix) || flag?(:wasm32) %} + require "./unix/env" +{% elsif flag?(:win32) %} require "./win32/env" {% else %} - require "./unix/env" + {% raise "No implementation of Crystal::System::Env available" %} {% end %} diff --git a/src/crystal/system/event_loop.cr b/src/crystal/system/event_loop.cr index e71fd8f513b6..9e1646db5b9d 100644 --- a/src/crystal/system/event_loop.cr +++ b/src/crystal/system/event_loop.cr @@ -29,7 +29,7 @@ struct Crystal::Event end {% if flag?(:wasm32) %} - require "./unix/event_loop_libevent_wasm32" + require "./wasm/event_loop" {% elsif flag?(:unix) %} require "./unix/event_loop_libevent" {% elsif flag?(:win32) %} diff --git a/src/crystal/system/fiber.cr b/src/crystal/system/fiber.cr index 23794756bc4b..ff4a4bfdab38 100644 --- a/src/crystal/system/fiber.cr +++ b/src/crystal/system/fiber.cr @@ -13,6 +13,8 @@ end require "./unix/fiber" {% elsif flag?(:win32) %} require "./win32/fiber" +{% elsif flag?(:wasm32) %} + require "./wasm/fiber" {% else %} {% raise "fiber not supported" %} {% end %} diff --git a/src/crystal/system/file.cr b/src/crystal/system/file.cr index 0ddabfb1cd58..44fe83667f6b 100644 --- a/src/crystal/system/file.cr +++ b/src/crystal/system/file.cr @@ -49,7 +49,7 @@ module Crystal::System::File # def file_descriptor_close end -{% if flag?(:unix) %} +{% if flag?(:unix) || flag?(:wasm32) %} require "./unix/file" {% elsif flag?(:win32) %} require "./win32/file" diff --git a/src/crystal/system/file_descriptor.cr b/src/crystal/system/file_descriptor.cr index f36e3e79e750..c058be3d696d 100644 --- a/src/crystal/system/file_descriptor.cr +++ b/src/crystal/system/file_descriptor.cr @@ -1,5 +1,9 @@ -{% if flag?(:win32) %} +{% if flag?(:unix) %} + require "./unix/file_descriptor" +{% elsif flag?(:win32) %} require "./win32/file_descriptor" +{% elsif flag?(:wasm32) %} + require "./wasm/file_descriptor" {% else %} - require "./unix/file_descriptor" + {% raise "No Crystal::System::FileDescriptor implementation available" %} {% end %} diff --git a/src/crystal/system/file_info.cr b/src/crystal/system/file_info.cr index 6a8b1fb69d07..ef2bf2f78f3f 100644 --- a/src/crystal/system/file_info.cr +++ b/src/crystal/system/file_info.cr @@ -1,4 +1,4 @@ -{% if flag?(:unix) %} +{% if flag?(:unix) || flag?(:wasm32) %} require "./unix/file_info" {% elsif flag?(:win32) %} require "./win32/file_info" diff --git a/src/crystal/system/group.cr b/src/crystal/system/group.cr index 56ffdc1f39a8..5900f61a9a08 100644 --- a/src/crystal/system/group.cr +++ b/src/crystal/system/group.cr @@ -1,5 +1,7 @@ {% if flag?(:unix) %} require "./unix/group" +{% elsif flag?(:wasm32) %} + require "./wasm/group" {% else %} {% raise "No Crystal::System::Group implementation available" %} {% end %} diff --git a/src/crystal/system/mime.cr b/src/crystal/system/mime.cr index 9b456daa291c..1ed1335460d7 100644 --- a/src/crystal/system/mime.cr +++ b/src/crystal/system/mime.cr @@ -7,6 +7,8 @@ end require "./unix/mime" {% elsif flag?(:win32) %} require "./win32/mime" +{% elsif flag?(:wasm32) %} + require "./wasm/mime" {% else %} {% raise "No Crystal::System::Mime implementation available" %} {% end %} diff --git a/src/crystal/system/process.cr b/src/crystal/system/process.cr index fca85f7a6c7e..1088d55b9c61 100644 --- a/src/crystal/system/process.cr +++ b/src/crystal/system/process.cr @@ -74,6 +74,8 @@ end require "./unix/process" {% elsif flag?(:win32) %} require "./win32/process" +{% elsif flag?(:wasm32) %} + require "./wasm/process" {% else %} {% raise "No Crystal::System::Process implementation available" %} {% end %} diff --git a/src/crystal/system/random.cr b/src/crystal/system/random.cr index e22de27179e0..d56e80310d35 100644 --- a/src/crystal/system/random.cr +++ b/src/crystal/system/random.cr @@ -13,7 +13,7 @@ end {% if flag?(:linux) %} require "./unix/getrandom" {% elsif flag?(:wasm32) %} - require "./unix/getentropy" + require "./wasm/getentropy" {% elsif flag?(:openbsd) || flag?(:netbsd) %} require "./unix/arc4random" {% elsif flag?(:unix) %} diff --git a/src/crystal/system/socket.cr b/src/crystal/system/socket.cr index 9f1fc7114592..e1e091199739 100644 --- a/src/crystal/system/socket.cr +++ b/src/crystal/system/socket.cr @@ -76,7 +76,7 @@ module Crystal::System::Socket # private def system_tcp_keepalive_count=(val : Int) end -{% if flag?(:unix) %} +{% if flag?(:unix) || flag?(:wasm32) %} require "./unix/socket" {% else %} {% raise "No Crystal::System::Socket implementation available" %} diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index ffaf51555782..dccd2f6e83d0 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -33,6 +33,8 @@ require "./thread_linked_list" require "./unix/pthread_condition_variable" {% elsif flag?(:win32) %} require "./win32/thread" +{% elsif flag?(:wasm32) %} + require "./wasm/thread" {% else %} {% raise "thread not supported" %} {% end %} diff --git a/src/crystal/system/thread_mutex.cr b/src/crystal/system/thread_mutex.cr index ced2563cefbc..aeb50fd9b25b 100644 --- a/src/crystal/system/thread_mutex.cr +++ b/src/crystal/system/thread_mutex.cr @@ -21,6 +21,8 @@ end require "./unix/pthread_mutex" {% elsif flag?(:win32) %} require "./win32/thread_mutex" +{% elsif flag?(:wasm32) %} + require "./wasm/thread_mutex" {% else %} {% raise "thread not supported" %} {% end %} diff --git a/src/crystal/system/time.cr b/src/crystal/system/time.cr index 340a9e06f19e..48b3695d5526 100644 --- a/src/crystal/system/time.cr +++ b/src/crystal/system/time.cr @@ -12,8 +12,10 @@ module Crystal::System::Time # def self.load_localtime : ::Time::Location? end -{% if flag?(:win32) %} +{% if flag?(:unix) || flag?(:wasm32) %} + require "./unix/time" +{% elsif flag?(:win32) %} require "./win32/time" {% else %} - require "./unix/time" + {% raise "No implementation of Crystal::System::Time available" %} {% end %} diff --git a/src/crystal/system/unix/file_descriptor.cr b/src/crystal/system/unix/file_descriptor.cr index 8b450b60bd99..bc3576a2fe01 100644 --- a/src/crystal/system/unix/file_descriptor.cr +++ b/src/crystal/system/unix/file_descriptor.cr @@ -163,26 +163,22 @@ module Crystal::System::FileDescriptor end def self.from_stdio(fd) - {% if flag?(:wasm32) %} - return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) - {% else %} - # If we have a TTY for stdin/out/err, it is possibly a shared terminal. - # We need to reopen it to use O_NONBLOCK without causing other programs to break - - # Figure out the terminal TTY name. If ttyname fails we have a non-tty, or something strange. - # For non-tty we set flush_on_newline to true for reasons described in STDOUT and STDERR docs. - path = uninitialized UInt8[256] - ret = LibC.ttyname_r(fd, path, 256) - return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) unless ret == 0 - - clone_fd = LibC.open(path, LibC::O_RDWR) - return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) if clone_fd == -1 - - # We don't buffer output for TTY devices to see their output right away - io = IO::FileDescriptor.new(clone_fd) - io.close_on_exec = true - io.sync = true - io - {% end %} + # If we have a TTY for stdin/out/err, it is possibly a shared terminal. + # We need to reopen it to use O_NONBLOCK without causing other programs to break + + # Figure out the terminal TTY name. If ttyname fails we have a non-tty, or something strange. + # For non-tty we set flush_on_newline to true for reasons described in STDOUT and STDERR docs. + path = uninitialized UInt8[256] + ret = LibC.ttyname_r(fd, path, 256) + return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) unless ret == 0 + + clone_fd = LibC.open(path, LibC::O_RDWR) + return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) if clone_fd == -1 + + # We don't buffer output for TTY devices to see their output right away + io = IO::FileDescriptor.new(clone_fd) + io.close_on_exec = true + io.sync = true + io end end diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index c0e1ca9eb18b..edbc833c536a 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -40,12 +40,7 @@ class Thread # the process (that already exists). def initialize @func = ->{} - @th = - {% if flag?(:wasm32) %} - Pointer(Void).null.as(LibC::PthreadT) - {% else %} - LibC.pthread_self - {% end %} + @th = LibC.pthread_self @main_fiber = Fiber.new(stack_address, self) Thread.threads.push(self) diff --git a/src/crystal/system/unix/pthread_mutex.cr b/src/crystal/system/unix/pthread_mutex.cr index f0635b000057..41069c02b561 100644 --- a/src/crystal/system/unix/pthread_mutex.cr +++ b/src/crystal/system/unix/pthread_mutex.cr @@ -1,83 +1,55 @@ require "c/pthread" -{% if flag?(:wasm32) %} +# :nodoc: +class Thread # :nodoc: - class Thread - # :nodoc: - class Mutex - def initialize - end - - def lock : Nil - end - - def try_lock : Bool - true - end + class Mutex + def initialize + attributes = uninitialized LibC::PthreadMutexattrT + LibC.pthread_mutexattr_init(pointerof(attributes)) + LibC.pthread_mutexattr_settype(pointerof(attributes), LibC::PTHREAD_MUTEX_ERRORCHECK) - def unlock : Nil - end + ret = LibC.pthread_mutex_init(out @mutex, pointerof(attributes)) + raise RuntimeError.from_os_error("pthread_mutex_init", Errno.new(ret)) unless ret == 0 - def synchronize - lock - yield self - ensure - unlock - end + LibC.pthread_mutexattr_destroy(pointerof(attributes)) end - end -{% else %} - # :nodoc: - class Thread - # :nodoc: - class Mutex - def initialize - attributes = uninitialized LibC::PthreadMutexattrT - LibC.pthread_mutexattr_init(pointerof(attributes)) - LibC.pthread_mutexattr_settype(pointerof(attributes), LibC::PTHREAD_MUTEX_ERRORCHECK) - - ret = LibC.pthread_mutex_init(out @mutex, pointerof(attributes)) - raise RuntimeError.from_os_error("pthread_mutex_init", Errno.new(ret)) unless ret == 0 - - LibC.pthread_mutexattr_destroy(pointerof(attributes)) - end - def lock : Nil - ret = LibC.pthread_mutex_lock(self) - raise RuntimeError.from_os_error("pthread_mutex_lock", Errno.new(ret)) unless ret == 0 - end + def lock : Nil + ret = LibC.pthread_mutex_lock(self) + raise RuntimeError.from_os_error("pthread_mutex_lock", Errno.new(ret)) unless ret == 0 + end - def try_lock : Bool - case ret = Errno.new(LibC.pthread_mutex_trylock(self)) - when .none? - true - when Errno::EBUSY - false - else - raise RuntimeError.from_os_error("pthread_mutex_trylock", ret) - end + def try_lock : Bool + case ret = Errno.new(LibC.pthread_mutex_trylock(self)) + when .none? + true + when Errno::EBUSY + false + else + raise RuntimeError.from_os_error("pthread_mutex_trylock", ret) end + end - def unlock : Nil - ret = LibC.pthread_mutex_unlock(self) - raise RuntimeError.from_os_error("pthread_mutex_unlock", Errno.new(ret)) unless ret == 0 - end + def unlock : Nil + ret = LibC.pthread_mutex_unlock(self) + raise RuntimeError.from_os_error("pthread_mutex_unlock", Errno.new(ret)) unless ret == 0 + end - def synchronize - lock - yield self - ensure - unlock - end + def synchronize + lock + yield self + ensure + unlock + end - def finalize - ret = LibC.pthread_mutex_destroy(self) - raise RuntimeError.from_os_error("pthread_mutex_destroy", Errno.new(ret)) unless ret == 0 - end + def finalize + ret = LibC.pthread_mutex_destroy(self) + raise RuntimeError.from_os_error("pthread_mutex_destroy", Errno.new(ret)) unless ret == 0 + end - def to_unsafe - pointerof(@mutex) - end + def to_unsafe + pointerof(@mutex) end end -{% end %} +end diff --git a/src/crystal/system/user.cr b/src/crystal/system/user.cr index a065bb4e712d..1148f18eb521 100644 --- a/src/crystal/system/user.cr +++ b/src/crystal/system/user.cr @@ -1,5 +1,7 @@ {% if flag?(:unix) %} require "./unix/user" +{% elsif flag?(:wasm32) %} + require "./wasm/user" {% else %} {% raise "No Crystal::System::User implementation available" %} {% end %} diff --git a/src/crystal/system/wasm/cpucount.cr b/src/crystal/system/wasm/cpucount.cr new file mode 100644 index 000000000000..943c65be506c --- /dev/null +++ b/src/crystal/system/wasm/cpucount.cr @@ -0,0 +1,5 @@ +module Crystal::System + def self.cpu_count + 1 + end +end diff --git a/src/crystal/system/unix/event_loop_libevent_wasm32.cr b/src/crystal/system/wasm/event_loop.cr similarity index 100% rename from src/crystal/system/unix/event_loop_libevent_wasm32.cr rename to src/crystal/system/wasm/event_loop.cr diff --git a/src/crystal/system/wasm/fiber.cr b/src/crystal/system/wasm/fiber.cr new file mode 100644 index 000000000000..6d78d2d8ca68 --- /dev/null +++ b/src/crystal/system/wasm/fiber.cr @@ -0,0 +1,10 @@ +require "c/sys/mman" + +module Crystal::System::Fiber + def self.allocate_stack(stack_size) : Void* + raise RuntimeError.new("Cannot allocate new fiber stack") + end + + def self.free_stack(stack : Void*, stack_size) : Nil + end +end diff --git a/src/crystal/system/wasm/file_descriptor.cr b/src/crystal/system/wasm/file_descriptor.cr new file mode 100644 index 000000000000..162db532aa1e --- /dev/null +++ b/src/crystal/system/wasm/file_descriptor.cr @@ -0,0 +1,8 @@ +require "../unix/file_descriptor" + +# :nodoc: +module Crystal::System::FileDescriptor + def self.from_stdio(fd) + return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) + end +end diff --git a/src/crystal/system/unix/getentropy.cr b/src/crystal/system/wasm/getentropy.cr similarity index 97% rename from src/crystal/system/unix/getentropy.cr rename to src/crystal/system/wasm/getentropy.cr index 34a785b578b1..a89741a5421b 100644 --- a/src/crystal/system/unix/getentropy.cr +++ b/src/crystal/system/wasm/getentropy.cr @@ -1,5 +1,3 @@ -{% skip_file unless flag?(:wasm32) %} - require "c/unistd" lib LibC diff --git a/src/crystal/system/wasm/group.cr b/src/crystal/system/wasm/group.cr new file mode 100644 index 000000000000..3939642fecc9 --- /dev/null +++ b/src/crystal/system/wasm/group.cr @@ -0,0 +1,9 @@ +module Crystal::System::Group + private def from_name?(groupname : String) + nil + end + + private def from_id?(groupid : String) + nil + end +end diff --git a/src/crystal/system/wasm/hostname.cr b/src/crystal/system/wasm/hostname.cr new file mode 100644 index 000000000000..99b143bf63eb --- /dev/null +++ b/src/crystal/system/wasm/hostname.cr @@ -0,0 +1,5 @@ +module Crystal::System + def self.hostname + "" + end +end diff --git a/src/crystal/system/wasm/mime.cr b/src/crystal/system/wasm/mime.cr new file mode 100644 index 000000000000..df4342d9311d --- /dev/null +++ b/src/crystal/system/wasm/mime.cr @@ -0,0 +1,4 @@ +module Crystal::System::MIME + def self.load + end +end diff --git a/src/crystal/system/wasm/process.cr b/src/crystal/system/wasm/process.cr new file mode 100644 index 000000000000..fb024e3f19ae --- /dev/null +++ b/src/crystal/system/wasm/process.cr @@ -0,0 +1,79 @@ +require "c/signal" +require "c/stdlib" +require "c/sys/resource" +require "c/unistd" +require "file/error" + +struct Crystal::System::Process + getter pid : LibC::PidT + + def initialize(@pid : LibC::PidT) + end + + def release + end + + def wait + raise NotImplementedError.new("Process#wait") + end + + def exists? + raise NotImplementedError.new("Process#exists?") + end + + def terminate + raise NotImplementedError.new("Process#terminate") + end + + def self.exit(status) + LibC.exit(status) + end + + def self.pid + 1 + end + + def self.pgid + raise NotImplementedError.new("Process.pgid") + end + + def self.pgid(pid) + raise NotImplementedError.new("Process.pgid") + end + + def self.ppid + raise NotImplementedError.new("Process.ppid") + end + + def self.signal(pid, signal) + raise NotImplementedError.new("Process.signal") + end + + def self.exists?(pid) + raise NotImplementedError.new("Process.exists?") + end + + def self.times + raise NotImplementedError.new("Process.times") + end + + def self.fork(*, will_exec = false) + raise NotImplementedError.new("Process.fork") + end + + def self.spawn(command_args, env, clear_env, input, output, error, chdir) + raise NotImplementedError.new("Process.spawn") + end + + def self.prepare_args(command : String, args : Enumerable(String)?, shell : Bool) : Array(String) + raise NotImplementedError.new("Process.prepare_args") + end + + def self.replace(command_args, env, clear_env, input, output, error, chdir) + raise NotImplementedError.new("Process.replace") + end + + def self.chroot(path) + raise NotImplementedError.new("Process.chroot") + end +end diff --git a/src/crystal/system/wasm/thread.cr b/src/crystal/system/wasm/thread.cr new file mode 100644 index 000000000000..b2c6433b5480 --- /dev/null +++ b/src/crystal/system/wasm/thread.cr @@ -0,0 +1,95 @@ +class Thread + # all thread objects, so the GC can see them (it doesn't scan thread locals) + @@threads = Thread::LinkedList(Thread).new + + @exception : Exception? + @detached = Atomic(UInt8).new(0) + @main_fiber : Fiber? + @func : (Proc(Nil))? + + # :nodoc: + property next : Thread? + + # :nodoc: + property previous : Thread? + + def self.unsafe_each + @@threads.unsafe_each { |thread| yield thread } + end + + def initialize + @main_fiber = Fiber.new(stack_address, self) + @@threads.push(self) + end + + def initialize(&@func : ->) + initialize + end + + def join : Nil + end + + def self.yield : Nil + end + + @@current : Thread? = nil + + # Associates the Thread object to the running system thread. + protected def self.current=(@@current : Thread) : Thread + end + + # Returns the Thread object associated to the running system thread. + def self.current : Thread + @@current || raise "BUG: Thread.current returned NULL" + end + + # Create the thread object for the current thread (aka the main thread of the + # process). + # + # TODO: consider moving to `kernel.cr` or `crystal/main.cr` + self.current = new + + # Returns the Fiber representing the thread's main stack. + def main_fiber + @main_fiber.not_nil! + end + + # :nodoc: + def scheduler + @scheduler ||= Crystal::Scheduler.new(main_fiber) + end + + protected def start + Thread.current = self + @main_fiber = fiber = Fiber.new(stack_address, self) + + begin + @func.call + rescue ex + @exception = ex + ensure + @@threads.delete(self) + Fiber.inactive(fiber) + detach_self + end + end + + private def stack_address : Void* + Pointer(Void).null + end + + # :nodoc: + class ConditionVariable + def signal : Nil + end + + def broadcast : Nil + end + + def wait(mutex : Thread::Mutex) : Nil + end + + def wait(mutex : Thread::Mutex, time : Time::Span, &) + end + end +end diff --git a/src/crystal/system/wasm/thread_mutex.cr b/src/crystal/system/wasm/thread_mutex.cr new file mode 100644 index 000000000000..0d90bebb67f8 --- /dev/null +++ b/src/crystal/system/wasm/thread_mutex.cr @@ -0,0 +1,17 @@ +# TODO: Implement +class Thread + class Mutex + def lock + end + + def try_lock + end + + def unlock + end + + def synchronize + yield + end + end +end diff --git a/src/crystal/system/wasm/user.cr b/src/crystal/system/wasm/user.cr new file mode 100644 index 000000000000..ecabf37c39ca --- /dev/null +++ b/src/crystal/system/wasm/user.cr @@ -0,0 +1,9 @@ +module Crystal::System::User + private def from_username?(username : String) + nil + end + + private def from_id?(id : String) + nil + end +end diff --git a/src/kernel.cr b/src/kernel.cr index 5032e663ded1..567348d55e94 100644 --- a/src/kernel.cr +++ b/src/kernel.cr @@ -502,7 +502,7 @@ def abort(message = nil, status = 1) : NoReturn exit status end -{% unless flag?(:preview_mt) %} +{% unless flag?(:preview_mt) || flag?(:wasm32) %} class Process # :nodoc: # diff --git a/src/prelude.cr b/src/prelude.cr index fd21dad87aa3..f391f0386ac2 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -70,7 +70,7 @@ require "range" require "reference" require "regex" require "set" -{% unless flag?(:win32) || flag?(:wasm32) %} +{% unless flag?(:win32) %} require "signal" {% end %} require "slice" diff --git a/src/signal.cr b/src/signal.cr index d1352f1f9f0d..4dda9c328f97 100644 --- a/src/signal.cr +++ b/src/signal.cr @@ -191,7 +191,7 @@ module Crystal::Signal alias Handler = ::Signal -> - @@pipe = IO.pipe(read_blocking: false, write_blocking: true) + private class_getter(pipe) { IO.pipe(read_blocking: false, write_blocking: true) } @@handlers = {} of ::Signal => Handler @@child_handler : Handler? @@mutex = Mutex.new(:unchecked) @@ -267,7 +267,7 @@ module Crystal::Signal # Replaces the signal pipe so the child process won't share the file # descriptors of the parent process and send it received signals. def self.after_fork - @@pipe.each(&.file_descriptor_close) + pipe.each(&.file_descriptor_close) ensure @@pipe = IO.pipe(read_blocking: false, write_blocking: true) end @@ -290,16 +290,16 @@ module Crystal::Signal end ensure {% unless flag?(:preview_mt) %} - @@pipe.each(&.file_descriptor_close) + pipe.each(&.file_descriptor_close) {% end %} end private def self.reader - @@pipe[0] + pipe[0] end private def self.writer - @@pipe[1] + pipe[1] end private def self.fatal(message : String) diff --git a/src/socket/address.cr b/src/socket/address.cr index f1279e63cf59..5d89086cd113 100644 --- a/src/socket/address.cr +++ b/src/socket/address.cr @@ -242,7 +242,7 @@ class Socket private def ipv6_addr8(addr : LibC::In6Addr) {% if flag?(:darwin) || flag?(:bsd) %} addr.__u6_addr.__u6_addr8 - {% elsif flag?(:linux) && flag?(:musl) %} + {% elsif flag?(:wasm32) || flag?(:linux) && flag?(:musl) %} addr.__in6_union.__s6_addr {% elsif flag?(:linux) %} addr.__in6_u.__u6_addr8 From fe511decad5802e5a965ba4019eafef87ba08e72 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 14 Jul 2021 17:29:21 -0400 Subject: [PATCH 05/41] Enable smoke tests for wasm32-wasi --- .github/workflows/smoke.yml | 1 + spec/std/string_spec.cr | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 938b8f5ca307..f202565f9aef 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -46,6 +46,7 @@ jobs: - aarch64-darwin - arm-linux-gnueabihf - i386-linux-musl + - wasm32-unknown-wasi - x86_64-dragonfly - x86_64-freebsd - x86_64-netbsd diff --git a/spec/std/string_spec.cr b/spec/std/string_spec.cr index fb6079528127..fb66531a3e1f 100644 --- a/spec/std/string_spec.cr +++ b/spec/std/string_spec.cr @@ -2646,12 +2646,14 @@ describe "String" do string.should be(clone) end - it "allocates buffer of correct size when UInt8 is given to new (#3332)" do - String.new(255_u8) do |buffer| - LibGC.size(buffer).should be >= 255 - {255, 0} + {% unless flag?(:wasm32) %} + it "allocates buffer of correct size when UInt8 is given to new (#3332)" do + String.new(255_u8) do |buffer| + LibGC.size(buffer).should be >= 255 + {255, 0} + end end - end + {% end %} it "raises on String.new if returned bytesize is greater than capacity" do expect_raises ArgumentError, "Bytesize out of capacity bounds" do From 165b97448a4707acc23d40ee6e144e2433fd6346 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 14 Jul 2021 17:33:56 -0400 Subject: [PATCH 06/41] Revert change on unix Thread --- src/crystal/system/unix/pthread.cr | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index edbc833c536a..4af585abe272 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -34,8 +34,6 @@ class Thread end end - @th : LibC::PthreadT - # Used once to initialize the thread object representing the main thread of # the process (that already exists). def initialize From be594ed51a4b2f42808876d3c6ddef3ca707bea7 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 14 Jul 2021 17:42:44 -0400 Subject: [PATCH 07/41] Smoke test: build compiler for the wasm test --- .github/workflows/smoke.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index f202565f9aef..78ea1d59f620 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -56,5 +56,9 @@ jobs: - name: Download Crystal source uses: actions/checkout@v2 + - name: Make compiler (special case only for wasm32, until next release). + if: ${{ matrix.target == 'wasm32-unknown-wasi' }} + run: bin/ci with_build_env make + - name: Run smoke test run: bin/ci with_build_env make smoke_test target=${{ matrix.target }} From 598c99f0899b21a247ef641e7dd7ab39174cafe9 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 21 Jul 2021 14:05:54 -0400 Subject: [PATCH 08/41] Mark stub methods with NotImplementedError or TODO --- src/crystal/system/mime.cr | 4 +--- src/crystal/system/wasm/cpucount.cr | 1 + src/crystal/system/wasm/event_loop.cr | 9 +++++---- src/crystal/system/wasm/fiber.cr | 3 ++- src/crystal/system/wasm/group.cr | 4 ++-- src/crystal/system/wasm/hostname.cr | 2 +- src/crystal/system/wasm/mime.cr | 4 ---- src/crystal/system/wasm/process.cr | 2 ++ src/crystal/system/wasm/thread.cr | 4 ++++ src/crystal/system/wasm/user.cr | 4 ++-- 10 files changed, 20 insertions(+), 17 deletions(-) delete mode 100644 src/crystal/system/wasm/mime.cr diff --git a/src/crystal/system/mime.cr b/src/crystal/system/mime.cr index 1ed1335460d7..fe90f43970f8 100644 --- a/src/crystal/system/mime.cr +++ b/src/crystal/system/mime.cr @@ -3,12 +3,10 @@ module Crystal::System::MIME # def self.load end -{% if flag?(:unix) %} +{% if flag?(:unix) || flag?(:wasm32) %} require "./unix/mime" {% elsif flag?(:win32) %} require "./win32/mime" -{% elsif flag?(:wasm32) %} - require "./wasm/mime" {% else %} {% raise "No Crystal::System::Mime implementation available" %} {% end %} diff --git a/src/crystal/system/wasm/cpucount.cr b/src/crystal/system/wasm/cpucount.cr index 943c65be506c..f6f068b09ae2 100644 --- a/src/crystal/system/wasm/cpucount.cr +++ b/src/crystal/system/wasm/cpucount.cr @@ -1,5 +1,6 @@ module Crystal::System def self.cpu_count + # TODO: There isn't a good way to get the number of CPUs on WebAssembly 1 end end diff --git a/src/crystal/system/wasm/event_loop.cr b/src/crystal/system/wasm/event_loop.cr index 95be1badee39..0d8eaf6f780a 100644 --- a/src/crystal/system/wasm/event_loop.cr +++ b/src/crystal/system/wasm/event_loop.cr @@ -2,26 +2,27 @@ module Crystal::EventLoop # Runs the event loop. def self.run_once + raise NotImplementedError.new("Crystal::EventLoop.run_once") end # Create a new resume event for a fiber. def self.create_resume_event(fiber : Fiber) : Crystal::Event - Crystal::Event.new + raise NotImplementedError.new("Crystal::EventLoop.create_resume_event") end # Creates a timeout_event. def self.create_timeout_event(fiber) : Crystal::Event - Crystal::Event.new + raise NotImplementedError.new("Crystal::EventLoop.create_timeout_event") end # Creates a write event for a file descriptor. def self.create_fd_write_event(io : IO::Evented, edge_triggered : Bool = false) : Crystal::Event - Crystal::Event.new + raise NotImplementedError.new("Crystal::EventLoop.create_fd_write_event") end # Creates a read event for a file descriptor. def self.create_fd_read_event(io : IO::Evented, edge_triggered : Bool = false) : Crystal::Event - Crystal::Event.new + raise NotImplementedError.new("Crystal::EventLoop.create_fd_read_event") end end diff --git a/src/crystal/system/wasm/fiber.cr b/src/crystal/system/wasm/fiber.cr index 6d78d2d8ca68..0db8324b403d 100644 --- a/src/crystal/system/wasm/fiber.cr +++ b/src/crystal/system/wasm/fiber.cr @@ -2,9 +2,10 @@ require "c/sys/mman" module Crystal::System::Fiber def self.allocate_stack(stack_size) : Void* - raise RuntimeError.new("Cannot allocate new fiber stack") + raise NotImplementedError.new("Crystal::System::Fiber.allocate_stack") end def self.free_stack(stack : Void*, stack_size) : Nil + raise NotImplementedError.new("Crystal::System::Fiber.free_stack") end end diff --git a/src/crystal/system/wasm/group.cr b/src/crystal/system/wasm/group.cr index 3939642fecc9..0aa09bd40aa8 100644 --- a/src/crystal/system/wasm/group.cr +++ b/src/crystal/system/wasm/group.cr @@ -1,9 +1,9 @@ module Crystal::System::Group private def from_name?(groupname : String) - nil + raise NotImplementedError.new("Crystal::System::Group#from_name?") end private def from_id?(groupid : String) - nil + raise NotImplementedError.new("Crystal::System::Group#from_id?") end end diff --git a/src/crystal/system/wasm/hostname.cr b/src/crystal/system/wasm/hostname.cr index 99b143bf63eb..e59611d6a0a4 100644 --- a/src/crystal/system/wasm/hostname.cr +++ b/src/crystal/system/wasm/hostname.cr @@ -1,5 +1,5 @@ module Crystal::System def self.hostname - "" + raise NotImplementedError.new("Crystal::System.hostname") end end diff --git a/src/crystal/system/wasm/mime.cr b/src/crystal/system/wasm/mime.cr deleted file mode 100644 index df4342d9311d..000000000000 --- a/src/crystal/system/wasm/mime.cr +++ /dev/null @@ -1,4 +0,0 @@ -module Crystal::System::MIME - def self.load - end -end diff --git a/src/crystal/system/wasm/process.cr b/src/crystal/system/wasm/process.cr index fb024e3f19ae..16ceec3b7b27 100644 --- a/src/crystal/system/wasm/process.cr +++ b/src/crystal/system/wasm/process.cr @@ -11,6 +11,7 @@ struct Crystal::System::Process end def release + raise NotImplementedError.new("Process#wait") end def wait @@ -30,6 +31,7 @@ struct Crystal::System::Process end def self.pid + # TODO: WebAssembly doesn't have the concept of processes. 1 end diff --git a/src/crystal/system/wasm/thread.cr b/src/crystal/system/wasm/thread.cr index b2c6433b5480..1b81dd853ddd 100644 --- a/src/crystal/system/wasm/thread.cr +++ b/src/crystal/system/wasm/thread.cr @@ -27,9 +27,11 @@ class Thread end def join : Nil + raise NotImplementedError.new("Thread#join") end def self.yield : Nil + raise NotImplementedError.new("Thread.yield") end @@current : Thread? = nil @@ -75,10 +77,12 @@ class Thread end private def stack_address : Void* + # TODO: Implement Pointer(Void).null end # :nodoc: + # TODO: Implement class ConditionVariable def signal : Nil end diff --git a/src/crystal/system/wasm/user.cr b/src/crystal/system/wasm/user.cr index ecabf37c39ca..06415897000e 100644 --- a/src/crystal/system/wasm/user.cr +++ b/src/crystal/system/wasm/user.cr @@ -1,9 +1,9 @@ module Crystal::System::User private def from_username?(username : String) - nil + raise NotImplementedError.new("Crystal::System::User#from_username?") end private def from_id?(id : String) - nil + raise NotImplementedError.new("Crystal::System::User#from_id?") end end From 2d78c9b6659c5c054afbfdb9800b45d2fba647e2 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 21 Jul 2021 15:37:47 -0300 Subject: [PATCH 09/41] Update src/crystal/system/wasm/process.cr Co-authored-by: Sijawusz Pur Rahnama --- src/crystal/system/wasm/process.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystal/system/wasm/process.cr b/src/crystal/system/wasm/process.cr index 16ceec3b7b27..cbe37f43f64f 100644 --- a/src/crystal/system/wasm/process.cr +++ b/src/crystal/system/wasm/process.cr @@ -11,7 +11,7 @@ struct Crystal::System::Process end def release - raise NotImplementedError.new("Process#wait") + raise NotImplementedError.new("Process#release") end def wait From ffd9c12292d0dfbb0521d6921c8ebb3a89f96b56 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 22 Jul 2021 16:46:53 -0400 Subject: [PATCH 10/41] Update wasi libc: it's now limited to what wasi actually provides. Mostly made by @maxfierke, with small changes. --- src/lib_c/wasm32-wasi | 1 - src/lib_c/wasm32-wasi/c/arpa/inet.cr | 9 ++ src/lib_c/wasm32-wasi/c/dirent.cr | 22 +++++ src/lib_c/wasm32-wasi/c/errno.cr | 79 ++++++++++++++++ src/lib_c/wasm32-wasi/c/fcntl.cr | 32 +++++++ src/lib_c/wasm32-wasi/c/iconv.cr | 9 ++ src/lib_c/wasm32-wasi/c/netdb.cr | 16 ++++ src/lib_c/wasm32-wasi/c/netinet/in.cr | 61 ++++++++++++ src/lib_c/wasm32-wasi/c/netinet/tcp.cr | 6 ++ src/lib_c/wasm32-wasi/c/pthread.cr | 5 + src/lib_c/wasm32-wasi/c/sched.cr | 3 + src/lib_c/wasm32-wasi/c/signal.cr | 53 +++++++++++ src/lib_c/wasm32-wasi/c/stdarg.cr | 3 + src/lib_c/wasm32-wasi/c/stddef.cr | 3 + src/lib_c/wasm32-wasi/c/stdint.cr | 10 ++ src/lib_c/wasm32-wasi/c/stdio.cr | 9 ++ src/lib_c/wasm32-wasi/c/stdlib.cr | 26 +++++ src/lib_c/wasm32-wasi/c/string.cr | 9 ++ src/lib_c/wasm32-wasi/c/sys/file.cr | 8 ++ src/lib_c/wasm32-wasi/c/sys/mman.cr | 31 ++++++ src/lib_c/wasm32-wasi/c/sys/resource.cr | 11 +++ src/lib_c/wasm32-wasi/c/sys/select.cr | 13 +++ src/lib_c/wasm32-wasi/c/sys/socket.cr | 38 ++++++++ src/lib_c/wasm32-wasi/c/sys/stat.cr | 51 ++++++++++ src/lib_c/wasm32-wasi/c/sys/syscall.cr | 2 + src/lib_c/wasm32-wasi/c/sys/time.cr | 15 +++ src/lib_c/wasm32-wasi/c/sys/times.cr | 12 +++ src/lib_c/wasm32-wasi/c/sys/types.cr | 61 ++++++++++++ src/lib_c/wasm32-wasi/c/sys/wait.cr | 5 + src/lib_c/wasm32-wasi/c/termios.cr | 120 ++++++++++++++++++++++++ src/lib_c/wasm32-wasi/c/time.cr | 32 +++++++ src/lib_c/wasm32-wasi/c/unistd.cr | 32 +++++++ 32 files changed, 786 insertions(+), 1 deletion(-) delete mode 120000 src/lib_c/wasm32-wasi create mode 100644 src/lib_c/wasm32-wasi/c/arpa/inet.cr create mode 100644 src/lib_c/wasm32-wasi/c/dirent.cr create mode 100644 src/lib_c/wasm32-wasi/c/errno.cr create mode 100644 src/lib_c/wasm32-wasi/c/fcntl.cr create mode 100644 src/lib_c/wasm32-wasi/c/iconv.cr create mode 100644 src/lib_c/wasm32-wasi/c/netdb.cr create mode 100644 src/lib_c/wasm32-wasi/c/netinet/in.cr create mode 100644 src/lib_c/wasm32-wasi/c/netinet/tcp.cr create mode 100644 src/lib_c/wasm32-wasi/c/pthread.cr create mode 100644 src/lib_c/wasm32-wasi/c/sched.cr create mode 100644 src/lib_c/wasm32-wasi/c/signal.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdarg.cr create mode 100644 src/lib_c/wasm32-wasi/c/stddef.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdint.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdio.cr create mode 100644 src/lib_c/wasm32-wasi/c/stdlib.cr create mode 100644 src/lib_c/wasm32-wasi/c/string.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/file.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/mman.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/resource.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/select.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/socket.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/stat.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/syscall.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/time.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/times.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/types.cr create mode 100644 src/lib_c/wasm32-wasi/c/sys/wait.cr create mode 100644 src/lib_c/wasm32-wasi/c/termios.cr create mode 100644 src/lib_c/wasm32-wasi/c/time.cr create mode 100644 src/lib_c/wasm32-wasi/c/unistd.cr diff --git a/src/lib_c/wasm32-wasi b/src/lib_c/wasm32-wasi deleted file mode 120000 index dc756741ff87..000000000000 --- a/src/lib_c/wasm32-wasi +++ /dev/null @@ -1 +0,0 @@ -i386-linux-musl \ No newline at end of file diff --git a/src/lib_c/wasm32-wasi/c/arpa/inet.cr b/src/lib_c/wasm32-wasi/c/arpa/inet.cr new file mode 100644 index 000000000000..afac8795f66f --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/arpa/inet.cr @@ -0,0 +1,9 @@ +require "../netinet/in" +require "../stdint" + +lib LibC + fun htons(x0 : UInt16T) : UInt16T + fun ntohs(x0 : UInt16T) : UInt16T + fun inet_ntop(x0 : Int, x1 : Void*, x2 : Char*, x3 : SocklenT) : Char* + fun inet_pton(x0 : Int, x1 : Char*, x2 : Void*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/dirent.cr b/src/lib_c/wasm32-wasi/c/dirent.cr new file mode 100644 index 000000000000..83836cdd73bb --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/dirent.cr @@ -0,0 +1,22 @@ +require "./sys/types" + +lib LibC + type DIR = Void + + DT_UNKNOWN = 0 + DT_DIR = 3 + DT_LINK = 7 + + struct Dirent + d_ino : InoT + d_off : OffT + d_reclen : UShort + d_type : Char + d_name : StaticArray(Char, 256) + end + + fun closedir(x0 : DIR*) : Int + fun opendir(x0 : Char*) : DIR* + fun readdir(x0 : DIR*) : Dirent* + fun rewinddir(x0 : DIR*) : Void +end diff --git a/src/lib_c/wasm32-wasi/c/errno.cr b/src/lib_c/wasm32-wasi/c/errno.cr new file mode 100644 index 000000000000..662c355ec1d3 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/errno.cr @@ -0,0 +1,79 @@ +lib LibC + E2BIG = 1_u16 + EACCES = 2_u16 + EADDRINUSE = 3_u16 + EADDRNOTAVAIL = 4_u16 + EAFNOSUPPORT = 5_u16 + EAGAIN = 6_u16 + EALREADY = 7_u16 + EBADF = 8_u16 + EBADMSG = 9_u16 + EBUSY = 10_u16 + ECANCELED = 11_u16 + ECHILD = 12_u16 + ECONNABORTED = 13_u16 + ECONNREFUSED = 14_u16 + ECONNRESET = 15_u16 + EDEADLK = 16_u16 + EDESTADDRREQ = 17_u16 + EDOM = 18_u16 + EDQUOT = 19_u16 + EEXIST = 20_u16 + EFAULT = 21_u16 + EFBIG = 22_u16 + EHOSTUNREACH = 23_u16 + EIDRM = 24_u16 + EILSEQ = 25_u16 + EINPROGRESS = 26_u16 + EINTR = 27_u16 + EINVAL = 28_u16 + EIO = 29_u16 + EISCONN = 30_u16 + EISDIR = 31_u16 + ELOOP = 32_u16 + EMFILE = 33_u16 + EMLINK = 34_u16 + EMSGSIZE = 35_u16 + EMULTIHOP = 36_u16 + ENAMETOOLONG = 37_u16 + ENETDOWN = 38_u16 + ENETRESET = 39_u16 + ENETUNREACH = 40_u16 + ENFILE = 41_u16 + ENOBUFS = 42_u16 + ENODEV = 43_u16 + ENOENT = 44_u16 + ENOEXEC = 45_u16 + ENOLCK = 46_u16 + ENOLINK = 47_u16 + ENOMEM = 48_u16 + ENOMSG = 49_u16 + ENOPROTOOPT = 50_u16 + ENOSPC = 51_u16 + ENOSYS = 52_u16 + ENOTCONN = 53_u16 + ENOTDIR = 54_u16 + ENOTEMPTY = 55_u16 + ENOTRECOVERABLE = 56_u16 + ENOTSOCK = 57_u16 + ENOTSUP = 58_u16 + ENOTTY = 59_u16 + ENXIO = 60_u16 + EOPNOTSUPP = LibC::ENOTSUP + EOVERFLOW = 61_u16 + EOWNERDEAD = 62_u16 + EPERM = 63_u16 + EPIPE = 64_u16 + EPROTO = 65_u16 + EPROTONOSUPPORT = 66_u16 + EPROTOTYPE = 67_u16 + ERANGE = 68_u16 + EROFS = 69_u16 + ESPIPE = 70_u16 + ESRCH = 71_u16 + ESTALE = 72_u16 + ETIMEDOUT = 73_u16 + ETXTBSY = 74_u16 + EWOULDBLOCK = LibC::EAGAIN + EXDEV = 75_u16 +end diff --git a/src/lib_c/wasm32-wasi/c/fcntl.cr b/src/lib_c/wasm32-wasi/c/fcntl.cr new file mode 100644 index 000000000000..37de7f454bb6 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/fcntl.cr @@ -0,0 +1,32 @@ +require "./sys/types" +require "./sys/stat" +require "./unistd" + +lib LibC + F_GETFD = 1 + F_SETFD = 2 + F_GETFL = 3 + F_SETFL = 4 + FD_CLOEXEC = 1 + O_CLOEXEC = 0 + O_CREAT = 1_u16 << 12 + O_NOFOLLOW = 0x01000000 + O_TRUNC = 8_u16 << 12 + O_APPEND = 1_u16 + O_NONBLOCK = 4_u16 + O_SYNC = 16_u16 + O_RDONLY = 0x04000000 + O_RDWR = O_RDONLY | O_WRONLY + O_WRONLY = 0x10000000 + + struct Flock + l_type : Short + l_whence : Short + l_start : OffT + l_len : OffT + l_pid : PidT + end + + fun fcntl(x0 : Int, x1 : Int, ...) : Int + fun open(x0 : Char*, x1 : Int, ...) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/iconv.cr b/src/lib_c/wasm32-wasi/c/iconv.cr new file mode 100644 index 000000000000..6496b957ed24 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/iconv.cr @@ -0,0 +1,9 @@ +require "./stddef" + +lib LibC + type IconvT = Void* + + fun iconv(x0 : IconvT, x1 : Char**, x2 : SizeT*, x3 : Char**, x4 : SizeT*) : SizeT + fun iconv_close(x0 : IconvT) : Int + fun iconv_open(x0 : Char*, x1 : Char*) : IconvT +end diff --git a/src/lib_c/wasm32-wasi/c/netdb.cr b/src/lib_c/wasm32-wasi/c/netdb.cr new file mode 100644 index 000000000000..f73708969962 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/netdb.cr @@ -0,0 +1,16 @@ +require "./netinet/in" +require "./sys/socket" +require "./stdint" + +lib LibC + struct Addrinfo + ai_flags : Int + ai_family : Int + ai_socktype : Int + ai_protocol : Int + ai_addrlen : SocklenT + ai_addr : Sockaddr* + ai_canonname : Char* + ai_next : Addrinfo* + end +end diff --git a/src/lib_c/wasm32-wasi/c/netinet/in.cr b/src/lib_c/wasm32-wasi/c/netinet/in.cr new file mode 100644 index 000000000000..20a96d5ed22d --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/netinet/in.cr @@ -0,0 +1,61 @@ +require "../sys/socket" +require "../stdint" + +lib LibC + IPPROTO_IP = 0 + IPPROTO_IPV6 = 41 + IPPROTO_ICMP = 1 + IPPROTO_RAW = 255 + IPPROTO_TCP = 6 + IPPROTO_UDP = 17 + + alias InPortT = UShort + alias InAddrT = UInt + + struct InAddr + s_addr : InAddrT + end + + struct In6Addr + s6_addr : StaticArray(UChar, 16) + end + + struct SockaddrIn + sin_family : SaFamilyT + sin_port : InPortT + sin_addr : InAddr + end + + struct SockaddrIn6 + sin6_family : SaFamilyT + sin6_port : InPortT + sin6_flowinfo : UInt + sin6_addr : In6Addr + sin6_scope_id : UInt + end + + IP_MULTICAST_IF = 32 + IPV6_MULTICAST_IF = 17 + + IP_MULTICAST_TTL = 33 + IPV6_MULTICAST_HOPS = 18 + + IP_MULTICAST_LOOP = 34 + IPV6_MULTICAST_LOOP = 19 + + IP_ADD_MEMBERSHIP = 35 + IPV6_JOIN_GROUP = 20 + + IP_DROP_MEMBERSHIP = 36 + IPV6_LEAVE_GROUP = 21 + + struct IpMreq + imr_multiaddr : InAddr + imr_interface : InAddr + end + + struct Ipv6Mreq + ipv6mr_multiaddr : In6Addr + ipv6mr_interface : UInt + end +end diff --git a/src/lib_c/wasm32-wasi/c/netinet/tcp.cr b/src/lib_c/wasm32-wasi/c/netinet/tcp.cr new file mode 100644 index 000000000000..beed1db6e081 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/netinet/tcp.cr @@ -0,0 +1,6 @@ +lib LibC + TCP_NODELAY = 1 + TCP_KEEPIDLE = 4 + TCP_KEEPINTVL = 5 + TCP_KEEPCNT = 6 +end diff --git a/src/lib_c/wasm32-wasi/c/pthread.cr b/src/lib_c/wasm32-wasi/c/pthread.cr new file mode 100644 index 000000000000..cf67b1d60261 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/pthread.cr @@ -0,0 +1,5 @@ +require "./sys/types" + +lib LibC + fun pthread_join(th : PthreadT, thread_return : Void**) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sched.cr b/src/lib_c/wasm32-wasi/c/sched.cr new file mode 100644 index 000000000000..9d83ed18504e --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sched.cr @@ -0,0 +1,3 @@ +lib LibC + fun sched_yield : Int +end diff --git a/src/lib_c/wasm32-wasi/c/signal.cr b/src/lib_c/wasm32-wasi/c/signal.cr new file mode 100644 index 000000000000..b7a88aaab362 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/signal.cr @@ -0,0 +1,53 @@ +require "./sys/types" +require "./time" + +lib LibC + SIGHUP = 1 + SIGINT = 2 + SIGQUIT = 3 + SIGILL = 4 + SIGTRAP = 5 + SIGIOT = LibC::SIGABRT + SIGABRT = 6 + SIGFPE = 8 + SIGKILL = 9 + SIGBUS = 7 + SIGSEGV = 11 + SIGSYS = 31 + SIGPIPE = 13 + SIGALRM = 14 + SIGTERM = 15 + SIGURG = 23 + SIGSTOP = 19 + SIGTSTP = 20 + SIGCONT = 18 + SIGCHLD = 17 + SIGTTIN = 21 + SIGTTOU = 22 + SIGIO = 29 + SIGXCPU = 24 + SIGXFSZ = 25 + SIGVTALRM = 26 + SIGUSR1 = 10 + SIGUSR2 = 12 + SIGWINCH = 28 + SIGPWR = 30 + SIGSTKFLT = 16 + SIGUNUSED = LibC::SIGSYS + + alias SigsetT = LibC::UChar + + alias SighandlerT = Int -> Void + + struct SiginfoT + si_signo : Int + si_code : Int + si_errno : Int + si_addr : Void* + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) + + fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void +end diff --git a/src/lib_c/wasm32-wasi/c/stdarg.cr b/src/lib_c/wasm32-wasi/c/stdarg.cr new file mode 100644 index 000000000000..882d4f51d35c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdarg.cr @@ -0,0 +1,3 @@ +lib LibC + type VaList = Void* +end diff --git a/src/lib_c/wasm32-wasi/c/stddef.cr b/src/lib_c/wasm32-wasi/c/stddef.cr new file mode 100644 index 000000000000..4afcdf34d723 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stddef.cr @@ -0,0 +1,3 @@ +lib LibC + alias SizeT = ULong +end diff --git a/src/lib_c/wasm32-wasi/c/stdint.cr b/src/lib_c/wasm32-wasi/c/stdint.cr new file mode 100644 index 000000000000..c3d333b17104 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdint.cr @@ -0,0 +1,10 @@ +lib LibC + alias Int8T = SChar + alias Int16T = Short + alias Int32T = Int + alias Int64T = LongLong + alias UInt8T = UChar + alias UInt16T = UShort + alias UInt32T = UInt + alias UInt64T = ULongLong +end diff --git a/src/lib_c/wasm32-wasi/c/stdio.cr b/src/lib_c/wasm32-wasi/c/stdio.cr new file mode 100644 index 000000000000..98967c3ddfe9 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdio.cr @@ -0,0 +1,9 @@ +require "./sys/types" +require "./stddef" + +lib LibC + fun dprintf(x0 : Int, x1 : Char*, ...) : Int + fun printf(x0 : Char*, ...) : Int + fun rename(x0 : Char*, x1 : Char*) : Int + fun snprintf(x0 : Char*, x1 : SizeT, x2 : Char*, ...) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/stdlib.cr b/src/lib_c/wasm32-wasi/c/stdlib.cr new file mode 100644 index 000000000000..698de00c0d17 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/stdlib.cr @@ -0,0 +1,26 @@ +require "./stddef" +require "./sys/wait" + +lib LibC + struct DivT + quot : Int + rem : Int + end + + fun arc4random : UInt32T + fun arc4random_buf(x0 : Void*, x1 : SizeT) : Void + fun arc4random_uniform(x0 : UInt32T) : UInt32T + fun atof(x0 : Char*) : Double + fun div(x0 : Int, x1 : Int) : DivT + fun exit(x0 : Int) : NoReturn + fun free(ptr : Void*) : Void + fun getenv(x0 : Char*) : Char* + fun malloc(size : SizeT) : Void* + fun putenv(x0 : Char*) : Int + fun realloc(ptr : Void*, size : SizeT) : Void* + fun setenv(x0 : Char*, x1 : Char*, x2 : Int) : Int + fun strtod(x0 : Char*, x1 : Char**) : Double + fun strtof(x0 : Char*, x1 : Char**) : Float + fun strtol(x0 : Char*, x1 : Char**, x2 : Int) : Long + fun unsetenv(x0 : Char*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/string.cr b/src/lib_c/wasm32-wasi/c/string.cr new file mode 100644 index 000000000000..5be77e03cf1c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/string.cr @@ -0,0 +1,9 @@ +require "./stddef" + +lib LibC + fun memchr(x0 : Void*, x1 : Int, x2 : SizeT) : Void* + fun memcmp(x0 : Void*, x1 : Void*, x2 : SizeT) : Int + fun strcmp(x0 : Char*, x1 : Char*) : Int + fun strerror(x0 : Int) : Char* + fun strlen(x0 : Char*) : ULong +end diff --git a/src/lib_c/wasm32-wasi/c/sys/file.cr b/src/lib_c/wasm32-wasi/c/sys/file.cr new file mode 100644 index 000000000000..5f6e63d09ce0 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/file.cr @@ -0,0 +1,8 @@ +lib LibC + LOCK_SH = 1 + LOCK_EX = 2 + LOCK_NB = 4 + LOCK_UN = 8 + + fun flock(x0 : Int, x1 : Int) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/mman.cr b/src/lib_c/wasm32-wasi/c/sys/mman.cr new file mode 100644 index 000000000000..1f7af8eba42c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/mman.cr @@ -0,0 +1,31 @@ +require "./types" + +lib LibC + PROT_EXEC = 4 + PROT_NONE = 0 + PROT_READ = 1 + PROT_WRITE = 2 + MAP_FIXED = 0x10 + MAP_PRIVATE = 0x02 + MAP_SHARED = 0x01 + MAP_ANON = 0x20 + MAP_ANONYMOUS = LibC::MAP_ANON + MAP_FAILED = Pointer(Void).new(-1) + POSIX_MADV_DONTNEED = 4 + POSIX_MADV_NORMAL = 0 + POSIX_MADV_RANDOM = 1 + POSIX_MADV_SEQUENTIAL = 2 + POSIX_MADV_WILLNEED = 3 + MADV_DONTNEED = 4 + MADV_NORMAL = 0 + MADV_RANDOM = 1 + MADV_SEQUENTIAL = 2 + MADV_WILLNEED = 3 + MADV_HUGEPAGE = 14 + MADV_NOHUGEPAGE = 15 + + fun mmap(x0 : Void*, x1 : SizeT, x2 : Int, x3 : Int, x4 : Int, x5 : OffT) : Void* + fun mprotect(x0 : Void*, x1 : SizeT, x2 : Int) : Int + fun munmap(x0 : Void*, x1 : SizeT) : Int + fun madvise(x0 : Void*, x1 : SizeT, x2 : Int) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/resource.cr b/src/lib_c/wasm32-wasi/c/sys/resource.cr new file mode 100644 index 000000000000..655a9009d3a9 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/resource.cr @@ -0,0 +1,11 @@ +lib LibC + RUSAGE_SELF = 1 + RUSAGE_CHILDREN = 2 + + struct Rusage + ru_utime : Timeval + ru_stime : Timeval + end + + fun getrusage(who : Int, usage : Rusage*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/select.cr b/src/lib_c/wasm32-wasi/c/sys/select.cr new file mode 100644 index 000000000000..ef8a031287a7 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/select.cr @@ -0,0 +1,13 @@ +require "./types" +require "./time" +require "../time" +require "../signal" + +lib LibC + struct FdSet + __nfds : SizeT + __fds : StaticArray(Int, 1024) + end + + fun select(x0 : Int, x1 : FdSet*, x2 : FdSet*, x3 : FdSet*, x4 : Timeval*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/socket.cr b/src/lib_c/wasm32-wasi/c/sys/socket.cr new file mode 100644 index 000000000000..82bcec46e9cc --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/socket.cr @@ -0,0 +1,38 @@ +require "./types" + +lib LibC + SOCK_DGRAM = 5_u8 + SOCK_STREAM = 6_u8 + SOL_SOCKET = 0x7fffffff + AF_INET = 1 + AF_INET6 = 2 + AF_UNIX = 3 + AF_UNSPEC = 0 + SHUT_RD = 1_u8 + SHUT_RDWR = SHUT_RD | SHUT_WR + SHUT_WR = 2_u8 + SOCK_CLOEXEC = 0x00002000 + + alias SocklenT = UInt + alias SaFamilyT = UShort + + struct Sockaddr + sa_family : SaFamilyT + sa_data : StaticArray(Char, 0) + end + + struct SockaddrStorage + ss_family : SaFamilyT + __ss_data : StaticArray(Char, 32) + end + + struct Linger + l_onoff : Int + l_linger : Int + end + + fun getsockopt(x0 : Int, x1 : Int, x2 : Int, x3 : Void*, x4 : SocklenT*) : Int + fun recv(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int) : SSizeT + fun send(x0 : Int, x1 : Void*, x2 : SizeT, x3 : Int) : SSizeT + fun shutdown(x0 : Int, x1 : Int) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/stat.cr b/src/lib_c/wasm32-wasi/c/sys/stat.cr new file mode 100644 index 000000000000..6622b793198c --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/stat.cr @@ -0,0 +1,51 @@ +require "./types" +require "../time" + +lib LibC + S_IFMT = S_IFBLK | S_IFCHR | S_IFDIR | S_IFIFO | S_IFLNK | S_IFREG | S_IFSOCK + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFIFO = 0xc000 + S_IFREG = 0x8000 + S_IFDIR = 0x4000 + S_IFLNK = 0xa000 + S_IFSOCK = 0xc000 + S_IRUSR = 0x100 + S_IWUSR = 0x80 + S_IXUSR = 0x40 + S_IRWXU = S_IXUSR | S_IWUSR | S_IRUSR + S_IRGRP = 0x20 + S_IWGRP = 0x10 + S_IXGRP = 0x8 + S_IRWXG = S_IXGRP | S_IWGRP | S_IRGRP + S_IROTH = 0x4 + S_IWOTH = 0x2 + S_IXOTH = 0x1 + S_IRWXO = S_IXOTH | S_IWOTH | S_IROTH + S_ISUID = 0x800 + S_ISGID = 0x400 + S_ISVTX = 0x200 + + struct Stat + st_dev : DevT + st_ino : InoT + st_nlink : NlinkT + st_mode : ModeT + st_uid : UidT + st_gid : GidT + __pad0 : UInt + st_rdev : DevT + st_size : OffT + st_blksize : BlksizeT + st_blocks : BlkcntT + st_atim : Timespec + st_mtim : Timespec + st_ctim : Timespec + __reserved : StaticArray(LongLong, 3) + end + + fun fstat(x0 : Int, x1 : Stat*) : Int + fun lstat(x0 : Char*, x1 : Stat*) : Int + fun mkdir(x0 : Char*, x1 : ModeT) : Int + fun stat(x0 : Char*, x1 : Stat*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/syscall.cr b/src/lib_c/wasm32-wasi/c/sys/syscall.cr new file mode 100644 index 000000000000..d65139312793 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/syscall.cr @@ -0,0 +1,2 @@ +lib LibC +end diff --git a/src/lib_c/wasm32-wasi/c/sys/time.cr b/src/lib_c/wasm32-wasi/c/sys/time.cr new file mode 100644 index 000000000000..2f0678b910c8 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/time.cr @@ -0,0 +1,15 @@ +require "./types" + +lib LibC + struct Timeval + tv_sec : TimeT + tv_usec : SusecondsT + end + + struct Timezone + tz_minuteswest : Int + tz_dsttime : Int + end + + fun gettimeofday(x0 : Timeval*, x1 : Void*) : Int +end diff --git a/src/lib_c/wasm32-wasi/c/sys/times.cr b/src/lib_c/wasm32-wasi/c/sys/times.cr new file mode 100644 index 000000000000..c190774559f4 --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/times.cr @@ -0,0 +1,12 @@ +require "./types" + +lib LibC + struct Tms + tms_utime : ClockT + tms_stime : ClockT + tms_cutime : ClockT + tms_cstime : ClockT + end + + fun times(x0 : Tms*) : ClockT +end diff --git a/src/lib_c/wasm32-wasi/c/sys/types.cr b/src/lib_c/wasm32-wasi/c/sys/types.cr new file mode 100644 index 000000000000..5cca3a65b89b --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/types.cr @@ -0,0 +1,61 @@ +require "../stddef" +require "../stdint" + +lib LibC + alias BlkcntT = LongLong + alias BlksizeT = Long + alias ClockT = LongLong + alias ClockidT = Int + alias DevT = ULongLong + alias GidT = UInt + alias IdT = UInt + alias InoT = ULongLong + alias ModeT = UInt + alias NlinkT = ULongLong + alias OffT = LongLong + alias PidT = Int + + union PthreadAttrTU + __i : StaticArray(Int, 14) + __vi : StaticArray(Int, 14) + __s : StaticArray(ULong, 7) + end + + struct PthreadAttrT + __u : PthreadAttrTU + end + + union PthreadCondTU + __i : StaticArray(Int, 12) + __vi : StaticArray(Int, 12) + __p : StaticArray(Void*, 6) + end + + struct PthreadCondT + __u : PthreadCondTU + end + + struct PthreadCondattrT + __attr : UInt + end + + union PthreadMutexTU + __i : StaticArray(Int, 10) + __vi : StaticArray(Int, 10) + __p : StaticArray(Void*, 5) + end + + struct PthreadMutexT + __u : PthreadMutexTU + end + + struct PthreadMutexattrT + __attr : UInt + end + + type PthreadT = Void* + alias SSizeT = Long + alias SusecondsT = LongLong + alias TimeT = LongLong + alias UidT = UInt +end diff --git a/src/lib_c/wasm32-wasi/c/sys/wait.cr b/src/lib_c/wasm32-wasi/c/sys/wait.cr new file mode 100644 index 000000000000..58e6a3d0a9eb --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/sys/wait.cr @@ -0,0 +1,5 @@ +require "./types" +require "../signal" + +lib LibC +end diff --git a/src/lib_c/wasm32-wasi/c/termios.cr b/src/lib_c/wasm32-wasi/c/termios.cr new file mode 100644 index 000000000000..be54a30c3caf --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/termios.cr @@ -0,0 +1,120 @@ +require "./sys/types" + +lib LibC + VEOF = 4 + VEOL = 11 + VERASE = 2 + VINTR = 0 + VKILL = 3 + VMIN = 6 + VQUIT = 1 + VSTART = 8 + VSTOP = 9 + VSUSP = 10 + BRKINT = 0o000002 + ICRNL = 0o000400 + IGNBRK = 0o000001 + IGNCR = 0o000200 + IGNPAR = 0o000004 + INLCR = 0o000100 + INPCK = 0o000020 + ISTRIP = 0o000040 + IXANY = 0o004000 + IXOFF = 0o010000 + IXON = 0o002000 + PARMRK = 0o000010 + OPOST = 0o000001 + ONLCR = 0o000004 + OCRNL = 0o000010 + ONOCR = 0o000020 + ONLRET = 0o000040 + OFDEL = 0o000200 + OFILL = 0o000100 + CRDLY = 0o003000 + CR0 = 0o000000 + CR1 = 0o001000 + CR2 = 0o002000 + CR3 = 0o003000 + TABDLY = 0o014000 + TAB0 = 0o000000 + TAB1 = 0o004000 + TAB2 = 0o010000 + TAB3 = 0o014000 + BSDLY = 0o020000 + BS0 = 0o000000 + BS1 = 0o020000 + VTDLY = 0o040000 + VT0 = 0o000000 + VT1 = 0o040000 + FFDLY = 0o100000 + FF0 = 0o000000 + FF1 = 0o100000 + NLDLY = 0o000400 + NL0 = 0o000000 + NL1 = 0o000400 + B0 = 0o000000 + B50 = 0o000001 + B75 = 0o000002 + B110 = 0o000003 + B134 = 0o000004 + B150 = 0o000005 + B200 = 0o000006 + B300 = 0o000007 + B600 = 0o000010 + B1200 = 0o000011 + B1800 = 0o000012 + B2400 = 0o000013 + B4800 = 0o000014 + B9600 = 0o000015 + B19200 = 0o000016 + B38400 = 0o000017 + CSIZE = 0o000060 + CS5 = 0o000000 + CS6 = 0o000020 + CS7 = 0o000040 + CS8 = 0o000060 + CSTOPB = 0o000100 + CREAD = 0o000200 + PARENB = 0o000400 + PARODD = 0o001000 + HUPCL = 0o002000 + CLOCAL = 0o004000 + ECHO = 0o000010 + ECHOE = 0o000020 + ECHOK = 0o000040 + ECHONL = 0o000100 + ICANON = 0o000002 + IEXTEN = 0o100000 + ISIG = 0o000001 + NOFLSH = 0o000200 + TOSTOP = 0o000400 + TCSANOW = 0 + TCSADRAIN = 1 + TCSAFLUSH = 2 + TCIFLUSH = 0 + TCIOFLUSH = 2 + TCOFLUSH = 1 + TCIOFF = 2 + TCION = 3 + TCOOFF = 0 + TCOON = 1 + + alias CcT = UInt8 + alias SpeedT = UInt + alias TcflagT = UInt + + struct Termios + c_iflag : TcflagT + c_oflag : TcflagT + c_cflag : TcflagT + c_lflag : TcflagT + c_line : CcT + c_cc : StaticArray(CcT, 32) + __c_ispeed : SpeedT + __c_ospeed : SpeedT + end + + fun tcgetattr(x0 : Int, x1 : Termios*) : Int + fun tcsetattr(x0 : Int, x1 : Int, x2 : Termios*) : Int + fun cfmakeraw(x0 : Termios*) : Void +end diff --git a/src/lib_c/wasm32-wasi/c/time.cr b/src/lib_c/wasm32-wasi/c/time.cr new file mode 100644 index 000000000000..6b8fc35a21eb --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/time.cr @@ -0,0 +1,32 @@ +require "./sys/types" + +lib LibC + CLOCK_MONOTONIC = 1 + CLOCK_REALTIME = 0 + + struct Tm + tm_sec : Int + tm_min : Int + tm_hour : Int + tm_mday : Int + tm_mon : Int + tm_year : Int + tm_wday : Int + tm_yday : Int + tm_isdst : Int + tm_gmtoff : Int + tm_zone : Char* + __tm_nsec : Int + end + + struct Timespec + tv_sec : TimeT + tv_nsec : Long + end + + fun clock_gettime(x0 : ClockidT, x1 : Timespec*) : Int + fun gmtime_r(x0 : TimeT*, x1 : Tm*) : Tm* + fun localtime_r(x0 : TimeT*, x1 : Tm*) : Tm* + fun mktime(x0 : Tm*) : TimeT + fun timegm(x0 : Tm*) : TimeT +end diff --git a/src/lib_c/wasm32-wasi/c/unistd.cr b/src/lib_c/wasm32-wasi/c/unistd.cr new file mode 100644 index 000000000000..7b4a5949cafd --- /dev/null +++ b/src/lib_c/wasm32-wasi/c/unistd.cr @@ -0,0 +1,32 @@ +require "./sys/types" +require "./stdint" + +lib LibC + F_OK = 0 + R_OK = 1 + W_OK = 2 + X_OK = 4 + SC_CLK_TCK = 2 + SC_NPROCESSORS_ONLN = 84 + + fun access(x0 : Char*, x1 : Int) : Int + fun chdir(x0 : Char*) : Int + fun close(fd : Int) : Int + fun _exit(x0 : Int) : NoReturn + fun fdatasync(x0 : Int) : Int + fun fsync(x0 : Int) : Int + fun ftruncate(x0 : Int, x1 : OffT) : Int + fun getcwd(x0 : Char*, x1 : SizeT) : Char* + fun isatty(x0 : Int) : Int + fun link(x0 : Char*, x1 : Char*) : Int + fun lseek(x0 : Int, x1 : OffT, x2 : Int) : OffT + fun read(x0 : Int, x1 : Void*, x2 : SizeT) : SSizeT + fun pread(x0 : Int, x1 : Void*, x2 : SizeT, x3 : OffT) : SSizeT + fun readlink(x0 : Char*, x1 : Char*, x2 : SizeT) : SSizeT + fun rmdir(x0 : Char*) : Int + fun sleep(x0 : UInt) : UInt + fun symlink(x0 : Char*, x1 : Char*) : Int + fun sysconf(x0 : Int) : Long + fun unlink(x0 : Char*) : Int + fun write(x0 : Int, x1 : Void*, x2 : SizeT) : SSizeT +end From 9faf7153cf0bfd5cbe4f6aa7d3ce0978e0a4f9c5 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 22 Jul 2021 16:47:36 -0400 Subject: [PATCH 11/41] Use arc4random instead of getentropy --- src/crystal/system/random.cr | 4 +- src/crystal/system/unix/arc4random.cr | 2 +- src/crystal/system/wasm/getentropy.cr | 72 --------------------------- 3 files changed, 2 insertions(+), 76 deletions(-) delete mode 100644 src/crystal/system/wasm/getentropy.cr diff --git a/src/crystal/system/random.cr b/src/crystal/system/random.cr index d56e80310d35..c60bdefad78a 100644 --- a/src/crystal/system/random.cr +++ b/src/crystal/system/random.cr @@ -12,9 +12,7 @@ end {% if flag?(:linux) %} require "./unix/getrandom" -{% elsif flag?(:wasm32) %} - require "./wasm/getentropy" -{% elsif flag?(:openbsd) || flag?(:netbsd) %} +{% elsif flag?(:openbsd) || flag?(:netbsd) || flag?(:wasm32) %} require "./unix/arc4random" {% elsif flag?(:unix) %} require "./unix/urandom" diff --git a/src/crystal/system/unix/arc4random.cr b/src/crystal/system/unix/arc4random.cr index 4338e3341974..8aa9c608e4ea 100644 --- a/src/crystal/system/unix/arc4random.cr +++ b/src/crystal/system/unix/arc4random.cr @@ -1,4 +1,4 @@ -{% skip_file unless flag?(:openbsd) || flag?(:netbsd) %} +{% skip_file unless flag?(:openbsd) || flag?(:netbsd) || flag?(:wasm32) %} require "c/stdlib" diff --git a/src/crystal/system/wasm/getentropy.cr b/src/crystal/system/wasm/getentropy.cr deleted file mode 100644 index a89741a5421b..000000000000 --- a/src/crystal/system/wasm/getentropy.cr +++ /dev/null @@ -1,72 +0,0 @@ -require "c/unistd" - -lib LibC - fun getentropy(buffer : Void*, len : SizeT) : Int -end - -module Crystal::System::Random - @@initialized = false - @@getentropy_available = false - @@urandom : ::File? - - private def self.init - @@initialized = true - - if LibC.getentropy(Bytes.new(16), 16) >= 0 - @@getentropy_available = true - else - urandom = ::File.open("/dev/urandom", "r") - return unless urandom.info.type.character_device? - - urandom.close_on_exec = true - urandom.sync = true # don't buffer bytes - @@urandom = urandom - end - end - - # Reads n random bytes using the Linux `getentropy(2)` syscall. - def self.random_bytes(buf : Bytes) : Nil - init unless @@initialized - - if @@getentropy_available - getentropy(buf) - elsif urandom = @@urandom - urandom.read_fully(buf) - else - raise "Failed to access secure source to generate random bytes!" - end - end - - def self.next_u : UInt8 - init unless @@initialized - - if @@getentropy_available - buf = uninitialized UInt8[1] - getentropy(buf.to_slice) - buf.unsafe_as(UInt8) - elsif urandom = @@urandom - urandom.read_byte.not_nil! - else - raise "Failed to access secure source to generate random bytes!" - end - end - - # Reads n random bytes using the Linux `getentropy(2)` syscall. - private def self.getentropy(buf) - # getentropy(2) may only read up to 256 bytes at once without being - # interrupted or returning early - chunk_size = 256 - - while buf.size > 0 - if buf.size < chunk_size - chunk_size = buf.size - end - - ret = LibC.getentropy(buf, chunk_size) - - raise RuntimeError.from_errno("getentropy") if ret == -1 - - buf += chunk_size - end - end -end From b0797c108bb6d9edd46c8e2594755a5ca1787cfa Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Mon, 2 Aug 2021 08:51:27 -0400 Subject: [PATCH 12/41] Remove Signal, Process and Sockets unimplemented method from Wasm32 --- spec/std/process_spec.cr | 2 + spec/std/signal_spec.cr | 2 + spec/std/socket/addrinfo_spec.cr | 4 +- spec/std/socket/tcp_server_spec.cr | 2 + spec/std/socket/tcp_socket_spec.cr | 2 + src/compiler/crystal/codegen/target.cr | 4 - src/compiler/crystal/command.cr | 2 +- src/crystal/system/file.cr | 4 +- src/crystal/system/socket.cr | 4 +- src/crystal/system/wasm/file.cr | 40 ++++ src/crystal/system/wasm/file_descriptor.cr | 10 +- src/crystal/system/wasm/socket.cr | 202 +++++++++++++++++++++ src/exception/call_stack.cr | 4 +- src/exception/call_stack/elf.cr | 4 +- src/io/file_descriptor.cr | 2 +- src/llvm/abi/wasm32.cr | 50 ++--- src/llvm/target_machine.cr | 2 +- src/prelude.cr | 2 +- src/process/status.cr | 7 + src/raise.cr | 4 +- src/socket.cr | 126 +++++++++---- src/socket/address.cr | 46 +++-- src/socket/addrinfo.cr | 84 +++++---- src/socket/common.cr | 13 +- src/socket/unix_socket.cr | 20 +- src/spec.cr | 2 +- 26 files changed, 487 insertions(+), 157 deletions(-) create mode 100644 src/crystal/system/wasm/file.cr create mode 100644 src/crystal/system/wasm/socket.cr diff --git a/spec/std/process_spec.cr b/spec/std/process_spec.cr index 4cda37bab562..5a18bf9f1b6b 100644 --- a/spec/std/process_spec.cr +++ b/spec/std/process_spec.cr @@ -1,3 +1,5 @@ +{% skip_file if flag?(:wasm32) %} + require "spec" require "process" require "./spec_helper" diff --git a/spec/std/signal_spec.cr b/spec/std/signal_spec.cr index c98b4a706bea..e70278aedb3e 100644 --- a/spec/std/signal_spec.cr +++ b/spec/std/signal_spec.cr @@ -1,3 +1,5 @@ +{% skip_file if flag?(:wasm32) %} + require "spec" require "signal" diff --git a/spec/std/socket/addrinfo_spec.cr b/spec/std/socket/addrinfo_spec.cr index b197e50679ac..b2ae4b745ca6 100644 --- a/spec/std/socket/addrinfo_spec.cr +++ b/spec/std/socket/addrinfo_spec.cr @@ -74,8 +74,8 @@ describe Socket::Addrinfo do end describe "Error" do - {% unless flag?(:win32) %} - # This method is not available on windows because windows support was introduced after deprecation. + {% unless flag?(:win32) || flag?(:wasm32) %} + # This method is not available on windows/wasm because windows/wasm support was introduced after deprecation. it ".new (deprecated)" do error = Socket::Addrinfo::Error.new(LibC::EAI_NONAME, "No address found", "foobar.com") error.os_error.should eq Errno.new(LibC::EAI_NONAME) diff --git a/spec/std/socket/tcp_server_spec.cr b/spec/std/socket/tcp_server_spec.cr index fe38253890af..a0859acff04d 100644 --- a/spec/std/socket/tcp_server_spec.cr +++ b/spec/std/socket/tcp_server_spec.cr @@ -1,3 +1,5 @@ +{% skip_file if flag?(:wasm32) %} + require "./spec_helper" describe TCPServer do diff --git a/spec/std/socket/tcp_socket_spec.cr b/spec/std/socket/tcp_socket_spec.cr index 8b77c8afb90c..4d4fc5cecb32 100644 --- a/spec/std/socket/tcp_socket_spec.cr +++ b/spec/std/socket/tcp_socket_spec.cr @@ -1,3 +1,5 @@ +{% skip_file if flag?(:wasm32) %} + require "./spec_helper" describe TCPSocket do diff --git a/src/compiler/crystal/codegen/target.cr b/src/compiler/crystal/codegen/target.cr index bc73199c68c8..df0f739e192b 100644 --- a/src/compiler/crystal/codegen/target.cr +++ b/src/compiler/crystal/codegen/target.cr @@ -96,10 +96,6 @@ class Crystal::Codegen::Target @environment.starts_with?("linux") end - def wasm? - @architecture.starts_with?("wasm") - end - def bsd? freebsd? || netbsd? || openbsd? || dragonfly? end diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr index 7f73093bccad..5612a0098f66 100644 --- a/src/compiler/crystal/command.cr +++ b/src/compiler/crystal/command.cr @@ -237,7 +237,7 @@ class Crystal::Command begin elapsed = Time.measure do Process.run(output_filename, args: run_args, input: Process::Redirect::Inherit, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit) do |process| - {% unless flag?(:win32) %} + {% unless flag?(:win32) || flag?(:wasm32) %} # Ignore the signal so we don't exit the running process # (the running process can still handle this signal) ::Signal::INT.ignore # do diff --git a/src/crystal/system/file.cr b/src/crystal/system/file.cr index 44fe83667f6b..43d0777955a2 100644 --- a/src/crystal/system/file.cr +++ b/src/crystal/system/file.cr @@ -49,10 +49,12 @@ module Crystal::System::File # def file_descriptor_close end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/file" {% elsif flag?(:win32) %} require "./win32/file" +{% elsif flag?(:wasm32) %} + require "./wasm/file" {% else %} {% raise "No Crystal::System::File implementation available" %} {% end %} diff --git a/src/crystal/system/socket.cr b/src/crystal/system/socket.cr index e1e091199739..efc7ba4c0d5d 100644 --- a/src/crystal/system/socket.cr +++ b/src/crystal/system/socket.cr @@ -76,8 +76,10 @@ module Crystal::System::Socket # private def system_tcp_keepalive_count=(val : Int) end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/socket" +{% elsif flag?(:wasm32) %} + require "./wasm/socket" {% else %} {% raise "No Crystal::System::Socket implementation available" %} {% end %} diff --git a/src/crystal/system/wasm/file.cr b/src/crystal/system/wasm/file.cr new file mode 100644 index 000000000000..c3c77dae2714 --- /dev/null +++ b/src/crystal/system/wasm/file.cr @@ -0,0 +1,40 @@ +require "../unix/file" + +# :nodoc: +module Crystal::System::File + def self.chmod(path, mode) + raise NotImplementedError.new "Crystal::System::File.chmod" + end + + def self.chown(path, uid : Int, gid : Int, follow_symlinks) + raise NotImplementedError.new "Crystal::System::File.chown" + end + + def self.real_path(path) + raise NotImplementedError.new "Crystal::System::File.real_path" + end + + def self.utime(atime : ::Time, mtime : ::Time, filename : String) : Nil + raise NotImplementedError.new "Crystal::System::File.utime" + end + + private def system_flock_shared(blocking) + raise NotImplementedError.new "Crystal::System::File#system_flock_shared" + end + + private def system_flock_exclusive(blocking) + raise NotImplementedError.new "Crystal::System::File#system_flock_exclusive" + end + + private def system_flock_unlock + raise NotImplementedError.new "Crystal::System::File#system_flock_unlock" + end + + private def flock(op : LibC::FlockOp, blocking : Bool = true) + raise NotImplementedError.new "Crystal::System::File#flock" + end + + def self.mktemp(prefix, suffix, dir) : {LibC::Int, String} + raise NotImplementedError.new "Crystal::System::File.mktemp" + end +end diff --git a/src/crystal/system/wasm/file_descriptor.cr b/src/crystal/system/wasm/file_descriptor.cr index 162db532aa1e..5bf5582433c5 100644 --- a/src/crystal/system/wasm/file_descriptor.cr +++ b/src/crystal/system/wasm/file_descriptor.cr @@ -3,6 +3,14 @@ require "../unix/file_descriptor" # :nodoc: module Crystal::System::FileDescriptor def self.from_stdio(fd) - return IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) + IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) + end + + def self.pipe(read_blocking, write_blocking) + raise NotImplementedError.new "Crystal::System::FileDescriptor.pipe" + end + + private def system_reopen(other : IO::FileDescriptor) + raise NotImplementedError.new "Crystal::System::FileDescriptor.system_reopen" end end diff --git a/src/crystal/system/wasm/socket.cr b/src/crystal/system/wasm/socket.cr new file mode 100644 index 000000000000..9b03dd8dd5ad --- /dev/null +++ b/src/crystal/system/wasm/socket.cr @@ -0,0 +1,202 @@ +require "c/netdb" +require "c/netinet/tcp" +require "c/sys/socket" +require "io/evented" + +module Crystal::System::Socket + include IO::Evented + + alias Handle = Int32 + + private def create_handle(family, type, protocol, blocking) : Handle + raise NotImplementedError.new "Crystal::System::Socket#create_handle" + end + + private def initialize_handle(fd) + {% unless LibC.has_constant?(:SOCK_CLOEXEC) %} + # Forces opened sockets to be closed on `exec(2)`. Only for platforms that don't + # support `SOCK_CLOEXEC` (e.g., Darwin). + LibC.fcntl(fd, LibC::F_SETFD, LibC::FD_CLOEXEC) + {% end %} + end + + private def system_connect(addr, timeout = nil, &) + raise NotImplementedError.new "Crystal::System::Socket#system_connect" + end + + # Tries to bind the socket to a local address. + # Yields an `Socket::BindError` if the binding failed. + private def system_bind(addr, addrstr, &) + raise NotImplementedError.new "Crystal::System::Socket#system_bind" + end + + private def system_listen(backlog, &) + raise NotImplementedError.new "Crystal::System::Socket#system_listen" + end + + private def system_accept + raise NotImplementedError.new "Crystal::System::Socket#system_accept" + end + + private def system_send(bytes : Bytes) : Int32 + evented_send(bytes, "Error sending datagram") do |slice| + LibC.send(fd, slice.to_unsafe.as(Void*), slice.size, 0) + end + end + + private def system_send_to(bytes : Bytes, addr : ::Socket::Address) + raise NotImplementedError.new "Crystal::System::Socket#system_send_to" + end + + private def system_receive(bytes) + raise NotImplementedError.new "Crystal::System::Socket#system_receive" + end + + private def system_close_read + if LibC.shutdown(fd, LibC::SHUT_RD) != 0 + raise ::Socket::Error.from_errno("shutdown read") + end + end + + private def system_close_write + if LibC.shutdown(fd, LibC::SHUT_WR) != 0 + raise ::Socket::Error.from_errno("shutdown write") + end + end + + private def system_reuse_port? + raise NotImplementedError.new "Crystal::System::Socket#system_reuse_port?" + end + + private def system_reuse_port=(val : Bool) + raise NotImplementedError.new "Crystal::System::Socket#system_reuse_port=" + end + + private def system_linger + v = LibC::Linger.new + ret = getsockopt LibC::SO_LINGER, v + ret.l_onoff == 0 ? nil : ret.l_linger + end + + private def system_linger=(val) + v = LibC::Linger.new + case val + when Int + v.l_onoff = 1 + v.l_linger = val + when nil + v.l_onoff = 0 + end + + setsockopt LibC::SO_LINGER, v + val + end + + private def system_getsockopt(fd, optname, optval, level = LibC::SOL_SOCKET, &) + raise NotImplementedError.new "Crystal::System::Socket#system_getsockopt" + end + + private def system_setsockopt(fd, optname, optval, level = LibC::SOL_SOCKET) + raise NotImplementedError.new "Crystal::System::Socket#system_setsockopt" + end + + private def system_blocking? + fcntl(LibC::F_GETFL) & LibC::O_NONBLOCK == 0 + end + + private def system_blocking=(value) + flags = fcntl(LibC::F_GETFL) + if value + flags &= ~LibC::O_NONBLOCK + else + flags |= LibC::O_NONBLOCK + end + fcntl(LibC::F_SETFL, flags) + end + + private def system_close_on_exec? + flags = fcntl(LibC::F_GETFD) + (flags & LibC::FD_CLOEXEC) == LibC::FD_CLOEXEC + end + + private def system_close_on_exec=(arg : Bool) + fcntl(LibC::F_SETFD, arg ? LibC::FD_CLOEXEC : 0) + arg + end + + def self.fcntl(fd, cmd, arg = 0) + r = LibC.fcntl fd, cmd, arg + raise ::Socket::Error.from_errno("fcntl() failed") if r == -1 + r + end + + private def system_tty? + LibC.isatty(fd) == 1 + end + + private def unbuffered_read(slice : Bytes) + evented_read(slice, "Error reading socket") do + LibC.recv(fd, slice, slice.size, 0).to_i32 + end + end + + private def unbuffered_write(slice : Bytes) + evented_write(slice, "Error writing to socket") do |slice| + LibC.send(fd, slice, slice.size, 0) + end + end + + private def system_close + # Perform libevent cleanup before LibC.close. + # Using a file descriptor after it has been closed is never defined and can + # always lead to undefined results. This is not specific to libevent. + evented_close + + # Clear the @volatile_fd before actually closing it in order to + # reduce the chance of reading an outdated fd value + fd = @volatile_fd.swap(-1) + + ret = LibC.close(fd) + + if ret != 0 + case Errno.value + when Errno::EINTR, Errno::EINPROGRESS + # ignore + else + raise ::Socket::Error.from_errno("Error closing socket") + end + end + end + + private def system_local_address + raise NotImplementedError.new "Crystal::System::Socket#system_local_address" + end + + private def system_remote_address + raise NotImplementedError.new "Crystal::System::Socket#system_remote_address" + end + + private def system_tcp_keepalive_idle + raise NotImplementedError.new("Crystal::System::Socket#system_tcp_keepalive_idle") + end + + private def system_tcp_keepalive_idle=(val : Int) + raise NotImplementedError.new("Crystal::System::Socket#system_tcp_keepalive_idle=") + end + + private def system_tcp_keepalive_interval + raise NotImplementedError.new("Crystal::System::Socket#system_tcp_keepalive_interval") + end + + private def system_tcp_keepalive_interval=(val : Int) + raise NotImplementedError.new("Crystal::System::Socket#system_tcp_keepalive_interval=") + end + + private def system_tcp_keepalive_count + raise NotImplementedError.new("Crystal::System::Socket#system_tcp_keepalive_count") + end + + private def system_tcp_keepalive_count=(val : Int) + raise NotImplementedError.new("Crystal::System::Socket#system_tcp_keepalive_count=") + end +end diff --git a/src/exception/call_stack.cr b/src/exception/call_stack.cr index 312ea26a8d59..17562dd5d198 100644 --- a/src/exception/call_stack.cr +++ b/src/exception/call_stack.cr @@ -1,6 +1,8 @@ {% skip_file if flag?(:win32) %} -require "c/dlfcn" +{% unless flag?(:wasm32) %} + require "c/dlfcn" +{% end %} require "c/stdio" require "c/string" require "./lib_unwind" diff --git a/src/exception/call_stack/elf.cr b/src/exception/call_stack/elf.cr index b83dc8dc13a2..a6e0df6f0b3d 100644 --- a/src/exception/call_stack/elf.cr +++ b/src/exception/call_stack/elf.cr @@ -1,5 +1,7 @@ require "crystal/elf" -require "c/link" +{% unless flag?(:wasm32) %} + require "c/link" +{% end %} struct Exception::CallStack protected def self.load_dwarf_impl diff --git a/src/io/file_descriptor.cr b/src/io/file_descriptor.cr index 240bfab1084f..74b870ce75d6 100644 --- a/src/io/file_descriptor.cr +++ b/src/io/file_descriptor.cr @@ -25,7 +25,7 @@ class IO::FileDescriptor < IO end end - unless blocking || {{flag?(:win32)}} + unless blocking || {{ flag?(:win32) || flag?(:wasm32) }} self.blocking = false end end diff --git a/src/llvm/abi/wasm32.cr b/src/llvm/abi/wasm32.cr index 2a3d3ca43874..1882a44c8c4a 100644 --- a/src/llvm/abi/wasm32.cr +++ b/src/llvm/abi/wasm32.cr @@ -1,23 +1,23 @@ require "../abi" -class LLVM::ABI::WebAssembly32 < LLVM::ABI - def abi_info(atys : Array(Type), rty : Type, ret_def : Bool, context : Context) : LLVM::ABI::FunctionType +class LLVM::ABI::Wasm32 < LLVM::ABI + def abi_info(atys : Array(Type), rty : Type, ret_def : Bool, context : Context) ret_ty = compute_return_type(rty, ret_def, context) arg_tys = compute_arg_types(atys, context) FunctionType.new(arg_tys, ret_ty) end - def align(type : Type) : Int32 - align(type, 4) + def align(type : Type) + target_data.abi_alignment(type).to_i32 end - def size(type : Type) : Int32 - size(type, 4) + def size(type : Type) + target_data.abi_size(type).to_i32 end - def register?(type) : Bool + private def aggregate?(type) case type.kind - when Type::Kind::Integer, Type::Kind::Float, Type::Kind::Double, Type::Kind::Pointer + when .struct?, .array? true else false @@ -25,40 +25,20 @@ class LLVM::ABI::WebAssembly32 < LLVM::ABI end private def compute_return_type(rty, ret_def, context) - if !ret_def - ArgType.direct(context.void) - elsif register?(rty) - non_struct(rty, context) + if aggregate?(rty) + ArgType.indirect(rty, LLVM::Attribute::ByVal) else - case size(rty) - when 1 - ArgType.direct(rty, context.int8) - when 2 - ArgType.direct(rty, context.int16) - when 3, 4 - ArgType.direct(rty, context.int32) - else - ArgType.indirect(rty, LLVM::Attribute::StructRet) - end + ArgType.direct(rty) end end private def compute_arg_types(atys, context) - atys.map do |aty| - if register?(aty) - non_struct(aty, context) + atys.map do |t| + if aggregate?(t) + ArgType.indirect(t, LLVM::Attribute::ByVal) else - if align(aty) <= 4 - ArgType.direct(aty, context.int32.array(((size(aty) + 3) // 4).to_u64)) - else - ArgType.direct(aty, context.int64.array(((size(aty) + 7) // 8).to_u64)) - end + ArgType.direct(t) end end end - - private def non_struct(type, context) - attr = type == context.int1 ? LLVM::Attribute::ZExt : nil - ArgType.direct(type, attr: attr) - end end diff --git a/src/llvm/target_machine.cr b/src/llvm/target_machine.cr index d01cf1e00be4..1b9dbf685921 100644 --- a/src/llvm/target_machine.cr +++ b/src/llvm/target_machine.cr @@ -58,7 +58,7 @@ class LLVM::TargetMachine when /arm/ ABI::ARM.new(self) when /wasm32/ - ABI::WebAssembly32.new(self) + ABI::Wasm32.new(self) else raise "Unsupported ABI for target triple: #{triple}" end diff --git a/src/prelude.cr b/src/prelude.cr index f391f0386ac2..fd21dad87aa3 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -70,7 +70,7 @@ require "range" require "reference" require "regex" require "set" -{% unless flag?(:win32) %} +{% unless flag?(:win32) || flag?(:wasm32) %} require "signal" {% end %} require "slice" diff --git a/src/process/status.cr b/src/process/status.cr index 53c74006a1db..56da75515688 100644 --- a/src/process/status.cr +++ b/src/process/status.cr @@ -48,6 +48,13 @@ class Process::Status {% end %} end + {% if flag?(:wasm32) %} + # wasm32 does not define `Signal` + def exit_signal + raise NotImplementedError.new("Process::Status#exit_signal") + end + {% end %} + # If `normal_exit?` is `true`, returns the exit code of the process. def exit_code : Int32 {% if flag?(:unix) %} diff --git a/src/raise.cr b/src/raise.cr index 2cca702862a0..714c8e16c5da 100644 --- a/src/raise.cr +++ b/src/raise.cr @@ -190,9 +190,7 @@ end end def raise(exception : Exception) : NoReturn - STDERR.puts - STDERR.puts "EXITING: Attempting to raise: " - exception.inspect_with_backtrace(STDERR) + LibC.printf("EXITING: Attempting to raise:\n#{exception.inspect_with_backtrace}") LibC.exit(1) end {% else %} diff --git a/src/socket.cr b/src/socket.cr index 34c520d3b820..b54a0746b7c5 100644 --- a/src/socket.cr +++ b/src/socket.cr @@ -264,55 +264,105 @@ class Socket < IO io << "#<#{self.class}:fd #{fd}>" end - def send_buffer_size : Int32 - getsockopt LibC::SO_SNDBUF, 0 - end + {% if flag?(:wasm32) %} + def send_buffer_size : Int32 + raise NotImplementedError.new "Socket#send_buffer_size" + end - def send_buffer_size=(val : Int32) - setsockopt LibC::SO_SNDBUF, val - val - end + def send_buffer_size=(val : Int32) + raise NotImplementedError.new "Socket#send_buffer_size=" + end - def recv_buffer_size : Int32 - getsockopt LibC::SO_RCVBUF, 0 - end + def recv_buffer_size : Int32 + raise NotImplementedError.new "Socket#recv_buffer_size" + end - def recv_buffer_size=(val : Int32) - setsockopt LibC::SO_RCVBUF, val - val - end + def recv_buffer_size=(val : Int32) + raise NotImplementedError.new "Socket#recv_buffer_size=" + end - def reuse_address? : Bool - getsockopt_bool LibC::SO_REUSEADDR - end + def reuse_address? : Bool + raise NotImplementedError.new "Socket#reuse_address?" + end - def reuse_address=(val : Bool) - setsockopt_bool LibC::SO_REUSEADDR, val - end + def reuse_address=(val : Bool) + raise NotImplementedError.new "Socket#reuse_address=" + end - def reuse_port? : Bool - system_reuse_port? - end + def reuse_port? : Bool + raise NotImplementedError.new "Socket#reuse_port?" + end - def reuse_port=(val : Bool) - self.system_reuse_port = val - end + def reuse_port=(val : Bool) + raise NotImplementedError.new "Socket#reuse_port=" + end - def broadcast? : Bool - getsockopt_bool LibC::SO_BROADCAST - end + def broadcast? : Bool + raise NotImplementedError.new "Socket#broadcast?" + end - def broadcast=(val : Bool) - setsockopt_bool LibC::SO_BROADCAST, val - end + def broadcast=(val : Bool) + raise NotImplementedError.new "Socket#broadcast=" + end - def keepalive? - getsockopt_bool LibC::SO_KEEPALIVE - end + def keepalive? + raise NotImplementedError.new "Socket#keepalive?" + end - def keepalive=(val : Bool) - setsockopt_bool LibC::SO_KEEPALIVE, val - end + def keepalive=(val : Bool) + raise NotImplementedError.new "Socket#keepalive=" + end + {% else %} + def send_buffer_size : Int32 + getsockopt LibC::SO_SNDBUF, 0 + end + + def send_buffer_size=(val : Int32) + setsockopt LibC::SO_SNDBUF, val + val + end + + def recv_buffer_size : Int32 + getsockopt LibC::SO_RCVBUF, 0 + end + + def recv_buffer_size=(val : Int32) + setsockopt LibC::SO_RCVBUF, val + val + end + + def reuse_address? : Bool + getsockopt_bool LibC::SO_REUSEADDR + end + + def reuse_address=(val : Bool) + setsockopt_bool LibC::SO_REUSEADDR, val + end + + def reuse_port? : Bool + system_reuse_port? + end + + def reuse_port=(val : Bool) + self.system_reuse_port = val + end + + def broadcast? : Bool + getsockopt_bool LibC::SO_BROADCAST + end + + def broadcast=(val : Bool) + setsockopt_bool LibC::SO_BROADCAST, val + end + + def keepalive? + getsockopt_bool LibC::SO_KEEPALIVE + end + + def keepalive=(val : Bool) + setsockopt_bool LibC::SO_KEEPALIVE, val + end + {% end %} def linger system_linger diff --git a/src/socket/address.cr b/src/socket/address.cr index 5d89086cd113..2ecfc32de029 100644 --- a/src/socket/address.cr +++ b/src/socket/address.cr @@ -242,8 +242,10 @@ class Socket private def ipv6_addr8(addr : LibC::In6Addr) {% if flag?(:darwin) || flag?(:bsd) %} addr.__u6_addr.__u6_addr8 - {% elsif flag?(:wasm32) || flag?(:linux) && flag?(:musl) %} + {% elsif flag?(:linux) && flag?(:musl) %} addr.__in6_union.__s6_addr + {% elsif flag?(:wasm32) %} + addr.s6_addr {% elsif flag?(:linux) %} addr.__in6_u.__u6_addr8 {% elsif flag?(:win32) %} @@ -329,19 +331,31 @@ class Socket getter path : String # :nodoc: - MAX_PATH_SIZE = LibC::SockaddrUn.new.sun_path.size - 1 + MAX_PATH_SIZE = {% if flag?(:wasm32) %} + 0 + {% else %} + LibC::SockaddrUn.new.sun_path.size - 1 + {% end %} def initialize(@path : String) if @path.bytesize + 1 > MAX_PATH_SIZE raise ArgumentError.new("Path size exceeds the maximum size of #{MAX_PATH_SIZE} bytes") end @family = Family::UNIX - @size = sizeof(LibC::SockaddrUn) + @size = {% if flag?(:wasm32) %} + 1 + {% else %} + sizeof(LibC::SockaddrUn) + {% end %} end # Creates an `UNIXSocket` from the internal OS representation. def self.from(sockaddr : LibC::Sockaddr*, addrlen) : UNIXAddress - new(sockaddr.as(LibC::SockaddrUn*), addrlen.to_i) + {% if flag?(:wasm32) %} + raise NotImplementedError.new "Socket::UnixAddress.from" + {% else %} + new(sockaddr.as(LibC::SockaddrUn*), addrlen.to_i) + {% end %} end # Parses a `Socket::UNIXAddress` from an URI. @@ -383,11 +397,13 @@ class Socket parse URI.parse(uri) end - protected def initialize(sockaddr : LibC::SockaddrUn*, size) - @family = Family::UNIX - @path = String.new(sockaddr.value.sun_path.to_unsafe) - @size = size || sizeof(LibC::SockaddrUn) - end + {% unless flag?(:wasm32) %} + protected def initialize(sockaddr : LibC::SockaddrUn*, size) + @family = Family::UNIX + @path = String.new(sockaddr.value.sun_path.to_unsafe) + @size = size || sizeof(LibC::SockaddrUn) + end + {% end %} def_equals_and_hash path @@ -396,10 +412,14 @@ class Socket end def to_unsafe : LibC::Sockaddr* - sockaddr = Pointer(LibC::SockaddrUn).malloc - sockaddr.value.sun_family = family - sockaddr.value.sun_path.to_unsafe.copy_from(@path.to_unsafe, @path.bytesize + 1) - sockaddr.as(LibC::Sockaddr*) + {% if flag?(:wasm32) %} + raise NotImplementedError.new "Socket::UnixAddress#to_unsafe" + {% else %} + sockaddr = Pointer(LibC::SockaddrUn).malloc + sockaddr.value.sun_family = family + sockaddr.value.sun_path.to_unsafe.copy_from(@path.to_unsafe, @path.bytesize + 1) + sockaddr.as(LibC::Sockaddr*) + {% end %} end end diff --git a/src/socket/addrinfo.cr b/src/socket/addrinfo.cr index 0d91666b8bd4..e82a148c3bb3 100644 --- a/src/socket/addrinfo.cr +++ b/src/socket/addrinfo.cr @@ -124,53 +124,57 @@ class Socket end private def self.getaddrinfo(domain, service, family, type, protocol, timeout) - # RFC 3986 says: - # > When a non-ASCII registered name represents an internationalized domain name - # > intended for resolution via the DNS, the name must be transformed to the IDNA - # > encoding [RFC3490] prior to name lookup. - domain = URI::Punycode.to_ascii domain - - hints = LibC::Addrinfo.new - hints.ai_family = (family || Family::UNSPEC).to_i32 - hints.ai_socktype = type - hints.ai_protocol = protocol - hints.ai_flags = 0 - - if service.is_a?(Int) - hints.ai_flags |= LibC::AI_NUMERICSERV - end - - # On OS X < 10.12, the libsystem implementation of getaddrinfo segfaults - # if AI_NUMERICSERV is set, and servname is NULL or 0. - {% if flag?(:darwin) %} - if (service == 0 || service == nil) && (hints.ai_flags & LibC::AI_NUMERICSERV) + {% if flag?(:wasm32) %} + raise NotImplementedError.new "Socket::Addrinfo.getaddrinfo" + {% else %} + # RFC 3986 says: + # > When a non-ASCII registered name represents an internationalized domain name + # > intended for resolution via the DNS, the name must be transformed to the IDNA + # > encoding [RFC3490] prior to name lookup. + domain = URI::Punycode.to_ascii domain + + hints = LibC::Addrinfo.new + hints.ai_family = (family || Family::UNSPEC).to_i32 + hints.ai_socktype = type + hints.ai_protocol = protocol + hints.ai_flags = 0 + + if service.is_a?(Int) hints.ai_flags |= LibC::AI_NUMERICSERV - service = "00" end - {% end %} - ret = LibC.getaddrinfo(domain, service.to_s, pointerof(hints), out ptr) - unless ret.zero? - {% if flag?(:posix) %} - # EAI_SYSTEM is not defined on win32 - if ret == LibC::EAI_SYSTEM - raise Error.from_errno message, domain: domain + # On OS X < 10.12, the libsystem implementation of getaddrinfo segfaults + # if AI_NUMERICSERV is set, and servname is NULL or 0. + {% if flag?(:darwin) %} + if (service == 0 || service == nil) && (hints.ai_flags & LibC::AI_NUMERICSERV) + hints.ai_flags |= LibC::AI_NUMERICSERV + service = "00" end {% end %} - error = {% if flag?(:win32) %} - WinError.new(ret.to_u32!) - {% else %} - Errno.new(ret) - {% end %} - raise Error.from_os_error(nil, error, domain: domain, type: type, protocol: protocol, service: service) - end + ret = LibC.getaddrinfo(domain, service.to_s, pointerof(hints), out ptr) + unless ret.zero? + {% if flag?(:posix) %} + # EAI_SYSTEM is not defined on win32 + if ret == LibC::EAI_SYSTEM + raise Error.from_errno message, domain: domain + end + {% end %} - begin - yield new(ptr) - ensure - LibC.freeaddrinfo(ptr) - end + error = {% if flag?(:win32) %} + WinError.new(ret.to_u32!) + {% else %} + Errno.new(ret) + {% end %} + raise Error.from_os_error(nil, error, domain: domain, type: type, protocol: protocol, service: service) + end + + begin + yield new(ptr) + ensure + LibC.freeaddrinfo(ptr) + end + {% end %} end # Resolves *domain* for the TCP protocol and returns an `Array` of possible diff --git a/src/socket/common.cr b/src/socket/common.cr index b1fc36e2a870..9602b462709d 100644 --- a/src/socket/common.cr +++ b/src/socket/common.cr @@ -1,6 +1,9 @@ {% if flag?(:win32) %} require "c/ws2tcpip" require "c/afunix" +{% elsif flag?(:wasm32) %} + require "c/arpa/inet" + require "c/netinet/in" {% else %} require "c/arpa/inet" require "c/sys/un" @@ -53,10 +56,12 @@ class Socket end enum Type - STREAM = LibC::SOCK_STREAM - DGRAM = LibC::SOCK_DGRAM - RAW = LibC::SOCK_RAW - SEQPACKET = LibC::SOCK_SEQPACKET + STREAM = LibC::SOCK_STREAM + DGRAM = LibC::SOCK_DGRAM + {% unless flag?(:wasm32) %} + RAW = LibC::SOCK_RAW + SEQPACKET = LibC::SOCK_SEQPACKET + {% end %} end class Error < IO::Error diff --git a/src/socket/unix_socket.cr b/src/socket/unix_socket.cr index 9ec3a8188ef6..4efbd1c1c4bd 100644 --- a/src/socket/unix_socket.cr +++ b/src/socket/unix_socket.cr @@ -63,18 +63,22 @@ class UNIXSocket < Socket # left.gets # => "message" # ``` def self.pair(type : Type = Type::STREAM) : {UNIXSocket, UNIXSocket} - fds = uninitialized Int32[2] + {% if flag?(:wasm32) %} + raise NotImplementedError.new "UNIXSocket.pair" + {% else %} + fds = uninitialized Int32[2] - socktype = type.value - {% if LibC.has_constant?(:SOCK_CLOEXEC) %} + socktype = type.value + {% if LibC.has_constant?(:SOCK_CLOEXEC) %} socktype |= LibC::SOCK_CLOEXEC - {% end %} + {% end %} - if LibC.socketpair(Family::UNIX, socktype, 0, fds) != 0 - raise Socket::Error.new("socketpair:") - end + if LibC.socketpair(Family::UNIX, socktype, 0, fds) != 0 + raise Socket::Error.new("socketpair:") + end - {UNIXSocket.new(fd: fds[0], type: type), UNIXSocket.new(fd: fds[1], type: type)} + {UNIXSocket.new(fd: fds[0], type: type), UNIXSocket.new(fd: fds[1], type: type)} + {% end %} end # Creates a pair of unnamed UNIX sockets (see `pair`) and yields them to the diff --git a/src/spec.cr b/src/spec.cr index 517acc720a58..5d370e71811a 100644 --- a/src/spec.cr +++ b/src/spec.cr @@ -127,7 +127,7 @@ end Spec.add_split_filter ENV["SPEC_SPLIT"]? -{% unless flag?(:win32) %} +{% unless flag?(:win32) || flag?(:wasm32) %} # TODO(windows): re-enable this once Signal is ported Signal::INT.trap { Spec.abort! } {% end %} From aec74adbe4d42946c99eff6d3b148af6db97b8f2 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Mon, 2 Aug 2021 08:51:56 -0400 Subject: [PATCH 13/41] Work around compiler bug in previous commit: BUG: `typeof(_io)` at expanded macro: spawn:6:18 has no type (Exception) --- src/crystal/system/wasm/socket.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystal/system/wasm/socket.cr b/src/crystal/system/wasm/socket.cr index 9b03dd8dd5ad..09bd2379b5a2 100644 --- a/src/crystal/system/wasm/socket.cr +++ b/src/crystal/system/wasm/socket.cr @@ -35,7 +35,7 @@ module Crystal::System::Socket end private def system_accept - raise NotImplementedError.new "Crystal::System::Socket#system_accept" + (raise NotImplementedError.new "Crystal::System::Socket#system_accept").as(Int32) end private def system_send(bytes : Bytes) : Int32 From 463d4cd801093c49c626cd9736d9d8a65f730501 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Mon, 2 Aug 2021 10:27:12 -0400 Subject: [PATCH 14/41] fix: cleanup from previous commit --- src/crystal/system/wasm/file_descriptor.cr | 1 + src/crystal/system/wasm/socket.cr | 5 ----- src/crystal/system/wasm/thread.cr | 2 ++ src/fiber/context/wasm32.cr | 2 ++ src/signal.cr | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/crystal/system/wasm/file_descriptor.cr b/src/crystal/system/wasm/file_descriptor.cr index 5bf5582433c5..7a375e89a136 100644 --- a/src/crystal/system/wasm/file_descriptor.cr +++ b/src/crystal/system/wasm/file_descriptor.cr @@ -3,6 +3,7 @@ require "../unix/file_descriptor" # :nodoc: module Crystal::System::FileDescriptor def self.from_stdio(fd) + # TODO: WASI doesn't offer a way to detect if a 'fd' is a TTY. IO::FileDescriptor.new(fd).tap(&.flush_on_newline=(true)) end diff --git a/src/crystal/system/wasm/socket.cr b/src/crystal/system/wasm/socket.cr index 09bd2379b5a2..b0cdd01ecc77 100644 --- a/src/crystal/system/wasm/socket.cr +++ b/src/crystal/system/wasm/socket.cr @@ -13,11 +13,6 @@ module Crystal::System::Socket end private def initialize_handle(fd) - {% unless LibC.has_constant?(:SOCK_CLOEXEC) %} - # Forces opened sockets to be closed on `exec(2)`. Only for platforms that don't - # support `SOCK_CLOEXEC` (e.g., Darwin). - LibC.fcntl(fd, LibC::F_SETFD, LibC::FD_CLOEXEC) - {% end %} end private def system_connect(addr, timeout = nil, &) diff --git a/src/crystal/system/wasm/thread.cr b/src/crystal/system/wasm/thread.cr index 1b81dd853ddd..2a9cf27502f5 100644 --- a/src/crystal/system/wasm/thread.cr +++ b/src/crystal/system/wasm/thread.cr @@ -20,6 +20,8 @@ class Thread def initialize @main_fiber = Fiber.new(stack_address, self) @@threads.push(self) + + # TODO: Create thread end def initialize(&@func : ->) diff --git a/src/fiber/context/wasm32.cr b/src/fiber/context/wasm32.cr index 6c9102079e0d..0d8372d3e325 100644 --- a/src/fiber/context/wasm32.cr +++ b/src/fiber/context/wasm32.cr @@ -3,11 +3,13 @@ class Fiber # :nodoc: def makecontext(stack_ptr, fiber_main) + # TODO: Implement this using Binaryen Asyncify end # :nodoc: @[NoInline] @[Naked] def self.swapcontext(current_context, new_context) : Nil + # TODO: Implement this using Binaryen Asyncify end end diff --git a/src/signal.cr b/src/signal.cr index 4dda9c328f97..d1352f1f9f0d 100644 --- a/src/signal.cr +++ b/src/signal.cr @@ -191,7 +191,7 @@ module Crystal::Signal alias Handler = ::Signal -> - private class_getter(pipe) { IO.pipe(read_blocking: false, write_blocking: true) } + @@pipe = IO.pipe(read_blocking: false, write_blocking: true) @@handlers = {} of ::Signal => Handler @@child_handler : Handler? @@mutex = Mutex.new(:unchecked) @@ -267,7 +267,7 @@ module Crystal::Signal # Replaces the signal pipe so the child process won't share the file # descriptors of the parent process and send it received signals. def self.after_fork - pipe.each(&.file_descriptor_close) + @@pipe.each(&.file_descriptor_close) ensure @@pipe = IO.pipe(read_blocking: false, write_blocking: true) end @@ -290,16 +290,16 @@ module Crystal::Signal end ensure {% unless flag?(:preview_mt) %} - pipe.each(&.file_descriptor_close) + @@pipe.each(&.file_descriptor_close) {% end %} end private def self.reader - pipe[0] + @@pipe[0] end private def self.writer - pipe[1] + @@pipe[1] end private def self.fatal(message : String) From b1dd5f7de7e9e7bc34ceb4ac4fbd6dd01db8e051 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 3 Aug 2021 13:44:22 -0400 Subject: [PATCH 15/41] crystal tool format --- src/lib_c/wasm32-wasi/c/sys/stat.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib_c/wasm32-wasi/c/sys/stat.cr b/src/lib_c/wasm32-wasi/c/sys/stat.cr index 6622b793198c..5b40bb7850bd 100644 --- a/src/lib_c/wasm32-wasi/c/sys/stat.cr +++ b/src/lib_c/wasm32-wasi/c/sys/stat.cr @@ -2,8 +2,8 @@ require "./types" require "../time" lib LibC - S_IFMT = S_IFBLK | S_IFCHR | S_IFDIR | S_IFIFO | S_IFLNK | S_IFREG | S_IFSOCK - S_IFBLK = 0x6000 + S_IFMT = S_IFBLK | S_IFCHR | S_IFDIR | S_IFIFO | S_IFLNK | S_IFREG | S_IFSOCK + S_IFBLK = 0x6000 S_IFCHR = 0x2000 S_IFIFO = 0xc000 S_IFREG = 0x8000 From 00b10d6a575405635f5b30668c829b66a12bdb9c Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Sat, 18 Dec 2021 11:22:20 +0000 Subject: [PATCH 16/41] fix: use correct .wasm extension --- src/compiler/crystal/codegen/link.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/crystal/codegen/link.cr b/src/compiler/crystal/codegen/link.cr index 86f021a4247b..a738c80f11e4 100644 --- a/src/compiler/crystal/codegen/link.cr +++ b/src/compiler/crystal/codegen/link.cr @@ -92,7 +92,7 @@ module Crystal class Program def object_extension - has_flag?("windows") ? ".obj" : ".o" + has_flag?("windows") ? ".obj" : has_flag?("wasm32") ? ".wasm" : ".o" end def lib_flags From e86b675311304ba6a31c919c9f7c26adf62e3df2 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 23 Dec 2021 19:42:24 +0000 Subject: [PATCH 17/41] feat: implement Crystal::System::Fiber with malloc/free --- src/crystal/system/wasm/fiber.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crystal/system/wasm/fiber.cr b/src/crystal/system/wasm/fiber.cr index 0db8324b403d..894b0793ada7 100644 --- a/src/crystal/system/wasm/fiber.cr +++ b/src/crystal/system/wasm/fiber.cr @@ -2,10 +2,10 @@ require "c/sys/mman" module Crystal::System::Fiber def self.allocate_stack(stack_size) : Void* - raise NotImplementedError.new("Crystal::System::Fiber.allocate_stack") + LibC.malloc(stack_size) end def self.free_stack(stack : Void*, stack_size) : Nil - raise NotImplementedError.new("Crystal::System::Fiber.free_stack") + LibC.free(stack) end end From ba5a53147fe749c0c985c1437a347dcfbd50a5b1 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Fri, 24 Dec 2021 16:11:09 -0300 Subject: [PATCH 18/41] fix: mark system_linger as not implemented --- src/crystal/system/wasm/socket.cr | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/crystal/system/wasm/socket.cr b/src/crystal/system/wasm/socket.cr index b0cdd01ecc77..974613b847c4 100644 --- a/src/crystal/system/wasm/socket.cr +++ b/src/crystal/system/wasm/socket.cr @@ -68,23 +68,11 @@ module Crystal::System::Socket end private def system_linger - v = LibC::Linger.new - ret = getsockopt LibC::SO_LINGER, v - ret.l_onoff == 0 ? nil : ret.l_linger + raise NotImplementedError.new "Crystal::System::Socket#system_linger" end private def system_linger=(val) - v = LibC::Linger.new - case val - when Int - v.l_onoff = 1 - v.l_linger = val - when nil - v.l_onoff = 0 - end - - setsockopt LibC::SO_LINGER, v - val + raise NotImplementedError.new "Crystal::System::Socket#system_linge=" end private def system_getsockopt(fd, optname, optval, level = LibC::SOL_SOCKET, &) From 25828170cfcfafc30bcc14fcace5f4773632eed3 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Fri, 24 Dec 2021 16:13:47 -0300 Subject: [PATCH 19/41] feat: add direct wasi integration for Dir.entries --- src/crystal/system/dir.cr | 4 +- src/crystal/system/wasm/dir.cr | 105 ++++++++++++ src/crystal/system/wasm/lib_wasi.cr | 101 +++++++++++ src/crystal/system/wasm/wasi.cr | 54 ++++++ src/lib_c/wasm32-wasi/c/dirent.cr | 22 --- src/prelude.cr | 4 + src/system_error.cr | 6 +- src/wasierror.cr | 249 ++++++++++++++++++++++++++++ 8 files changed, 519 insertions(+), 26 deletions(-) create mode 100644 src/crystal/system/wasm/dir.cr create mode 100644 src/crystal/system/wasm/lib_wasi.cr create mode 100644 src/crystal/system/wasm/wasi.cr delete mode 100644 src/lib_c/wasm32-wasi/c/dirent.cr create mode 100644 src/wasierror.cr diff --git a/src/crystal/system/dir.cr b/src/crystal/system/dir.cr index 7354aecfa616..cbf5ee4cb621 100644 --- a/src/crystal/system/dir.cr +++ b/src/crystal/system/dir.cr @@ -51,8 +51,10 @@ module Crystal::System::Dir # def self.delete(path : String) : Nil end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/dir" +{% elsif flag?(:wasm32) %} + require "./wasm/dir" {% elsif flag?(:win32) %} require "./win32/dir" {% else %} diff --git a/src/crystal/system/wasm/dir.cr b/src/crystal/system/wasm/dir.cr new file mode 100644 index 000000000000..df564efe8964 --- /dev/null +++ b/src/crystal/system/wasm/dir.cr @@ -0,0 +1,105 @@ +module Crystal::System::Dir + private class DirHandle + property fd : LibWasi::Fd + property buf = Bytes.new(4096) + property pos = 4096u32 + property end_pos = 4096u32 + property cookie = 0u64 + + def initialize(@fd) + end + + def fill_buffer(path) + err = LibWasi.fd_readdir(@fd, @buf, @buf.size, @cookie, pointerof(@end_pos)) + raise ::File::Error.from_os_error("Error reading directory entries", err, file: path) unless err.success? + @pos = 0 + end + end + + def self.open(path : String) : DirHandle + parent_fd, relative_path = Wasi.find_path_preopen(path) + + fd = uninitialized LibWasi::Fd + err = LibWasi.path_open(parent_fd, LibWasi::LookupFlags::SymlinkFollow, relative_path, LibWasi::OpenFlags::Directory, LibWasi::Rights::FdReaddir, LibWasi::Rights::None, LibWasi::FdFlags::None, pointerof(fd)) + raise ::File::Error.from_os_error("Error opening directory", err, file: path) unless err.success? + + DirHandle.new(fd) + end + + def self.next_entry(dir, path) : Entry? + if dir.end_pos < dir.buf.size && dir.pos >= dir.end_pos + return nil + end + + if dir.pos + sizeof(LibWasi::DirEnt) > dir.buf.size + dir.fill_buffer(path) + end + + dirent = Pointer(LibWasi::DirEnt).new(dir.buf.to_unsafe.address + dir.pos).value + + if dir.pos + sizeof(LibWasi::DirEnt) + dirent.d_namlen > dir.buf.size + if dir.pos == 0 + dir.buf = Bytes.new(dir.buf.size * 2) + end + dir.fill_buffer(path) + return next_entry(dir, path) + end + + name = String.new(dir.buf[dir.pos + sizeof(LibWasi::DirEnt), dirent.d_namlen]) + dir.pos += sizeof(LibWasi::DirEnt) + dirent.d_namlen + dir.cookie = dirent.d_next + + is_dir = case dirent.d_type + when .directory? then true + when .unknown?, .symbolic_link? then nil + else false + end + + Entry.new(name, is_dir) + end + + def self.rewind(dir) : Nil + dir.cookie = 0 + dir.end_pos = dir.pos = dir.buf.size.to_u32 + end + + def self.close(dir, path) : Nil + err = LibWasi.fd_close(dir.fd) + raise ::File::Error.from_os_error("Error opening directory", err, file: path) unless err.success? + end + + def self.current : String + unless dir = LibC.getcwd(nil, 0) + raise ::File::Error.from_errno("Error getting current directory", file: "./") + end + + dir_str = String.new(dir) + LibC.free(dir.as(Void*)) + dir_str + end + + def self.current=(path : String) + if LibC.chdir(path.check_no_null_byte) != 0 + raise ::File::Error.from_errno("Error while changing directory", file: path) + end + + path + end + + def self.tempdir + tmpdir = ENV["TMPDIR"]? || "/tmp" + tmpdir.rchop(::File::SEPARATOR) + end + + def self.create(path : String, mode : Int32) : Nil + if LibC.mkdir(path.check_no_null_byte, mode) == -1 + raise ::File::Error.from_errno("Unable to create directory", file: path) + end + end + + def self.delete(path : String) : Nil + if LibC.rmdir(path.check_no_null_byte) == -1 + raise ::File::Error.from_errno("Unable to remove directory", file: path) + end + end +end diff --git a/src/crystal/system/wasm/lib_wasi.cr b/src/crystal/system/wasm/lib_wasi.cr new file mode 100644 index 000000000000..0117480b695c --- /dev/null +++ b/src/crystal/system/wasm/lib_wasi.cr @@ -0,0 +1,101 @@ +lib LibWasi + alias Fd = Int32 + alias Size = UInt32 + alias FileSize = UInt64 + + struct PrestatDir + pr_name_len : Size + end + + union PrestatUnion + dir : PrestatDir + end + + enum PrestatTag : UInt8 + Dir + end + + struct Prestat + tag : PrestatTag + value : PrestatUnion + end + + @[Flags] + enum LookupFlags : UInt32 + SymlinkFollow + end + + @[Flags] + enum OpenFlags : UInt16 + Creat + Directory + Excl + Trunc + end + + @[Flags] + enum FdFlags : UInt16 + Append # Append mode: Data written to the file is always appended to the file's end. + Dsync # Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. + NonBlock # Non-blocking mode. + RSync # Synchronized read I/O operations. + Sync # Write according to synchronized I/O file integrity completion. In addition to synchronizing the data stored in the file, the implementation may also synchronously update the file's metadata. + end + + @[Flags] + enum Rights : UInt64 + FdDatasync # The right to invoke fd_datasync. If path_open is set, includes the right to invoke path_open with fdflags::dsync. + FdRead # The right to invoke fd_read and sock_recv. If rights::fd_seek is set, includes the right to invoke fd_pread. + FdSeek # The right to invoke fd_seek. This flag implies rights::fd_tell. + FdFdstatSetFlags # The right to invoke fd_fdstat_set_flags. + FdSync # The right to invoke fd_sync. If path_open is set, includes the right to invoke path_open with fdflags::rsync and fdflags::dsync. + FdTell # The right to invoke fd_seek in such a way that the file offset remains unaltered (i.e., whence::cur with offset zero), or to invoke fd_tell. + FdWrite # The right to invoke fd_write and sock_send. If rights::fd_seek is set, includes the right to invoke fd_pwrite. + FdAdvise # The right to invoke fd_advise. + FdAllocate # The right to invoke fd_allocate. + PathCreateDirectory # The right to invoke path_create_directory. + PathCreateFile # If path_open is set, the right to invoke path_open with oflags::creat. + PathLinkSource # The right to invoke path_link with the file descriptor as the source directory. + PathLinkTarget # The right to invoke path_link with the file descriptor as the target directory. + PathOpen # The right to invoke path_open. + FdReaddir # The right to invoke fd_readdir. + PathReadlink # The right to invoke path_readlink. + PathRenameSource # The right to invoke path_rename with the file descriptor as the source directory. + PathRenameTarget # The right to invoke path_rename with the file descriptor as the target directory. + PathFilestatGet # The right to invoke path_filestat_get. + PathFilestatSetSize # The right to change a file's size (there is no path_filestat_set_size). If path_open is set, includes the right to invoke path_open with oflags::trunc. + PathFilestatSetTimes # The right to invoke path_filestat_set_times. + FdFilestatGet # The right to invoke fd_filestat_get. + FdFilestatSetSize # The right to invoke fd_filestat_set_size. + FdFilestatSetTimes # The right to invoke fd_filestat_set_times. + PathSymlink # The right to invoke path_symlink. + PathRemoveDirectory # The right to invoke path_remove_directory. + PathUnlinkFile # The right to invoke path_unlink_file. + PollFdReadwrite # If rights::fd_read is set, includes the right to invoke poll_oneoff to subscribe to eventtype::fd_read. If rights::fd_write is set, includes the right to invoke poll_oneoff to subscribe to eventtype::fd_write. + SockShutdown # The right to invoke sock_shutdown. + end + + enum FileType : UInt8 + Unknown # The type of the file descriptor or file is unknown or is different from any of the other types specified. + BlockDevice # The file descriptor or file refers to a block device inode. + CharacterDevice # The file descriptor or file refers to a character device inode. + Directory # The file descriptor or file refers to a directory inode. + RegularFile # The file descriptor or file refers to a regular file inode. + SocketDgram # The file descriptor or file refers to a datagram socket. + SocketStream # The file descriptor or file refers to a byte-stream socket. + SymbolicLink # The file refers to a symbolic link inode. + end + + struct DirEnt + d_next : UInt64 + d_ino : UInt64 + d_namlen : UInt32 + d_type : FileType + end + + fun fd_prestat_get = __wasi_fd_prestat_get(fd : Fd, stat : Prestat*) : WasiError + fun fd_prestat_dir_name = __wasi_fd_prestat_dir_name(fd : Fd, path : UInt8*, len : Size) : WasiError + fun path_open = __wasi_path_open(fd : Fd, dirflags : LookupFlags, path : UInt8*, oflags : OpenFlags, fs_rights_base : Rights, fs_rights_inheriting : Rights, fdflags : FdFlags, ret : Fd*) : WasiError + fun fd_readdir = __wasi_fd_readdir(fd : Fd, buf : UInt8*, len : Size, cookie : UInt64, ret : Size*) : WasiError + fun fd_close = __wasi_fd_close(fd : Fd) : WasiError +end diff --git a/src/crystal/system/wasm/wasi.cr b/src/crystal/system/wasm/wasi.cr new file mode 100644 index 000000000000..564d27fb5509 --- /dev/null +++ b/src/crystal/system/wasm/wasi.cr @@ -0,0 +1,54 @@ +require "./lib_wasi" + +module Crystal::System::Wasi + PREOPENS = [] of {String, String, LibWasi::Fd} + + def self.init_preopens + # Skip stdin, stdout, and stderr, and count up until we reach an invalid file descriptor. + (3..).each do |fd| + stat = uninitialized LibWasi::Prestat + err = LibWasi.fd_prestat_get(fd, pointerof(stat)) + + break if err.badf? + unless err.success? + raise RuntimeError.from_os_error("fd_prestat_get", err) + end + + next unless stat.tag.dir? + + len = stat.value.dir.pr_name_len + + name = String.new(len + 1) do |buffer| + err = LibWasi.fd_prestat_dir_name(fd, buffer, len) + raise RuntimeError.from_os_error("fd_prestat_dir_name", err) unless err.success? + buffer[len] = 0 + len = LibC.strlen(buffer) + {len, 0} + end + + path = ::Path[name].expand.to_s + PREOPENS << {path, path.ends_with?("/") ? path : path + "/", fd} + end + + # Preopens added later take priority over preopens added earlier. + PREOPENS.reverse! + # Preopens of longer prefix take priority over shorter prefixes. + PREOPENS.sort_by! { |entry| -entry[0].size } + end + + def self.find_path_preopen(path) + path = ::Path[path].expand.to_s + PREOPENS.each do |preopen| + if preopen[0] == path + return {preopen[2], "."} + elsif path.starts_with? preopen[1] + return {preopen[2], path[preopen[1].size..-1]} + end + end + + # If we can't find a preopen for it, indicate that we lack capabilities. + raise RuntimeError.from_os_error(nil, WasiError::NOTCAPABLE) + end +end + +Crystal::System::Wasi.init_preopens diff --git a/src/lib_c/wasm32-wasi/c/dirent.cr b/src/lib_c/wasm32-wasi/c/dirent.cr deleted file mode 100644 index 83836cdd73bb..000000000000 --- a/src/lib_c/wasm32-wasi/c/dirent.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "./sys/types" - -lib LibC - type DIR = Void - - DT_UNKNOWN = 0 - DT_DIR = 3 - DT_LINK = 7 - - struct Dirent - d_ino : InoT - d_off : OffT - d_reclen : UShort - d_type : Char - d_name : StaticArray(Char, 256) - end - - fun closedir(x0 : DIR*) : Int - fun opendir(x0 : Char*) : DIR* - fun readdir(x0 : DIR*) : Dirent* - fun rewinddir(x0 : DIR*) : Void -end diff --git a/src/prelude.cr b/src/prelude.cr index 54983bb05eaf..37b97707f8a1 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -24,6 +24,9 @@ require "indexable" require "string" require "number" require "primitives" +{% if flag?(:wasm32) %} + require "crystal/system/wasm/wasi" +{% end %} # Alpha-sorted list require "annotations" @@ -45,6 +48,7 @@ require "enumerable" require "env" require "errno" require "winerror" +require "wasierror" require "file" require "float" require "gc" diff --git a/src/system_error.cr b/src/system_error.cr index f7e4653cc27a..7d434695b003 100644 --- a/src/system_error.cr +++ b/src/system_error.cr @@ -43,7 +43,7 @@ module SystemError end # The original system error wrapped by this exception - getter os_error : Errno | WinError | Nil + getter os_error : Errno | WinError | WasiError | Nil # :nodoc: protected def os_error=(@os_error) @@ -54,7 +54,7 @@ module SystemError # # The system message corresponding to the OS error value amends the *message*. # Additional keyword arguments are forwarded to the exception initializer `.new_from_os_error`. - def from_os_error(message : String?, os_error : Errno | WinError | Nil, **opts) + def from_os_error(message : String?, os_error : Errno | WinError | WasiError | Nil, **opts) message = self.build_message(message, **opts) message = if message @@ -94,7 +94,7 @@ module SystemError # By default it returns the result of `Errno#message` or `WinError#message`. # This method can be overridden for customization of the error message based # on *or_error* and *\*\*opts*. - protected def os_error_message(os_error : Errno | WinError | Nil, **opts) : String? + protected def os_error_message(os_error : Errno | WinError | WasiError | Nil, **opts) : String? os_error.try &.message end diff --git a/src/wasierror.cr b/src/wasierror.cr new file mode 100644 index 000000000000..9a04ed315463 --- /dev/null +++ b/src/wasierror.cr @@ -0,0 +1,249 @@ +enum WasiError : UInt16 + # Returns the system error message associated with this error code. + def message : String + case self + when SUCCESS then "No error occurred. System call completed successfully." + when TOOBIG then "Argument list too long." + when ACCES then "Permission denied." + when ADDRINUSE then "Address in use." + when ADDRNOTAVAIL then "Address not available." + when AFNOSUPPORT then "Address family not supported." + when AGAIN then "Resource unavailable, or operation would block." + when ALREADY then "Connection already in progress." + when BADF then "Bad file descriptor." + when BADMSG then "Bad message." + when BUSY then "Device or resource busy." + when CANCELED then "Operation canceled." + when CHILD then "No child processes." + when CONNABORTED then "Connection aborted." + when CONNREFUSED then "Connection refused." + when CONNRESET then "Connection reset." + when DEADLK then "Resource deadlock would occur." + when DESTADDRREQ then "Destination address required." + when DOM then "Mathematics argument out of domain of function." + when DQUOT then "Reserved." + when EXIST then "File exists." + when FAULT then "Bad address." + when FBIG then "File too large." + when HOSTUNREACH then "Host is unreachable." + when IDRM then "Identifier removed." + when ILSEQ then "Illegal byte sequence." + when INPROGRESS then "Operation in progress." + when INTR then "Interrupted function." + when INVAL then "Invalid argument." + when IO then "I/O error." + when ISCONN then "Socket is connected." + when ISDIR then "Is a directory." + when LOOP then "Too many levels of symbolic links." + when MFILE then "File descriptor value too large." + when MLINK then "Too many links." + when MSGSIZE then "Message too large." + when MULTIHOP then "Reserved." + when NAMETOOLONG then "Filename too long." + when NETDOWN then "Network is down." + when NETRESET then "Connection aborted by network." + when NETUNREACH then "Network unreachable." + when NFILE then "Too many files open in system." + when NOBUFS then "No buffer space available." + when NODEV then "No such device." + when NOENT then "No such file or directory." + when NOEXEC then "Executable file format error." + when NOLCK then "No locks available." + when NOLINK then "Reserved." + when NOMEM then "Not enough space." + when NOMSG then "No message of the desired type." + when NOPROTOOPT then "Protocol not available." + when NOSPC then "No space left on device." + when NOSYS then "Function not supported." + when NOTCONN then "The socket is not connected." + when NOTDIR then "Not a directory or a symbolic link to a directory." + when NOTEMPTY then "Directory not empty." + when NOTRECOVERABLE then "State not recoverable." + when NOTSOCK then "Not a socket." + when NOTSUP then "Not supported, or operation not supported on socket." + when NOTTY then "Inappropriate I/O control operation." + when NXIO then "No such device or address." + when OVERFLOW then "Value too large to be stored in data type." + when OWNERDEAD then "Previous owner died." + when PERM then "Operation not permitted." + when PIPE then "Broken pipe." + when PROTO then "Protocol error." + when PROTONOSUPPORT then "Protocol not supported." + when PROTOTYPE then "Protocol wrong type for socket." + when RANGE then "Result too large." + when ROFS then "Read-only file system." + when SPIPE then "Invalid seek." + when SRCH then "No such process." + when STALE then "Reserved." + when TIMEDOUT then "Connection timed out." + when TXTBSY then "Text file busy." + when XDEV then "Cross-device link." + when NOTCAPABLE then "Extension: Capabilities insufficient." + else "Unknown error." + end + end + + # Transforms this `WasiError` value to the equivalent `Errno` value. + # + # This is only defined for some values. If no transformation is defined for + # a specific value, the default result is `Errno::EINVAL`. + def to_errno : Errno + case self + when TOOBIG then Errno::E2BIG + when ACCES then Errno::EACCES + when ADDRINUSE then Errno::EADDRINUSE + when ADDRNOTAVAIL then Errno::EADDRNOTAVAIL + when AFNOSUPPORT then Errno::EAFNOSUPPORT + when AGAIN then Errno::EAGAIN + when ALREADY then Errno::EALREADY + when BADF then Errno::EBADF + when BADMSG then Errno::EBADMSG + when BUSY then Errno::EBUSY + when CANCELED then Errno::ECANCELED + when CHILD then Errno::ECHILD + when CONNABORTED then Errno::ECONNABORTED + when CONNREFUSED then Errno::ECONNREFUSED + when CONNRESET then Errno::ECONNRESET + when DEADLK then Errno::EDEADLK + when DESTADDRREQ then Errno::EDESTADDRREQ + when DOM then Errno::EDOM + when DQUOT then Errno::EDQUOT + when EXIST then Errno::EEXIST + when FAULT then Errno::EFAULT + when FBIG then Errno::EFBIG + when HOSTUNREACH then Errno::EHOSTUNREACH + when IDRM then Errno::EIDRM + when ILSEQ then Errno::EILSEQ + when INPROGRESS then Errno::EINPROGRESS + when INTR then Errno::EINTR + when INVAL then Errno::EINVAL + when IO then Errno::EIO + when ISCONN then Errno::EISCONN + when ISDIR then Errno::EISDIR + when LOOP then Errno::ELOOP + when MFILE then Errno::EMFILE + when MLINK then Errno::EMLINK + when MSGSIZE then Errno::EMSGSIZE + when MULTIHOP then Errno::EMULTIHOP + when NAMETOOLONG then Errno::ENAMETOOLONG + when NETDOWN then Errno::ENETDOWN + when NETRESET then Errno::ENETRESET + when NETUNREACH then Errno::ENETUNREACH + when NFILE then Errno::ENFILE + when NOBUFS then Errno::ENOBUFS + when NODEV then Errno::ENODEV + when NOENT then Errno::ENOENT + when NOEXEC then Errno::ENOEXEC + when NOLCK then Errno::ENOLCK + when NOLINK then Errno::ENOLINK + when NOMEM then Errno::ENOMEM + when NOMSG then Errno::ENOMSG + when NOPROTOOPT then Errno::ENOPROTOOPT + when NOSPC then Errno::ENOSPC + when NOSYS then Errno::ENOSYS + when NOTCONN then Errno::ENOTCONN + when NOTDIR then Errno::ENOTDIR + when NOTEMPTY then Errno::ENOTEMPTY + when NOTRECOVERABLE then Errno::ENOTRECOVERABLE + when NOTSOCK then Errno::ENOTSOCK + when NOTSUP then Errno::ENOTSUP + when NOTTY then Errno::ENOTTY + when NXIO then Errno::ENXIO + when OVERFLOW then Errno::EOVERFLOW + when OWNERDEAD then Errno::EOWNERDEAD + when PERM then Errno::EPERM + when PIPE then Errno::EPIPE + when PROTO then Errno::EPROTO + when PROTONOSUPPORT then Errno::EPROTONOSUPPORT + when PROTOTYPE then Errno::EPROTOTYPE + when RANGE then Errno::ERANGE + when ROFS then Errno::EROFS + when SPIPE then Errno::ESPIPE + when SRCH then Errno::ESRCH + when STALE then Errno::ESTALE + when TIMEDOUT then Errno::ETIMEDOUT + when TXTBSY then Errno::ETXTBSY + when XDEV then Errno::EXDEV + when NOTCAPABLE then Errno::ENOTCAPABLE + else Errno::EINVAL + end + end + + SUCCESS # No error occurred. System call completed successfully. + TOOBIG # Argument list too long. + ACCES # Permission denied. + ADDRINUSE # Address in use. + ADDRNOTAVAIL # Address not available. + AFNOSUPPORT # Address family not supported. + AGAIN # Resource unavailable, or operation would block. + ALREADY # Connection already in progress. + BADF # Bad file descriptor. + BADMSG # Bad message. + BUSY # Device or resource busy. + CANCELED # Operation canceled. + CHILD # No child processes. + CONNABORTED # Connection aborted. + CONNREFUSED # Connection refused. + CONNRESET # Connection reset. + DEADLK # Resource deadlock would occur. + DESTADDRREQ # Destination address required. + DOM # Mathematics argument out of domain of function. + DQUOT # Reserved. + EXIST # File exists. + FAULT # Bad address. + FBIG # File too large. + HOSTUNREACH # Host is unreachable. + IDRM # Identifier removed. + ILSEQ # Illegal byte sequence. + INPROGRESS # Operation in progress. + INTR # Interrupted function. + INVAL # Invalid argument. + IO # I/O error. + ISCONN # Socket is connected. + ISDIR # Is a directory. + LOOP # Too many levels of symbolic links. + MFILE # File descriptor value too large. + MLINK # Too many links. + MSGSIZE # Message too large. + MULTIHOP # Reserved. + NAMETOOLONG # Filename too long. + NETDOWN # Network is down. + NETRESET # Connection aborted by network. + NETUNREACH # Network unreachable. + NFILE # Too many files open in system. + NOBUFS # No buffer space available. + NODEV # No such device. + NOENT # No such file or directory. + NOEXEC # Executable file format error. + NOLCK # No locks available. + NOLINK # Reserved. + NOMEM # Not enough space. + NOMSG # No message of the desired type. + NOPROTOOPT # Protocol not available. + NOSPC # No space left on device. + NOSYS # Function not supported. + NOTCONN # The socket is not connected. + NOTDIR # Not a directory or a symbolic link to a directory. + NOTEMPTY # Directory not empty. + NOTRECOVERABLE # State not recoverable. + NOTSOCK # Not a socket. + NOTSUP # Not supported, or operation not supported on socket. + NOTTY # Inappropriate I/O control operation. + NXIO # No such device or address. + OVERFLOW # Value too large to be stored in data type. + OWNERDEAD # Previous owner died. + PERM # Operation not permitted. + PIPE # Broken pipe. + PROTO # Protocol error. + PROTONOSUPPORT # Protocol not supported. + PROTOTYPE # Protocol wrong type for socket. + RANGE # Result too large. + ROFS # Read-only file system. + SPIPE # Invalid seek. + SRCH # No such process. + STALE # Reserved. + TIMEDOUT # Connection timed out. + TXTBSY # Text file busy. + XDEV # Cross-device link. + NOTCAPABLE # Extension: Capabilities insufficient. +end From 4d5b0615bfbb1c018f43e191be86390c1bd476c7 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Fri, 24 Dec 2021 16:16:07 -0300 Subject: [PATCH 20/41] feat: enable libpcre --- src/regex/lib_pcre.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/regex/lib_pcre.cr b/src/regex/lib_pcre.cr index 024f216fc7b5..0d7ad4f57938 100644 --- a/src/regex/lib_pcre.cr +++ b/src/regex/lib_pcre.cr @@ -27,7 +27,7 @@ lib LibPCRE end # TODO(interpreted): remove this unless -{% unless flag?(:interpreted) || flag?(:wasm32) %} +{% unless flag?(:interpreted) %} LibPCRE.pcre_malloc = ->GC.malloc(LibC::SizeT) LibPCRE.pcre_free = ->GC.free(Void*) {% end %} From 5b4627f97f80a1935c5dfdb111441f4b73a3e308 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:03:05 -0300 Subject: [PATCH 21/41] chore: refactor Crystal::Program.object_extension --- src/compiler/crystal/codegen/link.cr | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/compiler/crystal/codegen/link.cr b/src/compiler/crystal/codegen/link.cr index c0322a4ca745..cc764678b990 100644 --- a/src/compiler/crystal/codegen/link.cr +++ b/src/compiler/crystal/codegen/link.cr @@ -100,7 +100,11 @@ module Crystal class Program def object_extension - has_flag?("windows") ? ".obj" : has_flag?("wasm32") ? ".wasm" : ".o" + case + when has_flag?("windows") then ".obj" + when has_flag?("wasm32") then ".wasm" + else ".o" + end end def lib_flags From 2519a6ae20b41ca413e51b48e250f99b0d2e9ecb Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:12:44 -0300 Subject: [PATCH 22/41] fix: mock Thread.current --- src/crystal/system/wasm/thread.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystal/system/wasm/thread.cr b/src/crystal/system/wasm/thread.cr index 2a9cf27502f5..3237f74bf336 100644 --- a/src/crystal/system/wasm/thread.cr +++ b/src/crystal/system/wasm/thread.cr @@ -36,7 +36,7 @@ class Thread raise NotImplementedError.new("Thread.yield") end - @@current : Thread? = nil + @@current : Thread? = Thread.new # Associates the Thread object to the running system thread. protected def self.current=(@@current : Thread) : Thread From fdef3acd9ec61a1d64217cf9eb386223cde5fc0f Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:13:14 -0300 Subject: [PATCH 23/41] chore: change PREOPENS to @@preopens --- src/crystal/system/wasm/wasi.cr | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/crystal/system/wasm/wasi.cr b/src/crystal/system/wasm/wasi.cr index 564d27fb5509..859cd4a74fcb 100644 --- a/src/crystal/system/wasm/wasi.cr +++ b/src/crystal/system/wasm/wasi.cr @@ -1,9 +1,9 @@ require "./lib_wasi" module Crystal::System::Wasi - PREOPENS = [] of {String, String, LibWasi::Fd} + @@preopens : Array({String, String, LibWasi::Fd}) = begin + preopens = [] of {String, String, LibWasi::Fd} - def self.init_preopens # Skip stdin, stdout, and stderr, and count up until we reach an invalid file descriptor. (3..).each do |fd| stat = uninitialized LibWasi::Prestat @@ -27,18 +27,22 @@ module Crystal::System::Wasi end path = ::Path[name].expand.to_s - PREOPENS << {path, path.ends_with?("/") ? path : path + "/", fd} + preopens << {path, path.ends_with?("/") ? path : path + "/", fd} end # Preopens added later take priority over preopens added earlier. - PREOPENS.reverse! + preopens.reverse! # Preopens of longer prefix take priority over shorter prefixes. - PREOPENS.sort_by! { |entry| -entry[0].size } + preopens.sort_by! { |entry| -entry[0].size } + + p preopens + + preopens end def self.find_path_preopen(path) path = ::Path[path].expand.to_s - PREOPENS.each do |preopen| + @@preopens.each do |preopen| if preopen[0] == path return {preopen[2], "."} elsif path.starts_with? preopen[1] @@ -50,5 +54,3 @@ module Crystal::System::Wasi raise RuntimeError.from_os_error(nil, WasiError::NOTCAPABLE) end end - -Crystal::System::Wasi.init_preopens From 10c6eb791ec437357714424b8268c7384eb5f4bc Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:13:29 -0300 Subject: [PATCH 24/41] fix: print fatal errors --- src/crystal/system/print_error.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crystal/system/print_error.cr b/src/crystal/system/print_error.cr index 18f68d923507..e58eca1f178e 100644 --- a/src/crystal/system/print_error.cr +++ b/src/crystal/system/print_error.cr @@ -3,7 +3,7 @@ module Crystal::System # This is useful for error messages from components that are required for # IO to work (fibers, scheduler, event_loop). def self.print_error(message, *args) - {% if flag?(:unix) %} + {% if flag?(:unix) || flag?(:wasm32) %} LibC.dprintf 2, message, *args {% elsif flag?(:win32) %} buffer = StaticArray(UInt8, 512).new(0_u8) From a0407ca6fe4857e9695eb9e5470ffee2af9f339e Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:14:09 -0300 Subject: [PATCH 25/41] fix: use Sync logger until channels work --- src/log/io_backend.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/log/io_backend.cr b/src/log/io_backend.cr index cc7e38458552..9092495c8bf4 100644 --- a/src/log/io_backend.cr +++ b/src/log/io_backend.cr @@ -3,8 +3,8 @@ class Log::IOBackend < Log::Backend property io : IO property formatter : Formatter - {% if flag?(:win32) %} - # TODO: this constructor must go away once channels are fixed in Windows + {% if flag?(:win32) || flag?(:wasm32) %} + # TODO: this constructor must go away once channels are fixed in Windows / WebAssembly def initialize(@io = STDOUT, *, @formatter : Formatter = ShortFormat, dispatcher : Dispatcher::Spec = DispatchMode::Sync) super(dispatcher) end From c3f035f4ba4d5368d1600c3661184a3adbaa8bde Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:15:20 -0300 Subject: [PATCH 26/41] chore: rename wasierror.cr -> wasi_error.cr --- src/prelude.cr | 2 +- src/{wasierror.cr => wasi_error.cr} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{wasierror.cr => wasi_error.cr} (100%) diff --git a/src/prelude.cr b/src/prelude.cr index 37b97707f8a1..f3bb60a2f111 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -48,7 +48,7 @@ require "enumerable" require "env" require "errno" require "winerror" -require "wasierror" +require "wasi_error" require "file" require "float" require "gc" diff --git a/src/wasierror.cr b/src/wasi_error.cr similarity index 100% rename from src/wasierror.cr rename to src/wasi_error.cr From 3ba1b96ab83188e47338e72247b2c959454be3ac Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 28 Dec 2021 12:47:01 -0300 Subject: [PATCH 27/41] chore: preopen cleanup --- src/crystal/system/wasm/wasi.cr | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/crystal/system/wasm/wasi.cr b/src/crystal/system/wasm/wasi.cr index 859cd4a74fcb..e420d4c9d85e 100644 --- a/src/crystal/system/wasm/wasi.cr +++ b/src/crystal/system/wasm/wasi.cr @@ -35,17 +35,16 @@ module Crystal::System::Wasi # Preopens of longer prefix take priority over shorter prefixes. preopens.sort_by! { |entry| -entry[0].size } - p preopens - preopens end def self.find_path_preopen(path) path = ::Path[path].expand.to_s @@preopens.each do |preopen| - if preopen[0] == path + case path + when preopen[0] return {preopen[2], "."} - elsif path.starts_with? preopen[1] + when .starts_with? preopen[1] return {preopen[2], path[preopen[1].size..-1]} end end From e58cf26a51fb36d5f3b5e1d96e1b34739ce79a5c Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 29 Dec 2021 18:48:55 -0300 Subject: [PATCH 28/41] fix: there is no need to initialize PREOPENS as early as possible if we check for any error --- src/crystal/system/wasm/wasi.cr | 9 +++------ src/prelude.cr | 3 --- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/crystal/system/wasm/wasi.cr b/src/crystal/system/wasm/wasi.cr index e420d4c9d85e..3db4f600df1c 100644 --- a/src/crystal/system/wasm/wasi.cr +++ b/src/crystal/system/wasm/wasi.cr @@ -1,7 +1,7 @@ require "./lib_wasi" module Crystal::System::Wasi - @@preopens : Array({String, String, LibWasi::Fd}) = begin + PREOPENS = begin preopens = [] of {String, String, LibWasi::Fd} # Skip stdin, stdout, and stderr, and count up until we reach an invalid file descriptor. @@ -9,10 +9,7 @@ module Crystal::System::Wasi stat = uninitialized LibWasi::Prestat err = LibWasi.fd_prestat_get(fd, pointerof(stat)) - break if err.badf? - unless err.success? - raise RuntimeError.from_os_error("fd_prestat_get", err) - end + break unless err.success? next unless stat.tag.dir? @@ -40,7 +37,7 @@ module Crystal::System::Wasi def self.find_path_preopen(path) path = ::Path[path].expand.to_s - @@preopens.each do |preopen| + PREOPENS.each do |preopen| case path when preopen[0] return {preopen[2], "."} diff --git a/src/prelude.cr b/src/prelude.cr index f3bb60a2f111..ea88f25215f1 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -24,9 +24,6 @@ require "indexable" require "string" require "number" require "primitives" -{% if flag?(:wasm32) %} - require "crystal/system/wasm/wasi" -{% end %} # Alpha-sorted list require "annotations" From 7bcd75a14fe3c41634020d294f9182aef929e963 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 29 Dec 2021 19:19:38 -0300 Subject: [PATCH 29/41] fix: missing wasi require --- src/crystal/system/wasm/dir.cr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crystal/system/wasm/dir.cr b/src/crystal/system/wasm/dir.cr index df564efe8964..2c1576b3f7e5 100644 --- a/src/crystal/system/wasm/dir.cr +++ b/src/crystal/system/wasm/dir.cr @@ -1,3 +1,5 @@ +require "./wasi" + module Crystal::System::Dir private class DirHandle property fd : LibWasi::Fd From cb2ea23450b2fcaa223c1139a68b6f1e3bde4604 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 29 Dec 2021 19:20:14 -0300 Subject: [PATCH 30/41] feat: generate better linker command --- src/compiler/crystal/compiler.cr | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compiler/crystal/compiler.cr b/src/compiler/crystal/compiler.cr index 98e163131fea..94a75518f053 100644 --- a/src/compiler/crystal/compiler.cr +++ b/src/compiler/crystal/compiler.cr @@ -394,6 +394,9 @@ module Crystal end {cmd, nil} + elsif program.has_flag? "wasm32" + link_flags = @link_flags || "" + { %(wasm-ld "${@}" -o #{Process.quote_posix(output_filename)} #{link_flags} -lc #{program.lib_flags}), object_names } else link_flags = @link_flags || "" link_flags += " -rdynamic" From ad2e402b2090032a61a7ef8f18574e04c692dd6d Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Wed, 29 Dec 2021 20:13:42 -0300 Subject: [PATCH 31/41] chore: stub Exception::CallStack#decode_backtrace until callback support --- src/exception/call_stack.cr | 90 +++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/exception/call_stack.cr b/src/exception/call_stack.cr index e74cbe412d33..b1e57010d0d3 100644 --- a/src/exception/call_stack.cr +++ b/src/exception/call_stack.cr @@ -40,62 +40,66 @@ struct Exception::CallStack end private def decode_backtrace - show_full_info = ENV["CRYSTAL_CALLSTACK_FULL_INFO"]? == "1" + {% if flag?(:wasm32) %} + [] of String + {% else %} + show_full_info = ENV["CRYSTAL_CALLSTACK_FULL_INFO"]? == "1" - @callstack.compact_map do |ip| - pc = CallStack.decode_address(ip) + @callstack.compact_map do |ip| + pc = CallStack.decode_address(ip) - file, line_number, column_number = CallStack.decode_line_number(pc) + file, line_number, column_number = CallStack.decode_line_number(pc) - if file && file != "??" - next if @@skip.includes?(file) + if file && file != "??" + next if @@skip.includes?(file) - # Turn to relative to the current dir, if possible - if current_dir = CURRENT_DIR - if rel = Path[file].relative_to?(current_dir) - rel = rel.to_s - file = rel unless rel.starts_with?("..") + # Turn to relative to the current dir, if possible + if current_dir = CURRENT_DIR + if rel = Path[file].relative_to?(current_dir) + rel = rel.to_s + file = rel unless rel.starts_with?("..") + end end - end - file_line_column = file - unless line_number == 0 - file_line_column = "#{file_line_column}:#{line_number}" - file_line_column = "#{file_line_column}:#{column_number}" unless column_number == 0 + file_line_column = file + unless line_number == 0 + file_line_column = "#{file_line_column}:#{line_number}" + file_line_column = "#{file_line_column}:#{column_number}" unless column_number == 0 + end end - end - if name = CallStack.decode_function_name(pc) - function = name - elsif frame = CallStack.decode_frame(ip) - _, function, file = frame - # Crystal methods (their mangled name) start with `*`, so - # we remove that to have less clutter in the output. - function = function.lchop('*') - else - function = "??" - end - - if file_line_column - if show_full_info && (frame = CallStack.decode_frame(ip)) - _, sname, _ = frame - line = "#{file_line_column} in '#{sname}'" + if name = CallStack.decode_function_name(pc) + function = name + elsif frame = CallStack.decode_frame(ip) + _, function, file = frame + # Crystal methods (their mangled name) start with `*`, so + # we remove that to have less clutter in the output. + function = function.lchop('*') else - line = "#{file_line_column} in '#{function}'" + function = "??" end - else - if file == "??" && function == "??" - line = "???" + + if file_line_column + if show_full_info && (frame = CallStack.decode_frame(ip)) + _, sname, _ = frame + line = "#{file_line_column} in '#{sname}'" + else + line = "#{file_line_column} in '#{function}'" + end else - line = "#{file} in '#{function}'" + if file == "??" && function == "??" + line = "???" + else + line = "#{file} in '#{function}'" + end end - end - if show_full_info - line = "#{line} at 0x#{ip.address.to_s(16)}" - end + if show_full_info + line = "#{line} at 0x#{ip.address.to_s(16)}" + end - line - end + line + end + {% end %} end end From 2e4b5177e1066ba230bee43daa20329e075236ed Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Fri, 31 Dec 2021 10:46:03 -0300 Subject: [PATCH 32/41] chore: remove some unused pieces from wasm libc --- src/crystal/system/wasm/fiber.cr | 2 - src/crystal/system/wasm/process.cr | 3 -- src/gc/boehm.cr | 2 +- src/gc/none.cr | 2 +- src/lib_c/wasm32-wasi/c/fcntl.cr | 8 ---- src/lib_c/wasm32-wasi/c/pthread.cr | 5 --- src/lib_c/wasm32-wasi/c/signal.cr | 53 -------------------------- src/lib_c/wasm32-wasi/c/stdlib.cr | 1 - src/lib_c/wasm32-wasi/c/sys/file.cr | 8 ---- src/lib_c/wasm32-wasi/c/sys/mman.cr | 31 --------------- src/lib_c/wasm32-wasi/c/sys/syscall.cr | 2 - src/lib_c/wasm32-wasi/c/sys/wait.cr | 5 --- 12 files changed, 2 insertions(+), 120 deletions(-) delete mode 100644 src/lib_c/wasm32-wasi/c/pthread.cr delete mode 100644 src/lib_c/wasm32-wasi/c/signal.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/mman.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/syscall.cr delete mode 100644 src/lib_c/wasm32-wasi/c/sys/wait.cr diff --git a/src/crystal/system/wasm/fiber.cr b/src/crystal/system/wasm/fiber.cr index 894b0793ada7..cabb06a9cd6e 100644 --- a/src/crystal/system/wasm/fiber.cr +++ b/src/crystal/system/wasm/fiber.cr @@ -1,5 +1,3 @@ -require "c/sys/mman" - module Crystal::System::Fiber def self.allocate_stack(stack_size) : Void* LibC.malloc(stack_size) diff --git a/src/crystal/system/wasm/process.cr b/src/crystal/system/wasm/process.cr index cbe37f43f64f..a9d5d0e9fa69 100644 --- a/src/crystal/system/wasm/process.cr +++ b/src/crystal/system/wasm/process.cr @@ -1,8 +1,5 @@ -require "c/signal" require "c/stdlib" -require "c/sys/resource" require "c/unistd" -require "file/error" struct Crystal::System::Process getter pid : LibC::PidT diff --git a/src/gc/boehm.cr b/src/gc/boehm.cr index 36782e3ddad6..62c52d581d03 100644 --- a/src/gc/boehm.cr +++ b/src/gc/boehm.cr @@ -88,7 +88,7 @@ lib LibGC fun size = GC_size(addr : Void*) : LibC::SizeT - {% unless flag?(:win32) %} + {% unless flag?(:win32) || flag?(:wasm32) %} # Boehm GC requires to use GC_pthread_create and GC_pthread_join instead of pthread_create and pthread_join fun pthread_create = GC_pthread_create(thread : LibC::PthreadT*, attr : LibC::PthreadAttrT*, start : Void* -> Void*, arg : Void*) : LibC::Int fun pthread_join = GC_pthread_join(thread : LibC::PthreadT, value : Void**) : LibC::Int diff --git a/src/gc/none.cr b/src/gc/none.cr index 24ed4cb597b1..4eef3d5a0144 100644 --- a/src/gc/none.cr +++ b/src/gc/none.cr @@ -66,7 +66,7 @@ module GC reclaimed_bytes_before_gc: zero) end - {% unless flag?(:win32) %} + {% unless flag?(:win32) || flag?(:wasm32) %} # :nodoc: def self.pthread_create(thread : LibC::PthreadT*, attr : LibC::PthreadAttrT*, start : Void* -> Void*, arg : Void*) LibC.pthread_create(thread, attr, start, arg) diff --git a/src/lib_c/wasm32-wasi/c/fcntl.cr b/src/lib_c/wasm32-wasi/c/fcntl.cr index 37de7f454bb6..7bbfe10f23ec 100644 --- a/src/lib_c/wasm32-wasi/c/fcntl.cr +++ b/src/lib_c/wasm32-wasi/c/fcntl.cr @@ -19,14 +19,6 @@ lib LibC O_RDWR = O_RDONLY | O_WRONLY O_WRONLY = 0x10000000 - struct Flock - l_type : Short - l_whence : Short - l_start : OffT - l_len : OffT - l_pid : PidT - end - fun fcntl(x0 : Int, x1 : Int, ...) : Int fun open(x0 : Char*, x1 : Int, ...) : Int end diff --git a/src/lib_c/wasm32-wasi/c/pthread.cr b/src/lib_c/wasm32-wasi/c/pthread.cr deleted file mode 100644 index cf67b1d60261..000000000000 --- a/src/lib_c/wasm32-wasi/c/pthread.cr +++ /dev/null @@ -1,5 +0,0 @@ -require "./sys/types" - -lib LibC - fun pthread_join(th : PthreadT, thread_return : Void**) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/signal.cr b/src/lib_c/wasm32-wasi/c/signal.cr deleted file mode 100644 index b7a88aaab362..000000000000 --- a/src/lib_c/wasm32-wasi/c/signal.cr +++ /dev/null @@ -1,53 +0,0 @@ -require "./sys/types" -require "./time" - -lib LibC - SIGHUP = 1 - SIGINT = 2 - SIGQUIT = 3 - SIGILL = 4 - SIGTRAP = 5 - SIGIOT = LibC::SIGABRT - SIGABRT = 6 - SIGFPE = 8 - SIGKILL = 9 - SIGBUS = 7 - SIGSEGV = 11 - SIGSYS = 31 - SIGPIPE = 13 - SIGALRM = 14 - SIGTERM = 15 - SIGURG = 23 - SIGSTOP = 19 - SIGTSTP = 20 - SIGCONT = 18 - SIGCHLD = 17 - SIGTTIN = 21 - SIGTTOU = 22 - SIGIO = 29 - SIGXCPU = 24 - SIGXFSZ = 25 - SIGVTALRM = 26 - SIGUSR1 = 10 - SIGUSR2 = 12 - SIGWINCH = 28 - SIGPWR = 30 - SIGSTKFLT = 16 - SIGUNUSED = LibC::SIGSYS - - alias SigsetT = LibC::UChar - - alias SighandlerT = Int -> Void - - struct SiginfoT - si_signo : Int - si_code : Int - si_errno : Int - si_addr : Void* - end - - alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> - SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) - - fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void -end diff --git a/src/lib_c/wasm32-wasi/c/stdlib.cr b/src/lib_c/wasm32-wasi/c/stdlib.cr index 698de00c0d17..619175b50d05 100644 --- a/src/lib_c/wasm32-wasi/c/stdlib.cr +++ b/src/lib_c/wasm32-wasi/c/stdlib.cr @@ -1,5 +1,4 @@ require "./stddef" -require "./sys/wait" lib LibC struct DivT diff --git a/src/lib_c/wasm32-wasi/c/sys/file.cr b/src/lib_c/wasm32-wasi/c/sys/file.cr index 5f6e63d09ce0..e69de29bb2d1 100644 --- a/src/lib_c/wasm32-wasi/c/sys/file.cr +++ b/src/lib_c/wasm32-wasi/c/sys/file.cr @@ -1,8 +0,0 @@ -lib LibC - LOCK_SH = 1 - LOCK_EX = 2 - LOCK_NB = 4 - LOCK_UN = 8 - - fun flock(x0 : Int, x1 : Int) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/mman.cr b/src/lib_c/wasm32-wasi/c/sys/mman.cr deleted file mode 100644 index 1f7af8eba42c..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/mman.cr +++ /dev/null @@ -1,31 +0,0 @@ -require "./types" - -lib LibC - PROT_EXEC = 4 - PROT_NONE = 0 - PROT_READ = 1 - PROT_WRITE = 2 - MAP_FIXED = 0x10 - MAP_PRIVATE = 0x02 - MAP_SHARED = 0x01 - MAP_ANON = 0x20 - MAP_ANONYMOUS = LibC::MAP_ANON - MAP_FAILED = Pointer(Void).new(-1) - POSIX_MADV_DONTNEED = 4 - POSIX_MADV_NORMAL = 0 - POSIX_MADV_RANDOM = 1 - POSIX_MADV_SEQUENTIAL = 2 - POSIX_MADV_WILLNEED = 3 - MADV_DONTNEED = 4 - MADV_NORMAL = 0 - MADV_RANDOM = 1 - MADV_SEQUENTIAL = 2 - MADV_WILLNEED = 3 - MADV_HUGEPAGE = 14 - MADV_NOHUGEPAGE = 15 - - fun mmap(x0 : Void*, x1 : SizeT, x2 : Int, x3 : Int, x4 : Int, x5 : OffT) : Void* - fun mprotect(x0 : Void*, x1 : SizeT, x2 : Int) : Int - fun munmap(x0 : Void*, x1 : SizeT) : Int - fun madvise(x0 : Void*, x1 : SizeT, x2 : Int) : Int -end diff --git a/src/lib_c/wasm32-wasi/c/sys/syscall.cr b/src/lib_c/wasm32-wasi/c/sys/syscall.cr deleted file mode 100644 index d65139312793..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/syscall.cr +++ /dev/null @@ -1,2 +0,0 @@ -lib LibC -end diff --git a/src/lib_c/wasm32-wasi/c/sys/wait.cr b/src/lib_c/wasm32-wasi/c/sys/wait.cr deleted file mode 100644 index 58e6a3d0a9eb..000000000000 --- a/src/lib_c/wasm32-wasi/c/sys/wait.cr +++ /dev/null @@ -1,5 +0,0 @@ -require "./types" -require "../signal" - -lib LibC -end From 5faa13a3f74e47b5b04de2acaf0621cdd17c1f91 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Thu, 27 Jan 2022 10:51:18 -0300 Subject: [PATCH 33/41] fix: use "out fd" --- src/crystal/system/wasm/dir.cr | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/crystal/system/wasm/dir.cr b/src/crystal/system/wasm/dir.cr index 2c1576b3f7e5..7f6ee0056cdb 100644 --- a/src/crystal/system/wasm/dir.cr +++ b/src/crystal/system/wasm/dir.cr @@ -21,8 +21,7 @@ module Crystal::System::Dir def self.open(path : String) : DirHandle parent_fd, relative_path = Wasi.find_path_preopen(path) - fd = uninitialized LibWasi::Fd - err = LibWasi.path_open(parent_fd, LibWasi::LookupFlags::SymlinkFollow, relative_path, LibWasi::OpenFlags::Directory, LibWasi::Rights::FdReaddir, LibWasi::Rights::None, LibWasi::FdFlags::None, pointerof(fd)) + err = LibWasi.path_open(parent_fd, LibWasi::LookupFlags::SymlinkFollow, relative_path, LibWasi::OpenFlags::Directory, LibWasi::Rights::FdReaddir, LibWasi::Rights::None, LibWasi::FdFlags::None, out fd) raise ::File::Error.from_os_error("Error opening directory", err, file: path) unless err.success? DirHandle.new(fd) @@ -67,7 +66,7 @@ module Crystal::System::Dir def self.close(dir, path) : Nil err = LibWasi.fd_close(dir.fd) - raise ::File::Error.from_os_error("Error opening directory", err, file: path) unless err.success? + raise ::File::Error.from_os_error("Error closing directory", err, file: path) unless err.success? end def self.current : String From 9de1150dd90b3bff707178715f4bb925588aff43 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 15:20:58 -0300 Subject: [PATCH 34/41] feat: add wasi random_get to avoid relying on arc4random polyfill --- src/crystal/system/random.cr | 4 +++- src/crystal/system/wasm/lib_wasi.cr | 1 + src/crystal/system/wasm/random.cr | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/crystal/system/wasm/random.cr diff --git a/src/crystal/system/random.cr b/src/crystal/system/random.cr index c60bdefad78a..e8748ff95676 100644 --- a/src/crystal/system/random.cr +++ b/src/crystal/system/random.cr @@ -12,10 +12,12 @@ end {% if flag?(:linux) %} require "./unix/getrandom" -{% elsif flag?(:openbsd) || flag?(:netbsd) || flag?(:wasm32) %} +{% elsif flag?(:openbsd) || flag?(:netbsd) %} require "./unix/arc4random" {% elsif flag?(:unix) %} require "./unix/urandom" +{% elsif flag?(:wasm32) %} + require "./wasm/random" {% elsif flag?(:win32) %} require "./win32/random" {% else %} diff --git a/src/crystal/system/wasm/lib_wasi.cr b/src/crystal/system/wasm/lib_wasi.cr index 0117480b695c..a958b6e46206 100644 --- a/src/crystal/system/wasm/lib_wasi.cr +++ b/src/crystal/system/wasm/lib_wasi.cr @@ -98,4 +98,5 @@ lib LibWasi fun path_open = __wasi_path_open(fd : Fd, dirflags : LookupFlags, path : UInt8*, oflags : OpenFlags, fs_rights_base : Rights, fs_rights_inheriting : Rights, fdflags : FdFlags, ret : Fd*) : WasiError fun fd_readdir = __wasi_fd_readdir(fd : Fd, buf : UInt8*, len : Size, cookie : UInt64, ret : Size*) : WasiError fun fd_close = __wasi_fd_close(fd : Fd) : WasiError + fun random_get = __wasi_random_get(buf : UInt8*, len : Size) : WasiError end diff --git a/src/crystal/system/wasm/random.cr b/src/crystal/system/wasm/random.cr new file mode 100644 index 000000000000..72649fac3e7c --- /dev/null +++ b/src/crystal/system/wasm/random.cr @@ -0,0 +1,14 @@ +require "./lib_wasi" + +module Crystal::System::Random + def self.random_bytes(buf : Bytes) : Nil + err = LibWasi.random_get(buf, buf.size) + raise RuntimeError.from_os_error("random_get", err) unless err.success? + end + + def self.next_u : UInt8 + buf = uninitialized UInt8[1] + random_bytes(buf.to_slice) + buf.unsafe_as(UInt8) + end +end From 2d3158eb11d725ab0260aede116b3e8deb784565 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 15:54:55 -0300 Subject: [PATCH 35/41] Mark WASI as a UNIX target and use it as the system environment, instead of wasm32 directly. This provides better support for the wasm32-unknown-unknown target. --- spec/compiler/ffi/ffi_spec.cr | 2 +- spec/compiler/loader/unix_spec.cr | 2 +- src/compiler/crystal/codegen/target.cr | 6 +++- src/crystal/system.cr | 8 ++--- src/crystal/system/dir.cr | 6 ++-- src/crystal/system/env.cr | 2 +- src/crystal/system/event_loop.cr | 4 +-- src/crystal/system/fiber.cr | 6 ++-- src/crystal/system/file.cr | 6 ++-- src/crystal/system/file_descriptor.cr | 6 ++-- src/crystal/system/file_info.cr | 2 +- src/crystal/system/group.cr | 6 ++-- src/crystal/system/mime.cr | 2 +- src/crystal/system/path.cr | 2 +- src/crystal/system/print_error.cr | 2 +- src/crystal/system/process.cr | 6 ++-- src/crystal/system/random.cr | 6 ++-- src/crystal/system/socket.cr | 6 ++-- src/crystal/system/thread.cr | 6 ++-- src/crystal/system/thread_mutex.cr | 6 ++-- src/crystal/system/time.cr | 2 +- src/crystal/system/user.cr | 6 ++-- src/crystal/system/{wasm => wasi}/cpucount.cr | 0 src/crystal/system/{wasm => wasi}/dir.cr | 0 .../system/{wasm => wasi}/event_loop.cr | 0 src/crystal/system/{wasm => wasi}/fiber.cr | 0 src/crystal/system/{wasm => wasi}/file.cr | 0 .../system/{wasm => wasi}/file_descriptor.cr | 0 src/crystal/system/{wasm => wasi}/group.cr | 0 src/crystal/system/{wasm => wasi}/hostname.cr | 0 src/crystal/system/{wasm => wasi}/lib_wasi.cr | 0 src/crystal/system/{wasm => wasi}/process.cr | 0 src/crystal/system/{wasm => wasi}/random.cr | 0 src/crystal/system/{wasm => wasi}/socket.cr | 0 src/crystal/system/{wasm => wasi}/thread.cr | 36 +++---------------- .../system/{wasm => wasi}/thread_mutex.cr | 0 src/crystal/system/{wasm => wasi}/user.cr | 0 src/crystal/system/{wasm => wasi}/wasi.cr | 0 38 files changed, 56 insertions(+), 80 deletions(-) rename src/crystal/system/{wasm => wasi}/cpucount.cr (100%) rename src/crystal/system/{wasm => wasi}/dir.cr (100%) rename src/crystal/system/{wasm => wasi}/event_loop.cr (100%) rename src/crystal/system/{wasm => wasi}/fiber.cr (100%) rename src/crystal/system/{wasm => wasi}/file.cr (100%) rename src/crystal/system/{wasm => wasi}/file_descriptor.cr (100%) rename src/crystal/system/{wasm => wasi}/group.cr (100%) rename src/crystal/system/{wasm => wasi}/hostname.cr (100%) rename src/crystal/system/{wasm => wasi}/lib_wasi.cr (100%) rename src/crystal/system/{wasm => wasi}/process.cr (100%) rename src/crystal/system/{wasm => wasi}/random.cr (100%) rename src/crystal/system/{wasm => wasi}/socket.cr (100%) rename src/crystal/system/{wasm => wasi}/thread.cr (62%) rename src/crystal/system/{wasm => wasi}/thread_mutex.cr (100%) rename src/crystal/system/{wasm => wasi}/user.cr (100%) rename src/crystal/system/{wasm => wasi}/wasi.cr (100%) diff --git a/spec/compiler/ffi/ffi_spec.cr b/spec/compiler/ffi/ffi_spec.cr index 2ef0fe19d5da..4b70658e6bb8 100644 --- a/spec/compiler/ffi/ffi_spec.cr +++ b/spec/compiler/ffi/ffi_spec.cr @@ -1,4 +1,4 @@ -{% skip_file if !flag?(:unix) || flag?(:without_ffi) %} +{% skip_file if !flag?(:unix) || flag?(:without_ffi) || flag?(:wasm32) %} require "../spec_helper" require "compiler/crystal/ffi" diff --git a/spec/compiler/loader/unix_spec.cr b/spec/compiler/loader/unix_spec.cr index e6b4be3d7d8b..cc2e9894b075 100644 --- a/spec/compiler/loader/unix_spec.cr +++ b/spec/compiler/loader/unix_spec.cr @@ -1,4 +1,4 @@ -{% skip_file unless flag?(:unix) %} +{% skip_file if !flag?(:unix) || flag?(:wasm32) %} require "./spec_helper" require "../spec_helper" diff --git a/src/compiler/crystal/codegen/target.cr b/src/compiler/crystal/codegen/target.cr index df0f739e192b..c89880deabda 100644 --- a/src/compiler/crystal/codegen/target.cr +++ b/src/compiler/crystal/codegen/target.cr @@ -96,12 +96,16 @@ class Crystal::Codegen::Target @environment.starts_with?("linux") end + def wasi? + @environment.starts_with?("wasi") + end + def bsd? freebsd? || netbsd? || openbsd? || dragonfly? end def unix? - macos? || bsd? || linux? + macos? || bsd? || linux? || wasi? end def gnu? diff --git a/src/crystal/system.cr b/src/crystal/system.cr index a3837350d6dd..953137edc730 100644 --- a/src/crystal/system.cr +++ b/src/crystal/system.cr @@ -8,7 +8,10 @@ module Crystal::System # def self.cpu_count end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./system/wasi/hostname" + require "./system/wasi/cpucount" +{% elsif flag?(:unix) %} require "./system/unix/hostname" {% if flag?(:bsd) %} @@ -19,9 +22,6 @@ end {% elsif flag?(:win32) %} require "./system/win32/hostname" require "./system/win32/cpucount" -{% elsif flag?(:wasm32) %} - require "./system/wasm/hostname" - require "./system/wasm/cpucount" {% else %} {% raise "No Crystal::System implementation available" %} {% end %} diff --git a/src/crystal/system/dir.cr b/src/crystal/system/dir.cr index cbf5ee4cb621..eef9f330fbab 100644 --- a/src/crystal/system/dir.cr +++ b/src/crystal/system/dir.cr @@ -51,10 +51,10 @@ module Crystal::System::Dir # def self.delete(path : String) : Nil end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/dir" +{% elsif flag?(:unix) %} require "./unix/dir" -{% elsif flag?(:wasm32) %} - require "./wasm/dir" {% elsif flag?(:win32) %} require "./win32/dir" {% else %} diff --git a/src/crystal/system/env.cr b/src/crystal/system/env.cr index cd5dfd1e6f98..b7593c856857 100644 --- a/src/crystal/system/env.cr +++ b/src/crystal/system/env.cr @@ -12,7 +12,7 @@ module Crystal::System::Env # def self.each(&block : String, String ->) end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/env" {% elsif flag?(:win32) %} require "./win32/env" diff --git a/src/crystal/system/event_loop.cr b/src/crystal/system/event_loop.cr index 9e1646db5b9d..d7dc351c6ae2 100644 --- a/src/crystal/system/event_loop.cr +++ b/src/crystal/system/event_loop.cr @@ -28,8 +28,8 @@ struct Crystal::Event # def add(time_span : Time::Span?) : Nil end -{% if flag?(:wasm32) %} - require "./wasm/event_loop" +{% if flag?(:wasi) %} + require "./wasi/event_loop" {% elsif flag?(:unix) %} require "./unix/event_loop_libevent" {% elsif flag?(:win32) %} diff --git a/src/crystal/system/fiber.cr b/src/crystal/system/fiber.cr index ff4a4bfdab38..230cf4cc010b 100644 --- a/src/crystal/system/fiber.cr +++ b/src/crystal/system/fiber.cr @@ -9,12 +9,12 @@ module Crystal::System::Fiber # def self.main_fiber_stack(stack_bottom : Void*) : Void* end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/fiber" +{% elsif flag?(:unix) %} require "./unix/fiber" {% elsif flag?(:win32) %} require "./win32/fiber" -{% elsif flag?(:wasm32) %} - require "./wasm/fiber" {% else %} {% raise "fiber not supported" %} {% end %} diff --git a/src/crystal/system/file.cr b/src/crystal/system/file.cr index 43d0777955a2..916237921642 100644 --- a/src/crystal/system/file.cr +++ b/src/crystal/system/file.cr @@ -49,12 +49,12 @@ module Crystal::System::File # def file_descriptor_close end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/file" +{% elsif flag?(:unix) %} require "./unix/file" {% elsif flag?(:win32) %} require "./win32/file" -{% elsif flag?(:wasm32) %} - require "./wasm/file" {% else %} {% raise "No Crystal::System::File implementation available" %} {% end %} diff --git a/src/crystal/system/file_descriptor.cr b/src/crystal/system/file_descriptor.cr index c058be3d696d..6e5621e57786 100644 --- a/src/crystal/system/file_descriptor.cr +++ b/src/crystal/system/file_descriptor.cr @@ -1,9 +1,9 @@ -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/file_descriptor" +{% elsif flag?(:unix) %} require "./unix/file_descriptor" {% elsif flag?(:win32) %} require "./win32/file_descriptor" -{% elsif flag?(:wasm32) %} - require "./wasm/file_descriptor" {% else %} {% raise "No Crystal::System::FileDescriptor implementation available" %} {% end %} diff --git a/src/crystal/system/file_info.cr b/src/crystal/system/file_info.cr index ef2bf2f78f3f..6a8b1fb69d07 100644 --- a/src/crystal/system/file_info.cr +++ b/src/crystal/system/file_info.cr @@ -1,4 +1,4 @@ -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/file_info" {% elsif flag?(:win32) %} require "./win32/file_info" diff --git a/src/crystal/system/group.cr b/src/crystal/system/group.cr index 5900f61a9a08..dce631e8c1ab 100644 --- a/src/crystal/system/group.cr +++ b/src/crystal/system/group.cr @@ -1,7 +1,7 @@ -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/group" +{% elsif flag?(:unix) %} require "./unix/group" -{% elsif flag?(:wasm32) %} - require "./wasm/group" {% else %} {% raise "No Crystal::System::Group implementation available" %} {% end %} diff --git a/src/crystal/system/mime.cr b/src/crystal/system/mime.cr index fe90f43970f8..9b456daa291c 100644 --- a/src/crystal/system/mime.cr +++ b/src/crystal/system/mime.cr @@ -3,7 +3,7 @@ module Crystal::System::MIME # def self.load end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/mime" {% elsif flag?(:win32) %} require "./win32/mime" diff --git a/src/crystal/system/path.cr b/src/crystal/system/path.cr index 058352a16170..17091ec3fc86 100644 --- a/src/crystal/system/path.cr +++ b/src/crystal/system/path.cr @@ -3,7 +3,7 @@ module Crystal::System::Path # def self.home : String end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/path" {% elsif flag?(:win32) %} require "./win32/path" diff --git a/src/crystal/system/print_error.cr b/src/crystal/system/print_error.cr index e58eca1f178e..18f68d923507 100644 --- a/src/crystal/system/print_error.cr +++ b/src/crystal/system/print_error.cr @@ -3,7 +3,7 @@ module Crystal::System # This is useful for error messages from components that are required for # IO to work (fibers, scheduler, event_loop). def self.print_error(message, *args) - {% if flag?(:unix) || flag?(:wasm32) %} + {% if flag?(:unix) %} LibC.dprintf 2, message, *args {% elsif flag?(:win32) %} buffer = StaticArray(UInt8, 512).new(0_u8) diff --git a/src/crystal/system/process.cr b/src/crystal/system/process.cr index 1088d55b9c61..b83d373382b7 100644 --- a/src/crystal/system/process.cr +++ b/src/crystal/system/process.cr @@ -70,12 +70,12 @@ module Crystal::System ORIGINAL_STDERR = IO::FileDescriptor.new(2, blocking: true) end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/process" +{% elsif flag?(:unix) %} require "./unix/process" {% elsif flag?(:win32) %} require "./win32/process" -{% elsif flag?(:wasm32) %} - require "./wasm/process" {% else %} {% raise "No Crystal::System::Process implementation available" %} {% end %} diff --git a/src/crystal/system/random.cr b/src/crystal/system/random.cr index e8748ff95676..becb879cedbb 100644 --- a/src/crystal/system/random.cr +++ b/src/crystal/system/random.cr @@ -10,14 +10,14 @@ module Crystal::System::Random # def self.next_u end -{% if flag?(:linux) %} +{% if flag?(:wasi) %} + require "./wasi/random" +{% elsif flag?(:linux) %} require "./unix/getrandom" {% elsif flag?(:openbsd) || flag?(:netbsd) %} require "./unix/arc4random" {% elsif flag?(:unix) %} require "./unix/urandom" -{% elsif flag?(:wasm32) %} - require "./wasm/random" {% elsif flag?(:win32) %} require "./win32/random" {% else %} diff --git a/src/crystal/system/socket.cr b/src/crystal/system/socket.cr index 164c584c0a92..54c49f62adaa 100644 --- a/src/crystal/system/socket.cr +++ b/src/crystal/system/socket.cr @@ -76,10 +76,10 @@ module Crystal::System::Socket # private def system_tcp_keepalive_count=(val : Int) end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/socket" +{% elsif flag?(:unix) %} require "./unix/socket" -{% elsif flag?(:wasm32) %} - require "./wasm/socket" {% elsif flag?(:win32) %} require "./win32/socket" {% else %} diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index dccd2f6e83d0..71f6286d9d36 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -28,13 +28,13 @@ end require "./thread_linked_list" -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/thread" +{% elsif flag?(:unix) %} require "./unix/pthread" require "./unix/pthread_condition_variable" {% elsif flag?(:win32) %} require "./win32/thread" -{% elsif flag?(:wasm32) %} - require "./wasm/thread" {% else %} {% raise "thread not supported" %} {% end %} diff --git a/src/crystal/system/thread_mutex.cr b/src/crystal/system/thread_mutex.cr index aeb50fd9b25b..1a5f3006d6eb 100644 --- a/src/crystal/system/thread_mutex.cr +++ b/src/crystal/system/thread_mutex.cr @@ -17,12 +17,12 @@ class Thread end end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/thread_mutex" +{% elsif flag?(:unix) %} require "./unix/pthread_mutex" {% elsif flag?(:win32) %} require "./win32/thread_mutex" -{% elsif flag?(:wasm32) %} - require "./wasm/thread_mutex" {% else %} {% raise "thread not supported" %} {% end %} diff --git a/src/crystal/system/time.cr b/src/crystal/system/time.cr index 48b3695d5526..1cd635c13218 100644 --- a/src/crystal/system/time.cr +++ b/src/crystal/system/time.cr @@ -12,7 +12,7 @@ module Crystal::System::Time # def self.load_localtime : ::Time::Location? end -{% if flag?(:unix) || flag?(:wasm32) %} +{% if flag?(:unix) %} require "./unix/time" {% elsif flag?(:win32) %} require "./win32/time" diff --git a/src/crystal/system/user.cr b/src/crystal/system/user.cr index 1148f18eb521..ecee92c8dcb5 100644 --- a/src/crystal/system/user.cr +++ b/src/crystal/system/user.cr @@ -1,7 +1,7 @@ -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/user" +{% elsif flag?(:unix) %} require "./unix/user" -{% elsif flag?(:wasm32) %} - require "./wasm/user" {% else %} {% raise "No Crystal::System::User implementation available" %} {% end %} diff --git a/src/crystal/system/wasm/cpucount.cr b/src/crystal/system/wasi/cpucount.cr similarity index 100% rename from src/crystal/system/wasm/cpucount.cr rename to src/crystal/system/wasi/cpucount.cr diff --git a/src/crystal/system/wasm/dir.cr b/src/crystal/system/wasi/dir.cr similarity index 100% rename from src/crystal/system/wasm/dir.cr rename to src/crystal/system/wasi/dir.cr diff --git a/src/crystal/system/wasm/event_loop.cr b/src/crystal/system/wasi/event_loop.cr similarity index 100% rename from src/crystal/system/wasm/event_loop.cr rename to src/crystal/system/wasi/event_loop.cr diff --git a/src/crystal/system/wasm/fiber.cr b/src/crystal/system/wasi/fiber.cr similarity index 100% rename from src/crystal/system/wasm/fiber.cr rename to src/crystal/system/wasi/fiber.cr diff --git a/src/crystal/system/wasm/file.cr b/src/crystal/system/wasi/file.cr similarity index 100% rename from src/crystal/system/wasm/file.cr rename to src/crystal/system/wasi/file.cr diff --git a/src/crystal/system/wasm/file_descriptor.cr b/src/crystal/system/wasi/file_descriptor.cr similarity index 100% rename from src/crystal/system/wasm/file_descriptor.cr rename to src/crystal/system/wasi/file_descriptor.cr diff --git a/src/crystal/system/wasm/group.cr b/src/crystal/system/wasi/group.cr similarity index 100% rename from src/crystal/system/wasm/group.cr rename to src/crystal/system/wasi/group.cr diff --git a/src/crystal/system/wasm/hostname.cr b/src/crystal/system/wasi/hostname.cr similarity index 100% rename from src/crystal/system/wasm/hostname.cr rename to src/crystal/system/wasi/hostname.cr diff --git a/src/crystal/system/wasm/lib_wasi.cr b/src/crystal/system/wasi/lib_wasi.cr similarity index 100% rename from src/crystal/system/wasm/lib_wasi.cr rename to src/crystal/system/wasi/lib_wasi.cr diff --git a/src/crystal/system/wasm/process.cr b/src/crystal/system/wasi/process.cr similarity index 100% rename from src/crystal/system/wasm/process.cr rename to src/crystal/system/wasi/process.cr diff --git a/src/crystal/system/wasm/random.cr b/src/crystal/system/wasi/random.cr similarity index 100% rename from src/crystal/system/wasm/random.cr rename to src/crystal/system/wasi/random.cr diff --git a/src/crystal/system/wasm/socket.cr b/src/crystal/system/wasi/socket.cr similarity index 100% rename from src/crystal/system/wasm/socket.cr rename to src/crystal/system/wasi/socket.cr diff --git a/src/crystal/system/wasm/thread.cr b/src/crystal/system/wasi/thread.cr similarity index 62% rename from src/crystal/system/wasm/thread.cr rename to src/crystal/system/wasi/thread.cr index 3237f74bf336..b10439852f55 100644 --- a/src/crystal/system/wasm/thread.cr +++ b/src/crystal/system/wasi/thread.cr @@ -1,30 +1,13 @@ class Thread - # all thread objects, so the GC can see them (it doesn't scan thread locals) - @@threads = Thread::LinkedList(Thread).new - - @exception : Exception? - @detached = Atomic(UInt8).new(0) @main_fiber : Fiber? - @func : (Proc(Nil))? - - # :nodoc: - property next : Thread? - - # :nodoc: - property previous : Thread? - - def self.unsafe_each - @@threads.unsafe_each { |thread| yield thread } - end def initialize @main_fiber = Fiber.new(stack_address, self) - @@threads.push(self) # TODO: Create thread end - def initialize(&@func : ->) + def initialize(&func : ->) initialize end @@ -36,7 +19,7 @@ class Thread raise NotImplementedError.new("Thread.yield") end - @@current : Thread? = Thread.new + @@current = Thread.new # Associates the Thread object to the running system thread. protected def self.current=(@@current : Thread) : Thread @@ -44,7 +27,7 @@ class Thread # Returns the Thread object associated to the running system thread. def self.current : Thread - @@current || raise "BUG: Thread.current returned NULL" + @@current end # Create the thread object for the current thread (aka the main thread of the @@ -64,18 +47,7 @@ class Thread end protected def start - Thread.current = self - @main_fiber = fiber = Fiber.new(stack_address, self) - - begin - @func.call - rescue ex - @exception = ex - ensure - @@threads.delete(self) - Fiber.inactive(fiber) - detach_self - end + raise NotImplementedError.new("Thread#start") end private def stack_address : Void* diff --git a/src/crystal/system/wasm/thread_mutex.cr b/src/crystal/system/wasi/thread_mutex.cr similarity index 100% rename from src/crystal/system/wasm/thread_mutex.cr rename to src/crystal/system/wasi/thread_mutex.cr diff --git a/src/crystal/system/wasm/user.cr b/src/crystal/system/wasi/user.cr similarity index 100% rename from src/crystal/system/wasm/user.cr rename to src/crystal/system/wasi/user.cr diff --git a/src/crystal/system/wasm/wasi.cr b/src/crystal/system/wasi/wasi.cr similarity index 100% rename from src/crystal/system/wasm/wasi.cr rename to src/crystal/system/wasi/wasi.cr From ac74badcd5625771af3f658445c4559e26fce8db Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 16:10:04 -0300 Subject: [PATCH 36/41] Update spec/compiler/loader/unix_spec.cr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johannes Müller --- spec/compiler/loader/unix_spec.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/compiler/loader/unix_spec.cr b/spec/compiler/loader/unix_spec.cr index cc2e9894b075..c14dcc934cc3 100644 --- a/spec/compiler/loader/unix_spec.cr +++ b/spec/compiler/loader/unix_spec.cr @@ -1,4 +1,4 @@ -{% skip_file if !flag?(:unix) || flag?(:wasm32) %} +{% skip_file if !flag?(:unix) || flag?(:wasi) %} require "./spec_helper" require "../spec_helper" From 9f72ef92673defde55b18edb02668c05e00799ee Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 16:10:22 -0300 Subject: [PATCH 37/41] Update spec/compiler/ffi/ffi_spec.cr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johannes Müller --- spec/compiler/ffi/ffi_spec.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/compiler/ffi/ffi_spec.cr b/spec/compiler/ffi/ffi_spec.cr index 4b70658e6bb8..8d18ec48f263 100644 --- a/spec/compiler/ffi/ffi_spec.cr +++ b/spec/compiler/ffi/ffi_spec.cr @@ -1,4 +1,4 @@ -{% skip_file if !flag?(:unix) || flag?(:without_ffi) || flag?(:wasm32) %} +{% skip_file if !flag?(:unix) || flag?(:without_ffi) || flag?(:wasi) %} require "../spec_helper" require "compiler/crystal/ffi" From fea289ad30e86cd0392b8755185cff703254b3a0 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 16:11:22 -0300 Subject: [PATCH 38/41] Revert "Update spec/compiler/loader/unix_spec.cr" This reverts commit ac74badcd5625771af3f658445c4559e26fce8db. --- spec/compiler/loader/unix_spec.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/compiler/loader/unix_spec.cr b/spec/compiler/loader/unix_spec.cr index c14dcc934cc3..cc2e9894b075 100644 --- a/spec/compiler/loader/unix_spec.cr +++ b/spec/compiler/loader/unix_spec.cr @@ -1,4 +1,4 @@ -{% skip_file if !flag?(:unix) || flag?(:wasi) %} +{% skip_file if !flag?(:unix) || flag?(:wasm32) %} require "./spec_helper" require "../spec_helper" From 53f6c25ea5fea53325790aa6ab785d8e39f937d2 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 16:11:35 -0300 Subject: [PATCH 39/41] Revert "Update spec/compiler/ffi/ffi_spec.cr" This reverts commit 9f72ef92673defde55b18edb02668c05e00799ee. --- spec/compiler/ffi/ffi_spec.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/compiler/ffi/ffi_spec.cr b/spec/compiler/ffi/ffi_spec.cr index 8d18ec48f263..4b70658e6bb8 100644 --- a/spec/compiler/ffi/ffi_spec.cr +++ b/spec/compiler/ffi/ffi_spec.cr @@ -1,4 +1,4 @@ -{% skip_file if !flag?(:unix) || flag?(:without_ffi) || flag?(:wasi) %} +{% skip_file if !flag?(:unix) || flag?(:without_ffi) || flag?(:wasm32) %} require "../spec_helper" require "compiler/crystal/ffi" From 5995375101194828dde763fb9b8f931607c432ea Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Tue, 8 Feb 2022 16:16:32 -0300 Subject: [PATCH 40/41] fix: correct usage of some wasm32<->wasi flags --- src/crystal/system/unix/arc4random.cr | 2 +- src/errno.cr | 4 ++-- src/io/file_descriptor.cr | 2 +- src/socket/common.cr | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/crystal/system/unix/arc4random.cr b/src/crystal/system/unix/arc4random.cr index 8aa9c608e4ea..4338e3341974 100644 --- a/src/crystal/system/unix/arc4random.cr +++ b/src/crystal/system/unix/arc4random.cr @@ -1,4 +1,4 @@ -{% skip_file unless flag?(:openbsd) || flag?(:netbsd) || flag?(:wasm32) %} +{% skip_file unless flag?(:openbsd) || flag?(:netbsd) %} require "c/stdlib" diff --git a/src/errno.cr b/src/errno.cr index 8b3134967ce7..cc05673b12f9 100644 --- a/src/errno.cr +++ b/src/errno.cr @@ -4,7 +4,7 @@ require "c/string" lib LibC {% if flag?(:linux) || flag?(:dragonfly) %} fun __errno_location : Int* - {% elsif flag?(:wasm32) %} + {% elsif flag?(:wasi) %} $errno : Int {% elsif flag?(:darwin) || flag?(:freebsd) %} fun __error : Int* @@ -45,7 +45,7 @@ enum Errno def self.value : self {% if flag?(:linux) || flag?(:dragonfly) %} Errno.new LibC.__errno_location.value - {% elsif flag?(:wasm32) %} + {% elsif flag?(:wasi) %} Errno.new LibC.errno {% elsif flag?(:darwin) || flag?(:bsd) %} Errno.new LibC.__error.value diff --git a/src/io/file_descriptor.cr b/src/io/file_descriptor.cr index 74b870ce75d6..d6a57a72fb9c 100644 --- a/src/io/file_descriptor.cr +++ b/src/io/file_descriptor.cr @@ -25,7 +25,7 @@ class IO::FileDescriptor < IO end end - unless blocking || {{ flag?(:win32) || flag?(:wasm32) }} + unless blocking || {{ flag?(:win32) || flag?(:wasi) }} self.blocking = false end end diff --git a/src/socket/common.cr b/src/socket/common.cr index e80c6f94f399..19f1700a2cbd 100644 --- a/src/socket/common.cr +++ b/src/socket/common.cr @@ -1,7 +1,7 @@ {% if flag?(:win32) %} require "c/ws2tcpip" require "c/afunix" -{% elsif flag?(:wasm32) %} +{% elsif flag?(:wasi) %} require "c/arpa/inet" require "c/netinet/in" {% else %} @@ -43,7 +43,7 @@ class Socket < IO enum Type STREAM = LibC::SOCK_STREAM DGRAM = LibC::SOCK_DGRAM - {% unless flag?(:wasm32) %} + {% unless flag?(:wasi) %} RAW = LibC::SOCK_RAW SEQPACKET = LibC::SOCK_SEQPACKET {% end %} From b0117612ddb6aef2b6960ad7ebc45452414fdf52 Mon Sep 17 00:00:00 2001 From: Guilherme Bernal Date: Fri, 11 Feb 2022 17:40:25 -0300 Subject: [PATCH 41/41] fix: home_path for wasi --- .github/workflows/smoke.yml | 2 +- src/crystal/system/path.cr | 4 +++- src/crystal/system/wasi/path.cr | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 src/crystal/system/wasi/path.cr diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 49acc40477ff..9c623f627e43 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -45,9 +45,9 @@ jobs: target: - aarch64-darwin - arm-linux-gnueabihf + - i386-linux-gnu - i386-linux-musl - wasm32-unknown-wasi - - i386-linux-gnu - x86_64-dragonfly - x86_64-freebsd - x86_64-netbsd diff --git a/src/crystal/system/path.cr b/src/crystal/system/path.cr index 17091ec3fc86..b421e1a46357 100644 --- a/src/crystal/system/path.cr +++ b/src/crystal/system/path.cr @@ -3,7 +3,9 @@ module Crystal::System::Path # def self.home : String end -{% if flag?(:unix) %} +{% if flag?(:wasi) %} + require "./wasi/path" +{% elsif flag?(:unix) %} require "./unix/path" {% elsif flag?(:win32) %} require "./win32/path" diff --git a/src/crystal/system/wasi/path.cr b/src/crystal/system/wasi/path.cr new file mode 100644 index 000000000000..5a570aa71dc8 --- /dev/null +++ b/src/crystal/system/wasi/path.cr @@ -0,0 +1,5 @@ +module Crystal::System::Path + def self.home : String + ENV["HOME"] + end +end