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
10 changes: 2 additions & 8 deletions CrashReporter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Comment on lines 3904 to 3908
);
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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;
Comment on lines 5724 to 5726
OTHER_CFLAGS = (
"$(inherited)",
Expand Down Expand Up @@ -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 = (
Comment on lines 5776 to 5778
"$(inherited)",
"-D$(PL_BUILD_CONFIG_FLAG)=1",
Expand Down Expand Up @@ -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)",
Expand All @@ -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)",
Expand Down
9 changes: 8 additions & 1 deletion Source/PLCrashAsyncImageList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <atomic>

using namespace plcrash::async;

Expand Down Expand Up @@ -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<plcrash_async_image_t *>::node *expected_node = NULL;
__atomic_compare_exchange_n(&image->_node,
&expected_node,
node,
false,
__ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);

return node->value();
}
Expand Down
1 change: 0 additions & 1 deletion Source/PLCrashAsyncImageList.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#define PLCRASH_ASYNC_IMAGE_LIST_H

#include <stdint.h>
#include <libkern/OSAtomic.h>
#include <stdbool.h>

#include "PLCrashAsyncMachOImage.h"
Expand Down
59 changes: 35 additions & 24 deletions Source/PLCrashAsyncLinkedList.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@

#include "PLCrashAsync.h"
#include "PLCrashMacros.h"
#include <libkern/OSAtomic.h>
#include <atomic>
#include <os/lock.h>
Comment thread
Copilot marked this conversation as resolved.

PLCR_CPP_BEGIN_NS
namespace async {
Expand Down Expand Up @@ -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);
}
Comment thread
Copilot marked this conversation as resolved.

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;
Expand All @@ -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<int32_t> _refcount;

/** The node free list. */
node *_free;
Expand All @@ -174,7 +185,7 @@ template <typename V> async_list<V>::async_list (void) {
_tail = NULL;
_free = NULL;
_refcount = 0;
_write_lock = OS_SPINLOCK_INIT;
_write_lock = OS_UNFAIR_LOCK_INIT;
}

template <typename V> async_list<V>::~async_list (void) {
Expand All @@ -195,7 +206,7 @@ template <typename V> async_list<V>::~async_list (void) {
*/
template <typename V> void async_list<V>::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) {
Expand All @@ -210,7 +221,7 @@ template <typename V> void async_list<V>::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) {
Expand All @@ -219,7 +230,7 @@ template <typename V> void async_list<V>::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.");
}
Expand All @@ -235,14 +246,14 @@ template <typename V> void async_list<V>::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);
}


Expand All @@ -256,7 +267,7 @@ template <typename V> void async_list<V>::nasync_prepend (V value) {
template <typename V> void async_list<V>::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) {
Expand All @@ -271,7 +282,7 @@ template <typename V> void async_list<V>::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) {
Expand All @@ -280,7 +291,7 @@ template <typename V> void async_list<V>::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.");
}
Expand All @@ -289,7 +300,7 @@ template <typename V> void async_list<V>::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");
}

Expand All @@ -298,7 +309,7 @@ template <typename V> void async_list<V>::nasync_append (V value) {
new_node->_prev = _tail;
_tail = new_node;
}
} OSSpinLockUnlock(&_write_lock);
} os_unfair_lock_unlock(&_write_lock);
}

/**
Expand Down Expand Up @@ -330,7 +341,7 @@ template <typename V> void async_list<V>::nasync_remove_first_value (V value) {
*/
template <typename V> void async_list<V>::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) {
Expand All @@ -342,7 +353,7 @@ template <typename V> void async_list<V>::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;
}

Expand All @@ -352,12 +363,12 @@ template <typename V> void async_list<V>::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");
}
}
Expand All @@ -375,7 +386,7 @@ template <typename V> void async_list<V>::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;

Expand All @@ -385,7 +396,7 @@ template <typename V> void async_list<V>::nasync_remove_node (node *deleted_node
} else {
delete item;
}
} OSSpinLockUnlock(&_write_lock);
} os_unfair_lock_unlock(&_write_lock);
}

/**
Expand All @@ -398,10 +409,10 @@ template <typename V> void async_list<V>::nasync_remove_node (node *deleted_node
template <typename V> void async_list<V>::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);
}
}

Expand All @@ -413,7 +424,7 @@ template <typename V> void async_list<V>::set_reading (bool enable) {
* @param current The current list node, or NULL to start iteration.
*/
template <typename V> typename async_list<V>::node *async_list<V>::next (node *current) {
PLCF_ASSERT(_refcount > 0);
PLCF_ASSERT(_refcount.load(std::memory_order_seq_cst) > 0);

if (current != NULL)
return current->_next;
Expand Down
30 changes: 10 additions & 20 deletions Source/PLCrashLogWriter.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

#import <mach-o/dyld.h>

#import <libkern/OSAtomic.h>
#import <stdatomic.h>

#import "PLCrashReport.h"
#import "PLCrashLogWriter.h"
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}

/**
Expand Down
Loading