(This is using Microsoft Windows [Version 10.0.19045.3570], Open Object Rexx Version 5.1.0 r12722 - Internal Test Version, Java openjdk version "17.0.6" 2023-01-17 LTS). But can be observed also on other Java versions, older or newer.)

This has been a phenomenon for quite some time: sometimes (not always) there is a hang in ooRexx in the following use case:

 * a Rexx script will use a /command/ (e.g. "rexxj.cmd testRunScript.rxj") to 
start a Java program
   that will load Rexx to execute some Rexx script (SRS_1),

     o Java will load the Rexx interpreter and keep a reference to the primodal 
RexxInterpreter
       instance (RII) which will get the number 1 assigned to its name ("RE_1", 
the Java side names
       each RII and uses a counter to keep them distinguishable by name)

     o Java will create another RexxInterpreter instance ("RE_2") which gets 
used to run the Rexx
       script SRS_1, upon execution of this script RE_2 gets terminated via JNI,

         + while SRS_1 executes another RexxInterpreter instance ("RI_3") gets 
created by Java
           (implicitly done by using the Java scripting framework javax.script 
to run another
           Rexx_script) to run another Rexx script (SRS_2) on RI_3, upon return 
RI_3 gets
           terminated which will cause the Java garbage collector to be invoked 
(using System.gc()
           followed by .runFinalization() to get as many Java RexxProxies freed 
to allow the
           proxied Rexx object's uninit methods to run) which will also free 
Java RexxProxy objects
           causing proxied Rexx objects to be freed, causing implicitly to run 
the Rexx uninit
           methods of those, as the RexxInterpreter instance will be terminated 
(and ooRexx will
           run the garbage collector at that point in time)

         + upon return of SRS_1 sometimes a hang may occur (and many times the 
Rexx garbage
           collector seems to run in parallel as an immediate ctl-c when the 
hang can be observed
           causes sometimes errors in the appropriate Rexx uninit method

If the hang occurs, then it occurs interestingly in SystemsCommands.cpp at line # 521 in the statement "/if (WAIT_FAILED != WaitForSingleObject ( piProcInfo.hProcess, INFINITE ) )/" which is highlighted bold and blue in the following snippet:

   SystemCommands.cpp

   line # 521
   code:

            ... cut ...
        SystemInterpreter::exceptionHostProcess = piProcInfo.hProcess;
            SystemInterpreter::exceptionHostProcessId = piProcInfo.dwProcessId;

           *if (WAIT_FAILED != WaitForSingleObject ( piProcInfo.hProcess, 
INFINITE ) )*
            {
                // Completed ok, get termination rc
                GetExitCodeProcess(piProcInfo.hProcess, &rc);
                // do we have input cleanup to perform?
                if (redirIn)
                {
                    // the process has returned, but the input thread may be 
stuck
                    // on a write for data that was never used. We need to 
close the
                    // pipe to force it to complete
                    inputThread.shutdown();
                    // close the process end of the pipe
                    CloseHandle(siStartInfo.hStdInput);
                    // wait for everything to complete
                    inputThread.waitForTermination();
                    // the INPUT thread may have encountered an error .. raise 
it now
                    if (inputThread.error != 0)
                    {
                        ErrorRedirection(context, inputThread.error);
                        return false;
                    }
                }

                // did we start an ERROR thread?
                if (redirOut)
                {
                    CloseHandle(siStartInfo.hStdOutput);  // close the handle 
so readFile will stop
                    // wait for the ERROR thread to finish
                    outputThread.waitForTermination();
                    if (outputThread.dataLength > 0)
                    {   // return what the ERROR thread read from its pipe
                        ioContext->WriteOutputBuffer(outputThread.pipeBuffer, 
outputThread.dataLength);
                    }
                    // the OUTPUT thread may have encountered an error .. raise 
it now
                    if (outputThread.error != 0)
                    {
                        ErrorRedirection(context, outputThread.error);
                        return false;
                    }
                }

                // did we start an ERROR thread?
                if (redirErr)
                {
                    CloseHandle(siStartInfo.hStdError);  // close the handle so 
readFile will stop
                    // wait for the ERROR thread to finish
                    errorThread.waitForTermination();
                    if (errorThread.dataLength > 0)
                    {   // return what the ERROR thread read from its pipe
                        ioContext->WriteErrorBuffer(errorThread.pipeBuffer, 
errorThread.dataLength);
                    }
                    // the ERROR thread may have encountered an error .. raise 
it now
                    if (errorThread.error != 0)
                    {
                        ErrorRedirection(context, errorThread.error);
                        return false;
                    }
                }
            }
            else
            {
                rc = GetLastError();    // Bad termination, get error code
                context->RaiseCondition("FAILURE", context->String(command), 
NULLOBJECT, context->WholeNumberToObject(rc));
                result = NULLOBJECT;
                return true;
            }

            // The new process must be detached so it will be discarded
            // automatically after execution.  The thread must be closed first
            if (titleChanged)
            {
                SetConsoleTitle(ctitle);
            }
            CloseHandle(piProcInfo.hThread);
            CloseHandle(piProcInfo.hProcess);
        }
        else
        {
            // return this as a failure for now ... the caller might try this 
again
            // later
            return false;
        }
   ... cut ...

Interestingly, sometimes this hang does not occur.

---

Experimenting with the Java Rexx launcher program to not run explicitly System.gc() followed by System.runFinalization() [from experiments doing so will effectivley allow to clean all Java objects that are not referenced anymore] such that at that point in time Java would not free the Java RexxProxies (potentially causing some to not be referenced anymore, hence becoming eligible for the Rexx garbage collector to be processed) seems to make these hangs go away as if not running the uninits at that point in time would play a role in this observation.

---

Another observation:

In rare cases a crash occurs in ucrtbase.dll!thread_start like this (even if not having gc() and runFinalizations() called):

   Not Flagged  >    30228   0       Worker Thread   
ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void *),1>      
ANSI64.dll!0000000057192732     Normal

Here the call stack:

   > ANSI64.dll!0000000057192732()   Unknown
        ANSI64.dll!00000000571929a0()   Unknown
        ANSI64.dll!0000000057193091()   Unknown
        ucrtbase.dll!try_get_module()   Unknown
        ucrtbase.dll!__acrt_AppPolicyGetThreadInitializationTypeInternal()      
Unknown
        ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void *),1>()    
Unknown
        kernel32.dll!BaseThreadInitThunk()     Unknown
        ntdll.dll!RtlUserThreadStart() Unknown

The above crash may occur independently of whether the Java Rexx launcher program uses gc() and runFinalization() right before terminating the Rexx engine or not. At that time there are no ooRexx related threads anymore, so probably the crash occurs in one of the Java shutdown threads. So wondering whether ooRexx causes thread related side effects in this case as Java is quite bullet-proof in this regard.

---rony

_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to