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

Side by Side Diff: base/message_loop.h

Issue 483: Eliminate the TimerManager by pulling its priority queue into MessageLoop.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | base/message_loop.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 #ifndef BASE_MESSAGE_LOOP_H_ 5 #ifndef BASE_MESSAGE_LOOP_H_
6 #define BASE_MESSAGE_LOOP_H_ 6 #define BASE_MESSAGE_LOOP_H_
7 7
8 #include <deque> 8 #include <deque>
9 #include <queue> 9 #include <queue>
10 #include <string> 10 #include <string>
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 }; 73 };
74 74
75 // Add a DestructionObserver, which will start receiving notifications 75 // Add a DestructionObserver, which will start receiving notifications
76 // immediately. 76 // immediately.
77 void AddDestructionObserver(DestructionObserver* destruction_observer); 77 void AddDestructionObserver(DestructionObserver* destruction_observer);
78 78
79 // Remove a DestructionObserver. It is safe to call this method while a 79 // Remove a DestructionObserver. It is safe to call this method while a
80 // DestructionObserver is receiving a notification callback. 80 // DestructionObserver is receiving a notification callback.
81 void RemoveDestructionObserver(DestructionObserver* destruction_observer); 81 void RemoveDestructionObserver(DestructionObserver* destruction_observer);
82 82
83 // Call the task's Run method asynchronously from within a message loop at 83 // The "PostTask" family of methods call the task's Run method asynchronously
84 // some point in the future. With the PostTask variant, tasks are invoked in 84 // from within a message loop at some point in the future.
85 // FIFO order, inter-mixed with normal UI event processing. With the
86 // PostDelayedTask variant, tasks are called after at least approximately
87 // 'delay_ms' have elapsed.
88 // 85 //
89 // The MessageLoop takes ownership of the Task, and deletes it after it 86 // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed
90 // has been Run(). 87 // with normal UI or IO event processing. With the PostDelayedTask variant,
88 // tasks are called after at least approximately 'delay_ms' have elapsed.
91 // 89 //
92 // NOTE: This method may be called on any thread. The Task will be invoked 90 // The NonNestable variants work similarly except that they promise never to
91 // dispatch the task from a nested invocation of MessageLoop::Run. Instead,
92 // such tasks get deferred until the top-most MessageLoop::Run is executing.
93 //
94 // The MessageLoop takes ownership of the Task, and deletes it after it has
95 // been Run().
96 //
97 // NOTE: These methods may be called on any thread. The Task will be invoked
93 // on the thread that executes MessageLoop::Run(). 98 // on the thread that executes MessageLoop::Run().
99
100 void PostTask(
101 const tracked_objects::Location& from_here, Task* task);
102
103 void PostDelayedTask(
104 const tracked_objects::Location& from_here, Task* task, int delay_ms);
94 105
95 void PostTask(const tracked_objects::Location& from_here, Task* task) { 106 void PostNonNestableTask(
96 PostDelayedTask(from_here, task, 0); 107 const tracked_objects::Location& from_here, Task* task);
97 }
98 108
99 void PostDelayedTask(const tracked_objects::Location& from_here, Task* task, 109 void PostNonNestableDelayedTask(
100 int delay_ms); 110 const tracked_objects::Location& from_here, Task* task, int delay_ms);
101 111
102 // A variant on PostTask that deletes the given object. This is useful 112 // A variant on PostTask that deletes the given object. This is useful
103 // if the object needs to live until the next run of the MessageLoop (for 113 // if the object needs to live until the next run of the MessageLoop (for
104 // example, deleting a RenderProcessHost from within an IPC callback is not 114 // example, deleting a RenderProcessHost from within an IPC callback is not
105 // good). 115 // good).
106 // 116 //
107 // NOTE: This method may be called on any thread. The object will be deleted 117 // NOTE: This method may be called on any thread. The object will be deleted
108 // on the thread that executes MessageLoop::Run(). If this is not the same 118 // on the thread that executes MessageLoop::Run(). If this is not the same
109 // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit 119 // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit
110 // from RefCountedThreadSafe<T>! 120 // from RefCountedThreadSafe<T>!
111 template <class T> 121 template <class T>
112 void DeleteSoon(const tracked_objects::Location& from_here, T* object) { 122 void DeleteSoon(const tracked_objects::Location& from_here, T* object) {
113 PostTask(from_here, new DeleteTask<T>(object)); 123 PostNonNestableTask(from_here, new DeleteTask<T>(object));
114 } 124 }
115 125
116 // A variant on PostTask that releases the given reference counted object 126 // A variant on PostTask that releases the given reference counted object
117 // (by calling its Release method). This is useful if the object needs to 127 // (by calling its Release method). This is useful if the object needs to
118 // live until the next run of the MessageLoop, or if the object needs to be 128 // live until the next run of the MessageLoop, or if the object needs to be
119 // released on a particular thread. 129 // released on a particular thread.
120 // 130 //
121 // NOTE: This method may be called on any thread. The object will be 131 // NOTE: This method may be called on any thread. The object will be
122 // released (and thus possibly deleted) on the thread that executes 132 // released (and thus possibly deleted) on the thread that executes
123 // MessageLoop::Run(). If this is not the same as the thread that calls 133 // MessageLoop::Run(). If this is not the same as the thread that calls
124 // PostDelayedTask(FROM_HERE, ), then T MUST inherit from 134 // PostDelayedTask(FROM_HERE, ), then T MUST inherit from
125 // RefCountedThreadSafe<T>! 135 // RefCountedThreadSafe<T>!
126 template <class T> 136 template <class T>
127 void ReleaseSoon(const tracked_objects::Location& from_here, T* object) { 137 void ReleaseSoon(const tracked_objects::Location& from_here, T* object) {
128 PostTask(from_here, new ReleaseTask<T>(object)); 138 PostNonNestableTask(from_here, new ReleaseTask<T>(object));
129 } 139 }
130 140
131 // Run the message loop. 141 // Run the message loop.
132 void Run(); 142 void Run();
133 143
134 // Process all pending tasks, windows messages, etc., but don't wait/sleep. 144 // Process all pending tasks, windows messages, etc., but don't wait/sleep.
135 // Return as soon as all items that can be run are taken care of. 145 // Return as soon as all items that can be run are taken care of.
136 void RunAllPending(); 146 void RunAllPending();
137 147
138 // Signals the Run method to return after it is done processing all pending 148 // Signals the Run method to return after it is done processing all pending
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 202
193 // Returns the MessageLoop object for the current thread, or null if none. 203 // Returns the MessageLoop object for the current thread, or null if none.
194 static MessageLoop* current() { 204 static MessageLoop* current() {
195 MessageLoop* loop = static_cast<MessageLoop*>(tls_index_.Get()); 205 MessageLoop* loop = static_cast<MessageLoop*>(tls_index_.Get());
196 // TODO(darin): sadly, we cannot enable this yet since people call us even 206 // TODO(darin): sadly, we cannot enable this yet since people call us even
197 // when they have no intention of using us. 207 // when they have no intention of using us.
198 //DCHECK(loop) << "Ouch, did you forget to initialize me?"; 208 //DCHECK(loop) << "Ouch, did you forget to initialize me?";
199 return loop; 209 return loop;
200 } 210 }
201 211
202 // Returns the TimerManager object for the current thread. This getter is
203 // deprecated. Please use OneShotTimer or RepeatingTimer instead.
204 base::TimerManager* timer_manager_deprecated() { return &timer_manager_; }
205
206 // Enables or disables the recursive task processing. This happens in the case 212 // Enables or disables the recursive task processing. This happens in the case
207 // of recursive message loops. Some unwanted message loop may occurs when 213 // of recursive message loops. Some unwanted message loop may occurs when
208 // using common controls or printer functions. By default, recursive task 214 // using common controls or printer functions. By default, recursive task
209 // processing is disabled. 215 // processing is disabled.
210 // 216 //
211 // The specific case where tasks get queued is: 217 // The specific case where tasks get queued is:
212 // - The thread is running a message loop. 218 // - The thread is running a message loop.
213 // - It receives a task #1 and execute it. 219 // - It receives a task #1 and execute it.
214 // - The task #1 implicitly start a message loop, like a MessageBox in the 220 // - The task #1 implicitly start a message loop, like a MessageBox in the
215 // unit test. This can also be StartDoc or GetSaveFileName. 221 // unit test. This can also be StartDoc or GetSaveFileName.
216 // - The thread receives a task #2 before or while in this second message 222 // - The thread receives a task #2 before or while in this second message
217 // loop. 223 // loop.
218 // - With NestableTasksAllowed set to true, the task #2 will run right away. 224 // - With NestableTasksAllowed set to true, the task #2 will run right away.
219 // Otherwise, it will get executed right after task #1 completes at "thread 225 // Otherwise, it will get executed right after task #1 completes at "thread
220 // message loop level". 226 // message loop level".
221 void SetNestableTasksAllowed(bool allowed); 227 void SetNestableTasksAllowed(bool allowed);
222 bool NestableTasksAllowed() const; 228 bool NestableTasksAllowed() const;
223 229
224 // Enables or disables the restoration during an exception of the unhandled 230 // Enables or disables the restoration during an exception of the unhandled
225 // exception filter that was active when Run() was called. This can happen 231 // exception filter that was active when Run() was called. This can happen
226 // if some third party code call SetUnhandledExceptionFilter() and never 232 // if some third party code call SetUnhandledExceptionFilter() and never
227 // restores the previous filter. 233 // restores the previous filter.
228 void set_exception_restoration(bool restore) { 234 void set_exception_restoration(bool restore) {
229 exception_restoration_ = restore; 235 exception_restoration_ = restore;
230 } 236 }
231 237
232
233 //---------------------------------------------------------------------------- 238 //----------------------------------------------------------------------------
234 protected: 239 protected:
235 friend class base::TimerManager; // So it can call DidChangeNextTimerExpiry
236
237 struct RunState { 240 struct RunState {
238 // Used to count how many Run() invocations are on the stack. 241 // Used to count how many Run() invocations are on the stack.
239 int run_depth; 242 int run_depth;
240 243
241 // Used to record that Quit() was called, or that we should quit the pump 244 // Used to record that Quit() was called, or that we should quit the pump
242 // once it becomes idle. 245 // once it becomes idle.
243 bool quit_received; 246 bool quit_received;
244 247
245 #if defined(OS_WIN) 248 #if defined(OS_WIN)
246 base::MessagePumpWin::Dispatcher* dispatcher; 249 base::MessagePumpWin::Dispatcher* dispatcher;
247 #endif 250 #endif
248 }; 251 };
249 252
250 class AutoRunState : RunState { 253 class AutoRunState : RunState {
251 public: 254 public:
252 AutoRunState(MessageLoop* loop); 255 AutoRunState(MessageLoop* loop);
253 ~AutoRunState(); 256 ~AutoRunState();
254 private: 257 private:
255 MessageLoop* loop_; 258 MessageLoop* loop_;
256 RunState* previous_state_; 259 RunState* previous_state_;
257 }; 260 };
258 261
259 // A prioritized queue with interface that mostly matches std::queue<>. 262 // This structure is copied around by value.
260 // For debugging/performance testing, you can swap in std::queue<Task*>. 263 struct PendingTask {
261 class PrioritizedTaskQueue { 264 Task* task; // The task to run.
262 public: 265 Time delayed_run_time; // The time when the task should be run.
263 PrioritizedTaskQueue() : next_sequence_number_(0) {} 266 int sequence_num; // Used to facilitate sorting by run time.
264 ~PrioritizedTaskQueue() {} 267 bool nestable; // True if OK to dispatch from a nested loop.
265 void pop() { queue_.pop(); }
266 bool empty() { return queue_.empty(); }
267 size_t size() { return queue_.size(); }
268 Task* front() { return queue_.top().task(); }
269 void push(Task * task);
270 268
271 private: 269 PendingTask(Task* task, bool nestable)
272 class PrioritizedTask { 270 : task(task), sequence_num(0), nestable(nestable) {
273 public: 271 }
274 PrioritizedTask(Task* task, int sequence_number) 272
275 : task_(task), 273 // Used to support sorting.
276 sequence_number_(sequence_number), 274 bool operator<(const PendingTask& other) const;
277 priority_(task->priority()) {}
278 Task* task() const { return task_; }
279 bool operator < (PrioritizedTask const & right) const ;
280
281 private:
282 Task* task_;
283 // Number to ensure (default) FIFO ordering in a PriorityQueue.
284 int sequence_number_;
285 // Priority of task when pushed.
286 int priority_;
287 }; // class PrioritizedTask
288
289 std::priority_queue<PrioritizedTask> queue_;
290 // Default sequence number used when push'ing (monotonically decreasing).
291 int next_sequence_number_;
292 DISALLOW_EVIL_CONSTRUCTORS(PrioritizedTaskQueue);
293 }; 275 };
294 276
295 // Implementation of a TaskQueue as a null terminated list, with end pointers. 277 typedef std::queue<PendingTask> TaskQueue;
296 class TaskQueue { 278 typedef std::priority_queue<PendingTask> DelayedTaskQueue;
297 public:
298 TaskQueue() : first_(NULL), last_(NULL) {}
299 void Push(Task* task);
300 Task* Pop(); // Extract the next Task from the queue, and return it.
301 bool Empty() const { return !first_; }
302 private:
303 Task* first_;
304 Task* last_;
305 };
306
307 // Implementation of a Task queue that automatically switches into a priority
308 // queue if it observes any non-zero priorities in tasks.
309 class OptionallyPrioritizedTaskQueue {
310 public:
311 OptionallyPrioritizedTaskQueue() : use_priority_queue_(false) {}
312 void Push(Task* task);
313 Task* Pop(); // Extract next Task from queue, and return it.
314 bool Empty();
315 bool use_priority_queue() const { return use_priority_queue_; }
316
317 private:
318 bool use_priority_queue_;
319 PrioritizedTaskQueue prioritized_queue_;
320 TaskQueue queue_;
321 DISALLOW_EVIL_CONSTRUCTORS(OptionallyPrioritizedTaskQueue);
322 };
323 279
324 #if defined(OS_WIN) 280 #if defined(OS_WIN)
325 base::MessagePumpWin* pump_win() { 281 base::MessagePumpWin* pump_win() {
326 return static_cast<base::MessagePumpWin*>(pump_.get()); 282 return static_cast<base::MessagePumpWin*>(pump_.get());
327 } 283 }
328 #endif 284 #endif
329 285
330 // A function to encapsulate all the exception handling capability in the 286 // A function to encapsulate all the exception handling capability in the
331 // stacks around the running of a main message loop. It will run the message 287 // stacks around the running of a main message loop. It will run the message
332 // loop in a SEH try block or not depending on the set_SEH_restoration() 288 // loop in a SEH try block or not depending on the set_SEH_restoration()
(...skipping 16 matching lines...) Expand all
349 // it executes a task. Queued tasks accumulate only when there is a 305 // it executes a task. Queued tasks accumulate only when there is a
350 // non-nestable task currently processing, in which case the new_task is 306 // non-nestable task currently processing, in which case the new_task is
351 // appended to the list work_queue_. Such re-entrancy generally happens when 307 // appended to the list work_queue_. Such re-entrancy generally happens when
352 // an unrequested message pump (typical of a native dialog) is executing in 308 // an unrequested message pump (typical of a native dialog) is executing in
353 // the context of a task. 309 // the context of a task.
354 bool QueueOrRunTask(Task* new_task); 310 bool QueueOrRunTask(Task* new_task);
355 311
356 // Runs the specified task and deletes it. 312 // Runs the specified task and deletes it.
357 void RunTask(Task* task); 313 void RunTask(Task* task);
358 314
359 // Make state adjustments just before and after running tasks so that we can 315 // Calls RunTask or queues the pending_task on the deferred task list if it
360 // continue to work if a native message loop is employed during a task. 316 // cannot be run right now. Returns true if the task was run.
361 void BeforeTaskRunSetup(); 317 bool DeferOrRunPendingTask(const PendingTask& pending_task);
362 void AfterTaskRunRestore();
363 318
364 // Load tasks from the incoming_queue_ into work_queue_ if the latter is 319 // Load tasks from the incoming_queue_ into work_queue_ if the latter is
365 // empty. The former requires a lock to access, while the latter is directly 320 // empty. The former requires a lock to access, while the latter is directly
366 // accessible on this thread. 321 // accessible on this thread.
367 void ReloadWorkQueue(); 322 void ReloadWorkQueue();
368 323
369 // Delete tasks that haven't run yet without running them. Used in the 324 // Delete tasks that haven't run yet without running them. Used in the
370 // destructor to make sure all the task's destructors get called. 325 // destructor to make sure all the task's destructors get called.
371 void DeletePendingTasks(); 326 void DeletePendingTasks();
372 327
373 // Post a task to our incomming queue. 328 // Post a task to our incomming queue.
374 void PostTaskInternal(Task* task); 329 void PostTask_Helper(const tracked_objects::Location& from_here, Task* task,
375 330 int delay_ms, bool nestable);
376 // Called by the TimerManager when its next timer changes.
377 void DidChangeNextTimerExpiry();
378
379 // Entry point for TimerManager to request the Run() of a task. If we
380 // created the task during an PostTask(FROM_HERE, ), then we will also
381 // perform destructions, and we'll have the option of queueing the task. If
382 // we didn't create the timer, then we will Run it immediately.
383 bool RunTimerTask(Timer* timer);
384
385 // Since some Timer's are owned by MessageLoop, the TimerManager (when it is
386 // being destructed) passses us the timers to discard (without doing a Run()).
387 void DiscardTimer(Timer* timer);
388 331
389 // base::MessagePump::Delegate methods: 332 // base::MessagePump::Delegate methods:
390 virtual bool DoWork(); 333 virtual bool DoWork();
391 virtual bool DoDelayedWork(Time* next_delayed_work_time); 334 virtual bool DoDelayedWork(Time* next_delayed_work_time);
392 virtual bool DoIdleWork(); 335 virtual bool DoIdleWork();
393 336
394 // Start recording histogram info about events and action IF it was enabled 337 // Start recording histogram info about events and action IF it was enabled
395 // and IF the statistics recorder can accept a registration of our histogram. 338 // and IF the statistics recorder can accept a registration of our histogram.
396 void StartHistogrammer(); 339 void StartHistogrammer();
397 340
398 // Add occurence of event to our histogram, so that we can see what is being 341 // Add occurence of event to our histogram, so that we can see what is being
399 // done in a specific MessageLoop instance (i.e., specific thread). 342 // done in a specific MessageLoop instance (i.e., specific thread).
400 // If message_histogram_ is NULL, this is a no-op. 343 // If message_histogram_ is NULL, this is a no-op.
401 void HistogramEvent(int event); 344 void HistogramEvent(int event);
402 345
403 static TLSSlot tls_index_; 346 static TLSSlot tls_index_;
404 static const LinearHistogram::DescriptionPair event_descriptions_[]; 347 static const LinearHistogram::DescriptionPair event_descriptions_[];
405 static bool enable_histogrammer_; 348 static bool enable_histogrammer_;
406 349
407 Type type_; 350 Type type_;
408 351
409 base::TimerManager timer_manager_; 352 // A list of tasks that need to be processed by this instance. Note that
353 // this queue is only accessed (push/pop) by our current thread.
354 TaskQueue work_queue_;
355
356 // Contains delayed tasks, sorted by their 'delayed_run_time' property.
357 DelayedTaskQueue delayed_work_queue_;
410 358
411 // A list of tasks that need to be processed by this instance. Note that this 359 // A queue of non-nestable tasks that we had to defer because when it came
412 // queue is only accessed (push/pop) by our current thread. 360 // time to execute them we were in a nested message loop. They will execute
413 // As an optimization, when we don't need to use the prioritization of 361 // once we're out of nested message loops.
414 // work_queue_, we use a null terminated list (TaskQueue) as our 362 TaskQueue deferred_non_nestable_work_queue_;
415 // implementation of the queue. This saves on memory (list uses pointers
416 // internal to Task) and probably runs faster than the priority queue when
417 // there was no real prioritization.
418 OptionallyPrioritizedTaskQueue work_queue_;
419 363
420 scoped_refptr<base::MessagePump> pump_; 364 scoped_refptr<base::MessagePump> pump_;
421 365
422 ObserverList<DestructionObserver> destruction_observers_; 366 ObserverList<DestructionObserver> destruction_observers_;
423 // A recursion block that prevents accidentally running additonal tasks when 367 // A recursion block that prevents accidentally running additonal tasks when
424 // insider a (accidentally induced?) nested message pump. 368 // insider a (accidentally induced?) nested message pump.
425 bool nestable_tasks_allowed_; 369 bool nestable_tasks_allowed_;
426 370
427 bool exception_restoration_; 371 bool exception_restoration_;
428 372
429 std::string thread_name_; 373 std::string thread_name_;
430 // A profiling histogram showing the counts of various messages and events. 374 // A profiling histogram showing the counts of various messages and events.
431 scoped_ptr<LinearHistogram> message_histogram_; 375 scoped_ptr<LinearHistogram> message_histogram_;
432 376
433 // A null terminated list which creates an incoming_queue of tasks that are 377 // A null terminated list which creates an incoming_queue of tasks that are
434 // aquired under a mutex for processing on this instance's thread. These tasks 378 // aquired under a mutex for processing on this instance's thread. These tasks
435 // have not yet been sorted out into items for our work_queue_ vs items that 379 // have not yet been sorted out into items for our work_queue_ vs items that
436 // will be handled by the TimerManager. 380 // will be handled by the TimerManager.
437 TaskQueue incoming_queue_; 381 TaskQueue incoming_queue_;
438 // Protect access to incoming_queue_. 382 // Protect access to incoming_queue_.
439 Lock incoming_queue_lock_; 383 Lock incoming_queue_lock_;
440 384
441 // A null terminated list of non-nestable tasks that we had to delay because 385 RunState* state_;
442 // when it came time to execute them we were in a nested message loop. They
443 // will execute once we're out of nested message loops.
444 TaskQueue delayed_non_nestable_queue_;
445 386
446 RunState* state_; 387 // The next sequence number to use for delayed tasks.
388 int next_sequence_num_;
447 389
448 DISALLOW_COPY_AND_ASSIGN(MessageLoop); 390 DISALLOW_COPY_AND_ASSIGN(MessageLoop);
449 }; 391 };
450 392
451 //----------------------------------------------------------------------------- 393 //-----------------------------------------------------------------------------
452 // MessageLoopForUI extends MessageLoop with methods that are particular to a 394 // MessageLoopForUI extends MessageLoop with methods that are particular to a
453 // MessageLoop instantiated with TYPE_UI. 395 // MessageLoop instantiated with TYPE_UI.
454 // 396 //
455 // This class is typically used like so: 397 // This class is typically used like so:
456 // MessageLoopForUI::current()->...call some method... 398 // MessageLoopForUI::current()->...call some method...
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 #endif // defined(OS_WIN) 456 #endif // defined(OS_WIN)
515 }; 457 };
516 458
517 // Do not add any member variables to MessageLoopForIO! This is important b/c 459 // Do not add any member variables to MessageLoopForIO! This is important b/c
518 // MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra 460 // MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra
519 // data that you need should be stored on the MessageLoop's pump_ instance. 461 // data that you need should be stored on the MessageLoop's pump_ instance.
520 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO), 462 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
521 MessageLoopForIO_should_not_have_extra_member_variables); 463 MessageLoopForIO_should_not_have_extra_member_variables);
522 464
523 #endif // BASE_MESSAGE_LOOP_H_ 465 #endif // BASE_MESSAGE_LOOP_H_
OLDNEW
« no previous file with comments | « no previous file | base/message_loop.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698