mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Implemented new MacOS-X methods
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@14874 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
54818427e8
commit
6cf363efd5
4 changed files with 223 additions and 21 deletions
|
@ -1,3 +1,9 @@
|
|||
2002-10-30 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSThread.m: Implemented and documented new MacOS-X methods -
|
||||
([-performSelectorOnMainThread:withObject:waitUntilDone:modes:])
|
||||
and ([-performSelectorOnMainThread:withObject:waitUntilDone:])
|
||||
|
||||
Wed Oct 30 03:14:34 2002 Nicola Pero <n.pero@mi.flashnet.it>
|
||||
|
||||
* Headers/gnustep/base/objc-load.h: Added copyright notice.
|
||||
|
|
|
@ -60,6 +60,18 @@
|
|||
|
||||
@end
|
||||
|
||||
#ifndef STRICT_OPENSTEP
|
||||
@interface NSObject(NSMainThreadPerformAdditions)
|
||||
- (void) performSelectorOnMainThread: (SEL)aSelector
|
||||
withObject: (id)anObject
|
||||
waitUntilDone: (BOOL)aFlag
|
||||
modes: (NSArray*)anArray;
|
||||
- (void) performSelectorOnMainThread: (SEL)aSelector
|
||||
withObject: (id)anObject
|
||||
waitUntilDone: (BOOL)aFlag;
|
||||
@end
|
||||
#endif
|
||||
|
||||
#ifndef NO_GNUSTEP
|
||||
/*
|
||||
* Don't use the following functions unless you really know what you are
|
||||
|
|
|
@ -1628,22 +1628,9 @@ if (0) {
|
|||
|
||||
+ (NSRunLoop*) currentRunLoop
|
||||
{
|
||||
static NSString *key = @"NSRunLoopThreadKey";
|
||||
NSMutableDictionary *d;
|
||||
NSRunLoop *r;
|
||||
extern NSRunLoop *GSRunLoopForThread();
|
||||
|
||||
d = GSCurrentThreadDictionary();
|
||||
r = [d objectForKey: key];
|
||||
if (r == nil)
|
||||
{
|
||||
if (d != nil)
|
||||
{
|
||||
r = [self new];
|
||||
[d setObject: r forKey: key];
|
||||
RELEASE(r);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
return GSRunLoopForThread(nil);
|
||||
}
|
||||
|
||||
/* This is the designated initializer. */
|
||||
|
@ -2206,6 +2193,13 @@ if (0) {
|
|||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up repeated sending of aSelector to target with argument.<br />
|
||||
* The selector is sent in each runloop iteration until cancelled.<br />
|
||||
* The target and argument objects are <em>not</em> retained.<br />
|
||||
* The order value is used to determine the order in which messages
|
||||
* are sent if multiple messages have been set up.
|
||||
*/
|
||||
- (void) performSelector: (SEL)aSelector
|
||||
target: (id)target
|
||||
argument: (id)argument
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include <Foundation/NSLock.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSNotificationQueue.h>
|
||||
#include <Foundation/NSRunLoop.h>
|
||||
#include <Foundation/NSConnection.h>
|
||||
|
||||
static Class threadClass = Nil;
|
||||
static NSNotificationCenter *nc = nil;
|
||||
|
@ -133,26 +135,62 @@ GSCurrentThread()
|
|||
* Fast access function for thread dictionary of current thread.
|
||||
*/
|
||||
NSMutableDictionary*
|
||||
GSCurrentThreadDictionary()
|
||||
GSDictionaryForThread(NSThread *t)
|
||||
{
|
||||
NSThread *thread = GSCurrentThread();
|
||||
|
||||
if (thread == nil)
|
||||
if (t == nil)
|
||||
{
|
||||
t = GSCurrentThread();
|
||||
}
|
||||
if (t == nil)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableDictionary *dict = thread->_thread_dictionary;
|
||||
NSMutableDictionary *dict = t->_thread_dictionary;
|
||||
|
||||
if (dict == nil)
|
||||
{
|
||||
dict = [thread threadDictionary];
|
||||
dict = [t threadDictionary];
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast access function for thread dictionary of current thread.
|
||||
*/
|
||||
NSMutableDictionary*
|
||||
GSCurrentThreadDictionary()
|
||||
{
|
||||
return GSDictionaryForThread(nil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the run loop for the specified thread (or, if t is nil,
|
||||
* for the current thread). Creates a new run loop if necessary.<br />
|
||||
* Returns nil on failure.
|
||||
*/
|
||||
NSRunLoop*
|
||||
GSRunLoopForThread(NSThread *t)
|
||||
{
|
||||
static NSString *key = @"NSRunLoopThreadKey";
|
||||
NSMutableDictionary *d = GSDictionaryForThread(t);
|
||||
NSRunLoop *r;
|
||||
|
||||
r = [d objectForKey: key];
|
||||
if (r == nil)
|
||||
{
|
||||
if (d != nil)
|
||||
{
|
||||
r = [NSRunLoop new];
|
||||
[d setObject: r forKey: key];
|
||||
RELEASE(r);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function so send notifications on becoming multi-threaded.
|
||||
*/
|
||||
|
@ -514,6 +552,158 @@ gnustep_base_thread_callback()
|
|||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface GSPerformHolder : NSObject
|
||||
{
|
||||
id receiver;
|
||||
id argument;
|
||||
SEL selector;
|
||||
NSLock *lock;
|
||||
}
|
||||
+ (GSPerformHolder*) newForReceiver: (id)r
|
||||
argument: (id)a
|
||||
selector: (SEL)s
|
||||
lock: (NSConditionLock*)l;
|
||||
- (void) fire;
|
||||
@end
|
||||
|
||||
@implementation GSPerformHolder
|
||||
|
||||
+ (GSPerformHolder*) newForReceiver: (id)r
|
||||
argument: (id)a
|
||||
selector: (SEL)s
|
||||
lock: (NSConditionLock*)l
|
||||
{
|
||||
GSPerformHolder *h;
|
||||
|
||||
h = (GSPerformHolder*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
||||
h->receiver = RETAIN(r);
|
||||
h->argument = RETAIN(a);
|
||||
h->selector = s;
|
||||
if (l != nil)
|
||||
{
|
||||
h->lock = RETAIN(l);
|
||||
[h->lock lock]; // Lock until fire.
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
DESTROY(receiver);
|
||||
DESTROY(argument);
|
||||
if (lock != nil)
|
||||
{
|
||||
[lock unlock];
|
||||
DESTROY(lock);
|
||||
}
|
||||
NSDeallocateObject(self);
|
||||
}
|
||||
|
||||
- (void) fire
|
||||
{
|
||||
[GSRunLoopForThread(defaultThread) cancelPerformSelectorsWithTarget: self];
|
||||
[receiver performSelector: selector withObject: argument];
|
||||
if (lock == nil)
|
||||
{
|
||||
RELEASE(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
[lock unlock];
|
||||
DESTROY(lock);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSObject(NSMainThreadPerformAdditions)
|
||||
|
||||
/**
|
||||
* <p>This method performs aSelector on the receiver, passing anObject as
|
||||
* an argument, but does so in the main thread of the program. The receiver
|
||||
* and anObject are both retained until the method is performed.
|
||||
* </p>
|
||||
* <p>The selector is performed when the runloop of the main thread is in
|
||||
* one of the modes specified in anArray, or if there are no modes in
|
||||
* anArray, the method has no effect and simply returns immediately.
|
||||
* </p>
|
||||
* <p>The argument aFlag specifies whether the method should wait until
|
||||
* the selector has been performed before returning.<br />
|
||||
* <strong>NB.</strong> This method does <em>not</em> cause the run loop of
|
||||
* the main thread to be run ... so if the run loop is not executed by some
|
||||
* code in the main thread, the thread waiting for the perform to complete
|
||||
* will block forever.
|
||||
* </p>
|
||||
* <p>As a special case, if aFlag == YES and the current thread is the main
|
||||
* thread, the modes array is ignord and the selector is performed immediately.
|
||||
* This behavior is necessary to avoid the main thread being blocked by
|
||||
* waiting for a perform which will never happen because the run loop is
|
||||
* not executing.
|
||||
* </p>
|
||||
*/
|
||||
- (void) performSelectorOnMainThread: (SEL)aSelector
|
||||
withObject: (id)anObject
|
||||
waitUntilDone: (BOOL)aFlag
|
||||
modes: (NSArray*)anArray
|
||||
{
|
||||
NSThread *t = GSCurrentThread();
|
||||
|
||||
if (aFlag == YES && (t == defaultThread))
|
||||
{
|
||||
[self performSelector: aSelector withObject: anObject];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSRunLoop *r = GSRunLoopForThread(defaultThread);
|
||||
NSConditionLock *l = nil;
|
||||
GSPerformHolder *h;
|
||||
|
||||
if (aFlag == YES)
|
||||
{
|
||||
l = [NSConditionLock new];
|
||||
}
|
||||
|
||||
h = [GSPerformHolder newForReceiver: self
|
||||
argument: anObject
|
||||
selector: aSelector
|
||||
lock: l];
|
||||
|
||||
[r performSelector: @selector(fire)
|
||||
target: h
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: anArray];
|
||||
|
||||
if (aFlag == YES)
|
||||
{
|
||||
[l lockBeforeDate: [NSDate distantFuture]];
|
||||
}
|
||||
RELEASE(h);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes -performSelectorOnMainThread:withObject:waitUntilDone:modes:
|
||||
* using the supplied arguments and an array containing common modes.
|
||||
*/
|
||||
- (void) performSelectorOnMainThread: (SEL)aSelector
|
||||
withObject: (id)anObject
|
||||
waitUntilDone: (BOOL)aFlag
|
||||
{
|
||||
static NSArray *commonModes = nil;
|
||||
|
||||
if (commonModes == nil)
|
||||
{
|
||||
commonModes = [[NSArray alloc] initWithObjects:
|
||||
NSDefaultRunLoopMode, NSConnectionReplyMode, nil];
|
||||
}
|
||||
[self performSelectorOnMainThread: aSelector
|
||||
withObject: anObject
|
||||
waitUntilDone: aFlag
|
||||
modes: commonModes];
|
||||
}
|
||||
@end
|
||||
typedef struct { @defs(NSThread) } NSThread_ivars;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue