Files
swift-mirror/stdlib/public/EmbeddedPlatform/EmbeddedPlatformMultiThreadedDarwin.c
Gonzalo Larralde a4805644b6 [Embedded] Move stdout locking into threading PALs
Use stdio.h in the POSIX and Darwin multi-threaded PALs instead of spelling platform-specific stdout symbols in Swift. Provide no-op hooks in the single-threaded PAL and default PAL-enabled test links to that backend unless a threading shim is explicitly selected.
2026-09-22 02:01:48 -04:00

165 lines
5.6 KiB
C

/*===------ EmbeddedPlatformMultiThreadedDarwin.c ----------------*- C -*-===*
*
* This source file is part of the Swift.org open source project
*
* Copyright (c) 2026 Apple Inc. and the Swift project authors
* Licensed under Apache License v2.0 with Runtime Library Exception
*
* See https://swift.org/LICENSE.txt for license information
* See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
*
*===----------------------------------------------------------------------===*
*
* A Darwin-only implementation of the Embedded Swift platform mutex hooks:
*
* - The non-recursive `_swift_mutex_*` family (with or without the CHECKED
* flag) uses `os_unfair_lock` (see <os/lock.h>), stored fully inline in
* the caller-owned mutex storage.
*
* - The `_swift_mutexRecursive_*` family uses a `pthread_mutex_t`
* initialized with `PTHREAD_MUTEX_RECURSIVE`, since `os_unfair_lock` has
* no reentrant mode and building one on top of it would duplicate what
* pthreads already provides.
*
*===----------------------------------------------------------------------===*/
#include "swift/EmbeddedPlatform.h"
#include "swift/Runtime/ConcurrencyDebug.h"
#include <os/lock.h>
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
void _swift_lockStandardOutput(void) {
flockfile(stdout);
}
void _swift_unlockStandardOutput(void) {
funlockfile(stdout);
}
#if __has_include(<pthread/tsd_private.h>)
#include <pthread/tsd_private.h>
#else
#define __PTK_FRAMEWORK_SWIFT_KEY0 100
#endif
#define SWIFT_EMBEDDED_PLATFORM_DARWIN_TLS_KEY_BASE __PTK_FRAMEWORK_SWIFT_KEY0
// Darwin stores the current task in a reserved pthread TLS slot.
__attribute__((used, retain))
uint32_t _swift_concurrency_debug_current_task_storage_kind =
SWIFT_CONCURRENCY_CURRENT_TASK_STORAGE_KIND_PTHREAD_RESERVED_KEY;
extern int pthread_key_init_np(int, void (*)(void *));
// Storage layout for the non-recursive `_swift_mutex_*` family, backed by an
// inline `os_unfair_lock`.
typedef struct {
uint32_t flags;
os_unfair_lock unfair;
} swift_darwin_mutex_t;
_Static_assert(sizeof(swift_darwin_mutex_t) <= EMBEDDED_SWIFT_MUTEX_NUM_WORDS * sizeof(void *),
"swift_darwin_mutex_t does not fit in the Embedded Swift "
"Platform mutex storage (EMBEDDED_SWIFT_MUTEX_NUM_WORDS "
"pointer-sized words)");
_Static_assert(_Alignof(swift_darwin_mutex_t) <= _Alignof(void *),
"swift_darwin_mutex_t requires stronger alignment than the "
"Embedded Swift Platform mutex storage provides");
// The `_swift_mutexRecursive_*` family is backed directly by a
// `pthread_mutex_t`, constructed in place in the caller-owned storage.
_Static_assert(sizeof(pthread_mutex_t) <= EMBEDDED_SWIFT_MUTEX_RECURSIVE_NUM_WORDS * sizeof(void *),
"pthread_mutex_t does not fit in the Embedded Swift Platform "
"recursive mutex storage "
"(EMBEDDED_SWIFT_MUTEX_RECURSIVE_NUM_WORDS pointer-sized "
"words)");
_Static_assert(_Alignof(pthread_mutex_t) <= _Alignof(void *),
"pthread_mutex_t requires stronger alignment than the "
"Embedded Swift Platform recursive mutex storage provides");
static void trap_if(int failed) {
if (failed) {
#if __has_builtin(__builtin_trap)
__builtin_trap();
#else
*(volatile int *)0x11 = 0;
#endif
}
}
static pthread_key_t swift_embedded_platform_tls_key(__swift_tls_key_t key) {
trap_if(key < 0 || key >= SWIFT_TLS_KEY_COUNT);
return SWIFT_EMBEDDED_PLATFORM_DARWIN_TLS_KEY_BASE + key;
}
void _swift_mutex_init(void *mutex, swift_mutex_flags_t flags) {
swift_darwin_mutex_t *m = (swift_darwin_mutex_t *)mutex;
m->flags = (uint32_t)flags;
m->unfair = (os_unfair_lock)OS_UNFAIR_LOCK_INIT;
}
void _swift_mutex_destroy(void *mutex) {
// `os_unfair_lock` has no destroy step.
}
void _swift_mutex_lock(void *mutex) {
swift_darwin_mutex_t *m = (swift_darwin_mutex_t *)mutex;
os_unfair_lock_lock(&m->unfair);
}
void _swift_mutex_unlock(void *mutex) {
swift_darwin_mutex_t *m = (swift_darwin_mutex_t *)mutex;
if (m->flags & SWIFT_MUTEX_CHECKED) {
// Aborts if the current thread does not own the lock, or the lock is
// not held at all.
os_unfair_lock_assert_owner(&m->unfair);
}
os_unfair_lock_unlock(&m->unfair);
}
__swift_ptrdiff_t _swift_mutex_tryLock(void *mutex) {
swift_darwin_mutex_t *m = (swift_darwin_mutex_t *)mutex;
return os_unfair_lock_trylock(&m->unfair) ? 1 : 0;
}
void _swift_mutexRecursive_init(void *mutex, swift_mutex_flags_t flags) {
pthread_mutexattr_t attr;
trap_if(pthread_mutexattr_init(&attr) != 0);
trap_if(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0);
trap_if(pthread_mutex_init((pthread_mutex_t *)mutex, &attr) != 0);
(void)pthread_mutexattr_destroy(&attr);
}
void _swift_mutexRecursive_destroy(void *mutex) {
trap_if(pthread_mutex_destroy((pthread_mutex_t *)mutex) != 0);
}
void _swift_mutexRecursive_lock(void *mutex) {
trap_if(pthread_mutex_lock((pthread_mutex_t *)mutex) != 0);
}
void _swift_mutexRecursive_unlock(void *mutex) {
trap_if(pthread_mutex_unlock((pthread_mutex_t *)mutex) != 0);
}
void _swift_tls_init(__swift_tls_key_t key, __swift_tls_dtor_t destructor) {
trap_if(
pthread_key_init_np((int)swift_embedded_platform_tls_key(key),
destructor) != 0);
}
void *_swift_tls_get(__swift_tls_key_t key) {
return pthread_getspecific(swift_embedded_platform_tls_key(key));
}
void _swift_tls_set(__swift_tls_key_t key, void *value) {
trap_if(pthread_setspecific(swift_embedded_platform_tls_key(key), value) != 0);
}
__swift_ptrdiff_t _swift_thread_isMain(void) {
return pthread_main_np() != 0;
}