Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(710)

Side by Side Diff: ios/chrome/app/deferred_initialization_runner.mm

Issue 2217083002: Add sequential dispatching for InitializationRunner (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix tests Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/chrome/app/deferred_initialization_runner.h" 5 #import "ios/chrome/app/deferred_initialization_runner.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #import "base/ios/weak_nsobject.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/mac/scoped_nsobject.h" 11 #include "base/mac/scoped_nsobject.h"
11 12
12 // An object encapsulating the deferred execution of a block of initialization 13 // An object encapsulating the deferred execution of a block of initialization
13 // code. 14 // code.
14 @interface DeferredInitializationBlock : NSObject { 15 @interface DeferredInitializationBlock : NSObject {
15 // A string to reference the initialization block. 16 // A string to reference the initialization block.
16 base::scoped_nsobject<NSString> _name; 17 base::scoped_nsobject<NSString> _name;
17 // A block of code to execute. 18 // A block of code to execute.
18 base::scoped_nsprotocol<ProceduralBlock> _runBlock; 19 base::scoped_nsprotocol<ProceduralBlock> _runBlock;
19 } 20 }
20 21
22 - (instancetype)init NS_UNAVAILABLE;
23
21 // Designated initializer. 24 // Designated initializer.
22 - (id)initWithName:(NSString*)name block:(ProceduralBlock)block; 25 - (instancetype)initWithName:(NSString*)name
26 block:(ProceduralBlock)block NS_DESIGNATED_INITIALIZER;
23 27
24 // Dispatches the deferred execution the block after |delaySeconds|. 28 // Dispatches the deferred execution the block after |delaySeconds|.
29 // Deprecated.
25 - (void)dispatch:(NSTimeInterval)delaySeconds; 30 - (void)dispatch:(NSTimeInterval)delaySeconds;
26 31
27 // Executes the deferred block now. 32 // Executes the deferred block now.
28 - (void)runSynchronously; 33 - (void)run;
29 34
30 // Cancels the block's execution. 35 // Cancels the block's execution.
31 - (void)cancel; 36 - (void)cancel;
37
32 @end 38 @end
33 39
34 @implementation DeferredInitializationBlock 40 @implementation DeferredInitializationBlock
35 41
36 // Overrides default designated initializer. 42 // Overrides default designated initializer.
37 - (id)init { 43 - (instancetype)init {
38 NOTREACHED(); 44 NOTREACHED();
39 return nil; 45 return nil;
40 } 46 }
41 47
42 - (id)initWithName:(NSString*)name block:(ProceduralBlock)block { 48 - (void)dispatch:(NSTimeInterval)delaySeconds {
49 int64_t nanoseconds = delaySeconds * NSEC_PER_SEC;
50 DCHECK([NSThread isMainThread]);
51 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds),
52 dispatch_get_main_queue(), ^() {
53 [self run];
54 });
55 }
56
57 - (instancetype)initWithName:(NSString*)name block:(ProceduralBlock)block {
43 DCHECK(block); 58 DCHECK(block);
44 self = [super init]; 59 self = [super init];
45 if (self) { 60 if (self) {
46 _name.reset([name copy]); 61 _name.reset([name copy]);
47 _runBlock.reset([block copy]); 62 _runBlock.reset([block copy]);
48 } 63 }
49 return self; 64 return self;
50 } 65 }
51 66
52 - (void)dispatch:(NSTimeInterval)delaySeconds { 67 - (void)run {
53 int64_t nanoseconds = delaySeconds * NSEC_PER_SEC;
54 DCHECK([NSThread isMainThread]);
55 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds),
56 dispatch_get_main_queue(), ^() {
57 [self runSynchronously];
58 });
59 }
60
61 - (void)runSynchronously {
62 ProceduralBlock deferredBlock = _runBlock.get(); 68 ProceduralBlock deferredBlock = _runBlock.get();
63 if (!deferredBlock) 69 if (!deferredBlock)
64 return; 70 return;
65 deferredBlock(); 71 deferredBlock();
66 [[DeferredInitializationRunner sharedInstance] cancelBlockNamed:_name]; 72 [[DeferredInitializationRunner sharedInstance] cancelBlockNamed:_name];
67 } 73 }
68 74
69 - (void)cancel { 75 - (void)cancel {
70 _runBlock.reset(); 76 _runBlock.reset();
71 } 77 }
72 78
73 @end 79 @end
74 80
75 @implementation DeferredInitializationRunner { 81 @interface DeferredInitializationRunner () {
82 base::scoped_nsobject<NSMutableArray> _blocksNameQueue;
76 base::scoped_nsobject<NSMutableDictionary> _runBlocks; 83 base::scoped_nsobject<NSMutableDictionary> _runBlocks;
84 BOOL _isBlockScheduled;
77 } 85 }
78 86
87 // Schedule the next block to be run after |delay| it will automatically
88 // schedule the next block after |delayBetweenBlocks|.
89 - (void)scheduleNextBlockWithDelay:(NSTimeInterval)delay;
90
91 // Time interval between two blocks. Default value is 200ms.
92 @property(nonatomic) NSTimeInterval delayBetweenBlocks;
93
94 // Time interval before running the first block. Default value is 3s.
95 @property(nonatomic) NSTimeInterval delayBeforeFirstBlock;
96
97 @end
98
99 @implementation DeferredInitializationRunner
100
101 @synthesize delayBetweenBlocks = _delayBetweenBlocks;
102 @synthesize delayBeforeFirstBlock = _delayBeforeFirstBlock;
103
79 + (DeferredInitializationRunner*)sharedInstance { 104 + (DeferredInitializationRunner*)sharedInstance {
80 static DeferredInitializationRunner* instance = 105 static dispatch_once_t once = 0;
81 [[DeferredInitializationRunner alloc] init]; 106 static DeferredInitializationRunner* instance = nil;
107 dispatch_once(&once, ^{
108 instance = [[DeferredInitializationRunner alloc] init];
109 });
82 return instance; 110 return instance;
83 } 111 }
84 112
85 - (id)init { 113 - (id)init {
86 self = [super init]; 114 self = [super init];
87 if (self) 115 if (self) {
116 _blocksNameQueue.reset([[NSMutableArray array] retain]);
88 _runBlocks.reset([[NSMutableDictionary dictionary] retain]); 117 _runBlocks.reset([[NSMutableDictionary dictionary] retain]);
118 _isBlockScheduled = NO;
119 _delayBetweenBlocks = 0.2;
120 _delayBeforeFirstBlock = 3.0;
121 }
89 return self; 122 return self;
90 } 123 }
91 124
125 - (void)enqueueBlockNamed:(NSString*)name block:(ProceduralBlock)block {
126 DCHECK(name);
jif 2016/09/26 09:12:47 I'm afraid of |enqueueBlockNamed:| being called wh
gambard 2016/09/26 13:42:55 Done.
127 [self cancelBlockNamed:name];
128 [_blocksNameQueue addObject:name];
129
130 base::scoped_nsobject<DeferredInitializationBlock> deferredBlock(
131 [[DeferredInitializationBlock alloc] initWithName:name block:block]);
132 [_runBlocks setObject:deferredBlock forKey:name];
133
134 if (!_isBlockScheduled) {
135 [self scheduleNextBlockWithDelay:self.delayBeforeFirstBlock];
136 }
137 }
138
139 - (void)scheduleNextBlockWithDelay:(NSTimeInterval)delay {
140 _isBlockScheduled = NO;
141 NSString* nextBlockName = [_blocksNameQueue firstObject];
142 if (!nextBlockName)
143 return;
144
145 DeferredInitializationBlock* nextBlock =
146 [_runBlocks objectForKey:nextBlockName];
147 DCHECK(nextBlock);
148
149 base::WeakNSObject<DeferredInitializationRunner> weakSelf(self);
150
151 dispatch_after(
152 dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)),
153 dispatch_get_main_queue(), ^{
154 [nextBlock run];
155 [weakSelf scheduleNextBlockWithDelay:[weakSelf delayBetweenBlocks]];
156 });
157
158 _isBlockScheduled = YES;
159 [_blocksNameQueue removeObjectAtIndex:0];
160 }
161
92 - (void)runBlockNamed:(NSString*)name 162 - (void)runBlockNamed:(NSString*)name
93 after:(NSTimeInterval)delaySeconds 163 after:(NSTimeInterval)delaySeconds
94 block:(ProceduralBlock)block { 164 block:(ProceduralBlock)block {
95 DCHECK(name); 165 DCHECK(name);
96 // Safety check in case this function is called with a nanosecond or 166 // Safety check in case this function is called with a nanosecond or
97 // microsecond parameter by mistake. 167 // microsecond parameter by mistake.
98 DCHECK(delaySeconds < 3600.0); 168 DCHECK(delaySeconds < 3600.0);
99 // Cancels the previously scheduled block, if there is one, so this 169 // Cancels the previously scheduled block, if there is one, so this
100 // |name| block will not be run more than once. 170 // |name| block will not be run more than once.
101 [[_runBlocks objectForKey:name] cancel]; 171 [[_runBlocks objectForKey:name] cancel];
102 base::scoped_nsobject<DeferredInitializationBlock> deferredBlock( 172 base::scoped_nsobject<DeferredInitializationBlock> deferredBlock(
103 [[DeferredInitializationBlock alloc] initWithName:name block:block]); 173 [[DeferredInitializationBlock alloc] initWithName:name block:block]);
104 [_runBlocks setObject:deferredBlock forKey:name]; 174 [_runBlocks setObject:deferredBlock forKey:name];
105 [deferredBlock dispatch:delaySeconds]; 175 [deferredBlock dispatch:delaySeconds];
106 } 176 }
107 177
108 - (void)runBlockIfNecessary:(NSString*)name { 178 - (void)runBlockIfNecessary:(NSString*)name {
109 [[_runBlocks objectForKey:name] runSynchronously]; 179 [[_runBlocks objectForKey:name] run];
110 } 180 }
111 181
112 - (void)cancelBlockNamed:(NSString*)name { 182 - (void)cancelBlockNamed:(NSString*)name {
113 DCHECK(name); 183 DCHECK(name);
184 [_blocksNameQueue removeObject:name];
114 [[_runBlocks objectForKey:name] cancel]; 185 [[_runBlocks objectForKey:name] cancel];
115 [_runBlocks removeObjectForKey:name]; 186 [_runBlocks removeObjectForKey:name];
116 } 187 }
117 188
118 - (NSUInteger)numberOfBlocksRemaining { 189 - (NSUInteger)numberOfBlocksRemaining {
119 return [_runBlocks count]; 190 return [_runBlocks count];
120 } 191 }
121 192
122 @end 193 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698