/core/externals/update-engine/Common/KSActionProcessor.m

http://macfuse.googlecode.com/ · Objective C · 231 lines · 154 code · 47 blank · 30 comment · 26 complexity · dd2eb17ee9f71fb771a70f83d67954d7 MD5 · raw file

  1. // Copyright 2008 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "KSActionProcessor.h"
  15. #import "KSAction.h"
  16. #import "GTMDefines.h"
  17. #import "GTMLogger.h"
  18. @interface KSActionProcessor (PrivateMethods)
  19. - (void)updateProgressWithFraction:(float)fraction;
  20. - (void)setCurrentAction:(KSAction *)action;
  21. - (void)processHead;
  22. @end
  23. @implementation KSActionProcessor
  24. - (id)init {
  25. return [self initWithDelegate:nil];
  26. }
  27. - (id)initWithDelegate:(id)delegate {
  28. if ((self = [super init])) {
  29. delegate_ = delegate;
  30. actionQ_ = [[NSMutableArray alloc] init];
  31. _GTMDevAssert(actionQ_ != nil, @"actionQ_ should never be nil");
  32. }
  33. return self;
  34. }
  35. - (void)dealloc {
  36. [self stopProcessing]; // This will release currentAction_
  37. [actionQ_ release];
  38. [super dealloc];
  39. }
  40. - (id)delegate {
  41. return delegate_;
  42. }
  43. - (void)setDelegate:(id)delegate {
  44. delegate_ = delegate;
  45. }
  46. - (void)enqueueAction:(KSAction *)action {
  47. _GTMDevAssert(actionQ_ != nil, @"actionQ_ should never be nil");
  48. if (action == nil) return;
  49. @synchronized (self) {
  50. [actionQ_ addObject:action];
  51. [action setProcessor:self];
  52. if ([delegate_ respondsToSelector:@selector(processor:enqueuedAction:)])
  53. [delegate_ processor:self enqueuedAction:action];
  54. }
  55. }
  56. - (NSArray *)actions {
  57. _GTMDevAssert(actionQ_ != nil, @"actionQ_ should never be nil");
  58. // We give the caller a non-mutable snapshot of the current actions so that
  59. // they can't touch our privates (ewww, that'd be bad).
  60. return [[actionQ_ copy] autorelease];
  61. }
  62. - (void)startProcessing {
  63. @synchronized (self) {
  64. if (isProcessing_)
  65. return;
  66. isProcessing_ = YES;
  67. if ([delegate_ respondsToSelector:@selector(processingStarted:)])
  68. [delegate_ processingStarted:self];
  69. [self processHead];
  70. }
  71. }
  72. - (void)stopProcessing {
  73. @synchronized (self) {
  74. isProcessing_ = NO;
  75. // Stop the current action then set it to nil (which will release it)
  76. [currentAction_ terminateAction];
  77. [currentAction_ setProcessor:nil];
  78. [self setCurrentAction:nil];
  79. if ([delegate_ respondsToSelector:@selector(processingStopped:)])
  80. [delegate_ processingStopped:self];
  81. }
  82. }
  83. - (BOOL)isProcessing {
  84. return isProcessing_;
  85. }
  86. - (float)progress {
  87. return progress_;
  88. }
  89. - (KSAction *)currentAction {
  90. return [[currentAction_ retain] autorelease];
  91. }
  92. - (int)actionsCompleted {
  93. return actionsCompleted_;
  94. }
  95. - (NSString *)description {
  96. return [NSString stringWithFormat:
  97. @"<%@:%p isProcessing=%d actions=%d current=%@>", [self class],
  98. self, isProcessing_, [actionQ_ count], [currentAction_ class]];
  99. }
  100. @end // KSActionProcessor
  101. @implementation KSActionProcessor (KSActionProcessorCallbacks)
  102. - (void)runningAction:(KSAction *)action progress:(float)progress {
  103. [self updateProgressWithFraction:progress];
  104. SEL sel = @selector(processor:runningAction:progress:);
  105. if ([delegate_ respondsToSelector:sel])
  106. [delegate_ processor:self runningAction:action progress:progress];
  107. }
  108. - (void)finishedProcessing:(KSAction *)action successfully:(BOOL)wasOK {
  109. @synchronized (self) {
  110. if (action != currentAction_) {
  111. // COV_NF_START
  112. GTMLoggerError(@"finished processing %@, which was not the current action"
  113. @" (%@)", action, currentAction_);
  114. return;
  115. // COV_NF_END
  116. }
  117. [self updateProgressWithFraction:1.0f];
  118. SEL sel = @selector(processor:finishedAction:successfully:);
  119. if ([delegate_ respondsToSelector:sel])
  120. [delegate_ processor:self finishedAction:action successfully:wasOK];
  121. // Get rid of our current action since it's finished
  122. [currentAction_ setProcessor:nil];
  123. [self setCurrentAction:nil];
  124. actionsCompleted_++;
  125. // If we're still supposed to be processing, process the next action
  126. if (isProcessing_)
  127. [self processHead];
  128. }
  129. }
  130. @end // KSActionProcessorCallbacks
  131. @implementation KSActionProcessor (PrivateMethods)
  132. - (void)updateProgressWithFraction:(float)fraction {
  133. NSInteger totalActions = [actionQ_ count] + actionsCompleted_;
  134. // Count the currently running action, and don't let totalActions == 0
  135. if (isProcessing_ || totalActions == 0) totalActions += 1;
  136. _GTMDevAssert(totalActions != 0, @"totalActions must not be 0");
  137. float unit = (float)1 / totalActions;
  138. @synchronized (self) {
  139. progress_ = (unit * actionsCompleted_) + (unit * fraction);
  140. // ensures 0.0 < progress_ < 1.0
  141. progress_ = (progress_ > 1.0f) ? 1.0f : progress_;
  142. progress_ = (progress_ < 0.0f) ? 0.0f : progress_;
  143. }
  144. }
  145. - (void)setCurrentAction:(KSAction *)action {
  146. [currentAction_ autorelease];
  147. currentAction_ = [action retain];
  148. }
  149. - (void)processHead {
  150. _GTMDevAssert(actionQ_ != nil, @"actionQ_ should never be nil");
  151. @synchronized (self) {
  152. _GTMDevAssert(currentAction_ == nil,
  153. @"currentAction_ (%@) must be nil before "
  154. @"processing a new action", currentAction_);
  155. if ([actionQ_ count] > 0) {
  156. // Get the first action and assign it to currentAction_, make sure the
  157. // action is not already running, then remove it from the queue.
  158. KSAction *action = [actionQ_ objectAtIndex:0];
  159. // Make sure the action we're about to run isn't already running. This
  160. // would be illegal, so we'll log and scream if it happens.
  161. if ([action isRunning]) {
  162. // COV_NF_START
  163. [self stopProcessing];
  164. _GTMDevAssert(NO, @"%@ can't run %@ because it's already running!",
  165. self, action);
  166. return;
  167. // COV_NF_END
  168. }
  169. [self setCurrentAction:action];
  170. [actionQ_ removeObjectAtIndex:0];
  171. if ([delegate_ respondsToSelector:@selector(processor:startingAction:)])
  172. [delegate_ processor:self startingAction:action];
  173. // Start the action
  174. [action performAction];
  175. } else {
  176. isProcessing_ = NO;
  177. // Tell the delegate that we're done processing
  178. if ([delegate_ respondsToSelector:@selector(processingDone:)])
  179. [delegate_ processingDone:self];
  180. [self stopProcessing];
  181. }
  182. }
  183. }
  184. @end // PrivateMethods