[libinline-java-perl] 247/398: version 1 of callbacks from multiple threads: control all from a single InlineJavaPerlCaller

Jonas Smedegaard dr at jones.dk
Thu Feb 26 11:43:10 UTC 2015


This is an automated email from the git hooks/post-receive script.

js pushed a commit to tag 0.55
in repository libinline-java-perl.

commit 8edac21a58fffce361ac40a745c24362b039609c
Author: patrick_leb <>
Date:   Fri Nov 21 03:52:54 2003 +0000

    version 1 of callbacks from multiple threads: control all from a single InlineJavaPerlCaller
---
 Java/sources/InlineJavaCallback.java   |  31 +++++++
 Java/sources/InlineJavaPerlCaller.java | 150 +++++++++++++++++++++++++++++++--
 Java/sources/InlineJavaServer.java     | 134 ++++++++++++-----------------
 t/12_callbacks.t                       |   2 +-
 t/swing_callback.pl                    |  28 ++++--
 5 files changed, 252 insertions(+), 93 deletions(-)

diff --git a/Java/sources/InlineJavaCallback.java b/Java/sources/InlineJavaCallback.java
new file mode 100644
index 0000000..1cd590f
--- /dev/null
+++ b/Java/sources/InlineJavaCallback.java
@@ -0,0 +1,31 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+
+
+/*
+	Callback to Perl...
+*/
+class InlineJavaCallback {
+	private String pkg = null ;
+	private String method = null ;
+	private Object args[] = null ;
+	private String cast = null ;
+
+	InlineJavaCallback(String _pkg, String _method, Object _args[], String _cast) {
+		pkg = _pkg ;
+		method = _method ;
+		args = _args ;
+		cast = _cast ;	
+	}
+
+	String GetCommand(InlineJavaProtocol ijp) throws InlineJavaException {
+		StringBuffer cmdb = new StringBuffer("callback " + pkg + " " + method + " " + cast) ;
+		if (args != null){
+			for (int i = 0 ; i < args.length ; i++){
+				 cmdb.append(" " + ijp.SerializeObject(args[i])) ;
+			}
+		}
+		return cmdb.toString() ;
+	}
+}
diff --git a/Java/sources/InlineJavaPerlCaller.java b/Java/sources/InlineJavaPerlCaller.java
index 928c4da..6f4fdc2 100644
--- a/Java/sources/InlineJavaPerlCaller.java
+++ b/Java/sources/InlineJavaPerlCaller.java
@@ -1,14 +1,27 @@
 package org.perl.inline.java ;
 
+import java.util.* ;
+import java.io.* ;
+
+
 /*
 	Callback to Perl...
 */
 public class InlineJavaPerlCaller {
+	private InlineJavaServer ijs = InlineJavaServer.GetInstance() ;
 	private Thread creator ;
+	private boolean stop_loop = false ;
+	private InlineJavaCallback queued_callback = null ;
+	private Object queued_response = null ;
+
 
+	/*
+		Only thread that communicate with Perl are allowed to create PerlCallers because
+		this is where we get the thread that needs to be notified when the callbacks come in.
+	*/
 	public InlineJavaPerlCaller() throws InlineJavaException {
 		Thread t = Thread.currentThread() ;
-		if (InlineJavaServer.GetInstance().IsThreadPerlContact(t)){
+		if (ijs.IsThreadPerlContact(t)){
 			creator = t ;
 		}
 		else{
@@ -23,11 +36,138 @@ public class InlineJavaPerlCaller {
 
 
 	public Object CallPerl(String pkg, String method, Object args[], String cast) throws InlineJavaException, InlineJavaPerlException {
-		return InlineJavaServer.GetInstance().Callback(pkg, method, args, cast) ;
+		InlineJavaCallback ijc = new InlineJavaCallback(pkg, method, args, cast) ;
+		return CallPerl(ijc) ;
+	}
+
+
+	synchronized public Object CallPerl(InlineJavaCallback ijc) throws InlineJavaException, InlineJavaPerlException {
+		Thread t = Thread.currentThread() ;
+		if (t == creator){
+			return Callback(ijc) ;
+		}
+		else{
+			// Enqueue the callback into the creator thread's queue and notify it
+			// that there is some work for him.
+			// ijs.EnqueueCallback(creator, ijc) ;
+			queued_callback = ijc ;
+			notify() ;
+
+			// Now we must wait until the callback is processed and get back the result...
+			while(true){
+				try {
+					wait() ;
+					if (queued_response != null){
+						break ;
+					}
+				}
+				catch (InterruptedException ie){
+					// Do nothing, return and wait() some more...
+				}
+			}
+
+			Object resp = queued_response ;
+			queued_response = null ;
+			
+			return resp ;
+		}
+	}
+
+
+	synchronized public void StartCallbackLoop() throws InlineJavaException, InlineJavaPerlException {
+		Thread t = Thread.currentThread() ;
+		if (! ijs.IsThreadPerlContact(t)){
+			throw new InlineJavaException("InlineJavaPerlCaller.start_callback_loop() can only be called by threads that communicate directly with Perl") ;
+		}
+
+		Object resp = null ;
+		CheckForCallback() ;
+		stop_loop = false ;
+		while (! stop_loop){
+			try {
+				wait() ;
+				CheckForCallback() ;
+			}
+			catch (InterruptedException ie){
+				// Do nothing, return and wait() some more...
+			}
+		}
+	}
+
+
+	private void CheckForCallback() throws InlineJavaException, InlineJavaPerlException {
+		//ijc = ijs.DequeueCallback(t) ;
+		//if (ijc != null){
+		//	resp = Callback(ijc) ;
+		// Send resp back to the calling thread?
+		//}
+		if (queued_callback != null){
+			InlineJavaCallback ijc = queued_callback ;
+			queued_callback = null ;
+			queued_response = Callback(ijc) ;
+			notify() ;
+		}
 	}
 
-	
-	public void wait_for_callbacks(){
-		// Not sure how this will work just yet...
+
+	synchronized public void StopCallbackLoop() {
+		stop_loop = true ;
+		notify() ;
+	}
+
+
+	private Object Callback(InlineJavaCallback ijcb) throws InlineJavaException, InlineJavaPerlException {
+		Object ret = null ;
+		try {
+			InlineJavaProtocol ijp = new InlineJavaProtocol(ijs, null) ;
+			String cmd = ijcb.GetCommand(ijp) ;
+			InlineJavaUtils.debug(2, "callback command: " + cmd) ;
+
+			Thread t = Thread.currentThread() ;
+			String resp = null ;
+			while (true) {
+				InlineJavaUtils.debug(3, "packet sent (callback) is " + cmd) ;
+				if (! ijs.IsJNI()){
+					// Client-server mode.
+					InlineJavaServerThread ijt = (InlineJavaServerThread)t ;
+					ijt.GetWriter().write(cmd + "\n") ;
+					ijt.GetWriter().flush() ;
+
+					resp = ijt.GetReader().readLine() ;
+				}
+				else{
+					// JNI mode
+					resp = ijs.jni_callback(cmd) ;
+				}
+				InlineJavaUtils.debug(3, "packet recv (callback) is " + resp) ;
+
+				StringTokenizer st = new StringTokenizer(resp, " ") ;
+				String c = st.nextToken() ;
+				if (c.equals("callback")){
+					boolean thrown = new Boolean(st.nextToken()).booleanValue() ;
+					String arg = st.nextToken() ;
+					InlineJavaClass ijc = new InlineJavaClass(ijs, ijp) ;
+					ret = ijc.CastArgument(java.lang.Object.class, arg) ;
+
+					if (thrown){
+						throw new InlineJavaPerlException(ret) ;
+					}
+
+					break ;
+				}
+				else{
+					// Pass it on through the regular channel...
+					InlineJavaUtils.debug(3, "packet is not callback response: " + resp) ;
+					cmd = ijs.ProcessCommand(resp, false) ;
+
+					continue ;
+				}
+			}
+		}
+		catch (IOException e){
+			throw new InlineJavaException("IO error: " + e.getMessage()) ;
+		}
+
+		return ret ;
 	}
 }
diff --git a/Java/sources/InlineJavaServer.java b/Java/sources/InlineJavaServer.java
index 92a6dba..b915223 100644
--- a/Java/sources/InlineJavaServer.java
+++ b/Java/sources/InlineJavaServer.java
@@ -16,6 +16,7 @@ public class InlineJavaServer {
 
 	private InlineJavaUserClassLoader ijucl = null ;
 	private HashMap thread_objects = new HashMap() ;
+	private HashMap thread_callback_queues = new HashMap() ;
 	private int objid = 1 ;
 	private boolean jni = false ;
 	private Thread creator = null ;
@@ -26,7 +27,7 @@ public class InlineJavaServer {
 		init(d) ;
 
 		jni = true ; 
-		thread_objects.put(creator, new HashMap()) ;
+		AddThread(creator) ;
 	}
 
 
@@ -49,8 +50,6 @@ public class InlineJavaServer {
 
 		while (true){
 			try {
-				// For now we pass our own InlineJavaUserClassLoader, but later
-				//  we can implement privacy by creating a new one.
 				InlineJavaServerThread ijt = new InlineJavaServerThread(this, ss.accept(), ijucl) ;
 				ijt.start() ;
 				if (! shared_jvm){
@@ -106,17 +105,21 @@ public class InlineJavaServer {
 	}
 
 
+	boolean IsJNI(){
+		return jni ;
+	}
+
+
 	/*
 		Since this function is also called from the JNI XS extension,
 		it's best if it doesn't throw any exceptions.
-		It is public only for testing purposes.
 	*/
 	String ProcessCommand(String cmd) {
 		return ProcessCommand(cmd, true) ;
 	}
 
 
-	private String ProcessCommand(String cmd, boolean addlf) {
+	String ProcessCommand(String cmd, boolean addlf) {
 		InlineJavaUtils.debug(3, "packet recv is " + cmd) ;
 
 		String resp = null ;
@@ -153,76 +156,11 @@ public class InlineJavaServer {
 	}
 
 
-	native private String jni_callback(String cmd) ;
-
-
-	// So far this is the only method that can be called (indirectly) by the
-	// user code to get back in to Perl. This means that this method really
-	// can be called by other threads the are not InlineJavaServerThreads...
-	//
-	// Is there a way to figure out which InlineJavaServerThread has created
-	// the current thread or is logically attached to it?
-	Object Callback(String pkg, String method, Object args[], String cast) throws InlineJavaException, InlineJavaPerlException {
-		Object ret = null ;
-
-		try {
-			InlineJavaProtocol ijp = new InlineJavaProtocol(this, null) ;
-			InlineJavaClass ijc = new InlineJavaClass(this, ijp) ;
-			StringBuffer cmdb = new StringBuffer("callback " + pkg + " " + method + " " + cast) ;
-			if (args != null){
-				for (int i = 0 ; i < args.length ; i++){
-					 cmdb.append(" " + ijp.SerializeObject(args[i])) ;
-				}
-			}
-			String cmd = cmdb.toString() ;
-			InlineJavaUtils.debug(2, "callback command: " + cmd) ;
-
-			Thread t = Thread.currentThread() ;
-			String resp = null ;
-			while (true) {
-				InlineJavaUtils.debug(3, "packet sent (callback) is " + cmd) ;
-				if (! jni){
-					// Client-server mode
-					InlineJavaServerThread ijt = (InlineJavaServerThread)t ;
-					ijt.GetWriter().write(cmd + "\n") ;
-					ijt.GetWriter().flush() ;
-
-					resp = ijt.GetReader().readLine() ;
-				}
-				else{
-					// JNI mode
-					resp = jni_callback(cmd) ;
-				}
-				InlineJavaUtils.debug(3, "packet recv (callback) is " + resp) ;
-
-				StringTokenizer st = new StringTokenizer(resp, " ") ;
-				String c = st.nextToken() ;
-				if (c.equals("callback")){
-					boolean thrown = new Boolean(st.nextToken()).booleanValue() ;
-					String arg = st.nextToken() ;
-					ret = ijc.CastArgument(java.lang.Object.class, arg) ;
-
-					if (thrown){
-						throw new InlineJavaPerlException(ret) ;
-					}
-
-					break ;
-				}
-				else{
-					// Pass it on through the regular channel...
-					InlineJavaUtils.debug(3, "packet is not callback response: " + resp) ;
-					cmd = ProcessCommand(resp, false) ;
-
-					continue ;
-				}
-			}
-		}
-		catch (IOException e){
-			throw new InlineJavaException("IO error: " + e.getMessage()) ;
-		}
-
-		return ret ;
-	}
+	/*
+		This method really has no business here, but for historical reasons
+		it will remain here.
+	*/
+	native String jni_callback(String cmd) ;
 
 
 	boolean IsThreadPerlContact(Thread t){
@@ -235,7 +173,7 @@ public class InlineJavaServer {
 	}
 
 
-	Object GetObject(int id) throws InlineJavaException {
+	synchronized Object GetObject(int id) throws InlineJavaException {
 		Object o = null ;
 		HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
 
@@ -253,7 +191,7 @@ public class InlineJavaServer {
 	}
 
 
-	int PutObject(Object o) throws InlineJavaException {
+	synchronized int PutObject(Object o) throws InlineJavaException {
 		HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
 
 		int id = objid ;
@@ -269,7 +207,7 @@ public class InlineJavaServer {
 	}
 
 
-	Object DeleteObject(int id) throws InlineJavaException {
+	synchronized Object DeleteObject(int id) throws InlineJavaException {
 		Object o = null ;
 		HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
 
@@ -287,7 +225,7 @@ public class InlineJavaServer {
 	}
 
 
-	int ObjectCount() throws InlineJavaException {
+	synchronized int ObjectCount() throws InlineJavaException {
 		int i = -1 ;
 		HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
 
@@ -302,16 +240,50 @@ public class InlineJavaServer {
 	}
 
 
-	void AddThread(InlineJavaServerThread t){
+	/*
+		Here the prototype accepts Threads because the JNI thread
+		calls this method also.
+	*/
+	synchronized void AddThread(Thread t){
 		thread_objects.put(t, new HashMap()) ;
+		thread_callback_queues.put(t, new ArrayList()) ;
 	}
 
 
-	void RemoveThread(InlineJavaServerThread t){
+	synchronized void RemoveThread(InlineJavaServerThread t){
 		thread_objects.remove(t) ;
+		thread_callback_queues.remove(t) ;
 	}
 	
 
+	synchronized void EnqueueCallback(Thread t, InlineJavaCallback ijc) throws InlineJavaException {
+		ArrayList a = (ArrayList)thread_callback_queues.get(t) ;
+
+		if (a == null){
+			throw new InlineJavaException("Can't find thread " + t.getName() + "!") ;
+		}
+		else{
+			a.add(ijc) ;
+		}
+	}
+
+
+	synchronized InlineJavaCallback DequeueCallback(Thread t) throws InlineJavaException {
+		ArrayList a = (ArrayList)thread_callback_queues.get(t) ;
+
+		if (a == null){
+			throw new InlineJavaException("Can't find thread " + t.getName() + "!") ;
+		}
+		else{
+			if (a.size() > 0){
+				return (InlineJavaCallback)a.remove(0) ;
+			}
+			return null ;
+		}
+	}
+
+
+
 	/*
 		Startup
 	*/
diff --git a/t/12_callbacks.t b/t/12_callbacks.t
index eaebcd4..b99cbaf 100755
--- a/t/12_callbacks.t
+++ b/t/12_callbacks.t
@@ -181,7 +181,7 @@ class t15 extends InlineJavaPerlCaller {
 	}
 
 
-	public t15() {
+	public t15() throws InlineJavaException {
 	}
 
 	public int add(int a, int b){
diff --git a/t/swing_callback.pl b/t/swing_callback.pl
index 7ae68f8..fbec625 100644
--- a/t/swing_callback.pl
+++ b/t/swing_callback.pl
@@ -4,14 +4,28 @@ use warnings;
 
 use Inline Java => "DATA";
 
+my $cnt = 0 ;
 my $greeter = MyButton->new();
-while (1) { sleep(100000) };
+eval {
+	$greeter->StartCallbackLoop() ;
+	print "done\n" ;
+} ;
+if ($@){
+	$@->printStackTrace() ;
+}
+
 
 ###########################################
 
-sub button_pressed
-{
-  print "Button Pressed (from perl)\n"
+
+sub button_pressed {
+  my $o = shift ;
+  my $id = shift ;
+  print "Button $id Pressed (from perl)\n" ;
+  if ($cnt >= 10){
+	 $o->StopCallbackLoop() ;
+  }
+  $cnt++ ;
 }
 
 __DATA__
@@ -47,9 +61,11 @@ public class MyButton extends    InlineJavaPerlCaller
   {
     try
     {
-      CallPerl("main", "button_pressed", new Object [] {});
+      CallPerl("main", "button_pressed", new Object [] {this,  new Integer(1)});
+      CallPerl("main", "button_pressed", new Object [] {this,  new Integer(2)});
+      CallPerl("main", "button_pressed", new Object [] {this,  new Integer(3)});
     }
     catch (InlineJavaPerlException pe)  { }
-    catch (InlineJavaException pe) { }
+    catch (InlineJavaException pe) { pe.printStackTrace() ;}
   }
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libinline-java-perl.git



More information about the Pkg-perl-cvs-commits mailing list