Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
if(ANDROID)
set(CMAKE_HAVE_LIBC_PTHREAD YES)
elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI")
# wasi-libc provides pthread stubs directly. Static-library try_compile
# cannot prove that by linking, and -pthread selects the unsupported
# threaded ABI instead of the single-threaded wasip1 target.
set(CMAKE_HAVE_LIBC_PTHREAD YES CACHE BOOL "WASI pthread stubs are in libc")
set(THREADS_PREFER_PTHREAD_FLAG OFF)
endif()
find_package(Threads REQUIRED)

Expand All @@ -115,6 +121,9 @@ include(CheckLibraryExists)
include(CheckLinkerFlag)
include(CheckSymbolExists)
include(GNUInstallDirs)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(BUILD_TESTING ON CACHE BOOL "build WASI smoke and policy tests")
endif()
include(CTest)

include(DispatchAppleOptions)
Expand All @@ -127,16 +136,28 @@ include(EnableFramePointers)
# NOTE(abdulras) this is the CMake supported way to control whether we generate
# shared or static libraries. This impacts the behaviour of `add_library` in
# what type of library it generates.
option(BUILD_SHARED_LIBS "build shared libraries" ON)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(BUILD_SHARED_LIBS_DEFAULT OFF)
else()
set(BUILD_SHARED_LIBS_DEFAULT ON)
endif()
option(BUILD_SHARED_LIBS "build shared libraries" ${BUILD_SHARED_LIBS_DEFAULT})

option(DISPATCH_ENABLE_ASSERTS "enable debug assertions" FALSE)

option(ENABLE_DISPATCH_INIT_CONSTRUCTOR "enable libdispatch_init as a constructor" ON)
set(USE_LIBDISPATCH_INIT_CONSTRUCTOR ${ENABLE_DISPATCH_INIT_CONSTRUCTOR})

option(ENABLE_DTRACE "enable dtrace support" "")
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(ENABLE_DTRACE_DEFAULT OFF)
else()
set(ENABLE_DTRACE_DEFAULT "")
endif()
option(ENABLE_DTRACE "enable dtrace support" "${ENABLE_DTRACE_DEFAULT}")

if(APPLE OR BSD)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(ENABLE_INTERNAL_PTHREAD_WORKQUEUES_DEFAULT ON)
elseif(APPLE OR BSD)
set(ENABLE_INTERNAL_PTHREAD_WORKQUEUES_DEFAULT OFF)
else()
set(ENABLE_INTERNAL_PTHREAD_WORKQUEUES_DEFAULT ON)
Expand Down Expand Up @@ -166,6 +187,29 @@ endif()
option(ENABLE_THREAD_LOCAL_STORAGE "enable usage of thread local storage via _Thread_local" ON)
set(DISPATCH_USE_THREAD_LOCAL_STORAGE ${ENABLE_THREAD_LOCAL_STORAGE})

if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
# CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY makes link-dependent checks
# compile-only. These values are the exported-symbol set of Swift 6.3.2's
# single-threaded wasip1 libc.a; cache entries remain caller-overridable.
set(HAVE__PTHREAD_WORKQUEUE_INIT 0 CACHE BOOL "WASI libc result")
set(HAVE_GETPROGNAME 0 CACHE BOOL "WASI libc result")
set(HAVE_MACH_ABSOLUTE_TIME 0 CACHE BOOL "WASI libc result")
set(HAVE_MACH_APPROXIMATE_TIME 0 CACHE BOOL "WASI libc result")
set(HAVE_MACH_PORT_CONSTRUCT 0 CACHE BOOL "WASI libc result")
set(HAVE_MALLOC_CREATE_ZONE 0 CACHE BOOL "WASI libc result")
set(HAVE_POSIX_FADVISE 1 CACHE BOOL "WASI libc result")
set(HAVE_POSIX_SPAWNP 0 CACHE BOOL "WASI libc result")
set(HAVE_PTHREAD_KEY_INIT_NP 0 CACHE BOOL "WASI libc result")
set(HAVE_PTHREAD_ATTR_SETCPUPERCENT_NP 0 CACHE BOOL "WASI libc result")
set(HAVE_PTHREAD_YIELD_NP 0 CACHE BOOL "WASI libc result")
set(HAVE_PTHREAD_MAIN_NP 0 CACHE BOOL "WASI libc result")
set(HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP 0 CACHE BOOL "WASI libc result")
set(HAVE_STRLCPY 1 CACHE BOOL "WASI libc result")
set(HAVE_SYSCONF 1 CACHE BOOL "WASI libc result")
set(HAVE_ARC4RANDOM 1 CACHE BOOL "WASI libc result")
set(USE_POSIX_SEM 0 CACHE BOOL "WASI libc result")
endif()


check_linker_flag(C "LINKER:--build-id=sha1" LINKER_SUPPORTS_BUILD_ID)

Expand Down Expand Up @@ -306,7 +350,10 @@ if(leaks_EXECUTABLE)
endif()


if(APPLE)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/wasi/module.modulemap>
$<$<COMPILE_LANGUAGE:C,CXX>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/generic/module.modulemap>)
elseif(APPLE)
add_compile_options($<:$<COMPILE_LANGUAGE:C,CXX>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap>
$<:$<COMPILE_LANGUAGE:C,CXX>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/darwin/module.modulemap>)
else()
Expand Down
104 changes: 104 additions & 0 deletions cmake/toolchains/WASI.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
if(CMAKE_VERSION VERSION_LESS 3.31)
message(FATAL_ERROR
"WASI builds require CMake 3.31 or newer for CMAKE_SYSTEM_NAME=WASI support")
endif()

set(CMAKE_SYSTEM_NAME WASI)
set(CMAKE_SYSTEM_PROCESSOR wasm32)

set(SWIFT_WASI_TOOLCHAIN_PATH "${SWIFT_WASI_TOOLCHAIN_PATH}" CACHE PATH
"Host Swift .xctoolchain used to build for WASI")
set(SWIFT_WASI_SDK_PATH "${SWIFT_WASI_SDK_PATH}" CACHE PATH
"wasm32-unknown-wasip1 directory in a Swift WASI SDK")
set(SWIFT_WASI_STATIC_RESOURCES_OVERRIDE "" CACHE PATH
"Optional override for the Swift static resource directory")
set(DISPATCH_WASI_BUILTINS_OVERRIDE "" CACHE FILEPATH
"Optional override for the WASI compiler-rt builtins archive")
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
SWIFT_WASI_TOOLCHAIN_PATH
SWIFT_WASI_SDK_PATH
SWIFT_WASI_STATIC_RESOURCES_OVERRIDE
DISPATCH_WASI_BUILTINS_OVERRIDE)

if(NOT SWIFT_WASI_TOOLCHAIN_PATH)
message(FATAL_ERROR "Set SWIFT_WASI_TOOLCHAIN_PATH to the host Swift .xctoolchain")
endif()
if(NOT SWIFT_WASI_SDK_PATH)
message(FATAL_ERROR "Set SWIFT_WASI_SDK_PATH to the wasm32-unknown-wasip1 SDK directory")
endif()

if(NOT IS_DIRECTORY "${SWIFT_WASI_TOOLCHAIN_PATH}")
message(FATAL_ERROR "SWIFT_WASI_TOOLCHAIN_PATH is not a directory: ${SWIFT_WASI_TOOLCHAIN_PATH}")
endif()
if(NOT IS_DIRECTORY "${SWIFT_WASI_SDK_PATH}")
message(FATAL_ERROR "SWIFT_WASI_SDK_PATH is not a directory: ${SWIFT_WASI_SDK_PATH}")
endif()

set(_dispatch_wasi_clang "${SWIFT_WASI_TOOLCHAIN_PATH}/usr/bin/clang")
set(_dispatch_wasi_clangxx "${SWIFT_WASI_TOOLCHAIN_PATH}/usr/bin/clang++")
set(_dispatch_wasi_ar "${SWIFT_WASI_TOOLCHAIN_PATH}/usr/bin/llvm-ar")
set(_dispatch_wasi_ranlib "${SWIFT_WASI_TOOLCHAIN_PATH}/usr/bin/llvm-ranlib")
set(_dispatch_wasi_swiftc "${SWIFT_WASI_TOOLCHAIN_PATH}/usr/bin/swiftc")
set(_dispatch_wasi_sysroot "${SWIFT_WASI_SDK_PATH}/WASI.sdk")

foreach(_dispatch_wasi_tool IN ITEMS
"${_dispatch_wasi_clang}"
"${_dispatch_wasi_clangxx}"
"${_dispatch_wasi_ar}"
"${_dispatch_wasi_ranlib}")
if(NOT EXISTS "${_dispatch_wasi_tool}")
message(FATAL_ERROR "Required WASI build tool does not exist: ${_dispatch_wasi_tool}")
endif()
endforeach()
if(NOT IS_DIRECTORY "${_dispatch_wasi_sysroot}")
message(FATAL_ERROR "WASI sysroot does not exist: ${_dispatch_wasi_sysroot}")
endif()

if(SWIFT_WASI_STATIC_RESOURCES_OVERRIDE)
set(SWIFT_WASI_STATIC_RESOURCES "${SWIFT_WASI_STATIC_RESOURCES_OVERRIDE}")
else()
set(SWIFT_WASI_STATIC_RESOURCES
"${SWIFT_WASI_SDK_PATH}/swift.xctoolchain/usr/lib/swift_static")
endif()
if(DISPATCH_WASI_BUILTINS_OVERRIDE)
set(DISPATCH_WASI_BUILTINS "${DISPATCH_WASI_BUILTINS_OVERRIDE}")
else()
set(DISPATCH_WASI_BUILTINS
"${SWIFT_WASI_SDK_PATH}/swift.xctoolchain/usr/lib/clang/lib/wasip1/libclang_rt.builtins-wasm32.a")
endif()
set(SWIFT_WASI_CLANG_RESOURCES
"${SWIFT_WASI_SDK_PATH}/swift.xctoolchain/usr/lib/clang")
if(NOT IS_DIRECTORY "${SWIFT_WASI_STATIC_RESOURCES}")
message(FATAL_ERROR
"Swift static resource directory does not exist: ${SWIFT_WASI_STATIC_RESOURCES}")
endif()
if(NOT EXISTS "${DISPATCH_WASI_BUILTINS}")
message(FATAL_ERROR "WASI builtins archive does not exist: ${DISPATCH_WASI_BUILTINS}")
endif()
if(NOT IS_DIRECTORY "${SWIFT_WASI_CLANG_RESOURCES}")
message(FATAL_ERROR
"WASI Clang resource directory does not exist: ${SWIFT_WASI_CLANG_RESOURCES}")
endif()

set(CMAKE_C_COMPILER "${_dispatch_wasi_clang}")
set(CMAKE_CXX_COMPILER "${_dispatch_wasi_clangxx}")
set(CMAKE_AR "${_dispatch_wasi_ar}")
set(CMAKE_RANLIB "${_dispatch_wasi_ranlib}")
set(CMAKE_C_COMPILER_TARGET wasm32-unknown-wasip1)
set(CMAKE_CXX_COMPILER_TARGET wasm32-unknown-wasip1)
set(CMAKE_SYSROOT "${_dispatch_wasi_sysroot}")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_EXECUTABLE_SUFFIX .wasm)

if(ENABLE_SWIFT)
if(NOT EXISTS "${_dispatch_wasi_swiftc}")
message(FATAL_ERROR "Swift compiler does not exist: ${_dispatch_wasi_swiftc}")
endif()
set(CMAKE_Swift_COMPILER "${_dispatch_wasi_swiftc}")
set(CMAKE_Swift_COMPILER_TARGET wasm32-unknown-wasip1)
set(CMAKE_Swift_FLAGS
"-sdk \"${CMAKE_SYSROOT}\" -resource-dir \"${SWIFT_WASI_STATIC_RESOURCES}\"")
set(dispatch_MODULE_TRIPLE wasm32-unknown-wasip1 CACHE STRING "Swift module triple")
set(dispatch_ARCH wasm32 CACHE STRING "Swift architecture")
set(dispatch_PLATFORM wasi CACHE STRING "Swift platform")
endif()
5 changes: 3 additions & 2 deletions dispatch/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

if(APPLE)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/wasi/module.modulemap)
elseif(APPLE)
set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap)
else()
set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/generic/module.modulemap)
Expand Down Expand Up @@ -30,4 +32,3 @@ if(ENABLE_SWIFT)
DESTINATION
"${INSTALL_DISPATCH_HEADERS_DIR}")
endif()

5 changes: 3 additions & 2 deletions dispatch/dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <os/base.h>
#elif defined(_WIN32)
#include <os/generic_win_base.h>
#elif defined(__unix__)
#elif defined(__unix__) || defined(__wasi__)
#include <os/generic_unix_base.h>
#endif

Expand All @@ -38,7 +38,8 @@
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || \
defined(__wasi__)
#include <unistd.h>
#endif
#include <fcntl.h>
Expand Down
27 changes: 27 additions & 0 deletions dispatch/wasi/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Dispatch {
requires blocks
export *
link "dispatch"
link "BlocksRuntime"
link "wasi-emulated-signal"
link "wasi-emulated-mman"
link "wasi-emulated-getpid"
}

module DispatchIntrospection [system] [extern_c] {
header "introspection.h"
export *
}

module CDispatch [system] [extern_c] {
umbrella header "dispatch.h"
export *
requires blocks
link "dispatch"
// Static WASI clients need explicit BlocksRuntime autolinking. Keep this
// in the WASI module map so generic Linux and Windows clients are unchanged.
link "BlocksRuntime"
link "wasi-emulated-signal"
link "wasi-emulated-mman"
link "wasi-emulated-getpid"
}
15 changes: 15 additions & 0 deletions os/generic_unix_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@
#include <libutil.h>
#include <fcntl.h>
#endif
#if defined(__wasi__)
/*
* Include <sys/types.h> before the textual <sys/param.h>. This only
* matters when this header is parsed into the CDispatch clang module by
* Swift's ClangImporter (plain C builds are unaffected): the toolchain's
* wasi-libc.modulemap declares <sys/types.h> as a header of the
* SwiftWASILibc module but leaves <sys/param.h> and <endian.h> textual,
* so the static inline __bswap* definitions from <endian.h> end up both
* inside SwiftWASILibc (via <sys/types.h>) and textually in CDispatch
* (via <sys/param.h>), which clang rejects as redefinitions. Importing
* the module first makes its include guards visible, so the textual
* re-include below is skipped instead of redefining them.
*/
#include <sys/types.h>
#endif
#include <sys/param.h>

#if __has_include(<sys/cdefs.h>)
Expand Down
2 changes: 1 addition & 1 deletion os/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <os/base.h>
#elif defined(_WIN32)
#include <os/generic_win_base.h>
#elif defined(__unix__)
#elif defined(__unix__) || defined(__wasi__)
#include <os/generic_unix_base.h>
#endif

Expand Down
18 changes: 18 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ add_library(dispatch
event/event_epoll.c
event/event_internal.h
event/event_kevent.c
event/event_wasi.c
event/event_windows.c
firehose/firehose_internal.h
shims/android_stubs.h
Expand Down Expand Up @@ -105,6 +106,17 @@ if(WIN32)
elseif(ANDROID)
target_compile_options(dispatch PRIVATE
-U_GNU_SOURCE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI")
target_compile_definitions(dispatch PRIVATE
DISPATCH_HW_CONFIG_UP=1)
target_compile_definitions(dispatch PUBLIC
"$<$<COMPILE_LANGUAGE:C,CXX>:_WASI_EMULATED_SIGNAL>"
"$<$<COMPILE_LANGUAGE:C,CXX>:_WASI_EMULATED_MMAN>"
"$<$<COMPILE_LANGUAGE:C,CXX>:_WASI_EMULATED_GETPID>")
target_compile_options(dispatch INTERFACE
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -D_WASI_EMULATED_SIGNAL>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -D_WASI_EMULATED_MMAN>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xcc -D_WASI_EMULATED_GETPID>")
endif()
if(DISPATCH_ENABLE_ASSERTS)
target_compile_definitions(dispatch PRIVATE
Expand Down Expand Up @@ -152,6 +164,12 @@ target_link_libraries(dispatch PRIVATE
Threads::Threads)
target_link_libraries(dispatch PUBLIC
BlocksRuntime::BlocksRuntime)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
target_link_libraries(dispatch PUBLIC
wasi-emulated-signal
wasi-emulated-mman
wasi-emulated-getpid)
endif()
if(WIN32)
target_link_libraries(dispatch PRIVATE
AdvAPI32
Expand Down
10 changes: 9 additions & 1 deletion src/event/event_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,27 @@
#ifndef __DISPATCH_EVENT_EVENT_CONFIG__
#define __DISPATCH_EVENT_EVENT_CONFIG__

#if defined(__linux__)
#if defined(__wasi__)
# define DISPATCH_EVENT_BACKEND_EPOLL 0
# define DISPATCH_EVENT_BACKEND_KEVENT 0
# define DISPATCH_EVENT_BACKEND_WASI 1
# define DISPATCH_EVENT_BACKEND_WINDOWS 0
#elif defined(__linux__)
# include <sys/eventfd.h>
# define DISPATCH_EVENT_BACKEND_EPOLL 1
# define DISPATCH_EVENT_BACKEND_KEVENT 0
# define DISPATCH_EVENT_BACKEND_WASI 0
# define DISPATCH_EVENT_BACKEND_WINDOWS 0
#elif __has_include(<sys/event.h>)
# include <sys/event.h>
# define DISPATCH_EVENT_BACKEND_EPOLL 0
# define DISPATCH_EVENT_BACKEND_KEVENT 1
# define DISPATCH_EVENT_BACKEND_WASI 0
# define DISPATCH_EVENT_BACKEND_WINDOWS 0
#elif defined(_WIN32)
# define DISPATCH_EVENT_BACKEND_EPOLL 0
# define DISPATCH_EVENT_BACKEND_KEVENT 0
# define DISPATCH_EVENT_BACKEND_WASI 0
# define DISPATCH_EVENT_BACKEND_WINDOWS 1
#else
# error unsupported event loop
Expand Down
13 changes: 13 additions & 0 deletions src/event/event_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,19 @@ void _dispatch_event_loop_timer_delete(dispatch_timer_heap_t dth, uint32_t tidx)

void _dispatch_event_loop_drain_timers(dispatch_timer_heap_t dth, uint32_t count);

#if DISPATCH_EVENT_BACKEND_WASI
// Cooperative drain for single-threaded WASI. The pending-work bookkeeping
// and the drain loop live in event_wasi.c; the actual queue draining is
// implemented in queue.c (it needs the static drain machinery there).
void _dispatch_wasi_drain(void);
void _dispatch_wasi_root_queue_poke(dispatch_queue_global_t dq);
void _dispatch_wasi_main_queue_poke(void);
// implemented in queue.c on behalf of the WASI event backend:
void _dispatch_wasi_root_queue_drain(dispatch_queue_global_t dq);
void _dispatch_wasi_mgr_queue_drain(void);
void _dispatch_wasi_main_queue_drain(void);
#endif // DISPATCH_EVENT_BACKEND_WASI

DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_timers_heap_dirty(dispatch_timer_heap_t dth, uint32_t tidx)
Expand Down
Loading