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

Unified Diff: remoting/android/java/src/org/chromium/chromoting/Event.java

Issue 1999583002: Add Event and EventTest (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resolve review comments Created 4 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: remoting/android/java/src/org/chromium/chromoting/Event.java
diff --git a/remoting/android/java/src/org/chromium/chromoting/Event.java b/remoting/android/java/src/org/chromium/chromoting/Event.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bc699051fa3e6c95359715f1aeec9e6b20a8efb
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/Event.java
@@ -0,0 +1,176 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chromoting;
+
+import java.util.HashSet;
+
+/**
+ * A thread-safe event queue which provides both {@link #add} and {@link #remove} functions with
+ * O(log(n)) time complexity, and a {@link raise} function in the derived class
+ * {@link Event.Raisable} to execute all queued callbacks.
+ *
+ * @param <ParamT> The parameter used in {@link ParameterRunnable} callback.
+ */
+public class Event<ParamT> {
+ /** A runnable with parameter. */
+ public static interface ParameterRunnable<ParamT> {
+ void run(ParamT p);
+ }
+
+ /** A callback with parameter. */
+ public static interface ParameterCallback<ReturnT, ParamT> {
+ ReturnT run(ParamT p);
+ }
+
+ /**
+ * An event provider version of {@link Event} implementation, provides {@link raise} function to
+ * execute appended {@link ParameterRunnable}, and {@link clear} function to clear all appended
+ * callbacks.
+ */
+ public static final class Raisable<ParamT> extends Event<ParamT> {
+ /** Clears all appended callbacks */
+ public void clear() {
+ synchronized (mSet) {
+ mSet.clear();
+ }
+ }
+
+ /**
+ * Executes all queued {@link ParameterRunnable} with |parameter|, returns an integer of
+ * total callbacks executed. Note, if an 'add' function call is executing concurrently
+ * with the 'raise' function call, the newly added object may not be executed.
+ */
+ public int raise(ParamT parameter) {
+ Object[] array;
+ synchronized (mSet) {
+ array = mSet.toArray();
+ }
+ int count = 0;
+ for (Object obj : array) {
+ execute(obj, parameter);
+ count++;
+ }
+ return count;
+ }
+
+ /** Executes |obj| as ParameterRunnable<ParamT> with |parameter| as ParamT. */
+ @SuppressWarnings("unchecked")
+ private void execute(Object obj, ParamT parameter) {
+ ParameterRunnable<ParamT> runnable = (ParameterRunnable<ParamT>) obj;
+ runnable.run(parameter);
+ }
+ }
+
+ /**
+ * A self removable {@link ParameterRunner}, uses a boolean {@link ParameterCallback} to decide
+ * whether removes self from {@link Event} or not.
+ */
+ private static class SelfRemovableParameterRunnable<ParamT>
+ implements ParameterRunnable<ParamT> {
+ private final ParameterCallback<Boolean, ParamT> mCallback;
+ private final Event<ParamT> mOwner;
+
+ // This lock is used to make sure mEvent is correctly set before remove in run function.
+ // i.e. mOwner.add and assigment of mEvent need to be atomic.
+ private final Object mLock;
+ private final Object mEvent;
+
+ private SelfRemovableParameterRunnable(Event<ParamT> owner,
+ ParameterCallback<Boolean, ParamT> callback) {
+ Preconditions.notNull(callback);
+ mCallback = callback;
+ mOwner = owner;
+ mLock = new Object();
+ synchronized (mLock) {
+ mEvent = mOwner.add(this);
+ }
+ Preconditions.notNull(mEvent);
+ }
+
+ public final void run(ParamT p) {
+ synchronized (mLock) {
+ if (mOwner.contains(mEvent)) {
+ if (!mCallback.run(p)) {
+ // Event.Raisable.clear may be called in a different thread.
+ mOwner.remove(mEvent);
+ }
+ }
+ }
+ }
+ }
+
+ protected final HashSet<ParameterRunnable<ParamT>> mSet;
+
+ public Event() {
+ mSet = new HashSet<>();
+ }
+
+ /**
+ * Adds a {@link ParameterRunnable} object into current instance, returns an object which can
+ * be used to {@link remove} the runnable from this instance. If |runnable| is null or it has
+ * been added to this instance already, this function returns null.
+ */
+ public Object add(ParameterRunnable<ParamT> runnable) {
+ if (runnable == null) {
+ return null;
+ }
+ synchronized (mSet) {
+ if (mSet.add(runnable)) {
+ return runnable;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds a self removable {@link ParameterRunnable} object into current instance; the runnable
+ * will remove itself from {@link Event} instance when callback returns false.
+ */
+ public void addSelfRemovable(ParameterCallback<Boolean, ParamT> callback) {
+ Preconditions.notNull(callback);
+
+ // SelfRemovableParameterRunner is self-contained, i.e. consumers do not need to have a
+ // reference of this instance, but all the logic is in new function.
+ new SelfRemovableParameterRunnable<ParamT>(this, callback);
+ }
+
+ /**
+ * Removes an object that was previously returned by {@link add}. Returns false if the object
+ * is not in the event queue, or not returned by {@link add} function.
+ */
+ public boolean remove(Object obj) {
+ synchronized (mSet) {
+ return mSet.remove(obj);
+ }
+ }
+
+ /**
+ * Returns whether current instance contains the object that was previously returned by
+ * {@link add}.
+ */
+ public boolean contains(Object obj) {
+ synchronized (mSet) {
+ return mSet.contains(obj);
+ }
+ }
+
+ /**
+ * Returns the total count of runnables attached to current instance.
+ */
+ public int size() {
+ synchronized (mSet) {
+ return mSet.size();
+ }
+ }
+
+ /**
+ * Returns true if there is no runnable attached to current instance.
+ */
+ public boolean isEmpty() {
+ synchronized (mSet) {
+ return mSet.isEmpty();
+ }
+ }
+}
« no previous file with comments | « remoting/android/client_java_tmpl.gni ('k') | remoting/android/java/src/org/chromium/chromoting/Preconditions.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698