Update to 10.5 SDK. Add DDPerformDebugger.m
1.1 --- a/DDFoundation.xcodeproj/project.pbxproj Thu Jan 21 23:03:04 2010 -0600
1.2 +++ b/DDFoundation.xcodeproj/project.pbxproj Fri Mar 19 21:42:47 2010 -0500
1.3 @@ -105,6 +105,7 @@
1.4 55EF2AA10E17021900B465BE /* NSArray+DDExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 55EF2A9F0E17021900B465BE /* NSArray+DDExtensions.h */; };
1.5 55EF2AA20E17021900B465BE /* NSArray+DDExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 55EF2AA00E17021900B465BE /* NSArray+DDExtensions.m */; };
1.6 55EF2AA90E17039500B465BE /* DDFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 55EF2AA80E17039500B465BE /* DDFoundation.h */; };
1.7 + 55F1D33311546CE7007928AE /* DDPerformDebugger.m in Sources */ = {isa = PBXBuildFile; fileRef = 55F1D33211546CE7007928AE /* DDPerformDebugger.m */; };
1.8 55F7D4C90DDAA4BC00FD433C /* NSObject+DDExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 55F7D4C70DDAA4BC00FD433C /* NSObject+DDExtensions.h */; };
1.9 55F7D4CA0DDAA4BC00FD433C /* NSObject+DDExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 55F7D4C80DDAA4BC00FD433C /* NSObject+DDExtensions.m */; };
1.10 55F7D4CF0DDAA4F000FD433C /* DDInvocationGrabber.h in Headers */ = {isa = PBXBuildFile; fileRef = 55F7D4CD0DDAA4F000FD433C /* DDInvocationGrabber.h */; };
1.11 @@ -259,6 +260,7 @@
1.12 55EF2A9F0E17021900B465BE /* NSArray+DDExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+DDExtensions.h"; sourceTree = "<group>"; };
1.13 55EF2AA00E17021900B465BE /* NSArray+DDExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+DDExtensions.m"; sourceTree = "<group>"; };
1.14 55EF2AA80E17039500B465BE /* DDFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFoundation.h; sourceTree = "<group>"; };
1.15 + 55F1D33211546CE7007928AE /* DDPerformDebugger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDPerformDebugger.m; sourceTree = "<group>"; };
1.16 55F7D4C70DDAA4BC00FD433C /* NSObject+DDExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+DDExtensions.h"; sourceTree = "<group>"; };
1.17 55F7D4C80DDAA4BC00FD433C /* NSObject+DDExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+DDExtensions.m"; sourceTree = "<group>"; };
1.18 55F7D4CD0DDAA4F000FD433C /* DDInvocationGrabber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDInvocationGrabber.h; sourceTree = "<group>"; };
1.19 @@ -490,6 +492,7 @@
1.20 55EA25D20E852DBE0051E267 /* NSSortDescriptor+DDExtensions.m */,
1.21 5536F14F0F2FBA4C00488A67 /* NSValue+DDExtensions.h */,
1.22 5536F14D0F2FBA0400488A67 /* DDFoundationExtensions.h */,
1.23 + 55F1D33211546CE7007928AE /* DDPerformDebugger.m */,
1.24 );
1.25 name = Utilities;
1.26 sourceTree = "<group>";
1.27 @@ -774,6 +777,7 @@
1.28 55A036110ED8853E0089F431 /* DDEqualBuilder.m in Sources */,
1.29 55D044410EF1A3BF002A18BE /* DDDelegateProxy.m in Sources */,
1.30 5519EBC611095C470067F023 /* NSDictionary+DDExtensions.m in Sources */,
1.31 + 55F1D33311546CE7007928AE /* DDPerformDebugger.m in Sources */,
1.32 );
1.33 runOnlyForDeploymentPostprocessing = 0;
1.34 };
1.35 @@ -840,12 +844,13 @@
1.36 isa = XCBuildConfiguration;
1.37 buildSettings = {
1.38 ARCHS = "$(ONLY_ACTIVE_ARCH_PRE_XCODE_3_1)";
1.39 + GCC_C_LANGUAGE_STANDARD = gnu99;
1.40 GCC_VERSION = 4.0;
1.41 GCC_WARN_ABOUT_RETURN_TYPE = YES;
1.42 GCC_WARN_UNUSED_VARIABLE = YES;
1.43 ONLY_ACTIVE_ARCH_PRE_XCODE_3_1 = "$(NATIVE_ARCH)";
1.44 PREBINDING = NO;
1.45 - SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
1.46 + SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;
1.47 WARNING_CFLAGS = (
1.48 "-Wall",
1.49 "-Wextra",
1.50 @@ -859,11 +864,12 @@
1.51 buildSettings = {
1.52 ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)";
1.53 ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
1.54 + GCC_C_LANGUAGE_STANDARD = gnu99;
1.55 GCC_VERSION = 4.0;
1.56 GCC_WARN_ABOUT_RETURN_TYPE = YES;
1.57 GCC_WARN_UNUSED_VARIABLE = YES;
1.58 PREBINDING = NO;
1.59 - SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
1.60 + SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;
1.61 WARNING_CFLAGS = (
1.62 "-Wall",
1.63 "-Wextra",
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/lib/DDPerformDebugger.m Fri Mar 19 21:42:47 2010 -0500
2.3 @@ -0,0 +1,184 @@
2.4 +/*
2.5 + * Copyright (c) 2007-2010 Dave Dribin
2.6 + *
2.7 + * Permission is hereby granted, free of charge, to any person
2.8 + * obtaining a copy of this software and associated documentation
2.9 + * files (the "Software"), to deal in the Software without
2.10 + * restriction, including without limitation the rights to use, copy,
2.11 + * modify, merge, publish, distribute, sublicense, and/or sell copies
2.12 + * of the Software, and to permit persons to whom the Software is
2.13 + * furnished to do so, subject to the following conditions:
2.14 + *
2.15 + * The above copyright notice and this permission notice shall be
2.16 + * included in all copies or substantial portions of the Software.
2.17 + *
2.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2.21 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2.22 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2.23 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2.24 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2.25 + * SOFTWARE.
2.26 + */
2.27 +
2.28 +#import <Foundation/Foundation.h>
2.29 +#include <objc/objc-runtime.h>
2.30 +#include <execinfo.h>
2.31 +
2.32 +
2.33 +@interface NSObject (DDPerformDebugger)
2.34 +
2.35 +- (void)dd_performSelector:(SEL)selector onThread:(NSThread *)thread withObject:(id)argument waitUntilDone:(BOOL)wait modes:(NSArray *)modes;
2.36 +- (void)dd_performSelector:(SEL)selector withObject:(id)argument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
2.37 +
2.38 +@end
2.39 +
2.40 +@interface DDPerformDebugger : NSObject
2.41 +{
2.42 + id _target;
2.43 + SEL _selector;
2.44 + id _argument;
2.45 + void * _callstack[128];
2.46 + int _frames;
2.47 +}
2.48 +
2.49 +- (id)initWithTarget:(id)target selector:(SEL)selector argument:(id)argument;
2.50 +
2.51 +- (void)perform;
2.52 +- (NSString *)backtrace;
2.53 +- (NSString *)description;
2.54 +
2.55 +@end
2.56 +
2.57 +
2.58 +/******************************************************************************/
2.59 +
2.60 +
2.61 +@implementation NSObject (DDPerformDebugger)
2.62 +
2.63 ++ (void)load
2.64 +{
2.65 + if (self != [NSObject class]) {
2.66 + return;
2.67 + }
2.68 +
2.69 + const char * enabledString = getenv("DDPerformDebug");
2.70 + BOOL enabled = ((enabledString != NULL) &&
2.71 + ((strcmp(enabledString, "1") == 0) || (strcmp(enabledString, "YES") == 0)));
2.72 + if (!enabled) {
2.73 + return;
2.74 + }
2.75 +
2.76 + Method originalMethod;
2.77 + Method replacedMethod;
2.78 +
2.79 + originalMethod = class_getInstanceMethod(
2.80 + self, @selector(performSelector:onThread:withObject:waitUntilDone:modes:));
2.81 + replacedMethod = class_getInstanceMethod(
2.82 + self, @selector(dd_performSelector:onThread:withObject:waitUntilDone:modes:));
2.83 + method_exchangeImplementations(originalMethod, replacedMethod);
2.84 +
2.85 + originalMethod = class_getInstanceMethod(
2.86 + self, @selector(performSelector:withObject:afterDelay:inModes:));
2.87 + replacedMethod = class_getInstanceMethod(
2.88 + self, @selector(dd_performSelector:withObject:afterDelay:inModes:));
2.89 + method_exchangeImplementations(originalMethod, replacedMethod);
2.90 +}
2.91 +
2.92 +- (void)dd_performSelector:(SEL)selector onThread:(NSThread *)thread withObject:(id)argument waitUntilDone:(BOOL)wait modes:(NSArray *)modes;
2.93 +{
2.94 + DDPerformDebugger * debugger = [[DDPerformDebugger alloc] initWithTarget:self
2.95 + selector:selector
2.96 + argument:argument];
2.97 + [debugger autorelease];
2.98 +
2.99 + // This is the original implemetion, not recursion
2.100 + [debugger dd_performSelector:@selector(perform)
2.101 + onThread:thread
2.102 + withObject:nil
2.103 + waitUntilDone:wait
2.104 + modes:modes];
2.105 +}
2.106 +
2.107 +- (void)dd_performSelector:(SEL)selector withObject:(id)argument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
2.108 +{
2.109 + DDPerformDebugger * debugger = [[DDPerformDebugger alloc] initWithTarget:self
2.110 + selector:selector
2.111 + argument:argument];
2.112 + [debugger autorelease];
2.113 +
2.114 + // This is the original implemetion, not recursion
2.115 + [debugger dd_performSelector:@selector(perform)
2.116 + withObject:nil
2.117 + afterDelay:delay
2.118 + inModes:modes];
2.119 +}
2.120 +
2.121 +@end
2.122 +
2.123 +
2.124 +/******************************************************************************/
2.125 +
2.126 +
2.127 +const char * DDPerformDescription;
2.128 +
2.129 +@implementation DDPerformDebugger
2.130 +
2.131 +- (id)initWithTarget:(id)target selector:(SEL)selector argument:(id)argument;
2.132 +{
2.133 + self = [super init];
2.134 + if (self == nil)
2.135 + return nil;
2.136 +
2.137 + _target = [target retain];
2.138 + _selector = selector;
2.139 + _argument = [argument retain];
2.140 + // Capture a backtrace at the time we're created
2.141 + _frames = backtrace(_callstack, sizeof(_callstack)/sizeof(*_callstack));
2.142 +
2.143 + return self;
2.144 +}
2.145 +
2.146 +- (void)dealloc
2.147 +{
2.148 + [_target release];
2.149 + [_argument release];
2.150 + [super dealloc];
2.151 +}
2.152 +
2.153 +- (void)perform;
2.154 +{
2.155 + NSString * nsDescription = [self description];
2.156 + // These can be useful if 'po self' can't be performed without a deadlock:
2.157 + // (gdb) printf "%s", description
2.158 + const char * description = [nsDescription UTF8String];
2.159 + DDPerformDescription = description;
2.160 + [_target performSelector:_selector withObject:_argument];
2.161 + DDPerformDescription = NULL;
2.162 +}
2.163 +
2.164 +- (NSString *)backtrace;
2.165 +{
2.166 + NSMutableString * backtrace = [NSMutableString string];
2.167 + char** strs = backtrace_symbols(_callstack, _frames);
2.168 + for (int i = 0; i < _frames; ++i) {
2.169 + [backtrace appendFormat:@"%s\n", strs[i]];
2.170 + }
2.171 + free(strs);
2.172 + return backtrace;
2.173 +}
2.174 +
2.175 +- (NSString *)description;
2.176 +{
2.177 + NSMutableString * description = [NSMutableString string];
2.178 + [description appendFormat:@"<%@ %p: ",[self class], self];
2.179 + [description appendFormat:@"target: <%@ %p>, ", [_target class], _target];
2.180 + [description appendFormat:@"selector: <%@>, ", NSStringFromSelector(_selector)];
2.181 + [description appendFormat:@"argument: <%@ %p>\n", [_argument class], _argument];
2.182 + [description appendFormat:@"%@", [self backtrace]];
2.183 +
2.184 + return description;
2.185 +}
2.186 +
2.187 +@end