(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