Chromium Code Reviews| 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; | |
|
mef
2014/12/04 20:37:56
Can we get into the situation where loop() is call
xunjieli
2014/12/04 20:55:53
HttpURLConnection is not thread-safe, so clients s
| |
| 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 |