mirror of
https://github.com/darlinghq/darling-foundation.git
synced 2025-02-17 09:48:13 +00:00
Hide use of C11 atomics in NSConnection and NSDistantObject
Including `stdatomic.h` conflicts with C++'s `atomic`. "Why is this a problem?", you ask? Well, because this little thing called Objective-C++ exists, and Foundation needs to play nice with C++ for that reason. Note that the current fix is *technically* UB (though Clang is supposed to do the right thing when working with integral types, as we are), so if we ever run into issues with it (doubtful, but still), you might want to look into Clang's `__atomic_*` builtins.
This commit is contained in:
parent
8f62502144
commit
0c9dbcebe4
@ -21,7 +21,6 @@
|
||||
#import <Foundation/NSNotification.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSRunLoop.h>
|
||||
#import <stdatomic.h>
|
||||
|
||||
@class NSArray<ObjectType>, NSMutableArray<ObjectType>, NSMutableDictionary<KeyType, ObjectType>;
|
||||
@class NSData, NSNumber, NSString;
|
||||
@ -59,8 +58,8 @@ FOUNDATION_EXPORT const NSNotificationName NSConnectionDidDieNotification;
|
||||
typedef NSArray<NSNumber *> *NSConnectionReleasedProxyRecord;
|
||||
|
||||
@interface NSConnection : NSObject {
|
||||
atomic_bool _isValid;
|
||||
atomic_uchar _canUseKeyedCoder;
|
||||
bool _isValid;
|
||||
unsigned char _canUseKeyedCoder;
|
||||
|
||||
id _rootObject;
|
||||
id<NSConnectionDelegate> _delegate;
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#import <Foundation/NSProxy.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <stdatomic.h>
|
||||
|
||||
@class NSCoder, NSConnection;
|
||||
|
||||
@ -51,7 +50,7 @@ typedef NS_ENUM(unsigned int, NSDistantObjectType) {
|
||||
// For remote proxies, this is the wire retain count we hold on them.
|
||||
// Note that for local proxies, wire retain count also contributes to the
|
||||
// regular retain count, i.e. we actually retain ourselves that many times.
|
||||
atomic_uint _wireRetainCount;
|
||||
unsigned int _wireRetainCount;
|
||||
// A protocol the proxy is known to conform to. This can be set explicitly,
|
||||
// and enables us to resolve method signatures locally instead of asking the
|
||||
// remote.
|
||||
|
@ -42,6 +42,8 @@
|
||||
#import "NSKeyedPortCoder.h"
|
||||
#import "NSUnkeyedPortCoder.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
@interface NSRunLoop (Wakeup)
|
||||
- (void) _wakeup;
|
||||
@end
|
||||
@ -55,6 +57,8 @@ static atomic_uint lastSequenceNumber = 0;
|
||||
static NSMutableArray<NSConnection *> *allConnections;
|
||||
static NSData *keyedMagic;
|
||||
|
||||
#define _atomic_isValid (*((atomic_bool*)&_isValid))
|
||||
#define _atomic_canUseKeyedCoder (*((atomic_uchar*)&_canUseKeyedCoder))
|
||||
|
||||
@implementation NSConnection
|
||||
|
||||
@ -112,7 +116,7 @@ static NSData *keyedMagic;
|
||||
// 5. Otherwise, create a new connection.
|
||||
_recvPort = [recvPort retain];
|
||||
_sendPort = [sendPort retain];
|
||||
_isValid = YES;
|
||||
_atomic_isValid = YES;
|
||||
|
||||
// 6. If there's a connection that uses our receive port
|
||||
// as both its receive and send port, it's our parent.
|
||||
@ -153,9 +157,9 @@ static NSData *keyedMagic;
|
||||
}
|
||||
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey: @"NSForceUnkeyedPortCoder"]) {
|
||||
_canUseKeyedCoder = NO;
|
||||
_atomic_canUseKeyedCoder = NO;
|
||||
} else {
|
||||
_canUseKeyedCoder = MAYBE;
|
||||
_atomic_canUseKeyedCoder = MAYBE;
|
||||
}
|
||||
|
||||
_classVersions = [NSMutableDictionary new];
|
||||
@ -230,11 +234,11 @@ static NSData *keyedMagic;
|
||||
}
|
||||
|
||||
- (BOOL) isValid {
|
||||
return _isValid;
|
||||
return _atomic_isValid;
|
||||
}
|
||||
|
||||
- (void) invalidate {
|
||||
BOOL wasValid = atomic_exchange(&_isValid, NO);
|
||||
BOOL wasValid = atomic_exchange((atomic_bool*)&_isValid, NO);
|
||||
if (!wasValid) {
|
||||
// Lost the race to invalidate this connection; some other thread is
|
||||
// going to invalidate us. Or maybe we are already invalidated. In any
|
||||
@ -362,7 +366,7 @@ static NSData *keyedMagic;
|
||||
internal: (BOOL) internal
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (!_isValid) {
|
||||
if (!_atomic_isValid) {
|
||||
// Sorry, we no longer accept new invocations.
|
||||
[NSException raise: NSInvalidReceivePortException
|
||||
format: @"attempted to send an invocation using an invalid connection"];
|
||||
@ -811,7 +815,7 @@ static NSData *keyedMagic;
|
||||
// For this, we use a special method, keyedRootObject, that returns
|
||||
// the same root object, but (if executed successfully) lets both
|
||||
// sides know they both support NSKeyedPortCoder.
|
||||
switch ((unsigned int) _canUseKeyedCoder) {
|
||||
switch ((unsigned int) _atomic_canUseKeyedCoder) {
|
||||
case YES:
|
||||
NSDOLog(@"can use NSKeyedPortCoder, using keyedRootObject");
|
||||
return [remoteConnection keyedRootObject];
|
||||
@ -825,7 +829,7 @@ static NSData *keyedMagic;
|
||||
NSDOLog(@"attempting to invoke keyedRootObject");
|
||||
id rootProxy = [remoteConnection keyedRootObject];
|
||||
// If no exception got thrown, the remote supports NSKeyedPortCoder!
|
||||
_canUseKeyedCoder = YES;
|
||||
_atomic_canUseKeyedCoder = YES;
|
||||
return rootProxy;
|
||||
} @catch (NSException *exception) {
|
||||
// Old versions of Cocoa don't support NSKeyedPortCoder and don't
|
||||
@ -834,7 +838,7 @@ static NSData *keyedMagic;
|
||||
if ([[exception name] isEqual: NSInvalidArgumentException]) {
|
||||
NSDOLog(@"got an exception %@;"
|
||||
" assuming remote doesn't support NSKeyedPortCoder", exception);
|
||||
_canUseKeyedCoder = NO;
|
||||
_atomic_canUseKeyedCoder = NO;
|
||||
return [remoteConnection rootObject];
|
||||
} else {
|
||||
NSDOLog(@"got an unexpected exception %@", exception);
|
||||
@ -845,12 +849,12 @@ static NSData *keyedMagic;
|
||||
}
|
||||
|
||||
- (id) keyedRootObject {
|
||||
if (_canUseKeyedCoder == NO) {
|
||||
if (_atomic_canUseKeyedCoder == NO) {
|
||||
// Pretend we got an unrecognized selector.
|
||||
[self doesNotRecognizeSelector: _cmd];
|
||||
}
|
||||
// If the remote is calling this, it supports NSKeyedPortCoder!
|
||||
_canUseKeyedCoder = YES;
|
||||
_atomic_canUseKeyedCoder = YES;
|
||||
return _rootObject;
|
||||
}
|
||||
|
||||
@ -917,7 +921,7 @@ static NSData *keyedMagic;
|
||||
[self addRunLoop: runLoop];
|
||||
|
||||
NSDate *distantFuture = [NSDate distantFuture];
|
||||
while (_isValid) {
|
||||
while (_atomic_isValid) {
|
||||
@autoreleasepool {
|
||||
[runLoop runMode: NSDefaultRunLoopMode
|
||||
beforeDate: distantFuture];
|
||||
@ -935,7 +939,7 @@ static NSData *keyedMagic;
|
||||
}
|
||||
|
||||
- (Class) _portCoderClass {
|
||||
if (_canUseKeyedCoder == YES) {
|
||||
if (_atomic_canUseKeyedCoder == YES) {
|
||||
return [NSKeyedPortCoder class];
|
||||
} else {
|
||||
return [NSUnkeyedPortCoder class];
|
||||
@ -964,13 +968,13 @@ static NSData *keyedMagic;
|
||||
portCoderClass = [NSKeyedPortCoder class];
|
||||
[mutableComponents removeLastObject];
|
||||
|
||||
switch ((unsigned int) _canUseKeyedCoder) {
|
||||
switch ((unsigned int) _atomic_canUseKeyedCoder) {
|
||||
case YES:
|
||||
break;
|
||||
case MAYBE:
|
||||
NSDOLog(@"got a keyed-coded message from the remote,"
|
||||
" assuming it supports NSKeyedPortCoder");
|
||||
_canUseKeyedCoder = YES;
|
||||
_atomic_canUseKeyedCoder = YES;
|
||||
break;
|
||||
case NO:
|
||||
NSDOLog(@"got an unexpected keyed-coded message from the remote");
|
||||
|
@ -32,6 +32,7 @@
|
||||
#import "NSMessageBuilder.h"
|
||||
#include <objc/runtime.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
@interface NSObject (NSDOAdditions)
|
||||
+ (struct objc_method_description *) methodDescriptionForSelector: (SEL) selector;
|
||||
@ -63,6 +64,8 @@ static const char *typeString(int type) {
|
||||
}
|
||||
}
|
||||
|
||||
#define _atomic_wireRetainCount (*((atomic_uint*)&_wireRetainCount))
|
||||
#define _proxy_atomic_writeRetainCount(proxy) (*((atomic_uint*)&proxy->_wireRetainCount))
|
||||
|
||||
@implementation NSDistantObject
|
||||
|
||||
@ -85,12 +88,12 @@ static const char *typeString(int type) {
|
||||
|
||||
switch (_type) {
|
||||
case NSDistantObjectTypeLocalProxy:
|
||||
NSAssert(_wireRetainCount == 0, @"deallocating a proxy that's still in use");
|
||||
NSAssert(_atomic_wireRetainCount == 0, @"deallocating a proxy that's still in use");
|
||||
break;
|
||||
case NSDistantObjectTypeRemoteProxy:
|
||||
if (_wireRetainCount != 0) {
|
||||
if (_atomic_wireRetainCount != 0) {
|
||||
// Tell the remote we're no longer using this proxy.
|
||||
[_connection releaseProxyID: _id count: _wireRetainCount];
|
||||
[_connection releaseProxyID: _id count: _atomic_wireRetainCount];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -134,7 +137,7 @@ static const char *typeString(int type) {
|
||||
);
|
||||
NSDOLog(@"local proxy with id %d, count %u", proxy->_id, count);
|
||||
|
||||
unsigned int previousWireRetainCount = atomic_fetch_sub(&proxy->_wireRetainCount, count);
|
||||
unsigned int previousWireRetainCount = atomic_fetch_sub((atomic_uint*)&proxy->_wireRetainCount, count);
|
||||
BOOL shouldInvalidate = previousWireRetainCount <= count;
|
||||
if (shouldInvalidate) {
|
||||
// The remote no longer needs this proxy. We cannot deallocate it just
|
||||
@ -206,7 +209,7 @@ static const char *typeString(int type) {
|
||||
if (type == NSDistantObjectTypeLocalProxy) {
|
||||
// Passing a local proxy encoded also implicitly
|
||||
// transfers them a strong reference.
|
||||
_wireRetainCount++;
|
||||
_atomic_wireRetainCount++;
|
||||
[self retain];
|
||||
}
|
||||
}
|
||||
@ -243,7 +246,7 @@ static const char *typeString(int type) {
|
||||
id: id
|
||||
type: NSDistantObjectTypeRemoteProxy];
|
||||
// Decoding a remote proxy gives us a strong reference.
|
||||
proxy->_wireRetainCount++;
|
||||
_proxy_atomic_writeRetainCount(proxy)++;
|
||||
[proxy retain];
|
||||
// [connection importObject: proxy];
|
||||
break;
|
||||
@ -277,7 +280,7 @@ static const char *typeString(int type) {
|
||||
id: id
|
||||
type: NSDistantObjectTypeRemoteProxy];
|
||||
// This also gives us a strong reference.
|
||||
proxy->_wireRetainCount++;
|
||||
_proxy_atomic_writeRetainCount(proxy)++;
|
||||
[proxy retain];
|
||||
// Should we [otherConnection importObject: proxy]; ??
|
||||
break;
|
||||
@ -436,7 +439,7 @@ static const char *typeString(int type) {
|
||||
newProxy->_connection = [newConnection retain];
|
||||
newProxy->_localObject = [oldProxy->_localObject retain];
|
||||
[allProxies addObject: newProxy];
|
||||
newProxy->_wireRetainCount = 1;
|
||||
_proxy_atomic_writeRetainCount(newProxy) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user