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