From 4bebdf955fb40a8c6a673386595cc589b70906a1 Mon Sep 17 00:00:00 2001 From: Alex Sh Date: Fri, 8 Sep 2023 16:13:58 +0200 Subject: [PATCH 001/102] Update Queue.swift Duplicate and unfinished line in the DispatchQueue documentation --- src/swift/Queue.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index ac9c9611a..1e0aea3c8 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -240,7 +240,6 @@ extension DispatchQueue { /// /// - parameter group: the dispatch group to associate with the submitted /// work item. If this is `nil`, the work item is not associated with a group. - /// - parameter flags: flags that control the execution environment of the /// - parameter qos: the QoS at which the work item should be executed. /// Defaults to `DispatchQoS.unspecified`. /// - parameter flags: flags that control the execution environment of the From be275d48811d26377e856544a05312c8994c9c6c Mon Sep 17 00:00:00 2001 From: Frederik Seiffert Date: Wed, 23 Feb 2022 09:41:28 +0100 Subject: [PATCH 002/102] [Win32] Initialize COM library on queue threads --- src/queue.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/queue.c b/src/queue.c index efafe923f..40f059c7a 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6264,8 +6264,13 @@ _dispatch_worker_thread(void *context) static unsigned WINAPI _dispatch_worker_thread_thunk(LPVOID lpParameter) { - _dispatch_worker_thread(lpParameter); - return 0; + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); + if (FAILED(hr)) { + _dispatch_client_assert_fail("Error %ld initializing Windows Runtime", hr); + } + _dispatch_worker_thread(lpParameter); + CoUninitialize(); + return 0; } #endif // defined(_WIN32) #endif // DISPATCH_USE_PTHREAD_POOL From 29babc17e2559339e48c163f4c02ed3356a7123f Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Thu, 14 Dec 2023 08:02:12 +0400 Subject: [PATCH 003/102] Avoid using rand() that leads to a lock contention Fixes https://github.com/apple/swift-corelibs-libdispatch/issues/760 --- src/shims/yield.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/shims/yield.h b/src/shims/yield.h index 53eb80065..ee47de5b4 100644 --- a/src/shims/yield.h +++ b/src/shims/yield.h @@ -98,22 +98,17 @@ void *_dispatch_wait_for_enqueuer(void **ptr); #define _dispatch_contention_spins() \ ((DISPATCH_CONTENTION_SPINS_MIN) + ((DISPATCH_CONTENTION_SPINS_MAX) - \ (DISPATCH_CONTENTION_SPINS_MIN)) / 2) -#elif defined(_WIN32) +#else // Use randomness to prevent threads from resonating at the same frequency and // permanently contending. Windows doesn't provide rand_r(), so use a simple // LCG. (msvcrt has rand_s(), but its security guarantees aren't optimal here.) +// The implementation of rand() can contain a lock (known with glibc at least). #define _dispatch_contention_spins() ({ \ static os_atomic(unsigned int) _seed = 1; \ unsigned int _next = os_atomic_load(&_seed, relaxed); \ os_atomic_store(&_seed, _next * 1103515245 + 12345, relaxed); \ ((_next >> 24) & (DISPATCH_CONTENTION_SPINS_MAX)) | \ (DISPATCH_CONTENTION_SPINS_MIN); }) -#else -// Use randomness to prevent threads from resonating at the same -// frequency and permanently contending. -#define _dispatch_contention_spins() ({ \ - ((unsigned int)rand() & (DISPATCH_CONTENTION_SPINS_MAX)) | \ - (DISPATCH_CONTENTION_SPINS_MIN); }) #endif #define _dispatch_contention_wait_until(c) ({ \ bool _out = false; \ From d92618a82c23ba4dd1db8d7b650ffd0c34cc8be3 Mon Sep 17 00:00:00 2001 From: Rose <83477269+AtariDreams@users.noreply.github.com> Date: Fri, 15 Dec 2023 14:44:33 -0500 Subject: [PATCH 004/102] Prefer aligned_alloc over posix_memalign aligned_alloc is more cleaner and portable. --- src/io.c | 5 +---- tests/dispatch_io.c | 2 +- tests/dispatch_read2.c | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/io.c b/src/io.c index e31e28c82..70c6721be 100644 --- a/src/io.c +++ b/src/io.c @@ -2374,10 +2374,7 @@ _dispatch_operation_perform(dispatch_operation_t op) } op->buf = _aligned_malloc(op->buf_siz, siInfo.dwPageSize); #else - err = posix_memalign(&op->buf, (size_t)PAGE_SIZE, op->buf_siz); - if (err != 0) { - goto error; - } + op->buf = aligned_alloc((size_t)PAGE_SIZE, op->buf_siz) #endif _dispatch_op_debug("buffer allocated", op); } else if (op->direction == DOP_DIR_WRITE) { diff --git a/tests/dispatch_io.c b/tests/dispatch_io.c index fbfcb6055..a5a1cea67 100644 --- a/tests/dispatch_io.c +++ b/tests/dispatch_io.c @@ -398,7 +398,7 @@ test_async_read(char *path, size_t size, int option, dispatch_queue_t queue, buffer = _aligned_malloc(size, si.dwPageSize); #else size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); - posix_memalign((void **)&buffer, pagesize, size); + buffer = aligned_alloc(pagesize, size); #endif ssize_t r = dispatch_test_fd_read(fd, buffer, size); if (r == -1) { diff --git a/tests/dispatch_read2.c b/tests/dispatch_read2.c index 0e4535961..401fb4f62 100644 --- a/tests/dispatch_read2.c +++ b/tests/dispatch_read2.c @@ -91,7 +91,7 @@ dispatch_read2(dispatch_fd_t fd, buffer = _aligned_malloc(bufsiz, pagesize); #else size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); - posix_memalign((void **)&buffer, pagesize, bufsiz); + buffer = aligned_alloc(pagesize, bufsiz); #endif ssize_t actual = dispatch_test_fd_read(fd, buffer, bufsiz); if (actual == -1) { From 116709451b43510d98afbb4b66f05f3d2db39250 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Tue, 13 Feb 2024 10:22:28 -0800 Subject: [PATCH 005/102] Support Windows ARM64 builds --- cmake/modules/DispatchWindowsSupport.cmake | 2 +- cmake/modules/SwiftSupport.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/DispatchWindowsSupport.cmake b/cmake/modules/DispatchWindowsSupport.cmake index 87675a78a..750b3be11 100644 --- a/cmake/modules/DispatchWindowsSupport.cmake +++ b/cmake/modules/DispatchWindowsSupport.cmake @@ -6,7 +6,7 @@ function(dispatch_windows_arch_spelling arch var) set(${var} x64 PARENT_SCOPE) elseif(${arch} STREQUAL armv7) set(${var} arm PARENT_SCOPE) - elseif(${arch} STREQUAL aarch64) + elseif(${arch} STREQUAL aarch64 OR ${arch} STREQUAL ARM64) set(${var} arm64 PARENT_SCOPE) else() message(FATAL_ERROR "do not know MSVC spelling for ARCH: `${arch}`") diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 702dd6c8f..a42b61e40 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -9,7 +9,7 @@ function(get_swift_host_arch result_var_name) if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") set("${result_var_name}" "x86_64" PARENT_SCOPE) - elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "AArch64|aarch64|arm64") + elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "AArch64|aarch64|arm64|ARM64") if(CMAKE_SYSTEM_NAME MATCHES Darwin) set("${result_var_name}" "arm64" PARENT_SCOPE) else() From 5460cefb493c88f577b8504de5c9718759e04a1b Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Thu, 15 Feb 2024 15:16:20 +0100 Subject: [PATCH 006/102] Support compiling on MinGW --- CMakeLists.txt | 32 ++++++++++++++++---- cmake/modules/DispatchCompilerWarnings.cmake | 4 ++- os/generic_win_base.h | 3 ++ src/event/workqueue.c | 5 +++ src/shims/generic_win_stubs.h | 2 ++ tests/generic_win_port.c | 2 ++ tests/generic_win_port.h | 4 +++ 7 files changed, 45 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57a37d3b5..cd77f499c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,14 +18,18 @@ if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") endif() if(CMAKE_SYSTEM_NAME STREQUAL Windows) - include(DispatchWindowsSupport) - dispatch_windows_arch_spelling(${CMAKE_SYSTEM_PROCESSOR} DISPATCH_MSVC_ARCH) - dispatch_windows_include_for_arch(${DISPATCH_MSVC_ARCH} DISPATCH_INCLUDES) - include_directories(BEFORE SYSTEM ${DISPATCH_INCLUDES}) - dispatch_windows_lib_for_arch(${CMAKE_SYSTEM_PROCESSOR} DISPATCH_LIBDIR) - link_directories(${DISPATCH_LIBDIR}) + if(NOT MINGW) + include(DispatchWindowsSupport) + dispatch_windows_arch_spelling(${CMAKE_SYSTEM_PROCESSOR} DISPATCH_MSVC_ARCH) + dispatch_windows_include_for_arch(${DISPATCH_MSVC_ARCH} DISPATCH_INCLUDES) + include_directories(BEFORE SYSTEM ${DISPATCH_INCLUDES}) + dispatch_windows_lib_for_arch(${CMAKE_SYSTEM_PROCESSOR} DISPATCH_LIBDIR) + link_directories(${DISPATCH_LIBDIR}) + endif() include(CheckCSourceCompiles) + include(CheckSymbolExists) + check_c_source_compiles([=[ #include int main(int argc, char *argv[]) { @@ -54,6 +58,22 @@ int main(int argc, char *argv[]) { if(DISPATCH_HAVE_EXTENDED_SLPI_22000) add_compile_definitions(DISPATCH_HAVE_EXTENDED_SLPI_22000) endif() + + check_c_source_compiles([=[ +#include +#include +int main(int argc, char *argv[]) { + FILE_PIPE_LOCAL_INFORMATION fpli; +} +]=] HAVE_FILE_PIPE_LOCAL_INFORMATION) + if(HAVE_FILE_PIPE_LOCAL_INFORMATION) + add_compile_definitions(HAVE_FILE_PIPE_LOCAL_INFORMATION) + endif() + + check_symbol_exists(mkstemp "stdlib.h" HAVE_MKSTEMP) + if(HAVE_MKSTEMP) + add_compile_definitions(HAVE_MKSTEMP) + endif() endif() set(CMAKE_C_STANDARD 11) diff --git a/cmake/modules/DispatchCompilerWarnings.cmake b/cmake/modules/DispatchCompilerWarnings.cmake index 35b80f3ec..e1117abdb 100644 --- a/cmake/modules/DispatchCompilerWarnings.cmake +++ b/cmake/modules/DispatchCompilerWarnings.cmake @@ -1,6 +1,8 @@ -if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") +if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC" OR MINGW) # TODO: someone needs to provide the msvc equivalent warning flags + # -fms-extensions will enable __popcnt64 + add_compile_options($<$,$>:-fms-extensions>) else() add_compile_options($<$,$>:-Werror>) add_compile_options($<$,$>:-Wall>) diff --git a/os/generic_win_base.h b/os/generic_win_base.h index af2c602ec..f94606da2 100644 --- a/os/generic_win_base.h +++ b/os/generic_win_base.h @@ -24,7 +24,10 @@ // Unices provide `howmany` via sys/param.h #define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#ifndef _MODE_T_ +#define _MODE_T_ typedef int mode_t; +#endif typedef void pthread_attr_t; #ifndef API_AVAILABLE diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 8f24194d6..749b0a452 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -24,6 +24,11 @@ #if defined(_WIN32) #include + +#if !defined(WCT_MAX_NODE_COUNT) +#define WCT_MAX_NODE_COUNT 16 +#endif + #endif /* diff --git a/src/shims/generic_win_stubs.h b/src/shims/generic_win_stubs.h index 985bbe30b..af32ed201 100644 --- a/src/shims/generic_win_stubs.h +++ b/src/shims/generic_win_stubs.h @@ -49,6 +49,7 @@ bool _dispatch_handle_is_socket(HANDLE hFile); void _dispatch_QueryInterruptTimePrecise(PULONGLONG lpInterruptTimePrecise); void _dispatch_QueryUnbiasedInterruptTimePrecise(PULONGLONG lpUnbiasedInterruptTimePrecise); +#ifndef HAVE_FILE_PIPE_LOCAL_INFORMATION enum { FilePipeLocalInformation = 24, }; @@ -65,6 +66,7 @@ typedef struct _FILE_PIPE_LOCAL_INFORMATION { ULONG NamedPipeState; ULONG NamedPipeEnd; } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; +#endif NTSTATUS _dispatch_NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, diff --git a/tests/generic_win_port.c b/tests/generic_win_port.c index 3a4fb2034..f10acbe79 100644 --- a/tests/generic_win_port.c +++ b/tests/generic_win_port.c @@ -238,6 +238,7 @@ randomize_name(char *out) } } +#ifndef HAVE_MKSTEMP dispatch_fd_t mkstemp(char *tmpl) { @@ -257,6 +258,7 @@ mkstemp(char *tmpl) errno = EEXIST; return -1; } +#endif void print_winapi_error(const char *function_name, DWORD error) diff --git a/tests/generic_win_port.h b/tests/generic_win_port.h index d693c7453..b027e43a7 100644 --- a/tests/generic_win_port.h +++ b/tests/generic_win_port.h @@ -7,7 +7,9 @@ #include typedef int kern_return_t; +#ifndef _PID_T_ typedef int pid_t; +#endif #if defined(_WIN64) typedef long long ssize_t; @@ -68,8 +70,10 @@ mach_timebase_info(mach_timebase_info_t tbi) return 0; } +#ifndef HAVE_MKSTEMP dispatch_fd_t mkstemp(char *tmpl); +#endif void print_winapi_error(const char *function_name, DWORD error); From e5b7b113079a068dfdaaf4a884f943d110621ac9 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Thu, 15 Feb 2024 21:15:09 +0100 Subject: [PATCH 007/102] PR feedback --- CMakeLists.txt | 20 ++++++++++++++++++++ cmake/modules/DispatchCompilerWarnings.cmake | 6 ++++-- os/generic_win_base.h | 3 +-- tests/generic_win_port.h | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd77f499c..1bb5453d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,26 @@ int main(int argc, char *argv[]) { if(HAVE_MKSTEMP) add_compile_definitions(HAVE_MKSTEMP) endif() + + check_c_source_compiles([=[ +#include +int main(int argc, char *argv[]) { + mode_t mode; +} +]=] HAVE_MODE_T) + if(HAVE_MODE_T) + add_compile_definitions(HAVE_MODE_T) + endif() + + check_c_source_compiles([=[ +#include +int main(int argc, char *argv[]) { + pid_t mode; +} +]=] HAVE_PID_T) + if(HAVE_PID_T) + add_compile_definitions(HAVE_PID_T) + endif() endif() set(CMAKE_C_STANDARD 11) diff --git a/cmake/modules/DispatchCompilerWarnings.cmake b/cmake/modules/DispatchCompilerWarnings.cmake index e1117abdb..9f390f010 100644 --- a/cmake/modules/DispatchCompilerWarnings.cmake +++ b/cmake/modules/DispatchCompilerWarnings.cmake @@ -1,7 +1,9 @@ -if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC" OR MINGW) +if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") # TODO: someone needs to provide the msvc equivalent warning flags - # -fms-extensions will enable __popcnt64 +elseif(WIN32) + # Tareting Windows but using a non-MSVC compiler. Set -fms-extensions + # so that we can use __popcnt64 add_compile_options($<$,$>:-fms-extensions>) else() add_compile_options($<$,$>:-Werror>) diff --git a/os/generic_win_base.h b/os/generic_win_base.h index f94606da2..5f1ea74c2 100644 --- a/os/generic_win_base.h +++ b/os/generic_win_base.h @@ -24,8 +24,7 @@ // Unices provide `howmany` via sys/param.h #define howmany(x, y) (((x) + ((y) - 1)) / (y)) -#ifndef _MODE_T_ -#define _MODE_T_ +#ifndef HAVE_MODE_T typedef int mode_t; #endif typedef void pthread_attr_t; diff --git a/tests/generic_win_port.h b/tests/generic_win_port.h index b027e43a7..f7e1d6152 100644 --- a/tests/generic_win_port.h +++ b/tests/generic_win_port.h @@ -7,7 +7,7 @@ #include typedef int kern_return_t; -#ifndef _PID_T_ +#ifndef HAVE_PID_T typedef int pid_t; #endif From 0b44b94437f11738f2c041c406c1fb8afb8e5c3d Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 21 Feb 2024 15:43:56 +0000 Subject: [PATCH 008/102] [Tests] Use in preference to . We probably shouldn't be using `` at all, but keep it in just in case something doesn't also have ``. rdar://123380262 --- tests/dispatch_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/dispatch_test.c b/tests/dispatch_test.c index d84a7b228..5c2aef948 100644 --- a/tests/dispatch_test.c +++ b/tests/dispatch_test.c @@ -33,6 +33,8 @@ #if __has_include() #define HAS_SYS_EVENT_H 1 #include +#elif __has_include() +#include #else #include #endif From 3b2e9ea13a67806c88cd7597cb66c6dd00241571 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 21 Feb 2024 15:44:45 +0000 Subject: [PATCH 009/102] [Build] Add `SWIFT_SYSTEM_NAME` setting. This lets us override the library subdir name when its derivation isn't straightforwardly just the lower-case version of `CMAKE_SYSTEM_NAME`. rdar://123380262 --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57a37d3b5..d999eb250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,7 +274,15 @@ add_compile_definitions($<$,$>:HA if(ENABLE_SWIFT) - set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/$" CACHE PATH "Path where the libraries will be installed") + if(NOT SWIFT_SYSTEM_NAME) + if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(SWIFT_SYSTEM_NAME macosx) + else() + set(SWIFT_SYSTEM_NAME "$") + endif() + endif() + + set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}" CACHE PATH "Path where the libraries will be installed") set(INSTALL_DISPATCH_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/dispatch" CACHE PATH "Path where the headers will be installed for libdispatch") set(INSTALL_BLOCK_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/Block" CACHE PATH "Path where the headers will be installed for the blocks runtime") set(INSTALL_OS_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/os" CACHE PATH "Path where the os/ headers will be installed") From d4147e8992bd7d1b038ef178a6a1d6152d794519 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Thu, 22 Feb 2024 09:12:50 -0800 Subject: [PATCH 010/102] Add a workaround for Windows ARM64 miscompile We get libdispatch assert failures with Windows ARM64 release mode in an internal app. We suspect that it is due to Clang miscompile. This is a temporary workaround to avoid them. --- src/CMakeLists.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 811e131e0..570c9197f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,6 +124,24 @@ else() target_compile_options(dispatch PRIVATE -Wall) endif() +# Work around a release-mode miscompile on windows arm64 +# Disable /Os and /Ot in /O1 and /O2 on queue.c +if(("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") AND + (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ARM64") OR + ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64"))) + string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) + set(FLAGS_BUILD_TYPE "${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}") + string(REGEX MATCHALL "/[Oo][12]" FLAGS "${CMAKE_C_FLAGS} ${FLAGS_BUILD_TYPE}") + if (FLAGS) + if (FLAGS MATCHES "1$") + set(FLAGS "/Od;/Og;/Oy;/Ob2;/GF;/Gy") + elseif (FLAGS MATCHES "2$") + set(FLAGS "/Od;/Og;/Oi;/Oy;/Ob2;/GF;/Gy") + endif() + set_source_files_properties(queue.c PROPERTIES COMPILE_OPTIONS "${FLAGS}") + endif() +endif() + # FIXME(compnerd) add check for -fblocks? target_compile_options(dispatch PRIVATE -fblocks) From daa23450e41c06ce8dd4f3ba4f5f6164db96913e Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Sat, 2 Mar 2024 14:00:10 +0000 Subject: [PATCH 011/102] Remove objc_retainAutoreleasedReturnValue workaround. The compiler has now been fixed to not generate calls to this function unless ObjC interop is enabled. rdar://123945799 --- src/swift/CMakeLists.txt | 13 ------------- src/swift/DispatchStubs.cc | 37 ------------------------------------- 2 files changed, 50 deletions(-) diff --git a/src/swift/CMakeLists.txt b/src/swift/CMakeLists.txt index c073e136d..4fffc84a4 100644 --- a/src/swift/CMakeLists.txt +++ b/src/swift/CMakeLists.txt @@ -1,16 +1,3 @@ - -# NOTE(compnerd) Today regardless of whether or not ObjC interop is enabled, -# swift will use an autoreleased return value convention for certain CF -# functions (including some that are used/related to dispatch). This means that -# the swift compiler in callers to such functions will call the function, and -# then pass the result of the function to objc_retainAutoreleasedReturnValue. In -# a context where we have ObjC interop disabled, we do not have access to the -# objc runtime so an implementation of objc_retainAutoreleasedReturnValue is not -# available. To work around this, we provide a shim for -# objc_retainAutoreleasedReturnValue in DispatchStubs.cc that just calls retain -# on the object. Once we fix the swift compiler to switch to a different model -# for handling these arguments with objc-interop disabled these shims can be -# eliminated. add_library(DispatchStubs STATIC DispatchStubs.cc) target_include_directories(DispatchStubs PRIVATE diff --git a/src/swift/DispatchStubs.cc b/src/swift/DispatchStubs.cc index 0625cc91f..dc320da29 100644 --- a/src/swift/DispatchStubs.cc +++ b/src/swift/DispatchStubs.cc @@ -56,40 +56,3 @@ static void _dispatch_overlay_constructor() { } #endif /* USE_OBJC */ - -#if !USE_OBJC -DISPATCH_RUNTIME_STDLIB_INTERFACE -extern "C" void * objc_retainAutoreleasedReturnValue(void *obj); -#endif - -#if !USE_OBJC - -// For CF functions with 'Get' semantics, the compiler currently assumes that -// the result is autoreleased and must be retained. It does so on all platforms -// by emitting a call to objc_retainAutoreleasedReturnValue. On Darwin, this is -// implemented by the ObjC runtime. On non-ObjC platforms, there is no runtime, -// and therefore we have to stub it out here ourselves. The compiler will -// eventually call swift_release to balance the retain below. This is a -// workaround until the compiler no longer emits this callout on non-ObjC -// platforms. -extern "C" -#if defined(_WIN32) -__declspec(dllimport) -#endif -void swift_retain(void *); - -DISPATCH_RUNTIME_STDLIB_INTERFACE -extern "C" void * objc_retainAutoreleasedReturnValue(void *obj) { - if (obj) { - swift_retain(obj); - return obj; - } - else return NULL; -} - -#if defined(_WIN32) -extern "C" void *(*__imp_objc_retainAutoreleasedReturnValue)(void *) = - &objc_retainAutoreleasedReturnValue; -#endif - -#endif // !USE_OBJC From 6495db77014d866a68f73ab4491f7f10f5bb1b53 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 28 Mar 2024 14:58:05 +0900 Subject: [PATCH 012/102] Adopt Sendable in DispatchQueue and similar types --- src/swift/Wrapper.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 4f80dcef2..999c22d6c 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -44,7 +44,7 @@ public class DispatchObject { } -public class DispatchGroup : DispatchObject { +public class DispatchGroup : DispatchObject, @unchecked Sendable { internal let __wrapped:dispatch_group_t; final internal override func wrapped() -> dispatch_object_t { @@ -68,7 +68,7 @@ public class DispatchGroup : DispatchObject { } } -public class DispatchSemaphore : DispatchObject { +public class DispatchSemaphore : DispatchObject, @unchecked Sendable { internal let __wrapped: dispatch_semaphore_t; final internal override func wrapped() -> dispatch_object_t { @@ -84,8 +84,8 @@ public class DispatchSemaphore : DispatchObject { } } -public class DispatchIO : DispatchObject { - internal let __wrapped:dispatch_io_t +public class DispatchIO : DispatchObject, @unchecked Sendable { + internal let __wrapped: dispatch_io_t final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) @@ -127,7 +127,7 @@ public class DispatchIO : DispatchObject { } } -public class DispatchQueue : DispatchObject { +public class DispatchQueue : DispatchObject, @unchecked Sendable { internal let __wrapped:dispatch_queue_t; final internal override func wrapped() -> dispatch_object_t { @@ -156,6 +156,7 @@ public class DispatchQueue : DispatchObject { } public class DispatchSource : DispatchObject, + @unchecked Sendable, DispatchSourceProtocol, DispatchSourceRead, DispatchSourceSignal, DispatchSourceTimer, DispatchSourceUserDataAdd, DispatchSourceUserDataOr, From a056677019468268f8731db6ce9fc0c0f25ce42c Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 28 Mar 2024 10:37:53 -0400 Subject: [PATCH 013/102] Add a missing semicolon in src/io.c. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 70c6721be..4a2653c84 100644 --- a/src/io.c +++ b/src/io.c @@ -2374,7 +2374,7 @@ _dispatch_operation_perform(dispatch_operation_t op) } op->buf = _aligned_malloc(op->buf_siz, siInfo.dwPageSize); #else - op->buf = aligned_alloc((size_t)PAGE_SIZE, op->buf_siz) + op->buf = aligned_alloc((size_t)PAGE_SIZE, op->buf_siz); #endif _dispatch_op_debug("buffer allocated", op); } else if (op->direction == DOP_DIR_WRITE) { From 2df0f761a6d0c9697590f084ee77d042db40b812 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Fri, 29 Mar 2024 10:40:05 +0900 Subject: [PATCH 014/102] queue.async/asyncAfter closures are @Sendable --- src/swift/Queue.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 1e0aea3c8..4b719f9bf 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -253,7 +253,7 @@ extension DispatchQueue { group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], - execute work: @escaping @convention(block) () -> Void) + execute work: @escaping @Sendable @convention(block) () -> Void) { if group == nil && qos == .unspecified { // Fast-path route for the most common API usage @@ -387,7 +387,7 @@ extension DispatchQueue { deadline: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], - execute work: @escaping @convention(block) () -> Void) + execute work: @escaping @Sendable @convention(block) () -> Void) { if #available(macOS 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) @@ -418,7 +418,7 @@ extension DispatchQueue { wallDeadline: DispatchWallTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], - execute work: @escaping @convention(block) () -> Void) + execute work: @escaping @Sendable @convention(block) () -> Void) { if #available(macOS 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) From 4a832dc5009c52b73f8c6a8cf03b23f206872992 Mon Sep 17 00:00:00 2001 From: Finagolfin Date: Sun, 21 Apr 2024 16:54:25 +0530 Subject: [PATCH 015/102] Check for `aligned_alloc()` and use `posix_memalign()` instead on platforms, like Android before API 28, that didn't have it --- CMakeLists.txt | 1 + src/io.c | 7 ++++++- tests/dispatch_io.c | 4 ++++ tests/dispatch_read2.c | 4 ++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f3d7aef0..eff610b89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,7 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Android) endif() check_function_exists(_pthread_workqueue_init HAVE__PTHREAD_WORKQUEUE_INIT) +check_function_exists(aligned_alloc HAVE_ALIGNED_ALLOC) check_function_exists(getprogname HAVE_GETPROGNAME) check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) check_function_exists(mach_approximate_time HAVE_MACH_APPROXIMATE_TIME) diff --git a/src/io.c b/src/io.c index 4a2653c84..12d2a2e63 100644 --- a/src/io.c +++ b/src/io.c @@ -2373,8 +2373,13 @@ _dispatch_operation_perform(dispatch_operation_t op) bQueried = true; } op->buf = _aligned_malloc(op->buf_siz, siInfo.dwPageSize); -#else +#elif defined(HAVE_ALIGNED_ALLOC) op->buf = aligned_alloc((size_t)PAGE_SIZE, op->buf_siz); +#else + err = posix_memalign(&op->buf, (size_t)PAGE_SIZE, op->buf_siz); + if (err != 0) { + goto error; + } #endif _dispatch_op_debug("buffer allocated", op); } else if (op->direction == DOP_DIR_WRITE) { diff --git a/tests/dispatch_io.c b/tests/dispatch_io.c index a5a1cea67..74f3c9bcc 100644 --- a/tests/dispatch_io.c +++ b/tests/dispatch_io.c @@ -398,7 +398,11 @@ test_async_read(char *path, size_t size, int option, dispatch_queue_t queue, buffer = _aligned_malloc(size, si.dwPageSize); #else size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); +#if defined(HAVE_ALIGNED_ALLOC) buffer = aligned_alloc(pagesize, size); +#else + posix_memalign((void **)&buffer, pagesize, size); +#endif #endif ssize_t r = dispatch_test_fd_read(fd, buffer, size); if (r == -1) { diff --git a/tests/dispatch_read2.c b/tests/dispatch_read2.c index 401fb4f62..274d942af 100644 --- a/tests/dispatch_read2.c +++ b/tests/dispatch_read2.c @@ -91,7 +91,11 @@ dispatch_read2(dispatch_fd_t fd, buffer = _aligned_malloc(bufsiz, pagesize); #else size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); +#if defined(HAVE_ALIGNED_ALLOC) buffer = aligned_alloc(pagesize, bufsiz); +#else + posix_memalign((void **)&buffer, pagesize, bufsiz); +#endif #endif ssize_t actual = dispatch_test_fd_read(fd, buffer, bufsiz); if (actual == -1) { From 7fa1340d416f597aca13064f767f233e284a1e27 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 9 May 2024 11:15:48 -0700 Subject: [PATCH 016/102] build: android bundles pthread into libc Add an additional flag to indicate that `-lc` is sufficient for pthread support and that `-lpthread` is not needed. This allows us to build with newer NDKs. --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index eff610b89..b11d52266 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) +if(ANDROID) + set(CMAKE_HAVE_LIBC_PTHREAD YES) +endif() find_package(Threads REQUIRED) include(CheckCCompilerFlag) From e173eda13777db99d1f0b29619cdcf10580a9d4a Mon Sep 17 00:00:00 2001 From: Priya Avhad Date: Wed, 24 Apr 2024 14:12:41 -0700 Subject: [PATCH 017/102] This change switches back _dispatch_operation_perform and other similar places to use posix_memalign from aligned_malloc. This was caught by thread sanitizer. --- CMakeLists.txt | 1 - src/io.c | 2 -- tests/dispatch_io.c | 4 ---- tests/dispatch_read2.c | 6 +----- 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b11d52266..2bae74ef9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,7 +191,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Android) endif() check_function_exists(_pthread_workqueue_init HAVE__PTHREAD_WORKQUEUE_INIT) -check_function_exists(aligned_alloc HAVE_ALIGNED_ALLOC) check_function_exists(getprogname HAVE_GETPROGNAME) check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) check_function_exists(mach_approximate_time HAVE_MACH_APPROXIMATE_TIME) diff --git a/src/io.c b/src/io.c index 12d2a2e63..e31e28c82 100644 --- a/src/io.c +++ b/src/io.c @@ -2373,8 +2373,6 @@ _dispatch_operation_perform(dispatch_operation_t op) bQueried = true; } op->buf = _aligned_malloc(op->buf_siz, siInfo.dwPageSize); -#elif defined(HAVE_ALIGNED_ALLOC) - op->buf = aligned_alloc((size_t)PAGE_SIZE, op->buf_siz); #else err = posix_memalign(&op->buf, (size_t)PAGE_SIZE, op->buf_siz); if (err != 0) { diff --git a/tests/dispatch_io.c b/tests/dispatch_io.c index 74f3c9bcc..fbfcb6055 100644 --- a/tests/dispatch_io.c +++ b/tests/dispatch_io.c @@ -398,11 +398,7 @@ test_async_read(char *path, size_t size, int option, dispatch_queue_t queue, buffer = _aligned_malloc(size, si.dwPageSize); #else size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); -#if defined(HAVE_ALIGNED_ALLOC) - buffer = aligned_alloc(pagesize, size); -#else posix_memalign((void **)&buffer, pagesize, size); -#endif #endif ssize_t r = dispatch_test_fd_read(fd, buffer, size); if (r == -1) { diff --git a/tests/dispatch_read2.c b/tests/dispatch_read2.c index 274d942af..d8ebba76c 100644 --- a/tests/dispatch_read2.c +++ b/tests/dispatch_read2.c @@ -91,11 +91,7 @@ dispatch_read2(dispatch_fd_t fd, buffer = _aligned_malloc(bufsiz, pagesize); #else size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); -#if defined(HAVE_ALIGNED_ALLOC) - buffer = aligned_alloc(pagesize, bufsiz); -#else posix_memalign((void **)&buffer, pagesize, bufsiz); -#endif #endif ssize_t actual = dispatch_test_fd_read(fd, buffer, bufsiz); if (actual == -1) { @@ -154,7 +150,7 @@ test_read(void) test_stop(); } #else - // investigate what the impact of lack of file cache disabling has + // investigate what the impact of lack of file cache disabling has // for this test #endif size_t size = (size_t)dispatch_test_fd_lseek(fd, 0, SEEK_END); From 8e43e3ec3760f2b0d5c7ac31564ff27ef2863948 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 26 Jun 2024 13:57:01 +0100 Subject: [PATCH 018/102] [Linux] Enable build IDs. We should use build IDs on Linux so that we can identify the built artefacts, and also so that we can match them up with debug information should we choose to separate it. rdar://130582819 --- CMakeLists.txt | 3 +++ src/BlocksRuntime/CMakeLists.txt | 4 ++++ src/CMakeLists.txt | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b11d52266..4cb17649a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ include(CheckCSourceCompiles) include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) +include(CheckLinkerFlag) include(CheckSymbolExists) include(GNUInstallDirs) include(CTest) @@ -175,6 +176,8 @@ option(ENABLE_THREAD_LOCAL_STORAGE "enable usage of thread local storage via _Th set(DISPATCH_USE_THREAD_LOCAL_STORAGE ${ENABLE_THREAD_LOCAL_STORAGE}) +check_linker_flag(C "LINKER:--build-id=sha1" LINKER_SUPPORTS_BUILD_ID) + check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE) if(_GNU_SOURCE) set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_GNU_SOURCE) diff --git a/src/BlocksRuntime/CMakeLists.txt b/src/BlocksRuntime/CMakeLists.txt index 50123d4b7..945e87a7e 100644 --- a/src/BlocksRuntime/CMakeLists.txt +++ b/src/BlocksRuntime/CMakeLists.txt @@ -22,6 +22,10 @@ endif() set_target_properties(BlocksRuntime PROPERTIES POSITION_INDEPENDENT_CODE TRUE) +if(LINKER_SUPPORTS_BUILD_ID) + target_link_options(BlocksRuntime PRIVATE "LINKER:--build-id=sha1") +endif() + add_library(BlocksRuntime::BlocksRuntime ALIAS BlocksRuntime) install(FILES Block.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 570c9197f..320b6fcdc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,6 +178,10 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") set_target_properties(dispatch PROPERTIES INSTALL_RPATH "$ORIGIN") endif() +if(LINKER_SUPPORTS_BUILD_ID) + target_link_options(dispatch PRIVATE "LINKER:--build-id=sha1") +endif() + if(ENABLE_SWIFT) add_subdirectory(swift) endif() From c22afb0a90ee5f1a884441488c72bc5bab5e031e Mon Sep 17 00:00:00 2001 From: "LamTrinh.Dev" Date: Thu, 25 Jul 2024 19:42:18 +0700 Subject: [PATCH 019/102] Update mach_private.h Correct the comment for DISPATCH_MACH_MSG_DESTRUCTOR_VM_DEALLOCATE --- private/mach_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/private/mach_private.h b/private/mach_private.h index e311aee16..d6b96c740 100644 --- a/private/mach_private.h +++ b/private/mach_private.h @@ -189,7 +189,7 @@ DISPATCH_DECL(dispatch_mach_msg); * @const DISPATCH_MACH_MSG_DESTRUCTOR_FREE * Message buffer will be deallocated with free(3). * - * @const DISPATCH_MACH_MSG_DESTRUCTOR_FREE + * @const DISPATCH_MACH_MSG_DESTRUCTOR_VM_DEALLOCATE * Message buffer will be deallocated with vm_deallocate. */ DISPATCH_ENUM(dispatch_mach_msg_destructor, unsigned int, From 0b9beca41be0d39f992f2c5ab1fa091d44a37ea2 Mon Sep 17 00:00:00 2001 From: Lam Trinh <> Date: Fri, 2 Aug 2024 18:06:03 +0700 Subject: [PATCH 020/102] Add more comments for #endif in .h file. --- dispatch/base.h | 2 +- dispatch/dispatch.h | 2 +- dispatch/group.h | 2 +- dispatch/introspection.h | 2 +- dispatch/object.h | 2 +- dispatch/once.h | 2 +- dispatch/queue.h | 2 +- dispatch/source.h | 2 +- dispatch/time.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dispatch/base.h b/dispatch/base.h index 7123f83ad..ce65f05f6 100644 --- a/dispatch/base.h +++ b/dispatch/base.h @@ -323,4 +323,4 @@ typedef void (*dispatch_function_t)(void *_Nullable); -#endif +#endif /* __DISPATCH_BASE__ */ diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 0c7bdd43a..ef65e38c2 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -77,4 +77,4 @@ #undef __DISPATCH_INDIRECT__ #endif /* !__DISPATCH_BUILDING_DISPATCH__ */ -#endif +#endif /* __DISPATCH_PUBLIC__ */ diff --git a/dispatch/group.h b/dispatch/group.h index 6b30b26c6..b98b47c16 100644 --- a/dispatch/group.h +++ b/dispatch/group.h @@ -276,4 +276,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_GROUP__ */ diff --git a/dispatch/introspection.h b/dispatch/introspection.h index ea7dcd8f5..d216f462a 100644 --- a/dispatch/introspection.h +++ b/dispatch/introspection.h @@ -185,4 +185,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_INTROSPECTION__ */ diff --git a/dispatch/object.h b/dispatch/object.h index 02815f3f2..3f3cf3279 100644 --- a/dispatch/object.h +++ b/dispatch/object.h @@ -547,4 +547,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_OBJECT__ */ diff --git a/dispatch/once.h b/dispatch/once.h index fbce4b111..19af4f9a6 100644 --- a/dispatch/once.h +++ b/dispatch/once.h @@ -122,4 +122,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_ONCE__ */ diff --git a/dispatch/queue.h b/dispatch/queue.h index 969dc880a..e2f7e05e9 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -1542,4 +1542,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_QUEUE__ */ diff --git a/dispatch/source.h b/dispatch/source.h index fa960d3c2..9d605a9df 100644 --- a/dispatch/source.h +++ b/dispatch/source.h @@ -770,4 +770,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_SOURCE__ */ diff --git a/dispatch/time.h b/dispatch/time.h index 02dd27f6e..9f66c195f 100644 --- a/dispatch/time.h +++ b/dispatch/time.h @@ -132,4 +132,4 @@ __END_DECLS DISPATCH_ASSUME_NONNULL_END -#endif +#endif /* __DISPATCH_TIME__ */ From 1990f4ede558773949580c49e74261a5e542e75e Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Thu, 8 Aug 2024 16:25:51 -0700 Subject: [PATCH 021/102] Disable new `cast-function-type-mismatch` Should fix this properly, but for now just disable the warning itself. --- cmake/modules/DispatchCompilerWarnings.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/modules/DispatchCompilerWarnings.cmake b/cmake/modules/DispatchCompilerWarnings.cmake index 9f390f010..cd71f36e5 100644 --- a/cmake/modules/DispatchCompilerWarnings.cmake +++ b/cmake/modules/DispatchCompilerWarnings.cmake @@ -77,4 +77,8 @@ else() add_compile_options($<$,$>:-Wno-shorten-64-to-32>) endif() add_compile_options($<$,$>:-Wno-error=assign-enum>) + + # Should re-enable after rdar://133498289 is fixed (ie. fixing the one mismatched cast in apply.c) + add_compile_options($<$,$>:-Wno-cast-function-type-mismatch>) + add_compile_options($<$,$>:-Wno-error=unknown-warning-option>) endif() From 90397f7f7ad2d33f54739556954ba8b2e55d80b3 Mon Sep 17 00:00:00 2001 From: Paris Date: Mon, 21 Oct 2024 14:16:13 -0700 Subject: [PATCH 022/102] Delete CONTRIBUTING.md old template; removing in favor of new contributing info for /swiftlang --- CONTRIBUTING.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index e36bf969f..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,10 +0,0 @@ -By submitting a pull request, you represent that you have the right to license -your contribution to Apple and the community, and agree by submitting the patch -that your contributions are licensed under the [Swift -license](https://swift.org/LICENSE.txt). - ---- - -Before submitting the pull request, please make sure you have tested your -changes and that they follow the Swift project [guidelines for contributing -code](https://swift.org/contributing/#contributing-code). From ee9c2b1f109344dc927a4bad397ca8f82801f239 Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Tue, 29 Oct 2024 16:37:26 -0700 Subject: [PATCH 023/102] Fix a memory leak in `DispatchData.withUnsafeBytes` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `DispatchData.withUnsafeBytes` created a new `dispatch_data_t` by calling `dispatch_data_create_map`. I assume that the intention was that this memory was freed when `data` is destroyed, based on the presence of `_fixLifetime(data)` but `data` was just a plain `dispatch_data_t` C struct, that doesn’t have any cleanup operations associated with it when destroyed. To fix the leak, wrap the `dispatch_data_t` in a `DispatchData`, which takes over the ownership of the `dispatch_data_t` and releases it when `data` gets destroyed. Alternatively, `_fixLifetime` could have been replaced by `_swift_dispatch_release(unsafeBitCast(data, to: dispatch_object_t.self))` but I think using `DispatchData` is the cleaner solution. --- src/swift/Data.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index 158ec1fe6..ac962d71c 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -110,7 +110,7 @@ public struct DispatchData : RandomAccessCollection { { var ptr: UnsafeRawPointer? = nil var size = 0 - let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size) + let data = DispatchData(data: CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size)) let contentPtr = ptr!.bindMemory( to: ContentType.self, capacity: size / MemoryLayout.stride) defer { _fixLifetime(data) } From 1483bf0b6c3cafe3077e9c8da5561b8b7ba907bd Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Wed, 7 Jul 2021 13:14:34 -0400 Subject: [PATCH 024/102] [cmake] Support OpenBSD amd64 architecture name. x86_64 is spelled "amd64" on this platform. Return "amd64", for consistency with Swift and other projects. For Windows, return "x86_64". --- cmake/modules/SwiftSupport.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index a42b61e40..c1e5c9d4c 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -27,8 +27,12 @@ function(get_swift_host_arch result_var_name) set("${result_var_name}" "armv7" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") set("${result_var_name}" "armv7" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") - set("${result_var_name}" "x86_64" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "amd64|AMD64") + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + set("${result_var_name}" "x86_64" PARENT_SCOPE) + else() + set("${result_var_name}" "amd64" PARENT_SCOPE) + endif() elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") set("${result_var_name}" "itanium" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86") From 99fce104939c82629ba15b4b46b2622d56911fc6 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Sat, 3 Oct 2020 00:27:45 -0400 Subject: [PATCH 025/102] HAVE_MACH is unnecessary here. The kevent backend requires _dispatch_bug_kevent_client unconditionally. We don't need to require this entire function require HAVE_MACH, just the inner few that is already present behind this conditional. --- src/init.c | 2 -- src/internal.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/init.c b/src/init.c index d54da4121..0fe0e4385 100644 --- a/src/init.c +++ b/src/init.c @@ -964,7 +964,6 @@ _dispatch_continuation_get_function_symbol(dispatch_continuation_t dc) return dc->dc_func; } -#if HAVE_MACH void _dispatch_bug_kevent_client(const char *msg, const char *filter, const char *operation, int err, uint64_t ident, uint64_t udata, @@ -1008,7 +1007,6 @@ _dispatch_bug_kevent_client(const char *msg, const char *filter, msg, strerror(err), err, udata, filter, ident, ident, func); } } -#endif // HAVE_MACH #if RDAR_49023449 diff --git a/src/internal.h b/src/internal.h index 4df1a2976..9f74f2c19 100644 --- a/src/internal.h +++ b/src/internal.h @@ -475,12 +475,10 @@ void _dispatch_bug_mach_client(const char *msg, mach_msg_return_t kr); struct dispatch_unote_class_s; -#if HAVE_MACH DISPATCH_NOINLINE DISPATCH_COLD void _dispatch_bug_kevent_client(const char *msg, const char *filter, const char *operation, int err, uint64_t ident, uint64_t udata, struct dispatch_unote_class_s *du); -#endif // HAVE_MACH DISPATCH_NOINLINE DISPATCH_COLD void _dispatch_bug_kevent_vanished(struct dispatch_unote_class_s *du); From d37d2fa18b4b9df99286982dedabdb71b5e30325 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Tue, 13 Oct 2020 19:59:28 -0400 Subject: [PATCH 026/102] fadvise is not present on OpenBSD. It is just a hint, after all, so it is not an error if it is unavailable. --- src/io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/io.c b/src/io.c index e31e28c82..8f73916d1 100644 --- a/src/io.c +++ b/src/io.c @@ -2328,8 +2328,11 @@ _dispatch_operation_advise(dispatch_operation_t op, size_t chunk_size) case ESPIPE: break; // fd refers to a pipe or FIFO default: (void)dispatch_assume_zero(err); break; } +#elif defined(__OpenBSD__) + (void)err; #else #error "_dispatch_operation_advise not implemented on this platform" + (void)err; #endif // defined(F_RDADVISE) #endif // defined(_WIN32) } From fff494547998d5856880e232e0d17777215fe969 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Thu, 28 Jan 2021 20:26:41 -0500 Subject: [PATCH 027/102] Properly annotate fallthrough in kevent backend. Building dispatch from swift sets -Werror -Wimplicit-fallthrough. It is not enough to just comment the fallthrough; we have elsewhere defined DISPATCH_FALLTHROUGH, so we might as well use it. --- src/event/event_kevent.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index 16b69b37d..fe5cfaa12 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -743,7 +743,7 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, switch (err) { case ENOMEM: _dispatch_temporary_resource_shortage(); - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case EINTR: goto retry; case EBADF: @@ -754,7 +754,7 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, (flags & KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST)) { return 0; } - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; #endif // DISPATCH_USE_KEVENT_WORKLOOP default: DISPATCH_CLIENT_CRASH(err, "Unexpected error from kevent"); @@ -1410,7 +1410,7 @@ _dispatch_kq_fill_workloop_event(dispatch_kevent_t ke, int which, switch (which) { case DISPATCH_WORKLOOP_ASYNC_FROM_SYNC: fflags |= NOTE_WL_END_OWNERSHIP; - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case DISPATCH_WORKLOOP_ASYNC: case DISPATCH_WORKLOOP_ASYNC_DISCOVER_SYNC: case DISPATCH_WORKLOOP_ASYNC_QOS_UPDATE: @@ -1434,10 +1434,10 @@ _dispatch_kq_fill_workloop_event(dispatch_kevent_t ke, int which, case DISPATCH_WORKLOOP_ASYNC_LEAVE_FROM_SYNC: fflags |= NOTE_WL_END_OWNERSHIP; - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case DISPATCH_WORKLOOP_ASYNC_LEAVE_FROM_TRANSFER: fflags |= NOTE_WL_IGNORE_ESTALE; - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case DISPATCH_WORKLOOP_ASYNC_LEAVE: dispatch_assert(!_dq_state_is_enqueued_on_target(dq_state)); action = EV_ADD | EV_DELETE | EV_ENABLE; From 413ed2459a7f917e226b8a597170cf7f660d4ec6 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Wed, 7 Jul 2021 15:52:29 -0400 Subject: [PATCH 028/102] [tests] Make test harness portable. Prior to this change, on non-Linux, the test harness will already attempt to use dispatch functionality when testing dispatch itself. This does not seem intentional, and instead appears to be intended as the Mac OS case where the platform already has Dispatch and is using that when testing the just-built version. Instead, make the Linux case the general `__unix__` case. --- tests/bsdtestharness.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/bsdtestharness.c b/tests/bsdtestharness.c index 93ed8324b..4b66c8956 100644 --- a/tests/bsdtestharness.c +++ b/tests/bsdtestharness.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) @@ -144,7 +145,7 @@ main(int argc, char *argv[]) //fprintf(stderr, "pid = %d\n", pid); assert(pid > 0); -#if defined(__linux__) +#if defined(__unix__) int status; struct rusage usage; struct timeval tv_stop, tv_wall; @@ -159,9 +160,9 @@ main(int argc, char *argv[]) assert(res2 != -1); test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0); - printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec); - printf("[PERF]\tuser time: %ld.%06ld\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec); - printf("[PERF]\tsystem time: %ld.%06ld\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); + printf("[PERF]\twall time: %" PRIdMAX ".%06" PRIdMAX "\n", (intmax_t)tv_wall.tv_sec, (intmax_t)tv_wall.tv_usec); + printf("[PERF]\tuser time: %" PRIdMAX ".%06" PRIdMAX"\n", (intmax_t)usage.ru_utime.tv_sec, (intmax_t)usage.ru_utime.tv_usec); + printf("[PERF]\tsystem time: %" PRIdMAX ".%06" PRIdMAX "\n", (intmax_t)usage.ru_stime.tv_sec, (intmax_t)usage.ru_stime.tv_usec); printf("[PERF]\tmax resident set size: %ld\n", usage.ru_maxrss); printf("[PERF]\tpage faults: %ld\n", usage.ru_majflt); printf("[PERF]\tswaps: %ld\n", usage.ru_nswap); From 3d7728e627225e89300c150bd9c62b2c002ef77d Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Wed, 7 Jul 2021 16:09:33 -0400 Subject: [PATCH 029/102] Lock implementation changes for OpenBSD. OpenBSD has futex, but not futex_pi. Segregate futex functionality from pi-futex functionality with a new preprocessor symbol. --- src/shims/lock.c | 29 ++++++++++++++++++++++++++--- src/shims/lock.h | 26 +++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/shims/lock.c b/src/shims/lock.c index 88fb8f8b6..8102c877c 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -56,6 +56,20 @@ _dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, #endif #endif +#if defined(__unix__) +#if !HAVE_UL_UNFAIR_LOCK && !HAVE_FUTEX_PI +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, + uint32_t timeout) +{ + (void)value; + (void)flags; + (void)timeout; +} +#endif +#endif + #pragma mark - semaphores #if USE_MACH_SEM @@ -395,8 +409,10 @@ _dispatch_unfair_lock_wake(uint32_t *uaddr, uint32_t flags) #include #ifdef __ANDROID__ #include -#else +#elif __linux__ #include +#else +#include #endif /* __ANDROID__ */ DISPATCH_ALWAYS_INLINE @@ -405,7 +421,12 @@ _dispatch_futex(uint32_t *uaddr, int op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3, int opflags) { +#if __linux__ return (int)syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3); +#else + (void)val3; + return futex(uaddr, op | opflags, (int)val, timeout, uaddr2); +#endif } // returns 0, ETIMEDOUT, EFAULT, EINTR, EWOULDBLOCK @@ -455,6 +476,7 @@ _dispatch_futex_wake(uint32_t *uaddr, int wake, int opflags) DISPATCH_INTERNAL_CRASH(errno, "_dlock_wake() failed"); } +#if HAVE_FUTEX_PI static void _dispatch_futex_lock_pi(uint32_t *uaddr, struct timespec *timeout, int detect, int opflags) @@ -472,6 +494,7 @@ _dispatch_futex_unlock_pi(uint32_t *uaddr, int opflags) if (rc == 0) return; DISPATCH_CLIENT_CRASH(errno, "futex_unlock_pi() failed"); } +#endif #endif #pragma mark - wait for address @@ -606,7 +629,7 @@ _dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul, } } } -#elif HAVE_FUTEX +#elif HAVE_FUTEX_PI void _dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul, dispatch_lock_options_t flags) @@ -643,7 +666,7 @@ _dispatch_unfair_lock_unlock_slow(dispatch_unfair_lock_t dul, dispatch_lock cur) if (_dispatch_lock_has_waiters(cur)) { _dispatch_unfair_lock_wake(&dul->dul_lock, 0); } -#elif HAVE_FUTEX +#elif HAVE_FUTEX_PI // futex_unlock_pi() handles both OWNER_DIED which we abuse & WAITERS _dispatch_futex_unlock_pi(&dul->dul_lock, FUTEX_PRIVATE_FLAG); #else diff --git a/src/shims/lock.h b/src/shims/lock.h index 6bf825aa7..0fcb65eb6 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -100,6 +100,25 @@ _dispatch_lock_owner(dispatch_lock lock_value) return lock_value & DLOCK_OWNER_MASK; } +#elif defined(__OpenBSD__) + +typedef uint32_t dispatch_tid; +typedef uint32_t dispatch_lock; + +#define DLOCK_OWNER_NULL ((dispatch_tid)0) +#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc) +#define DLOCK_WAITERS_BIT ((dispatch_lock)0x00000001) +#define DLOCK_FAILED_TRYLOCK_BIT ((dispatch_lock)0x00000002) + +#define _dispatch_tid_self() ((dispatch_tid)(_dispatch_get_tsd_base()->tid)) + +DISPATCH_ALWAYS_INLINE +static inline dispatch_tid +_dispatch_lock_owner(dispatch_lock lock_value) +{ + return lock_value & DLOCK_OWNER_MASK; +} + #else # error define _dispatch_lock encoding scheme for your platform here #endif @@ -167,10 +186,15 @@ _dispatch_lock_has_failed_trylock(dispatch_lock lock_value) #endif #ifndef HAVE_FUTEX -#ifdef __linux__ +#if defined(__linux__) +#define HAVE_FUTEX 1 +#define HAVE_FUTEX_PI 1 +#elif defined(__OpenBSD__) #define HAVE_FUTEX 1 +#define HAVE_FUTEX_PI 0 #else #define HAVE_FUTEX 0 +#define HAVE_FUTEX_PI 0 #endif #endif // HAVE_FUTEX From 05e05e9dd080bda511412217749d530f49098345 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Fri, 2 Oct 2020 23:36:39 -0400 Subject: [PATCH 030/102] Add a runloop implementation based on pipe2. The Linux implementation uses an eventfd to impement the runloop contract for CF. However, ordinary POSIX pipes are a widely available API and can be used to achieve the same result as eventfd on other systems that support it. Since POSIX pipes require a pair of file descriptors, we force file descriptors to 32-bit integers and pack these two into a single 64-bit integer. This keeps the management of the runloop handle simple rather than having to manage the handle storage externally, for the cost of limiting the range of the file descriptor type. --- private/private.h | 2 ++ src/queue.c | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/private/private.h b/private/private.h index b87f5dc2b..dc1777e49 100644 --- a/private/private.h +++ b/private/private.h @@ -191,6 +191,8 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); typedef mach_port_t dispatch_runloop_handle_t; #elif defined(__linux__) || defined(__FreeBSD__) typedef int dispatch_runloop_handle_t; +#elif defined(__unix__) && !defined(__linux__) && !defined(__FreeBSD__) +typedef uint64_t dispatch_runloop_handle_t; #elif defined(_WIN32) typedef void *dispatch_runloop_handle_t; #else diff --git a/src/queue.c b/src/queue.c index 40f059c7a..4195bddfa 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6472,7 +6472,7 @@ _dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle) { #if TARGET_OS_MAC return MACH_PORT_VALID(handle); -#elif defined(__linux__) +#elif defined(__linux__) || defined(__unix__) return handle >= 0; #elif defined(_WIN32) return handle != NULL; @@ -6490,6 +6490,8 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq) #elif defined(__linux__) // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1; +#elif defined(__unix__) && !defined(__linux__) + return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #elif defined(_WIN32) return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #else @@ -6507,6 +6509,8 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #elif defined(__linux__) // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL dq->do_ctxt = (void *)(uintptr_t)(handle + 1); +#elif defined(__unix__) && !defined(__linux__) + dq->do_ctxt = (void *)(uintptr_t)handle; #elif defined(_WIN32) dq->do_ctxt = (void *)(uintptr_t)handle; #else @@ -6514,6 +6518,12 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #endif } +#if defined(__unix__) +#define DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd) (((uint64_t)(rfd) << 32) | (wfd)) +#define DISPATCH_RUNLOOP_HANDLE_RFD(h) ((int)((h) >> 32)) +#define DISPATCH_RUNLOOP_HANDLE_WFD(h) ((int)((h) & 0xffffffff)) +#endif + static void _dispatch_runloop_queue_handle_init(void *ctxt) { @@ -6563,6 +6573,14 @@ _dispatch_runloop_queue_handle_init(void *ctxt) } } handle = fd; +#elif defined(__unix__) && !defined(__linux__) + int fds[2]; + int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK); + if (r == -1) { + DISPATCH_CLIENT_CRASH(errno, "pipe2 failure"); + } + uint32_t rfd = (uint32_t)fds[0], wfd = (uint32_t)fds[1]; + handle = DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd); #elif defined(_WIN32) HANDLE hEvent; hEvent = CreateEventW(NULL, /*bManualReset=*/FALSE, @@ -6597,6 +6615,11 @@ _dispatch_runloop_queue_handle_dispose(dispatch_lane_t dq) #elif defined(__linux__) int rc = close(handle); (void)dispatch_assume_zero(rc); +#elif defined(__unix__) && !defined(__linux__) + int rc = close(DISPATCH_RUNLOOP_HANDLE_WFD(handle)); + (void)dispatch_assume_zero(rc); + rc = close(DISPATCH_RUNLOOP_HANDLE_RFD(handle)); + (void)dispatch_assume_zero(rc); #elif defined(_WIN32) BOOL bSuccess; bSuccess = CloseHandle(handle); @@ -6633,6 +6656,13 @@ _dispatch_runloop_queue_class_poke(dispatch_lane_t dq) result = eventfd_write(handle, 1); } while (result == -1 && errno == EINTR); (void)dispatch_assume_zero(result); +#elif defined(__unix__) && !defined(__linux__) + int wfd = DISPATCH_RUNLOOP_HANDLE_WFD(handle); + ssize_t result; + do { + result = write(wfd, "x", 1); + } while (result == -1 && errno == EINTR); + (void)dispatch_assume_zero(result - 1); #elif defined(_WIN32) BOOL bSuccess; bSuccess = SetEvent(handle); @@ -7311,6 +7341,13 @@ _gettid(void) { return (pid_t)pthread_getthreadid_np(); } +#elif defined(__OpenBSD__) +DISPATCH_ALWAYS_INLINE +static inline pid_t +_gettid(void) +{ + return getthrid(); +} #elif defined(_WIN32) DISPATCH_ALWAYS_INLINE static inline DWORD From 18ffbd608b0b9afc6c25339d1067550095d7fa71 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Fri, 2 Oct 2020 22:53:00 -0400 Subject: [PATCH 031/102] Light cleanup of the kevent backend. Some functionality requires particular preprocessor feature flags to be set but errors are raised if they aren't, so the remedy is to put these behind relevant feature flags. * dispatch_kevent_t has a qos field only when DISPATCH_USE_KEVENT_QOS * _dispatch_kq_unote_update requires DISPATCH_HAVE_DIRECT_KNOTES as it is only called from functions behind this * _dispatch_workloop_actions and the associated enum are only used when DISPATCH_USE_KEVENT_WORKLOOP. Some unused variable void casts are removed (guard_ptr and pp), which do not refer to variables -- these may be upstream merge artefacts. A type cast is made to match types for _dispatch_bug_kevent_client. This function is incorrectly placed behind HAVE_MACH in src/init.c, but to keep the scope and impact of this commit narrow, we will defer that change. Since EVFILT_FS is not supported on all kevent implementations, put these behind an #ifdef. EVFILT_USER also requires similar handling, but since EVFILT_USER kevents are used intrinsically as part of the functionality, these will be handled in a separate commit. --- src/event/event_kevent.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index fe5cfaa12..2664e0753 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -101,7 +101,9 @@ _evfiltstr(short filt) _evfilt2(EVFILT_MACHPORT); _evfilt2(DISPATCH_EVFILT_MACH_NOTIFICATION); #endif +#ifdef EVFILT_FS _evfilt2(EVFILT_FS); +#endif _evfilt2(EVFILT_USER); #ifdef EVFILT_SOCK _evfilt2(EVFILT_SOCK); @@ -388,8 +390,10 @@ _dispatch_kevent_print_error(dispatch_kevent_t ke) switch (ke->data) { case 0: return; +#if DISPATCH_USE_KEVENT_QOS case ERANGE: /* A broken QoS was passed to kevent_id() */ DISPATCH_INTERNAL_CRASH(ke->qos, "Invalid kevent priority"); +#endif default: // log the unexpected error _dispatch_bug_kevent_client("kevent", _evfiltstr(ke->filter), @@ -397,7 +401,7 @@ _dispatch_kevent_print_error(dispatch_kevent_t ke) ke->flags & EV_DELETE ? "delete" : ke->flags & EV_ADD ? "add" : ke->flags & EV_ENABLE ? "enable" : "monitor", - (int)ke->data, ke->ident, ke->udata, du); + (int)ke->data, ke->ident, (uint64_t)ke->udata, du); } } @@ -591,7 +595,6 @@ _dispatch_kq_create(intptr_t *fd_ptr) guardid_t guard = (uintptr_t)fd_ptr; kqfd = guarded_kqueue_np(&guard, GUARD_CLOSE | GUARD_DUP); #else - (void)guard_ptr; kqfd = kqueue(); #endif if (kqfd == -1) { @@ -860,7 +863,6 @@ _dispatch_kq_unote_set_kevent(dispatch_unote_t _du, dispatch_kevent_t dk, du->du_priority), #endif }; - (void)pp; // if DISPATCH_USE_KEVENT_QOS == 0 } DISPATCH_ALWAYS_INLINE @@ -985,6 +987,7 @@ _dispatch_sync_ipc_handoff_end(dispatch_wlh_t wlh, mach_port_t port) } #endif +#if DISPATCH_HAVE_DIRECT_KNOTES DISPATCH_NOINLINE static bool _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, @@ -1055,6 +1058,7 @@ _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, dispatch_assume_zero(r); return true; } +#endif #pragma mark dispatch_muxnote_t @@ -1283,6 +1287,7 @@ _dispatch_unote_unregister_direct(dispatch_unote_t du, uint32_t flags) #pragma mark - #pragma mark dispatch_event_loop +#if DISPATCH_USE_KEVENT_WORKLOOP enum { DISPATCH_WORKLOOP_ASYNC, DISPATCH_WORKLOOP_ASYNC_FROM_SYNC, @@ -1316,6 +1321,7 @@ static char const * const _dispatch_workloop_actions[] = { [DISPATCH_WORKLOOP_SYNC_WAKE] = "sync-wake", [DISPATCH_WORKLOOP_SYNC_END] = "sync-end", }; +#endif void _dispatch_event_loop_atfork_child(void) @@ -2445,6 +2451,7 @@ const dispatch_source_type_s _dispatch_source_type_vnode = { .dst_merge_evt = _dispatch_source_merge_evt, }; +#ifdef EVFILT_FS const dispatch_source_type_s _dispatch_source_type_vfs = { .dst_kind = "vfs", .dst_filter = EVFILT_FS, @@ -2477,6 +2484,7 @@ const dispatch_source_type_s _dispatch_source_type_vfs = { .dst_create = _dispatch_unote_create_without_handle, .dst_merge_evt = _dispatch_source_merge_evt, }; +#endif #ifdef EVFILT_SOCK const dispatch_source_type_s _dispatch_source_type_sock = { From c4814ec404e0bbb36080abf31c0eedd9f6fff238 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Sat, 3 Oct 2020 00:25:36 -0400 Subject: [PATCH 032/102] Support relative kqueue timers. Some kqueue timer implementations do not support absolute timers; these also only have millisecond resolution. --- src/event/event_kevent.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index 2664e0753..a2c8c5f1d 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -2363,6 +2363,12 @@ _dispatch_event_loop_timer_arm(dispatch_timer_heap_t dth, uint32_t tidx, target += range.leeway; range.leeway = 0; } +#if !NOTE_ABSOLUTE + target = range.delay; +#if defined(__OpenBSD__) + target /= 1000000; +#endif +#endif _dispatch_event_loop_timer_program(dth, tidx, target, range.leeway, EV_ADD | EV_ENABLE); From b55398ed930b2a796177ca85964409460d25cbf7 Mon Sep 17 00:00:00 2001 From: Michael Chiu Date: Tue, 21 Jan 2025 14:04:16 -0800 Subject: [PATCH 033/102] fix freebsd build --- cmake/modules/SwiftSupport.cmake | 2 ++ private/private.h | 4 ++- src/event/event_kevent.c | 18 ++++++++--- src/event/workqueue.c | 45 ++++++++++++++++++++++++++ src/event/workqueue_internal.h | 2 +- src/init.c | 2 +- src/internal.h | 3 ++ src/io.c | 1 - src/queue.c | 32 ++++++++++++++++++ src/shims/lock.c | 29 ++++++++++++++++- src/shims/lock.h | 22 +++++++++++++ src/swift/Source.swift | 14 ++++++-- src/swift/Wrapper.swift | 8 +++-- src/swift/shims/DispatchOverlayShims.h | 5 +++ tests/bsdtestharness.c | 4 +-- tests/dispatch_apply.c | 2 +- tests/dispatch_io_pipe.c | 4 +++ tests/dispatch_select.c | 2 +- 18 files changed, 182 insertions(+), 17 deletions(-) diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index a42b61e40..a82842ef9 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -27,6 +27,8 @@ function(get_swift_host_arch result_var_name) set("${result_var_name}" "armv7" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") set("${result_var_name}" "armv7" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "amd64") + set("${result_var_name}" "x86_64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") set("${result_var_name}" "x86_64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") diff --git a/private/private.h b/private/private.h index b87f5dc2b..8f9922c31 100644 --- a/private/private.h +++ b/private/private.h @@ -189,8 +189,10 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); #if TARGET_OS_MAC typedef mach_port_t dispatch_runloop_handle_t; -#elif defined(__linux__) || defined(__FreeBSD__) +#elif defined(__linux__) typedef int dispatch_runloop_handle_t; +#elif defined(__FreeBSD__) +typedef uint64_t dispatch_runloop_handle_t; #elif defined(_WIN32) typedef void *dispatch_runloop_handle_t; #else diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index 16b69b37d..16cc6cbf4 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -389,8 +389,13 @@ _dispatch_kevent_print_error(dispatch_kevent_t ke) case 0: return; case ERANGE: /* A broken QoS was passed to kevent_id() */ +#if defined(__APPLE__) DISPATCH_INTERNAL_CRASH(ke->qos, "Invalid kevent priority"); +#else + DISPATCH_INTERNAL_CRASH(0, "Invalid kevent priority"); +#endif default: +#if HAVE_MACH // log the unexpected error _dispatch_bug_kevent_client("kevent", _evfiltstr(ke->filter), !ke->udata ? NULL : @@ -398,6 +403,9 @@ _dispatch_kevent_print_error(dispatch_kevent_t ke) ke->flags & EV_ADD ? "add" : ke->flags & EV_ENABLE ? "enable" : "monitor", (int)ke->data, ke->ident, ke->udata, du); +#else + break; +#endif } } @@ -591,7 +599,6 @@ _dispatch_kq_create(intptr_t *fd_ptr) guardid_t guard = (uintptr_t)fd_ptr; kqfd = guarded_kqueue_np(&guard, GUARD_CLOSE | GUARD_DUP); #else - (void)guard_ptr; kqfd = kqueue(); #endif if (kqfd == -1) { @@ -743,7 +750,7 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, switch (err) { case ENOMEM: _dispatch_temporary_resource_shortage(); - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case EINTR: goto retry; case EBADF: @@ -754,7 +761,7 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, (flags & KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST)) { return 0; } - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; #endif // DISPATCH_USE_KEVENT_WORKLOOP default: DISPATCH_CLIENT_CRASH(err, "Unexpected error from kevent"); @@ -860,7 +867,6 @@ _dispatch_kq_unote_set_kevent(dispatch_unote_t _du, dispatch_kevent_t dk, du->du_priority), #endif }; - (void)pp; // if DISPATCH_USE_KEVENT_QOS == 0 } DISPATCH_ALWAYS_INLINE @@ -985,6 +991,7 @@ _dispatch_sync_ipc_handoff_end(dispatch_wlh_t wlh, mach_port_t port) } #endif +#if DISPATCH_HAVE_DIRECT_KNOTES DISPATCH_NOINLINE static bool _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, @@ -1055,6 +1062,7 @@ _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, dispatch_assume_zero(r); return true; } +#endif // DISPATCH_HAVE_DIRECT_KNOTES #pragma mark dispatch_muxnote_t @@ -1300,6 +1308,7 @@ enum { DISPATCH_WORKLOOP_SYNC_END, }; +#if DISPATCH_USE_KEVENT_WORKLOOP static char const * const _dispatch_workloop_actions[] = { [DISPATCH_WORKLOOP_ASYNC] = "async", [DISPATCH_WORKLOOP_ASYNC_FROM_SYNC] = "async (from sync)", @@ -1316,6 +1325,7 @@ static char const * const _dispatch_workloop_actions[] = { [DISPATCH_WORKLOOP_SYNC_WAKE] = "sync-wake", [DISPATCH_WORKLOOP_SYNC_END] = "sync-end", }; +#endif // DISPATCH_USE_KEVENT_WORKLOOP void _dispatch_event_loop_atfork_child(void) diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 749b0a452..7c85cfb02 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -247,6 +247,51 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); } +#elif defined(__FreeBSD__) +#include +#include +#include + +static void +_dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) +{ + struct kinfo_proc kp[WORKQ_MAX_TRACKED_TIDS]; + size_t size; + int count, runners = 0; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)getpid()}; + + // get size we need + if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) { + _dispatch_debug("workq: failed to get size for kinfo_proc[] from sysctll"); + return; + } + + // only care about up to WORKQ_MAX_TRACKED_TIDS threads + size = size > sizeof(kp) ? sizeof(kp) : size; + count = (int)(size / sizeof(struct kinfo_proc)); + + if (sysctl(mib, 4, kp, &size, NULL, 0) < 0) { + _dispatch_debug("workq: failed to get kinfo_proc[] from sysctl"); + return; + } + + _dispatch_unfair_lock_lock(&mon->registered_tid_lock); + + for (int i = 0; i < mon->num_registered_tids; ++i) { + dispatch_tid tid = mon->registered_tids[i]; + for (int j = 0; i < count; ++i) { + if ((dispatch_tid)kp[j].ki_tid != tid) { continue; } + if (kp[j].ki_stat == SRUN || kp[j].ki_stat == SIDL) { + ++runners; + break; + } + } + } + + mon->num_runnable = runners; + + _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); +} #else #error must define _dispatch_workq_count_runnable_workers #endif diff --git a/src/event/workqueue_internal.h b/src/event/workqueue_internal.h index 62028077a..4b3839dea 100644 --- a/src/event/workqueue_internal.h +++ b/src/event/workqueue_internal.h @@ -30,7 +30,7 @@ void _dispatch_workq_worker_register(dispatch_queue_global_t root_q); void _dispatch_workq_worker_unregister(dispatch_queue_global_t root_q); -#if defined(__linux__) || defined(_WIN32) +#if defined(__linux__) || defined(_WIN32) || defined(__FreeBSD__) #define HAVE_DISPATCH_WORKQ_MONITORING 1 #else #define HAVE_DISPATCH_WORKQ_MONITORING 0 diff --git a/src/init.c b/src/init.c index d54da4121..6e1ff6882 100644 --- a/src/init.c +++ b/src/init.c @@ -1051,7 +1051,7 @@ _dispatch_bug_kevent_vanished(dispatch_unote_t du) "{ %p[%s], ident: %" PRIdPTR " / 0x%" PRIxPTR ", handler: %p }", dux_type(du._du)->dst_kind, dou._dq, dou._dq->dq_label ? dou._dq->dq_label : "", - du._du->du_ident, du._du->du_ident, func); + (intptr_t)du._du->du_ident, (intptr_t)du._du->du_ident, func); } #endif // RDAR_49023449 diff --git a/src/internal.h b/src/internal.h index 4df1a2976..36f4b8864 100644 --- a/src/internal.h +++ b/src/internal.h @@ -277,6 +277,9 @@ upcast(dispatch_object_t dou) #include #include #endif +#if defined(__FreeBSD__) +#include +#endif // __FreeBSD__ #include #include #include diff --git a/src/io.c b/src/io.c index e31e28c82..7be7de728 100644 --- a/src/io.c +++ b/src/io.c @@ -22,7 +22,6 @@ #if defined(__FreeBSD__) #include -#define F_RDADVISE F_RDAHEAD #endif #ifndef DISPATCH_IO_DEBUG diff --git a/src/queue.c b/src/queue.c index 40f059c7a..b018094ad 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6474,6 +6474,8 @@ _dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle) return MACH_PORT_VALID(handle); #elif defined(__linux__) return handle >= 0; +#elif defined(__FreeBSD__) + return handle > 0; #elif defined(_WIN32) return handle != NULL; #else @@ -6490,6 +6492,8 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq) #elif defined(__linux__) // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1; +#elif defined(__FreeBSD__) + return (dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt; #elif defined(_WIN32) return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #else @@ -6507,6 +6511,8 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #elif defined(__linux__) // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL dq->do_ctxt = (void *)(uintptr_t)(handle + 1); +#elif defined(__FreeBSD__) + dq->do_ctxt = (void *)(uintptr_t)handle; #elif defined(_WIN32) dq->do_ctxt = (void *)(uintptr_t)handle; #else @@ -6514,6 +6520,12 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #endif } +#if defined(__unix__) +#define DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd) (((uint64_t)(rfd) << 32) | (wfd)) +#define DISPATCH_RUNLOOP_HANDLE_RFD(h) ((int)((h) >> 32)) +#define DISPATCH_RUNLOOP_HANDLE_WFD(h) ((int)((h) & 0xffffffff)) +#endif + static void _dispatch_runloop_queue_handle_init(void *ctxt) { @@ -6563,6 +6575,14 @@ _dispatch_runloop_queue_handle_init(void *ctxt) } } handle = fd; +#elif defined(__unix__) && !defined(__linux__) + int fds[2]; + int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK); + if (r == -1) { + DISPATCH_CLIENT_CRASH(errno, "pipe2 failure"); + } + uint32_t rfd = (uint32_t)fds[0], wfd = (uint32_t)fds[1]; + handle = DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd); #elif defined(_WIN32) HANDLE hEvent; hEvent = CreateEventW(NULL, /*bManualReset=*/FALSE, @@ -6597,6 +6617,11 @@ _dispatch_runloop_queue_handle_dispose(dispatch_lane_t dq) #elif defined(__linux__) int rc = close(handle); (void)dispatch_assume_zero(rc); +#elif defined(__unix__) && !defined(__linux__) + int rc = close(DISPATCH_RUNLOOP_HANDLE_WFD(handle)); + (void)dispatch_assume_zero(rc); + rc = close(DISPATCH_RUNLOOP_HANDLE_RFD(handle)); + (void)dispatch_assume_zero(rc); #elif defined(_WIN32) BOOL bSuccess; bSuccess = CloseHandle(handle); @@ -6633,6 +6658,13 @@ _dispatch_runloop_queue_class_poke(dispatch_lane_t dq) result = eventfd_write(handle, 1); } while (result == -1 && errno == EINTR); (void)dispatch_assume_zero(result); +#elif defined(__unix__) && !defined(__linux__) + int wfd = DISPATCH_RUNLOOP_HANDLE_WFD(handle); + ssize_t result; + do { + result = write(wfd, "x", 1); + } while (result == -1 && errno == EINTR); + (void)dispatch_assume_zero(result - 1); #elif defined(_WIN32) BOOL bSuccess; bSuccess = SetEvent(handle); diff --git a/src/shims/lock.c b/src/shims/lock.c index 88fb8f8b6..dd705078f 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -56,6 +56,21 @@ _dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, #endif #endif +#if defined(__FreeBSD__) +#if !HAVE_UL_UNFAIR_LOCK +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, + uint32_t timeout) +{ + (void)value; + (void)flags; + (void)timeout; + sched_yield(); +} +#endif +#endif + #pragma mark - semaphores #if USE_MACH_SEM @@ -516,6 +531,16 @@ _dispatch_wait_on_address(uint32_t volatile *_address, uint32_t value, ? INFINITE : ((nsecs + 1000000) / 1000000); if (dwMilliseconds == 0) return ETIMEDOUT; return WaitOnAddress(address, &value, sizeof(value), dwMilliseconds) == TRUE; +#elif defined(__FreeBSD__) + (void)flags; + if (nsecs != DISPATCH_TIME_FOREVER) { + struct timespec ts = { + .tv_sec = (__typeof__(ts.tv_sec))(nsecs / NSEC_PER_SEC), + .tv_nsec = (__typeof__(ts.tv_nsec))(nsecs % NSEC_PER_SEC), + }; + return _umtx_op((void*)address, UMTX_OP_WAIT_UINT, value, (void*)(uintptr_t)sizeof(struct timespec), (void*)&ts); + } + return _umtx_op((void*)address, UMTX_OP_WAIT_UINT, value, 0, 0); #else #error _dispatch_wait_on_address unimplemented for this platform #endif @@ -530,6 +555,8 @@ _dispatch_wake_by_address(uint32_t volatile *address) _dispatch_futex_wake((uint32_t *)address, INT_MAX, FUTEX_PRIVATE_FLAG); #elif defined(_WIN32) WakeByAddressAll((uint32_t *)address); +#elif defined(__FreeBSD__) + _umtx_op((void*)address, UMTX_OP_WAKE, INT_MAX, 0, 0); #else (void)address; #endif @@ -689,7 +716,7 @@ _dispatch_once_wait(dispatch_once_gate_t dgo) _dispatch_futex_wait(lock, (dispatch_lock)new_v, NULL, FUTEX_PRIVATE_FLAG); #else - _dispatch_thread_switch(new_v, 0, timeout++); + _dispatch_thread_switch((dispatch_lock)new_v, 0, timeout++); #endif (void)timeout; } diff --git a/src/shims/lock.h b/src/shims/lock.h index 6bf825aa7..0e45eb345 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -79,6 +79,28 @@ _dispatch_lock_owner(dispatch_lock lock_value) return lock_value & DLOCK_OWNER_MASK; } +#elif defined(__FreeBSD__) + +#include +#include +#include + +typedef uint32_t dispatch_tid; +typedef uint32_t dispatch_lock; + +#define DLOCK_OWNER_NULL ((dispatch_tid)0) +#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc) +#define DLOCK_WAITERS_BIT ((dispatch_lock)0x00000001) +#define DLOCK_FAILED_TRYLOCK_BIT ((dispatch_lock)0x00000002) +#define _dispatch_tid_self() ((dispatch_tid)(_dispatch_get_tsd_base()->tid << 2)) + +DISPATCH_ALWAYS_INLINE +static inline dispatch_tid +_dispatch_lock_owner(dispatch_lock lock_value) +{ + return lock_value & DLOCK_OWNER_MASK; +} + #elif defined(_WIN32) #include diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 57677c2c2..44c8b6011 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -124,8 +124,17 @@ extension DispatchSource { public static let exit = ProcessEvent(rawValue: 0x80000000) public static let fork = ProcessEvent(rawValue: 0x40000000) public static let exec = ProcessEvent(rawValue: 0x20000000) +#if os(FreeBSD) + public static let track = ProcessEvent(rawValue: 0x00000001) +#else public static let signal = ProcessEvent(rawValue: 0x08000000) +#endif + +#if os(FreeBSD) + public static let all: ProcessEvent = [.exit, .fork, .exec, .track] +#else public static let all: ProcessEvent = [.exit, .fork, .exec, .signal] +#endif } #endif @@ -224,7 +233,7 @@ extension DispatchSource { return DispatchSource(source: source) as DispatchSourceUserDataReplace } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(FreeBSD) public class func makeFileSystemObjectSource(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { let source = dispatch_source_create(_swift_dispatch_source_type_VNODE(), UInt(fileDescriptor), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceFileSystemObject @@ -293,7 +302,8 @@ extension DispatchSourceMemoryPressure { #if !os(Linux) && !os(Android) && !os(Windows) extension DispatchSourceProcess { public var handle: pid_t { - return pid_t(dispatch_source_get_handle(self as! DispatchSource)) + return pid_t((self as! DispatchSource).handle) +// return pid_t(dispatch_source_get_handle(self as! DispatchSource)) } public var data: DispatchSource.ProcessEvent { diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 999c22d6c..c57a29b77 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -183,8 +183,12 @@ extension DispatchSource : DispatchSourceMachSend, #endif #if !os(Linux) && !os(Android) && !os(Windows) -extension DispatchSource : DispatchSourceProcess, - DispatchSourceFileSystemObject { +extension DispatchSource : DispatchSourceProcess { +} +#endif + +#if !os(Linux) && !os(Android) && !os(Windows) && !os(FreeBSD) +extension DispatchSource : DispatchSourceFileSystemObject { } #endif diff --git a/src/swift/shims/DispatchOverlayShims.h b/src/swift/shims/DispatchOverlayShims.h index 80e87a8db..222ac7456 100644 --- a/src/swift/shims/DispatchOverlayShims.h +++ b/src/swift/shims/DispatchOverlayShims.h @@ -88,6 +88,11 @@ SWIFT_DISPATCH_SOURCE_TYPE(PROC) SWIFT_DISPATCH_SOURCE_TYPE(VNODE) #endif +#if defined(__FreeBSD__) +SWIFT_DISPATCH_SOURCE_TYPE(PROC) +//SWIFT_DISPATCH_SOURCE_TYPE(VNODE) +#endif + extern void _swift_dispatch_source_create_abort(void); diff --git a/tests/bsdtestharness.c b/tests/bsdtestharness.c index 93ed8324b..d59d9356b 100644 --- a/tests/bsdtestharness.c +++ b/tests/bsdtestharness.c @@ -144,7 +144,7 @@ main(int argc, char *argv[]) //fprintf(stderr, "pid = %d\n", pid); assert(pid > 0); -#if defined(__linux__) +#if defined(__linux__) || defined(__FreeBSD__) int status; struct rusage usage; struct timeval tv_stop, tv_wall; @@ -211,7 +211,7 @@ main(int argc, char *argv[]) #else dispatch_queue_t main_q = dispatch_get_main_queue(); - dispatch_source_t tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, main_q); + dispatch_source_t tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, (uintptr_t)pid, DISPATCH_PROC_EXIT, main_q); assert(tmp_ds); dispatch_source_set_event_handler(tmp_ds, ^{ int status; diff --git a/tests/dispatch_apply.c b/tests/dispatch_apply.c index 1f2dfb470..01b3dfb65 100644 --- a/tests/dispatch_apply.c +++ b/tests/dispatch_apply.c @@ -81,7 +81,7 @@ static void busythread(void *ignored) static void test_apply_contended(dispatch_queue_t dq) { uint32_t activecpu; -#if defined(__linux__) || defined(__OpenBSD__) +#if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_WIN32) SYSTEM_INFO si; diff --git a/tests/dispatch_io_pipe.c b/tests/dispatch_io_pipe.c index f94438483..90c212236 100644 --- a/tests/dispatch_io_pipe.c +++ b/tests/dispatch_io_pipe.c @@ -90,6 +90,10 @@ test_get_pipe_buffer_size(int kind) CloseHandle(write_handle); }); return size; +#elif defined(__FreeBSD__) + // buffer size of blocking and non-blocking pipes is different on FreeBSD + (void)kind; + return PIPE_BUF; #else (void)kind; static dispatch_once_t once; diff --git a/tests/dispatch_select.c b/tests/dispatch_select.c index 6202711cb..b0758707d 100644 --- a/tests/dispatch_select.c +++ b/tests/dispatch_select.c @@ -39,7 +39,7 @@ void finish(void* cxt); void stage1(int stage) { -#if defined(_WIN32) +#if defined(_WIN32) || defined(__FreeBSD__) char *path = dispatch_test_get_large_file(); dispatch_fd_t fd = dispatch_test_fd_open(path, O_RDONLY); if (fd == -1) From 4faf129da445322595490fa5867b79bec8f62f97 Mon Sep 17 00:00:00 2001 From: Michael Chiu Date: Wed, 22 Jan 2025 14:37:10 -0800 Subject: [PATCH 034/102] fix infinite loop --- src/swift/Source.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 44c8b6011..7b3f4b768 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -302,8 +302,7 @@ extension DispatchSourceMemoryPressure { #if !os(Linux) && !os(Android) && !os(Windows) extension DispatchSourceProcess { public var handle: pid_t { - return pid_t((self as! DispatchSource).handle) -// return pid_t(dispatch_source_get_handle(self as! DispatchSource)) + return pid_t(CDispatch.dispatch_source_get_handle((self as! DispatchSource).__wrapped)) } public var data: DispatchSource.ProcessEvent { From a1c8b4743d432b9148c3ee676122114a4b846ac3 Mon Sep 17 00:00:00 2001 From: Michael Chiu Date: Wed, 22 Jan 2025 14:58:36 -0800 Subject: [PATCH 035/102] formatting --- src/queue.c | 1 + src/shims/lock.c | 2 +- src/shims/lock.h | 2 +- src/swift/shims/DispatchOverlayShims.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/queue.c b/src/queue.c index b018094ad..2daaf8758 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6576,6 +6576,7 @@ _dispatch_runloop_queue_handle_init(void *ctxt) } handle = fd; #elif defined(__unix__) && !defined(__linux__) + // swift-corelib-foundation PR #3004 implemented a pipe based queue handle int fds[2]; int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK); if (r == -1) { diff --git a/src/shims/lock.c b/src/shims/lock.c index dd705078f..27987b58a 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -556,7 +556,7 @@ _dispatch_wake_by_address(uint32_t volatile *address) #elif defined(_WIN32) WakeByAddressAll((uint32_t *)address); #elif defined(__FreeBSD__) - _umtx_op((void*)address, UMTX_OP_WAKE, INT_MAX, 0, 0); + _umtx_op((void*)address, UMTX_OP_WAKE, INT_MAX, 0, 0); #else (void)address; #endif diff --git a/src/shims/lock.h b/src/shims/lock.h index 0e45eb345..bcbf812ce 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -92,7 +92,7 @@ typedef uint32_t dispatch_lock; #define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc) #define DLOCK_WAITERS_BIT ((dispatch_lock)0x00000001) #define DLOCK_FAILED_TRYLOCK_BIT ((dispatch_lock)0x00000002) -#define _dispatch_tid_self() ((dispatch_tid)(_dispatch_get_tsd_base()->tid << 2)) +#define _dispatch_tid_self() ((dispatch_tid)(_dispatch_get_tsd_base()->tid << 2)) DISPATCH_ALWAYS_INLINE static inline dispatch_tid diff --git a/src/swift/shims/DispatchOverlayShims.h b/src/swift/shims/DispatchOverlayShims.h index 222ac7456..5ed8dd228 100644 --- a/src/swift/shims/DispatchOverlayShims.h +++ b/src/swift/shims/DispatchOverlayShims.h @@ -90,7 +90,7 @@ SWIFT_DISPATCH_SOURCE_TYPE(VNODE) #if defined(__FreeBSD__) SWIFT_DISPATCH_SOURCE_TYPE(PROC) -//SWIFT_DISPATCH_SOURCE_TYPE(VNODE) +SWIFT_DISPATCH_SOURCE_TYPE(VNODE) #endif extern void From 1169502f781f9f8d4ae7740eefbba3d52c40f9ea Mon Sep 17 00:00:00 2001 From: Jeremy Day Date: Fri, 24 Jan 2025 13:59:54 -0800 Subject: [PATCH 036/102] Switch Win32 pipes to PIPE_WAIT --- src/event/event_windows.c | 3 +++ src/io.c | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/event/event_windows.c b/src/event/event_windows.c index 94674a3bf..31613ca00 100644 --- a/src/event/event_windows.c +++ b/src/event/event_windows.c @@ -277,6 +277,9 @@ _dispatch_pipe_monitor_thread(void *context) char cBuffer[1]; DWORD dwNumberOfBytesTransferred; OVERLAPPED ov = {0}; + // Block on a 0-byte read; this will only resume when data is + // available in the pipe. The pipe must be PIPE_WAIT or this thread + // will spin. BOOL bSuccess = ReadFile(hPipe, cBuffer, /* nNumberOfBytesToRead */ 0, &dwNumberOfBytesTransferred, &ov); DWORD dwBytesAvailable; diff --git a/src/io.c b/src/io.c index e31e28c82..77be20977 100644 --- a/src/io.c +++ b/src/io.c @@ -1437,20 +1437,20 @@ _dispatch_fd_entry_create_with_fd(dispatch_fd_t fd, uintptr_t hash) int result = ioctlsocket((SOCKET)fd, (long)FIONBIO, &value); (void)dispatch_assume_zero(result); } else { - // Try to make writing nonblocking, although pipes not coming - // from Foundation.Pipe may not have FILE_WRITE_ATTRIBUTES. + // The _dispatch_pipe_monitor_thread expects pipes to be + // PIPE_WAIT and exploits this assumption by using a blocking + // 0-byte read as a synchronization mechanism. DWORD dwPipeMode = 0; if (GetNamedPipeHandleState((HANDLE)fd, &dwPipeMode, NULL, - NULL, NULL, NULL, 0) && !(dwPipeMode & PIPE_NOWAIT)) { - dwPipeMode |= PIPE_NOWAIT; + NULL, NULL, NULL, 0) && !(dwPipeMode & PIPE_WAIT)) { + dwPipeMode |= PIPE_WAIT; if (!SetNamedPipeHandleState((HANDLE)fd, &dwPipeMode, NULL, NULL)) { - // We may end up blocking on subsequent writes, but we - // don't have a good alternative. - // The WriteQuotaAvailable from NtQueryInformationFile - // erroneously returns 0 when there is a blocking read - // on the other end of the pipe. - _dispatch_fd_entry_debug("failed to set PIPE_NOWAIT", + // If setting the pipe to PIPE_WAIT fails, the + // monitoring thread will spin constantly, saturating + // a core, which is undesirable but non-fatal. + // The semantics will still be correct in this case. + _dispatch_fd_entry_debug("failed to set PIPE_WAIT", fd_entry); } } From b2544fedde097cf54095334552847e956379c70f Mon Sep 17 00:00:00 2001 From: Jeremy Day Date: Fri, 24 Jan 2025 14:21:30 -0800 Subject: [PATCH 037/102] Clamp write to bufsize-1 bytes to afford sentinel value for no-progress --- src/io.c | 39 +++++++++++++++++++++++++++++++++------ tests/dispatch_io_pipe.c | 7 ++++++- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/io.c b/src/io.c index 77be20977..0efb849ea 100644 --- a/src/io.c +++ b/src/io.c @@ -2518,13 +2518,40 @@ _dispatch_operation_perform(dispatch_operation_t op) NTSTATUS status = _dispatch_NtQueryInformationFile(hFile, &iosb, &fpli, sizeof(fpli), FilePipeLocalInformation); if (NT_SUCCESS(status)) { - // WriteQuotaAvailable is unreliable in the presence - // of a blocking reader, when it can return zero, so only - // account for it otherwise - if (fpli.WriteQuotaAvailable > 0) { - len = MIN(len, fpli.WriteQuotaAvailable); + // WriteQuotaAvailable is the free space in the output buffer + // that has not already been reserved for reading. In other words, + // WriteQuotaAvailable = + // OutboundQuota - WriteQuotaUsed - QueuedReadSize. + // It is not documented that QueuedReadSize is part of this + // calculation, but this behavior has been observed experimentally. + // Unfortunately, this means that it is not possible to distinguish + // between a full output buffer and a reader blocked waiting for a + // full buffer's worth of data. This is a problem because if the + // output buffer is full and no reader is waiting for data, then + // attempting to write to the buffer of a PIPE_WAIT, non- + // overlapped I/O pipe will block the dispatch queue thread. + // + // In order to work around this idiosyncrasy, we bound the size of + // the write to be OutboundQuota - 1. This affords us a sentinel value + // in WriteQuotaAvailable that can be used to detect if a reader is + // making progress or not. + // WriteQuotaAvailable = 0 => a reader is blocked waiting for data. + // WriteQuotaAvailable = 1 => the pipe has been written to, but no + // reader is making progress. + // When we detect that WriteQuotaAvailable == 1, we write 0 bytes to + // avoid blocking the dispatch queue thread. + if (fpli.WriteQuotaAvailable == 0) { + // This condition can only occur when we have a reader blocked + // waiting for data on the pipe. In this case, write a full + // buffer's worth of data (less one byte to preserve this + // sentinel value of WriteQuotaAvailable == 0). + len = MIN(len, fpli.OutboundQuota - 1); + } else { + // Subtract 1 from WriteQuotaAvailable to ensure we do not fill + // the pipe and preserve the sentinel value of + // WriteQuotaAvailable == 1. + len = MIN(len, fpli.WriteQuotaAvailable - 1); } - len = MIN(len, fpli.OutboundQuota); } OVERLAPPED ovlOverlapped = {}; diff --git a/tests/dispatch_io_pipe.c b/tests/dispatch_io_pipe.c index f94438483..50ddc8a87 100644 --- a/tests/dispatch_io_pipe.c +++ b/tests/dispatch_io_pipe.c @@ -404,7 +404,12 @@ test_dispatch_write(int kind, int delay) dispatch_group_t g = dispatch_group_create(); dispatch_group_enter(g); - const size_t bufsize = test_get_pipe_buffer_size(kind); + // The libdispatch implementation writes at most bufsize-1 bytes + // before requiring a reader to start making progress. Because + // these tests operate serially, the reader will not make progress + // until the write finishes, and a write of >= bufsize will not + // finish until the reader starts draining the pipe. + const size_t bufsize = test_get_pipe_buffer_size(kind) - 1; char *buf = calloc(bufsize, 1); assert(buf); From ae1524cacda30c3760656ff74ae74606fc053f90 Mon Sep 17 00:00:00 2001 From: Alexander Smarus Date: Tue, 4 Feb 2025 16:27:39 +0200 Subject: [PATCH 038/102] Handle multibyte path strings on Windows --- src/io.c | 52 +++++++++++++++++++++++++++++++++++++---------- src/io_internal.h | 8 +++++++- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/io.c b/src/io.c index e31e28c82..165f82ac6 100644 --- a/src/io.c +++ b/src/io.c @@ -407,9 +407,13 @@ dispatch_io_create_f(dispatch_io_type_t type, dispatch_fd_t fd, } #if defined(_WIN32) -#define _is_separator(ch) ((ch) == '/' || (ch) == '\\') +#define _is_separator(ch) ((ch) == L'/' || (ch) == L'\\') +#define _dispatch_stat _wstati64 +typedef struct _stati64 _dispatch_stat_t; #else #define _is_separator(ch) ((ch) == '/') +#define _dispatch_stat stat +typedef struct stat _dispatch_stat_t; #endif dispatch_io_t @@ -424,16 +428,36 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path, if (PathIsRelativeA(path)) { return DISPATCH_BAD_INPUT; } + int cchLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, NULL, 0); + if (!cchLength) { + dispatch_assert(GetLastError() == ERROR_NO_UNICODE_TRANSLATION); + return DISPATCH_BAD_INPUT; + } + dispatch_io_path_data_t path_data = malloc(sizeof(*path_data) + sizeof(WCHAR) * cchLength); + if (!path_data) { + return DISPATCH_OUT_OF_MEMORY; + } + path_data->pathlen = cchLength - 1; // Don't include terminating null character + cchLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, path_data->path, cchLength); + if (!cchLength) { + free(path_data); + // We already checked the input when measuring buffer length. + // Any error at this point seems fatal. + DISPATCH_INTERNAL_CRASH(GetLastError(), "MultiByteToWideChar"); + return DISPATCH_BAD_INPUT; + } #else if (!_is_separator(*path)) { return DISPATCH_BAD_INPUT; } -#endif size_t pathlen = strlen(path); dispatch_io_path_data_t path_data = malloc(sizeof(*path_data) + pathlen+1); if (!path_data) { return DISPATCH_OUT_OF_MEMORY; } + path_data->pathlen = pathlen; + memcpy(path_data->path, path, pathlen + 1); +#endif dispatch_io_t channel = _dispatch_io_create(type); channel->fd = -1; _dispatch_channel_debug("create with path %s", channel, path); @@ -441,16 +465,14 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path, path_data->channel = channel; path_data->oflag = oflag; path_data->mode = mode; - path_data->pathlen = pathlen; - memcpy(path_data->path, path, pathlen + 1); _dispatch_retain(queue); _dispatch_retain(channel); dispatch_async(channel->queue, ^{ int err = 0; - struct stat st; + _dispatch_stat_t st; _dispatch_io_syscall_switch_noerr(err, #if defined(_WIN32) - stat(path_data->path, &st), + _dispatch_stat(path_data->path, &st), #else (path_data->oflag & O_NOFOLLOW) == O_NOFOLLOW #if __APPLE__ @@ -465,7 +487,7 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path, if ((path_data->oflag & O_CREAT) && !_is_separator(*(path_data->path + path_data->pathlen - 1))) { // Check parent directory - char *c = NULL; + dispatch_io_path_char_t *c = NULL; for (ssize_t i = (ssize_t)path_data->pathlen - 1; i >= 0; i--) { if (_is_separator(path_data->path[i])) { c = &path_data->path[i]; @@ -476,7 +498,7 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path, *c = 0; int perr; _dispatch_io_syscall_switch_noerr(perr, - stat(path_data->path, &st), + _dispatch_stat(path_data->path, &st), case 0: // Since the parent directory exists, open() will // create a regular file after the fd_entry has @@ -486,7 +508,7 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path, break; ); #if defined(_WIN32) - *c = '\\'; + *c = L'\\'; #else *c = '/'; #endif @@ -602,7 +624,11 @@ dispatch_io_create_with_io(dispatch_io_type_t type, dispatch_io_t in_channel, mode_t mode = in_channel->fd_entry->stat.mode; dev_t dev = in_channel->fd_entry->stat.dev; size_t path_data_len = sizeof(struct dispatch_io_path_data_s) + +#if defined(_WIN32) + sizeof(WCHAR) * (in_channel->fd_entry->path_data->pathlen + 1); +#else in_channel->fd_entry->path_data->pathlen + 1; +#endif dispatch_io_path_data_t path_data = malloc(path_data_len); memcpy(path_data, in_channel->fd_entry->path_data, path_data_len); @@ -1292,7 +1318,7 @@ _dispatch_fd_entry_unguard(dispatch_fd_entry_t fd_entry) { (void)fd_entry; } #endif // DISPATCH_USE_GUARDED_FD static inline dispatch_fd_t -_dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const char *path, +_dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const dispatch_io_path_char_t *path, int oflag, mode_t mode) { #if DISPATCH_USE_GUARDED_FD guardid_t guard = (uintptr_t)fd_entry; @@ -1333,7 +1359,7 @@ _dispatch_fd_entry_guarded_open(dispatch_fd_entry_t fd_entry, const char *path, } else if (oflag & _O_TRUNC) { dwCreationDisposition = TRUNCATE_EXISTING; } - return (dispatch_fd_t)CreateFile(path, dwDesiredAccess, + return (dispatch_fd_t)CreateFileW(path, dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, dwCreationDisposition, 0, NULL); #else @@ -1597,7 +1623,11 @@ _dispatch_fd_entry_create_with_path(dispatch_io_path_data_t path_data, // On devs lock queue dispatch_fd_entry_t fd_entry = _dispatch_fd_entry_create( path_data->channel->queue); +#if defined(_WIN32) + _dispatch_fd_entry_debug("create: path %S", fd_entry, path_data->path); +#else _dispatch_fd_entry_debug("create: path %s", fd_entry, path_data->path); +#endif if (S_ISREG(mode)) { #if defined(_WIN32) _dispatch_disk_init(fd_entry, 0); diff --git a/src/io_internal.h b/src/io_internal.h index c076cfc69..f71a76b51 100644 --- a/src/io_internal.h +++ b/src/io_internal.h @@ -79,12 +79,18 @@ struct dispatch_stream_s { typedef struct dispatch_stream_s *dispatch_stream_t; +#if defined(_WIN32) +typedef WCHAR dispatch_io_path_char_t; +#else +typedef char dispatch_io_path_char_t; +#endif + struct dispatch_io_path_data_s { dispatch_io_t channel; int oflag; mode_t mode; size_t pathlen; - char path[]; + dispatch_io_path_char_t path[]; }; typedef struct dispatch_io_path_data_s *dispatch_io_path_data_t; From 13151a69447b6ffec8e05fb350113f5aeacaf436 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 24 Feb 2025 15:09:37 -0800 Subject: [PATCH 039/102] Add missing `Sendable` conformances to `DispatchPredicate`, `DispatchQoS`, and `DispatchTimeoutResult`. --- src/swift/Dispatch.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swift/Dispatch.swift b/src/swift/Dispatch.swift index 2ba819223..b14794d85 100644 --- a/src/swift/Dispatch.swift +++ b/src/swift/Dispatch.swift @@ -17,7 +17,7 @@ import CDispatch /// dispatch_assert @available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) -public enum DispatchPredicate { +public enum DispatchPredicate : Sendable { case onQueue(DispatchQueue) case onQueueAsBarrier(DispatchQueue) case notOnQueue(DispatchQueue) @@ -46,7 +46,7 @@ public func dispatchPrecondition(condition: @autoclosure () -> DispatchPredicate /// qos_class_t -public struct DispatchQoS : Equatable { +public struct DispatchQoS : Equatable, Sendable { public let qosClass: QoSClass public let relativePriority: Int @@ -67,7 +67,7 @@ public struct DispatchQoS : Equatable { public static let unspecified = DispatchQoS(qosClass: .unspecified, relativePriority: 0) - public enum QoSClass { + public enum QoSClass : Sendable { @available(macOS 10.10, iOS 8.0, *) case background @@ -125,7 +125,7 @@ public func ==(a: DispatchQoS, b: DispatchQoS) -> Bool { /// -public enum DispatchTimeoutResult { +public enum DispatchTimeoutResult : Sendable { static let KERN_OPERATION_TIMED_OUT:Int = 49 case success case timedOut From e36dbdacc2bde0be92ec5d34938f8e69d18197dc Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 24 Feb 2025 15:23:04 -0800 Subject: [PATCH 040/102] Add conditional `Sendable` conformance to `DispatchSpecificKey`. --- src/swift/Queue.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 4b719f9bf..f590c32df 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -19,6 +19,9 @@ public final class DispatchSpecificKey { public init() {} } +extension DispatchSpecificKey : Sendable where T : Sendable { +} + internal class _DispatchSpecificValue { internal let value: T internal init(value: T) { self.value = value } From d5cd841f2047971b06c8009524b7ad6fe644ede3 Mon Sep 17 00:00:00 2001 From: "(null)" Date: Mon, 17 Mar 2025 12:51:37 -0400 Subject: [PATCH 041/102] indentation fix --- src/event/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 7c85cfb02..b06e03347 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -257,7 +257,7 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) { struct kinfo_proc kp[WORKQ_MAX_TRACKED_TIDS]; size_t size; - int count, runners = 0; + int count, runners = 0; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)getpid()}; // get size we need From 67c57d1cf281cfab62bd908697271c6e064bfe1b Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 12 Mar 2025 15:13:06 -0700 Subject: [PATCH 042/102] build: simplify option handling slightly Reduce the verbosity in the generator expression to apply the compile flags to C or C++ code only. --- CMakeLists.txt | 20 +-- cmake/modules/DispatchCompilerWarnings.cmake | 138 +++++++++---------- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca03e573a..1e6519f5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -245,7 +245,7 @@ else() set(USE_MACH_SEM 0) endif() if(CMAKE_SYSTEM_NAME STREQUAL Windows) - add_compile_definitions($<$,$>:USE_WIN32_SEM>) + add_compile_definitions($<$:USE_WIN32_SEM>) endif() check_library_exists(pthread sem_init "" USE_POSIX_SEM) # NOTE: android has not always provided a libpthread, but uses the pthreads API @@ -275,7 +275,7 @@ check_symbol_exists(VQ_FREE_SPACE_CHANGE "sys/mount.h" HAVE_DECL_VQ_FREE_SPACE_C check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY) check_symbol_exists(program_invocation_name "errno.h" HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) if (HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) - add_compile_definitions($<$,$>:_GNU_SOURCE=1>) + add_compile_definitions($<$:_GNU_SOURCE=1>) endif() check_symbol_exists(__printflike "bsd/sys/cdefs.h" HAVE_PRINTFLIKE) @@ -284,7 +284,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Android) endif() if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) - add_compile_definitions($<$,$>:_WITH_DPRINTF>) + add_compile_definitions($<$:_WITH_DPRINTF>) endif() if(ENABLE_DTRACE) @@ -295,9 +295,9 @@ if(ENABLE_DTRACE) endif() if(dtrace_EXECUTABLE) - add_compile_definitions($<$,$>:DISPATCH_USE_DTRACE=1>) + add_compile_definitions($<$:DISPATCH_USE_DTRACE=1>) else() - add_compile_definitions($<$,$>:DISPATCH_USE_DTRACE=0>) + add_compile_definitions($<$:DISPATCH_USE_DTRACE=0>) endif() find_program(leaks_EXECUTABLE leaks) @@ -307,16 +307,16 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL Darwin) - add_compile_options($<$,$>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap> - $<$,$>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/darwin/module.modulemap>) + add_compile_options($<:$:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap> + $<:$:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/darwin/module.modulemap>) else() - add_compile_options($<$,$>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/generic/module.modulemap> - $<$,$>:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/generic/module.modulemap>) + add_compile_options($<$:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/generic/module.modulemap> + $<$:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/generic/module.modulemap>) endif() configure_file("${PROJECT_SOURCE_DIR}/cmake/config.h.in" "${PROJECT_BINARY_DIR}/config/config_ac.h") -add_compile_definitions($<$,$>:HAVE_CONFIG_H>) +add_compile_definitions($<$:HAVE_CONFIG_H>) if(ENABLE_SWIFT) diff --git a/cmake/modules/DispatchCompilerWarnings.cmake b/cmake/modules/DispatchCompilerWarnings.cmake index cd71f36e5..3fd1b3ddf 100644 --- a/cmake/modules/DispatchCompilerWarnings.cmake +++ b/cmake/modules/DispatchCompilerWarnings.cmake @@ -4,81 +4,81 @@ if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") elseif(WIN32) # Tareting Windows but using a non-MSVC compiler. Set -fms-extensions # so that we can use __popcnt64 - add_compile_options($<$,$>:-fms-extensions>) + add_compile_options($<$:-fms-extensions>) else() - add_compile_options($<$,$>:-Werror>) - add_compile_options($<$,$>:-Wall>) - add_compile_options($<$,$>:-Wextra>) + add_compile_options($<$:-Werror>) + add_compile_options($<$:-Wall>) + add_compile_options($<$:-Wextra>) - add_compile_options($<$,$>:-Warray-bounds-pointer-arithmetic>) - add_compile_options($<$,$>:-Wassign-enum>) - add_compile_options($<$,$>:-Watomic-properties>) - add_compile_options($<$,$>:-Wcomma>) - add_compile_options($<$,$>:-Wconditional-uninitialized>) - add_compile_options($<$,$>:-Wconversion>) - add_compile_options($<$,$>:-Wcovered-switch-default>) - add_compile_options($<$,$>:-Wdate-time>) - add_compile_options($<$,$>:-Wdeprecated>) - add_compile_options($<$,$>:-Wdocumentation>) - add_compile_options($<$,$>:-Wdouble-promotion>) - add_compile_options($<$,$>:-Wduplicate-enum>) - add_compile_options($<$,$>:-Wexpansion-to-defined>) - add_compile_options($<$,$>:-Wfloat-equal>) - add_compile_options($<$,$>:-Widiomatic-parentheses>) - add_compile_options($<$,$>:-Winfinite-recursion>) - add_compile_options($<$,$>:-Wmissing-prototypes>) - add_compile_options($<$,$>:-Wnewline-eof>) - add_compile_options($<$,$>:-Wnullable-to-nonnull-conversion>) - add_compile_options($<$,$>:-Wobjc-interface-ivars>) - add_compile_options($<$,$>:-Wover-aligned>) - add_compile_options($<$,$>:-Wpacked>) - add_compile_options($<$,$>:-Wpointer-arith>) - add_compile_options($<$,$>:-Wselector>) - add_compile_options($<$,$>:-Wshadow>) - add_compile_options($<$,$>:-Wshorten-64-to-32>) - add_compile_options($<$,$>:-Wsign-conversion>) - add_compile_options($<$,$>:-Wstatic-in-inline>) - add_compile_options($<$,$>:-Wsuper-class-method-mismatch>) - add_compile_options($<$,$>:-Wswitch>) - add_compile_options($<$,$>:-Wunguarded-availability>) - add_compile_options($<$,$>:-Wunreachable-code>) - add_compile_options($<$,$>:-Wunused>) + add_compile_options($<$:-Warray-bounds-pointer-arithmetic>) + add_compile_options($<$:-Wassign-enum>) + add_compile_options($<$:-Watomic-properties>) + add_compile_options($<$:-Wcomma>) + add_compile_options($<$:-Wconditional-uninitialized>) + add_compile_options($<$:-Wconversion>) + add_compile_options($<$:-Wcovered-switch-default>) + add_compile_options($<$:-Wdate-time>) + add_compile_options($<$:-Wdeprecated>) + add_compile_options($<$:-Wdocumentation>) + add_compile_options($<$:-Wdouble-promotion>) + add_compile_options($<$:-Wduplicate-enum>) + add_compile_options($<$:-Wexpansion-to-defined>) + add_compile_options($<$:-Wfloat-equal>) + add_compile_options($<$:-Widiomatic-parentheses>) + add_compile_options($<$:-Winfinite-recursion>) + add_compile_options($<$:-Wmissing-prototypes>) + add_compile_options($<$:-Wnewline-eof>) + add_compile_options($<$:-Wnullable-to-nonnull-conversion>) + add_compile_options($<$:-Wobjc-interface-ivars>) + add_compile_options($<$:-Wover-aligned>) + add_compile_options($<$:-Wpacked>) + add_compile_options($<$:-Wpointer-arith>) + add_compile_options($<$:-Wselector>) + add_compile_options($<$:-Wshadow>) + add_compile_options($<$:-Wshorten-64-to-32>) + add_compile_options($<$:-Wsign-conversion>) + add_compile_options($<$:-Wstatic-in-inline>) + add_compile_options($<$:-Wsuper-class-method-mismatch>) + add_compile_options($<$:-Wswitch>) + add_compile_options($<$:-Wunguarded-availability>) + add_compile_options($<$:-Wunreachable-code>) + add_compile_options($<$:-Wunused>) - add_compile_options($<$,$>:-Wno-unknown-warning-option>) - add_compile_options($<$,$>:-Wno-trigraphs>) - add_compile_options($<$,$>:-Wno-four-char-constants>) - add_compile_options($<$,$>:-Wno-disabled-macro-expansion>) - add_compile_options($<$,$>:-Wno-pedantic>) - add_compile_options($<$,$>:-Wno-bad-function-cast>) - add_compile_options($<$,$>:-Wno-c++-compat>) - add_compile_options($<$,$>:-Wno-c++98-compat>) - add_compile_options($<$,$>:-Wno-c++98-compat-pedantic>) - add_compile_options($<$,$>:-Wno-cast-align>) - add_compile_options($<$,$>:-Wno-cast-qual>) - add_compile_options($<$,$>:-Wno-documentation-unknown-command>) - add_compile_options($<$,$>:-Wno-format-nonliteral>) - add_compile_options($<$,$>:-Wno-missing-variable-declarations>) - add_compile_options($<$,$>:-Wno-old-style-cast>) - add_compile_options($<$,$>:-Wno-padded>) - add_compile_options($<$,$>:-Wno-reserved-id-macro>) - add_compile_options($<$,$>:-Wno-shift-sign-overflow>) - add_compile_options($<$,$>:-Wno-undef>) - add_compile_options($<$,$>:-Wno-unreachable-code-aggressive>) - add_compile_options($<$,$>:-Wno-unused-macros>) - add_compile_options($<$,$>:-Wno-used-but-marked-unused>) - add_compile_options($<$,$>:-Wno-void-pointer-to-int-cast>) - add_compile_options($<$,$>:-Wno-vla>) + add_compile_options($<$:-Wno-unknown-warning-option>) + add_compile_options($<$:-Wno-trigraphs>) + add_compile_options($<$:-Wno-four-char-constants>) + add_compile_options($<$:-Wno-disabled-macro-expansion>) + add_compile_options($<$:-Wno-pedantic>) + add_compile_options($<$:-Wno-bad-function-cast>) + add_compile_options($<$:-Wno-c++-compat>) + add_compile_options($<$:-Wno-c++98-compat>) + add_compile_options($<$:-Wno-c++98-compat-pedantic>) + add_compile_options($<$:-Wno-cast-align>) + add_compile_options($<$:-Wno-cast-qual>) + add_compile_options($<$:-Wno-documentation-unknown-command>) + add_compile_options($<$:-Wno-format-nonliteral>) + add_compile_options($<$:-Wno-missing-variable-declarations>) + add_compile_options($<$:-Wno-old-style-cast>) + add_compile_options($<$:-Wno-padded>) + add_compile_options($<$:-Wno-reserved-id-macro>) + add_compile_options($<$:-Wno-shift-sign-overflow>) + add_compile_options($<$:-Wno-undef>) + add_compile_options($<$:-Wno-unreachable-code-aggressive>) + add_compile_options($<$:-Wno-unused-macros>) + add_compile_options($<$:-Wno-used-but-marked-unused>) + add_compile_options($<$:-Wno-void-pointer-to-int-cast>) + add_compile_options($<$:-Wno-vla>) if(CMAKE_SYSTEM_NAME STREQUAL Android) - add_compile_options($<$,$>:-Wno-incompatible-function-pointer-types>) - add_compile_options($<$,$>:-Wno-implicit-function-declaration>) - add_compile_options($<$,$>:-Wno-conversion>) - add_compile_options($<$,$>:-Wno-int-conversion>) - add_compile_options($<$,$>:-Wno-shorten-64-to-32>) + add_compile_options($<$:-Wno-incompatible-function-pointer-types>) + add_compile_options($<$:-Wno-implicit-function-declaration>) + add_compile_options($<$:-Wno-conversion>) + add_compile_options($<$:-Wno-int-conversion>) + add_compile_options($<$:-Wno-shorten-64-to-32>) endif() - add_compile_options($<$,$>:-Wno-error=assign-enum>) + add_compile_options($<$:-Wno-error=assign-enum>) # Should re-enable after rdar://133498289 is fixed (ie. fixing the one mismatched cast in apply.c) - add_compile_options($<$,$>:-Wno-cast-function-type-mismatch>) - add_compile_options($<$,$>:-Wno-error=unknown-warning-option>) + add_compile_options($<$:-Wno-cast-function-type-mismatch>) + add_compile_options($<$:-Wno-error=unknown-warning-option>) endif() From e210ce63f6bb6b1386f5feac7f0e7cc5df8b222f Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 12 Mar 2025 15:16:51 -0700 Subject: [PATCH 043/102] build: bring `config.h.in` into sync with checked in copy `HAVE_STRLCPY` was added to the static configuration but not the dynamic configuration. Update the template for this. --- cmake/config.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/config.h.in b/cmake/config.h.in index 2896a2083..27737c991 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -257,3 +257,6 @@ /* Define if using Darwin $NOCANCEL */ #cmakedefine __DARWIN_NON_CANCELABLE + +/* Define to 1 if you have the `strlcpy` function. */ +#cmakedefine01 HAVE_STRLCPY From 7bb64702f03c6c928f29e9273b8edbc4a2adb74d Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 24 Mar 2025 11:31:09 -0700 Subject: [PATCH 044/102] dispatch: remove `DispatchStubs` on non-ObjC targets This is no longer required. Address the long standing FIXME and simplify the build. --- CMakeLists.txt | 2 ++ dispatch/CMakeLists.txt | 4 +--- dispatch/generic_static/module.modulemap | 19 --------------- src/BlocksRuntime/CMakeLists.txt | 3 --- src/CMakeLists.txt | 9 +------- src/swift/CMakeLists.txt | 23 ++++++++++--------- .../{DispatchStubs.cc => DispatchStubs.m} | 14 ++--------- 7 files changed, 18 insertions(+), 56 deletions(-) delete mode 100644 dispatch/generic_static/module.modulemap rename src/swift/{DispatchStubs.cc => DispatchStubs.m} (84%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e6519f5d..c040cb2a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ project(dispatch VERSION 1.3 LANGUAGES C CXX) +set(CMAKE_POSITION_INDEPENDENT_CODE YES) + if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") include(ClangClCompileRules) endif() diff --git a/dispatch/CMakeLists.txt b/dispatch/CMakeLists.txt index a7f5fc306..352915d91 100644 --- a/dispatch/CMakeLists.txt +++ b/dispatch/CMakeLists.txt @@ -1,10 +1,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap) -elseif(BUILD_SHARED_LIBS) - set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/generic/module.modulemap) else() - set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/generic_static/module.modulemap) + set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/generic/module.modulemap) endif() configure_file(dispatch-vfs.yaml.in ${CMAKE_BINARY_DIR}/dispatch-vfs-overlay.yaml diff --git a/dispatch/generic_static/module.modulemap b/dispatch/generic_static/module.modulemap deleted file mode 100644 index d5d64d2d1..000000000 --- a/dispatch/generic_static/module.modulemap +++ /dev/null @@ -1,19 +0,0 @@ -module Dispatch { - requires blocks - export * - link "dispatch" - link "BlocksRuntime" - link "DispatchStubs" -} - -module DispatchIntrospection [system] [extern_c] { - header "introspection.h" - export * -} - -module CDispatch [system] [extern_c] { - umbrella header "dispatch.h" - export * - requires blocks - link "dispatch" -} diff --git a/src/BlocksRuntime/CMakeLists.txt b/src/BlocksRuntime/CMakeLists.txt index 945e87a7e..f6fde93ee 100644 --- a/src/BlocksRuntime/CMakeLists.txt +++ b/src/BlocksRuntime/CMakeLists.txt @@ -19,9 +19,6 @@ if(HAVE_OBJC AND CMAKE_DL_LIBS) ${CMAKE_DL_LIBS}) endif() -set_target_properties(BlocksRuntime PROPERTIES - POSITION_INDEPENDENT_CODE TRUE) - if(LINKER_SUPPORTS_BUILD_ID) target_link_options(BlocksRuntime PRIVATE "LINKER:--build-id=sha1") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 320b6fcdc..846fb39b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,19 +82,12 @@ if(ENABLE_DTRACE) endif() if(HAVE_OBJC) - # TODO(compnerd) split DispatchStubs.cc into a separate component for the ObjC - # registration and a separate component for the swift compiler's emission of a - # call to the ObjC autorelease elision entry point. target_sources(dispatch PRIVATE data.m object.m - swift/DispatchStubs.cc) + swift/DispatchStubs.m) endif() - -set_target_properties(dispatch PROPERTIES - POSITION_INDEPENDENT_CODE YES) - target_include_directories(dispatch PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} diff --git a/src/swift/CMakeLists.txt b/src/swift/CMakeLists.txt index 4fffc84a4..38bef37af 100644 --- a/src/swift/CMakeLists.txt +++ b/src/swift/CMakeLists.txt @@ -1,9 +1,9 @@ -add_library(DispatchStubs STATIC - DispatchStubs.cc) -target_include_directories(DispatchStubs PRIVATE - ${PROJECT_SOURCE_DIR}) -set_target_properties(DispatchStubs PROPERTIES - POSITION_INDEPENDENT_CODE YES) +if(HAVE_OBJC) + add_library(DispatchStubs STATIC + DispatchStubs.m) + target_include_directories(DispatchStubs PRIVATE + ${PROJECT_SOURCE_DIR}) +endif() add_library(swiftDispatch Block.swift @@ -27,10 +27,14 @@ set_target_properties(swiftDispatch PROPERTIES Swift_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/swift INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/swift) target_link_libraries(swiftDispatch PRIVATE - DispatchStubs + $<$:DispatchStubs> BlocksRuntime::BlocksRuntime) target_link_libraries(swiftDispatch PUBLIC dispatch) +if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") + target_link_options(swiftDispatch PRIVATE "SHELL:-no-toolchain-stdlib-rpath") + set_target_properties(swiftDispatch PROPERTIES INSTALL_RPATH "$ORIGIN") +endif() get_swift_host_arch(swift_arch) install(FILES @@ -43,12 +47,9 @@ install(TARGETS swiftDispatch ARCHIVE DESTINATION ${INSTALL_TARGET_DIR} LIBRARY DESTINATION ${INSTALL_TARGET_DIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -if(NOT BUILD_SHARED_LIBS) +if(HAVE_OBJC AND NOT BUILD_SHARED_LIBS) set_property(GLOBAL APPEND PROPERTY DISPATCH_EXPORTS DispatchStubs) install(TARGETS DispatchStubs EXPORT dispatchExports DESTINATION ${INSTALL_TARGET_DIR}) -elseif(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") - target_link_options(swiftDispatch PRIVATE "SHELL:-no-toolchain-stdlib-rpath") - set_target_properties(swiftDispatch PROPERTIES INSTALL_RPATH "$ORIGIN") endif() diff --git a/src/swift/DispatchStubs.cc b/src/swift/DispatchStubs.m similarity index 84% rename from src/swift/DispatchStubs.cc rename to src/swift/DispatchStubs.m index dc320da29..1f72233eb 100644 --- a/src/swift/DispatchStubs.cc +++ b/src/swift/DispatchStubs.m @@ -11,13 +11,6 @@ //===----------------------------------------------------------------------===// #include -#include - -#if defined(__ELF__) || defined(__MACH__) || defined(__WASM__) -#define DISPATCH_RUNTIME_STDLIB_INTERFACE __attribute__((__visibility__("default"))) -#else -#define DISPATCH_RUNTIME_STDLIB_INTERFACE __declspec(dllexport) -#endif #if USE_OBJC @protocol OS_dispatch_source; @@ -34,11 +27,9 @@ @protocol OS_dispatch_source_vnode; @protocol OS_dispatch_source_write; -// #include -__attribute__((constructor)) +__attribute__((__constructor__)) static void _dispatch_overlay_constructor() { - Class source = objc_lookUpClass("OS_dispatch_source"); - if (source) { + if (Class source = objc_lookUpClass("OS_dispatch_source")) { class_addProtocol(source, @protocol(OS_dispatch_source)); class_addProtocol(source, @protocol(OS_dispatch_source_mach_send)); class_addProtocol(source, @protocol(OS_dispatch_source_mach_recv)); @@ -54,5 +45,4 @@ static void _dispatch_overlay_constructor() { class_addProtocol(source, @protocol(OS_dispatch_source_write)); } } - #endif /* USE_OBJC */ From 51ca1f04bd10c332afb9e92b5a9fb397e1aa2e18 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 12 Mar 2025 14:59:53 -0700 Subject: [PATCH 045/102] build: remove cross-compilation support These can be controlled by the user external to the project. Remove this to simplify the rules. --- CMakeLists.txt | 9 --- cmake/modules/DispatchWindowsSupport.cmake | 74 ---------------------- 2 files changed, 83 deletions(-) delete mode 100644 cmake/modules/DispatchWindowsSupport.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c040cb2a5..3211ba2f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,15 +20,6 @@ if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") endif() if(CMAKE_SYSTEM_NAME STREQUAL Windows) - if(NOT MINGW) - include(DispatchWindowsSupport) - dispatch_windows_arch_spelling(${CMAKE_SYSTEM_PROCESSOR} DISPATCH_MSVC_ARCH) - dispatch_windows_include_for_arch(${DISPATCH_MSVC_ARCH} DISPATCH_INCLUDES) - include_directories(BEFORE SYSTEM ${DISPATCH_INCLUDES}) - dispatch_windows_lib_for_arch(${CMAKE_SYSTEM_PROCESSOR} DISPATCH_LIBDIR) - link_directories(${DISPATCH_LIBDIR}) - endif() - include(CheckCSourceCompiles) include(CheckSymbolExists) diff --git a/cmake/modules/DispatchWindowsSupport.cmake b/cmake/modules/DispatchWindowsSupport.cmake deleted file mode 100644 index 750b3be11..000000000 --- a/cmake/modules/DispatchWindowsSupport.cmake +++ /dev/null @@ -1,74 +0,0 @@ - -function(dispatch_windows_arch_spelling arch var) - if(${arch} STREQUAL i686) - set(${var} x86 PARENT_SCOPE) - elseif(${arch} STREQUAL x86_64 OR ${arch} STREQUAL AMD64) - set(${var} x64 PARENT_SCOPE) - elseif(${arch} STREQUAL armv7) - set(${var} arm PARENT_SCOPE) - elseif(${arch} STREQUAL aarch64 OR ${arch} STREQUAL ARM64) - set(${var} arm64 PARENT_SCOPE) - else() - message(FATAL_ERROR "do not know MSVC spelling for ARCH: `${arch}`") - endif() -endfunction() - -function(dispatch_verify_windows_environment_variables) - set(VCToolsInstallDir $ENV{VCToolsInstallDir}) - set(UniversalCRTSdkDir $ENV{UniversalCRTSdkDir}) - set(UCRTVersion $ENV{UCRTVersion}) - - if("${VCToolsInstallDir}" STREQUAL "") - message(SEND_ERROR "VCToolsInstallDir environment variable must be set") - endif() - if("${UniversalCRTSdkDir}" STREQUAL "") - message(SEND_ERROR "UniversalCRTSdkDir environment variable must be set") - endif() - if("${UCRTVersion}" STREQUAL "") - message(SEND_ERROR "UCRTVersion environment variable must be set") - endif() -endfunction() - -function(dispatch_windows_include_for_arch arch var) - dispatch_verify_windows_environment_variables() - - set(paths - "$ENV{VCToolsInstallDir}/include" - "$ENV{UniversalCRTSdkDir}/Include/$ENV{UCRTVersion}/ucrt" - "$ENV{UniversalCRTSdkDir}/Include/$ENV{UCRTVersion}/shared" - "$ENV{UniversalCRTSdkDir}/Include/$ENV{UCRTVersion}/um") - set(${var} ${paths} PARENT_SCOPE) -endfunction() - -function(dispatch_windows_lib_for_arch arch var) - dispatch_verify_windows_environment_variables() - dispatch_windows_arch_spelling(${arch} ARCH) - - set(paths) - if(${ARCH} STREQUAL x86) - list(APPEND paths "$ENV{VCToolsInstallDir}/Lib") - else() - list(APPEND paths "$ENV{VCToolsInstallDir}/Lib/${ARCH}") - endif() - list(APPEND paths - "$ENV{UniversalCRTSdkDir}/Lib/$ENV{UCRTVersion}/ucrt/${ARCH}" - "$ENV{UniversalCRTSdkDir}/Lib/$ENV{UCRTVersion}/um/${ARCH}") - set(${var} ${paths} PARENT_SCOPE) -endfunction() - -function(dispatch_windows_generate_sdk_vfs_overlay flags) - dispatch_verify_windows_environment_variables() - - get_filename_component(VCToolsInstallDir $ENV{VCToolsInstallDir} ABSOLUTE) - get_filename_component(UniversalCRTSdkDir $ENV{UniversalCRTSdkDir} ABSOLUTE) - set(UCRTVersion $ENV{UCRTVersion}) - - # TODO(compnerd) use a target to avoid re-creating this file all the time - configure_file("${PROJECT_SOURCE_DIR}/utils/WindowsSDKVFSOverlay.yaml.in" - "${PROJECT_BINARY_DIR}/windows-sdk-vfs-overlay.yaml" - @ONLY) - - set(${flags} - -ivfsoverlay;"${PROJECT_BINARY_DIR}/windows-sdk-vfs-overlay.yaml" - PARENT_SCOPE) -endfunction() From ce4ef879e5531a407e8274629892bf49b7a27bd2 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Sat, 3 Oct 2020 00:20:01 -0400 Subject: [PATCH 046/102] Handle absence of EVFILT_USER with kevent backend. Some kqueue implementations do not have EVFILT_USER. We can work around this by creating a timer implementation with a very small timeout.[1] [1] Thanks to this post, which provided the idea for the workaround: https://lists.macosforge.org/pipermail/libdispatch-dev/2009-September/000010.html --- src/event/event_kevent.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index a2c8c5f1d..d64636623 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -104,7 +104,9 @@ _evfiltstr(short filt) #ifdef EVFILT_FS _evfilt2(EVFILT_FS); #endif +#ifdef EVFILT_USER _evfilt2(EVFILT_USER); +#endif #ifdef EVFILT_SOCK _evfilt2(EVFILT_SOCK); #endif @@ -532,11 +534,22 @@ _dispatch_kevent_merge_muxed(dispatch_kevent_t ke) } } +/* + * If the kevent implementation doesn't support EVFILT_USER for + * signaling, then we use EVFILT_TIMER with EV_ONESHOT with this ident + * to make do. + */ +#define DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT (~0ull << 9) + DISPATCH_NOINLINE static void _dispatch_kevent_drain(dispatch_kevent_t ke) { +#ifdef EVFILT_USER if (ke->filter == EVFILT_USER) { +#else + if (ke->filter == EVFILT_TIMER && ke->ident == DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT) { +#endif _dispatch_kevent_mgr_debug("received", ke); return; } @@ -583,10 +596,17 @@ static void _dispatch_kq_create(intptr_t *fd_ptr) { static const dispatch_kevent_s kev = { +#ifdef EVFILT_USER .ident = 1, .filter = EVFILT_USER, .flags = EV_ADD|EV_CLEAR, .udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER, +#else + .ident = DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT, + .filter = EVFILT_TIMER, + .flags = EV_ADD|EV_DISABLE|EV_ONESHOT, + .data = 1, +#endif }; int kqfd; @@ -789,9 +809,15 @@ _dispatch_kq_drain(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, #if DISPATCH_DEBUG for (r = 0; r < n; r++) { +#ifdef EVFILT_USER if (ke[r].filter != EVFILT_USER || DISPATCH_MGR_QUEUE_DEBUG) { _dispatch_kevent_debug_n(NULL, ke + r, r, n); } +#else + if (DISPATCH_MGR_QUEUE_DEBUG) { + _dispatch_kevent_debug_n(NULL, ke + r, r, n); + } +#endif } #endif @@ -923,9 +949,13 @@ _dispatch_kq_deferred_update(dispatch_wlh_t wlh, dispatch_kevent_t ke) ke->udata); dispatch_kevent_t dk = _dispatch_kq_deferred_reuse_slot(wlh, ddi, slot); *dk = *ke; +#ifdef EVFILT_USER if (ke->filter != EVFILT_USER) { _dispatch_kevent_mgr_debug("deferred", ke); } +#else + _dispatch_kevent_mgr_debug("deferred", ke); +#endif } else { _dispatch_kq_update_one(wlh, ke); } @@ -1887,10 +1917,17 @@ _dispatch_event_loop_poke(dispatch_wlh_t wlh, uint64_t dq_state, uint32_t flags) { if (wlh == DISPATCH_WLH_MANAGER) { dispatch_kevent_s ke = (dispatch_kevent_s){ +#ifdef EVFILT_USER .ident = 1, .filter = EVFILT_USER, .fflags = NOTE_TRIGGER, .udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER, +#else + .ident = DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT, + .filter = EVFILT_TIMER, + .flags = EV_ADD|EV_ENABLE|EV_ONESHOT, + .data = 1 +#endif }; return _dispatch_kq_deferred_update(DISPATCH_WLH_ANON, &ke); } else if (wlh && wlh != DISPATCH_WLH_ANON) { From 937f30969c181ef399b755ce251d2028f1b6bbd7 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Wed, 7 Jul 2021 13:01:27 -0400 Subject: [PATCH 047/102] Cast when printing dispatch_unote_ident_t. Different platforms may define dispatch_unote_ident_t differently and subsequently this type may have different bit widths. Therefore, when printing du_ident, cast explicitly to deal with format mismatch errors. The alternative is to specify explicit format string macros, but this is a little complex and casting is already being used in #584. One special case for consideration is `_dispatch_timer_unote_disarm`; this gets the `du_ident` and converts that into a `uint32_t` timer index. When `dispatch_unote_ident` is a `uint32_t` this is of course fine, but needs consideration for when it isn't. Here, we just cast down. This is somewhat reasonable since this is initialized from `_dispatch_timer_unote_idx` which returns an `unsigned int`. (Of course, we are not actually bounds checking that index, but that's outside the scope of this commit). --- src/event/event.c | 2 +- src/event/event_internal.h | 2 ++ src/event/event_kevent.c | 4 ++-- src/init.c | 4 ++-- src/source.c | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/event/event.c b/src/event/event.c index 6ace80ecb..33df9f171 100644 --- a/src/event/event.c +++ b/src/event/event.c @@ -792,7 +792,7 @@ static void _dispatch_timer_unote_disarm(dispatch_timer_source_refs_t dt, dispatch_timer_heap_t dth) { - uint32_t tidx = dt->du_ident; + uint32_t tidx = (uint32_t)dt->du_ident; dispatch_assert(_dispatch_unote_armed(dt)); _dispatch_timer_heap_remove(&dth[tidx], dt); diff --git a/src/event/event_internal.h b/src/event/event_internal.h index 14c485ee3..5b2c7fc80 100644 --- a/src/event/event_internal.h +++ b/src/event/event_internal.h @@ -125,6 +125,8 @@ _dispatch_timer_flags_from_clock(dispatch_clock_t clock) #if defined(_WIN32) typedef uintptr_t dispatch_unote_ident_t; +#elif defined(__OpenBSD__) +typedef uintptr_t dispatch_unote_ident_t; #else typedef uint32_t dispatch_unote_ident_t; #endif diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index d64636623..0d8db09f1 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -240,9 +240,9 @@ dispatch_kevent_debug(const char *verb, const dispatch_kevent_s *kev, #define _dispatch_du_debug(what, du) \ _dispatch_debug("kevent-source[%p]: %s kevent[%p] " \ - "{ filter = %s, ident = 0x%x }", \ + "{ filter = %s, ident = 0x%llx }", \ _dispatch_wref2ptr((du)->du_owner_wref), what, \ - (du), _evfiltstr((du)->du_filter), (du)->du_ident) + (du), _evfiltstr((du)->du_filter), (unsigned long long)(du)->du_ident) #if DISPATCH_MACHPORT_DEBUG #ifndef MACH_PORT_TYPE_SPREQUEST diff --git a/src/init.c b/src/init.c index 0fe0e4385..1640cbab8 100644 --- a/src/init.c +++ b/src/init.c @@ -1049,7 +1049,7 @@ _dispatch_bug_kevent_vanished(dispatch_unote_t du) "{ %p[%s], ident: %" PRIdPTR " / 0x%" PRIxPTR ", handler: %p }", dux_type(du._du)->dst_kind, dou._dq, dou._dq->dq_label ? dou._dq->dq_label : "", - du._du->du_ident, du._du->du_ident, func); + (intptr_t)du._du->du_ident, (uintptr_t)du._du->du_ident, func); } #endif // RDAR_49023449 @@ -1155,7 +1155,7 @@ _dispatch_logv_init(void *context DISPATCH_UNUSED) #else dprintf(dispatch_logfile, "=== log file opened for %s[%u] at " "%ld.%06u ===\n", getprogname() ?: "", getpid(), - tv.tv_sec, (int)tv.tv_usec); + (long)tv.tv_sec, (int)tv.tv_usec); #endif } } diff --git a/src/source.c b/src/source.c index d1581351d..69b731d92 100644 --- a/src/source.c +++ b/src/source.c @@ -1401,8 +1401,8 @@ _dispatch_source_debug_attr(dispatch_source_t ds, char* buf, size_t bufsiz) return dsnprintf(buf, bufsiz, "target = %s[%p], ident = 0x%llx, " "mask = 0x%x, pending_data = 0x%llx, registered = %d, " "armed = %d, %s%s%s", - target && target->dq_label ? target->dq_label : "", target, - (unsigned long long)dr->du_ident, dr->du_fflags, + target && target->dq_label ? target->dq_label : "", + target, (unsigned long long)dr->du_ident, dr->du_fflags, (unsigned long long)dr->ds_pending_data, _du_state_registered(du_state), _du_state_armed(du_state), (dqf & DSF_CANCELED) ? "cancelled, " : "", From 207ed9efaa7ef5e75d5f71d7de46e66867e73a6c Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Wed, 7 Jul 2021 16:17:30 -0400 Subject: [PATCH 048/102] Swift support and OpenBSD. Add the right `os(OpenBSD)` directives. Ensure `DISPATCH_COCOA_COMPAT` is defined and expose the runloop innards for `CFRunLoop` to use in Foundation down the line. --- private/private.h | 2 +- src/queue.c | 2 +- src/swift/Source.swift | 10 +++++----- src/swift/Wrapper.swift | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/private/private.h b/private/private.h index dc1777e49..b0ee07022 100644 --- a/private/private.h +++ b/private/private.h @@ -177,7 +177,7 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); #if TARGET_OS_MAC #define DISPATCH_COCOA_COMPAT 1 -#elif defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(_WIN32) #define DISPATCH_COCOA_COMPAT 1 #else #define DISPATCH_COCOA_COMPAT 0 diff --git a/src/queue.c b/src/queue.c index 4195bddfa..356fef19b 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6950,7 +6950,7 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq) _dispatch_runloop_queue_wakeup(upcast(dq)._dl, 0, false); } -#if TARGET_OS_MAC || defined(_WIN32) +#if TARGET_OS_MAC || defined(_WIN32) || defined(__OpenBSD__) dispatch_runloop_handle_t _dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t dq) { diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 57677c2c2..f9c24280d 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -116,7 +116,7 @@ extension DispatchSource { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public struct ProcessEvent : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } @@ -174,7 +174,7 @@ extension DispatchSource { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public class func makeProcessSource(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { let source = dispatch_source_create(_swift_dispatch_source_type_PROC(), UInt(identifier), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceProcess @@ -224,7 +224,7 @@ extension DispatchSource { return DispatchSource(source: source) as DispatchSourceUserDataReplace } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public class func makeFileSystemObjectSource(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { let source = dispatch_source_create(_swift_dispatch_source_type_VNODE(), UInt(fileDescriptor), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceFileSystemObject @@ -290,7 +290,7 @@ extension DispatchSourceMemoryPressure { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) extension DispatchSourceProcess { public var handle: pid_t { return pid_t(dispatch_source_get_handle(self as! DispatchSource)) @@ -646,7 +646,7 @@ extension DispatchSourceTimer { } } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) extension DispatchSourceFileSystemObject { public var handle: Int32 { return Int32(dispatch_source_get_handle((self as! DispatchSource).__wrapped)) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 999c22d6c..63f76bcd9 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -182,7 +182,7 @@ extension DispatchSource : DispatchSourceMachSend, } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) extension DispatchSource : DispatchSourceProcess, DispatchSourceFileSystemObject { } @@ -273,7 +273,7 @@ public protocol DispatchSourceMemoryPressure : DispatchSourceProtocol { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public protocol DispatchSourceProcess : DispatchSourceProtocol { var handle: pid_t { get } @@ -303,7 +303,7 @@ public protocol DispatchSourceTimer : DispatchSourceProtocol { func scheduleRepeating(wallDeadline: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval) } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public protocol DispatchSourceFileSystemObject : DispatchSourceProtocol { var handle: Int32 { get } From f0f7799d9d462aefa6c2c75570b1443de19ad47c Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Sun, 21 Nov 2021 20:56:12 -0500 Subject: [PATCH 049/102] [event] Workqueue monitoring for OpenBSD. Simply speaking, the global concurrent queue has a thread per cpu and schedules functions or blocks on one of these threads. If these threads are all busy, without workqueue monitoring, we cannot schedule a new function or block until one of those threads returns. If thread(s) have not returned however because they are asleep (say), then we could overcommit the global concurrent queue by scheduling more work. The Linux implementation checks each registered thread ID to see if the corresponding thread is in a runnable state according to procfs every second. On some platforms without procfs, this same information is obtainable essentially via the relevant sysctls. Libraries may exist to facilitate issuing the correct sysctls (c.f. `kvm_getprocs`) but these were not used here so to avoid complications with the right invocations when linking. A unit test is also added to test the overcommit functionality. In this test, we tie up all cpus to prevent the scheduled threads from returning and then attempt to run one more task. If the overcommit monitoring is working as intended, then Dispatch will detect all the threads are simply asleep and will attempt to overcommit. If not, the test will notice the function we attempted to overcommit did not run and fail the test. --- src/event/workqueue.c | 46 +++++++++++++++++++++ src/event/workqueue_internal.h | 2 +- tests/CMakeLists.txt | 6 +++ tests/dispatch_workqueue.c | 74 ++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 tests/dispatch_workqueue.c diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 749b0a452..6bc65c3b6 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -247,6 +247,52 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); } +#elif defined(__OpenBSD__) +#include +#include +#include + +static void +_dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) +{ + struct kinfo_proc kp[WORKQ_MAX_TRACKED_TIDS] = {0}; + size_t size, len; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)getpid(), (int)sizeof(struct kinfo_proc), 0}; + if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) { + _dispatch_debug("workq: Failed to sysctl1"); + return; + } + + size = size > sizeof(kp)? sizeof(kp): size; + len = size / sizeof(struct kinfo_proc); + mib[5] = (int)len; + if (sysctl(mib, 6, kp, &size, NULL, 0) < 0) { + _dispatch_debug("workq: Failed to sysctl2"); + return; + } + + int running_count = 0; + + _dispatch_unfair_lock_lock(&mon->registered_tid_lock); + + for (int i = 0; i < mon->num_registered_tids; i++) { + dispatch_tid tid = mon->registered_tids[i]; + for (size_t j = 0; j < len; j++) { + if ((dispatch_tid)kp[j].p_tid != tid) { + continue; + } + + if (kp[j].p_stat == SRUN || kp[j].p_stat == SIDL || kp[j].p_stat == SONPROC) { + running_count++; + break; + } + } + } + + mon->num_runnable = running_count; + + _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); +} #else #error must define _dispatch_workq_count_runnable_workers #endif diff --git a/src/event/workqueue_internal.h b/src/event/workqueue_internal.h index 62028077a..118d42db5 100644 --- a/src/event/workqueue_internal.h +++ b/src/event/workqueue_internal.h @@ -30,7 +30,7 @@ void _dispatch_workq_worker_register(dispatch_queue_global_t root_q); void _dispatch_workq_worker_unregister(dispatch_queue_global_t root_q); -#if defined(__linux__) || defined(_WIN32) +#if defined(__linux__) || defined(_WIN32) || defined(__OpenBSD__) #define HAVE_DISPATCH_WORKQ_MONITORING 1 #else #define HAVE_DISPATCH_WORKQ_MONITORING 0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0176a062b..9430c7c92 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -183,6 +183,12 @@ set_tests_properties(dispatch_io_pipe_close PROPERTIES TIMEOUT 5) add_unit_test(dispatch_c99 SOURCES dispatch_c99.c) add_unit_test(dispatch_plusplus SOURCES dispatch_plusplus.cpp) +if (DISPATCH_USE_INTERNAL_WORKQUEUE) + add_unit_test(dispatch_workqueue + SOURCES + dispatch_workqueue.c) +endif() + # test-specific link options if(WIN32) target_link_libraries(dispatch_io_muxed PRIVATE WS2_32) diff --git a/tests/dispatch_workqueue.c b/tests/dispatch_workqueue.c new file mode 100644 index 000000000..21e96e043 --- /dev/null +++ b/tests/dispatch_workqueue.c @@ -0,0 +1,74 @@ +#include +#include "dispatch_test.h" + +struct test_context { + uint32_t ncpu; + int flag; +}; + +static void +timeout(void *context) +{ + struct test_context *ctx = (struct test_context *)context; + sleep(2); // Give the monitor the best chance of firing. + test_int32_format(ctx->flag, 1, "flag"); + test_stop(); +} + +static void +raise_flag(void *context) +{ + struct test_context *ctx = (struct test_context *)context; + ctx->flag++; +} + +static void +spin(void *context) +{ + struct test_context *ctx = (struct test_context *)context; + sleep(ctx->ncpu * 2); +} + +static uint32_t +activecpu(void) +{ + uint32_t activecpu; +#if defined(__linux__) || defined(__OpenBSD__) + activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_WIN32) + SYSTEM_INFO si; + GetSystemInfo(&si); + activecpu = si.dwNumberOfProcessors; +#else + size_t s = sizeof(activecpu); + sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0); +#endif + return activecpu; +} + +struct test_context ctx; + +int +main(void) +{ + uint32_t ncpu = activecpu(); + + dispatch_test_start("Dispatch workqueue"); + + dispatch_queue_t global = dispatch_get_global_queue(0, 0); + test_ptr_notnull("dispatch_get_global_queue", global); + + ctx.ncpu = ncpu; + dispatch_async_f(global, &ctx, timeout); + + for(int i = 0; i < (int)ncpu - 1; i++) { + dispatch_async_f(global, &ctx, spin); + } + + // All cpus are tied up at this point. Workqueue + // should execute this function by overcommit. + dispatch_async_f(global, &ctx, raise_flag); + + dispatch_main(); + return 0; +} From 04ab2a4b87f2640c395afb5766a299221b037d3d Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Mon, 22 Aug 2022 22:31:03 -0400 Subject: [PATCH 050/102] Use some disposable heap arrays instead of stack. Using a 512K buffer in this test may mean that the test process may hit the stack size rlimit quickly and segfault. Instead of trying to reduce the buffer sizes and then subsequently try and unwind other weird behavior in this test, just use heap-allocated buffers. We don't actually seem to care about the contents in this test, so we can just throw them away immediately after we read into them. --- tests/dispatch_select.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/dispatch_select.c b/tests/dispatch_select.c index 6202711cb..352157a6e 100644 --- a/tests/dispatch_select.c +++ b/tests/dispatch_select.c @@ -67,8 +67,9 @@ stage1(int stage) dispatch_source_set_event_handler(source, ^{ size_t buffer_size = 500*1024; - char buffer[500*1024]; + char *buffer = malloc(buffer_size*sizeof(char)); ssize_t sz = dispatch_test_fd_read(fd, buffer, buffer_size); + free(buffer); test_sizet_less_than_or_equal("kevent read 1", sz, buffer_size+1); dispatch_source_cancel(source); }); @@ -129,12 +130,14 @@ stage2(void) dispatch_source_set_event_handler(source, ^{ size_t est = dispatch_source_get_data(source); test_sizet_less_than_or_equal("estimated", est, expected - actual); - char buffer[500*1024]; - ssize_t sz = dispatch_test_fd_read(fd, buffer, sizeof(buffer)); + size_t buffer_size = 500*1024*sizeof(char); + char *buffer = malloc(buffer_size); + ssize_t sz = dispatch_test_fd_read(fd, buffer, buffer_size); + free(buffer); actual += sz; - if (sz < (ssize_t)sizeof(buffer)) + if (sz < (ssize_t)(buffer_size)) { - sz = dispatch_test_fd_read(fd, buffer, sizeof(buffer)); + sz = dispatch_test_fd_read(fd, buffer, buffer_size); actual += sz; test_long("EOF", sz, 0); dispatch_source_cancel(source); From 1d1b1b17329f8eeea825a826915fc6dffaad8482 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 15 Apr 2025 21:45:12 -0700 Subject: [PATCH 051/102] build: bump CMake minimum requirement and drop workaround CMake 3.19.0 fixed the compiler invocation requiring the local workaround. Match the runtimes CMake version requirement and drop the workaround. --- CMakeLists.txt | 12 +----------- cmake/modules/ClangClCompileRules.cmake | 5 ----- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 cmake/modules/ClangClCompileRules.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3211ba2f1..4aa0f305e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,14 @@ -cmake_minimum_required(VERSION 3.15.1) +cmake_minimum_required(VERSION 3.26...3.29) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) -# NOTE(compnerd) enable CMP0091 - select MSVC runtime based on -# CMAKE_MSVC_RUNTIME_LIBRARY. Requires CMake 3.15 or newer. -if(POLICY CMP0091) - cmake_policy(SET CMP0091 NEW) -endif() - project(dispatch VERSION 1.3 LANGUAGES C CXX) set(CMAKE_POSITION_INDEPENDENT_CODE YES) -if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") - include(ClangClCompileRules) -endif() - if(CMAKE_SYSTEM_NAME STREQUAL Windows) include(CheckCSourceCompiles) include(CheckSymbolExists) diff --git a/cmake/modules/ClangClCompileRules.cmake b/cmake/modules/ClangClCompileRules.cmake deleted file mode 100644 index 0265d5ea7..000000000 --- a/cmake/modules/ClangClCompileRules.cmake +++ /dev/null @@ -1,5 +0,0 @@ - -# clang-cl interprets paths starting with /U as macro undefines, so we need to -# put a -- before the input file path to force it to be treated as a path. -string(REPLACE "-c " "-c -- " CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}") -string(REPLACE "-c " "-c -- " CMAKE_CXX_COMPILE_OBJECT "${CMAKE_CXX_COMPILE_OBJECT}") From 7ecec133a4ab15c9a1eedaa132bbd272d7adbb79 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 15 Apr 2025 21:53:55 -0700 Subject: [PATCH 052/102] build: simplify system checks (NFC) CMake 3.25 introduced a more consistent way to check what system is being built for. Adopt that uniformly through the build to make it easier to understand. --- CMakeLists.txt | 18 +++++++++--------- cmake/modules/DispatchCompilerWarnings.cmake | 2 +- cmake/modules/DispatchSanitization.cmake | 2 +- cmake/modules/SwiftSupport.cmake | 4 ++-- dispatch/CMakeLists.txt | 2 +- src/BlocksRuntime/CMakeLists.txt | 2 +- src/CMakeLists.txt | 14 +++++++------- src/swift/CMakeLists.txt | 2 +- tests/CMakeLists.txt | 9 ++++----- 9 files changed, 27 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aa0f305e..6df1097f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ project(dispatch set(CMAKE_POSITION_INDEPENDENT_CODE YES) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) include(CheckCSourceCompiles) include(CheckSymbolExists) @@ -128,7 +128,7 @@ set(USE_LIBDISPATCH_INIT_CONSTRUCTOR ${ENABLE_DISPATCH_INIT_CONSTRUCTOR}) option(ENABLE_DTRACE "enable dtrace support" "") -if(CMAKE_SYSTEM_NAME STREQUAL Darwin OR CMAKE_SYSTEM_NAME STREQUAL FreeBSD) +if(APPLE OR BSD) set(ENABLE_INTERNAL_PTHREAD_WORKQUEUES_DEFAULT OFF) else() set(ENABLE_INTERNAL_PTHREAD_WORKQUEUES_DEFAULT ON) @@ -172,7 +172,7 @@ if(__BUILTIN_TRAP) set(HAVE_NORETURN_BUILTIN_TRAP 1) endif() -if(NOT CMAKE_SYSTEM_NAME STREQUAL Android) +if(NOT ANDROID) find_package(LibRT) endif() @@ -227,12 +227,12 @@ if(HAVE_MACH) else() set(USE_MACH_SEM 0) endif() -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) add_compile_definitions($<$:USE_WIN32_SEM>) endif() check_library_exists(pthread sem_init "" USE_POSIX_SEM) # NOTE: android has not always provided a libpthread, but uses the pthreads API -if(CMAKE_SYSTEM_NAME STREQUAL Android) +if(ANDROID) set(USE_POSIX_SEM 1) endif() @@ -262,11 +262,11 @@ if (HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) endif() check_symbol_exists(__printflike "bsd/sys/cdefs.h" HAVE_PRINTFLIKE) -if(CMAKE_SYSTEM_NAME STREQUAL Android) +if(aNDROID) set(ENABLE_DTRACE_DEFAULT OFF) endif() -if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) +if(BSD) add_compile_definitions($<$:_WITH_DPRINTF>) endif() @@ -289,7 +289,7 @@ if(leaks_EXECUTABLE) endif() -if(CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(APPLE) add_compile_options($<:$:-fmodule-map-file=${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap> $<:$:-fmodule-map-file=${PROJECT_SOURCE_DIR}/private/darwin/module.modulemap>) else() @@ -304,7 +304,7 @@ add_compile_definitions($<$:HAVE_CONFIG_H>) if(ENABLE_SWIFT) if(NOT SWIFT_SYSTEM_NAME) - if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + if(APPLE) set(SWIFT_SYSTEM_NAME macosx) else() set(SWIFT_SYSTEM_NAME "$") diff --git a/cmake/modules/DispatchCompilerWarnings.cmake b/cmake/modules/DispatchCompilerWarnings.cmake index 3fd1b3ddf..b10644410 100644 --- a/cmake/modules/DispatchCompilerWarnings.cmake +++ b/cmake/modules/DispatchCompilerWarnings.cmake @@ -69,7 +69,7 @@ else() add_compile_options($<$:-Wno-void-pointer-to-int-cast>) add_compile_options($<$:-Wno-vla>) - if(CMAKE_SYSTEM_NAME STREQUAL Android) + if(ANDROID) add_compile_options($<$:-Wno-incompatible-function-pointer-types>) add_compile_options($<$:-Wno-implicit-function-declaration>) add_compile_options($<$:-Wno-conversion>) diff --git a/cmake/modules/DispatchSanitization.cmake b/cmake/modules/DispatchSanitization.cmake index a0641f524..b5c6ee64f 100644 --- a/cmake/modules/DispatchSanitization.cmake +++ b/cmake/modules/DispatchSanitization.cmake @@ -2,7 +2,7 @@ set(DISPATCH_USE_SANITIZER "" CACHE STRING "Define the sanitizer used to build binaries and tests.") -if(CMAKE_SYSTEM_NAME STREQUAL Darwin AND DISPATCH_USE_SANITIZER) +if(APPLE AND DISPATCH_USE_SANITIZER) message(FATAL_ERROR "building libdispatch with sanitization is not supported on Darwin") endif() diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index c1e5c9d4c..cd8450a0e 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -10,7 +10,7 @@ function(get_swift_host_arch result_var_name) if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") set("${result_var_name}" "x86_64" PARENT_SCOPE) elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "AArch64|aarch64|arm64|ARM64") - if(CMAKE_SYSTEM_NAME MATCHES Darwin) + if(APPLE) set("${result_var_name}" "arm64" PARENT_SCOPE) else() set("${result_var_name}" "aarch64" PARENT_SCOPE) @@ -28,7 +28,7 @@ function(get_swift_host_arch result_var_name) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") set("${result_var_name}" "armv7" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "amd64|AMD64") - if(CMAKE_SYSTEM_NAME MATCHES "Windows") + if(WIN32) set("${result_var_name}" "x86_64" PARENT_SCOPE) else() set("${result_var_name}" "amd64" PARENT_SCOPE) diff --git a/dispatch/CMakeLists.txt b/dispatch/CMakeLists.txt index 352915d91..478ee8fba 100644 --- a/dispatch/CMakeLists.txt +++ b/dispatch/CMakeLists.txt @@ -1,5 +1,5 @@ -if(CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(APPLE) set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/darwin/module.modulemap) else() set(DISPATCH_MODULE_MAP ${PROJECT_SOURCE_DIR}/dispatch/generic/module.modulemap) diff --git a/src/BlocksRuntime/CMakeLists.txt b/src/BlocksRuntime/CMakeLists.txt index f6fde93ee..fc3d60252 100644 --- a/src/BlocksRuntime/CMakeLists.txt +++ b/src/BlocksRuntime/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(BlocksRuntime data.c runtime.c) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) target_sources(BlocksRuntime PRIVATE BlocksRuntime.def) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 846fb39b5..a1f8a0c58 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ -if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(NOT APPLE) add_subdirectory(BlocksRuntime) endif() @@ -57,7 +57,7 @@ add_library(dispatch shims/yield.c shims/yield.h) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) target_sources(dispatch PRIVATE shims/generic_sys_queue.h shims/generic_win_stubs.c @@ -96,11 +96,11 @@ target_include_directories(dispatch PUBLIC target_include_directories(dispatch PRIVATE ${PROJECT_SOURCE_DIR}/private) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) target_compile_definitions(dispatch PRIVATE _CRT_NONSTDC_NO_WARNINGS _CRT_SECURE_NO_WARNINGS) -elseif(CMAKE_SYSTEM_NAME STREQUAL Android) +elseif(ANDROID) target_compile_options(dispatch PRIVATE -U_GNU_SOURCE) endif() @@ -150,7 +150,7 @@ target_link_libraries(dispatch PRIVATE Threads::Threads) target_link_libraries(dispatch PUBLIC BlocksRuntime::BlocksRuntime) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) target_link_libraries(dispatch PRIVATE AdvAPI32 ShLwApi @@ -159,7 +159,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows) synchronization) endif() -if(CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(APPLE) set_property(TARGET dispatch APPEND_STRING PROPERTY LINK_FLAGS "-Xlinker -compatibility_version -Xlinker 1" "-Xlinker -current_version -Xlinker ${VERSION}" @@ -167,7 +167,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Darwin) "-Xlinker -alias_list -Xlinker ${PROJECT_SOURCE_DIR}/xcodeconfig/libdispatch.aliases") endif() -if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") +if(NOT APPLE AND NOT WIN32) set_target_properties(dispatch PROPERTIES INSTALL_RPATH "$ORIGIN") endif() diff --git a/src/swift/CMakeLists.txt b/src/swift/CMakeLists.txt index 38bef37af..059f4ee30 100644 --- a/src/swift/CMakeLists.txt +++ b/src/swift/CMakeLists.txt @@ -31,7 +31,7 @@ target_link_libraries(swiftDispatch PRIVATE BlocksRuntime::BlocksRuntime) target_link_libraries(swiftDispatch PUBLIC dispatch) -if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") +if(NOT APPLE AND NOT WIN32) target_link_options(swiftDispatch PRIVATE "SHELL:-no-toolchain-stdlib-rpath") set_target_properties(swiftDispatch PROPERTIES INSTALL_RPATH "$ORIGIN") endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9430c7c92..f06162874 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ -if(CMAKE_SYSTEM_NAME STREQUAL Windows) +if(WIN32) execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/private" "${CMAKE_CURRENT_BINARY_DIR}/dispatch") @@ -15,7 +15,7 @@ else() "${CMAKE_CURRENT_BINARY_DIR}/leaks-wrapper") endif() -if(CMAKE_SYSTEM_NAME STREQUAL Linux) +if(LINUX) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt") endif() @@ -92,8 +92,7 @@ function(add_unit_test name) # fails with the multiple definition errors seen in android/ndk#176, so I # pulled in this workaround noted there. The tests build and run with this # flag applied. - if(NOT BUILD_SHARED_LIBS AND CMAKE_SYSTEM_NAME STREQUAL Android AND - CMAKE_SYSTEM_PROCESSOR STREQUAL armv7-a) + if(NOT BUILD_SHARED_LIBS AND ANDROID AND CMAKE_SYSTEM_PROCESSOR STREQUAL armv7-a) target_link_options(${name} PRIVATE "LINKER:--allow-multiple-definition") endif() target_link_libraries(${name} @@ -162,7 +161,7 @@ if(EXTENDED_TEST_SUITE) endif() # add C tests for platform-specific functionality when applicable -if(CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(APPLE) list(APPEND DISPATCH_C_TESTS deadname proc From affa604ef705f009deb5da0f579e3238e7227a90 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 16 Apr 2025 14:18:12 -0700 Subject: [PATCH 053/102] Update CMakeLists.txt Co-authored-by: Evan Wilde --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6df1097f2..527c4bc99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,7 +262,7 @@ if (HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) endif() check_symbol_exists(__printflike "bsd/sys/cdefs.h" HAVE_PRINTFLIKE) -if(aNDROID) +if(ANDROID) set(ENABLE_DTRACE_DEFAULT OFF) endif() From 88c34b39a82cddd9e93892c417ed5778a0df45f1 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Mon, 21 Apr 2025 18:12:30 +0200 Subject: [PATCH 054/102] Set CMP0157 to OLD for Android There is no early swift-driver build for the Windows toolchain. As a result, libdispatch fails to build properly when CMP0157 is set to NEW due to object files not being generated. This sets CMP0157 to OLD when targetting Android until the early swift-driver is available on Windows. --- CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 527c4bc99..1d99e0379 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,17 @@ - cmake_minimum_required(VERSION 3.26...3.29) +if(POLICY CMP0157) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows AND CMAKE_SYSTEM_NAME STREQUAL Android) + # CMP0157 causes libdispatch to fail to compile when targetting + # Android on Windows due to swift-driver not being present during the + # toolchain build. Disable it for now. + cmake_policy(SET CMP0157 OLD) + else() + # New Swift build model: improved incremental build performance and LSP support + cmake_policy(SET CMP0157 NEW) + endif() +endif() + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) project(dispatch From 13d250bf29e2af6988be8e92ebc40cce087e57c9 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 8 May 2025 09:41:29 -0700 Subject: [PATCH 055/102] build: simplify the handling for CMP0157 We can use the `CMAKE_Swift_USE_OLD_DRIVER` option to control the behaviour as the issue is related to the old Swift driver. --- CMakeLists.txt | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d99e0379..525fe1292 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,11 @@ cmake_minimum_required(VERSION 3.26...3.29) -if(POLICY CMP0157) - if(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows AND CMAKE_SYSTEM_NAME STREQUAL Android) - # CMP0157 causes libdispatch to fail to compile when targetting - # Android on Windows due to swift-driver not being present during the - # toolchain build. Disable it for now. - cmake_policy(SET CMP0157 OLD) - else() - # New Swift build model: improved incremental build performance and LSP support - cmake_policy(SET CMP0157 NEW) - endif() -endif() - list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) +if(POLICY CMP0157 AND CMAKE_Swift_COMPILER_USE_OLD_DRIVER) + cmake_policy(SET CMP0157 OLD) +endif() + project(dispatch VERSION 1.3 LANGUAGES C CXX) From b1b83360e1dcdc013852185b30800ec5f10f88e0 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 13 May 2025 10:50:16 -0700 Subject: [PATCH 056/102] dispatch: extract `DISPATCH_EXTERN` from the `DISPATCH_EXPORT` macro This extracts a new `DISPATCH_EXTERN` macro from the existing definition of `DISPATCH_EXPORT`. This follows the standard style of many of Darwin's frameworks. Extracting and re-using this macro allows us to make the definition of `DISPATCH_EXPORT` more concise. --- dispatch/base.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dispatch/base.h b/dispatch/base.h index ce65f05f6..6f83a4edb 100644 --- a/dispatch/base.h +++ b/dispatch/base.h @@ -178,24 +178,24 @@ #endif #endif +#ifndef DISPATCH_EXTERN +# if defined(__cplusplus) +# define DISPATCH_EXTERN extern "C" +# else +# define DISPATCH_EXTERN extern +# endif +#endif + #if defined(_WIN32) #if defined(__DISPATCH_BUILDING_DISPATCH__) -#if defined(__cplusplus) -#define DISPATCH_EXPORT extern "C" __declspec(dllexport) +#define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllexport) #else -#define DISPATCH_EXPORT extern __declspec(dllexport) -#endif -#else -#if defined(__cplusplus) -#define DISPATCH_EXPORT extern "C" __declspec(dllimport) -#else -#define DISPATCH_EXPORT extern __declspec(dllimport) -#endif +#define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllimport) #endif #elif __GNUC__ -#define DISPATCH_EXPORT extern __attribute__((visibility("default"))) +#define DISPATCH_EXPORT DISPATCH_EXTERN __attribute__((visibility("default"))) #else -#define DISPATCH_EXPORT extern +#define DISPATCH_EXPORT DISPATCH_EXTERN #endif #if __GNUC__ From e1fb2099d6d82abd70f7f93e9f999aae09347985 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 13 May 2025 10:54:36 -0700 Subject: [PATCH 057/102] dispatch: introduce `dispatch_STATIC` and honour `dispatch_EXPORT` When building with CMake, `dispatch_EXPORT` is automatically defined when building a shared library. We should additionally rely on `dispatch_STATIC` to indicate that we are building a static library. When building statically, we should ensure that the ABI of dispatch does not participate in dynamic linking as otherwise any consuming library would vend the dispatch ABI. Particularly for Linux, this would be problematic as the symbol resolution is ill-defined and can end up with multiple incompatible definitions. Co-authored-by: Evan Wilde --- dispatch/base.h | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/dispatch/base.h b/dispatch/base.h index 6f83a4edb..8e7728525 100644 --- a/dispatch/base.h +++ b/dispatch/base.h @@ -186,16 +186,24 @@ # endif #endif -#if defined(_WIN32) -#if defined(__DISPATCH_BUILDING_DISPATCH__) -#define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllexport) -#else -#define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllimport) -#endif -#elif __GNUC__ -#define DISPATCH_EXPORT DISPATCH_EXTERN __attribute__((visibility("default"))) +#if defined(dispatch_STATIC) +# if __GNUC__ +# define DISPATCH_EXPORT DISPATCH_EXTERN __attribute__((__visibility__("hidden"))) +# else +# define DISPATCH_EXPORT DISPATCH_EXTERN +# endif #else -#define DISPATCH_EXPORT DISPATCH_EXTERN +# if defined(_WIN32) +# if defined(dispatch_EXPORT) || defined(__DISPATCH_BUILDING_DISPATCH__) +# define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllexport) +# else +# define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllimport) +# endif +# elif __GNUC__ +# define DISPATCH_EXPORT DISPATCH_EXTERN __attribute__((__visibility__("default"))) +# else +# define DISPATCH_EXPORT DISPATCH_EXTERN +# endif #endif #if __GNUC__ From 98bcd9be787e9271ab75c4143fe653761cf532bf Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Fri, 16 May 2025 13:36:46 -0700 Subject: [PATCH 058/102] Install nested Swift modules Migrating to using the nested swiftmodule structure. This avoids needing to compute the architecture in the CMake script, using the compiler to tell us what the triple should be, making the build more robust. This also means that we can drop the architecture-specific subdirectory and install the dispatch modules alongside the swiftmodules for the other projects. --- cmake/modules/SwiftSupport.cmake | 67 ++++++++++++-------------------- src/swift/CMakeLists.txt | 6 +-- 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index cd8450a0e..c61b4c435 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,45 +1,28 @@ +if(NOT dispatch_MODULE_TRIPLE) + set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) + if(CMAKE_Swift_COMPILER_TARGET) + list(APPEND module_triple_command -target ${CMAKE_Swift_COMPILER_TARGET}) + endif() + execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) + + string(JSON module_triple GET "${target_info_json}" "target" "moduleTriple") + set(dispatch_MODULE_TRIPLE "${module_triple}" CACHE STRING "Triple used to install swiftmodule files") + mark_as_advanced(dispatch_MODULE_TRIPLE) + + message(CONFIGURE_LOG "Swift module triple: ${module_triple}") +endif() -# Returns the current achitecture name in a variable -# -# Usage: -# get_swift_host_arch(result_var_name) -# -# If the current architecture is supported by Swift, sets ${result_var_name} -# with the sanitized host architecture name derived from CMAKE_SYSTEM_PROCESSOR. -function(get_swift_host_arch result_var_name) - if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") - set("${result_var_name}" "x86_64" PARENT_SCOPE) - elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "AArch64|aarch64|arm64|ARM64") - if(APPLE) - set("${result_var_name}" "arm64" PARENT_SCOPE) - else() - set("${result_var_name}" "aarch64" PARENT_SCOPE) - endif() - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64") - set("${result_var_name}" "powerpc64" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") - set("${result_var_name}" "powerpc64le" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x") - set("${result_var_name}" "s390x" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") - set("${result_var_name}" "armv6" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7-a") - set("${result_var_name}" "armv7" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") - set("${result_var_name}" "armv7" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "amd64|AMD64") - if(WIN32) - set("${result_var_name}" "x86_64" PARENT_SCOPE) - else() - set("${result_var_name}" "amd64" PARENT_SCOPE) - endif() - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") - set("${result_var_name}" "itanium" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86") - set("${result_var_name}" "i686" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") - set("${result_var_name}" "i686" PARENT_SCOPE) - else() - message(FATAL_ERROR "Unrecognized architecture on host system: ${CMAKE_SYSTEM_PROCESSOR}") +function(install_swift_module target) + get_target_property(module ${target} Swift_MODULE_NAME) + if(NOT module) + set(module ${target}) endif() + install( + FILES $/${module}.swiftdoc + DESTINATION ${INSTALL_TARGET_DIR}/${module}.swiftmodule + RENAME ${dispatch_MODULE_TRIPLE}.swiftdoc) + install( + FILES $/${module}.swiftmodule + DESTINATION ${INSTALL_TARGET_DIR}/${module}.swiftmodule + RENAME ${dispatch_MODULE_TRIPLE}.swiftmodule) endfunction() diff --git a/src/swift/CMakeLists.txt b/src/swift/CMakeLists.txt index 059f4ee30..a0082fb1e 100644 --- a/src/swift/CMakeLists.txt +++ b/src/swift/CMakeLists.txt @@ -36,11 +36,7 @@ if(NOT APPLE AND NOT WIN32) set_target_properties(swiftDispatch PROPERTIES INSTALL_RPATH "$ORIGIN") endif() -get_swift_host_arch(swift_arch) -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/swift/Dispatch.swiftmodule - ${CMAKE_CURRENT_BINARY_DIR}/swift/Dispatch.swiftdoc - DESTINATION ${INSTALL_TARGET_DIR}/${swift_arch}) +install_swift_module(swiftDispatch) set_property(GLOBAL APPEND PROPERTY DISPATCH_EXPORTS swiftDispatch) install(TARGETS swiftDispatch EXPORT dispatchExports From 717244701de2311c252c19788a9b6dc69ccb34de Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Fri, 16 May 2025 14:25:40 -0700 Subject: [PATCH 059/102] Include SwiftSupport when needed Support for Swift is only needed when we have Swift enabled. We don't need to include the module when it isn't available. With the change to query the Swift compiler for the module triple, we need the Swift language to be enabled to set the swift module triple. Since the include was pulled from the main CMakeLists file, it's prudent to set the include guard to prevent accidentally loading the module multiple times. --- CMakeLists.txt | 1 - cmake/modules/SwiftSupport.cmake | 2 ++ src/swift/CMakeLists.txt | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 525fe1292..ac6e56857 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,7 +117,6 @@ include(DispatchAppleOptions) include(DispatchSanitization) include(DispatchCompilerWarnings) include(DTrace) -include(SwiftSupport) # 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 diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index c61b4c435..3da519ec5 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,3 +1,5 @@ +include_guard() + if(NOT dispatch_MODULE_TRIPLE) set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) if(CMAKE_Swift_COMPILER_TARGET) diff --git a/src/swift/CMakeLists.txt b/src/swift/CMakeLists.txt index a0082fb1e..d255f2cd7 100644 --- a/src/swift/CMakeLists.txt +++ b/src/swift/CMakeLists.txt @@ -1,3 +1,5 @@ +include(SwiftSupport) + if(HAVE_OBJC) add_library(DispatchStubs STATIC DispatchStubs.m) From a654472134bedd439c4a21baeab5ae528346ebb8 Mon Sep 17 00:00:00 2001 From: "(null)" Date: Wed, 21 May 2025 23:50:43 -0400 Subject: [PATCH 060/102] remove duplicated ifdefs, __unix__ should cover the FreeBSD cases too --- private/private.h | 4 +--- src/queue.c | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/private/private.h b/private/private.h index 17df862a6..8b1e19670 100644 --- a/private/private.h +++ b/private/private.h @@ -191,9 +191,7 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); typedef mach_port_t dispatch_runloop_handle_t; #elif defined(__linux__) typedef int dispatch_runloop_handle_t; -#elif defined(__FreeBSD__) -typedef uint64_t dispatch_runloop_handle_t; -#elif defined(__unix__) && !defined(__linux__) +#elif defined(__unix__) typedef uint64_t dispatch_runloop_handle_t; #elif defined(_WIN32) typedef void *dispatch_runloop_handle_t; diff --git a/src/queue.c b/src/queue.c index 17525c273..1d948e947 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6490,8 +6490,6 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq) #elif defined(__linux__) // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1; -#elif defined(__FreeBSD__) - return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #elif defined(__unix__) return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #elif defined(_WIN32) @@ -6511,9 +6509,7 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #elif defined(__linux__) // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL dq->do_ctxt = (void *)(uintptr_t)(handle + 1); -#elif defined(__FreeBSD__) - dq->do_ctxt = (void *)(uintptr_t)handle; -#elif defined(__unix__) && !defined(__linux__) +#elif defined(__unix__) dq->do_ctxt = (void *)(uintptr_t)handle; #elif defined(_WIN32) dq->do_ctxt = (void *)(uintptr_t)handle; From f642f480deda6e0b668a6f5c8f3cc8db4252f867 Mon Sep 17 00:00:00 2001 From: "(null)" Date: Thu, 22 May 2025 16:23:28 -0400 Subject: [PATCH 061/102] fix build --- src/event/event_kevent.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index 47e0a2a00..0d8db09f1 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -1088,7 +1088,7 @@ _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, dispatch_assume_zero(r); return true; } -#endif // DISPATCH_HAVE_DIRECT_KNOTES +#endif #pragma mark dispatch_muxnote_t @@ -1335,7 +1335,6 @@ enum { DISPATCH_WORKLOOP_SYNC_END, }; -#if DISPATCH_USE_KEVENT_WORKLOOP static char const * const _dispatch_workloop_actions[] = { [DISPATCH_WORKLOOP_ASYNC] = "async", [DISPATCH_WORKLOOP_ASYNC_FROM_SYNC] = "async (from sync)", @@ -1352,7 +1351,7 @@ static char const * const _dispatch_workloop_actions[] = { [DISPATCH_WORKLOOP_SYNC_WAKE] = "sync-wake", [DISPATCH_WORKLOOP_SYNC_END] = "sync-end", }; -#endif // DISPATCH_USE_KEVENT_WORKLOOP +#endif void _dispatch_event_loop_atfork_child(void) From 17ed7bd1d5a0b139ca84b75c18af62b6549e37d3 Mon Sep 17 00:00:00 2001 From: "(null)" Date: Fri, 23 May 2025 01:19:03 -0400 Subject: [PATCH 062/102] indentation fix and address comments --- src/event/workqueue.c | 2 +- src/shims/lock.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 15f22cb15..07cc17bc5 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -313,7 +313,7 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) } // only care about up to WORKQ_MAX_TRACKED_TIDS threads - size = size > sizeof(kp) ? sizeof(kp) : size; + size = MIN(sizeof(kp), size); if (sysctl(mib, 4, kp, &size, NULL, 0) < 0) { _dispatch_debug("workq: failed to get kinfo_proc[] from sysctl"); diff --git a/src/shims/lock.c b/src/shims/lock.c index 9b05ed8b8..6d0ab8764 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -64,7 +64,7 @@ _dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, (void)value; (void)flags; (void)timeout; - sched_yield(); + sched_yield(); } #endif // HAVE_UL_UNFAIR_LOCK #elif defined(__unix__) @@ -551,8 +551,8 @@ _dispatch_wait_on_address(uint32_t volatile *_address, uint32_t value, if (dwMilliseconds == 0) return ETIMEDOUT; return WaitOnAddress(address, &value, sizeof(value), dwMilliseconds) == TRUE; #elif defined(__FreeBSD__) - (void)flags; - if (nsecs != DISPATCH_TIME_FOREVER) { + (void)flags; + if (nsecs != DISPATCH_TIME_FOREVER) { struct timespec ts = { .tv_sec = (__typeof__(ts.tv_sec))(nsecs / NSEC_PER_SEC), .tv_nsec = (__typeof__(ts.tv_nsec))(nsecs % NSEC_PER_SEC), From 08e90e5a225a059500543620d37a4416b3a8c541 Mon Sep 17 00:00:00 2001 From: CodingCarpincho Date: Mon, 26 May 2025 20:18:32 -0700 Subject: [PATCH 063/102] Fix building tests on FreeBSD. The header file sys/sysctl.h needs to imported on FreeBSD in order to get access to the function sysctlbyname. --- tests/dispatch_test.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/dispatch_test.h b/tests/dispatch_test.h index a74da2190..99094ebbf 100644 --- a/tests/dispatch_test.h +++ b/tests/dispatch_test.h @@ -27,6 +27,10 @@ #include #endif +#if defined(__FreeBSD__) +#include +#endif + #define test_group_wait(g) do { \ if (dispatch_group_wait(g, dispatch_time(DISPATCH_TIME_NOW, \ 25ull * NSEC_PER_SEC))) { \ From 3ec2b843bb8cf66ea56018aaaf07c5d076daa76a Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 30 May 2025 10:04:29 +0100 Subject: [PATCH 064/102] [Tests] Fix Dispatch tests to work in container environments. We need to use `pthread_getaffinity_np()` to get the active core count; using `sysconf()` will tell us about the underlying machine, which may have many more cores than the container in which we are executing. rdar://152301793 --- tests/dispatch_apply.c | 9 +++++++++ tests/dispatch_workqueue.c | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/tests/dispatch_apply.c b/tests/dispatch_apply.c index 01b3dfb65..4f80aac71 100644 --- a/tests/dispatch_apply.c +++ b/tests/dispatch_apply.c @@ -21,6 +21,7 @@ #include #include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include #include #ifdef __ANDROID__ #include @@ -83,6 +84,14 @@ static void test_apply_contended(dispatch_queue_t dq) uint32_t activecpu; #if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); + +#if defined(__linux__) && __USE_GNU + cpu_set_t cpuset; + if (pthread_getaffinity_np(pthread_self(), + sizeof(cpu_set_t), + &cpuset) == 0) + activecpu = (uint32_t)CPU_COUNT(&cpuset); +#endif #elif defined(_WIN32) SYSTEM_INFO si; GetSystemInfo(&si); diff --git a/tests/dispatch_workqueue.c b/tests/dispatch_workqueue.c index 21e96e043..c12598b69 100644 --- a/tests/dispatch_workqueue.c +++ b/tests/dispatch_workqueue.c @@ -1,6 +1,11 @@ #include #include "dispatch_test.h" +#if defined(__linux__) +// For pthread_getaffinity_np() +#include +#endif + struct test_context { uint32_t ncpu; int flag; @@ -35,6 +40,15 @@ activecpu(void) uint32_t activecpu; #if defined(__linux__) || defined(__OpenBSD__) activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); + +#if defined(__linux__) && __USE_GNU + cpu_set_t cpuset; + if (pthread_getaffinity_np(pthread_self(), + sizeof(cpu_set_t), + &cpuset) == 0) + activecpu = (uint32_t)CPU_COUNT(&cpuset); +#endif + #elif defined(_WIN32) SYSTEM_INFO si; GetSystemInfo(&si); From e37c2465e08a516099ec2dfc8588380c53c27c44 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 15:35:21 +0200 Subject: [PATCH 065/102] Fix collision of QOS_CLASS_MAINTENANCE and DISPATCH_QOS_USER_INITIATED --- src/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.c b/src/init.c index 2f2efb0ae..b7364fea3 100644 --- a/src/init.c +++ b/src/init.c @@ -383,9 +383,9 @@ dispatch_get_global_queue(intptr_t priority, uintptr_t flags) } dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority); #if !HAVE_PTHREAD_WORKQUEUE_QOS - if (qos == QOS_CLASS_MAINTENANCE) { + if (qos == DISPATCH_QOS_MAINTENANCE) { qos = DISPATCH_QOS_BACKGROUND; - } else if (qos == QOS_CLASS_USER_INTERACTIVE) { + } else if (qos == DISPATCH_QOS_USER_INTERACTIVE) { qos = DISPATCH_QOS_USER_INITIATED; } #endif From 6fb87f82faa14cdf90042fa3849a9c31aec766b8 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 15:35:32 +0200 Subject: [PATCH 066/102] Check for pthread_setname_np --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac6e56857..189cd9fc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,6 +191,7 @@ check_function_exists(pthread_attr_setcpupercent_np HAVE_PTHREAD_ATTR_SETCPUPERC check_function_exists(pthread_yield_np HAVE_PTHREAD_YIELD_NP) check_function_exists(pthread_main_np HAVE_PTHREAD_MAIN_NP) check_function_exists(pthread_workqueue_setdispatch_np HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP) +check_function_exists(pthread_setname_np HAVE_PTHREAD_SETNAME_NP) check_function_exists(strlcpy HAVE_STRLCPY) check_function_exists(sysconf HAVE_SYSCONF) check_function_exists(arc4random HAVE_ARC4RANDOM) From cdeb87de902ba41b81bad5cd7771108f8655e2a2 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 15:35:49 +0200 Subject: [PATCH 067/102] Add HAVE_PTHREAD_SETNAME_NP to config.h.in --- cmake/config.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/config.h.in b/cmake/config.h.in index 27737c991..fc630ea67 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -208,6 +208,9 @@ /* Define to 1 if you have the `_pthread_workqueue_init' function. */ #cmakedefine HAVE__PTHREAD_WORKQUEUE_INIT +/* Define to 1 if you have the `pthread_setname_np' function. */ +#cmakedefine01 HAVE_PTHREAD_SETNAME_NP + /* Define to use non-portable pthread TSD optimizations for Mac OS X) */ #cmakedefine USE_APPLE_TSD_OPTIMIZATIONS From 8e935e022f7d495cbcb237e59b2e92212ee939a6 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 15:37:38 +0200 Subject: [PATCH 068/102] Implement _dispatch_pp_to_nice --- src/shims/priority.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/shims/priority.h b/src/shims/priority.h index 3a79c5efb..e4e51283c 100644 --- a/src/shims/priority.h +++ b/src/shims/priority.h @@ -210,6 +210,46 @@ _dispatch_qos_to_pp(dispatch_qos_t qos) return pp | _PTHREAD_PRIORITY_PRIORITY_MASK; } + +#if defined(__linux__) +// These presets roughly match the `android.os.Process' constants +// used for `setThreadPriority()'. +// +// Be aware that with the Completely Fair Scheduler (CFS) the weight is computed +// as 1024 / (1.25) ^ (nice) where nice is in the range -20 to 19. +// This means that nice is not a linear scale. +#define DISPATCH_NICE_BACKGROUND 10 +#define DISPATCH_NICE_UTILITY 2 +#define DISPATCH_NICE_DEFAULT 0 +// Note that you might not have permission to increase the priority +// of a thread beyond the default priority. +#define DISPATCH_NICE_USER_INITIATED -2 +#define DISPATCH_NICE_USER_INTERACTIVE -4 + +DISPATCH_ALWAYS_INLINE +static inline int _dispatch_pp_to_nice(pthread_priority_t pp) +{ + // FIXME: What about relative priorities? + uint32_t qos = _dispatch_qos_from_pp(pp); + + switch (qos) { + case DISPATCH_QOS_BACKGROUND: + return DISPATCH_NICE_BACKGROUND; + case DISPATCH_QOS_UTILITY: + return DISPATCH_NICE_UTILITY; + case DISPATCH_QOS_DEFAULT: + return DISPATCH_NICE_DEFAULT; + case DISPATCH_QOS_USER_INITIATED: + return DISPATCH_NICE_USER_INITIATED; + case DISPATCH_QOS_USER_INTERACTIVE: + return DISPATCH_NICE_USER_INTERACTIVE; + } + + return DISPATCH_NICE_DEFAULT; +} +#endif // defined(__linux__) + + // including maintenance DISPATCH_ALWAYS_INLINE static inline bool From 8913f063942864b664383148bb77288d5824b12b Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 15:39:08 +0200 Subject: [PATCH 069/102] Basic worker thread prioritization on Linux --- src/queue.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/queue.c b/src/queue.c index 1d948e947..c4859b35d 100644 --- a/src/queue.c +++ b/src/queue.c @@ -23,6 +23,11 @@ #include "protocol.h" // _dispatch_send_wakeup_runloop_thread #endif +#if defined(__linux__) +#include +#include +#endif + static inline void _dispatch_root_queues_init(void); static void _dispatch_lane_barrier_complete(dispatch_lane_class_t dqu, dispatch_qos_t qos, dispatch_wakeup_flags_t flags); @@ -6169,6 +6174,7 @@ _dispatch_root_queue_init_pthread_pool(dispatch_queue_global_t dq, } if (pool_size && pool_size < thread_pool_size) thread_pool_size = pool_size; dq->dgq_thread_pool_size = thread_pool_size; + // TODO: Save priority for later configuration in _dispatch_worker_thread qos_class_t cls = _dispatch_qos_to_qos_class(_dispatch_priority_qos(pri) ?: _dispatch_priority_fallback_qos(pri)); if (cls) { @@ -6216,10 +6222,39 @@ _dispatch_worker_thread(void *context) _dispatch_sigmask(); #endif _dispatch_introspection_thread_add(); + dispatch_priority_t pri = dq->dq_priority; + pthread_priority_t pp = _dispatch_get_priority(); + + // The Linux kernel does not have a direct analogue to the QoS-based + // thread policy engine found in XNU. + // + // We cannot use 'pthread_setschedprio', because all threads with default + // scheduling policy (SCHED_OTHER) have the same pthread 'priority'. + // For both CFS, which was introduced in Linux 2.6.23, and its successor + // EEVDF (since 6.6) 'sched_get_priority_max' and 'sched_get_priority_min' + // will just return 0. + // + // However, as outlined in "man 2 setpriority", the nice value is a + // per‐thread attribute: different threads in the same process can have + // different nice values. We can thus setup the thread's initial priority + // by converting the QoS class and relative priority to a 'nice' value. + #if defined(__linux__) + pp = _dispatch_priority_to_pp_strip_flags(pri); + int nice = _dispatch_pp_to_nice(pp); + + #if HAVE_PTHREAD_SETNAME_NP + pthread_setname_np(pthread_self(), "DispatchWorker"); + #endif + + errno = 0; + int rc = setpriority(PRIO_PROCESS, 0, nice); + if (rc != -1 || errno == 0) { + _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp); + } + + #endif // defined(__linux__) const int64_t timeout = 5ull * NSEC_PER_SEC; - pthread_priority_t pp = _dispatch_get_priority(); - dispatch_priority_t pri = dq->dq_priority; // If the queue is neither // - the manager From dc8a3abb019ef9a3b91f80348fd1ece11d1160e6 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 15:39:20 +0200 Subject: [PATCH 070/102] Fix small typo --- dispatch/queue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dispatch/queue.h b/dispatch/queue.h index e2f7e05e9..ff68d2308 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -173,12 +173,12 @@ DISPATCH_DECL_SUBCLASS(dispatch_queue_main, dispatch_queue_serial); * * @discussion * Dispatch concurrent queues are lightweight objects to which regular and - * barrier workitems may be submited. Barrier workitems are invoked in + * barrier workitems may be submitted. Barrier workitems are invoked in * exclusion of any other kind of workitem in FIFO order. * * Regular workitems can be invoked concurrently for the same concurrent queue, * in any order. However, regular workitems will not be invoked before any - * barrier workitem submited ahead of them has been invoked. + * barrier workitem submitted ahead of them has been invoked. * * In other words, if a serial queue is equivalent to a mutex in the Dispatch * world, a concurrent queue is equivalent to a reader-writer lock, where From cf2abb1ab4b516c633a3357b65e5fa8d43c67a92 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 16:17:21 +0200 Subject: [PATCH 071/102] Remove TODO --- src/queue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/queue.c b/src/queue.c index c4859b35d..490d7be47 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6174,7 +6174,6 @@ _dispatch_root_queue_init_pthread_pool(dispatch_queue_global_t dq, } if (pool_size && pool_size < thread_pool_size) thread_pool_size = pool_size; dq->dgq_thread_pool_size = thread_pool_size; - // TODO: Save priority for later configuration in _dispatch_worker_thread qos_class_t cls = _dispatch_qos_to_qos_class(_dispatch_priority_qos(pri) ?: _dispatch_priority_fallback_qos(pri)); if (cls) { From 1072e1ca5ae1872c4f981f93c922edafb58255f3 Mon Sep 17 00:00:00 2001 From: hmelder Date: Tue, 27 Aug 2024 18:56:10 -0700 Subject: [PATCH 072/102] Basic prioritisation on Windows --- src/queue.c | 61 ++++++++++++++++++++++++++++++++++++++++++-- src/shims/priority.h | 23 +++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/queue.c b/src/queue.c index 490d7be47..256ce2dbe 100644 --- a/src/queue.c +++ b/src/queue.c @@ -28,6 +28,29 @@ #include #endif +#if defined(_WIN32) +// Needs to be free'd after use +static inline wchar_t *_Nullable _dispatch_char_to_wchar_str(const char *str) { + int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if (wideCharSize == 0) { + return NULL; + } + + wchar_t* wideCharStr = (wchar_t*)malloc(wideCharSize * sizeof(wchar_t)); + if (wideCharStr == NULL) { + return NULL; + } + + int result = MultiByteToWideChar(CP_UTF8, 0, str, -1, wideCharStr, wideCharSize); + if (result == 0) { + free(wideCharStr); + return NULL; + } + + return wideCharStr; +} +#endif + static inline void _dispatch_root_queues_init(void); static void _dispatch_lane_barrier_complete(dispatch_lane_class_t dqu, dispatch_qos_t qos, dispatch_wakeup_flags_t flags); @@ -6237,11 +6260,14 @@ _dispatch_worker_thread(void *context) // per‐thread attribute: different threads in the same process can have // different nice values. We can thus setup the thread's initial priority // by converting the QoS class and relative priority to a 'nice' value. - #if defined(__linux__) +#if defined(__linux__) pp = _dispatch_priority_to_pp_strip_flags(pri); int nice = _dispatch_pp_to_nice(pp); #if HAVE_PTHREAD_SETNAME_NP + // pthread thread names are restricted to just 16 characters + // including NUL. It does not make sense to pass the queue's + // label as a name. pthread_setname_np(pthread_self(), "DispatchWorker"); #endif @@ -6249,9 +6275,32 @@ _dispatch_worker_thread(void *context) int rc = setpriority(PRIO_PROCESS, 0, nice); if (rc != -1 || errno == 0) { _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp); + } else { + _dispatch_log("Failed to set thread priority for worker thread: pqc=%p errno=%d\n", pqc, errno); } +#elif defined(_WIN32) + pp = _dispatch_priority_to_pp_strip_flags(pri); + int win_priority = _dispatch_pp_to_win32_priority(pp); + + HANDLE current = GetCurrentThread(); - #endif // defined(__linux__) + // Set thread description to the label of the root queue + if (dq->dq_label) { + wchar_t *desc = _dispatch_char_to_wchar_str(dq->dq_label); + if (likely(desc != NULL)) { + SetThreadDescription(current, desc); + free(desc); + } + } + + int rc = SetThreadPriority(current, win_priority); + if (rc) { + _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp); + } else { + DWORD dwError = GetLastError(); + _dispatch_log("Failed to set thread priority for worker thread: pqc=%p win_priority=%d dwError=%lu\n", pqc, win_priority, dwError); + } +#endif const int64_t timeout = 5ull * NSEC_PER_SEC; @@ -6292,6 +6341,14 @@ _dispatch_worker_thread(void *context) (void)os_atomic_inc2o(dq, dgq_thread_pool_size, release); _dispatch_root_queue_poke(dq, 1, 0); _dispatch_release(dq); // retained in _dispatch_root_queue_poke_slow + +#if defined(_WIN32) + // Make sure to properly end the background processing mode + if (win_priority == THREAD_MODE_BACKGROUND_BEGIN) { + SetThreadPriority(current, THREAD_MODE_BACKGROUND_END); + } +#endif + return NULL; } #if defined(_WIN32) diff --git a/src/shims/priority.h b/src/shims/priority.h index e4e51283c..e20ebb091 100644 --- a/src/shims/priority.h +++ b/src/shims/priority.h @@ -249,6 +249,29 @@ static inline int _dispatch_pp_to_nice(pthread_priority_t pp) } #endif // defined(__linux__) +#if defined(_WIN32) +DISPATCH_ALWAYS_INLINE +static inline int _dispatch_pp_to_win32_priority(pthread_priority_t pp) { + uint32_t qos = _dispatch_qos_from_pp(pp); + + switch (qos) { + case DISPATCH_QOS_BACKGROUND: + // Make sure to end background mode before exiting the thread! + return THREAD_MODE_BACKGROUND_BEGIN; + case DISPATCH_QOS_UTILITY: + return THREAD_PRIORITY_BELOW_NORMAL; + case DISPATCH_QOS_DEFAULT: + return THREAD_PRIORITY_NORMAL; + case DISPATCH_QOS_USER_INITIATED: + return THREAD_PRIORITY_ABOVE_NORMAL; + case DISPATCH_QOS_USER_INTERACTIVE: + return THREAD_PRIORITY_HIGHEST; + } + + return THREAD_PRIORITY_NORMAL; +} +#endif // defined(_WIN32) + // including maintenance DISPATCH_ALWAYS_INLINE From 2d98ac7a7c0c22106c6729ca15d7c7d9654b15ab Mon Sep 17 00:00:00 2001 From: hmelder Date: Mon, 18 Nov 2024 10:19:21 +0100 Subject: [PATCH 073/102] Cap thread priority to normal for qos >= DISPATCH_QOS_DEFAULT The high-priority class should be reserved for threads that must respond to time-critical events, user input threads should be THREAD_PRIORITY_NORMAL. --- src/shims/priority.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/priority.h b/src/shims/priority.h index e20ebb091..92646c3db 100644 --- a/src/shims/priority.h +++ b/src/shims/priority.h @@ -262,10 +262,12 @@ static inline int _dispatch_pp_to_win32_priority(pthread_priority_t pp) { return THREAD_PRIORITY_BELOW_NORMAL; case DISPATCH_QOS_DEFAULT: return THREAD_PRIORITY_NORMAL; + // User input threads should be THREAD_PRIORITY_NORMAL, to + // avoid unintentionally starving the system case DISPATCH_QOS_USER_INITIATED: - return THREAD_PRIORITY_ABOVE_NORMAL; + return THREAD_PRIORITY_NORMAL; case DISPATCH_QOS_USER_INTERACTIVE: - return THREAD_PRIORITY_HIGHEST; + return THREAD_PRIORITY_NORMAL; } return THREAD_PRIORITY_NORMAL; From 9d76b1764121f79c54b777ea20d8203e5a115424 Mon Sep 17 00:00:00 2001 From: hmelder Date: Mon, 18 Nov 2024 10:33:40 +0100 Subject: [PATCH 074/102] Implement _dispatch_win32_set_thread_description This function is a wrapper around SetThreadDescription, which accepts UTF-8 strings. --- src/queue.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/queue.c b/src/queue.c index 256ce2dbe..8fea3c6c5 100644 --- a/src/queue.c +++ b/src/queue.c @@ -29,25 +29,28 @@ #endif #if defined(_WIN32) -// Needs to be free'd after use -static inline wchar_t *_Nullable _dispatch_char_to_wchar_str(const char *str) { - int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - if (wideCharSize == 0) { - return NULL; +// Wrapper around SetThreadDescription for UTF-8 strings +void _dispatch_win32_set_thread_description(HANDLE hThread, const char *description) { + int wcsize = MultiByteToWideChar(CP_UTF8, 0, description, -1, NULL, 0); + if (wcsize == 0) { + return; } - wchar_t* wideCharStr = (wchar_t*)malloc(wideCharSize * sizeof(wchar_t)); - if (wideCharStr == NULL) { - return NULL; + wchar_t* wcstr = (wchar_t*)malloc(wcsize * sizeof(wchar_t)); + if (wcstr == NULL) { + return; } - int result = MultiByteToWideChar(CP_UTF8, 0, str, -1, wideCharStr, wideCharSize); + int result = MultiByteToWideChar(CP_UTF8, 0, description, -1, wcstr, wcsize); if (result == 0) { - free(wideCharStr); - return NULL; + free(wcstr); + return; } - return wideCharStr; + if (likely(wcstr != NULL)) { + SetThreadDescription(hThread, wcstr); + free(wcstr); + } } #endif @@ -6286,11 +6289,7 @@ _dispatch_worker_thread(void *context) // Set thread description to the label of the root queue if (dq->dq_label) { - wchar_t *desc = _dispatch_char_to_wchar_str(dq->dq_label); - if (likely(desc != NULL)) { - SetThreadDescription(current, desc); - free(desc); - } + _dispatch_win32_set_thread_description(current, dq->dq_label); } int rc = SetThreadPriority(current, win_priority); From adcc48b80944578c2e82fcd7d5d8d3a76817bca2 Mon Sep 17 00:00:00 2001 From: Hugo Melder Date: Tue, 3 Jun 2025 09:57:37 +0200 Subject: [PATCH 075/102] Simplify error handling of string conversion Unconditionally free heap-allocated buffer, and only set thread description if MultiByteToWideChar returns a non-zero integer. --- src/queue.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/queue.c b/src/queue.c index 8fea3c6c5..cbead2ed0 100644 --- a/src/queue.c +++ b/src/queue.c @@ -42,15 +42,11 @@ void _dispatch_win32_set_thread_description(HANDLE hThread, const char *descript } int result = MultiByteToWideChar(CP_UTF8, 0, description, -1, wcstr, wcsize); - if (result == 0) { - free(wcstr); - return; - } - - if (likely(wcstr != NULL)) { + if (result != 0) { SetThreadDescription(hThread, wcstr); - free(wcstr); } + + free(wcstr); } #endif From cf63fca0be3a551b6584b954f79960c79d5be89d Mon Sep 17 00:00:00 2001 From: Hugo Melder Date: Tue, 3 Jun 2025 10:09:06 +0200 Subject: [PATCH 076/102] Move discussion about thread policy below macro --- src/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queue.c b/src/queue.c index cbead2ed0..e369e5b9f 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6246,6 +6246,7 @@ _dispatch_worker_thread(void *context) dispatch_priority_t pri = dq->dq_priority; pthread_priority_t pp = _dispatch_get_priority(); +#if defined(__linux__) // The Linux kernel does not have a direct analogue to the QoS-based // thread policy engine found in XNU. // @@ -6259,7 +6260,6 @@ _dispatch_worker_thread(void *context) // per‐thread attribute: different threads in the same process can have // different nice values. We can thus setup the thread's initial priority // by converting the QoS class and relative priority to a 'nice' value. -#if defined(__linux__) pp = _dispatch_priority_to_pp_strip_flags(pri); int nice = _dispatch_pp_to_nice(pp); From 322ba68605cedcb9e025f5fa463c0cb55b1844f6 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 3 Jun 2025 09:44:45 -0700 Subject: [PATCH 077/102] POSIX: Keep original timeout from sleep call The `dispatch_sema4_timedwait` would reset the `_timeout` to an absolute time after the sleep was interrupted instead of when the sleep was called. Interrupting the process while it was sleeping would result in the new absolute timeout deadline being computed using the `timeout` offset from the time of the interrupt. e.g. if the timeout is 10 seconds, it will be ten seconds from when the process was interrupted because the absolute deadline was recomputed. Interrupting the process repeatedly while sleeping would will make the process go back to sleep instead of waking up when the original absolute deadline was reached. `timeout` is a relative timeout offset. `nsec` and `_timeout` are absolute times since the epoch specifying when the wait should stop. --- src/shims/lock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/lock.c b/src/shims/lock.c index 6d0ab8764..85e44544c 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -231,10 +231,10 @@ _dispatch_sema4_timedwait(_dispatch_sema4_t *sema, dispatch_time_t timeout) struct timespec _timeout; int ret; + uint64_t nsec = _dispatch_time_nanoseconds_since_epoch(timeout); + _timeout.tv_sec = (__typeof__(_timeout.tv_sec))(nsec / NSEC_PER_SEC); + _timeout.tv_nsec = (__typeof__(_timeout.tv_nsec))(nsec % NSEC_PER_SEC); do { - uint64_t nsec = _dispatch_time_nanoseconds_since_epoch(timeout); - _timeout.tv_sec = (__typeof__(_timeout.tv_sec))(nsec / NSEC_PER_SEC); - _timeout.tv_nsec = (__typeof__(_timeout.tv_nsec))(nsec % NSEC_PER_SEC); ret = sem_timedwait(sema, &_timeout); } while (unlikely(ret == -1 && errno == EINTR)); From b62136d72674646d4db92f34edc2b77698ec0fa7 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 15 May 2025 20:59:25 -0700 Subject: [PATCH 078/102] build: hoist the BlocksRuntime `add_subdirectory` Move the subdirectory recursion for the BlocksRuntime to the top level as this is a separate target entity. --- CMakeLists.txt | 3 +++ src/CMakeLists.txt | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac6e56857..a7d0dc275 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -329,6 +329,9 @@ add_subdirectory(dispatch) add_subdirectory(man) add_subdirectory(os) add_subdirectory(private) +if(NOT APPLE) + add_subdirectory(src/BlocksRuntime) +endif() add_subdirectory(src) if(BUILD_TESTING) add_subdirectory(tests) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1f8a0c58..feeaa25e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,4 @@ -if(NOT APPLE) - add_subdirectory(BlocksRuntime) -endif() - add_library(dispatch allocator.c apply.c From 1cc58de40104be1d4f785b2e3e0b75122a11542c Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Fri, 6 Jun 2025 13:23:26 -0700 Subject: [PATCH 079/102] Set the FreeBSD clock types Dispatch passes everything through in nanoseconds, but the default time on FreeBSD is in milliseconds, resulting in delays taking a million times longer than expected. This stands out most with `Task.sleep`, where a 2 second sleep would take hours. By setting the EVFILT_TIMER filter flag to use nanoseconds, we get the expected delay. Also sets up the absolute time flag. The spelling on FreeBSD is `NOTE_ABSTIME` instead of `NOTE_ABSOLUTE`. --- src/event/event_config.h | 6 +++++- src/event/event_kevent.c | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/event/event_config.h b/src/event/event_config.h index 4f4b6e5a3..fac801256 100644 --- a/src/event/event_config.h +++ b/src/event/event_config.h @@ -118,7 +118,11 @@ // FreeBSD's kevent does not support those # ifndef NOTE_ABSOLUTE -# define NOTE_ABSOLUTE 0 +# ifdef NOTE_ABSTIME +# define NOTE_ABSOLUTE NOTE_ABSTIME +# else +# define NOTE_ABSOLUTE 0 +# endif # endif # ifndef NOTE_EXITSTATUS # define NOTE_EXITSTATUS 0 diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index 0d8db09f1..eb80082c8 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -50,6 +50,10 @@ DISPATCH_STATIC_GLOBAL(struct dispatch_muxnote_bucket_s _dispatch_sources[DSL_HA #define DISPATCH_NOTE_CLOCK_WALL NOTE_NSECONDS | NOTE_MACH_CONTINUOUS_TIME #define DISPATCH_NOTE_CLOCK_MONOTONIC NOTE_MACHTIME | NOTE_MACH_CONTINUOUS_TIME #define DISPATCH_NOTE_CLOCK_UPTIME NOTE_MACHTIME +#elif __FreeBSD__ +#define DISPATCH_NOTE_CLOCK_WALL NOTE_NSECONDS +#define DISPATCH_NOTE_CLOCK_MONOTONIC NOTE_NSECONDS +#define DISPATCH_NOTE_CLOCK_UPTIME NOTE_NSECONDS #else #define DISPATCH_NOTE_CLOCK_WALL 0 #define DISPATCH_NOTE_CLOCK_MONOTONIC 0 From 38872e2d44d66d2fb94186988509defc734888a5 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Mon, 9 Jun 2025 19:42:15 +0100 Subject: [PATCH 080/102] Silence signedness change through implicit conversion error The error pops up when using the rebranch Clang (stable/20250402): ``` /home/build-user/swift-corelibs-libdispatch/src/event/event_epoll.c:92:27: error: implicit conversion changes signedness: 'int' to 'uint32_t' (aka 'unsigned int') [-Werror,-Wsign-conversion] 92 | return dmn->dmn_events & ~dmn->dmn_disarmed_events; | ~ ^~~~~~~~~~~~~~~~~~~~~~~~~ ``` --- src/event/event_epoll.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/event/event_epoll.c b/src/event/event_epoll.c index f31d13ee0..b7fe8379b 100644 --- a/src/event/event_epoll.c +++ b/src/event/event_epoll.c @@ -89,7 +89,9 @@ DISPATCH_ALWAYS_INLINE static inline uint32_t _dispatch_muxnote_armed_events(dispatch_muxnote_t dmn) { - return dmn->dmn_events & ~dmn->dmn_disarmed_events; + uint32_t events = dmn->dmn_events; + uint16_t disarmed_events = dmn->dmn_disarmed_events; + return events & ~(uint32_t)disarmed_events; } DISPATCH_ALWAYS_INLINE From 2609ca78c665f23306e5e4c333ec95828fdad01e Mon Sep 17 00:00:00 2001 From: Kris Cieplak Date: Thu, 26 Jun 2025 10:33:19 -0400 Subject: [PATCH 081/102] Revert "Merge pull request #854 from z2oh/pipe_wait-with-sentinel-bufsize" This reverts commit 1bf870dfbb305575978f2003174e9f6d83e0c83d, reversing changes made to 57a1f4e84c52bb5c8502767008a7ede5fc1504f7. --- src/event/event_windows.c | 3 -- src/io.c | 59 +++++++++++---------------------------- tests/dispatch_io_pipe.c | 7 +---- 3 files changed, 17 insertions(+), 52 deletions(-) diff --git a/src/event/event_windows.c b/src/event/event_windows.c index 31613ca00..94674a3bf 100644 --- a/src/event/event_windows.c +++ b/src/event/event_windows.c @@ -277,9 +277,6 @@ _dispatch_pipe_monitor_thread(void *context) char cBuffer[1]; DWORD dwNumberOfBytesTransferred; OVERLAPPED ov = {0}; - // Block on a 0-byte read; this will only resume when data is - // available in the pipe. The pipe must be PIPE_WAIT or this thread - // will spin. BOOL bSuccess = ReadFile(hPipe, cBuffer, /* nNumberOfBytesToRead */ 0, &dwNumberOfBytesTransferred, &ov); DWORD dwBytesAvailable; diff --git a/src/io.c b/src/io.c index 95c9d2d60..7ae1e0efe 100644 --- a/src/io.c +++ b/src/io.c @@ -1462,20 +1462,20 @@ _dispatch_fd_entry_create_with_fd(dispatch_fd_t fd, uintptr_t hash) int result = ioctlsocket((SOCKET)fd, (long)FIONBIO, &value); (void)dispatch_assume_zero(result); } else { - // The _dispatch_pipe_monitor_thread expects pipes to be - // PIPE_WAIT and exploits this assumption by using a blocking - // 0-byte read as a synchronization mechanism. + // Try to make writing nonblocking, although pipes not coming + // from Foundation.Pipe may not have FILE_WRITE_ATTRIBUTES. DWORD dwPipeMode = 0; if (GetNamedPipeHandleState((HANDLE)fd, &dwPipeMode, NULL, - NULL, NULL, NULL, 0) && !(dwPipeMode & PIPE_WAIT)) { - dwPipeMode |= PIPE_WAIT; + NULL, NULL, NULL, 0) && !(dwPipeMode & PIPE_NOWAIT)) { + dwPipeMode |= PIPE_NOWAIT; if (!SetNamedPipeHandleState((HANDLE)fd, &dwPipeMode, NULL, NULL)) { - // If setting the pipe to PIPE_WAIT fails, the - // monitoring thread will spin constantly, saturating - // a core, which is undesirable but non-fatal. - // The semantics will still be correct in this case. - _dispatch_fd_entry_debug("failed to set PIPE_WAIT", + // We may end up blocking on subsequent writes, but we + // don't have a good alternative. + // The WriteQuotaAvailable from NtQueryInformationFile + // erroneously returns 0 when there is a blocking read + // on the other end of the pipe. + _dispatch_fd_entry_debug("failed to set PIPE_NOWAIT", fd_entry); } } @@ -2550,40 +2550,13 @@ _dispatch_operation_perform(dispatch_operation_t op) NTSTATUS status = _dispatch_NtQueryInformationFile(hFile, &iosb, &fpli, sizeof(fpli), FilePipeLocalInformation); if (NT_SUCCESS(status)) { - // WriteQuotaAvailable is the free space in the output buffer - // that has not already been reserved for reading. In other words, - // WriteQuotaAvailable = - // OutboundQuota - WriteQuotaUsed - QueuedReadSize. - // It is not documented that QueuedReadSize is part of this - // calculation, but this behavior has been observed experimentally. - // Unfortunately, this means that it is not possible to distinguish - // between a full output buffer and a reader blocked waiting for a - // full buffer's worth of data. This is a problem because if the - // output buffer is full and no reader is waiting for data, then - // attempting to write to the buffer of a PIPE_WAIT, non- - // overlapped I/O pipe will block the dispatch queue thread. - // - // In order to work around this idiosyncrasy, we bound the size of - // the write to be OutboundQuota - 1. This affords us a sentinel value - // in WriteQuotaAvailable that can be used to detect if a reader is - // making progress or not. - // WriteQuotaAvailable = 0 => a reader is blocked waiting for data. - // WriteQuotaAvailable = 1 => the pipe has been written to, but no - // reader is making progress. - // When we detect that WriteQuotaAvailable == 1, we write 0 bytes to - // avoid blocking the dispatch queue thread. - if (fpli.WriteQuotaAvailable == 0) { - // This condition can only occur when we have a reader blocked - // waiting for data on the pipe. In this case, write a full - // buffer's worth of data (less one byte to preserve this - // sentinel value of WriteQuotaAvailable == 0). - len = MIN(len, fpli.OutboundQuota - 1); - } else { - // Subtract 1 from WriteQuotaAvailable to ensure we do not fill - // the pipe and preserve the sentinel value of - // WriteQuotaAvailable == 1. - len = MIN(len, fpli.WriteQuotaAvailable - 1); + // WriteQuotaAvailable is unreliable in the presence + // of a blocking reader, when it can return zero, so only + // account for it otherwise + if (fpli.WriteQuotaAvailable > 0) { + len = MIN(len, fpli.WriteQuotaAvailable); } + len = MIN(len, fpli.OutboundQuota); } OVERLAPPED ovlOverlapped = {}; diff --git a/tests/dispatch_io_pipe.c b/tests/dispatch_io_pipe.c index eb32b6b87..90c212236 100644 --- a/tests/dispatch_io_pipe.c +++ b/tests/dispatch_io_pipe.c @@ -408,12 +408,7 @@ test_dispatch_write(int kind, int delay) dispatch_group_t g = dispatch_group_create(); dispatch_group_enter(g); - // The libdispatch implementation writes at most bufsize-1 bytes - // before requiring a reader to start making progress. Because - // these tests operate serially, the reader will not make progress - // until the write finishes, and a write of >= bufsize will not - // finish until the reader starts draining the pipe. - const size_t bufsize = test_get_pipe_buffer_size(kind) - 1; + const size_t bufsize = test_get_pipe_buffer_size(kind); char *buf = calloc(bufsize, 1); assert(buf); From c12b88d571df0469a88967375cbe6b2360fbf3a9 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 16 May 2025 10:49:00 -0700 Subject: [PATCH 082/102] build: support static libclosure builds While we are still undecided on the state of libclosure (whether it should be supported as a dynamic-only linked dependency or whether we should support statically linking against the library), tweak the build to support the static builds on Windows. --- src/BlocksRuntime/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/BlocksRuntime/CMakeLists.txt b/src/BlocksRuntime/CMakeLists.txt index fc3d60252..3732b0aec 100644 --- a/src/BlocksRuntime/CMakeLists.txt +++ b/src/BlocksRuntime/CMakeLists.txt @@ -7,8 +7,11 @@ if(WIN32) BlocksRuntime.def) if(NOT BUILD_SHARED_LIBS) - target_compile_definitions(BlocksRuntime PRIVATE + target_compile_definitions(BlocksRuntime PUBLIC BlocksRuntime_STATIC) + target_compile_options(BlocksRuntime PUBLIC + "$<$:SHELL:$<$:-Xclang >-static-libclosure>" + $<$:SHELL:-Xcc -static-libclosure>) endif() endif() From 053f8ad0b81e8d6d3f5613dc2528d5f7517cfee7 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 16 May 2025 10:49:00 -0700 Subject: [PATCH 083/102] build: support static dispatch builds In order to support the MUSL Linux SDK, we need to ensure that we are able to build libdispatch statically. Add support to correctly build the static library on all platforms. --- dispatch/base.h | 2 +- src/CMakeLists.txt | 4 ++++ tests/CMakeLists.txt | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dispatch/base.h b/dispatch/base.h index 8e7728525..00c723b36 100644 --- a/dispatch/base.h +++ b/dispatch/base.h @@ -194,7 +194,7 @@ # endif #else # if defined(_WIN32) -# if defined(dispatch_EXPORT) || defined(__DISPATCH_BUILDING_DISPATCH__) +# if defined(dispatch_EXPORTS) # define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllexport) # else # define DISPATCH_EXPORT DISPATCH_EXTERN __declspec(dllimport) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index feeaa25e8..b436454e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,10 @@ target_include_directories(dispatch PUBLIC target_include_directories(dispatch PRIVATE ${PROJECT_SOURCE_DIR}/private) +if(NOT BUILD_SHARED_LIBS) + target_compile_definitions(dispatch PUBLIC + dispatch_STATIC) +endif() if(WIN32) target_compile_definitions(dispatch PRIVATE _CRT_NONSTDC_NO_WARNINGS diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f06162874..0ec603842 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,6 +23,8 @@ add_library(bsdtests STATIC bsdtests.c dispatch_test.c) +target_link_libraries(bsdtests PUBLIC + dispatch) target_include_directories(bsdtests PRIVATE ${CMAKE_CURRENT_BINARY_DIR} From 0b37204e1ec5f83050b9a5ca1233cb523bef0a5b Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 11 Jul 2025 10:14:40 -0700 Subject: [PATCH 084/102] build: correct linking to static libdispatch on Windows When building against the static libdispatch, we need to inform the dispatch headers that the library will be linked statically via `-Ddispatch_STATIC`. Wire this up onto the dispatch library to allow `swiftDispatch` to properly propagate that flag. --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b436454e9..47ac2cfd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -95,6 +95,8 @@ target_include_directories(dispatch PRIVATE if(NOT BUILD_SHARED_LIBS) target_compile_definitions(dispatch PUBLIC dispatch_STATIC) + target_compile_options(dispatch PUBLIC + "$<$:SHELL:-Xcc -Ddispatch_STATIC>") endif() if(WIN32) target_compile_definitions(dispatch PRIVATE From b529310bf3a0197d55e708735c7ddba2bb2229d2 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 15 Jul 2025 10:41:35 -0700 Subject: [PATCH 085/102] event: ensure acquire release semantics for muxnote disposal While it is sufficient to use the relaxed ordering for the acquire semantics in the `_dispatch_muxnote_retain`, we need to use the acquire release semantics on the release in `_dispatch_muxnote_release` to ensure that any pending retains are not interrupted. This should hopefully alleviate the occasional crashes that have been observed with the muxnote reference counting. Fixes: #887, #844 --- src/event/event_windows.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/event/event_windows.c b/src/event/event_windows.c index 94674a3bf..af67dfd4c 100644 --- a/src/event/event_windows.c +++ b/src/event/event_windows.c @@ -260,8 +260,16 @@ _dispatch_muxnote_retain(dispatch_muxnote_t dmn) static void _dispatch_muxnote_release(dispatch_muxnote_t dmn) { - uintptr_t refcount = os_atomic_dec(&dmn->dmn_refcount, relaxed); + // We perform a minor optimization here - perform the decrement with + // release semantics. In the case that we are going to dispose of the + // value, we perform the acquire fence. This reduces the cost on the + // normal path by avoiding the acquire fence. This should be more + // beneficial on ARM64, as X64 being TSO'ed doesn't gain much. However, + // `mfence` being isolated should hopefully be a bit more efficient than + // the repeated `lock` if there is contention. + uintptr_t refcount = os_atomic_dec(&dmn->dmn_refcount, release); if (refcount == 0) { + os_atomic_thread_fence(acquire); _dispatch_muxnote_dispose(dmn); } else if (refcount == UINTPTR_MAX) { DISPATCH_INTERNAL_CRASH(0, "muxnote refcount underflow"); From e73dc2b755d360c0049fe34d2d33fdfe4b0b8535 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Wed, 23 Jul 2025 09:53:08 -0700 Subject: [PATCH 086/102] build: Install libraries in an `arch` sub-folder This is the proper installation scheme for Swift libraries and prevents having to manually copy them in `build.ps1`. --- CMakeLists.txt | 5 ++- cmake/modules/SwiftSupport.cmake | 65 +++++++++++++++++++++++++++++++- src/swift/CMakeLists.txt | 2 - 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 711f64a4d..bb65348c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,8 @@ add_compile_definitions($<$:HAVE_CONFIG_H>) if(ENABLE_SWIFT) + include(SwiftSupport) + if(NOT SWIFT_SYSTEM_NAME) if(APPLE) set(SWIFT_SYSTEM_NAME macosx) @@ -313,8 +315,9 @@ if(ENABLE_SWIFT) set(SWIFT_SYSTEM_NAME "$") endif() endif() + get_swift_host_arch(swift_arch) - set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}" CACHE PATH "Path where the libraries will be installed") + set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}/${swift_arch}" CACHE PATH "Path where the libraries will be installed") set(INSTALL_DISPATCH_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/dispatch" CACHE PATH "Path where the headers will be installed for libdispatch") set(INSTALL_BLOCK_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/Block" CACHE PATH "Path where the headers will be installed for the blocks runtime") set(INSTALL_OS_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/os" CACHE PATH "Path where the os/ headers will be installed") diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 3da519ec5..e80d5da6e 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,5 +1,56 @@ include_guard() +# Returns the architecture name in a variable +# +# Usage: +# get_swift_host_arch(result_var_name) +# +# Sets ${result_var_name} with the converted architecture name derived from +# CMAKE_SYSTEM_PROCESSOR or CMAKE_HOST_SYSTEM_PROCESSOR. +function(get_swift_host_arch result_var_name) + if(CMAKE_SYSTEM_PROCESSOR) + set(cmake_arch ${CMAKE_SYSTEM_PROCESSOR}) + else() + set(cmake_arch ${CMAKE_HOST_SYSTEM_PROCESSOR}) + endif() + if("${cmake_arch}" STREQUAL "x86_64") + set("${result_var_name}" "x86_64" PARENT_SCOPE) + elseif(cmake_arch MATCHES "aarch64|ARM64|arm64") + if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET OR + "${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL "") + set("${result_var_name}" "aarch64" PARENT_SCOPE) + else() + set("${result_var_name}" "arm64" PARENT_SCOPE) + endif() + elseif("${cmake_arch}" STREQUAL "ppc64") + set("${result_var_name}" "powerpc64" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "ppc64le") + set("${result_var_name}" "powerpc64le" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "s390x") + set("${result_var_name}" "s390x" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "armv6l") + set("${result_var_name}" "armv6" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "armv7-a") + set("${result_var_name}" "armv7" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "armv7l") + set("${result_var_name}" "armv7" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "amd64") + set("${result_var_name}" "amd64" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "AMD64") + set("${result_var_name}" "x86_64" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "IA64") + set("${result_var_name}" "itanium" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "x86") + set("${result_var_name}" "i686" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "i686") + set("${result_var_name}" "i686" PARENT_SCOPE) + elseif("${cmake_arch}" STREQUAL "riscv64") + set("${result_var_name}" "riscv64" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unrecognized architecture: ${cmake_arch}") + endif() +endfunction() + if(NOT dispatch_MODULE_TRIPLE) set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) if(CMAKE_Swift_COMPILER_TARGET) @@ -19,12 +70,22 @@ function(install_swift_module target) if(NOT module) set(module ${target}) endif() + + if(NOT SWIFT_SYSTEM_NAME) + if(APPLE) + set(SWIFT_SYSTEM_NAME macosx) + else() + set(SWIFT_SYSTEM_NAME "$") + endif() + endif() + set(INSTALL_SWIFT_MODULE_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}" CACHE PATH "Path where the swift modules will be installed") + install( FILES $/${module}.swiftdoc - DESTINATION ${INSTALL_TARGET_DIR}/${module}.swiftmodule + DESTINATION ${INSTALL_SWIFT_MODULE_DIR}/${module}.swiftmodule RENAME ${dispatch_MODULE_TRIPLE}.swiftdoc) install( FILES $/${module}.swiftmodule - DESTINATION ${INSTALL_TARGET_DIR}/${module}.swiftmodule + DESTINATION ${INSTALL_SWIFT_MODULE_DIR}/${module}.swiftmodule RENAME ${dispatch_MODULE_TRIPLE}.swiftmodule) endfunction() diff --git a/src/swift/CMakeLists.txt b/src/swift/CMakeLists.txt index d255f2cd7..a0082fb1e 100644 --- a/src/swift/CMakeLists.txt +++ b/src/swift/CMakeLists.txt @@ -1,5 +1,3 @@ -include(SwiftSupport) - if(HAVE_OBJC) add_library(DispatchStubs STATIC DispatchStubs.m) From 5301c966363ff78ac34191dc46b549bea8c81bda Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Mon, 4 Aug 2025 11:51:36 -0700 Subject: [PATCH 087/102] Use the arch value from the compiler --- CMakeLists.txt | 3 +- cmake/modules/SwiftSupport.cmake | 71 +++++++++----------------------- 2 files changed, 21 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb65348c2..bbc4aeb36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,9 +315,8 @@ if(ENABLE_SWIFT) set(SWIFT_SYSTEM_NAME "$") endif() endif() - get_swift_host_arch(swift_arch) - set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}/${swift_arch}" CACHE PATH "Path where the libraries will be installed") + set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}/${dispatch_Swift_ARCH}" CACHE PATH "Path where the libraries will be installed") set(INSTALL_DISPATCH_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/dispatch" CACHE PATH "Path where the headers will be installed for libdispatch") set(INSTALL_BLOCK_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/Block" CACHE PATH "Path where the headers will be installed for the blocks runtime") set(INSTALL_OS_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/os" CACHE PATH "Path where the os/ headers will be installed") diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index e80d5da6e..6c6911f63 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,56 +1,5 @@ include_guard() -# Returns the architecture name in a variable -# -# Usage: -# get_swift_host_arch(result_var_name) -# -# Sets ${result_var_name} with the converted architecture name derived from -# CMAKE_SYSTEM_PROCESSOR or CMAKE_HOST_SYSTEM_PROCESSOR. -function(get_swift_host_arch result_var_name) - if(CMAKE_SYSTEM_PROCESSOR) - set(cmake_arch ${CMAKE_SYSTEM_PROCESSOR}) - else() - set(cmake_arch ${CMAKE_HOST_SYSTEM_PROCESSOR}) - endif() - if("${cmake_arch}" STREQUAL "x86_64") - set("${result_var_name}" "x86_64" PARENT_SCOPE) - elseif(cmake_arch MATCHES "aarch64|ARM64|arm64") - if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET OR - "${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL "") - set("${result_var_name}" "aarch64" PARENT_SCOPE) - else() - set("${result_var_name}" "arm64" PARENT_SCOPE) - endif() - elseif("${cmake_arch}" STREQUAL "ppc64") - set("${result_var_name}" "powerpc64" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "ppc64le") - set("${result_var_name}" "powerpc64le" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "s390x") - set("${result_var_name}" "s390x" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "armv6l") - set("${result_var_name}" "armv6" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "armv7-a") - set("${result_var_name}" "armv7" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "armv7l") - set("${result_var_name}" "armv7" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "amd64") - set("${result_var_name}" "amd64" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "AMD64") - set("${result_var_name}" "x86_64" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "IA64") - set("${result_var_name}" "itanium" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "x86") - set("${result_var_name}" "i686" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "i686") - set("${result_var_name}" "i686" PARENT_SCOPE) - elseif("${cmake_arch}" STREQUAL "riscv64") - set("${result_var_name}" "riscv64" PARENT_SCOPE) - else() - message(FATAL_ERROR "Unrecognized architecture: ${cmake_arch}") - endif() -endfunction() - if(NOT dispatch_MODULE_TRIPLE) set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) if(CMAKE_Swift_COMPILER_TARGET) @@ -65,6 +14,26 @@ if(NOT dispatch_MODULE_TRIPLE) message(CONFIGURE_LOG "Swift module triple: ${module_triple}") endif() +if(NOT dispatch_Swift_ARCH) + if(CMAKE_Swift_COMPILER_VERSION VERSION_EQUAL 0.0.0 OR CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 6.2) + # For newer compilers, we can use the -print-target-info command to get the architecture. + set(module_arch_command "${CMAKE_Swift_COMPILER}" -print-target-info) + if(CMAKE_Swift_COMPILER_TARGET) + list(APPEND module_arch_command -target ${CMAKE_Swift_COMPILER_TARGET}) + endif() + execute_process(COMMAND ${module_arch_command} OUTPUT_VARIABLE target_info_json) + string(JSON module_arch GET "${target_info_json}" "target" "arch") + else() + # For older compilers, extract the value from `dispatch_MODULE_TRIPLE`. + string(REGEX MATCH "^[^-]+" module_arch "${dispatch_MODULE_TRIPLE}") + endif() + + set(dispatch_Swift_ARCH "${module_arch}" CACHE STRING "Arch folder name used to install libraries") + mark_as_advanced(dispatch_Swift_ARCH) + + message(CONFIGURE_LOG "Swift arch: ${dispatch_Swift_ARCH}") +endif() + function(install_swift_module target) get_target_property(module ${target} Swift_MODULE_NAME) if(NOT module) From 3eff559e84288e3601437a79a19c7739a6f94bf6 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Tue, 5 Aug 2025 11:37:24 -0700 Subject: [PATCH 088/102] Get the platform name from the compiler This also refactors the code so we only do a single call to the Swift compiler to gather the target info JSON. --- CMakeLists.txt | 10 +------ cmake/modules/SwiftSupport.cmake | 51 ++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bbc4aeb36..56af381e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,15 +308,7 @@ add_compile_definitions($<$:HAVE_CONFIG_H>) if(ENABLE_SWIFT) include(SwiftSupport) - if(NOT SWIFT_SYSTEM_NAME) - if(APPLE) - set(SWIFT_SYSTEM_NAME macosx) - else() - set(SWIFT_SYSTEM_NAME "$") - endif() - endif() - - set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}/${dispatch_Swift_ARCH}" CACHE PATH "Path where the libraries will be installed") + set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_Swift_PLATFORM}/${dispatch_Swift_ARCH}" CACHE PATH "Path where the libraries will be installed") set(INSTALL_DISPATCH_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/dispatch" CACHE PATH "Path where the headers will be installed for libdispatch") set(INSTALL_BLOCK_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/Block" CACHE PATH "Path where the headers will be installed for the blocks runtime") set(INSTALL_OS_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/os" CACHE PATH "Path where the os/ headers will be installed") diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 6c6911f63..67a891879 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,60 +1,67 @@ include_guard() -if(NOT dispatch_MODULE_TRIPLE) +if(NOT dispatch_Swift_MODULE_TRIPLE OR NOT dispatch_Swift_ARCH OR NOT dispatch_Swift_SYSTEM) + # Get the target information from the Swift compiler. set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) if(CMAKE_Swift_COMPILER_TARGET) list(APPEND module_triple_command -target ${CMAKE_Swift_COMPILER_TARGET}) endif() execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) +endif() +if(NOT dispatch_Swift_MODULE_TRIPLE) string(JSON module_triple GET "${target_info_json}" "target" "moduleTriple") - set(dispatch_MODULE_TRIPLE "${module_triple}" CACHE STRING "Triple used to install swiftmodule files") - mark_as_advanced(dispatch_MODULE_TRIPLE) - + set(dispatch_Swift_MODULE_TRIPLE "${module_triple}" CACHE STRING "Triple used to install swiftmodule files") + mark_as_advanced(dispatch_Swift_MODULE_TRIPLE) message(CONFIGURE_LOG "Swift module triple: ${module_triple}") endif() if(NOT dispatch_Swift_ARCH) if(CMAKE_Swift_COMPILER_VERSION VERSION_EQUAL 0.0.0 OR CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 6.2) # For newer compilers, we can use the -print-target-info command to get the architecture. - set(module_arch_command "${CMAKE_Swift_COMPILER}" -print-target-info) - if(CMAKE_Swift_COMPILER_TARGET) - list(APPEND module_arch_command -target ${CMAKE_Swift_COMPILER_TARGET}) - endif() - execute_process(COMMAND ${module_arch_command} OUTPUT_VARIABLE target_info_json) string(JSON module_arch GET "${target_info_json}" "target" "arch") else() - # For older compilers, extract the value from `dispatch_MODULE_TRIPLE`. - string(REGEX MATCH "^[^-]+" module_arch "${dispatch_MODULE_TRIPLE}") + # For older compilers, extract the value from `dispatch_Swift_MODULE_TRIPLE`. + string(REGEX MATCH "^[^-]+" module_arch "${dispatch_Swift_MODULE_TRIPLE}") endif() set(dispatch_Swift_ARCH "${module_arch}" CACHE STRING "Arch folder name used to install libraries") mark_as_advanced(dispatch_Swift_ARCH) - message(CONFIGURE_LOG "Swift arch: ${dispatch_Swift_ARCH}") endif() +if(NOT dispatch_Swift_PLATFORM) + if(CMAKE_Swift_COMPILER_VERSION VERSION_EQUAL 0.0.0 OR CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 6.2) + # For newer compilers, we can use the -print-target-info command to get the platform. + string(JSON swift_platform GET "${target_info_json}" "target" "platform") + else() + # For older compilers, compile the value from `CMAKE_SYSTEM_NAME`. + if(APPLE) + set(swift_platform macosx) + else() + set(swift_platform "$") + endif() + endif() + + set(dispatch_Swift_PLATFORM "${swift_platform}" CACHE STRING "Platform folder name used to install libraries") + mark_as_advanced(dispatch_Swift_PLATFORM) + message(CONFIGURE_LOG "Swift platform: ${dispatch_Swift_PLATFORM}") +endif() + function(install_swift_module target) get_target_property(module ${target} Swift_MODULE_NAME) if(NOT module) set(module ${target}) endif() - if(NOT SWIFT_SYSTEM_NAME) - if(APPLE) - set(SWIFT_SYSTEM_NAME macosx) - else() - set(SWIFT_SYSTEM_NAME "$") - endif() - endif() - set(INSTALL_SWIFT_MODULE_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}" CACHE PATH "Path where the swift modules will be installed") + set(INSTALL_SWIFT_MODULE_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_Swift_PLATFORM}" CACHE PATH "Path where the swift modules will be installed") install( FILES $/${module}.swiftdoc DESTINATION ${INSTALL_SWIFT_MODULE_DIR}/${module}.swiftmodule - RENAME ${dispatch_MODULE_TRIPLE}.swiftdoc) + RENAME ${dispatch_Swift_MODULE_TRIPLE}.swiftdoc) install( FILES $/${module}.swiftmodule DESTINATION ${INSTALL_SWIFT_MODULE_DIR}/${module}.swiftmodule - RENAME ${dispatch_MODULE_TRIPLE}.swiftmodule) + RENAME ${dispatch_Swift_MODULE_TRIPLE}.swiftmodule) endfunction() From a0def02d741bdcffc3eb07091f4058f979df7221 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Tue, 5 Aug 2025 16:54:11 -0700 Subject: [PATCH 089/102] Use the right variable name --- cmake/modules/SwiftSupport.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 67a891879..4704758f7 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,6 +1,6 @@ include_guard() -if(NOT dispatch_Swift_MODULE_TRIPLE OR NOT dispatch_Swift_ARCH OR NOT dispatch_Swift_SYSTEM) +if(NOT dispatch_Swift_MODULE_TRIPLE OR NOT dispatch_Swift_ARCH OR NOT dispatch_Swift_PLATFORM) # Get the target information from the Swift compiler. set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) if(CMAKE_Swift_COMPILER_TARGET) From f51e4816218e04e4dc37eb9fa56bce7ee00e2c36 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Wed, 6 Aug 2025 09:55:55 -0700 Subject: [PATCH 090/102] Rename `dispatch_Swift_*` to `dispatch_*` --- CMakeLists.txt | 2 +- cmake/modules/SwiftSupport.cmake | 34 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56af381e8..38cc7c547 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,7 +308,7 @@ add_compile_definitions($<$:HAVE_CONFIG_H>) if(ENABLE_SWIFT) include(SwiftSupport) - set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_Swift_PLATFORM}/${dispatch_Swift_ARCH}" CACHE PATH "Path where the libraries will be installed") + set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_PLATFORM}/${dispatch_ARCH}" CACHE PATH "Path where the libraries will be installed") set(INSTALL_DISPATCH_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/dispatch" CACHE PATH "Path where the headers will be installed for libdispatch") set(INSTALL_BLOCK_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/Block" CACHE PATH "Path where the headers will be installed for the blocks runtime") set(INSTALL_OS_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/os" CACHE PATH "Path where the os/ headers will be installed") diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 4704758f7..697d98516 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -1,6 +1,6 @@ include_guard() -if(NOT dispatch_Swift_MODULE_TRIPLE OR NOT dispatch_Swift_ARCH OR NOT dispatch_Swift_PLATFORM) +if(NOT dispatch_MODULE_TRIPLE OR NOT dispatch_ARCH OR NOT dispatch_PLATFORM) # Get the target information from the Swift compiler. set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) if(CMAKE_Swift_COMPILER_TARGET) @@ -9,28 +9,28 @@ if(NOT dispatch_Swift_MODULE_TRIPLE OR NOT dispatch_Swift_ARCH OR NOT dispatch_S execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) endif() -if(NOT dispatch_Swift_MODULE_TRIPLE) +if(NOT dispatch_MODULE_TRIPLE) string(JSON module_triple GET "${target_info_json}" "target" "moduleTriple") - set(dispatch_Swift_MODULE_TRIPLE "${module_triple}" CACHE STRING "Triple used to install swiftmodule files") - mark_as_advanced(dispatch_Swift_MODULE_TRIPLE) + set(dispatch_MODULE_TRIPLE "${module_triple}" CACHE STRING "Triple used to install swiftmodule files") + mark_as_advanced(dispatch_MODULE_TRIPLE) message(CONFIGURE_LOG "Swift module triple: ${module_triple}") endif() -if(NOT dispatch_Swift_ARCH) +if(NOT dispatch_ARCH) if(CMAKE_Swift_COMPILER_VERSION VERSION_EQUAL 0.0.0 OR CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 6.2) # For newer compilers, we can use the -print-target-info command to get the architecture. string(JSON module_arch GET "${target_info_json}" "target" "arch") else() - # For older compilers, extract the value from `dispatch_Swift_MODULE_TRIPLE`. - string(REGEX MATCH "^[^-]+" module_arch "${dispatch_Swift_MODULE_TRIPLE}") + # For older compilers, extract the value from `dispatch_MODULE_TRIPLE`. + string(REGEX MATCH "^[^-]+" module_arch "${dispatch_MODULE_TRIPLE}") endif() - set(dispatch_Swift_ARCH "${module_arch}" CACHE STRING "Arch folder name used to install libraries") - mark_as_advanced(dispatch_Swift_ARCH) - message(CONFIGURE_LOG "Swift arch: ${dispatch_Swift_ARCH}") + set(dispatch_ARCH "${module_arch}" CACHE STRING "Arch folder name used to install libraries") + mark_as_advanced(dispatch_ARCH) + message(CONFIGURE_LOG "Swift arch: ${dispatch_ARCH}") endif() -if(NOT dispatch_Swift_PLATFORM) +if(NOT dispatch_PLATFORM) if(CMAKE_Swift_COMPILER_VERSION VERSION_EQUAL 0.0.0 OR CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 6.2) # For newer compilers, we can use the -print-target-info command to get the platform. string(JSON swift_platform GET "${target_info_json}" "target" "platform") @@ -43,9 +43,9 @@ if(NOT dispatch_Swift_PLATFORM) endif() endif() - set(dispatch_Swift_PLATFORM "${swift_platform}" CACHE STRING "Platform folder name used to install libraries") - mark_as_advanced(dispatch_Swift_PLATFORM) - message(CONFIGURE_LOG "Swift platform: ${dispatch_Swift_PLATFORM}") + set(dispatch_PLATFORM "${swift_platform}" CACHE STRING "Platform folder name used to install libraries") + mark_as_advanced(dispatch_PLATFORM) + message(CONFIGURE_LOG "Swift platform: ${dispatch_PLATFORM}") endif() function(install_swift_module target) @@ -54,14 +54,14 @@ function(install_swift_module target) set(module ${target}) endif() - set(INSTALL_SWIFT_MODULE_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_Swift_PLATFORM}" CACHE PATH "Path where the swift modules will be installed") + set(INSTALL_SWIFT_MODULE_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_PLATFORM}" CACHE PATH "Path where the swift modules will be installed") install( FILES $/${module}.swiftdoc DESTINATION ${INSTALL_SWIFT_MODULE_DIR}/${module}.swiftmodule - RENAME ${dispatch_Swift_MODULE_TRIPLE}.swiftdoc) + RENAME ${dispatch_MODULE_TRIPLE}.swiftdoc) install( FILES $/${module}.swiftmodule DESTINATION ${INSTALL_SWIFT_MODULE_DIR}/${module}.swiftmodule - RENAME ${dispatch_Swift_MODULE_TRIPLE}.swiftmodule) + RENAME ${dispatch_MODULE_TRIPLE}.swiftmodule) endfunction() From 0fcef7dca474b6c20a4caacf6d284da90ccb691b Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Wed, 6 Aug 2025 13:28:56 -0700 Subject: [PATCH 091/102] Add option to install into an arch-subdir --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38cc7c547..c34b0de6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,8 +307,9 @@ add_compile_definitions($<$:HAVE_CONFIG_H>) if(ENABLE_SWIFT) include(SwiftSupport) + option(dispatch_INSTALL_ARCH_SUBDIR "Install libraries under an architecture subdirectory" NO) - set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_PLATFORM}/${dispatch_ARCH}" CACHE PATH "Path where the libraries will be installed") + set(INSTALL_TARGET_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/${dispatch_PLATFORM}$<$:/${dispatch_ARCH}>" CACHE PATH "Path where the libraries will be installed") set(INSTALL_DISPATCH_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/dispatch" CACHE PATH "Path where the headers will be installed for libdispatch") set(INSTALL_BLOCK_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/Block" CACHE PATH "Path where the headers will be installed for the blocks runtime") set(INSTALL_OS_HEADERS_DIR "${CMAKE_INSTALL_LIBDIR}/swift$<$>:_static>/os" CACHE PATH "Path where the os/ headers will be installed") From 7fc19ec5f4bec5f6d5f16a039521f2affad4800e Mon Sep 17 00:00:00 2001 From: Finagolfin Date: Mon, 11 Aug 2025 22:20:06 +0530 Subject: [PATCH 092/102] build: Use new 16 KB page alignment on 64-bit Android --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 711f64a4d..45461eb78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,7 @@ check_symbol_exists(__printflike "bsd/sys/cdefs.h" HAVE_PRINTFLIKE) if(ANDROID) set(ENABLE_DTRACE_DEFAULT OFF) + add_link_options("LINKER:-z,max-page-size=16384") endif() if(BSD) From 4a345d0e59a96cd8e0037afdd319b8fe97b5df91 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Wed, 11 Sep 2024 10:48:29 +0000 Subject: [PATCH 093/102] Use CMAKE_C_COMPILER_FRONTEND_VARIANT to detect msvc --- src/CMakeLists.txt | 2 +- tests/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47ac2cfd3..c10583054 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -111,7 +111,7 @@ if(DISPATCH_ENABLE_ASSERTS) DISPATCH_DEBUG=1) endif() -if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") +if("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC") target_compile_options(dispatch PRIVATE /EHs-c-) target_compile_options(dispatch PRIVATE /W3) else() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0ec603842..ed5d2f444 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -83,7 +83,7 @@ function(add_unit_test name) target_include_directories(${name} SYSTEM BEFORE PRIVATE "${BlocksRuntime_INCLUDE_DIR}") - if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") + if("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC") target_compile_options(${name} PRIVATE -Xclang -fblocks) target_compile_options(${name} PRIVATE /W3 -Wno-deprecated-declarations) else() From 85ce1cb80c50d7ae85fda8ef8261e4326dc29203 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Thu, 14 Aug 2025 17:02:50 -0400 Subject: [PATCH 094/102] OpenBSD can makeProcessSource after all. Unwind some conditionals hiding makeProcessSource and associated DispatchSourceProcess. We can probably makeFileSystemObjectSource too, but presumably since pid_t on OpenBSD is Int32, there is a protocol conflict with DispatchSourceProcess and DispatchSourceFileSystemObject. For now, just reveal DispatchSourceProcess. --- src/swift/Source.swift | 21 ++++++++++++--------- src/swift/Wrapper.swift | 4 ++-- src/swift/shims/DispatchOverlayShims.h | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 92201f8e0..0c3abc7f9 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -116,7 +116,7 @@ extension DispatchSource { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) +#if !os(Linux) && !os(Android) && !os(Windows) public struct ProcessEvent : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } @@ -124,16 +124,19 @@ extension DispatchSource { public static let exit = ProcessEvent(rawValue: 0x80000000) public static let fork = ProcessEvent(rawValue: 0x40000000) public static let exec = ProcessEvent(rawValue: 0x20000000) -#if os(FreeBSD) - public static let track = ProcessEvent(rawValue: 0x00000001) -#else + +#if canImport(Darwin) public static let signal = ProcessEvent(rawValue: 0x08000000) #endif +#if os(FreeBSD) || os(OpenBSD) + public static let track = ProcessEvent(rawValue: 0x00000001) +#endif -#if os(FreeBSD) - public static let all: ProcessEvent = [.exit, .fork, .exec, .track] -#else +#if canImport(Darwin) public static let all: ProcessEvent = [.exit, .fork, .exec, .signal] +#endif +#if os(FreeBSD) || os(OpenBSD) + public static let all: ProcessEvent = [.exit, .fork, .exec, .track] #endif } #endif @@ -183,7 +186,7 @@ extension DispatchSource { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) +#if !os(Linux) && !os(Android) && !os(Windows) public class func makeProcessSource(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { let source = dispatch_source_create(_swift_dispatch_source_type_PROC(), UInt(identifier), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceProcess @@ -299,7 +302,7 @@ extension DispatchSourceMemoryPressure { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) +#if !os(Linux) && !os(Android) && !os(Windows) extension DispatchSourceProcess { public var handle: pid_t { return pid_t(CDispatch.dispatch_source_get_handle((self as! DispatchSource).__wrapped)) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 1118bb6e4..a260697f2 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -182,7 +182,7 @@ extension DispatchSource : DispatchSourceMachSend, } #endif -#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) +#if !os(Linux) && !os(Android) && !os(Windows) extension DispatchSource : DispatchSourceProcess { } #endif @@ -277,7 +277,7 @@ public protocol DispatchSourceMemoryPressure : DispatchSourceProtocol { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) +#if !os(Linux) && !os(Android) && !os(Windows) public protocol DispatchSourceProcess : DispatchSourceProtocol { var handle: pid_t { get } diff --git a/src/swift/shims/DispatchOverlayShims.h b/src/swift/shims/DispatchOverlayShims.h index 5ed8dd228..fbcf0116e 100644 --- a/src/swift/shims/DispatchOverlayShims.h +++ b/src/swift/shims/DispatchOverlayShims.h @@ -88,7 +88,7 @@ SWIFT_DISPATCH_SOURCE_TYPE(PROC) SWIFT_DISPATCH_SOURCE_TYPE(VNODE) #endif -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) SWIFT_DISPATCH_SOURCE_TYPE(PROC) SWIFT_DISPATCH_SOURCE_TYPE(VNODE) #endif From ea88133475e09ed4de3e46bb6a0362ba603923a9 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 26 Aug 2025 15:08:30 -0700 Subject: [PATCH 095/102] FreeBSD: Improve CPU core count handling This improves the CPU core count handling for FreeBSD. This uses sysconf to grab the number of configured processors when logical and physical CPU counts are requested, and then pthread_getaffinity_np and the number of active processors. This takes into account the number of available cores when the process is restricted to a subset of the processors. This also fixes the `dispatch_workqueye` test, which has its own implementation to extract the core count. FreeBSD does not have an `hw.activecpu` syscall, so the syscallbyname was failing and the activecpu count was garbage from the stack. I've updated the test to initialize the value with `0xa1a1a1` to make the garbage clearer. Also update the test for FreeBSD to take advantage of sysconf and pthread_getaffinity_np in the test. Fixes: #897 --- src/shims.h | 6 +++--- src/shims/hw_config.h | 4 ++-- tests/dispatch_workqueue.c | 10 +++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/shims.h b/src/shims.h index e14697a9f..a65052dd0 100644 --- a/src/shims.h +++ b/src/shims.h @@ -58,9 +58,6 @@ #define DISPATCH_WORKQ_MAX_PTHREAD_COUNT 255 #endif -#include "shims/hw_config.h" -#include "shims/priority.h" - #if HAVE_PTHREAD_NP_H #include #endif @@ -69,6 +66,9 @@ #include #endif +#include "shims/hw_config.h" +#include "shims/priority.h" + #if !HAVE_DECL_FD_COPY #define FD_COPY(f, t) (void)(*(t) = *(f)) #endif diff --git a/src/shims/hw_config.h b/src/shims/hw_config.h index 06b8921d9..4e6f7c3c9 100644 --- a/src/shims/hw_config.h +++ b/src/shims/hw_config.h @@ -102,14 +102,14 @@ static inline uint32_t _dispatch_hw_get_config(_dispatch_hw_config_t c) { uint32_t val = 1; -#if defined(__linux__) && HAVE_SYSCONF +#if defined(__FreeBSD__) || (defined(__linux__) && HAVE_SYSCONF) switch (c) { case _dispatch_hw_config_logical_cpus: case _dispatch_hw_config_physical_cpus: return (uint32_t)sysconf(_SC_NPROCESSORS_CONF); case _dispatch_hw_config_active_cpus: { -#ifdef __USE_GNU +#if defined(__FreeBSD__) || __USE_GNU // Prefer pthread_getaffinity_np because it considers // scheduler cpu affinity. This matters if the program // is restricted to a subset of the online cpus (eg via numactl). diff --git a/tests/dispatch_workqueue.c b/tests/dispatch_workqueue.c index c12598b69..3f3328736 100644 --- a/tests/dispatch_workqueue.c +++ b/tests/dispatch_workqueue.c @@ -4,6 +4,10 @@ #if defined(__linux__) // For pthread_getaffinity_np() #include +#elif defined(__FreeBSD__) +// for pthread_getaffinity_np / cpu_set_t +#include +#include #endif struct test_context { @@ -37,11 +41,11 @@ spin(void *context) static uint32_t activecpu(void) { - uint32_t activecpu; -#if defined(__linux__) || defined(__OpenBSD__) + uint32_t activecpu = 0xa1a1a1; +#if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); -#if defined(__linux__) && __USE_GNU +#if defined(__FreeBSD__) || (defined(__linux__) && __USE_GNU) cpu_set_t cpuset; if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), From 249d706f5262840d54afab83ad0e64614841b26e Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Fri, 29 Aug 2025 09:53:14 -0700 Subject: [PATCH 096/102] Opt-in to CMP0181 This is necessary for CMake 4.0+ support. All this does is enable CMake to handled `LINKER:arg1,arg2` syntax for `CMAKE_[EXE|SHARED|MODULE|_LINKER_FLAGS`. It does not mandate that syntax. --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 127bd9b7a..f935db51a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,10 @@ if(POLICY CMP0157 AND CMAKE_Swift_COMPILER_USE_OLD_DRIVER) cmake_policy(SET CMP0157 OLD) endif() +if(POLICY CMP0181) + cmake_policy(SET CMP0181 NEW) +endif() + project(dispatch VERSION 1.3 LANGUAGES C CXX) From f1ca39a4b81a7931bb9f4790ddca188aff50505f Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 2 Sep 2025 16:51:21 -0700 Subject: [PATCH 097/102] bsdtest harness: Test for bad uint32 values Adding testing functions to verify that a uint32 isn't a specific number. --- tests/bsdtests.c | 14 ++++++++++++++ tests/bsdtests.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/tests/bsdtests.c b/tests/bsdtests.c index 6307180fd..3ea91a381 100644 --- a/tests/bsdtests.c +++ b/tests/bsdtests.c @@ -164,6 +164,20 @@ test_uint32_format(uint32_t actual, uint32_t expected, const char *format, ...) _test_uint32(NULL, 0, desc, actual, expected); } +void +_test_uint32_not(const char* file, long line, const char* desc, uint32_t actual, uint32_t unexpected) +{ + _test_print(file, line, desc, + (actual != unexpected), "%u", actual, "!%u", unexpected); +} + +void +test_uint32_not_format(uint32_t actual, uint32_t unexpected, const char *format, ...) +{ + GENERATE_DESC + _test_uint32_not(NULL, 0, desc, actual, unexpected); +} + void _test_int32(const char* file, long line, const char* desc, int32_t actual, int32_t expected) { diff --git a/tests/bsdtests.h b/tests/bsdtests.h index e8e292e6e..6c579efa1 100644 --- a/tests/bsdtests.h +++ b/tests/bsdtests.h @@ -111,6 +111,10 @@ void _test_uint32(const char* file, long line, const char* desc, uint32_t actual #define test_uint32(a,b,c) _test_uint32(__SOURCE_FILE__, __LINE__, a, b, c) void test_uint32_format(uint32_t actual, uint32_t expected, const char *format, ...) __printflike(3,4); +void _test_uint32_not(const char* file, long line, const char* desc, uint32_t actual, uint32_t unexpected); +#define test_uint32_not(a,b,c) _test_uint32(__SOURCE_FILE__, __LINE__, a, b, c) +void test_uint32_not_format(uint32_t actual, uint32_t unexpected, const char *format, ...) __printflike(3,4); + void _test_int32(const char* file, long line, const char* desc, int32_t actual, int32_t expected); #define test_int32(a,b,c) _test_int32(__SOURCE_FILE__, __LINE__, a, b, c) void test_int32_format(int32_t actual, int32_t expected, const char* format, ...) __printflike(3,4); From 165659ead74e1fa67327cf22168a5e2a33a14b54 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 2 Sep 2025 16:53:19 -0700 Subject: [PATCH 098/102] dispatch_workqueue: check for bad syscall Adding a check to verify that `syscltbyname` didn't fail. If it did, it likely indicates that the `hw.activecpu` syscall doesn't exist. If the call fails, return zero, indicating that we don't know how many cpus are available. --- tests/dispatch_workqueue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/dispatch_workqueue.c b/tests/dispatch_workqueue.c index c12598b69..f7f4cb6e5 100644 --- a/tests/dispatch_workqueue.c +++ b/tests/dispatch_workqueue.c @@ -55,7 +55,8 @@ activecpu(void) activecpu = si.dwNumberOfProcessors; #else size_t s = sizeof(activecpu); - sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0); + if (sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0) != 0) + return 0; #endif return activecpu; } @@ -66,6 +67,7 @@ int main(void) { uint32_t ncpu = activecpu(); + test_uint32_not("Failed to get CPU count", ncpu, 0); dispatch_test_start("Dispatch workqueue"); From be329e9b25677a00513961f32f396c239b87bcf5 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Wed, 3 Sep 2025 10:33:28 -0700 Subject: [PATCH 099/102] BSDTest: Fix uint32 'not' behavior Accidentally pointed the test_uint32_not macro at the _test_uint32 implementation instead of the _test_uint32_not, so the condition is wrong. --- tests/bsdtests.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bsdtests.h b/tests/bsdtests.h index 6c579efa1..3437a51ed 100644 --- a/tests/bsdtests.h +++ b/tests/bsdtests.h @@ -112,7 +112,7 @@ void _test_uint32(const char* file, long line, const char* desc, uint32_t actual void test_uint32_format(uint32_t actual, uint32_t expected, const char *format, ...) __printflike(3,4); void _test_uint32_not(const char* file, long line, const char* desc, uint32_t actual, uint32_t unexpected); -#define test_uint32_not(a,b,c) _test_uint32(__SOURCE_FILE__, __LINE__, a, b, c) +#define test_uint32_not(a,b,c) _test_uint32_not(__SOURCE_FILE__, __LINE__, a, b, c) void test_uint32_not_format(uint32_t actual, uint32_t unexpected, const char *format, ...) __printflike(3,4); void _test_int32(const char* file, long line, const char* desc, int32_t actual, int32_t expected); From f735c96b7b390799c4dd56d63685da1dae7db973 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Tue, 16 Sep 2025 18:19:27 +0100 Subject: [PATCH 100/102] Add thread names on linux Truncate the name of threads from the front instead to avoid allocating a new string and the end of the name tends to be more unique when creating multiple threads. --- src/queue.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/queue.c b/src/queue.c index e369e5b9f..37806352f 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6265,10 +6265,18 @@ _dispatch_worker_thread(void *context) #if HAVE_PTHREAD_SETNAME_NP // pthread thread names are restricted to just 16 characters - // including NUL. It does not make sense to pass the queue's - // label as a name. - pthread_setname_np(pthread_self(), "DispatchWorker"); - #endif + // including NUL. Truncate the label name from the beginning as it tends + // to be more unique at the end. + size_t label_length = strlen(dq->dq_label); + char * thread_name = dq->dq_label; + if (label_length > 0) { + const size_t max_thread_name_length = 16 - 1; // minus the NUL byte; + thread_name = thread_name + (label_length - max_thread_name_length); + } else { + thread_name = "DispatchWorker"; + } + pthread_setname_np(pthread_self(), thread_name); + #endif // HAVE_PTHREAD_SETNAME_NP errno = 0; int rc = setpriority(PRIO_PROCESS, 0, nice); From 4077418f878d5774f913c8e8669bc58ad34467b4 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike Date: Wed, 17 Sep 2025 14:11:21 +0100 Subject: [PATCH 101/102] [Debug] make const --- src/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queue.c b/src/queue.c index 37806352f..fe8344c15 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6268,7 +6268,7 @@ _dispatch_worker_thread(void *context) // including NUL. Truncate the label name from the beginning as it tends // to be more unique at the end. size_t label_length = strlen(dq->dq_label); - char * thread_name = dq->dq_label; + const char * thread_name = dq->dq_label; if (label_length > 0) { const size_t max_thread_name_length = 16 - 1; // minus the NUL byte; thread_name = thread_name + (label_length - max_thread_name_length); From a8b689a278a045b8ea6bd1f2ddfd3c52369db89d Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 29 Sep 2025 15:29:10 +0100 Subject: [PATCH 102/102] [Build] Enable frame pointers. Frame pointers should be enabled everywhere. rdar://160759746 --- CMakeLists.txt | 2 ++ cmake/modules/EnableFramePointers.cmake | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 cmake/modules/EnableFramePointers.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 45461eb78..fccbced99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,8 @@ include(DispatchSanitization) include(DispatchCompilerWarnings) include(DTrace) +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. diff --git a/cmake/modules/EnableFramePointers.cmake b/cmake/modules/EnableFramePointers.cmake new file mode 100644 index 000000000..8573d8dc4 --- /dev/null +++ b/cmake/modules/EnableFramePointers.cmake @@ -0,0 +1,13 @@ +# +# Including this file enables frame pointers, if we know how. +# + +include(CheckCompilerFlag) + +# Check if the compiler supports -fno-omit-frame-pointer +check_compiler_flag(C -fno-omit-frame-pointer SUPPORTS_NO_OMIT_FP) + +# If it does, use it +if (SUPPORTS_NO_OMIT_FP) + add_compile_options($<$:-fno-omit-frame-pointer>) +endif()