I would have put the attachThread() inside the constructor, but that works.

Rick

On Sun, Jul 27, 2025 at 8:49 AM Rony G. Flatscher <rony.flatsc...@wu.ac.at>
wrote:

> On 27.07.2025 13:24, Rick McGuire wrote:
>
> If an exception happens, the detachThread() never happens, which would
> leave the interpreter in an inconsistent state. The best fix would be to
> write a small class with a destructor method that will do the detach thread
> when the variable leaves the scope.
>
> Thank you, Rick.
>
> How about:
>
> Index: interpreter/runtime/Interpreter.cpp
> ===================================================================
> --- interpreter/runtime/Interpreter.cpp       (revision 12998)
> +++ interpreter/runtime/Interpreter.cpp       (working copy)
> @@ -235,7 +235,10 @@
>          // to shut down so that the package manager can unload
>          // the libraries (it needs to pass a RexxThreadContext
>          // pointer out to package unloaders, if they are defined)
> -        InstanceBlock instance;
> +        InstanceBlock tmpInstance;
> +        tmpInstance.instance->InterpreterInstance::attachThread();
> +        InstanceDetacher instDet = InstanceDetacher(tmpInstance.instance);
> +
>          // run whatever uninits we can before we start releasing the 
> libraries
>          memoryObject.lastChanceUninit();
>
> @@ -487,6 +490,28 @@
>
>
>  /**
> + * Make sure that detachThread() gets carried out for the supplied 
> InterpreterInstance.
> + *
> + * @param i InterpreterInstance
> + */
> +InstanceDetacher::InstanceDetacher(InterpreterInstance *i)
> +{
> +    // Get an instance.
> +    instance = i;
> +}
> +
> +/**
> + * Carry out detachThread() for the instance, if going out of scope.
> + */
> +InstanceDetacher::~InstanceDetacher()
> +{
> +    // detach from the instance
> +    instance->InterpreterInstance::detachThread();
> +}
> +
> +
> +
> +/**
>   * Decode a condition directory into a easier to use
>   * structure form for a native code user.  This breaks
>   * the directory into its component pieces, including
> Index: interpreter/runtime/Interpreter.hpp
> ===================================================================
> --- interpreter/runtime/Interpreter.hpp       (revision 12998)
> +++ interpreter/runtime/Interpreter.hpp       (working copy)
> @@ -248,4 +248,14 @@
>  };
>
>
> +class InstanceDetacher
> +{
> +public:
> +    InstanceDetacher(InterpreterInstance *i);
> +    ~InstanceDetacher();
> +
> +    InterpreterInstance  *instance;    // interpreter instance
> +};
> +
> +
>  #endif
>
>
> Any comments, suggestions?
>
> ---rony
>
>
>
>
> On Sun, Jul 27, 2025 at 6:51 AM Rony G. Flatscher <rony.flatsc...@wu.ac.at>
> wrote:
>
>> It seems that the following patch fixes the reported crash:
>>
>> Index: interpreter/runtime/Interpreter.cpp
>> ===================================================================
>> --- interpreter/runtime/Interpreter.cpp (revision 12998)
>> +++ interpreter/runtime/Interpreter.cpp (working copy)
>> @@ -235,11 +235,15 @@
>>          // to shut down so that the package manager can unload
>>          // the libraries (it needs to pass a RexxThreadContext
>>          // pointer out to package unloaders, if they are defined)
>> -        InstanceBlock instance;
>> +        InstanceBlock tmpInstance;
>> +        tmpInstance.instance->InterpreterInstance::attachThread();
>> +
>>          // run whatever uninits we can before we start releasing the 
>> libraries
>>          memoryObject.lastChanceUninit();
>>
>>          PackageManager::unload();
>> +
>> +        tmpInstance.instance->InterpreterInstance::detachThread();
>>      }
>>      catch (ActivityException)
>>      {
>>
>> Any comments, suggestions?
>>
>> ---rony
>>
>>
>> On 23.12.2023 18:03, Rony G. Flatscher wrote:
>>
>> Since last August a crash got reported in
>> <https://sourceforge.net/p/oorexx/bugs/1872/>
>> <https://sourceforge.net/p/oorexx/bugs/1872/> which can be easily
>> reproduced by following the directions there. Using the supplied simple
>> C++-only program will work flawlessly if invoked simply as
>>
>> testTerminate.exe
>>
>> it will run flawlessly using 250 Rexx interpreter instances to execute a
>> simple script (issuing a single dot on stdout) and then terminate it on the
>> same thread.
>>
>> However if supplying an argument to that test program (source got
>> uploaded with #1872 as well), then the termination of the Rexx interpreter
>> instance occurs on a separate thread and will cause the crash upon
>> terminating the second Rexx interpreter instance on a separate thread:
>>
>> testTerminate.exe 
>> anyArgumentSufficesToRunTheRIIOnSeparateThreadAndCauseTheCrash
>>
>> The relevant Windows code is:
>>
>> ... cut ...
>> // from 
>> <https://stackoverflow.com/questions/1981459/using-threads-in-c-on-windows-simple-example>
>>  
>> <https://stackoverflow.com/questions/1981459/using-threads-in-c-on-windows-simple-example>,
>> // also 
>> <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread>
>>  
>> <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread>
>> // #include <windows.h>
>>
>> DWORD WINAPI ThreadFunc(void* data) {
>>   // Do stuff.  This will be the first function called on the new thread.
>>   // When this function returns, the thread goes away.  See MSDN for more 
>> details.
>>
>>     RexxInstance *instance = (RexxInstance *) data;
>>     // uncommenting the following statement, makes it run
>>     *// fprintf(stderr, "ThreadFunc(), arrived: terminating instance 
>> [%p]\n", instance);fflush(stderr);
>> *
>>     // Now wait for the interpreter to terminate and we are done.
>>     instance->Terminate();
>>
>>     // fprintf(stderr, "ThreadFunc(), leaving: terminating instance [%p]\n", 
>> instance);fflush(stderr);
>>
>>   return 0;
>>
>> ... cut ...
>>
>>         if (argc>1) // if argument given terminate on separate thread
>>         {
>>             void *data = interpreter;
>>             HANDLE thread = CreateThread(NULL, 0, ThreadFunc, data, 0, NULL);
>>             if (thread)
>>             {
>>                 fprintf(stderr, "Created [%d], thread [%p] for terminating 
>> instance [%p]\n", i, thread, interpreter);fflush(stderr);
>>             }
>>
>>         }
>>         else        // terminate on main thread
>>         {
>>             // Now wait for the interpreter to terminate and we are done.
>>             interpreter->Terminate();
>>         }
>>
>> ... cut ...
>>
>> Uncommenting the blue fprintf statement makes the crash go away *most* of
>> the time such that all 250 Rexx interpreter instances can be terminated on
>> a separate thread. Reducing that to just fflush(stderr) makes it go away
>> *most* of the time as well (whereas using fflush(stdout) instead does not
>> have any effect. So accessing stderr in that thread somehow influences the
>> behaviour).
>> ---
>>
>> Originally this crash occurred in the context of BSF4ooRexx and I
>> reported it in <https://sourceforge.net/p/oorexx/feature-requests/806/>
>> <https://sourceforge.net/p/oorexx/feature-requests/806/>. It seems that
>> Rick thought it had to do with the code in BSF4ooRexx and not with ooRexx.
>> Eventually this thread led to a new, small C++ (supplied with #1872 above)
>> only (only creates a RII, runs a simple Rexx script, terminates the RII)
>> showcase in which no external dependency could be made responsible for the
>> crash, such that it becomes clear that the cause lies in ooRexx itself.
>>
>> As the crash occurs rather early, if using "testTerminate.exe someArg" I
>> had hoped that some of the C++ gurus would be able to locate (and hopfeully
>> fix) the cause relatively quickly (realizing that multithreaded bugs can be
>> extremely hard to trace down and to fix). Unfortunately, this has not
>> happened to this day (after almost 16 months). As this is a showstopper and
>> inhibits using this great ooRexx feature, namely being able to create any
>> number of different Rexx interpreter instances (each having its own .local)
>> in a process and terminate them.
>>
>> Therefore I kindly request any of the C++ experts to look into this
>> matter if possible. Maybe the upcoming vacation time allows for a few time
>> slots to use for analyzing, finding and hopefully fixing the cause of this
>> showstopper crash!
>>
>> ---rony
>>
>> P.S.: Have simplified the test code a little bit, also allowing the test
>> program to run with all three reported scenarios; it is enclosed as (also
>> slightly stripped down) "testTerminate2.cpp" and "Makefile2.windows"
>> ("nmake /f Makefil2.windows" will create testTerminate2.exe) which after
>> successful compilation can be invoked as:
>>
>>    - testTerminate2.exe
>>
>>    - no arguments: will create and terminate all 250 Rexx interpreter
>>       instances (RII) on the same (main) thread without any crash
>>
>>       - testTerminate2.exe oneArg
>>
>>    - any single argument will cause the crash to always occur while
>>       terminating the *second* RII on a separate thread (as if terminating 
>> the
>>       previous RII on a separate thread left something in an unbalanced 
>> state)
>>
>>       - testTerminate2.exe oneArg secondArg
>>
>>    - any two arguments will cause fflush(stderr) in the terminating
>>       thread to be issued and as a result most of the time all 250 Rexx
>>       interpreter instances can be terminated on a separate thread without a
>>       crash; running it a couple of times may however cause that crash to 
>> occur
>>       at different RIIs
>>
>> Terminate() will kick off the garbage collector and the crash seems to
>> occur during its run.
>>
>> P.P.S.: Would it be possible to have the termination of a RII carried out
>> on the same thread as its creation (which seems to run stably) by ooRexx
>> itself (e.g. having a specific thread to create and to terminate RIIs)?
>>
>> This may need a function to learn about whether a RII is currently
>> running/blocked and only terminate it on the creation thread if not in use
>> so not to block the creation thread. Maybe also (an asynchroneous?) a
>> function to force termination of a RII would be helpful in such a scenario,
>> maybe with an option that indicates whether running/blocking Rexx code on
>> that RII should be forcefully halted or not.
>>
>>
>> _______________________________________________
> Oorexx-devel mailing list
> Oorexx-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/oorexx-devel
>
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to