/* 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([[context objectAtIndex:0] pointerValue])); id object([[context objectAtIndex:1] nonretainedObjectValue]); volatile bool &stopped(*reinterpret_cast([[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(&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