soc.2012.android: e8029b62: Implemented Eventloop and PurpleThread.

michael at soc.pidgin.im michael at soc.pidgin.im
Sat Jun 9 16:02:19 EDT 2012


----------------------------------------------------------------------
Revision: e8029b62e918a90751ff1830647e7facb7cd88b2
Parent:   3e86308d7f711600e74e7345df84b0175eed799c
Author:   michael at soc.pidgin.im
Date:     06/09/12 15:56:23
Branch:   im.pidgin.soc.2012.android
URL: http://d.pidgin.im/viewmtn/revision/info/e8029b62e918a90751ff1830647e7facb7cd88b2

Changelog: 

Implemented Eventloop and PurpleThread.


Changes against parent 3e86308d7f711600e74e7345df84b0175eed799c

  dropped  android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/PurpleThread.java
  added    android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread
  added    android/workspace/im.pidgin.libpurple/native/PurpleAccountManager.c
  added    android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/EventloopTask.java
  added    android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/AbstractWaitableRunnable.java
  added    android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/PurpleThread.java
  added    android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/WaitableRunnable.java
  added    android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/WaitableRunnableRunner.java
  patched  android/workspace/im.pidgin.libpurple/native/EventLoop.c
  patched  android/workspace/im.pidgin.libpurple/native/helpers.c
  patched  android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/AbstractPurpleManaged.java
  patched  android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/CoreManager.java
  patched  android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/EventLoop.java

-------------- next part --------------
============================================================
--- android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/AbstractPurpleManaged.java	057d60c6f99da96e7cacf68e2f3fdd118f552726
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/AbstractPurpleManaged.java	00ebe9b80214bdb5389c8771728a8de6f85af587
@@ -15,4 +15,8 @@ public class AbstractPurpleManaged imple
 	public AbstractPurpleManaged(CoreManager manager) {
 		this.manager = manager;
 	}
+	
+	protected CoreManager getManager() {
+		return manager;
+	}
 }
============================================================
--- android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/CoreManager.java	af2780980367f21c1f77375cba4170316aa3f8e0
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/CoreManager.java	50d0a4a45ae8e37d6684a1e945d3e3a73519d0df
@@ -1,6 +1,7 @@ import im.pidgin.libpurple.account.Purpl
 package im.pidgin.libpurple.core;
 
 import im.pidgin.libpurple.account.PurpleAccountManager;
+import im.pidgin.libpurple.core.thread.PurpleThread;
 
 /**
  * This is the core purple manager, that provides access to all functionality.
@@ -14,6 +15,8 @@ public class CoreManager{
 	
 	private final EventLoop eventloop = new EventLoop(this);
 	
+	private final PurpleThread purpleThread = new PurpleThread();
+	
 	/**
 	 * Initializes libpurple by setting all the ui ops and calling
 	 * purple_core_init().
@@ -37,7 +40,11 @@ public class CoreManager{
 	 * Do not register the eventloop, since it is alredy registered.
 	 */
 	protected void coreInitUI() { 
-		
+		accountList.register();
 	}
 
+	public PurpleThread getThread() {
+		return purpleThread;
+	}
+
 }
============================================================
--- android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/EventLoop.java	24b9a8da3645d52deb82a68c30c575764aa9eb20
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/EventLoop.java	cade8a6767bb7929b28c837f23464d32e9fe1737
@@ -1,5 +1,11 @@ package im.pidgin.libpurple.core;
 package im.pidgin.libpurple.core;
 
+import im.pidgin.libpurple.core.thread.AbstractWaitableRunnable;
+import im.pidgin.libpurple.core.thread.WaitableRunnable;
+
+import java.util.Hashtable;
+import java.util.Timer;
+
 /**
  * This is the eventloop implementation that is used to schedule libpruple
  * events on the purple thread.
@@ -9,6 +15,13 @@ public class EventLoop extends AbstractP
  */
 public class EventLoop extends AbstractPurpleManaged {
 
+	Timer eventTimer = new Timer("Event queue timer");
+
+	private final Object scheduledTimersMutex = new Object();
+	private final Hashtable<Integer, EventloopTask> scheduledTimers = new Hashtable<Integer, EventloopTask>();
+
+	private int timeoutCounter = 0;
+
 	public EventLoop(CoreManager manager) {
 		super(manager);
 	}
@@ -24,12 +37,98 @@ public class EventLoop extends AbstractP
 		init_native();
 	}
 
-	public boolean eventloopRemoveTimeout(int handle) {
+	/**
+	 * Should create a callback timer with an interval measured in milliseconds.
+	 * 
+	 * The supplied function should be called every interval seconds until it
+	 * returns FALSE, after which it should not be called again.
+	 * 
+	 * Analogous to g_timeout_add in glib.
+	 * 
+	 * Note: On Win32, this function may be called from a thread other than the
+	 * libpurple thread. You should make sure to detect this situation and to
+	 * only call "function" from the libpurple thread.
+	 * 
+	 * @param interval
+	 *            the interval in milliseconds between calls to function.
+	 * @param function
+	 *            the function pointer
+	 * @param data
+	 *            arbitrary data to be passed to function at each call.
+	 * @return a handle for the timeout, which can be passed to timeout_remove.
+	 */
+	protected int eventloopAddTimeout(int interval, long function, long data) {
+		int key = timeoutCounter;
+		
+		System.out.println("Adding eventloop task " + key + " to be scheduled every " + interval + " milliseconds.");
+		EventloopTask task = new EventloopTask(new EventloopFunctionExecutor(
+				key, function, data), getManager().getThread());
+		if (interval <= 0) {
+			interval = 1;
+		}
+		eventTimer.schedule(task, interval, interval);
+
+		scheduledTimers.put(key, task);
+		timeoutCounter++;
+		return key;
+	}
+
+	/**
+	 * 
+	 * @param handle
+	 *            an identifier for a timeout, as returned by timeout_add.
+	 * @return TRUE if the timeout identified by handle was found and removed.
+	 */
+	private boolean eventloopRemoveTimeout(int handle) {
+		synchronized (scheduledTimersMutex) {
+			cancelByHandle(handle);
+		}
 		return false;
 	}
 
-	public int eventloopAddTimeout(int interval, long function, long data) {
-		return 0;
+	private void cancelByHandle(int handle) {
+		System.out.println("Canceling eventloop task " + handle + ".");
+		EventloopTask task = scheduledTimers.remove(handle);
+		if (task != null) {
+			task.cancel();
+		}
 	}
 
+	/**
+	 * This is a {@link WaitableRunnable} that executes the given function.
+	 * 
+	 * @author michaelz
+	 * 
+	 */
+	private class EventloopFunctionExecutor extends AbstractWaitableRunnable {
+		private final long function;
+		private final long data;
+		private final int key;
+
+		private EventloopFunctionExecutor(int key, long function, long data) {
+			this.key = key;
+			this.function = function;
+			this.data = data;
+		}
+
+		/**
+		 * Cancels the timer task for this function.
+		 */
+		private void cancel() {
+			cancelByHandle(key);
+		}
+
+		@Override
+		protected void execute() {
+			boolean doContinue = exeucte_native(function, data);
+			if (!doContinue) {
+				cancel();
+			}
+			markForReuse();
+		}
+
+	}
+
+	private native boolean exeucte_native(long function, long data);
+
 }
============================================================
--- android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/PurpleThread.java	ab51165467a319469e318e32a3f66cf657a56cab
+++ /dev/null	
@@ -1,13 +0,0 @@
-package im.pidgin.libpurple.core;
-
-/**
- * This is the main thread of libpurple. It is used internally to execute
- * libpurple functions that can be called from everywhere, because libpurple is
- * not thread safe.
- * 
- * @author michaelz
- * 
- */
-public class PurpleThread {
-
-}
============================================================
--- android/workspace/im.pidgin.libpurple/native/helpers.c	0c0df1819a5cc9d897d0324515e88032ae76ec73
+++ android/workspace/im.pidgin.libpurple/native/helpers.c	5269f1dedca9ca9cf4f1b201e7f1277b4223ff5e
@@ -29,7 +29,7 @@ setJavaObject(JavaObjectReference *ref, 
 	}
 
 	ref->class = (*env)->NewGlobalRef(env, localClass);
-	ref->handlerObject = object;
+	ref->handlerObject = (*env)->NewGlobalRef(env, object);
 	ref->jvm = jvm;
 	(*env)->DeleteLocalRef(env, localClass);
 
@@ -63,9 +63,13 @@ getMethodIDCachedReferenced(JNIEnv *env,
 getMethodIDCachedReferenced(JNIEnv *env, jclass *class,
 		JavaMethodIDCache *cache)
 {
+	g_return_val_if_fail(env != NULL, NULL);
+	g_return_val_if_fail(class != NULL, NULL);
+	g_return_val_if_fail(cache != NULL, NULL);
+
 	if (cache->mid == NULL) {
 		cache->mid = (*env)->GetMethodID(env, class, cache->name,
 				cache->signature);
 	}
-	return NULL;//cache->mid;
+	return cache->mid;
 }
============================================================
--- android/workspace/im.pidgin.libpurple/native/EventLoop.c	8bb800ca3cf58195849fcb90896362142af1ddd5
+++ android/workspace/im.pidgin.libpurple/native/EventLoop.c	c698172b7a14bf26ca3e1d2b24a198643737ac24
@@ -8,14 +8,18 @@
 #include "EventLoop.h"
 #include <libpurple/eventloop.h>
 #include <libpurple/debug.h>
+#include "helpers.h"
 
 static guint
 eventloopAddTimeout(guint interval, GSourceFunc function, gpointer data);
+
 static gboolean
 eventloopRemoveTimeout(guint handle);
+
 static guint
 eventloopAddInput(int fd, PurpleInputCondition cond, PurpleInputFunction func,
 		gpointer user_data);
+
 static gboolean
 eventloopRemoveInput(guint handle);
 
@@ -31,6 +35,15 @@ Java_im_pidgin_libpurple_core_EventLoop_
 	setJavaObject(&eventloop, env, obj);
 }
 
+JNIEXPORT jboolean JNICALL
+Java_im_pidgin_libpurple_core_EventLoop_exeucte_1native(JNIEnv *env,
+		jobject obj, jlong functionPointer, jlong data)
+{
+	GSourceFunc function = (GSourceFunc) longToP(functionPointer);
+	gboolean result = function((gpointer) longToP(data));
+	return result ? JNI_TRUE : JNI_FALSE;
+}
+
 PurpleEventLoopUiOps *
 getEventloopUiOps()
 {
============================================================
--- /dev/null	
+++ android/workspace/im.pidgin.libpurple/native/PurpleAccountManager.c	b56c2ee8099623b6b83a36b15e6b2b070e2ae9bf
@@ -0,0 +1,185 @@
+#include <jni.h>
+#include "helpers.h"
+#include "PurpleAccountManager.h"
+#include <libpurple/account.h>
+static void
+notify_added(PurpleAccount* account, const char* remote_user, const char* id,
+		const char* alias, const char* message);
+
+void
+status_changed(PurpleAccount* account, PurpleStatus* status);
+
+void
+request_add(PurpleAccount* account, const char* remote_user, const char* id,
+		const char* alias, const char* message);
+
+void*
+request_authorize(PurpleAccount* account, const char* remote_user,
+		const char* id, const char* alias, const char* message,
+		gboolean on_list, PurpleAccountRequestAuthorizationCb authorize_cb,
+		PurpleAccountRequestAuthorizationCb deny_cb, void* user_data);
+
+void
+close_account_request(void* ui_handle);
+
+PurpleAccountUiOps uiOps = { notify_added, status_changed, request_add,
+		request_authorize, close_account_request, NULL, NULL, NULL, NULL
+};
+
+JavaObjectReference accountList = JAVA_NULL_OBJECT_REF;
+
+/*
+ * Class:     im_pidgin_libpurple_account_PurpleAccountManager
+ * Method:    register_native
+ * Signature: ()V
+ */JNIEXPORT void JNICALL
+Java_im_pidgin_libpurple_account_PurpleAccountManager_register_1native(
+		JNIEnv *env, jobject obj)
+{
+	setJavaObject(&accountList, env, obj);
+	purple_accounts_set_ui_ops(&uiOps);
+}
+
+static void
+notify_added(PurpleAccount* account, const char* remote_user, const char* id,
+		const char* alias, const char* message)
+{
+	static JavaMethodIDCache methodCache =
+					METHOD_CACHE("notifyAdded", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+
+	jmethodID mid;
+	jlong account_ptr;
+	jstring remote_user_obj;
+	jstring id_obj;
+	jstring alias_obj;
+	jstring message_obj;
+
+	CALLBACK_START_VOID(accountList);
+
+	account_ptr = pToLong(account);
+	remote_user_obj = (*env)->NewStringUTF(env, remote_user);
+	id_obj = (*env)->NewStringUTF(env, id);
+	alias_obj = (*env)->NewStringUTF(env, alias);
+	message_obj = (*env)->NewStringUTF(env, message);
+
+	mid = getMethodIDCachedReferenced(env, accountList.class, &methodCache);
+	if (mid != NULL && remote_user_obj != NULL && id_obj != NULL
+			&& alias_obj != NULL && message_obj != NULL) {
+		(*env)->CallVoidMethod(env, accountList.handlerObject, mid, account_ptr,
+				remote_user_obj, id_obj, alias_obj, message_obj);
+	}
+}
+
+void
+status_changed(PurpleAccount* account, PurpleStatus* status)
+{
+	static JavaMethodIDCache methodCache =
+			METHOD_CACHE("statusChanged", "(JJ)V");
+
+	jmethodID mid;
+	jlong account_ptr;
+	jlong status_ptr;
+
+	CALLBACK_START_VOID(accountList);
+
+	account_ptr = pToLong(account);
+	status_ptr = pToLong(status);
+
+	mid = getMethodIDCachedReferenced(env, accountList.class, &methodCache);
+	if (mid != NULL) {
+		(*env)->CallVoidMethod(env, accountList.handlerObject, mid, account_ptr,
+				status_ptr);
+	}
+}
+
+void
+request_add(PurpleAccount* account, const char* remote_user, const char* id,
+		const char* alias, const char* message)
+{
+	static JavaMethodIDCache methodCache =
+					METHOD_CACHE("requestAdd", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+
+	jmethodID mid;
+	jlong account_ptr;
+	jstring remote_user_obj;
+	jstring id_obj;
+	jstring alias_obj;
+	jstring message_obj;
+
+	CALLBACK_START_VOID(accountList);
+
+	account_ptr = pToLong(account);
+	remote_user_obj = (*env)->NewStringUTF(env, remote_user);
+	id_obj = (*env)->NewStringUTF(env, id);
+	alias_obj = (*env)->NewStringUTF(env, alias);
+	message_obj = (*env)->NewStringUTF(env, message);
+
+	mid = getMethodIDCachedReferenced(env, accountList.class, &methodCache);
+	if (mid != NULL && remote_user_obj != NULL && id_obj != NULL
+			&& alias_obj != NULL && message_obj != NULL) {
+		(*env)->CallVoidMethod(env, accountList.handlerObject, mid, account_ptr,
+				remote_user_obj, id_obj, alias_obj, message_obj);
+	}
+}
+
+void*
+request_authorize(PurpleAccount* account, const char* remote_user,
+		const char* id, const char* alias, const char* message,
+		gboolean on_list, PurpleAccountRequestAuthorizationCb authorize_cb,
+		PurpleAccountRequestAuthorizationCb deny_cb, void* user_data)
+{
+	static JavaMethodIDCache methodCache =
+					METHOD_CACHE("requestAuthorize", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZJJJ)J");
+
+	jmethodID mid;
+	jlong account_ptr;
+	jstring remote_user_obj;
+	jstring id_obj;
+	jstring alias_obj;
+	jstring message_obj;
+	jlong authorize_cb_ptr;
+	jlong deny_cb_ptr;
+	jlong user_data_ptr;
+	jlong result = 0;
+
+	CALLBACK_START(accountList, NULL);
+
+	account_ptr = pToLong(account);
+	remote_user_obj = (*env)->NewStringUTF(env, remote_user);
+	id_obj = (*env)->NewStringUTF(env, id);
+	alias_obj = (*env)->NewStringUTF(env, alias);
+	message_obj = (*env)->NewStringUTF(env, message);
+	authorize_cb_ptr = pToLong(authorize_cb);
+	deny_cb_ptr = pToLong(deny_cb);
+	user_data_ptr = pToLong(user_data);
+
+	mid = getMethodIDCachedReferenced(env, accountList.class, &methodCache);
+	if (mid != NULL && remote_user_obj != NULL && id_obj != NULL
+			&& alias_obj != NULL && message_obj != NULL) {
+		result = (*env)->CallLongMethod(env, accountList.handlerObject, mid,
+				account_ptr, remote_user_obj, id_obj, alias_obj, message_obj,
+				(jboolean) on_list, authorize_cb_ptr, deny_cb_ptr,
+				user_data_ptr);
+	}
+	return longToP(result);
+}
+
+void
+close_account_request(void* ui_handle)
+{
+	static JavaMethodIDCache methodCache =
+			METHOD_CACHE("closeAccountRequest", "(J)V");
+
+	jmethodID mid;
+	jlong ui_handle_ptr;
+
+	CALLBACK_START_VOID(accountList);
+
+	ui_handle_ptr = pToLong(ui_handle);
+
+	mid = getMethodIDCachedReferenced(env, accountList.class, &methodCache);
+	if (mid != NULL) {
+		(*env)->CallVoidMethod(env, accountList.handlerObject, mid,
+				ui_handle_ptr);
+	}
+}
============================================================
--- /dev/null	
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/EventloopTask.java	8f480a976af87c752327c41c7113c3321a967ff4
@@ -0,0 +1,39 @@
+package im.pidgin.libpurple.core;
+
+import im.pidgin.libpurple.core.thread.PurpleThread;
+import im.pidgin.libpurple.core.thread.WaitableRunnable;
+
+import java.util.TimerTask;
+
+/**
+ * This is a special task for the eventloop.
+ * 
+ * @author michaelz
+ * 
+ */
+public class EventloopTask extends TimerTask {
+
+	private final WaitableRunnable runnable;
+	private final PurpleThread thread;
+
+	public EventloopTask(WaitableRunnable runnable, PurpleThread thread) {
+		this.runnable = runnable;
+		this.thread = thread;
+	}
+
+	@Override
+	public void run() {
+		thread.schedule(runnable);
+		try {
+			runnable.waitFor();
+		} catch (InterruptedException e) {
+			/*
+			 * should not happen, since timer thread is private and never
+			 * interrupted.
+			 */
+			System.err.println("Unexpected interupt exception"
+					+ " during an EventloopTask executioon.");
+		}
+	}
+
+}
============================================================
--- /dev/null	
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/AbstractWaitableRunnable.java	a9bc2d38b3a0f2e3feba177800df28e14359f58b
@@ -0,0 +1,53 @@
+package im.pidgin.libpurple.core.thread;
+
+/**
+ * An abstract implementation of {@link WaitableRunnable}
+ * 
+ * @author michaelz
+ * 
+ */
+public abstract class AbstractWaitableRunnable implements WaitableRunnable {
+	private final Object mutex = new Object();
+	private boolean wasRun = false;
+
+	private int waitForRunning = 0;
+
+	@Override
+	public void run() {
+		execute();
+		synchronized (mutex) {
+			mutex.notifyAll();
+			wasRun = true;
+		}
+	}
+
+	protected abstract void execute();;
+
+	@Override
+	public void waitFor() throws InterruptedException {
+		synchronized (mutex) {
+			waitForRunning++;
+			try {
+				while (!wasRun) {
+					mutex.wait();
+				}
+			} finally {
+				waitForRunning--;
+				mutex.notifyAll();
+			}
+		}
+	}
+
+	protected void markForReuse() {
+		synchronized (mutex) {
+			while (waitForRunning > 0) {
+				try {
+					mutex.wait();
+				} catch (InterruptedException e) {
+					// ignored, since we won't wait on anyone but ourselves.
+				}
+			}
+			wasRun = false;
+		}
+	}
+}
============================================================
--- /dev/null	
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/PurpleThread.java	5246a975f3b7e3b360d0edb96046338b0a2d6e91
@@ -0,0 +1,89 @@
+package im.pidgin.libpurple.core.thread;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * This is the main thread of libpurple. It is used internally to execute
+ * libpurple functions that can be called from everywhere, because libpurple is
+ * not thread safe.
+ * 
+ * @author michaelz
+ * 
+ */
+public class PurpleThread {
+	private final BlockingQueue<WaitableRunnable> waiting = new LinkedBlockingQueue<WaitableRunnable>();
+	private final Object purpleMutex = new Object();
+	private final Object lastScheduledMutex = new Object();
+	private WaitableRunnable lastScheduled;
+
+	public PurpleThread() {
+		Thread thread = new Thread(new PurpleThreadRunner());
+		thread.start();
+	}
+
+	/**
+	 * Gets a mutex you can synchronize against to do purple calls. Only use for
+	 * really short calls. This method blocks until the thread is in a safe
+	 * state and returns a mutex to you. There may be other tasks scheduled
+	 * between you got the mutex and you got the lock.
+	 * 
+	 * @return A synchronisation mutex.
+	 * @throws InterruptedException
+	 */
+	public Object createSynchronizationMutex() throws InterruptedException {
+		// wait until the current tail is executed and not in the queue
+		// any more, to avoid race conditions.
+		WaitableRunnable last;
+		synchronized (lastScheduledMutex) {
+			last = lastScheduled;
+		}
+
+		if (last != null) {
+			last.waitFor();
+		}
+
+		return purpleMutex;
+	}
+
+	private class PurpleThreadRunner implements Runnable {
+		@Override
+		public void run() {
+			// just run until program exits for now.
+			while (true) {
+				try {
+					Runnable runnable = waiting.take();
+					synchronized (purpleMutex) {
+						synchronized (lastScheduledMutex) {
+							if (lastScheduled == runnable) {
+								lastScheduled = null;
+							}
+						}
+						runnable.run();
+					}
+
+				} catch (InterruptedException e) {
+					System.out.println("Purple thread was interrupted,"
+							+ " but is continuing.");
+				} catch (Throwable t) {
+					System.err.println("Purple thread catched throwable: "
+							+ t.getMessage());
+					t.printStackTrace(System.err);
+				}
+			}
+		}
+	}
+
+	public void schedule(WaitableRunnable r) {
+		synchronized (lastScheduledMutex) {
+			waiting.offer(r);
+			lastScheduled = r;
+		}
+	}
+
+	public void scheduleAndWaitFor(Runnable r) throws InterruptedException {
+		WaitableRunnableRunner waitable = new WaitableRunnableRunner(r);
+		schedule(waitable);
+		waitable.waitFor();
+	}
+}
============================================================
--- /dev/null	
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/WaitableRunnable.java	154b00a62ccb0de70d5ea712c350942704f11524
@@ -0,0 +1,18 @@
+package im.pidgin.libpurple.core.thread;
+
+/**
+ * This is a special form of a runnable, that can be waited for.
+ * 
+ * @author michaelz
+ * 
+ */
+public interface WaitableRunnable extends Runnable {
+	/**
+	 * Waits for this object to execute. May only be called before the run()
+	 * Mehtod was ececuted.
+	 * 
+	 * @throws InterruptedException
+	 *             If the wait was interrupted somewhere.
+	 */
+	public void waitFor() throws InterruptedException;
+}
============================================================
--- /dev/null	
+++ android/workspace/im.pidgin.libpurple/src/im/pidgin/libpurple/core/thread/WaitableRunnableRunner.java	7ba069ed1c30ad8e161f928a2b4403509ef012fd
@@ -0,0 +1,22 @@
+package im.pidgin.libpurple.core.thread;
+
+/**
+ * A runnable we can wait for. We might use an object pool for this.
+ * 
+ * @author michaelz
+ * 
+ */
+public class WaitableRunnableRunner extends AbstractWaitableRunnable {
+
+	private final Runnable runnable;
+
+	public WaitableRunnableRunner(Runnable r) {
+		this.runnable = r;
+	}
+
+	@Override
+	protected void execute() {
+		runnable.run();
+	}
+
+}


More information about the Commits mailing list