"Played" around all the weekend, trying to create a test case which
would cause an exception in the context of employing multithreading
heavily, without BSF4Rexx and Java.

Finally, after quite some time, I was "lucky" to get the following call
trace:

    >   rexx.dll!RexxBehaviour::isPrimitive()  Line 101 + 0xa bytes     C++
        rexx.dll!RexxInternalObject::isBaseClass()  Line 175    C++
        rexx.dll!RexxObject::requestString()  Line 1132 + 0x8 bytes     C++
        rexx.dll!REQUEST_STRING(RexxObject * object=0x7f0f28e0)  Line 277 + 
0x24 bytes  C++
        rexx.dll!ObjectToStringValue(RexxThreadContext_ * c=0x7eeed024, 
_RexxObjectPtr * o=0x7f0f28e0)  Line 971 + 0x8 bytes    C++
        
TestThreadedExecution.exe!RexxThreadContext_::ObjectToStringValue(_RexxObjectPtr
 * o=0x7f0f28e0)  Line 1026     C++
        TestThreadedExecution.exe!MyThreadFunction(void * lpParam=0x0015d5c0)  
Line 261 + 0xc bytes     C++
        kernel32.dll!7c80b729()         
        [Frames below may be incorrect and/or missing, no symbols loaded for 
kernel32.dll]      
        rexx.dll!RexxMemory::holdObject(RexxInternalObject * obj=0x0015d5c0)  
Line 1617 C++
      

Here's the exception:

    The thread 'Win32 Thread' (0x584) has exited with code 0 (0x0).
    Unhandled exception at 0x10017f8a (rexx.dll) in TestThreadedExecution.exe: 
0xC0000005: Access violation reading location 0x000000d2.
      

It was necessary to more or less come up with the same architecture as
with BSF4Rexx, before I hit this (but had to run the program a couple of
times):

    * a C-program that creates a Rexx interpreter instance (using it to
      create an array object that will be passed on to add the
      tid-value) and spins off 59 threads, in which each one creates
      another Rexx interpreter instance which is then used to run a Rexx
      program that spins off 29 Rexx threads; in the Rexx programs an
      external routine is called to return the TID to them.
    * main() sets up the parameters, one Rexx interpreter instance and
      calls CreateAndRunThreads(...), which controls the creation of
      threads; each thread executes the code in MyThreadFunction( ).

Using the debug version of the 4.0.0 release; the exe and dll is created
with debug information as well, such that each accounts for over 400KB,
hence uploading the binaries to Sourceforge is not possible, judging
from the last such attempts.

Also, please note, that the exception does not occur reliably, so one
may have to re-run the program a couple of times before it may bomb.
(Also, I did change the  parameters at the beginning of main() a couple
of times, recompiled, re-ran the exe a couple of times.)

Please advise where I should upload the archive to (compiled,
sourcecode, Makefile and def-file), which is about 290KB.

Regards,

---rony



Rony G. Flatscher wrote:
> One more observation: changing the Java code for the Java threads to
> not use the same Rexx interpreter instance (RII) as the previously
> posted example, but rather create their own RII that then is used to
> run the submitted Rexx program (which then will spin off Rexx
> threads), then I get reliably exceptions (all Java threads got created
> at that point, but no Rexx script has generated any debug output yet),
> with a stack trace that goes into rexx.
>
> Unfortunately, because of the beginning winter semester, I have barely
> time to analyze this further, as my planner is now full with
> University meetings and preparation for classes and the like. So
> further information from my side may take a couple of days. [The
> *totally unsubstantiated* "gut feeling" - from weeks of looking at all
> sort of debug outputs - would be at the moment, that something goes
> wrong in the AttachThread() or DetachThread() in a heavily
> multithreaded run-set. Once I debug this new test case, which looks
> promising just because it reliably fails, I would know more. One test
> case I plan to create on the weekend is to write a small C++ program
> that creates 23 threads in which individual RIIs get created, which
> are then used from the threads to run an adapted Rexx proram, that
> spins off 27 Rexx threads. With a little "luck" that may exhibit the
> same behaviour, although the context switches between the Java and
> Rexx environments would not take place in this case.]
>
> Just posted this for the record, as it may be the case that someone
> has additional ideas about what I should be looking into while working
> on this this coming weekend.
>
> ---rony
>
>
> Rony G. Flatscher wrote:
>> Short of an example that would reliably produce an exception in the
>> heavy multithreading scenario, maybe this descritpion of what happens
>> in BSF4Rexx may be helpful:
>>
>> In the context of the testUnits a Rexx program will create an
>> instance of the Java class TestNestedEngines, supplying it the
>> parameters (see below) and RexxProxy objects to follow/interact with.
>> Below is the Java program, followed by the Rexx program that gets
>> invoked. Finally, a brief description of how the Rexx APIs get used.
>>
>>     * the following Java program from the BSF4Rexx test unit gets
>>       invoked from a Rexx script, supplying as arguments the current
>>       BSFManager object which manages one Rexx interpreter instance
>>       (RII), a RexxProxy that allows to interact with the testUnit
>>       (allowing sending it assert messages), the nrJavaThreads and
>>       the nrRexxThreads per Java thread, and a RexxProxy for an
>>       ooRexx array, which will get the different thread's thread IDs
>>       added (the items in this array will indicate how many threads
>>       got invoked):
>>       // rgf, 2009-09-10: test execution of Rexx scripts by concurrently 
>> creating Rexx scripts
>>
>>       package rgf.F_multiThreading;
>>
>>       import org.rexxla.bsf.engines.rexx.RexxProxy;
>>
>>       import org.apache.bsf.*;    // BSF support
>>       import java.io.IOException; // exception handling
>>
>>       import java.io.File;
>>       import java.io.FileReader;
>>       import java.util.Vector;
>>
>>       /** Test Java program which demonstrates how easy it is to invoke Rexx 
>> via BSF.
>>        * @author   Rony G. Flatscher, 2001-04-27, 2007-09-10, 2009-09-11
>>        */
>>       public class TestNestedEngines {
>>           static BSFManager  bm=null;             // BSFManager of the Rexx 
>> instance that invoked this Java program
>>           static RexxProxy   testUnit=null;       // to allow assertions
>>           static int         nrJavaThreads=0;     // determine number of 
>> Java threads
>>           static int         nrRexxThreads=0;     // determine number of 
>> Rexx threads
>>           static String      rexxCode=null;       // Rexx code to run
>>           static RexxProxy   rpArray=null;        // RexxProxy to allow 
>> storing TID in Rexx array object
>>
>>
>>           public TestNestedEngines(BSFManager bm, RexxProxy testUnit, int 
>> nrJavaThreads, int nrRexxThreads, String rexxCode, RexxProxy rpArray)
>>           {
>>                   // save arguments in attributes
>>               TestNestedEngines.bm            =bm;
>>               TestNestedEngines.testUnit      =testUnit;
>>               TestNestedEngines.nrJavaThreads =nrJavaThreads;
>>               TestNestedEngines.nrRexxThreads =nrRexxThreads;
>>               TestNestedEngines.rexxCode      =rexxCode;
>>               TestNestedEngines.rpArray       =rpArray;
>>           }
>>
>>
>>         /** Creates number of desired threads, runs them. */
>>         public void dispatchRexxScripts() throws Exception
>>         {
>>
>>             String      tmpResult="";
>>             Throwable   tmpTh=null;
>>             String      tmpthreadName=null;
>>
>>               // create arrays of needed size
>>             Thread               t[]=new Thread[nrJavaThreads];
>>             ThreadedJNIRexxStart r[]=new ThreadedJNIRexxStart[nrJavaThreads];
>>
>>             for (int i=0;i<nrJavaThreads; i++)
>>             {
>>                 r[i]=new ThreadedJNIRexxStart();
>>                 t[i]=new Thread(r[i]);             // create thread
>>                 r[i].setThreadName(t[i].getName());
>>                 t[i].start();               // start execution on own thread
>>             }
>>             // all got started
>>
>>             for (int i=0;i<nrJavaThreads; i++)        // join all threads
>>             {
>>                 t[i].join();
>>             }
>>             // all are finished
>>
>>         }
>>
>>
>>               // Runnable inner class
>>           static private class ThreadedJNIRexxStart implements Runnable
>>           {
>>                   // define thread local variables
>>               private static ThreadLocal tlThrowable = new ThreadLocal();
>>               private static ThreadLocal tlResult    = new ThreadLocal();
>>               private static ThreadLocal tlThreadName= new ThreadLocal();
>>
>>
>>               public void run ()  // invoke ooRexx on its own Java thread
>>               {
>>                   try {
>>                       String threadName=Thread.currentThread().getName();
>>
>>                       rpArray.invoke("APPEND", new Object [] {threadName} ); 
>>  // save this thread name in supplied RexxProxy array
>>
>>                       // define arguments for Rexx script
>>                       Vector args = new Vector(4);
>>                       args.add(testUnit);
>>                       args.add(rpArray);
>>                       args.add(new Integer(nrRexxThreads));
>>                       args.add(threadName);
>>
>>                       // load the Rexx engine for this BSFManager instance
>>                       BSFEngine  rexx = bm.loadScriptingEngine("rexx");
>>
>>                       // execute the Rexx script
>>                       Object result= rexx.apply ("rexx", 0, 0,
>>                                                   
>> rexxCode.replaceAll("@threadName", (""+threadName)),
>>                                                   null,
>>                                                   args);
>>
>>                       tlResult.set(result);   // save result
>>                   }
>>                   catch (Throwable th) {
>>                       tlThrowable.set(th);   // save Throwable
>>                       System.err.println("TestNestedEngines: 
>> threadName=["+tlThreadName.get()+"], Throwable=["+th+"]");
>>                       th.printStackTrace();
>>                   }
>>               }
>>
>>               public Object getResult() {         // getter
>>                   return tlResult.get();
>>               }
>>
>>               public Throwable getThrowable() {   // getter
>>                   return (Throwable) tlThrowable.get();
>>               }
>>
>>               public String getThreadName() {     // getter
>>                   return (String) tlThreadName.get();
>>               }
>>
>>               public void setThreadName(String threadName) {   // setter
>>                   tlThreadName.set(threadName);
>>               }
>>           }
>>       }
>>           
>>     * this is the Rexx program, that the Java program executes: it
>>       gets the proxied Rexx object for doing direct assertions, but
>>       leaves the rpArray RexxProxy object and addresses it as a Java
>>       object (the Java side will then forward whatever message and
>>       arguments directly to the proxied Rexx object); an instance of
>>       .counter is used to count the active Rexx threads (each thread
>>       will decrease the counter before returning, such that the
>>       counter drops to 0, if all threads ended; here and then one
>>       thread may still be pending after three seconds); the main
>>       ooRexx program, which runs in the same thread as the Java
>>       thread that started it, supplies its TID to the message "work"
>>       which it sends to each instance of .ThreadClz. The "work"
>>       method does a reply, in the remaining code the supplied TID
>>       will be used to attach the Rexx thread to Java using TID's
>>       global referenced Java object, but attaching using Java's
>>       AttachCurrentThread, creating (and caching) a valid JNIEnv
>>       which then is used to interface with Java:
>>       use arg rpTestUnit, rpArray, nrThreads, javaThreadName
>>
>>           tid=bsfGetTID()              -- get this TID
>>           testUnit=BsfRexxProxy(rpTestUnit, "ooRexxObject") -- get ooRexx 
>> object that gets proxied
>>
>>                 -- save this thread's TID
>>           argArray=bsf.createJavaArrayOf("java.lang.Object", tid)
>>           rpArray~invoke("APPEND", argArray)
>>
>>           rexxArray=.array~new         -- create a new rexxArray for this 
>> controller's threads
>>
>>           counter=.counter~new         -- create a counter object
>>
>>           do i=1 to nrThreads
>>              counter~increase                   -- increase the counter
>>                 -- thread will decrease counter before returning
>>              .ThreadClz_using_RexxProxy_Array~new~work(testUnit, tid, i, 
>> counter, rpArray, rexxArray, javaThreadName)
>>           end
>>
>>           call time "Reset"            -- reset timer
>>           loop while counter~value>0, time("elapsed")<3  -- until no more 
>> threads, or over 10seconds
>>              call sysSleep .001              -- yield
>>           end
>>
>>           testUnit~assertEquals(0, counter~value, "active thread counter in 
>> Java thread:" javaThreadName)
>>
>>             -- this controller created 'nrThreads' threads, check it
>>           testUnit~assertEquals(nrThreads, rexxArray~items, "total number of 
>> threads:" javaThreadName)
>>
>>
>>       ::requires BSF.CLS
>>
>>
>>       /* 
>> ====================================================================================
>>  */
>>       -- implement a counter that one can increase/decrease
>>       ::class counter
>>       ::method init           -- constructor
>>         expose value
>>         value=0               -- set attribute
>>         forward to (super)    -- let superclass initialize
>>
>>       ::attribute value       -- allow interfacing with the attribute
>>
>>       ::method increase       -- increase value by 1
>>         expose value
>>         value+=1
>>         return value
>>
>>       ::method decrease       -- decrease value by 1
>>         expose value
>>         value-=1
>>         return value
>>
>>
>>
>>       /* 
>> ====================================================================================
>>  */
>>       -- implement a class with a threaded worker method
>>       ::class "ThreadClz_using_RexxProxy_Array"
>>       ::method work
>>         use arg testUnit, TID, nr, counter, rpArray, rexxArray, 
>> javaThreadName
>>         reply                 -- return & create a new thread
>>
>>         thisTID=BsfGetTID()
>>         testUnit~assertTrue(BsfAttachToTID(TID), "attaching to main TID:" 
>> TID", thread #" nr", thisTID="thisTID "running in Java thread named:" 
>> javaThreadName)
>>
>>          -- have the RexxProxy send the following message to its proxied 
>> Rexx object
>>         argArray=bsf.createJavaArrayOf("java.lang.Object", thisTID)
>>         rpArray~invoke("APPEND", argArray) -- save thisTID
>>         rexxArray~append(thisTID)
>>
>>         testUnit~assertTrue(BsfDetach(), "detaching from main TID:" TID", 
>> thread #" nr", thisTID="thisTID "running in Java thread named:" 
>> javaThreadName)
>>         counter~decrease
>>         return
>>           
>>
>>
>> The Java program above will use the passed BSFManager object to get a
>> reference to its RexxEngine instance which represents a unique Rexx
>> interpreter instance (RII). This RII is then used via JNI to dispatch
>> Rexx scripts or to send messages to Rexx objects. In the case where a
>> Rexx script gets dispatched the following happens:
>>
>>     * for each created Java thread rexx.apply() will use JNI to run
>>       the supplied Rexx program by
>>           o defining: rtc->NewRoutine()
>>           o running it: rtc->CallRoutine()
>>     * the invoked Rexx program will interact with an ooRexx object
>>       directly, with a RexxProxy() via Java, i.e.
>>           o the RexxProxy Java method "invoke" is invoked supplying a
>>             Java array with arguments,
>>           o the Java side will excercise the JNI function that allows
>>             sending a Rexx object a message:
>>                 + the native side will do an AttachThread() using the
>>                   RII,
>>                 + the Rexx object is retrieved from the RexxProxy cache,
>>                 + the received Java aguments are unmarshalled,
>>                 + the ooRexx object gets the message sent (with the
>>                   arguments, if any),
>>                 + upon return a DetachThread() is executed, the
>>                   return value marshalled for Java
>>           o the received return value will then returned to the Rexx
>>             side where at the JNI-level it gets unmarshalled and
>>             returned.
>>
>> If there is anything else I could supply at the moment, please let me
>> know.
>>
>> ---rony

------------------------------------------------------------------------------
Come build with us! The BlackBerry&reg; Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9&#45;12, 2009. Register now&#33;
http://p.sf.net/sfu/devconf
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to