[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