fis-gtm/sr_port/have_crit.c

141 lines
4.8 KiB
C

/****************************************************************
* *
* Copyright 2001, 2010 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. *
* *
****************************************************************/
#include "mdef.h"
#include "gtm_inet.h"
#ifdef VMS
#include <descrip.h> /* Required for gtmsource.h */
#endif
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "repl_msg.h"
#include "gtmsource.h"
#include "filestruct.h"
#include "jnl.h"
#include "dpgbldir.h"
#include "have_crit.h"
#include "send_msg.h"
GBLREF volatile int4 crit_count;
GBLREF jnlpool_addrs jnlpool;
GBLREF uint4 process_id;
GBLREF uint4 crit_deadlock_check_cycle;
GBLREF uint4 dollar_tlevel;
GBLREF unsigned int t_tries;
GBLREF boolean_t hold_onto_locks;
/* Return number of regions (including jnlpool dummy region) if have or are aquiring crit or in_wtstart
* ** NOTE ** This routine is called from signal handlers and is thus called asynchronously.
* If CRIT_IN_COMMIT bit is set, we check if in middle of commit (PHASE1 inside crit or PHASE2 outside crit) on some region.
* If CRIT_RELEASE bit is set, we release crit on region(s) that:
* 1) we hold crit on (neither CRIT_IN_COMMIT NOR CRIT_TRANS_NO_REG is specified)
* 2) are part of the current transactions except those regions that are marked as being valid
* to have crit in by virtue of their crit_check_cycle value is the same as crit_deadlock_check_cycle.
* Note: CRIT_RELEASE implies CRIT_ALL_REGIONS
* If CRIT_ALL_REGIONS bit is set, go through the entire list of regions
*/
uint4 have_crit(uint4 crit_state)
{
gd_region *r_top, *r_local;
gd_addr *addr_ptr;
sgmnt_addrs *csa;
uint4 crit_reg_cnt = 0;
error_def(ERR_MUTEXRELEASED);
/* in order to proper release the necessary regions, CRIT_RELEASE implies going through all the regions */
if (crit_state & CRIT_RELEASE)
{
assert(!hold_onto_locks); /* should not request crit to be released with this variable set to TRUE */
crit_state |= CRIT_ALL_REGIONS;
}
if (0 != crit_count)
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
{
for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions; r_local < r_top; r_local++)
{
if (r_local->open && !r_local->was_open)
{
csa = &FILE_INFO(r_local)->s_addrs;
if (NULL != csa)
{
if (csa->now_crit)
{
crit_reg_cnt++;
/* It is possible that if DSE has done a CRIT REMOVE and stolen our crit, it
could be given to someone else which would cause this test to fail. The
current thinking is that the state DSE put this process is no longer viable
and it should die at the earliest opportunity, there being no way to know if
that is what happened anyway.
*/
if (csa->nl->in_crit != process_id)
GTMASSERT;
/* If we are releasing (all) regions with critical section or if special
TP case, release if the cycle number doesn't match meaning this is a
region we should not hold crit in (even if it is part of tp_reg_list).
*/
if ((0 != (crit_state & CRIT_RELEASE)) &&
(0 == (crit_state & CRIT_NOT_TRANS_REG) ||
crit_deadlock_check_cycle != csa->crit_check_cycle))
{
assert(FALSE);
rel_crit(r_local);
send_msg(VARLSTCNT(8) ERR_MUTEXRELEASED, 6,
process_id, process_id, DB_LEN_STR(r_local),
dollar_tlevel, t_tries);
}
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
/* In Commit-crit is defined as the time since when early_tn is 1 + curr_tn upto when
* t_commit_crit is set to FALSE. Note that the first check should be done only if we
* hold crit as otherwise we could see inconsistent values.
*/
if ((crit_state & CRIT_IN_COMMIT)
&& (csa->now_crit && (csa->ti->early_tn != csa->ti->curr_tn) || csa->t_commit_crit))
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
if ((crit_state & CRIT_IN_WTSTART) && csa->in_wtstart)
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
}
}
}
}
if (NULL != jnlpool.jnlpool_ctl)
{
csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
if (NULL != csa && csa->now_crit)
{
crit_reg_cnt++;
if (0 != (crit_state & CRIT_RELEASE))
rel_lock(jnlpool.jnlpool_dummy_reg);
}
}
return crit_reg_cnt;
}