Update to 10.5 SDK. Add DDPerformDebugger.m default tip
authorDave Dribin <dave@dribin.org>
Fri Mar 19 21:42:47 2010 -0500 (2010-03-19)
changeset 168bee1125db0c9
parent 167 de4178bcaacf
Update to 10.5 SDK. Add DDPerformDebugger.m
DDFoundation.xcodeproj/project.pbxproj
lib/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