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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,19 @@ function(_get_common_compile_options output_var flags)
list(APPEND compile_options "-idirafter${LIBC_KERNEL_HEADERS}")
endif()
endif()
if(LIBC_TARGET_OS_IS_DARWIN)
execute_process(
COMMAND xcrun --sdk macosx --show-sdk-path
OUTPUT_VARIABLE MACOSX_SDK_PATH
RESULT_VARIABLE MACOSX_SDK_PATH_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(MACOSX_SDK_PATH_RESULT EQUAL 0)
list(APPEND compile_options "-I" "${MACOSX_SDK_PATH}/usr/include")
else()
message(WARNING "Could not find macOS SDK path. `xcrun --sdk macosx --show-sdk-path` failed.")
endif()
endif()
endif()

if(LIBC_COMPILER_HAS_FIXED_POINT)
Expand Down
1 change: 1 addition & 0 deletions libc/config/darwin/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.setjmp.setjmp
libc.src.setjmp.siglongjmp
libc.src.setjmp.sigsetjmp
libc.src.stdlib._Exit
)
endif()

Expand Down
5 changes: 5 additions & 0 deletions libc/include/llvm-libc-macros/darwin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_header(
time_macros
HDR
time-macros.h
)
14 changes: 14 additions & 0 deletions libc/include/llvm-libc-macros/darwin/time-macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//===-- Definition of macros from time.h ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H
#define LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H

#include <_time.h>

#endif // LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H
2 changes: 2 additions & 0 deletions libc/include/llvm-libc-macros/time-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "linux/time-macros.h"
#elif defined(__ELF__)
#include "baremetal/time-macros.h"
#elif defined(__APPLE__)
#include "darwin/time-macros.h"
#else
#define CLOCKS_PER_SEC 1000000
#endif
Expand Down
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-types/clockid_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#ifndef LLVM_LIBC_TYPES_CLOCKID_T_H
#define LLVM_LIBC_TYPES_CLOCKID_T_H

#if defined(__APPLE__)
// Darwin provides its own defintion for clockid_t . Use that to prevent
// redeclaration errors and correctness.
#include <_time.h>
#else
typedef int clockid_t;
#endif // __APPLE__

#endif // LLVM_LIBC_TYPES_CLOCKID_T_H
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-types/struct_timespec.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
#ifndef LLVM_LIBC_TYPES_STRUCT_TIMESPEC_H
#define LLVM_LIBC_TYPES_STRUCT_TIMESPEC_H

#if defined(__APPLE__)
// Darwin provides its own definition for struct timespec. Include it directly
// to ensure type compatibility and avoid redefinition errors.
#include <sys/_types/_timespec.h>
#else
#include "time_t.h"

struct timespec {
time_t tv_sec; /* Seconds. */
/* TODO: BIG_ENDIAN may require padding. */
long tv_nsec; /* Nanoseconds. */
};
#endif // __APPLE__

#endif // LLVM_LIBC_TYPES_STRUCT_TIMESPEC_H
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-types/struct_timeval.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@
#include "suseconds_t.h"
#include "time_t.h"

#if defined(__APPLE__)
// Darwin provides its own definition for struct timeval. Include it directly
// to ensure type compatibility and avoid redefinition errors.
#include <sys/_types/_timeval.h>
#else
struct timeval {
time_t tv_sec; // Seconds
suseconds_t tv_usec; // Micro seconds
};
#endif // __APPLE__

#endif // LLVM_LIBC_TYPES_STRUCT_TIMEVAL_H
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-types/suseconds_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
// types...] and suseconds_t are no greater than the width of type long.

// The kernel expects 64 bit suseconds_t at least on x86_64.
#if defined(__APPLE__)
// Darwin provides its own definition for suseconds_t. Include it directly
// to ensure type compatibility and avoid redefinition errors.
#include <sys/_types/_suseconds_t.h>
#else
typedef long suseconds_t;
#endif // __APPLE__

#endif // LLVM_LIBC_TYPES_SUSECONDS_T_H
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-types/time_t_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#ifndef LLVM_LIBC_TYPES_TIME_T_32_H
#define LLVM_LIBC_TYPES_TIME_T_32_H

#if defined(__APPLE__)
// Darwin provides its own definition for time_t. Include it directly
// to ensure type compatibility and avoid redefinition errors.
#include <sys/_types/_time_t.h>
#else
typedef __INT32_TYPE__ time_t;
#endif // __APPLE__

#endif // LLVM_LIBC_TYPES_TIME_T_32_H
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-types/time_t_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#ifndef LLVM_LIBC_TYPES_TIME_T_64_H
#define LLVM_LIBC_TYPES_TIME_T_64_H

#if defined(__APPLE__)
// Darwin provides its own definition for time_t. Include it directly
// to ensure type compatibility and avoid redefinition errors.
#include <sys/_types/_time_t.h>
#else
typedef __INT64_TYPE__ time_t;
#endif // __APPLE__

#endif // LLVM_LIBC_TYPES_TIME_T_64_H
7 changes: 6 additions & 1 deletion libc/include/sys/syscall.h.def
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
#ifndef LLVM_LIBC_SYS_SYSCALL_H
#define LLVM_LIBC_SYS_SYSCALL_H

//TODO: Handle non-linux syscalls
#if defined(__APPLE__)

#include <sys/syscall.h>

#elif defined(__linux__)

#include <asm/unistd.h>

Expand Down Expand Up @@ -2361,5 +2365,6 @@
#define SYS_writev __NR_writev
#endif

#endif // __linux__

#endif // LLVM_LIBC_SYS_SYSCALL_H
7 changes: 5 additions & 2 deletions libc/src/__support/OSUtil/darwin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ endif()

add_subdirectory(${LIBC_TARGET_ARCHITECTURE})

add_header_library(
add_object_library(
darwin_util
SRCS
exit.cpp
HDRS
io.h
syscall.h
DEPENDS
.${LIBC_TARGET_ARCHITECTURE}.darwin_util
.${LIBC_TARGET_ARCHITECTURE}.darwin_${LIBC_TARGET_ARCHITECTURE}_util
libc.src.__support.common
libc.src.__support.CPP.string_view
libc.include.sys_syscall
)
2 changes: 1 addition & 1 deletion libc/src/__support/OSUtil/darwin/aarch64/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_header_library(
darwin_util
darwin_aarch64_util
HDRS
syscall.h
DEPENDS
Expand Down
24 changes: 24 additions & 0 deletions libc/src/__support/OSUtil/darwin/exit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===------------ MacOS implementation of an exit function ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/OSUtil/darwin/syscall.h" // syscall_impl
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "sys/syscall.h" // For syscall numbers.

namespace LIBC_NAMESPACE_DECL {
namespace internal {

[[noreturn]] void exit(int status) {
for (;;) {
LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, status);
}
}

} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
11 changes: 11 additions & 0 deletions libc/src/__support/threads/darwin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if(NOT TARGET libc.src.__support.OSUtil.osutil)
return()
endif()

add_header_library(
mutex
HDRS
mutex.h
DEPENDS
libc.src.__support.threads.mutex_common
)
132 changes: 132 additions & 0 deletions libc/src/__support/threads/darwin/mutex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//===--- Implementation of a Darwin mutex class ------------------*- C++
//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H

#include "src/__support/libc_assert.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/mutex_common.h"
#include "src/__support/threads/sleep.h" // For sleep_briefly
#include "src/__support/time/linux/abs_timeout.h"

#include <mach/mach_init.h> // For mach_thread_self
#include <mach/mach_port.h> // For mach_port_t and MACH_PORT_NULL
#include <os/lock.h> // For os_unfair_lock
#include <time.h> // For clock_gettime

namespace LIBC_NAMESPACE_DECL {

// This file is an implementation of `LIBC_NAMESPACE::mutex` for Darwin-based
// platforms. It is a wrapper around `os_unfair_lock`, which is a low-level,
// high-performance locking primitive provided by the kernel.
//
// `os_unfair_lock` is a non-recursive, thread-owned lock that blocks waiters
// efficiently in the kernel. As the name implies, it is "unfair," meaning
// it does not guarantee the order in which waiting threads acquire the lock.
// This trade-off allows for higher performance in contended scenarios.
//
// The lock must be unlocked from the same thread that locked it. Attempting
// to unlock from a different thread will result in a runtime error.
//
// This implementation is suitable for simple critical sections where fairness
// and reentrancy are not concerns.

class Mutex final {
os_unfair_lock_s lock_val = OS_UNFAIR_LOCK_INIT;
mach_port_t owner = MACH_PORT_NULL;

// API compatibility fields.
unsigned char timed;
unsigned char recursive;
unsigned char robust;
unsigned char pshared;

public:
LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust,
bool is_pshared)
: owner(MACH_PORT_NULL), timed(is_timed), recursive(is_recursive),
robust(is_robust), pshared(is_pshared) {}

LIBC_INLINE constexpr Mutex()
: owner(MACH_PORT_NULL), timed(0), recursive(0), robust(0), pshared(0) {}

LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool is_recur,
bool is_robust, bool is_pshared) {
mutex->lock_val = OS_UNFAIR_LOCK_INIT;
mutex->owner = MACH_PORT_NULL;
mutex->timed = is_timed;
mutex->recursive = is_recur;
mutex->robust = is_robust;
mutex->pshared = is_pshared;
return MutexError::NONE;
}

LIBC_INLINE static MutexError destroy(Mutex *lock) {
LIBC_ASSERT(lock->owner == MACH_PORT_NULL &&
"Mutex destroyed while locked.");
return MutexError::NONE;
}

LIBC_INLINE MutexError lock() {
os_unfair_lock_lock(&lock_val);
owner = mach_thread_self();
return MutexError::NONE;
}

LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) {
while (true) {
if (try_lock() == MutexError::NONE) {
return MutexError::NONE;
}

// Manually check if the timeout has expired.
struct timespec now;
// The clock used here must match the clock used to create the
// absolute timeout.
clock_gettime(abs_time.is_realtime() ? CLOCK_REALTIME : CLOCK_MONOTONIC,
&now);
const timespec &target_ts = abs_time.get_timespec();

if (now.tv_sec > target_ts.tv_sec || (now.tv_sec == target_ts.tv_sec &&
now.tv_nsec >= target_ts.tv_nsec)) {
// We might have acquired the lock between the last try_lock() and now.
// To avoid returning TIMEOUT incorrectly, we do one last try_lock().
if (try_lock() == MutexError::NONE)
return MutexError::NONE;
return MutexError::TIMEOUT;
}

sleep_briefly();
}
}

LIBC_INLINE MutexError unlock() {
// This check is crucial. It prevents both double-unlocks and unlocks
// by threads that do not own the mutex.
if (owner != mach_thread_self()) {
return MutexError::UNLOCK_WITHOUT_LOCK;
}
owner = MACH_PORT_NULL;
os_unfair_lock_unlock(&lock_val);
return MutexError::NONE;
}

LIBC_INLINE MutexError try_lock() {
if (os_unfair_lock_trylock(&lock_val)) {
owner = mach_thread_self();
return MutexError::NONE;
}
return MutexError::BUSY;
}
};

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H
4 changes: 3 additions & 1 deletion libc/src/__support/threads/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@

#if defined(__linux__)
#include "src/__support/threads/linux/mutex.h"
#endif // __linux__
#elif defined(__APPLE__)
#include "src/__support/threads/darwin/mutex.h"
#endif

#elif LIBC_THREAD_MODE == LIBC_THREAD_MODE_SINGLE

Expand Down
12 changes: 12 additions & 0 deletions libc/src/__support/time/darwin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_object_library(
clock_gettime
SRCS
clock_gettime.cpp
HDRS
../clock_gettime.h
DEPENDS
libc.src.__support.common
libc.src.__support.error_or
libc.hdr.types.struct_timeval
libc.hdr.types.struct_timespec
)
Loading
Loading