1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
/****************************************************************
* *
* Copyright 2011, 2013 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_SEMUTILS_H
#define GTM_SEMUTILS_H
#include <sys/sem.h>
/* Database startup wait related macros */
#define DEFAULT_DBINIT_MAX_HRTBT_DELTA 12
#define NO_SEMWAIT_ON_EAGAIN 0
#define INDEFINITE_WAIT_ON_EAGAIN (uint4) -1
#define MAX_BYPASS_WAIT_SEC 3
#define MAX_C_STACK_TRACES_FOR_SEMWAIT 2
#define DB_CONTROL_SEM 0
#define DB_COUNTER_SEM 1
error_def(ERR_CRITSEMFAIL);
error_def(ERR_DBFILERR);
error_def(ERR_FTOKERR);
error_def(ERR_MAXSEMGETRETRY);
error_def(ERR_SEMKEYINUSE);
error_def(ERR_SEMWT2LONG);
error_def(ERR_SYSCALL);
/* Possible semaphore functions that can fail */
enum sem_syscalls
{
op_invalid_sem_syscall,
op_ftok,
op_semget,
op_semop,
op_semctl,
op_semctl_or_semop
};
enum gtm_semtype
{
gtm_ftok_sem,
gtm_access_sem
};
typedef struct semwait_status_struct
{
int line_no;
int save_errno; /* This value must be checked/assigned only errors. May not be 0 on success. */
int status1;
int status2;
int sem_pid;
const char *module;
enum sem_syscalls op;
} semwait_status_t;
boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrtbt_cntr,
semwait_status_t *status, gd_region *reg, boolean_t *bypass);
#define SENDMSG_SEMOP_SUCCESS_IF_NEEDED(STACKTRACE_ISSUED, SEMTYPE) \
{ \
if (TREF(gtm_environment_init) && STACKTRACE_ISSUED) \
{ \
const char *lcl_msgstr = NULL; \
\
lcl_msgstr = (gtm_ftok_sem == SEMTYPE) ? "SEMWT2LONG_FTOK_SUCCEEDED: semop for the ftok semaphore succeeded" \
: "SEMWT2LONG_ACCSEM_SUCCEEDED: semop for the ftok semaphore succeeded"; \
send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(lcl_msgstr)); \
} \
}
#define DBFILERR_PARAMS(REG) ERR_DBFILERR, 2, DB_LEN_STR(REG)
#define CRITSEMFAIL_PARAMS(REG) ERR_CRITSEMFAIL,2, DB_LEN_STR(REG)
#define SYSCALL_PARAMS(RETSTAT, OP) ERR_SYSCALL, 5, LEN_AND_STR(OP), LEN_AND_STR(RETSTAT->module), RETSTAT->line_no
#define SEMKEYINUSE_PARAMS(UDI) ERR_SEMKEYINUSE, 1, UDI->key
#define SEMWT2LONG_PARAMS(REG, RETSTAT, GTM_SEMTYPE, TOT_WAIT_TIME) \
ERR_SEMWT2LONG, 7, process_id, TOT_WAIT_TIME, \
LEN_AND_LIT(GTM_SEMTYPE), DB_LEN_STR(REG), RETSTAT->sem_pid
#define GET_OP_STR(RETSTAT, OP) \
{ \
switch (RETSTAT->op) \
{ \
case op_semget: \
OP = "semget()"; \
break; \
case op_semop: \
OP = "semop()"; \
break; \
case op_semctl: \
OP = "semctl()"; \
break; \
case op_semctl_or_semop: \
OP = "semctl()/semop()"; \
break; \
default: \
OP = ""; \
assert(FALSE); \
} \
}
#define ISSUE_SEMWAIT_ERROR(RETSTAT, REG, UDI, GTM_SEMTYPE) \
{ \
const char *op; \
uint4 tot_wait_time; \
\
GBLREF uint4 process_id; \
\
if (ERR_CRITSEMFAIL == RETSTAT->status2) \
{ \
if (0 == RETSTAT->status1) \
{ \
GET_OP_STR(RETSTAT, op); \
rts_error(VARLSTCNT(16) DBFILERR_PARAMS(REG), CRITSEMFAIL_PARAMS(REG), \
SYSCALL_PARAMS(RETSTAT, op), RETSTAT->save_errno); \
} else if (ERR_SEMKEYINUSE == RETSTAT->status1) \
{ \
rts_error(VARLSTCNT(11) DBFILERR_PARAMS(REG), CRITSEMFAIL_PARAMS(REG), \
SEMKEYINUSE_PARAMS(UDI)); \
} else \
GTMASSERT; \
} else if (ERR_MAXSEMGETRETRY == RETSTAT->status2) \
{ \
rts_error(VARLSTCNT(7) DBFILERR_PARAMS(REG), ERR_MAXSEMGETRETRY, 1, MAX_SEMGET_RETRIES); \
} else if (ERR_FTOKERR == RETSTAT->status2) \
{ \
rts_error(VARLSTCNT(9) DBFILERR_PARAMS(REG), ERR_FTOKERR, 2, DB_LEN_STR(REG), \
RETSTAT->save_errno); \
} else if (0 == RETSTAT->status2) \
{ \
assert(ERR_SEMWT2LONG == RETSTAT->status1); \
assert(RETSTAT->sem_pid && (-1 != RETSTAT->sem_pid)); \
tot_wait_time = TREF(dbinit_max_hrtbt_delta) * HEARTBEAT_INTERVAL_IN_SECS; \
rts_error(VARLSTCNT(13) DBFILERR_PARAMS(REG), \
SEMWT2LONG_PARAMS(REG, RETSTAT, GTM_SEMTYPE, tot_wait_time)); \
} else \
GTMASSERT; \
}
/* Set the value of semaphore number 2 ( = FTOK_SEM_PER_ID - 1) as GTM_ID. This way, in case of an orphaned
* semaphore (say, kill -9), MUPIP RUNDOWN will be able to identify GT.M semaphore from the value and will
* remove it.
*/
#define SET_GTM_ID_SEM(SEMID, RC) \
{ \
union semun semarg; \
\
semarg.val = GTM_ID; \
RC = semctl(SEMID, FTOK_SEM_PER_ID - 1, SETVAL, semarg); \
}
/* Set up typical GT.M semaphore (access control semaphore and/or ftok semaphore) */
#define SET_GTM_SOP_ARRAY(SOP, SOPCNT, INCR_CNT, SEMFLG) \
{ \
/* Typically, multiple statements are not specified in a single line. However, each of the 2 lines below represent \
* "one" semaphore operation and hence an acceptible exception to the coding guidelines. \
*/ \
SOP[0].sem_num = DB_CONTROL_SEM; SOP[0].sem_op = 0; /* Wait for 0 (unlocked) */ \
SOP[1].sem_num = DB_CONTROL_SEM; SOP[1].sem_op = 1; /* Then lock it */ \
if (INCR_CNT) \
{ \
SOP[2].sem_num = DB_COUNTER_SEM; SOP[2].sem_op = 1; /* Increment counter semaphore */ \
SOPCNT = 3; \
} else \
SOPCNT = 2; \
SOP[0].sem_flg = SOP[1].sem_flg = SOP[2].sem_flg = SEMFLG; \
}
#define RETURN_SEMWAIT_FAILURE(RETSTAT, ERRNO, OP, STATUS1, STATUS2, SEMPID) \
{ \
RETSTAT->line_no = __LINE__; \
RETSTAT->save_errno = ERRNO; \
RETSTAT->op = OP; \
RETSTAT->status1 = STATUS1; \
RETSTAT->status2 = STATUS2; \
RETSTAT->sem_pid = SEMPID; \
RETSTAT->module = __FILE__; \
return FALSE; \
}
#define SEM_REMOVED(ERRNO) ((EINVAL == ERRNO) || (EIDRM == ERRNO)) /* EIDRM is only on Linux */
#endif /* GTM_SEMUTILS_H */
|