fis-gtm/sr_port/gtm_threadgbl.h

113 lines
6.1 KiB
C

/****************************************************************
* *
* Copyright 2010, 2011 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#ifndef GTM_THREADGBL_included
#define GTM_THREADGBL_included
#ifndef NO_THREADGBL_DEFTYPES
# include "gtm_threadgbl_deftypes.h" /* Avoided for gtm_threadgbl_deftypes.c which builds this header file */
#endif
/* The following three macros allow access to global variables located in the thread-global array. The ultimate
* goal of this array is to permit GTM to become thread-safe. That is not yet true but this framework is the first
* step in taming our global variable use. In the future, these macros will change to their thread-safe counterparts
* such that we can have different arrays per thread.
*
* The macros can be classified as declaration (DCL_THREADGBL_ACCESS), definition (SETUP_THREADGBL_ACCESS), and
* usage (TADR, TREF, TAREF1, TAREF2, RFPTR, SFPTR, IVFPTR).
*
* DCL_THREADGBL_ACCESS - simple job is to declare the local variable used as an anchor to the thread global
* array. It should be located in the declaration section of an entry point.
*
* SETUP_THREAD_GBL_ACCESS - Sets the value of the local variable used as an anchor. Today, this is just a
* global var de-reference. In the future, it will use thread-logic to access a
* thread related base var. This should be placed near the top of the executable
* code for the routine - certainly before the first TREF macro.
* TADR - Used to obtain the address of the element.
* TREF - Used to dereference a global var (see notes at TREF macro for usage).
* TAREF1/TAREF2 - Used to access array elements - TAREF1 for vectors, TAREF2 for 2 subscript access.
* RFPTR - Used to reference a function pointer in an expression or conditional.
* SFPTR - Used to set a new value into a function pointer.
* IVFPTR - Used to invoke a function pointer.
*/
/* Declare local thread global anchor */
#define DCL_THREADGBL_ACCESS void *lcl_gtm_threadgbl
/* Setup the local thread global anchor giving a value (and purpose in life) */
#define SETUP_THREADGBL_ACCESS lcl_gtm_threadgbl = gtm_threadgbl
/* Reference a given global in the thread global array. There are a couple of different ways this macro can be
* used. Note that its first term is a "de-reference" (aka "*"). As an example, say we have a global name defined
* as follows:
*
* somestruct *gblname;
*
* and we wish to access gblname->subfield. If we code "TREF(gblname)->subfield", that would generate
*
* *((somestruct **)((char *)lcl_gtm_threadgbl + nnn))->subfield
*
* Note that the first dereference covers the entire expression instead of just the TREF expression. This is an incorrect
* reference that hopefully produces a compiler error instead of a hard-to-find bug. What needs to be coded instead is
* (TREF(gblname))->subfield which generates:
*
* (*((somestruct **)((char *)lcl_gtm_threadgbl + nnn)))->subfield
*
* This isolates the dereference to the expression it needs to refer to and produces an expression to correctly access the
* desired field. However, if the global is not a pointer, but say, a boolean, then you CANNOT surround the TREF macro with
* parens if the expression is on the left hand side of the "=" operator because that is not a valid LREF expression. So if
* the field were a boolean, you could modify it as "TREF(somebool) = TRUE;".
*
* The general rule of thumb is if the global is a pointer being used to access a subfield, or if the global is a structure
* itself and you are accessing subfields with a "." operator (e.g. (TREF(fnpca)).fnpcs[i].indx = i;) surround the TREF with ().
* Otherwise* you can leave it unadorned.
*
* Note that function pointers present some odd constraints. You can cast something to a function pointer type but only
* when you are going to actually invoke it (as the IVFPTR() macro does below). But this means that non-invoking references
* (or assignments) cannot use casts to make types match. So we need 2 additional macros for reference in an expression (RFPTR)
* or setting a function pointer (SFPTR) so we can control the necessary aspects of the expressions involved. See
* $sr_unix/generic_signal_handler.c for uses of most of these macros used with function pointers.
*/
#define TREF(name) *((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name))
/* For address of item use TADR(name) macro */
#define TADR(name) ((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name))
/* For access to single dimension array (vector), use TAREF1 macro */
#define TAREF1(name, indx1) (TADR(name))[indx1]
/* For access to 2 dimension array, use TAREF2 macro */
#define TAREF2(name, indx1, indx2) ((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name + /* Base addr of array */ \
(((indx1) - 1) * SIZEOF(ggt_##name) * ggd_##name)))[indx2] /* Row offset */
/* To set a function pointer, use SFPTR(name) macro - Used to copy an address INTO a function pointer */
#define SFPTR(name, value) *((char **)((char *)lcl_gtm_threadgbl + ggo_##name)) = (char *)(value)
/* To reference a function pointer's value, use RFPTR(name) macro. Use only in rvalue RHS expressions. Does not produce
* an lvalue suitable for LHS usage. See SFPTR() above if function pointer needs a new value.
*/
#define RFPTR(name) (ggt_##name (*)gga_##name)(*(char **)((char *)lcl_gtm_threadgbl + ggo_##name))
/* To invoke a function pointer, use IVFPTR(name) macro */
#define IVFPTR(name) ((ggf_##name)(*(char **)((char *)lcl_gtm_threadgbl + ggo_##name)))
/* In the main routines for GTM and the utilities that need to initialize the thread global structure all other routines access,
* this macro should be used in lieu of SETUP_THREADGBL_ACCESS.
*/
#define GTM_THREADGBL_INIT \
{ \
gtm_threadgbl_init(); \
SETUP_THREADGBL_ACCESS; \
}
#endif