1#import "ObjectTesting.h"
2
3#import "Foundation/NSAutoreleasePool.h"
4#import "Foundation/NSThread.h"
5#import "Foundation/NSTimer.h"
6#import "Foundation/NSRunLoop.h"
7#import "GNUstepBase/GSConfig.h"
8
9const NSTimeInterval kDelay = 0.01;
10
11#if GS_USE_LIBDISPATCH_RUNLOOP && __has_feature(blocks)
12#  define DISPATCH_RL_INTEGRATION 1
13#  if __has_include(<dispatch.h>)
14#    include <dispatch.h>
15#  else
16#    include <dispatch/dispatch.h>
17#  endif
18#endif
19
20/**
21 * This is a simple counter object that gets incremented from a different
22 * thread, but by using dispatch_async() to put the actual increment operation
23 * onto the main queue.
24 */
25@interface Counter : NSObject
26{
27  NSUInteger counter;
28}
29- (void)increment;
30- (NSUInteger)counter;
31@end
32
33/**
34 * This is the object running in the other thread. It's purpose is to dispatch
35 * five increments to the main queue and then exit.
36 */
37@interface Queuer : NSObject
38- (void)worker: (Counter*)counter;
39- (void)run;
40- (void)timeout: (NSTimer*)t;
41@end
42
43@implementation Counter
44- (void)increment
45{
46  counter++;
47}
48
49- (NSUInteger)counter
50{
51  return counter;
52}
53@end
54
55@implementation Queuer
56
57- (void)worker: (Counter*)counter
58{
59  NSUInteger i = 0;
60  NSAutoreleasePool     *pool = [NSAutoreleasePool new];
61  for (i  = 0; i < 5; i++)
62  {
63#   ifdef DISPATCH_RL_INTEGRATION
64      dispatch_async(dispatch_get_main_queue(), ^ {
65        [counter increment];
66      });
67#   endif
68    NSDate *d  = [NSDate dateWithTimeIntervalSinceNow: kDelay];
69    while ([d timeIntervalSinceNow] > 0)
70      {
71        [[NSRunLoop currentRunLoop] runUntilDate: d];
72      }
73  }
74  [pool release];
75}
76
77
78- (void)timeout: (NSTimer*)t
79{
80  PASS(NO, "Timeout while trying to run blocks on main thread");
81}
82
83- (void) run
84{
85  NSDate *until = [NSDate dateWithTimeIntervalSinceNow: 1.0];
86  Counter *c = [Counter new];
87  [NSTimer scheduledTimerWithTimeInterval: 1.0
88                                   target: self
89                                 selector: @selector(timeout:)
90                                 userInfo: nil
91                                  repeats: YES];
92
93  [NSThread detachNewThreadSelector: @selector(worker:)
94                           toTarget: self
95                         withObject: c];
96
97  while ([until timeIntervalSinceNow] > 0)
98    {
99      NSDate  *tick = [NSDate dateWithTimeIntervalSinceNow: kDelay * 2];
100      [[NSRunLoop currentRunLoop] runUntilDate: tick];
101      if ([c counter] == 5)
102        {
103          break;
104        }
105    }
106  PASS([c counter] == 5, "Dispatch blocks execute on main queue");
107}
108
109@end
110
111int main(int argc, char *argv[])
112{
113  NSAutoreleasePool *pool = [NSAutoreleasePool new];
114  START_SET("NSRunLoop libdispatch integration")
115# ifndef DISPATCH_RL_INTEGRATION
116  SKIP("No libdispatch, no blocks support or no runloop integration hooks in libdispatch")
117# else
118  [[[Queuer new] autorelease] run];
119# endif
120  END_SET("NSRunLoop libdispatch integration")
121  [pool release];
122  return 0;
123}
124