diff options
Diffstat (limited to 'Menes/yieldToSelector.mm')
-rw-r--r-- | Menes/yieldToSelector.mm | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/Menes/yieldToSelector.mm b/Menes/yieldToSelector.mm new file mode 100644 index 0000000..e168313 --- /dev/null +++ b/Menes/yieldToSelector.mm @@ -0,0 +1,103 @@ +/* Cydia - iPhone UIKit Front-End for Debian APT + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* Modified BSD License {{{ */ +/* + * Redistribution and use in source and binary + * forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the + * above copyright notice, this list of conditions + * and the following disclaimer. + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions + * and the following disclaimer in the documentation + * and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse + * or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* }}} */ + +#include "Menes/yieldToSelector.h" + +@implementation NSObject (MenesYieldToSelector) + +- (void) doNothing { +} + +- (void) _yieldToContext:(NSMutableArray *)context { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + + SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue])); + id object([[context objectAtIndex:1] nonretainedObjectValue]); + volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue])); + + /* XXX: deal with exceptions */ + id value([self performSelector:selector withObject:object]); + + NSMethodSignature *signature([self methodSignatureForSelector:selector]); + [context removeAllObjects]; + if ([signature methodReturnLength] != 0 && value != nil) + [context addObject:value]; + + stopped = true; + + [self + performSelectorOnMainThread:@selector(doNothing) + withObject:nil + waitUntilDone:NO + ]; + + [pool release]; +} + +- (id) yieldToSelector:(SEL)selector withObject:(id)object { + volatile bool stopped(false); + + NSMutableArray *context([NSMutableArray arrayWithObjects: + [NSValue valueWithPointer:selector], + [NSValue valueWithNonretainedObject:object], + [NSValue valueWithPointer:const_cast<bool *>(&stopped)], + nil]); + + NSThread *thread([[[NSThread alloc] + initWithTarget:self + selector:@selector(_yieldToContext:) + object:context + ] autorelease]); + + [thread start]; + + NSRunLoop *loop([NSRunLoop currentRunLoop]); + NSDate *future([NSDate distantFuture]); + NSString *mode([loop currentMode] ?: NSDefaultRunLoopMode); + + while (!stopped && [loop runMode:mode beforeDate:future]); + + return [context count] == 0 ? nil : [context objectAtIndex:0]; +} + +- (id) yieldToSelector:(SEL)selector { + return [self yieldToSelector:selector withObject:nil]; +} + +@end |