diff --git a/Sources/CSystem/include/CSystemWASI.h b/Sources/CSystem/include/CSystemWASI.h new file mode 100644 index 00000000..9877853e --- /dev/null +++ b/Sources/CSystem/include/CSystemWASI.h @@ -0,0 +1,31 @@ +/* + This source file is part of the Swift System open source project + + Copyright (c) 2024 Apple Inc. and the Swift System project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information +*/ + +#pragma once + +#if __wasi__ + +#include +#include + +// wasi-libc defines the following constants in a way that Clang Importer can't +// understand, so we need to expose them manually. +static inline int32_t _getConst_O_ACCMODE(void) { return O_ACCMODE; } +static inline int32_t _getConst_O_APPEND(void) { return O_APPEND; } +static inline int32_t _getConst_O_CREAT(void) { return O_CREAT; } +static inline int32_t _getConst_O_DIRECTORY(void) { return O_DIRECTORY; } +static inline int32_t _getConst_O_EXCL(void) { return O_EXCL; } +static inline int32_t _getConst_O_NONBLOCK(void) { return O_NONBLOCK; } +static inline int32_t _getConst_O_TRUNC(void) { return O_TRUNC; } +static inline int32_t _getConst_O_WRONLY(void) { return O_WRONLY; } + +static inline int32_t _getConst_EWOULDBLOCK(void) { return EWOULDBLOCK; } +static inline int32_t _getConst_EOPNOTSUPP(void) { return EOPNOTSUPP; } + +#endif diff --git a/Sources/CSystem/include/module.modulemap b/Sources/CSystem/include/module.modulemap index 776f7766..6e8b89e9 100644 --- a/Sources/CSystem/include/module.modulemap +++ b/Sources/CSystem/include/module.modulemap @@ -1,5 +1,6 @@ module CSystem { header "CSystemLinux.h" + header "CSystemWASI.h" header "CSystemWindows.h" export * } diff --git a/Sources/System/Errno.swift b/Sources/System/Errno.swift index 498ccbcf..093023d0 100644 --- a/Sources/System/Errno.swift +++ b/Sources/System/Errno.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift System open source project - Copyright (c) 2020 Apple Inc. and the Swift System project authors + Copyright (c) 2021 - 2024 Apple Inc. and the Swift System project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -226,7 +226,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "badAddress") public static var EFAULT: Errno { badAddress } -#if !os(Windows) +#if !os(Windows) && !os(WASI) /// Not a block device. /// /// You attempted a block device operation on a nonblock device or file. @@ -618,6 +618,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "protocolNotSupported") public static var EPROTONOSUPPORT: Errno { protocolNotSupported } +#if !os(WASI) /// Socket type not supported. /// /// Support for the socket type hasn't been configured into the system @@ -630,6 +631,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "socketTypeNotSupported") public static var ESOCKTNOSUPPORT: Errno { socketTypeNotSupported } +#endif /// Not supported. /// @@ -644,6 +646,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "notSupported") public static var ENOTSUP: Errno { notSupported } +#if !os(WASI) /// Protocol family not supported. /// /// The protocol family hasn't been configured into the system @@ -656,6 +659,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "protocolFamilyNotSupported") public static var EPFNOSUPPORT: Errno { protocolFamilyNotSupported } +#endif /// The address family isn't supported by the protocol family. /// @@ -802,6 +806,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "socketNotConnected") public static var ENOTCONN: Errno { socketNotConnected } +#if !os(WASI) /// Can't send after socket shutdown. /// /// A request to send data wasn't permitted @@ -815,6 +820,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "socketShutdown") public static var ESHUTDOWN: Errno { socketShutdown } +#endif /// Operation timed out. /// @@ -871,6 +877,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "fileNameTooLong") public static var ENAMETOOLONG: Errno { fileNameTooLong } +#if !os(WASI) /// The host is down. /// /// A socket operation failed because the destination host was down. @@ -882,6 +889,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "hostIsDown") public static var EHOSTDOWN: Errno { hostIsDown } +#endif /// No route to host. /// @@ -920,6 +928,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { public static var EPROCLIM: Errno { tooManyProcesses } #endif +#if !os(WASI) /// Too many users. /// /// The quota system ran out of table entries. @@ -931,6 +940,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "tooManyUsers") public static var EUSERS: Errno { tooManyUsers } +#endif /// Disk quota exceeded. /// @@ -1284,6 +1294,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "multiHop") public static var EMULTIHOP: Errno { multiHop } +#if !os(WASI) /// No message available. /// /// No message was available to be received by the requested operation. @@ -1295,6 +1306,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "noData") public static var ENODATA: Errno { noData } +#endif /// Reserved. /// @@ -1308,6 +1320,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "noLink") public static var ENOLINK: Errno { noLink } +#if !os(WASI) /// Reserved. /// /// This error is reserved for future use. @@ -1331,6 +1344,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "notStream") public static var ENOSTR: Errno { notStream } +#endif #endif /// Protocol error. @@ -1347,7 +1361,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { @available(*, unavailable, renamed: "protocolError") public static var EPROTO: Errno { protocolError } -#if !os(OpenBSD) +#if !os(OpenBSD) && !os(WASI) /// Reserved. /// /// This error is reserved for future use. @@ -1379,7 +1393,6 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable { // Constants defined in header but not man page @available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *) extension Errno { - /// Operation would block. /// /// The corresponding C error is `EWOULDBLOCK`. @@ -1390,6 +1403,7 @@ extension Errno { @available(*, unavailable, renamed: "wouldBlock") public static var EWOULDBLOCK: Errno { wouldBlock } +#if !os(WASI) /// Too many references: can't splice. /// /// The corresponding C error is `ETOOMANYREFS`. @@ -1409,6 +1423,7 @@ extension Errno { @_alwaysEmitIntoClient @available(*, unavailable, renamed: "tooManyRemoteLevels") public static var EREMOTE: Errno { tooManyRemoteLevels } +#endif #if SYSTEM_PACKAGE_DARWIN /// No such policy registered. diff --git a/Sources/System/Internals/CInterop.swift b/Sources/System/Internals/CInterop.swift index 3b4792e8..80d37d05 100644 --- a/Sources/System/Internals/CInterop.swift +++ b/Sources/System/Internals/CInterop.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift System open source project - Copyright (c) 2020 - 2021 Apple Inc. and the Swift System project authors + Copyright (c) 2020 - 2024 Apple Inc. and the Swift System project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -18,6 +18,11 @@ import Glibc #elseif canImport(Musl) @_implementationOnly import CSystem import Musl +#elseif canImport(WASILibc) +import WASILibc +#elseif canImport(Bionic) +@_implementationOnly import CSystem +import Bionic #else #error("Unsupported Platform") #endif diff --git a/Sources/System/Internals/Constants.swift b/Sources/System/Internals/Constants.swift index 8d4e4bb1..904e5b22 100644 --- a/Sources/System/Internals/Constants.swift +++ b/Sources/System/Internals/Constants.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift System open source project - Copyright (c) 2020 - 2021 Apple Inc. and the Swift System project authors + Copyright (c) 2020 - 2024 Apple Inc. and the Swift System project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -21,6 +21,11 @@ import Glibc #elseif canImport(Musl) import CSystem import Musl +#elseif canImport(WASILibc) +import CSystem +import WASILibc +#elseif canImport(Android) +import Android #else #error("Unsupported Platform") #endif @@ -73,7 +78,7 @@ internal var _EACCES: CInt { EACCES } @_alwaysEmitIntoClient internal var _EFAULT: CInt { EFAULT } -#if !os(Windows) +#if !os(Windows) && !os(WASI) @_alwaysEmitIntoClient internal var _ENOTBLK: CInt { ENOTBLK } #endif @@ -141,7 +146,13 @@ internal var _ERANGE: CInt { ERANGE } internal var _EAGAIN: CInt { EAGAIN } @_alwaysEmitIntoClient -internal var _EWOULDBLOCK: CInt { EWOULDBLOCK } +internal var _EWOULDBLOCK: CInt { +#if os(WASI) + _getConst_EWOULDBLOCK() +#else + EWOULDBLOCK +#endif +} @_alwaysEmitIntoClient internal var _EINPROGRESS: CInt { EINPROGRESS } @@ -167,6 +178,7 @@ internal var _ENOPROTOOPT: CInt { ENOPROTOOPT } @_alwaysEmitIntoClient internal var _EPROTONOSUPPORT: CInt { EPROTONOSUPPORT } +#if !os(WASI) @_alwaysEmitIntoClient internal var _ESOCKTNOSUPPORT: CInt { #if os(Windows) @@ -175,6 +187,7 @@ internal var _ESOCKTNOSUPPORT: CInt { return ESOCKTNOSUPPORT #endif } +#endif @_alwaysEmitIntoClient internal var _ENOTSUP: CInt { @@ -185,6 +198,7 @@ internal var _ENOTSUP: CInt { #endif } +#if !os(WASI) @_alwaysEmitIntoClient internal var _EPFNOSUPPORT: CInt { #if os(Windows) @@ -193,6 +207,7 @@ internal var _EPFNOSUPPORT: CInt { return EPFNOSUPPORT #endif } +#endif @_alwaysEmitIntoClient internal var _EAFNOSUPPORT: CInt { EAFNOSUPPORT } @@ -227,6 +242,7 @@ internal var _EISCONN: CInt { EISCONN } @_alwaysEmitIntoClient internal var _ENOTCONN: CInt { ENOTCONN } +#if !os(WASI) @_alwaysEmitIntoClient internal var _ESHUTDOWN: CInt { #if os(Windows) @@ -244,6 +260,7 @@ internal var _ETOOMANYREFS: CInt { return ETOOMANYREFS #endif } +#endif @_alwaysEmitIntoClient internal var _ETIMEDOUT: CInt { ETIMEDOUT } @@ -257,6 +274,7 @@ internal var _ELOOP: CInt { ELOOP } @_alwaysEmitIntoClient internal var _ENAMETOOLONG: CInt { ENAMETOOLONG } +#if !os(WASI) @_alwaysEmitIntoClient internal var _EHOSTDOWN: CInt { #if os(Windows) @@ -265,6 +283,7 @@ internal var _EHOSTDOWN: CInt { return EHOSTDOWN #endif } +#endif @_alwaysEmitIntoClient internal var _EHOSTUNREACH: CInt { EHOSTUNREACH } @@ -277,6 +296,7 @@ internal var _ENOTEMPTY: CInt { ENOTEMPTY } internal var _EPROCLIM: CInt { EPROCLIM } #endif +#if !os(WASI) @_alwaysEmitIntoClient internal var _EUSERS: CInt { #if os(Windows) @@ -285,6 +305,7 @@ internal var _EUSERS: CInt { return EUSERS #endif } +#endif @_alwaysEmitIntoClient internal var _EDQUOT: CInt { @@ -304,6 +325,7 @@ internal var _ESTALE: CInt { #endif } +#if !os(WASI) @_alwaysEmitIntoClient internal var _EREMOTE: CInt { #if os(Windows) @@ -312,6 +334,7 @@ internal var _EREMOTE: CInt { return EREMOTE #endif } +#endif #if SYSTEM_PACKAGE_DARWIN @_alwaysEmitIntoClient @@ -399,30 +422,41 @@ internal var _EBADMSG: CInt { EBADMSG } @_alwaysEmitIntoClient internal var _EMULTIHOP: CInt { EMULTIHOP } +#if !os(WASI) @_alwaysEmitIntoClient internal var _ENODATA: CInt { ENODATA } +#endif @_alwaysEmitIntoClient internal var _ENOLINK: CInt { ENOLINK } +#if !os(WASI) @_alwaysEmitIntoClient internal var _ENOSR: CInt { ENOSR } @_alwaysEmitIntoClient internal var _ENOSTR: CInt { ENOSTR } #endif +#endif @_alwaysEmitIntoClient internal var _EPROTO: CInt { EPROTO } -#if !os(OpenBSD) +#if !os(OpenBSD) && !os(WASI) @_alwaysEmitIntoClient internal var _ETIME: CInt { ETIME } #endif #endif + @_alwaysEmitIntoClient -internal var _EOPNOTSUPP: CInt { EOPNOTSUPP } +internal var _EOPNOTSUPP: CInt { +#if os(WASI) + _getConst_EOPNOTSUPP() +#else + EOPNOTSUPP +#endif +} #if SYSTEM_PACKAGE_DARWIN @_alwaysEmitIntoClient @@ -462,15 +496,33 @@ internal var _O_ACCMODE: CInt { 0x03|O_SEARCH } #else // TODO: API? @_alwaysEmitIntoClient -internal var _O_ACCMODE: CInt { O_ACCMODE } +internal var _O_ACCMODE: CInt { +#if os(WASI) + _getConst_O_ACCMODE() +#else + O_ACCMODE +#endif +} #endif @_alwaysEmitIntoClient -internal var _O_NONBLOCK: CInt { O_NONBLOCK } +internal var _O_NONBLOCK: CInt { +#if os(WASI) + _getConst_O_NONBLOCK() +#else + O_NONBLOCK +#endif +} #endif @_alwaysEmitIntoClient -internal var _O_APPEND: CInt { O_APPEND } +internal var _O_APPEND: CInt { +#if os(WASI) + _getConst_O_APPEND() +#else + O_APPEND +#endif +} #if SYSTEM_PACKAGE_DARWIN @_alwaysEmitIntoClient @@ -481,22 +533,42 @@ internal var _O_EXLOCK: CInt { O_EXLOCK } #endif #if !os(Windows) +#if !os(WASI) // TODO: API? @_alwaysEmitIntoClient internal var _O_ASYNC: CInt { O_ASYNC } +#endif @_alwaysEmitIntoClient internal var _O_NOFOLLOW: CInt { O_NOFOLLOW } #endif @_alwaysEmitIntoClient -internal var _O_CREAT: CInt { O_CREAT } +internal var _O_CREAT: CInt { +#if os(WASI) + _getConst_O_CREAT() +#else + O_CREAT +#endif +} @_alwaysEmitIntoClient -internal var _O_TRUNC: CInt { O_TRUNC } +internal var _O_TRUNC: CInt { +#if os(WASI) + _getConst_O_TRUNC() +#else + O_TRUNC +#endif +} @_alwaysEmitIntoClient -internal var _O_EXCL: CInt { O_EXCL } +internal var _O_EXCL: CInt { +#if os(WASI) + _getConst_O_EXCL() +#else + O_EXCL +#endif +} #if SYSTEM_PACKAGE_DARWIN @_alwaysEmitIntoClient @@ -509,7 +581,13 @@ internal var _O_EVTONLY: CInt { O_EVTONLY } internal var _O_NOCTTY: CInt { O_NOCTTY } @_alwaysEmitIntoClient -internal var _O_DIRECTORY: CInt { O_DIRECTORY } +internal var _O_DIRECTORY: CInt { +#if os(WASI) + _getConst_O_DIRECTORY() +#else + O_DIRECTORY +#endif +} #endif #if SYSTEM_PACKAGE_DARWIN diff --git a/Sources/System/Internals/Exports.swift b/Sources/System/Internals/Exports.swift index e20454ee..d18102a2 100644 --- a/Sources/System/Internals/Exports.swift +++ b/Sources/System/Internals/Exports.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift System open source project - Copyright (c) 2020 - 2021 Apple Inc. and the Swift System project authors + Copyright (c) 2020 - 2024 Apple Inc. and the Swift System project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -23,6 +23,11 @@ import Glibc #elseif canImport(Musl) @_implementationOnly import CSystem import Musl +#elseif canImport(WASILibc) +import WASILibc +#elseif canImport(Android) +@_implementationOnly import CSystem +import Android #else #error("Unsupported Platform") #endif @@ -58,6 +63,16 @@ internal var system_errno: CInt { get { Musl.errno } set { Musl.errno = newValue } } +#elseif canImport(WASILibc) +internal var system_errno: CInt { + get { WASILibc.errno } + set { WASILibc.errno = newValue } +} +#elseif canImport(Android) +internal var system_errno: CInt { + get { Android.errno } + set { Android.errno = newValue } +} #endif // MARK: C stdlib decls @@ -149,6 +164,24 @@ extension String { // TLS #if os(Windows) internal typealias _PlatformTLSKey = DWORD +#elseif os(WASI) && (swift(<6.1) || !_runtime(_multithreaded)) +// Mock TLS storage for single-threaded WASI +internal final class _PlatformTLSKey { + fileprivate init() {} +} +private final class TLSStorage: @unchecked Sendable { + var storage = [ObjectIdentifier: UnsafeMutableRawPointer]() +} +private let sharedTLSStorage = TLSStorage() + +func pthread_setspecific(_ key: _PlatformTLSKey, _ p: UnsafeMutableRawPointer?) -> Int { + sharedTLSStorage.storage[ObjectIdentifier(key)] = p + return 0 +} + +func pthread_getspecific(_ key: _PlatformTLSKey) -> UnsafeMutableRawPointer? { + sharedTLSStorage.storage[ObjectIdentifier(key)] +} #else internal typealias _PlatformTLSKey = pthread_key_t #endif @@ -160,6 +193,8 @@ internal func makeTLSKey() -> _PlatformTLSKey { fatalError("Unable to create key") } return raw + #elseif os(WASI) && (swift(<6.1) || !_runtime(_multithreaded)) + return _PlatformTLSKey() #else var raw = pthread_key_t() guard 0 == pthread_key_create(&raw, nil) else { diff --git a/Sources/System/Internals/Syscalls.swift b/Sources/System/Internals/Syscalls.swift index 3794d6e0..6f885be5 100644 --- a/Sources/System/Internals/Syscalls.swift +++ b/Sources/System/Internals/Syscalls.swift @@ -17,6 +17,8 @@ import Musl import WASILibc #elseif os(Windows) import ucrt +#elseif canImport(Android) +import Android #else #error("Unsupported Platform") #endif @@ -189,7 +191,7 @@ internal func system_confstr( internal let SYSTEM_AT_REMOVE_DIR = AT_REMOVEDIR internal let SYSTEM_DT_DIR = DT_DIR internal typealias system_dirent = dirent -#if os(Linux) +#if os(Linux) || os(Android) internal typealias system_DIRPtr = OpaquePointer #else internal typealias system_DIRPtr = UnsafeMutablePointer