Guidelines for making the C source code thread safe
- Last Updated: August 19, 2021
- 3 minute read
- OpenEdge
- Version 12.2
- 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). When you build your HLC library on AIX, includecsmtcrt.oso that the library uses thread safe implementations of the C run-time library functions.
- Validate the global variables in the HLC library are
thread safe (for example, using the