WebWorkers: Add MessageQueueThreadRegistry

Summary:
public

It is helpful to be able to access the current MessageQueueThread like you would the current Looper. I would do this exactly as Looper does it, but we have forked implementations of MQT for the native bridge and MQT is an interface that can't hold private members.

Reviewed By: lexs

Differential Revision: D2779072

fb-gh-sync-id: 0ff841d8c490b971697c8e5d45f9c0a57668376b
This commit is contained in:
Andy Street 2016-01-04 12:00:18 -08:00 committed by facebook-github-bot-0
parent 8c9c7e6286
commit 42e5b2a5bc
3 changed files with 82 additions and 16 deletions

View File

@ -10,10 +10,8 @@
package com.facebook.react.bridge.queue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import android.os.Looper;
@ -21,6 +19,7 @@ import com.facebook.common.logging.FLog;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.AssertionException;
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.futures.SimpleSettableFuture;
@ -28,7 +27,7 @@ import com.facebook.react.common.futures.SimpleSettableFuture;
* Encapsulates a Thread that has a {@link Looper} running on it that can accept Runnables.
*/
@DoNotStrip
/* package */ class MessageQueueThreadImpl implements MessageQueueThread {
public class MessageQueueThreadImpl implements MessageQueueThread {
private final String mName;
private final Looper mLooper;
@ -142,7 +141,25 @@ import com.facebook.react.common.futures.SimpleSettableFuture;
String name,
QueueThreadExceptionHandler exceptionHandler) {
Looper mainLooper = Looper.getMainLooper();
return new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
final MessageQueueThreadImpl mqt =
new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
// Ensure that the MQT is registered by the time this method returns
if (UiThreadUtil.isOnUiThread()) {
MessageQueueThreadRegistry.register(mqt);
} else {
final SimpleSettableFuture<Void> registrationFuture = new SimpleSettableFuture<>();
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
MessageQueueThreadRegistry.register(mqt);
registrationFuture.set(null);
}
});
registrationFuture.getOrThrow(5000, TimeUnit.MILLISECONDS);
}
return mqt;
}
/**
@ -150,30 +167,29 @@ import com.facebook.react.common.futures.SimpleSettableFuture;
* running on it. Give it a name for easier debugging. When this method exits, the new
* MessageQueueThreadImpl is ready to receive events.
*/
private static MessageQueueThreadImpl startNewBackgroundThread(
String name,
public static MessageQueueThreadImpl startNewBackgroundThread(
final String name,
QueueThreadExceptionHandler exceptionHandler) {
final SimpleSettableFuture<Looper> simpleSettableFuture = new SimpleSettableFuture<>();
final SimpleSettableFuture<Looper> looperFuture = new SimpleSettableFuture<>();
final SimpleSettableFuture<MessageQueueThread> mqtFuture = new SimpleSettableFuture<>();
Thread bgThread = new Thread(
new Runnable() {
@Override
public void run() {
Looper.prepare();
simpleSettableFuture.set(Looper.myLooper());
looperFuture.set(Looper.myLooper());
MessageQueueThreadRegistry.register(mqtFuture.getOrThrow(5000, TimeUnit.MILLISECONDS));
Looper.loop();
}
}, "mqt_" + name);
bgThread.start();
try {
return new MessageQueueThreadImpl(
name,
simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS),
exceptionHandler);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
Looper myLooper = looperFuture.getOrThrow(5000, TimeUnit.MILLISECONDS);
MessageQueueThreadImpl mqt = new MessageQueueThreadImpl(name, myLooper, exceptionHandler);
mqtFuture.set(mqt);
return mqt;
}
}

View File

@ -0,0 +1,38 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge.queue;
import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
/**
* A utility for getting the MessageQueueThread for the current thread. Once there is only one
* implementation of MessageQueueThread, this should move to that class.
*/
@DoNotStrip
public class MessageQueueThreadRegistry {
private static ThreadLocal<MessageQueueThread> sMyMessageQueueThread = new ThreadLocal<>();
/*package*/ static void register(MessageQueueThread mqt) {
mqt.assertIsOnThread();
sMyMessageQueueThread.set(mqt);
}
/**
* @return the MessageQueueThread that owns the current Thread.
*/
public static MessageQueueThread myMessageQueueThread() {
return Assertions.assertNotNull(
sMyMessageQueueThread.get(),
"This thread doesn't have a MessageQueueThread registered to it!");
}
}

View File

@ -91,6 +91,18 @@ public class SimpleSettableFuture<T> implements Future<T> {
return mResult;
}
/**
* Convenience wrapper for {@link #get(long, TimeUnit)} that re-throws get()'s Exceptions as
* RuntimeExceptions.
*/
public @Nullable T getOrThrow(long timeout, TimeUnit unit) {
try {
return get(timeout, unit);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
}
private void checkNotSet() {
if (mReadyLatch.getCount() == 0) {
throw new RuntimeException("Result has already been set!");