From e1b988967751f32ac9cdaddcbfc225e7949573da Mon Sep 17 00:00:00 2001 From: rfm Date: Sat, 4 Mar 2006 06:47:56 +0000 Subject: [PATCH] make housekeeping timer more transparent and remove deprecated code git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@22593 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 14 ++++ Headers/Foundation/NSRunLoop.h | 15 ---- Source/GSRunLoopCtxt.h | 9 +-- Source/NSRunLoop.m | 125 ++++++++++++++++++--------------- Source/NSThread.m | 8 +-- Source/win32/GNUmakefile | 1 - Source/win32/GSRunLoopCtxt.m | 10 +-- Source/win32/NSRunLoopWin32.m | 36 ---------- Source/win32/NSStreamWin32.m | 8 +-- 9 files changed, 96 insertions(+), 130 deletions(-) delete mode 100644 Source/win32/NSRunLoopWin32.m diff --git a/ChangeLog b/ChangeLog index e03dd626d..be8a50d71 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2006-03-04 Richard Frith-Macdonald + + * Source/NSRunLoop.m: Rewrite housekeeping timer. + * Source/GSRunLoopCtxt.h: Remove obsolete message/selector. + * Source/win32/GSRunLoopCtxt.m: Add housekeeping timer. + * Source/win32/NSRunLoopWin32.m: remove unused code. + * Source/win32/GNUmakefile: remove /NSRunLoopWin32.m + * Source/win32/NSStreamWin32.m: minor tidyups + * Source/NSThread.m: Use new internal API for housekeeping timer. + * Headers/Foundation/NSRunLoop.h: Remove deprecated mingw api + Basically, remove deprecated mingw32 specific api, and change + housekeeper to try to make it as invisible as possible in terms of + side effects. + 2006-03-03 Richard Frith-Macdonald * Tools/gdomap.c: Check for HAVE_STDINT_H for safety of include diff --git a/Headers/Foundation/NSRunLoop.h b/Headers/Foundation/NSRunLoop.h index 050e1d728..cb7d52660 100644 --- a/Headers/Foundation/NSRunLoop.h +++ b/Headers/Foundation/NSRunLoop.h @@ -201,19 +201,4 @@ typedef enum { - (void) getFds: (int*)fds count: (int*)count; @end -#if defined(__MINGW32__) -/** - * Obsolete interface that add method to set target for win32 messages.
- */ -@interface NSRunLoop(mingw32) -/** Deprecated ... will be removed - */ -- (void) addMsgTarget: (id)target - withMethod: (SEL)selector - forMode: (NSString*)mode; -/** Deprecated ... will be removed - */ -- (void) removeMsgForMode: (NSString*)mode; -@end -#endif #endif /*__NSRunLoop_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Source/GSRunLoopCtxt.h b/Source/GSRunLoopCtxt.h index f2b5f0677..d62dd0e27 100644 --- a/Source/GSRunLoopCtxt.h +++ b/Source/GSRunLoopCtxt.h @@ -39,10 +39,7 @@ typedef struct{ GSIArray performers; /** The actions to perform regularly. */ GSIArray timers; /** The timers set for the runloop mode */ GSIArray watchers; /** The inputs set for the runloop mode */ -#if defined(__MINGW32__) - id msgTarget; /** Target to raise a win32 message */ - SEL msgSelector; /** method of target */ -#endif + NSTimer *housekeeper; /** Housekeeping timer for loop. */ @private #if defined(__MINGW32__) NSMapTable *handleMap; @@ -67,4 +64,8 @@ typedef struct{ - (BOOL) pollUntil: (int)milliseconds within: (NSArray*)contexts; @end +@interface NSRunLoop (Housekeeper) +- (void) _setHousekeeper: (NSTimer*)timer; +@end + #endif /* __GSRunLoopCtxt_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Source/NSRunLoop.m b/Source/NSRunLoop.m index e7995da8f..a16b12058 100644 --- a/Source/NSRunLoop.m +++ b/Source/NSRunLoop.m @@ -770,15 +770,15 @@ extern IMP wRetImp; /** * Fires timers whose fire date has passed, and checks timers and limit dates - * for input sources, determining the earliest time that anything watched for - * becomes useless. Returns that date/time. + * for input sources, determining the earliest time that any future timeout + * becomes due. Returns that date/time. */ - (NSDate*) limitDateForMode: (NSString*)mode { - extern NSTimer *GSHousekeeper(void); - GSRunLoopCtxt *context = NSMapGet(_contextMap, mode); + GSRunLoopCtxt *context; NSDate *when = nil; + context = NSMapGet(_contextMap, mode); if (context != nil) { GSRunLoopWatcher *min_watcher = nil; @@ -791,6 +791,19 @@ extern IMP wRetImp; GSIArray timers = context->timers; GSIArray watchers = context->watchers; + /* + * Fire housekeeping timer as necessary + */ + while (context->housekeeper != nil + && ([timerDate(context->housekeeper) timeIntervalSinceNow] <= 0.0)) + { + [context->housekeeper fire]; + } + + /* + * Handle normal timers ... remove invalidated timers and fire any + * whose date has passed. + */ while (GSIArrayCount(timers) != 0) { NSTimer *min_timer = GSIArrayItemAtIndex(timers, 0).obj; @@ -806,7 +819,7 @@ extern IMP wRetImp; { when = [timerDate(min_timer) copy]; } - if ([timerDate(min_timer) timeIntervalSinceNow] > 0) + if ([timerDate(min_timer) timeIntervalSinceNow] > 0.0) { break; } @@ -826,8 +839,6 @@ extern IMP wRetImp; GSNotifyASAP(); /* Post notifications. */ } - /* Is this right? At the moment we invalidate and discard watchers - whose limit-dates have passed. */ while (GSIArrayCount(watchers) != 0) { min_watcher = GSIArrayItemAtIndex(watchers, 0).obj; @@ -849,9 +860,9 @@ extern IMP wRetImp; NSDate *nxt = nil; /* - * If the receiver or its delegate wants to know about - * timeouts - inform it and give it a chance to set a - * revised limit date. + * If the receiver or its delegate wants to know about + * timeouts - inform it and give it a chance to set a + * revised limit date. */ GSIArrayRemoveItemAtIndexNoRelease(watchers, 0); obj = min_watcher->receiver; @@ -895,32 +906,6 @@ extern IMP wRetImp; min_watcher = nil; } } - - /* - * If there is nothing being watched, and no valid timers - * other than the housekeeper, we set when to nil so - * that the housekeeper timer does not keep the runloop - * active. It's a special case set up in NSThread.m - */ - if (min_watcher == nil && when != nil) - { - unsigned count = GSIArrayCount(timers); - - while (count-- > 1) - { - NSTimer *tmp = GSIArrayItemAtIndex(timers, 0).obj; - - if (timerInvalidated(tmp) == YES) - { - GSIArrayRemoveItemAtIndex(timers, count); - } - } - if (GSIArrayCount(timers) == 1) - { - DESTROY(when); - } - } - _currentMode = savedMode; } NS_HANDLER @@ -944,25 +929,18 @@ extern IMP wRetImp; if (min_watcher != nil && [min_watcher->_date compare: when] == NSOrderedAscending) { - RELEASE(when); + RELEASE(when); when = min_watcher->_date; } - else - { - AUTORELEASE(when); - } + else + { + AUTORELEASE(when); + } } else if (min_watcher != nil) { when = min_watcher->_date; } -#if defined(__MINGW32__) - // if there are handler for win32 messages - else if (context->msgTarget != nil) - { - when = theFuture; - } -#endif else { return nil; /* Nothing waiting to be done. */ @@ -1006,14 +984,20 @@ extern IMP wRetImp; GSIArray watchers; unsigned i; + /* + * If we have a housekeeping timer, and it is earlier than the + * limit date we have been given, we use the date of the housekeeper + * to determine when to stop. + */ + if (limit_date != nil && context != nil && context->housekeeper != nil + && [timerDate(context->housekeeper) timeIntervalSinceReferenceDate] + < [limit_date timeIntervalSinceReferenceDate]) + { + limit_date = timerDate(context->housekeeper); + } + if ((context == nil || (watchers = context->watchers) == 0 - || (i = GSIArrayCount(watchers)) == 0) -#if defined(__MINGW32__) - // there are inputs for win32 messages - && context->msgTarget == 0) -#else - ) -#endif + || (i = GSIArrayCount(watchers)) == 0)) { NSDebugMLLog(@"NSRunLoop", @"no inputs in mode %@", mode); GSNotifyASAP(); @@ -1276,11 +1260,12 @@ extern IMP wRetImp; /** * Sets up sending of aSelector to target with argument.
* The selector is sent before the next runloop iteration (unless - * cancelled before then).
+ * cancelled before then) in any of the specified modes.
* The target and argument objects are not retained.
* The order value is used to determine the order in which messages * are sent if multiple messages have been set up. Messages with a lower - * order value are sent first. + * order value are sent first.
+ * If the modes array is empty, this method has no effect. */ - (void) performSelector: (SEL)aSelector target: (id)target @@ -1351,3 +1336,29 @@ extern IMP wRetImp; } @end + +@implementation NSRunLoop (Housekeeper) +- (void) _setHousekeeper: (NSTimer*)timer +{ + GSRunLoopCtxt *context; + + context = NSMapGet(_contextMap, NSDefaultRunLoopMode); + if (context == nil) + { + context = [[GSRunLoopCtxt alloc] initWithMode: NSDefaultRunLoopMode + extra: _extra]; + NSMapInsert(_contextMap, context->mode, context); + RELEASE(context); + } + if (context->housekeeper != timer) + { + [context->housekeeper invalidate]; + DESTROY(context->housekeeper); + } + if (timer != nil) + { + context->housekeeper = RETAIN(timer); + } +} +@end + diff --git a/Source/NSThread.m b/Source/NSThread.m index b6dbd3c4f..4b1d31ab5 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -53,6 +53,7 @@ #include "Foundation/NSConnection.h" #include "Foundation/NSInvocation.h" +#include "GSRunLoopCtxt.h" typedef struct { @defs(NSThread) } NSThread_ivars; @@ -353,10 +354,6 @@ GSCurrentThreadDictionary(void) * on-disk database. */ static NSTimer *housekeeper = nil; -NSTimer *GSHousekeeper(void) -{ - return housekeeper; -} /** * Returns the runloop for the specified thread (or, if t is nil, @@ -406,7 +403,8 @@ GSRunLoopForThread(NSThread *t) selector: NULL userInfo: nil repeats: YES]; - [r addTimer: housekeeper forMode: NSDefaultRunLoopMode]; + [r _setHousekeeper: housekeeper]; + RELEASE(housekeeper); RELEASE(arp); } } diff --git a/Source/win32/GNUmakefile b/Source/win32/GNUmakefile index 6ca8f953e..a87520509 100644 --- a/Source/win32/GNUmakefile +++ b/Source/win32/GNUmakefile @@ -35,7 +35,6 @@ win32_OBJC_FILES =\ GSRunLoopWatcher.m \ NSMessagePortWin32.m \ NSMessagePortNameServerWin32.m \ - NSRunLoopWin32.m \ NSStreamWin32.m \ NSUserDefaultsWin32.m \ diff --git a/Source/win32/GSRunLoopCtxt.m b/Source/win32/GSRunLoopCtxt.m index 01b8c68af..51ad44983 100644 --- a/Source/win32/GSRunLoopCtxt.m +++ b/Source/win32/GSRunLoopCtxt.m @@ -131,19 +131,14 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = WatcherMapValueCallBacks, 0); winMsgMap = NSCreateMapTable(NSIntMapKeyCallBacks, WatcherMapValueCallBacks, 0); - - msgTarget = nil; } return self; } /* - * If there is no msgTarget || there is a generic watcher (watching hwnd == 0), + * If there is a generic watcher (watching hwnd == 0), * loop through all events, and send them to the correct * watcher (if there are any) and then process the rest right here. - * else if there is a msgTarget, - * then loop through watchers and process for their - * hwnd's only. Then call msgTarget to clean up the rest of them. * Return a flag to say whether any messages were handled. */ - (BOOL) processAllWindowsMessages:(int)num_winMsgs within: (NSArray*)contexts @@ -158,7 +153,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = generic = NSMapGet(winMsgMap,0); } - if (msgTarget == nil || (generic != nil && generic->_invalidated == NO)) + if (generic != nil && generic->_invalidated == NO) { while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { @@ -242,7 +237,6 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = NSEndMapTableEnumeration(&hEnum); } completed = YES; - [msgTarget performSelector: msgSelector withObject: nil]; } return handled; } diff --git a/Source/win32/NSRunLoopWin32.m b/Source/win32/NSRunLoopWin32.m deleted file mode 100644 index c1bc7c697..000000000 --- a/Source/win32/NSRunLoopWin32.m +++ /dev/null @@ -1,36 +0,0 @@ -#include "config.h" -#include "GNUstepBase/preface.h" -#include "Foundation/NSRunLoop.h" -#include "Foundation/NSDebug.h" -#include "../GSRunLoopCtxt.h" - -@implementation NSRunLoop (mingw32) -- (void) addMsgTarget: (id)target - withMethod: (SEL)selector - forMode: (NSString*)mode -{ - GSRunLoopCtxt *context; - - GSOnceMLog(@"This method is deprecated, use -addEvent:type:watcher:forMode"); - context = NSMapGet(_contextMap, mode); - if (context == nil) - { - context = [[GSRunLoopCtxt alloc] initWithMode: mode extra: _extra]; - NSMapInsert(_contextMap, context->mode, context); - RELEASE(context); - } - context->msgTarget = target; - context->msgSelector = selector; -} -- (void) removeMsgForMode: (NSString*)mode -{ - GSRunLoopCtxt *context; - - context = NSMapGet(_contextMap, mode); - if (context == nil) - { - return; - } - context->msgTarget = nil; -} -@end diff --git a/Source/win32/NSStreamWin32.m b/Source/win32/NSStreamWin32.m index c19a42ea3..f2249f59c 100644 --- a/Source/win32/NSStreamWin32.m +++ b/Source/win32/NSStreamWin32.m @@ -838,7 +838,7 @@ static void setNonblocking(SOCKET fd) return [super propertyForKey: key]; } -- (void)_dispatch +- (void) _dispatch { BOOL av = [self hasSpaceAvailable]; NSStreamEvent myEvent = av ? NSStreamEventHasSpaceAvailable : @@ -856,7 +856,7 @@ static void setNonblocking(SOCKET fd) } } -- (void)scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode +- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode { NSAssert(!_runloop || _runloop == aRunLoop, @"Attempt to schedule in more than one runloop."); @@ -873,7 +873,7 @@ static void setNonblocking(SOCKET fd) } } -- (void)removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode +- (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode { NSAssert(_runloop == aRunLoop, @"Attempt to remove unscheduled runloop"); @@ -884,7 +884,7 @@ static void setNonblocking(SOCKET fd) { [_runloop cancelPerformSelector: @selector(_dispatch) target: self - argument: nil]; + argument: nil]; } if ([_modes count] == 0) {