fis-gtm/sr_port/mdef.h

1887 lines
78 KiB
C

/****************************************************************
* *
* Copyright 2001, 2012 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 MDEF_included
#define MDEF_included
/* mstr needs to be defined before including "mdefsp.h". */
typedef int mstr_len_t;
#ifndef __vms
typedef struct
{
unsigned int char_len; /* Character length */
mstr_len_t len;
char *addr;
} mstr;
# define MSTR_CONST(name, string) mstr name = {0, LEN_AND_LIT(string)}
# define MSTR_DEF(name, length, string) mstr name = {0, length, string}
# define MIDENT_CONST(name, string) mident name = {0, LEN_AND_LIT(string)}
# define MIDENT_DEF(name, length, string) mident name = {0, length, string}
#else
typedef struct
{
mstr_len_t len; /* Byte length */
char *addr;
} mstr;
# define MSTR_CONST(name, string) mstr name = {LEN_AND_LIT(string)}
# define MSTR_DEF(name, length, string) mstr name = {length, string}
# define MIDENT_CONST(name, string) mident name = {LEN_AND_LIT(string)}
# define MIDENT_DEF(name, length, string) mident name = {length, string}
#endif
#define GET_MSTR_LEN(X, Y) GET_ULONG(X, Y)
#define PUT_MSTR_LEN(X, Y) PUT_ULONG(X, Y)
#define MEMVCMP(STR1, STR1LEN, STR2, STR2LEN, RESULT) \
{ \
int lcl_str1Len, lcl_str2Len; \
int lcl_minLen, lcl_retVal, lcl_retVal2; \
\
lcl_str1Len = STR1LEN; \
lcl_str2Len = STR2LEN; \
if (lcl_str1Len < lcl_str2Len) \
{ \
lcl_minLen = lcl_str1Len; \
lcl_retVal = -1; \
} else if (lcl_str1Len > lcl_str2Len) \
{ \
lcl_minLen = lcl_str2Len; \
lcl_retVal = 1; \
} else \
{ \
lcl_minLen = lcl_str1Len; \
lcl_retVal = 0; \
} \
RESULT = (0 == (lcl_retVal2 = memcmp(STR1, STR2, lcl_minLen))) ? lcl_retVal : lcl_retVal2; \
}
/* There are 2 MSTR*CMP macros. One is if the parameters are available as MSTRs and another if the parameters
* are available as MSTR pointers. Use whichever is appropriate as it saves cycles.
*/
#define MSTRP_CMP(x, y, result) MEMVCMP((x)->addr, (x)->len, (y)->addr, (y)->len, result)
#define MSTR_CMP(x, y, result) MEMVCMP((x).addr, (x).len, (y).addr, (y).len, result)
#define MSTR_EQ(x, y) (((x)->len == (y)->len) && !memcmp((x)->addr, (y)->addr, (x)->len))
#include <sys/types.h>
typedef int int4; /* 4-byte signed integer */
typedef unsigned int uint4; /* 4-byte unsigned integer */
#define sssize_t size_t
/* If ever the following macro (SHMDT) is expanded to a multi-line macro, care should be taken to save the errno immediately after
* the "shmdt" system call invocation to avoid errno from being mutated by subsequent system calls.
*/
#define SHMDT(X) shmdt((void *)(X))
/* constant needed for FIFO - OS390 redefines in mdefsp.h */
#define FIFO_PERMISSION 010666 /* fifo with RW permissions for owner, group, other */
#include <inttypes.h>
#include "mdefsa.h"
#include <mdefsp.h>
#include "gtm_sizeof.h"
#include "gtm_threadgbl.h"
/* Anchor for thread-global structure rather than individual global vars */
GBLREF void *gtm_threadgbl; /* Accessed through TREF macro in gtm_threadgbl.h */
#ifdef DEBUG
error_def(ERR_ASSERT);
#define assert(x) ((x) ? 1 : rts_error(VARLSTCNT(7) ERR_ASSERT, 5, LEN_AND_LIT(__FILE__), __LINE__, (SIZEOF(#x) - 1), (#x)))
#else
#define assert(x)
#endif
#ifdef GTM64
# define lvaddr "%016lx"
#else
# define lvaddr "%08lx"
#endif
/* Define GT.M interlude functions for open, close, pipe, creat and dup system calls. This lets GT.M trace through all file
* descriptor activity (needed for D9I11-002714). Do this on all Unix platforms. Note that only the macro GTM_FD_TRACE is
* defined here. gtm_unistd.h and gtm_fcntl.h define the actual GT.M interlude functions based on this macro.
*/
#if defined(UNIX)
# define GTM_FD_TRACE
# define GTM_FD_TRACE_ONLY(X) X
#else
# define GTM_FD_TRACE_ONLY(X)
#endif
/* Define what is an invalid file descriptor in Unix and VMS. */
#if defined(UNIX)
# define FD_INVALID -1 /* fd of -1 is invalid in Unix posix calls */
# define FD_INVALID_NONPOSIX FD_INVALID
#else
# define FD_INVALID -1 /* fd of -1 is invalid in VMS if using POSIX interface (open/close etc.) */
# define FD_INVALID_NONPOSIX 0 /* fd of 0 is invalid in VMS if using RMS sys$open calls (non-posix interface) */
#endif
/* Now that mdefsp.h is included, GBLDEF should have been #defined. Use it to define STATICDEF for variables
* and STATICFNDEF, STATICFNDCL for functions. Define STATICDEF to "GBLDEF". This way we know such usages are intended
* to be "static" but yet can effectively debug these variables since they are externally visible.
* For functions, do not use the "static" keyword to make them externally visible.
* Note that a STATICREF for variables does not make sense since statics are supposed to be used only within one module.
*/
#define STATICDEF GBLDEF
#define STATICFNDCL extern
#define STATICFNDEF
/* INTPTR_T is an integer that has the same length as a pointer on each platform. Its basic use is for arithmetic
or generic parameters. For all platforms except Tru64/VMS (alpha platforms), the [U]INTPTR_T types will be
equivalenced to [u]intptr_t. But since this type is used for alignment and other checking, and since Tru64/VMS
(implemented as a 32 bit platform) unconditionally sets this type to its 8 char variant, on Tru64/VMS we will
explicitly make [U]INTPTR_T a 4 byte creature.
*/
#if !defined(__alpha)
typedef intptr_t INTPTR_T;
typedef uintptr_t UINTPTR_T;
#else
typedef int INTPTR_T;
typedef unsigned int UINTPTR_T;
#endif
/* The intszofptr_t type is defined to be basically the same size as an address on the platforms it runs on. So it
is the same size as INTPTR_T without the connotation of being a pointer. This is used in places where size_t
or ssize_t would normally be used except they can't be used because they are the wrong size on Alpha systems.
Classic usage is in places where need consistant integer and pointer sized elements like constructed parameter
lists or other arrays.
*/
typedef INTPTR_T intszofptr_t;
typedef UINTPTR_T uintszofptr_t;
#ifdef GTM64
# define USER_STACK_SIZE 8192
# define GTM64_ONLY(X) X
# define NON_GTM64_ONLY(X)
# define VA_ARG_TYPE long
# define VA_ARG_TYPE_BOOL int
# define GTM_IS_64BIT TRUE
# define GTM_BITNESS_THIS "64-bit"
# define GTM_BITNESS_OTHER "32-bit"
#else
# define USER_STACK_SIZE 4096
# define GTM64_ONLY(X)
# define NON_GTM64_ONLY(X) X
# define VA_ARG_TYPE int
# define VA_ARG_TYPE_BOOL int
# define GTM_IS_64BIT FALSE
# define GTM_BITNESS_THIS "32-bit"
# define GTM_BITNESS_OTHER "64-bit"
#endif /* GTM64 */
#ifdef __CYGWIN__
# define CYGWIN_ONLY(X) X
#else
# define CYGWIN_ONLY(X)
#endif
#ifdef __linux__
# define LINUX_ONLY(X) X
# define NON_LINUX_ONLY(X)
#else
# define LINUX_ONLY(X)
# define NON_LINUX_ONLY(X) X
#endif
#ifdef __MVS__
# define ZOS_ONLY(X) X
#else
# define ZOS_ONLY(X)
#endif
#ifdef Linux390
# define Linux390_ONLY(X) X
#else
# define Linux390_ONLY(X)
#endif
#if !defined(__alpha) && !defined(__sparc) && !defined(__hpux) && !defined(mips) && !defined(__ia64)
# define UNALIGNED_ACCESS_SUPPORTED
#endif
#if defined(__ia64)
# define IA64_ONLY(X) X
# define NON_IA64_ONLY(X)
# ifdef DEBUG
# define IA64_DEBUG_ONLY(X) X
# else
# define IA64_DEBUG_ONLY(X)
# endif /* DEBUG */
#else
# define IA64_ONLY(X)
# define NON_IA64_ONLY(X) X
# define IA64_DEBUG_ONLY(X)
#endif/* __ia64 */
#if defined(__ia64) || defined(__MVS__)
# define INTCAST(X) ((int)(X))
# define UINTCAST(X) ((uint4)(X))
# define STRLEN(X) ((int)(strlen(X)))
# define USTRLEN(X) ((unsigned int)(strlen(X)))
# define OFFSETOF(X,Y) ((int)(offsetof(X,Y)))
#else
# define INTCAST(X) X
# define UINTCAST(X) X
# define STRLEN(X) strlen(X)
# define USTRLEN(X) strlen(X)
# define OFFSETOF(X,Y) offsetof(X,Y)
#endif
/* macro to check that the OFFSET & SIZE of TYPE1.MEMBER1 is identical to that of TYPE2.MEMBER2 */
#define IS_OFFSET_AND_SIZE_MATCH(TYPE1, MEMBER1, TYPE2, MEMBER2) \
(SIZEOF(((TYPE1 *)NULL)->MEMBER1) == SIZEOF(((TYPE2 *)NULL)->MEMBER2)) \
&& (OFFSETOF(TYPE1, MEMBER1) == OFFSETOF(TYPE2, MEMBER2))
#define IS_OFFSET_MATCH(TYPE1, MEMBER1, TYPE2, MEMBER2) (OFFSETOF(TYPE1, MEMBER1) == OFFSETOF(TYPE2, MEMBER2))
#define ARRAYSIZE(arr) SIZEOF(arr)/SIZEOF(arr[0]) /* # of elements defined in the array */
#define ARRAYTOP(arr) (&arr[0] + ARRAYSIZE(arr)) /* address of the TOP of the array (first byte AFTER array limits).
* use &arr[0] + size instead of &arr[size] to avoid compiler warning.
*/
#ifdef __x86_64__
#define X86_64_ONLY(x) x
#define NON_X86_64_ONLY(x)
#else
#define X86_64_ONLY(x)
#define NON_X86_64_ONLY(x) x
#endif /* __x86_64__ */
#if defined(__i386) || defined(__x86_64__) || defined(__ia64) || defined(__MVS__) || defined(Linux390)
#define NON_RISC_ONLY(x) x
#define RISC_ONLY(x)
#elif defined(__sparc) || defined(_AIX) || defined(__hppa) || defined(__alpha)
#define RISC_ONLY(x) x
#define NON_RISC_ONLY(x)
#endif
#ifdef _AIX
# define AIX_ONLY(X) X
#else
# define AIX_ONLY(X)
#endif
#ifdef __sparc
# define SPARC_ONLY(X) X
#else
#define SPARC_ONLY(X)
#endif
#define BITS_PER_UCHAR 8 /* note, C does not require this to be 8, see <limits.h> for definitions of CHAR_BIT and UCHAR_MAX */
#define MAXPOSINT4 ((int4)0x7fffffff)
#define MAX_DIGITS_IN_INT 10 /* maximum number of decimal digits in a 4-byte integer */
#define MAX_DIGITS_IN_INT8 20 /* maximum number of decimal digits in an 8-byte integer */
#define MAX_HEX_DIGITS_IN_INT 8 /* maximum number of hexadecimal digits in a 4-byte integer */
#define MAX_HEX_DIGITS_IN_INT8 16 /* maximum number of hexadecimal digits in an 8-byte integer */
#define MAX_DIGITS_IN_EXP 2 /* maximum number of decimal digits in an exponent */
#define MAX_HOST_NAME_LEN 256
#define MAX_LONG_IN_DOUBLE 0xFFFFFFFFFFFFF /*Max Fraction part in IEEE double format*/
#ifndef _AIX
# ifndef __sparc
typedef int boolean_t;
# endif
#endif
typedef char bool;
typedef unsigned char mreg;
typedef int4 mint;
#define PRE_V5_MAX_MIDENT_LEN 8 /* Maximum length of an mident/mname before GT.M V5.0 */
typedef struct
{ /* The old mident structure used before V50FT01 */
char c[PRE_V5_MAX_MIDENT_LEN];
} pre_v5_mident;
#define MAX_MIDENT_LEN 31 /* Maximum length of an mident/mname */
typedef mstr mident;
typedef struct
{ /* Although we use 31 chars, the extra byte is to keep things aligned AND to keep a null terminator byte for places that care */
char c[MAX_MIDENT_LEN + 1];
} mident_fixed;
#define mid_len(name) strlen(&(name)->c[0]) /* callers of mid_len should include gtm_string.h as well */
#define MIDENT_CMP(x,y,result) MSTRP_CMP(x, y, result)
#define MIDENT_EQ(x,y) MSTR_EQ(x, y)
#ifdef INT8_NATIVE
# define NATIVE_WSIZE 8
#else
# define NATIVE_WSIZE 4
#endif
/* Maximum length of entry reference of the form "label+offset^routine" */
#define MAX_ENTRYREF_LEN (2 * MAX_MIDENT_LEN + MAX_DIGITS_IN_INT + STR_LIT_LEN("+^"))
/* M name entry used in various structures - variable table (rtnhdr.h), hash table (hashtab_def.h) and
* global variable (gv_namehead in gdsfhead.h) */
typedef struct
{
mident var_name; /* var_name.addr points to the actual variable name */
uint4 hash_code; /* hash (scrambled) value of the variable name text */
boolean_t marked; /* Used when in hashtable entry for xkill (at least) */
} mname_entry;
/* The M stack frame on all platforms that follow pv-based linkage model (alpha model)
* contains a pointer to the base of routine's literal section. All such platforms
* must define HAS_LITERAL_SECT so that the routines that create a new stack frame
* initialize literal_ptr field apppropriately.
*
*/
#if defined(__alpha) || defined(_AIX) || defined(__hpux) || defined(__sparc) || defined(__MVS__) || (defined(__linux__) && \
(defined(__ia64) || defined(__x86_64__) || defined(__s390__)))
# define HAS_LITERAL_SECT
#endif
typedef long ulimit_t; /* NOT int4; the Unix ulimit function returns a value of type long */
/* Bit definitions for mval type (mvtype) */
#define MV_NM 1 /* 0x0001 */
#define MV_INT 2 /* 0x0002
* Note: this bit is set for integers and non-integers with <= 3 digits after the decimal point */
#define MV_NUM_MASK 3 /* 0x0003 (MV_NM | MV_INT) */
#define MV_STR 4 /* 0x0004 */
#define MV_NUM_APPROX 8 /* 0x0008 */ /* bit set implies value is guaranteed to be part number, part string */
#define MV_CANONICAL 16 /* 0x0010
* Note: this bit is set currently only for mvals corresponding to local variable subscripts
* in lv_tree.c/lv_tree.h. This bit should not be examined/relied-upon anywhere outside lv_tree.c
*/
#define MV_SYM 32 /* 0x0020 */
#define MV_SUBLIT 64 /* 0x0040 */
#define MV_RETARG 128 /* 0x0080 */
#define MV_UTF_LEN 256 /* 0x0100 */
#define MV_ALIASCONT 512 /* 0x0200 */
#define MV_INT_OFF ~(MV_INT) /* Mask to turn off MV_INT */
#define MV_STR_OFF ~(MV_STR) /* Mask to turn off MV_STR */
#define MV_CANONICAL_OFF ~(MV_CANONICAL) /* Mask to turn off MV_CANONICAL */
#define MV_UTF_LEN_OFF ~(MV_UTF_LEN) /* Mask to turn off MV_UTF_LEN */
#define MV_EXT_NUM_MASK (MV_NM | MV_INT | MV_CANONICAL)
/* Special definition used when an xnew'd lv_val is moved from a popped symtab to an earlier
* one so it can be preserved. This flag marks the lv_val as a pointer to the new symtab so
* multiple references to it can be resolved.
*/
#define MV_LVCOPIED 0xf000
/* A few more special definitions */
#define MV_LV_TREE 0xf001 /* An "lvTree" structure has its "ident" field set to this special value */
#define MV_XBIAS 62
#define MV_XZERO 0
#define MV_BIAS 1000
#define MV_BIAS_PWR 3
#define NR_REG 16
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#ifndef NULL
# define NULL ((void *) 0)
#endif
#define NUL 0x00
#define SP 0x20
#define DEL 0x7f
#define MAX_STRLEN_32K 32767
/* MAX_STRLEN for local variable is changed from 32767 to 1048576 (1 MB) */
#define MAX_STRLEN (1 * 1024 * 1024) /*maximum GT.M string size (1 MB)*/
#define MAX_DBSTRLEN (32 * 1024 - 1) /* Maximum database string size */
/* Initial buffer size allocated for a GT.M string which can geometrically be increased upto the size enough to fit in MAX_STRLEN */
#define MAX_STRBUFF_INIT (32 * 1024)
#define MAX_NUM_SIZE 64
#define MAX_FORM_NUM_SUBLEN 128 /* this is enough to hold the largest numeric subscript */
#define PERIODIC_FLUSH_CHECK_INTERVAL (30 * 1000)
#define MAX_ARGS 256 /* in formallist */
#ifdef UNIX
# define MAX_KEY_SZ 1023 /* maximum database key size */
#else
# define MAX_KEY_SZ 255
#endif
# define OLD_MAX_KEY_SZ 255 /* For V5 and earlier, when only 1 byte was used for compression count */
/* The macro ZWR_EXP_RATIO returns the inflated length when converting the internal subscript
* representation (byte) length to ZWR representation.
* In "M" mode,
* Worst case is every other character is non-graphic. e.g. $C(128)_"A"_$C(128).
* In "UTF-8" mode,
* Worst case is with a non-graphic character and every other character is an illegal
* character. Here are the expansion ratios for different ranges of characters.
* ------------------------------------------------------------------------------
* Byte pattern max. expanded input byte ratio
* output length length
* ------------------------------------------------------------------------------
* $C(129)_$ZCH(128)_ 18 2 9
* $C(1536)_$ZCH(128)_ 19 3 7
* $C(65279)_$ZCH(128)_ 20 4 5
* $C(917585)_$ZCH(128)_ 21 5 6
* $C(1114111)_$ZCH(128)_ 22 5 6
* ------------------------------------------------------------------------------
* To cover cases of odd numbers of characters, add some buffer.
*
* MAX_ZWR_KEY_SZ, on the other hand, needs to be a compile-time constant since it's used in
* temporary allocation on the stack
*/
GBLREF boolean_t gtm_utf8_mode;
#ifdef UNICODE_SUPPORTED
# define ZWR_EXP_RATIO(X) ((!gtm_utf8_mode) ? (((X) * 6 + 7)) : ((X) * 9 + 11))
# define MAX_ZWR_KEY_SZ (MAX_KEY_SZ * 9 + 11)
# define MAX_ZWR_EXP_RATIO 9
#else
# define ZWR_EXP_RATIO(X) ((X) * 6 + 7)
# define MAX_ZWR_KEY_SZ (MAX_KEY_SZ * 6 + 7)
# define MAX_ZWR_EXP_RATIO 6
#endif
#define MAX_SYSERR 1000000
unsigned char *n2s(mval *mv_ptr);
char *s2n(mval *u);
mval *underr (mval *start, ...);
#ifdef DEBUG
# define DBG_ASSERT(X) assert(X),
#else
# define DBG_ASSERT(X)
#endif
/* Use the "D" format of these MV_FORCE macros only in those places where there is no possibility of the input being undefined */
#define MV_FORCE_STR(X) (MV_FORCE_DEFINED(X), MV_FORCE_STRD(X))
#define MV_FORCE_STRD(X) (DBG_ASSERT(MV_DEFINED(X)) (0 == ((X)->mvtype & MV_STR)) ? n2s(X) : NULL)
#define MV_FORCE_NUM(X) (MV_FORCE_DEFINED(X), MV_FORCE_NUMD(X))
#define MV_FORCE_NUMD(X) (DBG_ASSERT(MV_DEFINED(X)) (0 == ((X)->mvtype & MV_NM )) ? s2n(X) : NULL)
#define MV_FORCE_BOOL(X) (MV_FORCE_NUM(X), (X)->m[1] ? TRUE : FALSE)
#define MV_FORCE_INT(M) (MV_FORCE_DEFINED(M), MV_FORCE_INTD(M))
#define MV_FORCE_INTD(M) (DBG_ASSERT(MV_DEFINED(M)) (M)->mvtype & MV_INT ? (M)->m[1]/MV_BIAS : mval2i(M))
#define MV_FORCE_UMVAL(M,I) (((I) >= 1000000) ? i2usmval((M),(int)(I)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS ))
#define MV_FORCE_MVAL(M,I) (((I) >= 1000000 || (I) <= -1000000) ? i2mval((M),(int)(I)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS ))
#ifdef GTM64
#define MV_FORCE_ULMVAL(M,L) (((L) >= 1000000) ? ul2mval((M),(unsigned long)(L)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS ))
#define MV_FORCE_LMVAL(M,L) (((L) >= 1000000 || (L) <= -1000000) ? l2mval((M),(long)(L)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS ))
#else
#define MV_FORCE_ULMVAL MV_FORCE_UMVAL
#define MV_FORCE_LMVAL MV_FORCE_MVAL
#endif
#define MV_FORCE_DEFINED(X) ((!MV_DEFINED(X)) ? (X) = underr(X) : (X))
/* Note MV_FORCE_CANONICAL currently only used in op_add() when vars are known to be defined so no MV_FORCE_DEFINED()
macro has been added. If uses are added, this needs to be revisited. 01/2008 se
*/
#define MV_FORCE_CANONICAL(X) ((((X)->mvtype & MV_NM) == 0 ? s2n(X) : 0 ) \
,((X)->mvtype & MV_NUM_APPROX ? (X)->mvtype &= MV_NUM_MASK : 0 ))
#define MV_IS_NUMERIC(X) (((X)->mvtype & MV_NM) != 0)
#define MV_IS_INT(X) (((X)->mvtype & MV_INT) != 0) /* returns TRUE if input has MV_INT bit set */
#define MV_IS_TRUEINT(X, INTVAL_P) (isint(X, INTVAL_P)) /* returns TRUE if input is a true integer (no fractions) */
#define MV_IS_STRING(X) (((X)->mvtype & MV_STR) != 0)
#define MV_DEFINED(X) (((X)->mvtype & (MV_STR | MV_NM)) != 0)
#define MV_IS_CANONICAL(X) (((X)->mvtype & MV_NM) ? (((X)->mvtype & MV_NUM_APPROX) == 0) : (boolean_t)val_iscan(X))
#define MV_INIT(X) ((X)->mvtype = 0, (X)->fnpc_indx = 0xff)
#define MV_INIT_STRING(X, LEN, ADDR) ((X)->mvtype = MV_STR, (X)->fnpc_indx = 0xff, \
(X)->str.len = INTCAST(LEN), (X)->str.addr = (char *)ADDR)
/* The MVTYPE_IS_* macros are similar to the MV_IS_* macros except that the input is an mvtype instead of an "mval *".
* In the caller, use appropriate macro depending on available input. Preferable to use the MVTYPE_IS_* variant to avoid
* the (X)->mvtype dereference */
#define MVTYPE_IS_NUMERIC(X) (0 != ((X) & MV_NM))
#define MVTYPE_IS_INT(X) (0 != ((X) & MV_INT))
#define MVTYPE_IS_NUM_APPROX(X) (0 != ((X) & MV_NUM_APPROX))
#define MVTYPE_IS_STRING(X) (0 != ((X) & MV_STR))
/* DEFINE_MVAL_LITERAL is intended to be used to define a string mval where the string is a literal or defined with type
* "readonly". In other words, the value of the string does not change. Since we expect all callers of this macro to use
* ASCII literals, the MV_UTF_LEN bit is set in the type, and the character length is set to the same value as the byte length.
*/
#define DEFINE_MVAL_LITERAL(TYPE, EXPONENT, SIGN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
DEFINE_MVAL_COMMON(TYPE | MV_UTF_LEN, EXPONENT, SIGN, LENGTH, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH)
/* DEFINE_MVAL_STRING is intended to be used to define a string mval where the value of the string can change */
#define DEFINE_MVAL_STRING(TYPE, EXPONENT, SIGN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, 0, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH)
#ifdef VMS
#define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
{TYPE, EXPONENT, SIGN, 0xff, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH}
#else
#ifdef BIGENDIAN
#ifdef UNICODE_SUPPORTED
#define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
{TYPE, SIGN, EXPONENT, 0xff, MANT_LOW, MANT_HIGH, UTF_LEN, LENGTH, ADDRESS}
#else
#define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
{TYPE, SIGN, EXPONENT, 0xff, MANT_LOW, MANT_HIGH, LENGTH, ADDRESS}
#endif
#else /* BIGENDIAN */
#ifdef UNICODE_SUPPORTED
#define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
{TYPE, EXPONENT, SIGN, 0xff, MANT_LOW, MANT_HIGH, UTF_LEN, LENGTH, ADDRESS}
#else
#define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \
{TYPE, EXPONENT, SIGN, 0xff, MANT_LOW, MANT_HIGH, LENGTH, ADDRESS}
#endif /* UNICODE */
#endif /* BIGENDIAN */
#endif /* VMS */
#define ASCII_MAX (unsigned char)0x7F
#define IS_ASCII(X) ((uint4)(X) <= ASCII_MAX) /* X can be greater than 255 hence the typecast to uint4 */
#ifdef UNICODE_SUPPORTED
# define MV_FORCE_LEN(X) ((!((X)->mvtype & MV_UTF_LEN)) \
? (utf8_len(&(X)->str), ((X)->mvtype |= MV_UTF_LEN), (X)->str.char_len) \
: (X)->str.char_len)
/* MV_FORCE_LEN_STRICT() is used to ensure that mval is valid in addition to computing the char_len.
* Note that the validation is always forced even if MV_UTF_LEN is set since the previously computed
* char_len might have been evaluated in VIEW "NOBADCHAR" setting. */
# define MV_FORCE_LEN_STRICT(X) (((X)->str.char_len = UTF8_LEN_STRICT((X)->str.addr, (X)->str.len)), \
((X)->mvtype |= MV_UTF_LEN), (X)->str.char_len)
# define MV_IS_SINGLEBYTE(X) (((X)->mvtype & MV_UTF_LEN) && ((X)->str.len == (X)->str.char_len))
#else
# define MV_FORCE_LEN(X) ((X)->str.len)
# define MV_FORCE_LEN_STRICT(X) ((X)->str.len)
# define MV_IS_SINGLEBYTE(X) (TRUE) /* all characters are single-byte in non-Unicode platforms */
#endif
#define DISK_BLOCK_SIZE 512
#define LOG2_DISK_BLOCK_SIZE 9
#define DIVIDE_ROUND_UP(VALUE, MODULUS) (((VALUE) + ((MODULUS) - 1)) / (MODULUS))
#define DIVIDE_ROUND_DOWN(VALUE, MODULUS) ((VALUE) / (MODULUS))
#define ROUND_UP(VALUE, MODULUS) (DIVIDE_ROUND_UP(VALUE, MODULUS) * (MODULUS))
#define ROUND_DOWN(VALUE, MODULUS) (DIVIDE_ROUND_DOWN(VALUE, MODULUS) * (MODULUS))
#ifdef DEBUG
# define CHECKPOT(MODULUS) ((MODULUS) & ((MODULUS) - 1)) ? GTMASSERT, 0 :
# define BREAK_IN_PRO__CONTINUE_IN_DBG continue
# define DEBUG_ONLY(statement) statement
# define DEBUG_ONLY_COMMA(statement) statement,
# define PRO_ONLY(statement)
#else
# define CHECKPOT(MODULUS)
# define BREAK_IN_PRO__CONTINUE_IN_DBG break
# define DEBUG_ONLY(statement)
# define DEBUG_ONLY_COMMA(statement)
# define PRO_ONLY(statement) statement
#endif
/* These are the analogs of the preceding, but are more efficient when the MODULUS is a Power Of Two.
* One thing to watch for is that VALUE could be 8-byte and MODULUS could be 4-bytes. In that case, we
* want to return an 8-byte value. So need to typecast MODULUS to 8-bytes before we do "& ~(MODULUS -1)"
* or else that will be a 4-byte value and cause a bitwise & with an 8-byte value resulting in a truncated
* 8-byte return value (loss of high order bits). We choose sm_long_t to reflect that type as it is 8-bytes
* on the 64-bit platforms and 4-bytes on the 32-bit platforms. Choosing gtm_uint64_t unconditionally will
* make it 8-bytes on the 32-bit platforms too and result in warnings due to the 8-byte value eventually being
* truncated to 4-bytes by the caller after the return from the below macro.
*/
#define ROUND_UP2(VALUE, MODULUS) (CHECKPOT(MODULUS) ((VALUE) + ((MODULUS) - 1)) & ~(((sm_long_t)MODULUS) - 1))
#define ROUND_DOWN2(VALUE, MODULUS) (CHECKPOT(MODULUS) (VALUE) & ~(((sm_long_t)MODULUS) - 1))
/* Length needed to pad out to a given power of 2 boundary */
#define PADLEN(value, bndry) (int)(ROUND_UP2((sm_long_t)(value), bndry) - (sm_long_t)(value))
/* LOG2_OF_INTEGER returns the ceiling of log (base 2) of number */
#define LOG2_OF_INTEGER(number, log2_of_number) \
{ \
int temp = (number) - 1; \
for (log2_of_number = 0; 0 < temp; log2_of_number++) \
temp = (temp) >> 1; \
}
#define CALLFROM LEN_AND_LIT(__FILE__), __LINE__
void gtm_assert(int file_name_len, char file_name[], int line_no);
int gtm_assert2(int condlen, char *condtext, int file_name_len, char file_name[], int line_no);
#define GTMASSERT (gtm_assert(CALLFROM))
#define assertpro(x) ((x) ? 1 : gtm_assert2((SIZEOF(#x) - 1), (#x), CALLFROM))
#ifdef UNIX
#ifdef DEBUG
/* The below debug only macros are always used in pairs to indicate a window where the code doesn't expect rts_errors to happen.
* One reason why the code doesn't expect rts_errors is if the logic is complicated enough that having a condition handler for
* the window is tricky and will not undo the state of various global variables that were modified. An example of such a window
* is in gvcst_init. If an rts_error happens in this window, an assert will trip in rts_error at which point, the window as well
* as the rts_error can be re-examined to see whether the rts_error can be removed or the range of the window can be changed.
*/
#define DBG_MARK_RTS_ERROR_USABLE { assert(TREF(rts_error_unusable)); TREF(rts_error_unusable) = FALSE; }
#define DBG_MARK_RTS_ERROR_UNUSABLE { assert(!TREF(rts_error_unusable)); TREF(rts_error_unusable) = TRUE; }
#else
#define DBG_MARK_RTS_ERROR_USABLE
#define DBG_MARK_RTS_ERROR_UNUSABLE
#endif
int rts_error(int argcnt, ...);
void dec_err(uint4 argcnt, ...);
#elif defined(VMS)
void dec_err(int4 msgnum, ...);
#else
#error unsupported platform
#endif
void stx_error(int in_error, ...);
void ins_errtriple(int4 in_error);
int4 timeout2msec(int4 timeout);
/* the RTS_ERROR_TEXT macro will stay till all existing references to it have been renamed to RTS_ERROR_{LITERAL,STRING} */
#define RTS_ERROR_TEXT(STRING) LENGTH_AND_STRING(STRING)
/* for those who prefer not remembering the order of the length and the literal/string in the rts_error command line */
#define RTS_ERROR_LITERAL(LITERAL) LENGTH_AND_LITERAL(LITERAL)
#define RTS_ERROR_STRING(STRING) LENGTH_AND_STRING(STRING)
/* the LITERAL version of the macro should be used over STRING whenever possible for efficiency reasons */
#define STR_LIT_LEN(LITERAL) (SIZEOF(LITERAL) - 1)
#define LITERAL_AND_LENGTH(LITERAL) (LITERAL), (SIZEOF(LITERAL) - 1)
#define LENGTH_AND_LITERAL(LITERAL) (SIZEOF(LITERAL) - 1), (LITERAL)
#define STRING_AND_LENGTH(STRING) (STRING), (STRLEN((char *)(STRING)))
#define LENGTH_AND_STRING(STRING) (strlen((char *)(STRING))), (STRING)
#define LEN_AND_LIT(LITERAL) LENGTH_AND_LITERAL(LITERAL)
#define LIT_AND_LEN(LITERAL) LITERAL_AND_LENGTH(LITERAL)
#define STR_AND_LEN(STRING) STRING_AND_LENGTH(STRING)
#define LEN_AND_STR(STRING) LENGTH_AND_STRING(STRING)
#define MEMCMP_LIT(SOURCE, LITERAL) memcmp(SOURCE, LITERAL, SIZEOF(LITERAL) - 1)
#define MEMCPY_LIT(TARGET, LITERAL) memcpy(TARGET, LITERAL, SIZEOF(LITERAL) - 1)
#define SET_PROCESS_EXITING_TRUE \
{ \
GBLREF int process_exiting; \
\
process_exiting = TRUE; \
}
/* Macro to copy a source string to a malloced area that is set to the destination pointer.
* Since it is possible that DST might have multiple pointer dereferences in its usage, we
* use a local pointer variable and finally assign it to DST thereby avoiding duplication of
* those pointer dereferences (one for the malloc and one for the strcpy).
* There are two macros depending on whether a string or literal is passed.
*/
#define MALLOC_CPY_STR(DST, SRC) \
{ \
char *mcs_ptr; \
int mcs_len; \
\
mcs_len = STRLEN(SRC) + 1; \
mcs_ptr = malloc(mcs_len); \
memcpy(mcs_ptr, SRC, mcs_len); \
DST = mcs_ptr; \
}
#define MALLOC_CPY_LIT(DST, SRC) \
{ \
char *mcs_ptr; \
int mcs_len; \
\
mcs_len = SIZEOF(SRC); \
mcs_ptr = malloc(mcs_len); \
memcpy(mcs_ptr, SRC, mcs_len); \
DST = mcs_ptr; \
}
#define MALLOC_INIT(DST, SIZ) \
{ \
void *lcl_ptr; \
\
lcl_ptr = malloc(SIZ); \
memset(lcl_ptr, 0, SIZ); \
DST = lcl_ptr; \
}
/* *********************************************************************************************************** */
/* Frequently used len + str combinations in macro form. */
/* *********************************************************************************************************** */
#define DB_STR_LEN(reg) (reg)->dyn.addr->fname, (reg)->dyn.addr->fname_len
#define DB_LEN_STR(reg) (reg)->dyn.addr->fname_len, (reg)->dyn.addr->fname
#define REG_STR_LEN(reg) (reg)->rname, (reg)->rname_len
#define REG_LEN_STR(reg) (reg)->rname_len, (reg)->rname
#define JNL_STR_LEN(csd) (csd)->jnl_file_name, (csd)->jnl_file_len
#define JNL_LEN_STR(csd) (csd)->jnl_file_len, (csd)->jnl_file_name
#define FAB_LEN_STR(fab) (fab)->fab$b_fns, (fab)->fab$l_fna
/* *********************************************************************************************************** */
#ifdef DEBUG
/* Original debug code has been removed since it was superfluous and did not work on all platforms. SE 03/01 */
# define SET_TRACEABLE_VAR(var,value) var = value;
#else
# define SET_TRACEABLE_VAR(var,value) var = value;
#endif
/* If this is unix, we have a faster sleep for short sleeps ( < 1 second) than doing a hiber start.
* Take this chance to define UNIX_ONLY and VMS_ONLY macros.
*/
int m_usleep(int useconds);
#ifdef UNIX
# define SHORT_SLEEP(x) {assert(1000 > (x)); m_usleep((x) * 1000);}
#else
# define SHORT_SLEEP(x) hiber_start(x);
#endif
/* The following "MSYNC" defines are for the MM access method
* NO_MSYNC -- minimum number of msyncs -- only in run down
* UNTARGETED_MSYNC -- msync the entire file
* TARGETED_MSYNC -- keep track of changed buffers and only msync them
* REGULAR_MSYNC -- do regular file I/O on the mapped file (ignoring the fact it is mapped)
*
* If none of the MSYNCs are explicitly defined, the ifdef and elif defined sequence will fall through
* to the else case, defining NO_MSYNC as the default.
*/
#ifdef UNIX
# define UNIX_ONLY(X) X
# define UNIX_ONLY_COMMA(X) X,
# if defined UNTARGETED_MSYNC
# define UNTARGETED_MSYNC_ONLY(X) X
# define NON_UNTARGETED_MSYNC_ONLY(X)
# define TARGETED_MSYNC_ONLY(X)
# define NON_TARGETED_MSYNC_ONLY(X) X
# define REGULAR_MSYNC_ONLY(X)
# define NON_REGULAR_MSYNC_ONLY(X) X
# define NO_MSYNC_ONLY(X)
# define NON_NO_MSYNC_ONLY(X)
# elif defined TARGETED_MSYNC
# define UNTARGETED_MSYNC_ONLY(X)
# define NON_UNTARGETED_MSYNC_ONLY(X) X
# define TARGETED_MSYNC_ONLY(X) X
# define NON_TARGETED_MSYNC_ONLY(X)
# define REGULAR_MSYNC_ONLY(X)
# define NON_REGULAR_MSYNC_ONLY(X) X
# define NO_MSYNC_ONLY(X)
# define NON_NO_MSYNC_ONLY(X)
# elif defined REGULAR_MSYNC
# define UNTARGETED_MSYNC_ONLY(X)
# define NON_UNTARGETED_MSYNC_ONLY(X) X
# define TARGETED_MSYNC_ONLY(X)
# define NON_TARGETED_MSYNC_ONLY(X) X
# define REGULAR_MSYNC_ONLY(X) X
# define NON_REGULAR_MSYNC_ONLY(X)
# define NO_MSYNC_ONLY(X)
# define NON_NO_MSYNC_ONLY(X)
# else
# define NO_MSYNC
# define UNTARGETED_MSYNC_ONLY(X)
# define NON_UNTARGETED_MSYNC_ONLY(X)
# define TARGETED_MSYNC_ONLY(X)
# define NON_TARGETED_MSYNC_ONLY(X)
# define REGULAR_MSYNC_ONLY(X)
# define NON_REGULAR_MSYNC_ONLY(X)
# define NO_MSYNC_ONLY(X) X
# define NON_NO_MSYNC_ONLY(X)
# endif
#else
# define UNIX_ONLY(X)
# define UNIX_ONLY_COMMA(X)
# define UNTARGETED_MSYNC_ONLY(X)
# define TARGETED_MSYNC_ONLY(X)
# define REGULAR_MSYNC_ONLY(X)
# define NON_UNTARGETED_MSYNC_ONLY(X)
# define NON_TARGETED_MSYNC_ONLY(X)
# define NON_REGULAR_MSYNC_ONLY(X)
# define NO_MSYNC_ONLY(X)
# define NON_NO_MSYNC_ONLY(X)
#endif
/* HP-UX on PA-RISC and z/OS are not able to have dynamic file extensions while running in MM access mode
* HP-UX:
* All HP-UX before v3 (PA-RISC and 11i v1 and v2) have distinct memory map buffers and file system buffers with no simple
* way to map between them. To get around this problem the "Unified File Cache" was implemented in v3 for both Itanium
* and PA-RISC which solves things. The only way around the limitation in v1 and v2 would be to strategically place calls
* to "msync" throughout the code to keep the memory maps and file cache buffers in sync. This is too onerous a price
* to pay.
* z/OS:
* If multiple processes are accessing the same mapped file, and one process needs to extend/remap the file,
* all the other processes must also unmap the file.
*
* This same comment is in the test framework in set_gtm_machtype.csh. If this comment is updated, also update the other.
*/
#ifdef UNIX
# if !defined(__hppa) && !defined(__MVS__)
# define MM_FILE_EXT_OK
# else
# undef MM_FILE_EXT_OK
# endif
#endif
#ifdef VMS
# define VMS_ONLY(X) X
# define VMS_ONLY_COMMA(X) X,
#else
# define VMS_ONLY(X)
# define VMS_ONLY_COMMA(X)
#endif
#if (defined(UNIX) || defined(VMS))
# define UNSUPPORTED_PLATFORM_CHECK
#else
# define UNSUPPORTED_PLATFORM_CHECK #error UNSUPPORTED PLATFORM
#endif
/* Note the macros below refer to the UNIX Shared Binary Support. Because the
support is *specifically* for the Unix platform, "NON_USHBIN_ONLY()" will
also be true for VMS even though that platform does have shared binary support
(but it does not have Unix Shared Binary support). Use "NON_USHBIN_UNIX_ONLY()"
for UNIX platforms that do not support Shared Binaries. */
#ifdef USHBIN_SUPPORTED
# define USHBIN_ONLY(X) X
# define NON_USHBIN_ONLY(X)
# define NON_USHBIN_UNIX_ONLY(X)
#else
# define USHBIN_ONLY(X)
# define NON_USHBIN_ONLY(X) X
# ifdef UNIX
# define NON_USHBIN_UNIX_ONLY(X) X
# else
# define NON_USHBIN_UNIX_ONLY(X)
# endif
#endif
/* Unicode. Although most (all?) Unix platforms currently support Unicode, that may
not always be the case so a separate contingent is defined.
*/
#ifdef UNICODE_SUPPORTED
# define UNICODE_ONLY(X) X
# define NON_UNICODE_ONLY(X)
#else
# define UNICODE_ONLY(X)
# define NON_UNICODE_ONLY(X) X
#endif
/* Note: LONG_SLEEP *MUST*NOT* be the sleep() function because use of the sleep() function in
GT.M causes problems with GT.M's timers on some platforms. Specifically, the sleep() function
causes the SIGARLM handler to be silently deleted on Solaris systems (through Solaris 9 at least).
This leads to lost timer pops and has the potential for system hangs.
*/
#define LONG_SLEEP(x) hiber_start((x) * 1000)
#define OS_PAGE_SIZE gtm_os_page_size
#define OS_PAGE_SIZE_DECLARE GBLREF int4 gtm_os_page_size;
#ifdef VMS
# define MAX_IO_BLOCK_SIZE DISK_BLOCK_SIZE
#else
# define MAX_IO_BLOCK_SIZE 65536
#endif
#ifndef GTM_INT64T_DEFINED
#define GTM_INT64T_DEFINED
typedef uint64_t gtm_uint64_t;
typedef int64_t gtm_int64_t;
#endif
typedef INTPTR_T sm_off_t;
/* HPPA latches (used by load_and_clear) must be 16 byte aligned.
* By allocating 16 bytes, the routines and macros used to access the latch can do the alignment.
* Since nothing else should follow to avoid cache threshing, this doesn't really waste space.
* Note that the additional space for this latch is only allocated on HPPA. All other platforms
* have a "sensible" compare-and-swap type lock using the first two words in the latch.
*/
typedef struct
{
union
{
gtm_uint64_t pid_imgcnt; /* Combined atomic (unique) process id used on VMS */
struct
{
volatile int4 latch_pid; /* (Usually) Process id of latch holder or LOCK_AVAILABLE. On VMS
this word may have other values. */
volatile int4 latch_word; /* Extra word associated with lock (sometimes bci lock or image cnt
for VMS) */
} parts;
} u;
#if defined __hppa
volatile int4 hp_latch_space[4]; /* Used for HP load_and_clear locking instructions per
HP whitepaper on spinlocks */
#endif
} global_latch_t;
#define latch_image_count latch_word
#define GLOBAL_LATCH_HELD_BY_US(latch) (process_id == (latch)->u.parts.latch_pid \
VMS_ONLY(&& image_count == (latch)->u.parts.latch_image_count))
typedef struct compswap_time_field_struct
{ /* This structure is used where we want to do a compare-n-swap (CAS) on a time value. The CAS interfaces
* need an instance of global_latch_t to operate on. We will utilize the "latch_pid" field to hold the
* time and the latch_word is unused except on VMS where it will hold 0. Since this structure must be of
* a constant size (size of global_latch_t varies), pad the latch with sufficient space to match the
* size of global_latch_t's largest size (on HPUX).
*/
global_latch_t time_latch;
#ifndef __hppa
int4 hp_latch_space[4]; /* padding only on non-hpux systems */
#endif
} compswap_time_field;
/* takes value of time() but needs to be 4 byte so can use compswap on it. Not using time_t, as that is an indeterminate size on
* various platforms. Value is time (in seconds) in a compare/swap updated field so only one process performs a given task in a
* given interval
*/
#define cas_time time_latch.u.parts.latch_pid
typedef union gtm_time8_struct
{
time_t ctime; /* For current GTM code sem_ctime field corresponds to creation time */
int4 filler[2]; /* Filler to ensure size is 2 words on all platforms */
} gtm_time8;
typedef uint4 gtm_time4_t;
typedef struct
{
sm_off_t fl; /* forward link - relative offset from beginning of this element to next element in queue */
sm_off_t bl; /* backward link - relative offset from beginning of this element to previous element in queue */
} que_ent; /* this structure is intended to be identical to the first two items in a cache_que_head */
typedef struct
{
sm_off_t fl; /* forward link - relative offset from beginning of this element to next element in queue */
sm_off_t bl; /* backward link - relative offset from beginning of this element to previous element in queue */
global_latch_t latch; /* required for platforms without atomic operations to modify both fl and bl concurrently;
* unused on platforms with such instructions. */
} que_head, cache_que_head, mmblk_que_head;
#define IS_PTR_ALIGNED(ptr, ptr_base, elemSize) \
(0 == ((((sm_uc_ptr_t)(ptr)) - ((sm_uc_ptr_t)(ptr_base))) % elemSize))
#define IS_PTR_IN_RANGE(ptr, ptr_lo, ptr_hi) \
(((sm_uc_ptr_t)(ptr) >= (sm_uc_ptr_t)(ptr_lo)) && ((sm_uc_ptr_t)(ptr) < (sm_uc_ptr_t)(ptr_hi)))
#define IS_PTR_2BYTE_ALIGNED(ptr) (0 == (((uintszofptr_t)ptr) % 2))
#define IS_PTR_4BYTE_ALIGNED(ptr) (0 == (((uintszofptr_t)ptr) % 4))
#define IS_PTR_8BYTE_ALIGNED(ptr) (0 == (((uintszofptr_t)ptr) % 8))
#ifdef DB64
# ifdef __osf__
# pragma pointer_size(save)
# pragma pointer_size(long)
# else
# error UNSUPPORTED PLATFORM
# endif
#endif
typedef que_ent * que_ent_ptr_t;
typedef que_head * que_head_ptr_t;
#ifdef DB64
# ifdef __osf__
# pragma pointer_size(restore)
# endif
#endif
/* Define 8-bytes as a structure containing 2-byte array of uint4s. Overlay this structure upon an 8 byte quantity for easy
* access to the lower or upper 4 bytes using lsb_index and msb_index respectively.
*/
typedef struct
{
uint4 value[2];
} non_native_uint8;
# define BIG_ENDIAN_MARKER 'B' /* to denote BIG-ENDIAN machine */
# define LITTLE_ENDIAN_MARKER 'L' /* to denote LITTLE-ENDIAN machine */
#ifdef BIGENDIAN
# define msb_index 0
# define lsb_index 1
# define NODE_ENDIANNESS BIG_ENDIAN_MARKER
# define ENDIANTHIS "BIG"
# define ENDIANOTHER "LITTLE"
# define ENDIANTHISJUSTIFY " BIG" /* right justified */
# define GTM_IS_LITTLE_ENDIAN FALSE
# define BIGENDIAN_ONLY(X) X
# define LITTLEENDIAN_ONLY(X)
#else
# define msb_index 1
# define lsb_index 0
# define NODE_ENDIANNESS LITTLE_ENDIAN_MARKER
# define ENDIANTHIS "LITTLE"
# define ENDIANOTHER "BIG"
# define ENDIANTHISJUSTIFY "LITTLE" /* right justified */
# define GTM_IS_LITTLE_ENDIAN TRUE
# define BIGENDIAN_ONLY(X)
# define LITTLEENDIAN_ONLY(X) X
#endif
#ifdef INT8_SUPPORTED
typedef gtm_uint64_t qw_num;
typedef gtm_uint64_t seq_num; /* Define 8-byte sequence number */
typedef gtm_uint64_t token_num; /* Define 8-byte token number */
typedef gtm_uint64_t qw_off_t; /* quad-word offset */
# define DWASSIGNQW(A,B) (A)=(uint4)(B)
# define QWASSIGN(A,B) (A)=(B)
# define QWASSIGNDW(A,B) QWASSIGN((A),(gtm_uint64_t)(B))
# define QWASSIGN2DW(A,B,C) QWASSIGN((A),(gtm_uint64_t)(B) << 32 | (C))
# define QWADD(A,B,C) (A)=(B)+(C)
# define QWSUB(A,B,C) (A)=(B)-(C)
# define QWADDDW(A,B,C) (A)=(B)+(gtm_uint64_t)(C)
# define QWSUBDW(A,B,C) (A)=(B)-(gtm_uint64_t)(C)
# define QWINCRBY(A,B) (A)+=(B)
# define QWDECRBY(A,B) (A)-=(B)
# define QWINCRBYDW(A,B) (A)+=(gtm_uint64_t)(B)
# define QWDECRBYDW(A,B) (A)-=(gtm_uint64_t)(B)
# define QWMULBYDW(A,B,C) (A)=(B)*(C)
# define QWDIVIDEBYDW(A,B,Q,R) {(R)=(int)((A)%(B)); (Q)=(A)/(B);}
# define QWMODDW(A,B) ((A)%(B))
# define QWLE(A,B) ((A)<=(B))
# define QWLT(A,B) ((A)<(B))
# define QWGE(A,B) ((A)>=(B))
# define QWGT(A,B) ((A)>(B))
# define QWEQ(A,B) ((A)==(B))
# define QWNE(A,B) ((A)!=(B))
# define INT8_PRINT(x) x
# define INT8_PRINTX(x) x
# define INT8_ONLY(x) x
#else
typedef struct non_native_uint8 qw_num;
typedef struct non_native_uint8 seq_num;
typedef struct non_native_uint8 token_num;
typedef struct non_native_uint8 qw_off_t;
# define DWASSIGNQW(A,B) (A)=(B).value[lsb_index]
# define QWASSIGN(A,B) (A)=(B)
# define QWASSIGNDW(A,B) {(A).value[msb_index]=0; (A).value[lsb_index]=B;}
# define QWASSIGN2DW(A,B,C) {(A).value[msb_index]=B; (A).value[lsb_index]=C;}
# define QWADD(A,B,C) { \
uint4 temp; \
temp = (B).value[lsb_index]; \
(A).value[lsb_index]=(B).value[lsb_index]+(C).value[lsb_index]; \
(A).value[msb_index]=(B).value[msb_index]+(C).value[msb_index]; \
if ((A).value[lsb_index] < temp) (A).value[msb_index]++; \
}
# define QWSUB(A,B,C) { \
uint4 temp; \
temp = (B).value[lsb_index]; \
(A).value[lsb_index]=(B).value[lsb_index]-(C).value[lsb_index]; \
(A).value[msb_index]=(B).value[msb_index]-(C).value[msb_index]; \
if ((A).value[lsb_index] > temp) (A).value[msb_index]--; \
}
# define QWADDDW(A,B,C) { \
uint4 temp; \
temp = (B).value[lsb_index]; \
(A).value[lsb_index]=(B).value[lsb_index]+C; \
(A).value[msb_index]=(B).value[msb_index]; \
if ((A).value[lsb_index] < temp) (A).value[msb_index]++; \
}
# define QWSUBDW(A,B,C) { \
uint4 temp; \
temp = (B).value[lsb_index]; \
(A).value[lsb_index]=(B).value[lsb_index]-(C); \
(A).value[msb_index]=(B).value[msb_index]; \
if ((A).value[lsb_index] > temp) (A).value[msb_index]--; \
}
# define QWINCRBY(A,B) QWADD(A,A,B)
# define QWDECRBY(A,B) QWSUB(A,A,B)
# define QWINCRBYDW(A,B) QWADDDW(A,A,B)
# define QWDECRBYDW(A,B) QWSUBDW(A,A,B)
/* B should be less than 64K for the QWDIDIVEBYDW, QWMODDW macros to work correctly */
# define QWMULBYDW(A,B,C) { \
uint4 bh, bl, ch, cl, temp, temp1, temp2; \
(A).value[msb_index] = (B).value[msb_index] * (C); \
bl = (B).value[lsb_index] & 0x0000ffff; \
bh = ((B).value[lsb_index] & 0xffff0000) >> 16; \
cl = (C) & 0x0000ffff; \
ch = ((C) & 0xffff0000) >> 16; \
(A).value[msb_index] += bh * ch; \
(A).value[lsb_index] = bl * cl; \
temp = temp1 = bh * cl; \
temp += bl * ch; \
if (temp1 > temp) \
(A).value[msb_index] += 0x00010000; \
temp2 = (A).value[lsb_index]; \
(A).value[lsb_index] += (temp & 0x0000ffff) << 16; \
if ((A).value[lsb_index] < temp2) \
(A).value[msb_index] ++; \
(A).value[msb_index] += (temp & 0xffff0000) >> 16; \
}
# define QWDIVIDEBYDW(A,B,Q,R) { \
uint4 msbr, lsbq, twoq, twor; \
(R) = (A).value[lsb_index] % (B); \
lsbq = (A).value[lsb_index] / (B); \
msbr = A.value[msb_index] % B; \
(Q).value[msb_index] = (A).value[msb_index] / (B); \
twoq = ((uint4)-1) / (B); \
twor = (((uint4)-1) % (B) + 1) % (B); \
if (0 == twor) \
twoq++; \
(Q).value[lsb_index] = lsbq; \
(Q).value[lsb_index] += twoq * msbr; \
if ((Q).value[lsb_index] < lsbq) \
(Q).value[msb_index]++; \
(R) = (R) + (twor * msbr) % (B); \
lsbq = (Q).value[lsb_index]; \
(Q).value[lsb_index] += (twor * msbr) / (B); \
if ((R) > (B)) \
{ \
(R) -= (B); \
(Q).value[lsb_index]++; \
} \
if ((Q).value[lsb_index] < lsbq) \
(Q).value[msb_index]++; \
}
# define QWMODDW(A,B) ((((A).value[msb_index] % (B)) * (((uint4)-1) % (B) + 1) \
+ (A).value[lsb_index]) % (B))
# define QWLE(A,B) ((A).value[msb_index] < (B).value[msb_index] || \
((A).value[msb_index] == (B).value[msb_index] \
&& (A).value[lsb_index] <= (B).value[lsb_index]))
# define QWLT(A,B) ((A).value[msb_index] < (B).value[msb_index] || \
((A).value[msb_index] == (B).value[msb_index] \
&& (A).value[lsb_index] < (B).value[lsb_index]))
# define QWGE(A,B) ((A).value[msb_index] > (B).value[msb_index] || \
((A).value[msb_index] == (B).value[msb_index] \
&& (A).value[lsb_index] >= (B).value[lsb_index]))
# define QWGT(A,B) ((A).value[msb_index] > (B).value[msb_index] || \
((A).value[msb_index] == (B).value[msb_index] \
&& (A).value[lsb_index] > (B).value[lsb_index]))
# define QWEQ(A,B) ((A).value[msb_index] == (B).value[msb_index] \
&& (A).value[lsb_index] == (B).value[lsb_index])
# define QWNE(A,B) ((A).value[msb_index] != (B).value[msb_index] \
|| (A).value[lsb_index] != (B).value[lsb_index])
# define INT8_FMT "%s"
# define INT8_FMTX "[0x%s]"
# define INT8_PRINT(x) (seq_num_ptr = i2ascl(seq_num_str, x), \
seq_num_str[seq_num_ptr - &seq_num_str[0]] = '\0', seq_num_str)
# define INT8_PRINTX(x) (seq_num_ptrx = i2asclx(seq_num_strx, x), \
seq_num_strx[seq_num_ptrx - &seq_num_strx[0]] = '\0', seq_num_strx)
# define INT8_ONLY(x)
#endif
#define MAX_SEQNO ((seq_num)-1) /* actually 0xFFFFFFFFFFFFFFFF (max possible seqno) */
/* The HPUX Itanium compiler is giving warnings whenever a cast is being done and there is a potential alignment change */
/* The RECAST macro will eliminate these warnings by first casting to (void *) before the doing the ultimate cast */
#define RECAST(type) (type)(void_ptr_t)
/* Define some basic types for shared memory (sm) access depending on whether the platform we are */
/* using is capable of supporting 32 or 64 bit pointers or not. */
#if defined(DB64) || defined(GTM64)
# if defined(__osf__) && defined(__alpha)
# pragma pointer_size(save)
# pragma pointer_size(long)
# endif
typedef char *char_ptr_t; /* Define 64 bit pointer to char */
typedef unsigned char *uchar_ptr_t; /* Define 64 bit pointer to unsigned char */
typedef short *short_ptr_t; /* Define 64 bit pointer to short */
typedef unsigned short *ushort_ptr_t; /* Define 64 bit pointer to unsigned short */
typedef int4 *int_ptr_t; /* Define 64 bit pointer to int */
typedef volatile int4 *vint_ptr_t; /* Define 64 bit pointer to volatile int */
typedef uint4 *uint_ptr_t; /* Define 64 bit pointer to uint */
typedef volatile uint4 *vuint_ptr_t; /* Define 64 bit pointer to volatile uint */
typedef void *void_ptr_t; /* Define 64 bit pointer to void */
typedef qw_num *qw_num_ptr_t; /* Define 64 bit pointer to qw_num */
typedef latch_t *latch_ptr_t; /* Define 64 bit pointer to latch_t */
typedef ulatch_t *ulatch_ptr_t; /* Define 64 bit pointer to ulatch_t */
/* Shared memory connotation */
typedef char_ptr_t sm_c_ptr_t; /* Define 64 bit pointer to char */
typedef uchar_ptr_t sm_uc_ptr_t; /* Define 64 bit pointer to unsigned char */
typedef short_ptr_t sm_short_ptr_t; /* Define 64 bit pointer to short */
typedef ushort_ptr_t sm_ushort_ptr_t; /* Define 64 bit pointer to unsigned short */
typedef int_ptr_t sm_int_ptr_t; /* Define 64 bit pointer to int */
typedef vint_ptr_t sm_vint_ptr_t; /* Define 64 bit pointer to volatile int */
typedef uint_ptr_t sm_uint_ptr_t; /* Define 64 bit pointer to uint */
typedef vuint_ptr_t sm_vuint_ptr_t; /* Define 64 bit pointer to volatile uint */
typedef gtm_int64_t sm_long_t; /* Define 64 bit integer type */
typedef gtm_uint64_t sm_ulong_t; /* Define 64 bit unsigned integer type */
typedef global_latch_t *sm_global_latch_ptr_t; /* Define 64 bit pointer to hp_latch */
# ifdef __osf__
# pragma pointer_size(restore)
# endif
/* The macro FILL8DCL (explained below) is simple on a 64 bit system since all 64 bits
will be declared and used. */
# define FILL8DCL(type,name,fillnum) type name
#else
typedef char *char_ptr_t; /* Define 32 bit pointer to char */
typedef unsigned char *uchar_ptr_t; /* Define 32 bit pointer to unsigned char */
typedef short *short_ptr_t; /* Define 32 bit pointer to short */
typedef unsigned short *ushort_ptr_t; /* Define 32 bit pointer to unsigned short */
typedef int4 *int_ptr_t; /* Define 32 bit pointer to int */
typedef volatile int4 *vint_ptr_t; /* Define 32 bit pointer to volatile int */
typedef uint4 *uint_ptr_t; /* Define 32 bit pointer to uint */
typedef volatile uint4 *vuint_ptr_t; /* Define 32 bit pointer to volatile uint */
typedef void *void_ptr_t; /* Define 32 bit pointer to void */
typedef qw_num *qw_num_ptr_t; /* Define 32 bit pointer to qw_num */
typedef latch_t *latch_ptr_t; /* Define 32 bit pointer to latch_t */
typedef ulatch_t *ulatch_ptr_t; /* Define 32 bit pointer to ulatch_t */
/* Shared memory connotation */
typedef char_ptr_t sm_c_ptr_t; /* Define 32 bit pointer to char */
typedef uchar_ptr_t sm_uc_ptr_t; /* Define 32 bit pointer to unsigned char */
typedef short_ptr_t sm_short_ptr_t; /* Define 32 bit pointer to short */
typedef ushort_ptr_t sm_ushort_ptr_t; /* Define 32 bit pointer to unsigned short */
typedef int_ptr_t sm_int_ptr_t; /* Define 32 bit pointer to int */
typedef vint_ptr_t sm_vint_ptr_t; /* Define 32 bit pointer to volatile int */
typedef uint_ptr_t sm_uint_ptr_t; /* Define 32 bit pointer to uint */
typedef vuint_ptr_t sm_vuint_ptr_t; /* Define 32 bit pointer to volatile uint */
typedef INTPTR_T sm_long_t; /* Define 32 bit integer type */
typedef UINTPTR_T sm_ulong_t; /* Define 32 bit unsigned integer type */
typedef global_latch_t *sm_global_latch_ptr_t; /* Define 32 bit pointer to hp_latch */
/* The macro FILL8DCL is used (on a 32 bit system) to provide a filler area of 32 bits and
the actual 32 bit declared area. Whether the high order word or the low order word of
the 64 bit area should be filler depends on the endian mode of the machine. This macro
will be defined to take care of that for us. */
# ifdef BIGENDIAN
# define FILL8DCL(type,name,fillnum) type fill##fillnum,name
# else
# define FILL8DCL(type,name,fillnum) type name,fill##fillnum
# endif
#endif
/* Need to define a type for storing pointer differences */
typedef INTPTR_T ptroff_t;
/* Need to define a consistently sized off_t type. Some platforms it is 4 bytes, others it is
4 or 8 bytes depending on flags. The following OFF_T macro is setup to allow the size of the
variable declared by it to always take up 8 bytes for alignment purposes. If the OFF_T_LONG
value is set, we will expect the size of 'off_t' to be 8 bytes. An assert will be placed in
gtm.c to verify this. */
#ifdef OFF_T_LONG
# define OFF_T(name,fillnum) off_t name
#else
# define OFF_T(name,fillnum) FILL8DCL(off_t,name,fillnum)
#endif
/* Type for offsets in journal files. VMS uses uint4 to get a full 32 bit
offset for large journal files (OK since doesn't use lseek/etc. for IO.) */
#ifdef OFF_T_LONG
# define JNL_OFF_T(name,fillnum) off_t name
#else
# ifdef VMS
# define JNL_OFF_T(name,fillnum) FILL8DCL(uint4,name,fillnum)
# else
# define JNL_OFF_T(name,fillnum) FILL8DCL(off_t,name,fillnum)
# endif
#endif
/* Need to define a consistently sized counter that is controlled by interlocks. The counter
will occupy 4 bytes in the file header but on some platforms (currently VAX and AXP VMS),
these counters need to be shorts whereas other platforms would realize a performance
improvement if they were 32 bits long. So we create another macro in the spirit of the
FILL8DCL macro above which will always give us a 32 byte entity but will pad a 2 byte
addressable entity if necessary. If not specified, the default is for 'short' counters. */
# ifdef CNTR_WORD_32
# define FILL4DCL(type,name,fillnum) type name
# define CNTR4DCL(name,fillnum) int4 name
# else
# ifdef BIGENDIAN
# define FILL4DCL(type,name,fillnum) type fill##fillnum,name
# else
# define FILL4DCL(type,name,fillnum) type name,fill##fillnum
# endif
# define CNTR4DCL(name,fillnum) FILL4DCL(short,name,fillnum)
# endif
/* For machines with a cache line dependency for locks and such,
define a macro that can be used to generate padding such that
fields are in separate cache lines. Note that this macro should
*NOT* be used in the fileheader as its length expansion is platform
specific. It should only be used in internal shared memory
structures that are NOT otherwise placement sensitive.
A ; is included in the definition instead of when used since an extra ;
in a structure is not accepted by some compilers.
*/
#ifdef CACHELINE_SIZE
# define CACHELINE_PAD(fieldSize, fillnum) char fill_cacheline##fillnum[CACHELINE_SIZE - (fieldSize)];
#else
# define CACHELINE_PAD(fieldSize, fillnum)
#endif
/* In certain cases we need to conditionally do a CACHELINE pad. For those platforms that
have load-locked/store-conditional logic, counters that are incremented under interlock
need to have spacing so they do not interfere with each other. But platforms that do
NOT have this capability need the spacing on the actual latch used instead. Hence this
form of padding is conditional.
*/
#if defined(__alpha) || defined(_AIX)
# define CACHELINE_PAD_COND(fieldSize, fillnum) CACHELINE_PAD(fieldSize, fillnum)
#else
# define CACHELINE_PAD_COND(fieldSize, fillnum)
#endif
#define MEMCP(dst,src,start,count,limit){ \
if (start+count > limit) \
rts_error(VARLSTCNT(1) ERR_CPBEYALLOC); \
else \
memcpy(dst+start,src,count); \
}
#ifndef USING_ICONV
typedef enum
{
NO_XLAT = 0,
EBCDIC_TO_ASCII,
ASCII_TO_EBCDIC
} gtm_iconv_t;
#define iconv_t gtm_iconv_t
#endif
#ifdef _AIX
# define VSIG_ATOMIC_T sig_atomic_t
#else
# define VSIG_ATOMIC_T volatile sig_atomic_t
#endif
/* For copying va_list items - Linux/390 needs __va_copy */
#ifndef VAR_COPY
#define VAR_COPY(dst, src) dst = src
#endif
#define NOLICENSE /* cheap way to obsolete it */
/* integer conversion functions */
void i2hex(UINTPTR_T val, uchar_ptr_t dest, int len);
void i2hexl(qw_num val, uchar_ptr_t dest, int len);
void i2hex_blkfill(int num, uchar_ptr_t addr, int len);
void i2hexl_blkfill(qw_num num, uchar_ptr_t addr, int len);
int i2hex_nofill(int num, uchar_ptr_t addr, int len);
int i2hexl_nofill(qw_num num, uchar_ptr_t addr, int len);
uchar_ptr_t i2ascl(uchar_ptr_t p, qw_num n);
uchar_ptr_t i2asclx(uchar_ptr_t p, qw_num n);
uchar_ptr_t i2asc(uchar_ptr_t p, unsigned int n);
/* ascii conversion functions */
int4 asc2i(uchar_ptr_t p, int4 len);
qw_num asc2l(uchar_ptr_t p, int4 len);
unsigned int asc_hex2i(char *p, int len);
/* This macro converts an integer to a decimal string (a more efficient alternative to i2asc).
* It is used by format2zwr() which is called a lot during MUPIP EXTRACT (which can be time-consuming
* for a big database), hence the need to make it efficient.
*/
#define I2A(des, des_len, num) \
{ \
if ((unsigned)(num) < 1000) \
{ /* perform light-weight conversion of numbers upto 3 digits */ \
int n1, n2; /* digits at the 10th and 100th decimal positions respectively */ \
n2 = ((num) / 100) % 10; \
if (0 != n2) \
(des)[(des_len)++] = n2 + '0'; \
n1 = ((num) / 10) % 10; \
if (0 != n1 || 0 != n2) \
(des)[(des_len)++] = n1 + '0'; \
(des)[(des_len)++] = ((num) % 10) + '0'; \
} else \
des_len += (int)(i2asc((uchar_ptr_t)((des) + des_len), num) - (uchar_ptr_t)((des) + des_len)); \
}
/* The following is similar to I2A except that it updates the input pointer directly (no length parameter needed) */
#define I2A_INLINE(des, num) \
{ \
if ((unsigned)(num) < 1000) \
{ /* perform light-weight conversion of numbers upto 3 digits */ \
int n1, n2; /* digits at the 10th and 100th decimal positions respectively */ \
n2 = ((num) / 100) % 10; \
if (0 != n2) \
*des++ = n2 + '0'; \
n1 = ((num) / 10) % 10; \
if (0 != n1 || 0 != n2) \
*des++ = n1 + '0'; \
*des++ = ((num) % 10) + '0'; \
} else \
des = (char *)i2asc((uchar_ptr_t)des, num); \
}
/* This macro converts a decimal string to a number (a more efficient alternative to asc2i).
* It is used by zwr2format() and str2gvargs which is called a lot during MUPIP LOAD (can be time-consuming for a big database).
*/
#define A2I(cp, end, num) \
{ \
unsigned char *cpbase = (unsigned char*)(cp); \
char ch; \
\
for (num = 0; (cp) < (end) && ('0' <= (ch = *((unsigned char*)cp))) && ('9' >= ch); ++(cp)) \
num = (num) * 10 + (ch - '0'); \
if (cpbase == ((unsigned char*)cp)) \
num = -1; \
}
void double2s(double *dp, mval *v); /* double conversion */
int skpc(char c, int length, char *string);
/* If the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */
void *gtm_malloc(size_t size);
/* If the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */
void gtm_free(void *addr);
int gtm_memcmp (const void *, const void *, size_t);
DEBUG_ONLY(void printMallocInfo(void);)
int is_equ(mval *u, mval *v);
char is_ident(mstr *v);
int val_iscan(mval *v);
void mcfree(void);
int4 getprime(int4 n);
void push_parm(UNIX_ONLY_COMMA(unsigned int totalcnt) int truth_value, ...);
void suspend(void);
mval *push_mval(mval *arg1);
void mval_lex(mval *v, mstr *output);
#define ZTRAP_CODE 0x00000001
#define ZTRAP_ENTRYREF 0x00000002
#define ZTRAP_POP 0x00000004
#define ZTRAP_ADAPTIVE (ZTRAP_CODE | ZTRAP_ENTRYREF)
#define GTM_BYTESWAP_16(S) \
( (((S) & 0xff00) >> 8) \
| (((S) & 0x00ff) << 8) \
)
#define GTM_BYTESWAP_24(L) \
( (((L) & 0xff0000) >> 16) \
| ((L) & 0x00ff00) \
| (((L) & 0x0000ff) << 16) \
)
#define GTM_BYTESWAP_32(L) \
( (((L) & 0xff000000) >> 24) \
| (((L) & 0x00ff0000) >> 8) \
| (((L) & 0x0000ff00) << 8) \
| (((L) & 0x000000ff) << 24) \
)
qw_num gtm_byteswap_64(qw_num num64);
#ifdef INT8_SUPPORTED
#define GTM_BYTESWAP_64(LL) \
( (((LL) & 0xff00000000000000ull) >> 56) \
| (((LL) & 0x00ff000000000000ull) >> 40) \
| (((LL) & 0x0000ff0000000000ull) >> 24) \
| (((LL) & 0x000000ff00000000ull) >> 8) \
| (((LL) & 0x00000000ff000000ull) << 8) \
| (((LL) & 0x0000000000ff0000ull) << 24) \
| (((LL) & 0x000000000000ff00ull) << 40) \
| (((LL) & 0x00000000000000ffull) << 56) \
)
#else
#define GTM_BYTESWAP_64(LL) gtm_byteswap_64(LL)
#endif
#define ZDIR_FORM_FULLPATH 0x00000000
#define ZDIR_FORM_DIRECTORY 0x00000001
#define IS_VALID_ZDIR_FORM(zdirform) (ZDIR_FORM_FULLPATH == (zdirform) || ZDIR_FORM_DIRECTORY == (zdirform))
#define MAXNUMLEN 128 /* from PV_N2S */
#define CENTISECONDS 100 /* VMS lib$day returns 1/100s, we want seconds, use this factor to convert b/n the two */
#define MINUTE 60 /* seconds in a minute */
#define HOUR 3600 /* one hour in seconds 60 * 60 */
#define ONEDAY 86400 /* seconds in a day */
#define MILLISECS_IN_SEC 1000 /* millseconds in a second */
#define MICROSEC_IN_SEC 1000000 /* microseconds in a second */
#define ASSERT_IN_RANGE(low, x, high) assert((low <= x) && (x <= high))
#if defined(VMS)
#define DAYS 6530 /* adjust VMS returned days by this amount; GTM zero time Dec 31, 1840, VMS zero time 7-NOV-1858 */
#define VARLSTCNT1(CNT) VARLSTCNT(CNT)
#define PUT_SYS_ERRNO(SYS_ERRNO) SYS_ERRNO
#elif defined(UNIX)
#define DAYS 47117 /* adjust Unix returned days (seconds converted to days); Unix zero time 1970 */
#define VARLSTCNT1(CNT) VARLSTCNT(CNT + 1)
#define PUT_SYS_ERRNO(SYS_ERRNO) 0, SYS_ERRNO
#else
#error Unsupported platform
#endif
#define EXIT_NRM 0
#define EXIT_INF 1
#define EXIT_WRN 2
#define EXIT_ERR 4
#define EXIT_RDONLY 8
#define EXIT_MASK 7
#define MIN_FN_LEN 1
#define MAX_FN_LEN 255
#define V4_MAX_FN_LEN 255 /* required for dbcertify.h */
#define MAX_TRANS_NAME_LEN 257
typedef uint4 jnl_tm_t;
typedef uint4 off_jnl_t;
typedef gtm_uint64_t gtm_off_t;
#define MAXUINT8 ((gtm_uint64_t)-1)
#define MAXUINT4 ((uint4)-1)
#define MAXUINT2 ((unsigned short)-1)
#define MAXINT2 (MAXUINT2/2)
/* On platforms that support native 8 byte operations (such as Alpha), an assignment to an 8 byte field is atomic. On other
* platforms, an 8 byte assignment is a sequence of 4 byte operations. On such platforms, use this macro to determine if the
* change from the current value to the new value provides a consistent view (entirely the pre read, or entirely the post read,
* and not in between). Any change that causes the most significant 4 bytes to differ can cause inconsistency. In such cases, it
* may be necessary to grab crit if modifying a shared field.
*/
#ifdef INT8_NATIVE
#define QWCHANGE_IS_READER_CONSISTENT(FROM8, TO8) (TRUE)
#else
/* Note: cannot use this macro when FROM8 or TO8 do not have an lvalue (eg. literal) */
#define QWCHANGE_IS_READER_CONSISTENT(FROM8, TO8) (((non_native_uint8 *)&(FROM8))->value[msb_index] \
== ((non_native_uint8 *)&(TO8))->value[msb_index])
#endif
#define MAX_SUPPL_STRMS 16 /* max # of non-supplementary streams that can connect to a supplementary root primary */
#ifdef UNIX /* Replication instance file related structures */
/* The below macros and typedef are required in "repl_instance.h", "gtmsource.h", "gtmrecv.h" and "repl_msg.h".
* They are hence included in this common header file
*/
#define MAX_INSTNAME_LEN 16 /* Max Length of the replication instance name including terminating null character '\0' */
#define NUM_GTMSRC_LCL 16 /* max number of source servers that can run on a root primary instance.
* also the number of gtmsrc_lcl structures in the replication instance file */
#define NUM_GTMRCV_LCL 16 /* max number of receiver servers that can run at the same time on a supplementary
* root primary instance. On a non-supplementary instance, only 1 receiver server can run */
#define INVALID_SUPPL_STRM -1 /* stream #s 0 to 15 are the valid ones */
#define REPL_INST_HDR_SIZE (SIZEOF(repl_inst_hdr))
#define GTMSRC_LCL_SIZE (SIZEOF(gtmsrc_lcl) * NUM_GTMSRC_LCL) /* size of the gtmsrc_lcl array */
#define GTMSOURCE_LOCAL_SIZE (SIZEOF(gtmsource_local_struct) * NUM_GTMSRC_LCL) /* size of the gtmsource_local array */
#define REPL_INST_HISTINFO_START (REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE)
/* Although we have dedicated 60-bits for the stream specific seqno, it is still a very high value and should not be reached
* in practice. Therefore, we arbitrarily pick 48-bits as the maximum value for this seqno and assert that the remaining 12 bits
* are zero in at least our test environments. This way we catch any uninitialized/garbage value usages of this seqno in the code.
*/
#define IS_VALID_STRM_SEQNO(SEQNO) (0 == (SEQNO & 0x0FFF000000000000LLU))
/* Given a strm_seqno, determine the corresponding stream# by getting the most significant 4 bits of the 64-bit seqno */
#define GET_STRM_INDEX(SEQNO) (DBG_ASSERT(IS_VALID_STRM_SEQNO(SEQNO)) \
(((SEQNO) >> 60) & 0xF))
/* Given a 64-bit strm_seqno, determine the corresponding 60-bit stream specific seqno. */
#define GET_STRM_SEQ60(SEQNO) (DBG_ASSERT(IS_VALID_STRM_SEQNO(SEQNO)) \
((SEQNO) & (0x0FFFFFFFFFFFFFFFLLU)))
/* Given a 60-bit strm_seqno and 4-bit stream#, this macro returns a unified 64-bit sequence number */
#define SET_STRM_INDEX(SEQNO, STRM_NO) (DBG_ASSERT(0 == GET_STRM_INDEX(SEQNO)) \
DBG_ASSERT((STRM_NO) <= 0xF) \
((SEQNO) | (((seq_num)STRM_NO) << 60)))
#define MAX_NODENAME_LEN 16 /* used by repl_instance.h. A similar macro JPV_LEN_NODE is defined in jnl.h */
#define UNKNOWN_INSTNAME "<UNKNOWN>" /* used in places where instance name is not known (e.g. if pre-V51000 version) */
/* The following defines the structure holding the instance information in a replication instance file.
* Any changes to this structure might need changes to the ENDIAN_CONVERT_REPL_INST_UUID macro.
*/
typedef struct repl_inst_uuid_struct
{
unsigned char created_nodename[MAX_NODENAME_LEN]; /* Nodename on which instance file was created */
unsigned char this_instname[MAX_INSTNAME_LEN]; /* Instance name that this file corresponds to */
uint4 created_time; /* Time when this instance file was created */
uint4 creator_pid; /* Process id that created the instance file */
} repl_inst_uuid;
/* Macro to endian convert an entire "repl_inst_uuid" structure contents given a pointer to the structure */
#define ENDIAN_CONVERT_REPL_INST_UUID(PTR) \
{ \
/* No need to convert "created_nodename" as it is a character array */ \
/* No need to convert "this_instname" as it is a character array */ \
/* Endian convert 4-byte "created_time" */ \
(PTR)->created_time = GTM_BYTESWAP_32((PTR)->created_time); \
/* Endian convert 4-byte "creator_pid" */ \
(PTR)->creator_pid = GTM_BYTESWAP_32((PTR)->creator_pid); \
}
/* A NULL UUID is denoted by a 0 value for created_time. In that case, other fields are uninitialized and hence unusable.
* A non-NULL UUID has a non-zero value for created_time. In that case, other fields are guaranteed to have been initialized.
*/
#define IS_REPL_INST_UUID_NULL(UUID) (0 == (UUID).created_time)
#define IS_REPL_INST_UUID_NON_NULL(UUID) (!IS_REPL_INST_UUID_NULL(UUID))
#define NULL_INITIALIZE_REPL_INST_UUID(UUID) (UUID).created_time = 0
/* Lot of code (e.g. repl_inst_dump) relies on "created_nodename" (which can be a string upto MAX_NODENAME_LEN bytes long)
* being NOT null-terminated at the (MAX_NODENAME_LEN - 1)th byte ONLY if the node name length is LESS THAN the max length.
* This lets them avoid a scan of the string (to find the real length) in the null-terminated case and safely pass it to
* any function (e.g. printf etc.) that expects a null-terminated string. Verify that using the below assert.
*/
#ifdef DEBUG
#define DBG_CHECK_CREATED_NODENAME(PTR) \
{ \
int index, last_byte_non_null; \
char *lclPtr = (char *)PTR; \
\
last_byte_non_null = lclPtr[MAX_NODENAME_LEN -1]; \
if (last_byte_non_null) \
{ \
for (index = 0; index < MAX_NODENAME_LEN; index++) \
{ \
if (!lclPtr[index]) \
assert(FALSE); \
} \
} \
}
#else
#define DBG_CHECK_CREATED_NODENAME(PTR)
#endif
/* The following macros define what value the "histinfo_type" member of the repl_histinfo structure gets filled in with */
#define HISTINFO_TYPE_NORMAL 1 /* A history record generated whenever a root primary starts up */
#define HISTINFO_TYPE_UPDRESYNC 2 /* A history record generated when a receiver server starts up with -UPDATERESYNC on
* a supplementary root primary instance.
*/
#define HISTINFO_TYPE_NORESYNC 3 /* A history record generated when a receiver server starts up with -NORESYNC.
* Used by a propagating primary supplementary instance to know that "prev_histinfo_num"
* has to be recomputed on the receiver side.
*/
/* The following defines the structure of a history record in the instance file.
* Any changes to this structure might need changes to the ENDIAN_CONVERT_REPL_HISTINFO macro.
*/
typedef struct repl_histinfo_struct
{ /* Each history record is uniquely defined by the following 5 fields (consider start_seqno and strm_seqno as one field) */
unsigned char root_primary_instname[MAX_INSTNAME_LEN];/* the root primary instance that generated this history record */
seq_num start_seqno; /* the first seqno generated in this history record by the
* root primary. In case of a supplementary instance, this
* seqno is the unified seqno across all streams.
*/
seq_num strm_seqno; /* the stream specific jnl seqno. this will help identify which
* of the potentially 16 streams (0 for local instance, 1 to 15 for
* non-local streams) this history record corresponds to.
*/
uint4 root_primary_cycle; /* a copy of the "root_primary_cycle" field in the instance file
* header of the root primary when it generated the seqno
* "start_seqno". This is needed to distinguish two invocations
* of the same instance
*/
uint4 creator_pid; /* pid on rootprimary instance that wrote this history record */
uint4 created_time; /* time on rootprimary when this history record was generated */
int4 histinfo_num; /* = 'n' if this is the n'th history record in the instance file */
int4 prev_histinfo_num; /* = 'n' if the previous history record corresponding to this
* stream is the n'th history record in the instance file.
*/
char strm_index; /* = 0 by default.
* = anywhere from 1 to 15 if this history record corresponds to a
* non-supplementary stream of updates.
*/
char history_type; /* can take any one of the HISTINFO_TYPE_* macro values */
char filler_8[2]; /* Filler for 8-byte alignment */
repl_inst_uuid lms_group; /* Non-null only if this instance file is supplementary AND if
* the history record has "strm_index" greater than 0.
* Null otherwise. In the non-null case, this field stores
* the lms group uuid for this particular non-supplementary
* stream. The "created_time" field will be non-zero in this case
* else zero (this field will be used to determine whether the
* "lms_group" member is valid or not given a history record).
*/
int4 last_histinfo_num[MAX_SUPPL_STRMS]; /* a copy of the last_histinfo_num[] array from the instance file
* header BEFORE this history record was added to the instance file.
*/
} repl_histinfo;
/* Macro to endian convert an entire "repl_inst_uuid" structure contents given a pointer to the structure */
#define ENDIAN_CONVERT_REPL_HISTINFO(PTR) \
{ \
/* No need to convert "root_primary_instname" as it is a character array */ \
/* Endian convert 8-byte "start_seqno" */ \
(PTR)->start_seqno = GTM_BYTESWAP_64((PTR)->start_seqno); \
/* Endian convert 8-byte "strm_seqno" */ \
(PTR)->strm_seqno = GTM_BYTESWAP_64((PTR)->strm_seqno); \
/* Endian convert 4-byte "root_primary_cycle" */ \
(PTR)->root_primary_cycle = GTM_BYTESWAP_32((PTR)->root_primary_cycle); \
/* Endian convert 4-byte "creator_pid" */ \
(PTR)->creator_pid = GTM_BYTESWAP_32((PTR)->creator_pid); \
/* Endian convert 4-byte "created_time" */ \
(PTR)->created_time = GTM_BYTESWAP_32((PTR)->created_time); \
/* Endian convert 4-byte "histinfo_num" */ \
(PTR)->histinfo_num = GTM_BYTESWAP_32((PTR)->histinfo_num); \
/* Endian convert 4-byte "prev_histinfo_num" */ \
(PTR)->prev_histinfo_num = GTM_BYTESWAP_32((PTR)->prev_histinfo_num); \
/* No need to convert "strm_index" as it is a 1-byte character */ \
/* No need to convert "history_type" as it is a 1-byte character */ \
/* Endian convert "lms_group" of type "repl_inst_uuid" */ \
ENDIAN_CONVERT_REPL_INST_UUID(&((PTR)->lms_group)); \
/* No need to endian convert "last_histinfo_num" as this is not relevant \
* across a replication connection and is regenerated on the receiver anyways. \
*/ \
}
#define INVALID_HISTINFO_NUM -1 /* 0 is a valid history record number (first element of array) so set it to -1 */
#define UNKNOWN_HISTINFO_NUM -2 /* Special value to indicate there is a history record but is not yet part of the
* replication instance file and hence does not have a history number yet (this is
* assigned by the function "repl_inst_histinfo_add" only when it adds this history
* record to the instance file on the receiving instance). This is possible for
* example if the history record is in the receive pool waiting for it to be played
* by the update process. Currently used by a propagating primary supplementary instance.
*/
/* The following two macros convert a history record from that of a non-supplementary instance to a supplementary instance
* and vice versa. The "start_seqno" and "strm_seqno" fields are the ones which are manipulated in these conversions.
*/
#define CONVERT_NONSUPPL2SUPPL_HISTINFO(HISTINFO, JNLPOOL_CTL) \
{ \
/* Until now "start_seqno" actually corresponded to the non-supplementary stream's seqno. \
* Now that we are writing this history record into a supplementary instance file, switch it \
* to be the supplementary seqno (jnlpool_ctl->jnl_seqno). Until now "strm_seqno" was 0. \
* Now switch that to be what "start_seqno" was before. \
*/ \
assert(0 < (HISTINFO)->strm_index); \
assert(MAX_SUPPL_STRMS > (HISTINFO)->strm_index); \
assert(0 == (HISTINFO)->strm_seqno); \
(HISTINFO)->strm_seqno = (HISTINFO)->start_seqno; \
(HISTINFO)->start_seqno = (JNLPOOL_CTL)->jnl_seqno; \
}
#define CONVERT_SUPPL2NONSUPPL_HISTINFO(HISTINFO) \
{ \
/* This macro is invoked just before sending a non-supplementary stream history record \
* in a supplementary instance back to a non-supplementary instance. The latter does not \
* understand strm_seqnos hence the need to convert. \
*/ \
assert(0 < (HISTINFO).strm_index); \
assert(MAX_SUPPL_STRMS > (HISTINFO).strm_index); \
assert((HISTINFO).strm_seqno); \
(HISTINFO).start_seqno = (HISTINFO).strm_seqno; \
(HISTINFO).strm_seqno = 0; \
}
/* A structure to hold ALL aspects of ONE side (could be local or remote) of a replication connection */
typedef struct repl_conn_info_struct
{
int4 proto_ver; /* The replication communication protocol version of this side of the pipe.
* Needs to be "signed" in order to be able to do signed comparisons of this with
* the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1)
*/
uint4 jnl_ver; /* Format of the journal records */
boolean_t is_std_null_coll; /* TRUE if M-standard null collation; FALSE if GT.M null collation */
boolean_t trigger_supported; /* TRUE if supports triggers; FALSE otherwise */
boolean_t cross_endian; /* TRUE if both sides of the replication connection have different endianness */
boolean_t endianness_known; /* TRUE if endianness of other side is known/determined; FALSE until then */
boolean_t null_subs_xform; /* 0 if the null subscript collation is same between the servers
* Non-zero (GTMNULL_TO_STDNULL_COLL or STDNULL_TO_GTMNULL_COLL) if different
*/
boolean_t is_supplementary; /* Whether one side of the connection is a supplementary instance */
} repl_conn_info_t;
#endif /* Replication instance file related structures */
/* Enumerator codes for supported CHSETs in GT.M */
typedef enum
{
CHSET_M,
CHSET_UTF8,
CHSET_UTF16,
CHSET_UTF16LE,
CHSET_UTF16BE,
CHSET_ASCII,
CHSET_EBCDIC,
CHSET_BINARY,
CHSET_MAX_IDX_ALL /* maximum number of CHSETs supported */
} gtm_chset_t;
#define CHSET_UTF_MIN CHSET_UTF8
#define CHSET_UTF_MAX CHSET_UTF16BE
#define CHSET_MAX_IDX CHSET_ASCII /* max true CHSETs */
#define IS_UTF16_CHSET(chset) ((CHSET_UTF16 == (chset)) || (CHSET_UTF16LE == (chset)) || (CHSET_UTF16BE == (chset)))
#define IS_UTF_CHSET(chset) ((CHSET_UTF_MIN <= (chset)) && (CHSET_UTF_MAX >= (chset)))
#define CHK_BOUNDARY_ALIGNMENT(pointer) (((UINTPTR_T)pointer) & (SIZEOF(UINTPTR_T) - 1))
#if defined(__ia64) || defined(__i386) || defined(__x86_64__) || defined(__sparc) || defined(_AIX) || defined(__MVS__) \
|| defined(__s390__)
#define GTM_CRYPT
#define GTMCRYPT_ONLY(X) X
#else
#define GTMCRYPT_ONLY(X)
#endif
#define GTMCRYPT_HASH_LEN 64
#define GTMCRYPT_HASH_HEX_LEN GTMCRYPT_HASH_LEN * 2
#define GTMCRYPT_RESERVED_HASH_LEN 256
#define GET_HASH_IN_HEX(in, out, len) \
{ \
int i; \
\
assert(0 == len % 2); \
for (i = 0; i < len; i+=2) \
SPRINTF((char *)out + i, "%02X", (unsigned char)in[i/2]); \
}
#ifdef UNIX
# define GTM_SNAPSHOT
# define NON_GTM_SNAPSHOT_ONLY(X)
# define GTM_SNAPSHOT_ONLY(X) X
#else
# define NON_GTM_SNAPSHOT_ONLY(X) X
# define GTM_SNAPSHOT_ONLY(X)
#endif
/* Currently MUPIP REORG -TRUNCATE is only supported on Unix */
#ifdef UNIX
# define GTM_TRUNCATE
# define NON_GTM_TRUNCATE_ONLY(X)
# define GTM_TRUNCATE_ONLY(X) X
#else
# define NON_GTM_TRUNCATE_ONLY(X) X
# define GTM_TRUNCATE_ONLY(X)
#endif
/* Currently triggers are supported only on Unix */
#if defined(UNIX) && !defined(__hppa) /* triggers not supported on HPUX-HPPA */
# define GTM_TRIGGER
# define GTMTRIG_ONLY(X) X
# define NON_GTMTRIG_ONLY(X)
# define GTMTRIG_DBG_ONLY(X) DEBUG_ONLY(X)
# define GTM_TRIGGER_DEPTH_MAX 127 /* Maximum depth triggers can nest */
#else
# define GTMTRIG_ONLY(X)
# define NON_GTMTRIG_ONLY(X) X
# define GTMTRIG_DBG_ONLY(X)
#endif
/* A type definition to hold a range of numbers */
typedef struct gtm_num_range_struct
{
uint4 min; /* included in range */
uint4 max; /* included in range */
} gtm_num_range_t;
/* Debug FPRINTF with pre and post requisite flushing of appropriate streams */
#ifndef DBGFPF
# define DBGFPF(x) {flush_pio(); FPRINTF x; FFLUSH(stderr); FFLUSH(stdout);}
#endif
/* Settings for lv_null_subs */
enum
{
LVNULLSUBS_FIRST = -1, /* So _NO is 0 to match existing values */
LVNULLSUBS_NO, /* No null LV subscripts in SET type cases */
LVNULLSUBS_OK, /* Null LV subscripts are allowed */
LVNULLSUBS_NEVER, /* LVNULLSUBS_NO plus LV subscripts prohibited in $DATA, $GET, $ORDER, $QUERY, KILL, etc */
LVNULLSUBS_LAST
};
#define MAX_GVSUBSCRIPTS 32
#define MAX_LVSUBSCRIPTS 32
#define MAX_INDSUBSCRIPTS 32
#define MAX_FOR_STACK 32
#define MAX_ACTUALS 32 /* Maximum number of arguments allowed in an actuallist. This value also determines
* how many parameters are allowed to be passed between M and C.
*/
#if defined(DEBUG) && defined(UNIX)
#define OPERATOR_LOG_MSG \
{ \
error_def(ERR_TEXT); \
if (gtm_white_box_test_case_enabled && (WBTEST_OPER_LOG_MSG == gtm_white_box_test_case_number)) \
{ \
send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Send message to operator log")); \
} \
}
#else
#define OPERATOR_LOG_MSG
#endif
#endif /* MDEF_included */