fis-gtm/sr_port/relqueopi.c

261 lines
8.7 KiB
C
Raw Normal View History

/****************************************************************
* *
* Copyright 2001, 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. *
* *
****************************************************************/
/* relqueopi - C-callable relative queue interlocked routines
*
* These routines perform interlocked operations on doubly-linked
* relative queues. They are designed to emulate the VAX machine
* instructions (and corresponding VAX C library routines) after
* which they are named.
*
* insqhi - insert entry into queue at head, interlocked
* insqti - insert entry into queue at tail, interlocked
* remqhi - remove entry from queue at head, interlocked
* remqti - remove entry from queue at tail, interlocked
*/
#include "mdef.h"
/* N.B. lockconst.h is needed for the lock values.
* all the rest are needed to define INTERLOCK_FAIL (sigh).
*/
/* These are instructions/library routines on VMS so this module is unnecessary for those platforms. */
#ifndef VMS
#include <errno.h>
#include "aswp.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsroot.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "copy.h"
#include "interlock.h"
#include "relqueopi.h"
#include "performcaslatchcheck.h"
#include "relqop.h"
#include "wcs_sleep.h"
#include "caller_id.h"
#include "rel_quant.h"
#include "sleep_cnt.h"
#include "gtm_c_stack_trace.h"
GBLREF volatile int4 fast_lock_count;
GBLREF int4 process_id;
GBLREF gd_region *gv_cur_region;
GBLREF int num_additional_processors;
int insqhi2(que_ent_ptr_t new, que_head_ptr_t base)
{
int retries, spins, maxspins;
uint4 stuck_cnt = 0;
++fast_lock_count; /* Disable wcs_stale for duration */
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
for (retries = LOCK_TRIES - 1; 0 < retries; retries--) /* - 1 so do rel_quant 3 times first */
{
for (spins = maxspins; 0 < spins; spins--)
{
if (GET_SWAPLOCK(&base->latch))
{
LOCK_HIST("OBTN", &base->latch, process_id, retries);
VERIFY_QUEUE(base);
insqh(new, (que_ent_ptr_t)base);
VERIFY_QUEUE(base);
LOCK_HIST("RLSE", &base->latch, process_id, retries);
RELEASE_SWAPLOCK(&base->latch);
--fast_lock_count;
assert(0 <= fast_lock_count);
return QUEUE_INSERT_SUCCESS;
}
}
if (retries & 0x3)
/* On all but every 4th pass, do a simple rel_quant */
rel_quant(); /* Release processor to holder of lock (hopefully) */
else
{
/* On every 4th pass, we bide for awhile */
wcs_sleep(LOCK_SLEEP);
assert(0 == (LOCK_TRIES % 4)); /* assures there are 3 rel_quants prior to first wcs_sleep() */
/* If near end of loop, see if target is dead and/or wake it up */
if (RETRY_CASLATCH_CUTOFF == retries)
performCASLatchCheck(&base->latch, TRUE);
}
}
DUMP_LOCKHIST();
--fast_lock_count;
stuck_cnt++;
GET_C_STACK_FROM_SCRIPT("INTERLOCK_FAIL", process_id, base->latch.u.parts.latch_pid, stuck_cnt);
assert(0 <= fast_lock_count);
assert(FALSE);
return INTERLOCK_FAIL;
}
int insqti2(que_ent_ptr_t new, que_head_ptr_t base)
{
int retries, spins, maxspins;
uint4 stuck_cnt = 0;
++fast_lock_count; /* Disable wcs_stale for duration */
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
for (retries = LOCK_TRIES - 1; 0 < retries; retries--) /* - 1 so do rel_quant 3 times first */
{
for (spins = maxspins; 0 < spins; spins--)
{
if (GET_SWAPLOCK(&base->latch))
{
LOCK_HIST("OBTN", &base->latch, process_id, retries);
VERIFY_QUEUE(base);
insqt(new, (que_ent_ptr_t)base);
VERIFY_QUEUE(base);
LOCK_HIST("RLSE", &base->latch, process_id, retries);
RELEASE_SWAPLOCK(&base->latch);
--fast_lock_count;
assert(0 <= fast_lock_count);
return QUEUE_INSERT_SUCCESS;
}
}
if (retries & 0x3)
/* On all but every 4th pass, do a simple rel_quant */
rel_quant(); /* Release processor to holder of lock (hopefully) */
else
{
/* On every 4th pass, we bide for awhile */
wcs_sleep(LOCK_SLEEP);
/* If near end of loop, see if target is dead and/or wake it up */
assert(0 == (LOCK_TRIES % 4)); /* assures there are 3 rel_quants prior to first wcs_sleep() */
if (RETRY_CASLATCH_CUTOFF == retries)
performCASLatchCheck(&base->latch, TRUE);
}
}
DUMP_LOCKHIST();
--fast_lock_count;
stuck_cnt++;
GET_C_STACK_FROM_SCRIPT("INTERLOCK_FAIL", process_id, base->latch.u.parts.latch_pid, stuck_cnt);
assert(0 <= fast_lock_count);
assert(FALSE);
return INTERLOCK_FAIL;
}
void_ptr_t remqhi1(que_head_ptr_t base)
{
int retries, spins, maxspins;
que_ent_ptr_t ret;
uint4 stuck_cnt = 0;
++fast_lock_count; /* Disable wcs_stale for duration */
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
for (retries = LOCK_TRIES - 1; 0 < retries; retries--) /* - 1 so do rel_quant 3 times first */
{
for (spins = maxspins; 0 < spins; spins--)
{
if (GET_SWAPLOCK(&base->latch))
{
LOCK_HIST("OBTN", &base->latch, process_id, retries);
VERIFY_QUEUE(base);
ret = (que_ent_ptr_t)remqh((que_ent_ptr_t)base);
VERIFY_QUEUE(base);
LOCK_HIST("RLSE", &base->latch, process_id, retries);
/* Unix wcs_get_space and the queue functions in gtm_relqueopi.c rely on the links being
* reset to 0 right after an element is removed from the queue. Note that this has to be
* done BEFORE releasing the queue header lock as Unix wcs_get_space assumes its has
* exclusive control of the queue if it has the queue header lock.
*/
if (NULL != ret)
ret->fl = ret->bl = 0;
RELEASE_SWAPLOCK(&base->latch);
--fast_lock_count;
assert(0 <= fast_lock_count);
return (void_ptr_t)ret;
}
}
if (retries & 0x3)
/* On all but every 4th pass, do a simple rel_quant */
rel_quant(); /* Release processor to holder of lock (hopefully) */
else
{
/* On every 4th pass, we bide for awhile */
wcs_sleep(LOCK_SLEEP);
/* If near end of loop, see if target is dead and/or wake it up */
assert(0 == (LOCK_TRIES % 4)); /* assures there are 3 rel_quants prior to first wcs_sleep() */
if (RETRY_CASLATCH_CUTOFF == retries)
performCASLatchCheck(&base->latch, TRUE);
}
}
DUMP_LOCKHIST();
--fast_lock_count;
stuck_cnt++;
GET_C_STACK_FROM_SCRIPT("INTERLOCK_FAIL", process_id, base->latch.u.parts.latch_pid, stuck_cnt);
assert(0 <= fast_lock_count);
assert(FALSE);
return (void_ptr_t)INTERLOCK_FAIL;
}
void_ptr_t remqti1(que_head_ptr_t base)
{
int retries, spins, maxspins;
que_ent_ptr_t ret;
uint4 stuck_cnt = 0;
++fast_lock_count; /* Disable wcs_stale for duration */
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
for (retries = LOCK_TRIES - 1; 0 < retries; retries--) /* - 1 so do rel_quant 3 times first */
{
for (spins = maxspins; 0 < spins; spins--)
{
if (GET_SWAPLOCK(&base->latch))
{
LOCK_HIST("OBTN", &base->latch, process_id, retries);
VERIFY_QUEUE(base);
ret = (que_ent_ptr_t)remqt((que_ent_ptr_t)base);
VERIFY_QUEUE(base);
LOCK_HIST("RLSE", &base->latch, process_id, retries);
/* Unix wcs_get_space and the queue functions in gtm_relqueopi.c rely on the links being
* reset to 0 right after an element is removed from the queue. Note that this has to be
* done BEFORE releasing the queue header lock as Unix wcs_get_space assumes its has
* exclusive control of the queue if it has the queue header lock.
*/
if (NULL != ret)
ret->fl = ret->bl = 0;
RELEASE_SWAPLOCK(&base->latch);
--fast_lock_count;
assert(0 <= fast_lock_count);
return (void_ptr_t)ret;
}
}
if (retries & 0x3)
/* On all but every 4th pass, do a simple rel_quant */
rel_quant(); /* Release processor to holder of lock (hopefully) */
else
{
/* On every 4th pass, we bide for awhile */
wcs_sleep(LOCK_SLEEP);
assert(0 == (LOCK_TRIES % 4)); /* assures there are 3 rel_quants prior to first wcs_sleep() */
/* If near end of loop, see if target is dead and/or wake it up */
if (RETRY_CASLATCH_CUTOFF == retries)
performCASLatchCheck(&base->latch, TRUE);
}
}
DUMP_LOCKHIST();
--fast_lock_count;
stuck_cnt++;
GET_C_STACK_FROM_SCRIPT("INTERLOCK_FAIL", process_id, base->latch.u.parts.latch_pid, stuck_cnt);
assert(0 <= fast_lock_count);
assert(FALSE);
return (void_ptr_t)INTERLOCK_FAIL;
}
#endif