| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.net.urlconnection; |
| 6 |
| 7 import java.io.IOException; |
| 8 import java.util.concurrent.BlockingQueue; |
| 9 import java.util.concurrent.Executor; |
| 10 import java.util.concurrent.LinkedBlockingQueue; |
| 11 import java.util.concurrent.RejectedExecutionException; |
| 12 |
| 13 /** |
| 14 * A MessageLoop class for use in {@link CronetHttpURLConnection}. |
| 15 */ |
| 16 public final class MessageLoop implements Executor { |
| 17 private final BlockingQueue<Runnable> mQueue; |
| 18 |
| 19 // A reusable runnable to quit the message loop. |
| 20 private final Runnable mQuitTask; |
| 21 |
| 22 // Indicates whether this message loop is currently running. |
| 23 private boolean mLoopRunning = false; |
| 24 |
| 25 // Indicates whether an InterruptedException or a RuntimeException has |
| 26 // occurred in loop(). If true, the loop cannot be safely started because |
| 27 // this might cause the loop to terminate immediately if there is a quit |
| 28 // task enqueued. |
| 29 private boolean mLoopFailed = false; |
| 30 |
| 31 public MessageLoop() { |
| 32 mQueue = new LinkedBlockingQueue<Runnable>(); |
| 33 mQuitTask = new Runnable() { |
| 34 @Override |
| 35 public void run() { |
| 36 mLoopRunning = false; |
| 37 } |
| 38 }; |
| 39 } |
| 40 |
| 41 /** |
| 42 * Runs the message loop. Be sure to call {@link MessageLoop#postQuitTask()} |
| 43 * to end the loop. If an interruptedException occurs, the loop cannot be |
| 44 * started again (see {@link #mLoopFailed}). |
| 45 * @throws IOException |
| 46 */ |
| 47 public void loop() throws IOException { |
| 48 if (mLoopFailed) { |
| 49 throw new IllegalStateException( |
| 50 "Cannot run loop as an exception has occurred previously."); |
| 51 } |
| 52 if (mLoopRunning) { |
| 53 throw new IllegalStateException( |
| 54 "Cannot run loop when it is already running."); |
| 55 } |
| 56 mLoopRunning = true; |
| 57 while (mLoopRunning) { |
| 58 try { |
| 59 Runnable task = mQueue.take(); // Blocks if the queue is empty. |
| 60 task.run(); |
| 61 } catch (InterruptedException | RuntimeException e) { |
| 62 mLoopRunning = false; |
| 63 mLoopFailed = true; |
| 64 if (e instanceof InterruptedException) { |
| 65 throw new IOException(e); |
| 66 } else if (e instanceof RuntimeException) { |
| 67 throw (RuntimeException) e; |
| 68 } |
| 69 } |
| 70 } |
| 71 } |
| 72 |
| 73 /** |
| 74 * Posts a reusable runnable, {@link #mQuitTask} to quit the loop. This |
| 75 * causes the {@link #loop()} to stop after processing all currently |
| 76 * enqueued messages. |
| 77 */ |
| 78 public void postQuitTask() { |
| 79 execute(mQuitTask); |
| 80 } |
| 81 |
| 82 /** |
| 83 * Posts a task to the message loop. |
| 84 */ |
| 85 @Override |
| 86 public void execute(Runnable task) throws RejectedExecutionException { |
| 87 if (task == null) { |
| 88 throw new IllegalArgumentException(); |
| 89 } |
| 90 try { |
| 91 mQueue.put(task); |
| 92 } catch (InterruptedException e) { |
| 93 // In theory this exception won't happen, since we have an blocking |
| 94 // queue with Integer.MAX_Value capacity, put() call will not block. |
| 95 throw new RejectedExecutionException(e); |
| 96 } |
| 97 } |
| 98 |
| 99 /** |
| 100 * Returns whether the loop is currently running. Used in testing. |
| 101 */ |
| 102 public boolean isRunning() { |
| 103 return mLoopRunning; |
| 104 } |
| 105 |
| 106 /** |
| 107 * Returns whether an exception occurred in {#loop()}. Used in testing. |
| 108 */ |
| 109 public boolean hasLoopFailed() { |
| 110 return mLoopFailed; |
| 111 } |
| 112 } |
| OLD | NEW |