/**************************************************************** * * * Copyright 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_SEMUTILS_H #define GTM_SEMUTILS_H #include /* 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_C_STACK_TRACES_FOR_SEMWAIT 2 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; int status1; int status2; int sem_pid; const char *module; enum sem_syscalls op; } semwait_status_t; boolean_t do_blocking_semop(int semid, struct sembuf *sop, int sopcnt, enum gtm_semtype semtype, uint4 start_hrtbt_cntr, semwait_status_t *status); #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 = 0; SOP[0].sem_op = 0; /* Wait for 0 (unlocked) */ \ SOP[1].sem_num = 0; SOP[1].sem_op = 1; /* Then lock it */ \ if (INCR_CNT) \ { \ SOP[2].sem_num = 1; 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 */