If the ABL procedure that has the ABL CALL statement is deployed to a PAS for OpenEdge instance, ensure the C source code is thread safe to take advantage of the multi-threaded functionality of the PAS for OpenEdge multi-session agent. Otherwise, C function calls are serialized.

Use the following guidelines to ensure your C source code is thread safe:
  • Change calls to non-thread safe C run-time library functions in your C source code to thread safe implementations:
    1. Make a list of all the C run-time library function calls in the C source code.
    2. Classify the calls as thread safe and non-thread safe.
      Note: Interposing a function is the act of substituting an original function with a custom wrapper function.
    3. For non-thread safe function calls, ignore function calls that are interposed in the following Progress executables:
      • _progres for the ABL client
      • _mproapsv for the PAS for OpenEdge multi-session agent
      You are left with references to C run-time library functions that do not have thread safe implementations.

      For the complete list of C run-time library functions interposed in OpenEdge, see C run-time library functions interposed in the OpenEdge code.

    4. Change the remaining references to their thread safe versions.
  • Reduce the usage of non-constant global variables in your source code:
    1. Make a list of all the non-constant global variables in your source code.
    2. Review the list.
    3. If there are global variables in the list which can be marked constant, then mark them so.
  • Localize the remaining non-constant global variables:
    1. Move your global variables into a single structure.

      For example:

      struct myglobaldata { /* obviously, name this whatever you want*/ 
      int tls_foo; /* global called foo */
      struct datastruct *tls_pmydata; /* global called pmydata etc. */
      };
    2. Allocate and initialize the myglobaldata structure each time proHLC_InitSession() is called.
    3. Register myglobaldata with proSetGlobalStruct().

      When proHLC_ExitSession() is called, clean up your global pointers and release myglobaldata.

      Whenever the C code needs to access a non-constant global variable, the code:
      1. Retrieves the allocated structure by calling proGetGlobalStruct().
      2. Accesses the non-constant global variable in the retrieved structure.
    4. Define a thread variable for your myglobaldata structure. For example:

      On Unix

      __thread struct myglobaldata *pmygd; /* defined once */
      extern __thread struct myglobaldata *pmygd; /* everywhere you need access */

      On Windows

      _declspec (thread) struct myglobaldata *pmygd; /* defined once */
      _declspec (thread) __thread struct myglobaldata *pmygd; /* everywhere you need it */
    5. Set the thread variable each time PRODSP() is called. For example:
      pmygd = (struct myglobaldata *) proGetGlobalStruct(); /* retrieves */
    6. Change global references so the code accesses them via the thread variable.

      For example, foo = 10; becomes pmygd->tls_foo = 10;. Since pmygd is set when PRODSP() is called, it is available for as long as you need it.

    7. If you have multiple global references, consider using a #define schema in your code. Include a #define schema wherever you need access to a global variable. For example:

      #define foo pmygd->tls_foo

  • Avoid loading an extra DLL or shared object from the C source code. If you must load an extra DLL or shared object:
    • Confirm the DLL or shared object is thread safe.
    • Serialize the loading operation using synchronization mechanisms available in the C library.
    • Ensure the DLL or shared object is loaded only once and not by multiple threads.
  • After you build the HLC library, perform the following checks:
    • Validate the global variables in the HLC library are thread safe (for example, using the nm command).
    • Validate the C run-time library function calls made by the HLC library are thread safe (for example, using the nm command).