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
|
/****************************************************************
* *
* Copyright (c) 2014-2021 Fidelity National Information *
* Services, Inc. and/or its subsidiaries. All rights reserved. *
* *
* 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"
#ifdef DEBUG
#include "gtm_unistd.h" /* for "getpid" */
#endif
#include "gtm_facility.h"
#include "gdsroot.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "interlock.h"
#include "performcaslatchcheck.h"
#include "gtm_rel_quant.h"
#include "sleep_cnt.h"
#include "wcs_sleep.h"
#include "min_max.h"
#include "gt_timer.h"
GBLREF int num_additional_processors;
GBLREF uint4 process_id;
GBLREF volatile int4 fast_lock_count; /* Stop interrupts while we have our parts exposed */
/* Grab a latch. If cannot get it in the approximate time requested, return FALSE, else TRUE.
* originally intended to protect verify_queue which only runs in debug
* but adopted by some auto-relink code - not clear that's appropriate
*/
boolean_t grab_latch(sm_global_latch_ptr_t latch, int max_timeout_in_secs, wait_state state, sgmnt_addrs *csa)
{
ABS_TIME cur_time, end_time, remain_time;
int maxspins, retries, spins;
int4 max_sleep_mask;
boolean_t skip_time_calc;
assert(process_id == getpid()); /* Make sure "process_id" global variable is reliable (used below in an assert) */
if (process_id == latch->u.parts.latch_pid)
{ /* Already have lock */
assert(FALSE); /* Don't expect caller to call us if we hold the lock already. in pro be safe and return */
return TRUE;
}
skip_time_calc = !max_timeout_in_secs || (GRAB_LATCH_INDEFINITE_WAIT == max_timeout_in_secs);
if (!skip_time_calc)
{
sys_get_curr_time(&cur_time);
add_int_to_abs_time(&cur_time, max_timeout_in_secs * 1000, &end_time);
remain_time.at_sec = 0; /* ensure one try */
}
/* Define number of hard-spins the inner loop does */
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
UPDATE_CRIT_COUNTER(csa, state);
for (retries = 1; ; retries++)
{
++fast_lock_count; /* Disable interrupts (i.e. wcs_stale) for duration to avoid potential deadlocks */
for (spins = maxspins; spins > 0 ; spins--)
{ /* We better not hold it if trying to get it */
assert(latch->u.parts.latch_pid != process_id);
if (GET_SWAPLOCK(latch))
{
--fast_lock_count;
assert(0 <= fast_lock_count);
return TRUE;
}
}
--fast_lock_count;
if (!max_timeout_in_secs)
break;
if (!skip_time_calc)
{
REST_FOR_LATCH(latch, USEC_IN_NSEC_MASK, retries);
sys_get_curr_time(&cur_time);
remain_time = sub_abs_time(&end_time, &cur_time);
if (0 > remain_time.at_sec)
break;
} else
{ /* Indefinite wait for lock. Periodically check if latch is held by dead pid. If so get it back. */
SLEEP_FOR_LATCH(latch, retries);
}
}
assert(0 <= fast_lock_count);
assert(FALSE);
return FALSE;
}
|