Guidelines for making the C source code thread safe
- Last Updated: January 17, 2024
- 3 minute read
- OpenEdge
- Version 12.8
- Documentation
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.
- Change calls to non-thread safe C run-time library functions in your C
source code to thread safe implementations:
- Make a list of all the C run-time library function calls in the C source code.
- 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.
- For non-thread safe function calls, ignore function
calls that are interposed in the following Progress executables:
_progresfor the ABL client_mproapsvfor the PAS for OpenEdge multi-session agent
For the complete list of C run-time library functions interposed in OpenEdge, see C run-time library functions interposed in the OpenEdge code.
- Change the remaining references to their thread safe versions.
- Reduce the usage of non-constant global variables in your source
code:
- Make a list of all the non-constant global variables in your source code.
- Review the list.
- If there are global variables in the list which can be marked constant, then mark them so.
- Localize the remaining non-constant global variables:
- Move your global variables into a single structure.
For example:
structmyglobaldata{ /* obviously, name this whatever you want*/ int tls_foo; /* global called foo */ struct datastruct *tls_pmydata; /* global called pmydata etc. */ }; - Allocate and initialize the
myglobaldatastructure each timeproHLC_InitSession()is called. - Register
myglobaldatawithproSetGlobalStruct().When
proHLC_ExitSession()is called, clean up your global pointers and releasemyglobaldata.Whenever the C code needs to access a non-constant global variable, the code:- Retrieves the allocated structure by calling
proGetGlobalStruct(). - Accesses the non-constant global variable in the retrieved structure.
- Retrieves the allocated structure by calling
- Define a thread variable for your
myglobaldatastructure. For example:On Unix
__thread structmyglobaldata*pmygd; /* defined once */ extern __thread structmyglobaldata*pmygd; /* everywhere you need access */On Windows
_declspec (thread) structmyglobaldata*pmygd; /* defined once */ _declspec (thread) __thread structmyglobaldata*pmygd; /* everywhere you need it */ - Set the thread variable each time
PRODSP()is called. For example:pmygd = (structmyglobaldata*) proGetGlobalStruct(); /* retrieves */ - Change global references so the code accesses them via
the thread variable.
For example,
foo = 10;becomespmygd->tls_foo = 10;. Sincepmygdis set whenPRODSP()is called, it is available for as long as you need it. - If you have multiple global references, consider using a
#defineschema in your code. Include a#defineschema wherever you need access to a global variable. For example:#define foo pmygd->tls_foo
- Move your global variables into a single structure.
- 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
nmcommand). - Validate the C run-time library function calls made by the HLC library are
thread safe (for example, using the
nmcommand).
- Validate the global variables in the HLC library are
thread safe (for example, using the