diff --git a/CrashReporter.xcodeproj/project.pbxproj b/CrashReporter.xcodeproj/project.pbxproj index 3f5c4587..e88f9392 100644 --- a/CrashReporter.xcodeproj/project.pbxproj +++ b/CrashReporter.xcodeproj/project.pbxproj @@ -2808,7 +2808,6 @@ 05E7485C1760D62A009B8745 /* PLCrashAsyncDwarfFDE.hpp in Headers */, 05E7488C176135CF009B8745 /* PLCrashAsyncDwarfExpression.hpp in Headers */, 05E748B017616D30009B8745 /* dwarf_stack.hpp in Headers */, - 1F14AC842BACB4330037FCD3 /* CPPCrashHelper.h in Headers */, 05C76DAF176B8C7000E9B10D /* dwarf_opstream.hpp in Headers */, 05C76DD1176FBAF300E9B10D /* PLCrashAsyncDwarfCFAState.hpp in Headers */, 05920D27177B9257001E8975 /* PLCrashFrameDWARFUnwind.h in Headers */, @@ -2943,7 +2942,6 @@ 8064D7CB1C4D22D8005A8B4C /* PLCrashAsyncDwarfFDE.hpp in Headers */, 8064D7CC1C4D22D8005A8B4C /* PLCrashAsyncDwarfExpression.hpp in Headers */, 8064D7CD1C4D22D8005A8B4C /* dwarf_stack.hpp in Headers */, - 1F14AC862BACB4330037FCD3 /* CPPCrashHelper.h in Headers */, 8064D7CE1C4D22D8005A8B4C /* dwarf_opstream.hpp in Headers */, 8064D7CF1C4D22D8005A8B4C /* PLCrashAsyncDwarfCFAState.hpp in Headers */, 8064D7D01C4D22D8005A8B4C /* PLCrashFrameDWARFUnwind.h in Headers */, @@ -3906,7 +3904,6 @@ 05BEC42817BD4F290082CBFB /* PLCrashAsyncMachExceptionInfo.c in Sources */, 05BEC43C17BF1CB10082CBFB /* PLCrashReporterConfig.m in Sources */, 05A5E28A17C04188008A75E5 /* PLCrashAsyncLinkedList.cpp in Sources */, - 1F14AC832BACB4330037FCD3 /* CPPCrashHelper.mm in Sources */, 05B929EE17C9336600B051E3 /* PLCrashUncaughtExceptionHandler.m in Sources */, 0513E23A17D15ED400727919 /* PLCrashReportMachExceptionInfo.m in Sources */, ); @@ -4402,7 +4399,6 @@ 8064D7FD1C4D22D8005A8B4C /* PLCrashMachExceptionServer.m in Sources */, 8064D7FE1C4D22D8005A8B4C /* PLCrashFrameStackUnwind.c in Sources */, 8064D7FF1C4D22D8005A8B4C /* PLCrashAsyncThread.c in Sources */, - 1F14AC852BACB4330037FCD3 /* CPPCrashHelper.mm in Sources */, 8064D8001C4D22D8005A8B4C /* PLCrashAsyncThread_x86.c in Sources */, C2C80E102350D23B0084D513 /* protobuf-c.c in Sources */, 8064D8011C4D22D8005A8B4C /* PLCrashAsyncThread_arm.c in Sources */, @@ -5726,7 +5722,7 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_SHADOW = YES; HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/protobuf-c\""; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 14.0; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", @@ -5778,7 +5774,7 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_SHADOW = YES; HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/protobuf-c\""; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 14.0; OTHER_CFLAGS = ( "$(inherited)", "-D$(PL_BUILD_CONFIG_FLAG)=1", @@ -5882,7 +5878,6 @@ GCC_ENABLE_EXCEPTIONS = NO; GCC_OPTIMIZATION_LEVEL = 0; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = 10.11; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", @@ -5908,7 +5903,6 @@ EXPORTED_SYMBOLS_FILE = Resources/CrashReporter.exp; GCC_ENABLE_EXCEPTIONS = NO; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = 10.11; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", diff --git a/Source/PLCrashAsyncImageList.cpp b/Source/PLCrashAsyncImageList.cpp index 37c779fe..61b110a5 100644 --- a/Source/PLCrashAsyncImageList.cpp +++ b/Source/PLCrashAsyncImageList.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using namespace plcrash::async; @@ -206,7 +207,13 @@ plcrash_async_image_t *plcrash_async_image_list_next (plcrash_async_image_list_t /* Lazily swap in the cyclic node reference. This is pessimestic, but there's really not a better time to do it. */ plcrash_async_image_t *image = node->value(); - OSAtomicCompareAndSwapPtrBarrier(NULL, (void *) node, (void * volatile *) &image->_node); + async_list::node *expected_node = NULL; + __atomic_compare_exchange_n(&image->_node, + &expected_node, + node, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); return node->value(); } diff --git a/Source/PLCrashAsyncImageList.h b/Source/PLCrashAsyncImageList.h index 6be61fdd..d388e4b9 100644 --- a/Source/PLCrashAsyncImageList.h +++ b/Source/PLCrashAsyncImageList.h @@ -30,7 +30,6 @@ #define PLCRASH_ASYNC_IMAGE_LIST_H #include -#include #include #include "PLCrashAsyncMachOImage.h" diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index 83ad078a..d8acaa84 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -31,7 +31,8 @@ #include "PLCrashAsync.h" #include "PLCrashMacros.h" -#include +#include +#include PLCR_CPP_BEGIN_NS namespace async { @@ -149,10 +150,20 @@ class async_list { } private: + static inline bool cas_ptr_barrier (node **target, node *expected, node *desired) { + node *expected_value = expected; + return __atomic_compare_exchange_n(target, + &expected_value, + desired, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); + } + void free_list (node *next); /** The lock used by writers. No lock is required for readers. */ - OSSpinLock _write_lock; + os_unfair_lock _write_lock; /** The head of the list, or NULL if the list is empty. Must only be used to iterate or delete entries. */ node *_head; @@ -162,7 +173,7 @@ class async_list { /** The list reference count. No nodes will be deallocated while the count is greater than 0. If the count * reaches 0, all nodes in the free list will be deallocated. */ - int32_t _refcount; + std::atomic _refcount; /** The node free list. */ node *_free; @@ -174,7 +185,7 @@ template async_list::async_list (void) { _tail = NULL; _free = NULL; _refcount = 0; - _write_lock = OS_SPINLOCK_INIT; + _write_lock = OS_UNFAIR_LOCK_INIT; } template async_list::~async_list (void) { @@ -195,7 +206,7 @@ template async_list::~async_list (void) { */ template void async_list::nasync_prepend (V value) { /* Lock the list from other writers. */ - OSSpinLockLock(&_write_lock); { + os_unfair_lock_lock(&_write_lock); { /* Construct the new entry, or recycle an existing one. */ node *new_node; if (_free != NULL) { @@ -210,7 +221,7 @@ template void async_list::nasync_prepend (V value) { } /* Issue a memory barrier to ensure a consistent view of the value. */ - OSMemoryBarrier(); + std::atomic_thread_fence(std::memory_order_seq_cst); /* If this is the first entry, initialize the list. */ if (_tail == NULL) { @@ -219,7 +230,7 @@ template void async_list::nasync_prepend (V value) { _tail = new_node; /* Atomically update the list head; this will be iterated upon by lockless readers. */ - if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new_node, (void **) (&_head))) { + if (!cas_ptr_barrier(&_head, NULL, new_node)) { /* Should never occur */ PLCF_DEBUG("An async image head was set with tail == NULL despite holding lock."); } @@ -235,14 +246,14 @@ template void async_list::nasync_prepend (V value) { _head->_prev = new_node; /* Issue a memory barrier to ensure a consistent view of the nodes. */ - OSMemoryBarrier(); + std::atomic_thread_fence(std::memory_order_seq_cst); /* Atomically slot the new record into place; this may be iterated on by a lockless reader. */ - if (!OSAtomicCompareAndSwapPtrBarrier(new_node->_next, new_node, (void **) (&_head))) { + if (!cas_ptr_barrier(&_head, new_node->_next, new_node)) { PLCF_DEBUG("Failed to prepend to image list despite holding lock"); } } - } OSSpinLockUnlock(&_write_lock); + } os_unfair_lock_unlock(&_write_lock); } @@ -256,7 +267,7 @@ template void async_list::nasync_prepend (V value) { template void async_list::nasync_append (V value) { /* Lock the list from other writers. */ - OSSpinLockLock(&_write_lock); { + os_unfair_lock_lock(&_write_lock); { /* Construct the new entry, or recycle an existing one. */ node *new_node; if (_free != NULL) { @@ -271,7 +282,7 @@ template void async_list::nasync_append (V value) { } /* Issue a memory barrier to ensure a consistent view of the value. */ - OSMemoryBarrier(); + std::atomic_thread_fence(std::memory_order_seq_cst); /* If this is the first entry, initialize the list. */ if (_tail == NULL) { @@ -280,7 +291,7 @@ template void async_list::nasync_append (V value) { _tail = new_node; /* Atomically update the list head; this will be iterated upon by lockless readers. */ - if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new_node, (void **) (&_head))) { + if (!cas_ptr_barrier(&_head, NULL, new_node)) { /* Should never occur */ PLCF_DEBUG("An async image head was set with tail == NULL despite holding lock."); } @@ -289,7 +300,7 @@ template void async_list::nasync_append (V value) { /* Otherwise, append to the end of the list */ else { /* Atomically slot the new record into place; this may be iterated on by a lockless reader. */ - if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new_node, (void **) (&_tail->_next))) { + if (!cas_ptr_barrier(&_tail->_next, NULL, new_node)) { PLCF_DEBUG("Failed to append to image list despite holding lock"); } @@ -298,7 +309,7 @@ template void async_list::nasync_append (V value) { new_node->_prev = _tail; _tail = new_node; } - } OSSpinLockUnlock(&_write_lock); + } os_unfair_lock_unlock(&_write_lock); } /** @@ -330,7 +341,7 @@ template void async_list::nasync_remove_first_value (V value) { */ template void async_list::nasync_remove_node (node *deleted_node) { /* Lock the list from other writers. */ - OSSpinLockLock(&_write_lock); { + os_unfair_lock_lock(&_write_lock); { /* Find the record. */ node *item = _head; while (item != NULL) { @@ -342,7 +353,7 @@ template void async_list::nasync_remove_node (node *deleted_node /* If not found, nothing to do */ if (item == NULL) { - OSSpinLockUnlock(&_write_lock); + os_unfair_lock_unlock(&_write_lock); return; } @@ -352,12 +363,12 @@ template void async_list::nasync_remove_node (node *deleted_node * This serves as a synchronization point -- after the CAS, the item is no longer reachable via the list. */ if (item == _head) { - if (!OSAtomicCompareAndSwapPtrBarrier(item, item->_next, (void **) &_head)) { + if (!cas_ptr_barrier(&_head, item, item->_next)) { PLCF_DEBUG("Failed to remove image list head despite holding lock"); } } else { /* There MUST be a non-NULL prev pointer, as this is not HEAD. */ - if (!OSAtomicCompareAndSwapPtrBarrier(item, item->_next, (void **) &item->_prev->_next)) { + if (!cas_ptr_barrier(&item->_prev->_next, item, item->_next)) { PLCF_DEBUG("Failed to remove image list item despite holding lock"); } } @@ -375,7 +386,7 @@ template void async_list::nasync_remove_node (node *deleted_node /* If a reader is active, place the node on the free list. The item is unreachable here when readers * aren't active, so if we have a 0 refcount, we can safely delete the item, and be sure that no * reader holds a reference to it. */ - if (_refcount > 0) { + if (_refcount.load(std::memory_order_seq_cst) > 0) { item->_prev = NULL; item->_next = _free; @@ -385,7 +396,7 @@ template void async_list::nasync_remove_node (node *deleted_node } else { delete item; } - } OSSpinLockUnlock(&_write_lock); + } os_unfair_lock_unlock(&_write_lock); } /** @@ -398,10 +409,10 @@ template void async_list::nasync_remove_node (node *deleted_node template void async_list::set_reading (bool enable) { if (enable) { /* Increment and issue a barrier. Once issued, no items will be deallocated while a reference is held. */ - OSAtomicIncrement32Barrier(&_refcount); + _refcount.fetch_add(1, std::memory_order_seq_cst); } else { /* Increment and issue a barrier. Once issued, items may again be deallocated. */ - OSAtomicDecrement32Barrier(&_refcount); + _refcount.fetch_sub(1, std::memory_order_seq_cst); } } @@ -413,7 +424,7 @@ template void async_list::set_reading (bool enable) { * @param current The current list node, or NULL to start iteration. */ template typename async_list::node *async_list::next (node *current) { - PLCF_ASSERT(_refcount > 0); + PLCF_ASSERT(_refcount.load(std::memory_order_seq_cst) > 0); if (current != NULL) return current->_next; diff --git a/Source/PLCrashLogWriter.m b/Source/PLCrashLogWriter.m index 119e277c..0225d93d 100644 --- a/Source/PLCrashLogWriter.m +++ b/Source/PLCrashLogWriter.m @@ -38,7 +38,7 @@ #import -#import +#import #import "PLCrashReport.h" #import "PLCrashLogWriter.h" @@ -439,32 +439,22 @@ plcrash_error_t plcrash_log_writer_init (plcrash_log_writer_t *writer, #elif TARGET_OS_MAC /* Mac OS X */ { - SInt32 major, minor, bugfix; - - /* Fetch the major, minor, and bugfix versions. - * Fetching the OS version should not fail. */ - if (Gestalt(gestaltSystemVersionMajor, &major) != noErr) { - PLCF_DEBUG("Could not retrieve system major version with Gestalt"); - return PLCRASH_EINTERNAL; - } - if (Gestalt(gestaltSystemVersionMinor, &minor) != noErr) { - PLCF_DEBUG("Could not retrieve system minor version with Gestalt"); - return PLCRASH_EINTERNAL; - } - if (Gestalt(gestaltSystemVersionBugFix, &bugfix) != noErr) { - PLCF_DEBUG("Could not retrieve system bugfix version with Gestalt"); - return PLCRASH_EINTERNAL; - } + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + NSOperatingSystemVersion systemVersion = processInfo.operatingSystemVersion; /* Compose the string */ - asprintf(&writer->system_info.version, "%" PRId32 ".%" PRId32 ".%" PRId32, (int32_t)major, (int32_t)minor, (int32_t)bugfix); + asprintf(&writer->system_info.version, + "%ld.%ld.%ld", + (long) systemVersion.majorVersion, + (long) systemVersion.minorVersion, + (long) systemVersion.patchVersion); } #else #error Unsupported Platform #endif /* Ensure that any signal handler has a consistent view of the above initialization. */ - OSMemoryBarrier(); + atomic_thread_fence(memory_order_seq_cst); return PLCRASH_ESUCCESS; } @@ -499,7 +489,7 @@ void plcrash_log_writer_set_exception (plcrash_log_writer_t *writer, NSException } /* Ensure that any signal handler has a consistent view of the above initialization. */ - OSMemoryBarrier(); + atomic_thread_fence(memory_order_seq_cst); } /** diff --git a/Source/PLCrashMachExceptionServer.m b/Source/PLCrashMachExceptionServer.m index ccad4c51..4655879a 100644 --- a/Source/PLCrashMachExceptionServer.m +++ b/Source/PLCrashMachExceptionServer.m @@ -88,7 +88,7 @@ #import "PLCrashAsync.h" #import -#import +#import #import #import @@ -189,7 +189,7 @@ static exception_mask_t exception_to_mask (exception_type_t exception) { * This value must be updated atomically and with a memory barrier, as it will be accessed * without locking. */ - uint32_t server_should_stop; + _Atomic uint32_t server_should_stop; /** Intended to be observed by the waiting initialization thread. Informs * the waiting thread that shutdown has completed . */ @@ -719,7 +719,7 @@ kern_return_t PLCrashMachExceptionForward (task_t task, /* We intentionally do not acquire a lock here. It is possible that we've been woken * spuriously with the process in an unknown state, in which case we must not call * out to non-async-safe functions */ - if (exc_context->server_should_stop) { + if (atomic_load_explicit(&exc_context->server_should_stop, memory_order_seq_cst)) { /* Inform the requesting thread of completion */ pthread_mutex_lock(&exc_context->lock); { exc_context->server_stop_done = true; @@ -805,7 +805,12 @@ - (void) dealloc { } /* Mark the server for termination */ - OSAtomicCompareAndSwap32Barrier(0, 1, (int32_t *) &_serverContext->server_should_stop); + uint32_t expected = 0; + atomic_compare_exchange_strong_explicit(&_serverContext->server_should_stop, + &expected, + 1, + memory_order_seq_cst, + memory_order_seq_cst); /* Wake up the waiting server */ mach_msg_header_t msg; diff --git a/Source/PLCrashReport.m b/Source/PLCrashReport.m index 8312bc83..1d8bf075 100644 --- a/Source/PLCrashReport.m +++ b/Source/PLCrashReport.m @@ -340,7 +340,7 @@ - (PLCrashReportSystemInfo *) extractSystemInfo: (Plcrash__CrashReport__SystemIn * us is the deprecated architecture field. From that we will generate a * PLCrashReportProcessorInfo object so that library users don't have to * get at the architecture information multiple ways. */ - if (processorInfo == nil) { + if (processorInfo == nil) { processorInfo = [self synthesizeProcessorInfoFromArchitecture: systemInfo->architecture error: outError]; if (processorInfo == nil) return nil; diff --git a/Source/PLCrashReporter.m b/Source/PLCrashReporter.m index d98e2580..187b32a0 100644 --- a/Source/PLCrashReporter.m +++ b/Source/PLCrashReporter.m @@ -50,6 +50,7 @@ #import #import #import +#import #define NSDEBUG(msg, args...) {\ NSLog(@"[PLCrashReporter] " msg, ## args); \ @@ -372,8 +373,13 @@ static void uncaught_exception_handler (NSException *exception) { * It is possible that another crash may occur between setting the uncaught * exception field, and triggering the signal handler. */ - static int32_t exception_is_handled = 0; - if (!OSAtomicCompareAndSwap32(0, 1, &exception_is_handled)) { + static _Atomic int32_t exception_is_handled = 0; + int32_t expected = 0; + if (!atomic_compare_exchange_strong_explicit(&exception_is_handled, + &expected, + 1, + memory_order_relaxed, + memory_order_relaxed)) { return; } @@ -435,12 +441,10 @@ + (void) initialize { * clients should initialize a crash reporter instance directly. */ + (PLCrashReporter *) sharedReporter { - /* Once we drop 10.5 support, this may be converted to dispatch_once() */ - static OSSpinLock onceLock = OS_SPINLOCK_INIT; - OSSpinLockLock(&onceLock); { - if (sharedReporter == nil) - sharedReporter = [[PLCrashReporter alloc] initWithBundle: [NSBundle mainBundle] configuration: [PLCrashReporterConfig defaultConfiguration]]; - } OSSpinLockUnlock(&onceLock); + static dispatch_once_t once; + dispatch_once(&once, ^{ + sharedReporter = [[PLCrashReporter alloc] initWithBundle: [NSBundle mainBundle] configuration: [PLCrashReporterConfig defaultConfiguration]]; + }); return sharedReporter; }