Index: interpreter/RexxClasses/CoreClasses.orx
===================================================================
--- interpreter/RexxClasses/CoreClasses.orx	(revision 12786)
+++ interpreter/RexxClasses/CoreClasses.orx	(working copy)
@@ -3979,3 +3979,164 @@
      s=result           -- fetch & save the returned instance
   end
   return s              -- return singleton instance
+
+
+/** This class maintains trace information meant to support debugging and analyzing
+*   execution traces. The makeString method will return a string that will be formatted
+*   according to the current setting of the OPTION class attribute. If the COLLECTOR
+*   class attribute is not .nil then the traceObject will be appended to it.
+*
+*/
+::class "TraceObject" subclass StringTable public
+
+---------------------- class level ----------------------
+::method    activate    class
+  expose option collector counter
+  self~activate:super
+  option   ='N'         -- normal (makeString returns the TRACELINE entry)
+  collector=.nil        -- no appending to the collector will take place
+  counter  =0           -- value will be used to number the TraceObject instances
+
+::method    new         class    -- a new instance gets requested
+  expose option collector counter
+  dt = .dateTime~new    -- take the current date and time
+  forward class (super) continue -- let the superclass do the job
+  newObj = result       -- fetch freshly created object
+  newObj["TIMESTAMP"]=dt
+  newObj["OPTION"]   =option
+  counter += 1
+  newObj["NR"]       =counter
+  if \collector~isNil then -- collector exists, append traceObject
+     collector~append(newObj)
+  return newObj         -- return the new object
+
+::attribute collector   class       -- .nil or an object that does understand APPEND(object)
+
+::attribute counter     get class   -- we only allow get access
+
+::attribute option      set class
+  expose option
+  parse upper arg o +1  -- extract first letter
+  pos=pos(o,"NTSFP")    -- option letter in hand? (Normal, Thread, Standard, Full, Profiling)
+  if pos>0 then         -- valid option, use it
+     option=o
+  else                  -- unknown option, raise condition
+     raise syntax 93.914 array (1, '"N" (normal), "T" (thread), "S" (standard), "F" (full) or "P" (profiling)', arg(1))
+
+::attribute option      get class
+
+::method setMakeString  class -- allow replacing the predefined makeStringImpl method
+  use strict arg newMethod
+  self~setMethod("makeStringImpl",newMethod) -- replace the makeStringImpl method with the new one
+
+::method unsetMakeString  class  -- allow replacing the predefined makeStringImpl method
+  use strict arg
+  self~unsetMethod("makeStringImpl")   -- remove any set makeStringImpl method
+
+
+/** Create the traceline string, if option:
+*     'N' ... just return the traceline (default)
+
+*     'T' ... inserts the thread in the trace prefix after the second character ... thread
+
+*     'S' ... return prefix [T1   I1  ]          ... thread, invocation
+                          for a method statement:
+*                           [T1   I1   G L1   *] ... thread, invocation, guarded/unguarded, lockcount, hasObjectLock
+*     'F' ... return prefix [R1   T1   I1   ]... interpreter, thread, invocation
+                          for a method statement:
+*                           [R1   T1   I1   G A1   L1   *] ... interpreter, thread, invocation, guarded/unguarded, attribute pool, lockcount, hasObjectLock
+*     'P' ... will cause ooRexx to not forward the traceObject (this option is meant for profiling);
+              if set while makeString gets invoked via a Rexx program, then makeString will
+              format the traceline with the option in effect of creating the TraceObject (if still
+              'P', then use 'N' formating)
+*/
+::method makeStringImpl class    -- the formatting method
+  expose option
+  use strict arg traceObj
+
+  tmpOption=option         -- get current option
+
+  if tmpOption='P' then    -- currently profiling/probing, use original option if not 'P'
+  do
+     oriOption=str(traceObj["OPTION"])     -- get original option, if also 'P', then use 'N' formatting
+     if oriOption='?' then -- OPTION entry does not exist, resort to 'N' formatting
+        tmpOption='N'      -- if no option available, format as normal
+     else      -- if original option is P as well then format as normal, otherwise as original option
+        tmpOption=(oriOption='P')~?('N',oriOption)
+  end
+
+  if tmpOption='N' then return str(traceObj["TRACELINE"])
+
+  if tmpOption='T' then
+  do
+     parse value traceObj~traceline with line 7 prefix rest
+     return line prefix~insert(traceObj["THREAD"],2) rest
+  end
+
+  mb = .MutableBuffer~new  -- for performance reasons
+  mb~append("[")
+  if tmpOption='F' then    -- full information
+     mb~append("R", adjLeft(str(traceObj["INTERPRETER"]),3), " ")  -- R_exx interpreter instance
+
+  mb~append("T", adjLeft(str(traceObj["THREAD"])    ,3), " ")  -- T_hread/activity
+  mb~append("I", adjLeft(str(traceObj["INVOCATION"]),4)     )  -- I_nvocation/activation
+  ap=traceObj["ATTRIBUTEPOOL"]
+  if \ap~isNil then        -- an object's variable dictionary in hand, we are in a method
+  do
+     mb~append(" ")
+     isTrue=str(traceObj["ISGUARDED"])
+     if isTrue='?' then
+        mb~append(isTrue)                    -- ? (if not set), else G_uarded or U_unguarded
+     else
+        mb~append(isTrue~?("G","U"), " ")    -- G_uarded or U_unguarded
+
+     if tmpOption='F' then    -- full information
+         mb~append("A", adjLeft(ap,4), " ")  -- Attribute pool (variable dictionary)
+
+     mb~append("L", adjLeft(str(traceObj["OBJECTLOCKCOUNT"]),3), " ")   -- L ... lock reserve count
+     isTrue=str(traceObj["HASOBJECTLOCK"])
+     if isTrue='?' then
+        mb~append(isTrue)              -- indicates that value is not present
+     else
+        mb~append(isTrue~?("*"," "))   -- asterisk to indicate holding object lock (can execute)
+     mb~append("] ")
+  end
+  else   -- no object related information in this traceObject
+  do
+     if tmpOption='S' then
+        mb~append("]          ")     -- Standard: make sure we align traceline
+     else
+        mb~append("]                ")  -- Full: make sure we align traceline
+  end
+
+  mb~append(str(traceObj["TRACELINE"]))
+  return mb~string   -- return trace line with mtPrefix
+
+
+adjLeft: procedure   -- left adjust, but make sure we show all chars
+  use arg value, width
+  if value~length>=width then -- no left adjustment
+     return value
+  return value~left(width)    -- left adjust with given width
+
+str: procedure       -- make sure we supply a string if .nil, otherwise MutableBuffer causes an error
+  use arg value
+  if value~isNil then return '?' -- no entry, Rexx user omitted or deleted it
+  return value
+
+
+---------------------- instance level -------------------
+
+::method compareTo   -- allow sorting, by default by NR which represents the creation sequence
+  use arg other
+  return sign(nz(self["NR"],-1) - nz(other["NR"],-1)) -- cf. rexxref.pdf, ComparableClass' compareTo definition
+
+nz: procedure  -- in case a Rexx user removed the NR entry, make sure the subtraction can take place
+  use arg val,ifNilValue=0
+  if val~isNil then return ifNilValue
+  return val
+
+::method makeString  -- returns the traceline string
+  return self~class~makeStringImpl(self)  -- let the class method makeStringImpl do the work
+
+
Index: interpreter/concurrency/Activity.cpp
===================================================================
--- interpreter/concurrency/Activity.cpp	(revision 12786)
+++ interpreter/concurrency/Activity.cpp	(working copy)
@@ -78,8 +78,12 @@
 #include "MutexSemaphore.hpp"
 #include "IdentityTableClass.hpp"
 
+#include "StringTableClass.hpp"
+
 #include <stdio.h>
 #include <time.h>
+#include <atomic>
+#include <unordered_map>
 
 
 const size_t ACT_STACK_SIZE = 20;
@@ -98,6 +102,17 @@
 }
 
 
+static std::atomic<uint32_t> counter(0); // to generate idntfr for concurrency trace information
+static std::unordered_map<thread_id_t, uint32_t> threadIDs; // to associate idntfr to system threads
+
+uint32_t Activity::getIdntfr()
+{
+    thread_id_t threadID = currentThread.getThreadID();
+    if (threadIDs.find(threadID) == threadIDs.end()) threadIDs[threadID] = ++counter;
+    return threadIDs[threadID];
+}
+
+
 /**
  * Normal garbage collection live marking
  *
@@ -3059,6 +3074,49 @@
 }
 
 
+
+// ---- begin TraceObject; caching class for performance reasons (if the Rexx user
+//      should be allowed to change the class object after tracing has started, we
+//      need to change the logic to do the findClass() each time)
+inline RexxClass *getRexxPackageTraceObject()    // only do the findClass() once
+{
+    static RexxClass *RexxPackageTraceObject = OREF_NULL;
+    if (RexxPackageTraceObject==OREF_NULL)
+    {
+        RexxObject *t = OREF_NULL;   // required for the findClass call
+        RexxPackageTraceObject = TheRexxPackage->findClass(GlobalNames::TRACEOBJECT, t);
+    }
+    return RexxPackageTraceObject;
+}
+
+
+/** Fill in additional trace information, some concurrency related. */
+StringTable* CreateTraceObject(Activity *activity, RexxActivation *activation, RexxString *traceline)
+{
+    ProtectedObject result;
+    StringTable *traceObject = (StringTable *) getRexxPackageTraceObject()->messageSend(GlobalNames::NEW, OREF_NULL, 0, result);
+    ProtectedObject p(traceObject);
+
+    traceObject -> put(traceline, GlobalNames::TRACELINE );
+    traceObject -> put(new_integer(activity->getInstance()->getIdntfr()), GlobalNames::INTERPRETER );
+    traceObject -> put(new_integer(activity->getIdntfr()), GlobalNames::THREAD );
+
+    traceObject -> put(new_integer(activation ? activation->getIdntfr() : 0), GlobalNames::INVOCATION);
+
+        // get variableDictionary if any
+    VariableDictionary *variableDictionary = (activation ? activation->getVariableDictionary() : NULL);
+    size_t variableDictionaryNr = variableDictionary ? variableDictionary->getIdntfr() : 0;
+    if (variableDictionaryNr > 0)   // if method routine, get further information
+    {
+        traceObject -> put(new_integer(variableDictionaryNr), GlobalNames::ATTRIBUTEPOOL);  // Rexx users relate better if using ATTRIBUTE
+        traceObject -> put(activation->isGuarded() ? TheTrueObject : TheFalseObject, GlobalNames::ISGUARDED );
+        traceObject -> put(new_integer(activation ? activation->getReserveCount() : 0), GlobalNames::OBJECTLOCKCOUNT);
+        traceObject -> put(activation->isObjectScopeLocked() ? TheTrueObject : TheFalseObject, GlobalNames::HASOBJECTLOCK);
+    }
+    return traceObject;
+}
+
+
 /**
  * Write out a line of trace output.
  *
@@ -3068,11 +3126,19 @@
 void  Activity::traceOutput(RexxActivation *activation, RexxString *line)
 {
     // make sure this is a real string value (likely, since we constructed it in the first place)
-    line = line->stringTrace();
+    Protected<RexxString> pline = line->stringTrace();
 
+    Protected<StringTable> traceObject=CreateTraceObject(this, activation, pline);
+
     // if the exit passes on the call, we write this to the .traceouput
-    if (callTraceExit(activation, line))
+    if (callTraceExit(activation, pline))
     {
+        // if in profiling mode we only let collect the traceObjects, but do not issue the tracelin
+        // we do not output the traceLine if currently in profiling mode
+        RexxObject *option = (RexxString *) traceObject->get(GlobalNames::OPTION); // the entry may be missing
+        if (option && ((RexxString *) option)->getStringData()[0] == 'P')
+            return;
+
         RexxObject *stream = getLocalEnvironment(GlobalNames::TRACEOUTPUT);
 
         if (stream != OREF_NULL && stream != TheNilObject)
@@ -3082,17 +3148,18 @@
             try
             {
                 ProtectedObject result;
-                stream->sendMessage(GlobalNames::LINEOUT, line, result);
+
+                stream->sendMessage(GlobalNames::LINEOUT, traceObject, result);
             }
             catch (NativeActivation *)
             {
-                lineOut(line); // don't lose the data!
+                lineOut(traceObject->requestString()); // don't lose the data!
             }
         }
         // could not find the target, but don't lose the data!
         else
         {
-            lineOut(line);
+            lineOut(traceObject->requestString()); // don't lose the data!
         }
     }
 }
Index: interpreter/concurrency/Activity.hpp
===================================================================
--- interpreter/concurrency/Activity.hpp	(revision 12786)
+++ interpreter/concurrency/Activity.hpp	(working copy)
@@ -1,7 +1,7 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
-/* Copyright (c) 2005-2020 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -220,6 +220,7 @@
     void detachInstance();
     void detachThread();
     inline InterpreterInstance *getInstance() { return instance; }
+    uint32_t getIdntfr();
 
     void nestAttach();
     void returnAttach();
Index: interpreter/execution/RexxActivation.cpp
===================================================================
--- interpreter/execution/RexxActivation.cpp	(revision 12786)
+++ interpreter/execution/RexxActivation.cpp	(working copy)
@@ -1,7 +1,7 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
-/* Copyright (c) 2005-2023 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -82,8 +82,20 @@
 #include "CommandIOConfiguration.hpp"
 #include "CommandIOContext.hpp"
 #include "LibraryPackage.hpp"
+
+#include <atomic>
+
 #include <stdexcept> // std::exception_ptr, std::current_exception, std::rethrow_exception
 
+
+static std::atomic<uint32_t> counter(0); // to generate idntfr for concurrency trace
+
+uint32_t RexxActivation::getIdntfr()
+{
+    if (idntfr == 0) idntfr = ++counter;
+    return idntfr;
+}
+
 /**
  * Create a new activation object
  *
@@ -450,6 +462,7 @@
     // the "msgname" can also be the name of an external routine, the label
     // name of an internal routine.
     settings.messageName = name;
+    bool traceEntryDone = false;
 
     // not a reply restart situation?  We need to do the full
     // initial setup
@@ -495,6 +508,19 @@
                 {
                     // get the object variables and reserve these
                     settings.objectVariables = receiver->getObjectVariables(scope);
+
+                    // For proper diagnostic in case of deadlock, do the trace now
+                    if (tracingLabels() && isMethodOrRoutine())
+                    {
+                        traceEntry();
+                        if (!tracingAll())
+                        {
+                            // we pause on the label only for ::OPTIONS TRACE LABELS
+                            pauseLabel();
+                        }
+                        traceEntryDone = true;
+                    }
+
                     settings.objectVariables->reserve(activity);
                     objectScope = SCOPE_RESERVED;
                 }
@@ -559,7 +585,7 @@
     // is a routine or method invocation in one of those packages, give the
     // initial entry trace so the user knows where we are.
     // Must be one of ::OPTIONS TRACE ALL/RESULTS/INTERMEDIATES/LABELS
-    if (tracingLabels() && isMethodOrRoutine())
+    if (!traceEntryDone && tracingLabels() && isMethodOrRoutine())
     {
         traceEntry();
         if (!tracingAll())
Index: interpreter/execution/RexxActivation.hpp
===================================================================
--- interpreter/execution/RexxActivation.hpp	(revision 12786)
+++ interpreter/execution/RexxActivation.hpp	(working copy)
@@ -1,7 +1,7 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
-/* Copyright (c) 2005-2023 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -122,6 +122,7 @@
    void live(size_t) override;
    void liveGeneral(MarkReason reason) override;
 
+   uint32_t getIdntfr();
    RexxObject *dispatch() override;
    wholenumber_t digits() override;
    wholenumber_t fuzz() override;
@@ -407,6 +408,9 @@
    inline bool              isTopLevel() { return (activationContext&TOP_LEVEL_CALL) != 0; }
    inline bool              isGuarded() { return settings.isGuarded(); }
    inline void              setGuarded() { settings.setGuarded(true); }
+   inline bool              isObjectScopeLocked() { return this->objectScope == SCOPE_RESERVED; } // for concurrency trace
+   unsigned short           getReserveCount() { VariableDictionary *ovd = this->getVariableDictionary(); return ovd ? ovd->getReserveCount() : 0; } // for concurrency trace. Try to get the ovd counter, even if not yet assigned to current activation.
+   VariableDictionary *     getVariableDictionary() { return this->receiver ? this->receiver->getObjectVariables(this->scope) : NULL; } // for concurrency trace. Try to get the ovd, even if not yet assigned to current activation.
 
           void              enableExternalTrace();
           void              disableExternalTrace();
@@ -631,5 +635,6 @@
     bool                 randomSet;     // random seed has been set
     size_t               blockNest;     // block instruction nesting level
     size_t               instructionCount;  // The number of instructions since we last yielded control
+    uint32_t             idntfr;        // idntfr for concurrency trace
  };
  #endif
Index: interpreter/execution/VariableDictionary.cpp
===================================================================
--- interpreter/execution/VariableDictionary.cpp	(revision 12786)
+++ interpreter/execution/VariableDictionary.cpp	(working copy)
@@ -62,8 +62,18 @@
 #include "DirectoryClass.hpp"
 #include "GlobalNames.hpp"
 #include "CompoundTableElement.hpp"
+#include <atomic>
 
 
+static std::atomic<uint32_t> counter(0); // to generate idntfr for concurrency trace
+
+uint32_t VariableDictionary::getIdntfr()
+{
+    if (idntfr == 0) idntfr = ++counter;
+    return idntfr;
+}
+
+
 /**
  * Create a new variable dictionary object.
  *
Index: interpreter/execution/VariableDictionary.hpp
===================================================================
--- interpreter/execution/VariableDictionary.hpp	(revision 12786)
+++ interpreter/execution/VariableDictionary.hpp	(working copy)
@@ -1,7 +1,7 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
-/* Copyright (c) 2005-2018 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -204,6 +204,9 @@
 
     RexxObject  *realStemValue(RexxString *stemName);
 
+    uint32_t getIdntfr();
+    inline unsigned short getReserveCount() { return reserveCount; } // for concurrency trace
+
     inline bool isScope(RexxClass *otherScope) { return scope == otherScope; }
     inline VariableDictionary *getNextDictionary() { return nextDictionary; }
     inline Activity *getReservingActivity() { return reservingActivity; }
@@ -226,6 +229,7 @@
     unsigned short reserveCount;         // number of times reserved
     VariableDictionary *nextDictionary;  // chained object dictionary
     RexxClass *scope;                    // scopy of this object dictionary
+    uint32_t idntfr;                     // idntfr for concurrency trace
 };
 
 inline VariableDictionary *new_variableDictionary(size_t s) { return new VariableDictionary(s); }
Index: interpreter/memory/GlobalNames.h
===================================================================
--- interpreter/memory/GlobalNames.h	(revision 12786)
+++ interpreter/memory/GlobalNames.h	(working copy)
@@ -1,7 +1,7 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
-/* Copyright (c) 2005-2022 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -258,3 +258,13 @@
 GLOBAL_NAME(TIMESPAN, "TIMESPAN")
 GLOBAL_NAME(TOTALSECONDS, "TOTALSECONDS")
 
+GLOBAL_NAME(ATTRIBUTEPOOL,       "ATTRIBUTEPOOL")       // TraceObject: a counter (number)
+GLOBAL_NAME(HASOBJECTLOCK,       "HASOBJECTLOCK")       // TraceObject: .true/.false (isObjectScopeLocked)
+GLOBAL_NAME(INTERPRETER,         "INTERPRETER")         // TraceObject: a counter (number)
+GLOBAL_NAME(INVOCATION,          "INVOCATION")          // TraceObject: a counter (number)
+GLOBAL_NAME(ISGUARDED,           "ISGUARDED")           // TraceObject: .true/.false (method definition)
+GLOBAL_NAME(OBJECTLOCKCOUNT,     "OBJECTLOCKCOUNT")     // TraceObject: a counter (number, reserveCount)
+GLOBAL_NAME(OPTION,              "OPTION")              // TraceObject: option at creation time
+GLOBAL_NAME(THREAD,              "THREAD")              // TraceObject: a counter (number, activity)
+GLOBAL_NAME(TRACELINE,           "TRACELINE")           // TraceObject: a trace line string
+GLOBAL_NAME(TRACEOBJECT,         "TRACEOBJECT")         // TraceObject: class name
Index: interpreter/runtime/InterpreterInstance.cpp
===================================================================
--- interpreter/runtime/InterpreterInstance.cpp	(revision 12786)
+++ interpreter/runtime/InterpreterInstance.cpp	(working copy)
@@ -1,7 +1,7 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
-/* Copyright (c) 2005-2022 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -52,8 +52,18 @@
 #include "WeakReferenceClass.hpp"
 #include "RoutineClass.hpp"
 #include "NativeActivation.hpp"
+#include <atomic>
 
 
+static std::atomic<uint32_t> counter(0); // to generate idntfr for concurrency trace
+
+uint32_t InterpreterInstance::getIdntfr()
+{
+    if (idntfr == 0) idntfr = ++counter;
+    return idntfr;
+}
+
+
 /**
  * Create a new Package object instance.
  *
Index: interpreter/runtime/InterpreterInstance.hpp
===================================================================
--- interpreter/runtime/InterpreterInstance.hpp	(revision 12786)
+++ interpreter/runtime/InterpreterInstance.hpp	(working copy)
@@ -1,6 +1,6 @@
 /*----------------------------------------------------------------------------*/
 /*                                                                            */
-/* Copyright (c) 2005-2020 Rexx Language Association. All rights reserved.    */
+/* Copyright (c) 2005-2024 Rexx Language Association. All rights reserved.    */
 /*                                                                            */
 /* This program and the accompanying materials are made available under       */
 /* the terms of the Common Public License v1.0 which accompanies this         */
@@ -79,6 +79,7 @@
 
     RexxString *getDefaultEnvironment() { return defaultEnvironment; }
     Activity *getRootActivity() { return rootActivity; }
+    uint32_t getIdntfr();
 
     InterpreterInstance(ExitHandler *handlers);
     void addActivity(Activity *);
@@ -144,6 +145,7 @@
     RexxString          *searchPath;         // additional Rexx search path
     ArrayClass          *searchExtensions;   // extensions to search on for external calls
     void                *applicationData;    // application specific data
+    uint32_t            idntfr;              // idntfr for concurrency trace
     DirectoryClass      *localEnvironment;   // the current local environment
     StringTable         *commandHandlers;    // our list of command environment handlers
     StringTable         *requiresFiles;      // our list of requires files used by this instance
