2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Lock Manager
|
2003-11-28 07:48:34 +01:00
|
|
|
* MODULE: lock.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Generic ISC Lock Manager
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase Public
|
|
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy
|
|
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
|
|
* or implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2002-02-16 04:27:33 +01:00
|
|
|
*
|
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
|
|
|
|
*
|
2002-10-28 04:47:47 +01:00
|
|
|
* 2002.10.27 Sean Leyne - Completed removal of obsolete "DELTA" port
|
2002-10-28 04:52:09 +01:00
|
|
|
* 2002.10.27 Sean Leyne - Completed removal of obsolete "IMP" port
|
2002-10-28 04:47:47 +01:00
|
|
|
*
|
2002-10-30 07:40:58 +01:00
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
2003-03-24 15:32:34 +01:00
|
|
|
* 2003.03.24 Nickolay Samofatov
|
|
|
|
* - cleanup #define's,
|
|
|
|
* - shutdown blocking thread cleanly on Windows CS
|
|
|
|
* - fix Windows CS lock-ups (make wakeup event manual-reset)
|
|
|
|
* - detect deadlocks instantly in most cases (if blocking owner
|
|
|
|
* dies during AST processing deadlock scan timeout still applies)
|
2003-04-29 20:42:55 +02:00
|
|
|
* 2003.04.29 Nickolay Samofatov - fix broken lock table resizing code in CS builds
|
2003-08-11 22:56:07 +02:00
|
|
|
* 2003.08.11 Nickolay Samofatov - finally and correctly fix Windows CS lock-ups.
|
|
|
|
* Roll back earlier workarounds on this subject.
|
2002-10-30 07:40:58 +01:00
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
2003-03-24 15:32:34 +01:00
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/common.h"
|
2008-01-16 08:40:12 +01:00
|
|
|
#include "../jrd/ThreadStart.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/isc.h"
|
|
|
|
#include "../lock/lock.h"
|
|
|
|
#include "../lock/lock_proto.h"
|
2003-11-11 13:19:20 +01:00
|
|
|
#include "gen/iberror.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
|
|
#include "../jrd/isc_proto.h"
|
2008-01-16 08:40:12 +01:00
|
|
|
#include "../jrd/isc_signal.h"
|
2003-09-08 22:23:46 +02:00
|
|
|
#include "../jrd/os/isc_i_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/isc_s_proto.h"
|
2004-05-18 00:30:09 +02:00
|
|
|
#include "../jrd/thread_proto.h"
|
2002-12-07 14:27:12 +01:00
|
|
|
#include "../common/config/config.h"
|
2008-02-11 18:30:23 +01:00
|
|
|
#include "../common/classes/array.h"
|
2008-01-16 08:40:12 +01:00
|
|
|
#include "../common/classes/semaphore.h"
|
2008-01-23 16:52:40 +01:00
|
|
|
#include "../common/classes/init.h"
|
2008-02-11 18:30:23 +01:00
|
|
|
#include "../common/classes/timestamp.h"
|
2008-01-16 08:40:12 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <errno.h>
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
2004-05-13 21:47:30 +02:00
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
2002-09-18 14:50:13 +02:00
|
|
|
# include <sys/wait.h>
|
|
|
|
#endif
|
2001-07-30 01:43:24 +02:00
|
|
|
|
2002-09-18 14:50:13 +02:00
|
|
|
#if TIME_WITH_SYS_TIME
|
|
|
|
# include <sys/time.h>
|
|
|
|
# include <time.h>
|
|
|
|
#else
|
|
|
|
# if HAVE_SYS_TIME_H
|
|
|
|
# include <sys/time.h>
|
|
|
|
# else
|
|
|
|
# include <time.h>
|
|
|
|
# endif
|
2001-07-30 01:43:24 +02:00
|
|
|
#endif
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
|
|
|
|
2002-09-11 13:30:50 +02:00
|
|
|
#ifdef HAVE_VFORK_H
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <vfork.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
#include <process.h>
|
2008-01-16 08:40:12 +01:00
|
|
|
#define MUTEX &lock_manager_mutex
|
2004-05-17 17:14:10 +02:00
|
|
|
#else
|
|
|
|
#define MUTEX LOCK_header->lhb_mutex
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
#define VALIDATE_LOCK_TABLE
|
2008-02-11 18:30:23 +01:00
|
|
|
#define ASSERT_ACQUIRED fb_assert(LOCK_header->lhb_active_owner)
|
|
|
|
#if (defined HAVE_MMAP || defined WIN_NT)
|
|
|
|
#define LOCK_DEBUG_REMAP
|
|
|
|
#define DEBUG_REMAP_INTERVAL 5000
|
|
|
|
static ULONG debug_remap_count = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2004-05-17 17:14:10 +02:00
|
|
|
#define CHECK(x) { if (!(x)) bug_assert ("consistency check", __LINE__); }
|
|
|
|
#else // DEV_BUILD
|
2008-02-11 18:30:23 +01:00
|
|
|
#define ASSERT_ACQUIRED
|
|
|
|
#define CHECK(x)
|
2004-05-17 17:14:10 +02:00
|
|
|
#endif // DEV_BUILD
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define DEBUG_MANAGER "manager"
|
|
|
|
#define DEBUG_TRACE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG_TRACE
|
2004-05-09 07:48:33 +02:00
|
|
|
#define LOCK_TRACE(x) { time_t t; time(&t); printf("%s", ctime(&t) ); printf x; fflush (stdout); gds__log x;}
|
2004-05-17 17:14:10 +02:00
|
|
|
#else
|
2008-02-11 18:30:23 +01:00
|
|
|
#define LOCK_TRACE(x)
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
SSHORT LOCK_debug_level = 0;
|
2004-11-24 10:22:07 +01:00
|
|
|
#define DEBUG_MSG(l, x) if ((l) <= LOCK_debug_level) { time_t t; time(&t); printf("%s", ctime(&t) ); printf x; fflush (stdout); gds__log x; }
|
2004-05-17 17:14:10 +02:00
|
|
|
#else
|
2008-02-11 18:30:23 +01:00
|
|
|
#define DEBUG_MSG(l, x)
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Debug delay is used to create nice big windows for signals or other
|
|
|
|
// events to occur in - eg: slow down the code to try and make
|
|
|
|
// timing race conditions show up
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
#define DEBUG_DELAY debug_delay (__LINE__)
|
2004-05-17 17:14:10 +02:00
|
|
|
#else
|
2001-05-23 15:26:42 +02:00
|
|
|
#define DEBUG_DELAY /* nothing */
|
|
|
|
#endif
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
// CVC: Unlike other definitions, SRQ_PTR is not a pointer to something in lowercase.
|
|
|
|
// It's LONG.
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const SRQ_PTR DUMMY_OWNER = -1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
static void acquire(SRQ_PTR);
|
2008-01-17 14:40:35 +01:00
|
|
|
static UCHAR *alloc(SSHORT, ISC_STATUS*);
|
|
|
|
static lbl* alloc_lock(USHORT, ISC_STATUS*);
|
2008-01-16 08:40:12 +01:00
|
|
|
static void blocking_action(SRQ_PTR, SRQ_PTR);
|
2003-03-24 15:32:34 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
2004-06-08 15:41:08 +02:00
|
|
|
static THREAD_ENTRY_DECLARE blocking_action_thread(THREAD_ENTRY_PARAM);
|
2003-03-01 18:44:34 +01:00
|
|
|
#endif
|
2008-01-17 14:40:35 +01:00
|
|
|
static void bug(ISC_STATUS*, const TEXT*);
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
2008-01-17 14:40:35 +01:00
|
|
|
static void bug_assert(const TEXT*, ULONG);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2004-05-03 19:36:27 +02:00
|
|
|
static bool convert(SRQ_PTR, UCHAR, SSHORT, lock_ast_t, void*, ISC_STATUS*);
|
2008-01-17 14:40:35 +01:00
|
|
|
static bool create_owner(ISC_STATUS*, LOCK_OWNER_T, UCHAR, SRQ_PTR*);
|
2008-02-11 18:30:23 +01:00
|
|
|
static bool create_process(ISC_STATUS*);
|
2008-01-17 14:40:35 +01:00
|
|
|
static void deadlock_clear();
|
2008-01-16 08:40:12 +01:00
|
|
|
static lrq* deadlock_scan(own*, lrq*);
|
2008-01-17 14:40:35 +01:00
|
|
|
static lrq* deadlock_walk(lrq*, bool*);
|
2004-05-03 19:36:27 +02:00
|
|
|
static void dequeue(SRQ_PTR);
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
static void debug_delay(ULONG);
|
|
|
|
#endif
|
2008-01-17 14:40:35 +01:00
|
|
|
static void exit_handler(void*);
|
2008-01-16 08:40:12 +01:00
|
|
|
static lbl* find_lock(SRQ_PTR, USHORT, const UCHAR*, USHORT, USHORT*);
|
|
|
|
static lrq* get_request(SRQ_PTR);
|
|
|
|
static void grant(lrq*, lbl*);
|
|
|
|
static SRQ_PTR grant_or_que(lrq*, lbl*, SSHORT);
|
2008-01-17 14:40:35 +01:00
|
|
|
static bool init_lock_table(ISC_STATUS*);
|
2008-01-16 08:40:12 +01:00
|
|
|
static void init_owner_block(own*, UCHAR, LOCK_OWNER_T);
|
2003-11-28 07:48:34 +01:00
|
|
|
static void lock_initialize(void*, SH_MEM, bool);
|
2008-01-16 08:40:12 +01:00
|
|
|
static void insert_data_que(lbl*);
|
2001-05-23 15:26:42 +02:00
|
|
|
static void insert_tail(SRQ, SRQ);
|
2008-01-16 08:40:12 +01:00
|
|
|
static USHORT lock_state(lbl*);
|
2008-02-11 18:30:23 +01:00
|
|
|
static void post_blockage(lrq*, lbl*);
|
2004-05-03 19:36:27 +02:00
|
|
|
static void post_history(USHORT, SRQ_PTR, SRQ_PTR, SRQ_PTR, bool);
|
2008-01-16 08:40:12 +01:00
|
|
|
static void post_pending(lbl*);
|
2006-04-29 02:34:06 +02:00
|
|
|
static void post_wakeup(own*);
|
2008-02-11 18:30:23 +01:00
|
|
|
static bool probe_processes();
|
2006-04-29 02:34:06 +02:00
|
|
|
static void purge_owner(SRQ_PTR, own*);
|
2008-02-11 18:30:23 +01:00
|
|
|
static void purge_process(prc*);
|
|
|
|
static void remap_local_owners();
|
2001-05-23 15:26:42 +02:00
|
|
|
static void remove_que(SRQ);
|
2004-05-03 19:36:27 +02:00
|
|
|
static void release(SRQ_PTR);
|
2008-01-17 14:40:35 +01:00
|
|
|
static void release_mutex();
|
2008-01-16 08:40:12 +01:00
|
|
|
static void release_request(lrq*);
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_history(const SRQ_PTR history_header);
|
|
|
|
static void validate_parent(const lhb*, const SRQ_PTR);
|
|
|
|
static void validate_lhb(const lhb*);
|
|
|
|
static void validate_lock(const SRQ_PTR, USHORT, const SRQ_PTR);
|
|
|
|
static void validate_owner(const SRQ_PTR, USHORT);
|
|
|
|
static void validate_request(const SRQ_PTR, USHORT, USHORT);
|
|
|
|
static void validate_shb(const SRQ_PTR);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2008-03-04 20:07:55 +01:00
|
|
|
static void shutdown_blocking_thread(ISC_STATUS*);
|
2008-02-11 18:30:23 +01:00
|
|
|
static bool signal_owner(own*, SRQ_PTR);
|
2008-01-17 14:40:35 +01:00
|
|
|
static USHORT wait_for_request(lrq*, SSHORT, ISC_STATUS*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static SSHORT LOCK_bugcheck = 0;
|
2008-01-16 08:40:12 +01:00
|
|
|
static lhb* volatile LOCK_header = NULL;
|
|
|
|
static int LOCK_pid = 0;
|
2008-02-11 18:30:23 +01:00
|
|
|
static prc* LOCK_process = NULL;
|
|
|
|
static SRQ_PTR LOCK_process_offset = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static SH_MEM_T LOCK_data;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
static Firebird::GlobalPtr<Firebird::Mutex> localMutex;
|
|
|
|
static Firebird::GlobalPtr<Firebird::RWLock> remapSync;
|
|
|
|
static Firebird::AtomicCounter waitingOwners;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
2008-01-23 16:52:40 +01:00
|
|
|
static Firebird::GlobalPtr<Firebird::Semaphore> cleanupSemaphore;
|
|
|
|
static Firebird::GlobalPtr<Firebird::Semaphore> startupSemaphore;
|
2008-01-16 08:40:12 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef WIN_NT
|
2008-01-16 08:40:12 +01:00
|
|
|
static MTX_T lock_manager_mutex;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2004-05-17 17:14:10 +02:00
|
|
|
const SLONG HASH_MIN_SLOTS = 101;
|
2007-01-24 20:48:58 +01:00
|
|
|
const SLONG HASH_MAX_SLOTS = 65521;
|
2004-05-17 17:14:10 +02:00
|
|
|
const USHORT HISTORY_BLOCKS = 256;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-06-09 20:57:07 +02:00
|
|
|
#define SRQ_BASE ((UCHAR*) LOCK_header)
|
2004-05-03 19:36:27 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
static const bool compatibility[LCK_max][LCK_max] =
|
|
|
|
{
|
|
|
|
/* Shared Prot Shared Prot
|
|
|
|
none null Read Read Write Write Exclusive */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
/* none */ {true, true, true, true, true, true, true},
|
|
|
|
/* null */ {true, true, true, true, true, true, true},
|
|
|
|
/* SR */ {true, true, true, true, true, true, false},
|
|
|
|
/* PR */ {true, true, true, true, false, false, false},
|
|
|
|
/* SW */ {true, true, true, false, true, false, false},
|
|
|
|
/* PW */ {true, true, true, false, false, false, false},
|
|
|
|
/* EX */ {true, true, false, false, false, false, false}
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
//#define COMPATIBLE(st1, st2) compatibility[st1 * LCK_max + st2]
|
2008-01-16 08:40:12 +01:00
|
|
|
|
|
|
|
static inline bool lockOrdering()
|
|
|
|
{
|
|
|
|
return (LOCK_header->lhb_flags & LHB_lock_ordering) ? true : false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
bool LOCK_convert(SRQ_PTR request_offset,
|
|
|
|
UCHAR type,
|
|
|
|
SSHORT lck_wait,
|
|
|
|
lock_ast_t ast_routine,
|
|
|
|
void* ast_argument,
|
|
|
|
ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ c o n v e r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Perform a lock conversion, if possible.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_convert (%d, %d)\n", type, lck_wait));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(request->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!owner->own_count)
|
2003-12-31 06:36:12 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
acquire(request->lrq_owner);
|
|
|
|
++LOCK_header->lhb_converts;
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset); /* remap */
|
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_series < LCK_MAX_SERIES)
|
|
|
|
++LOCK_header->lhb_operations[lock->lbl_series];
|
|
|
|
else
|
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
return convert(request_offset, type, lck_wait, ast_routine, ast_argument,
|
|
|
|
status_vector);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
bool LOCK_deq(SRQ_PTR request_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2002-02-16 04:27:33 +01:00
|
|
|
* L O C K _ d e q
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release an outstanding lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-06-30 13:02:52 +02:00
|
|
|
LOCK_TRACE(("LOCK_deq (%ld)\n", request_offset));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR owner_offset = request->lrq_owner;
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!owner->own_count)
|
2008-01-17 14:40:35 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
acquire(owner_offset);
|
|
|
|
++LOCK_header->lhb_deqs;
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset); /* remap */
|
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_series < LCK_MAX_SERIES)
|
|
|
|
++LOCK_header->lhb_operations[lock->lbl_series];
|
|
|
|
else
|
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
|
|
|
|
dequeue(request_offset);
|
|
|
|
release(owner_offset);
|
2008-01-17 14:40:35 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
UCHAR LOCK_downgrade(SRQ_PTR request_offset,
|
|
|
|
ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ d o w n g r a d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Downgrade an existing lock returning
|
|
|
|
* its new state.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-06-30 13:02:52 +02:00
|
|
|
LOCK_TRACE(("LOCK_downgrade (%ld)\n", request_offset));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR owner_offset = request->lrq_owner;
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!owner->own_count)
|
2008-01-17 14:40:35 +01:00
|
|
|
return FALSE; // Warning! Can be treated as LCK_none by the caller!
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
acquire(owner_offset);
|
|
|
|
++LOCK_header->lhb_downgrades;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset); /* Re-init after a potential remap */
|
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2003-12-31 06:36:12 +01:00
|
|
|
UCHAR pending_state = LCK_none;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Loop thru requests looking for pending conversions
|
|
|
|
// and find the highest requested state
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(lock->lbl_requests, lock_srq) {
|
2008-01-16 08:40:12 +01:00
|
|
|
const lrq* pending = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_lbl_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
if (pending->lrq_flags & LRQ_pending && pending != request) {
|
|
|
|
pending_state = MAX(pending->lrq_requested, pending_state);
|
|
|
|
if (pending_state == LCK_EX)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
UCHAR state = request->lrq_state;
|
2008-01-16 08:40:12 +01:00
|
|
|
while (state > LCK_none && !compatibility[pending_state][state])
|
2003-12-31 06:36:12 +01:00
|
|
|
--state;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (state == LCK_none || state == LCK_null) {
|
|
|
|
dequeue(request_offset);
|
|
|
|
release(owner_offset);
|
|
|
|
state = LCK_none;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
convert(request_offset, state, FALSE,
|
|
|
|
request->lrq_ast_routine, request->lrq_ast_argument,
|
|
|
|
status_vector);
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
SRQ_PTR LOCK_enq(SRQ_PTR prior_request,
|
|
|
|
SRQ_PTR parent_request,
|
2008-02-14 08:33:50 +01:00
|
|
|
const USHORT series,
|
2008-01-17 14:40:35 +01:00
|
|
|
const UCHAR* value,
|
2008-02-14 08:33:50 +01:00
|
|
|
const USHORT length,
|
2008-01-17 14:40:35 +01:00
|
|
|
UCHAR type,
|
|
|
|
lock_ast_t ast_routine,
|
|
|
|
void* ast_argument,
|
|
|
|
SLONG data,
|
|
|
|
SSHORT lck_wait,
|
|
|
|
ISC_STATUS* status_vector,
|
|
|
|
SRQ_PTR owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ e n q
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Enque on a lock. If the lock can't be granted immediately,
|
|
|
|
* return an event count on which to wait. If the lock can't
|
|
|
|
* be granted because of deadlock, return NULL.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-06-30 13:02:52 +02:00
|
|
|
LOCK_TRACE(("LOCK_enq (%ld)\n", parent_request));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!owner_offset || !owner->own_count)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
acquire(owner_offset);
|
|
|
|
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
++LOCK_header->lhb_enqs;
|
|
|
|
|
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
|
|
|
if ((LOCK_header->lhb_enqs % 50) == 0)
|
|
|
|
validate_lhb(LOCK_header);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (prior_request)
|
|
|
|
dequeue(prior_request);
|
|
|
|
|
2008-01-26 13:52:51 +01:00
|
|
|
lrq* request = NULL;
|
|
|
|
SRQ_PTR parent = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (parent_request) {
|
|
|
|
request = get_request(parent_request);
|
|
|
|
parent = request->lrq_lock;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Allocate or reuse a lock request block
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
ASSERT_ACQUIRED;
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_EMPTY(LOCK_header->lhb_free_requests)) {
|
2008-01-16 08:40:12 +01:00
|
|
|
if (!(request = (lrq*) alloc(sizeof(lrq), status_vector))) {
|
2001-05-23 15:26:42 +02:00
|
|
|
release(owner_offset);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ASSERT_ACQUIRED;
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) ((UCHAR *) SRQ_NEXT(LOCK_header->lhb_free_requests) -
|
|
|
|
OFFSET(lrq*, lrq_lbl_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&request->lrq_lbl_requests);
|
|
|
|
}
|
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(owner_offset); /* Re-init after a potential remap */
|
2004-05-03 19:36:27 +02:00
|
|
|
post_history(his_enq, owner_offset, (SRQ_PTR)0, SRQ_REL_PTR(request), true);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->lrq_type = type_lrq;
|
|
|
|
request->lrq_flags = 0;
|
|
|
|
request->lrq_requested = type;
|
|
|
|
request->lrq_state = LCK_none;
|
|
|
|
request->lrq_data = 0;
|
|
|
|
request->lrq_owner = owner_offset;
|
2003-05-16 22:35:19 +02:00
|
|
|
request->lrq_ast_routine = ast_routine;
|
|
|
|
request->lrq_ast_argument = ast_argument;
|
2001-05-23 15:26:42 +02:00
|
|
|
insert_tail(&owner->own_requests, &request->lrq_own_requests);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(request->lrq_own_blocks);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if the lock already exists
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
USHORT hash_slot;
|
|
|
|
lbl* lock = find_lock(parent, series, value, length, &hash_slot);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock)
|
|
|
|
{
|
|
|
|
if (series < LCK_MAX_SERIES) {
|
|
|
|
++LOCK_header->lhb_operations[series];
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
insert_tail(&lock->lbl_requests, &request->lrq_lbl_requests);
|
|
|
|
request->lrq_data = data;
|
2008-01-17 14:40:35 +01:00
|
|
|
const SRQ_PTR lock_id = grant_or_que(request, lock, lck_wait);
|
2003-12-31 06:36:12 +01:00
|
|
|
if (!lock_id) {
|
2003-11-11 13:19:20 +01:00
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = (lck_wait > 0) ? isc_deadlock :
|
|
|
|
((lck_wait < 0) ? isc_lock_timeout : isc_lock_conflict);
|
|
|
|
*status_vector++ = isc_arg_end;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return lock_id;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Lock doesn't exist. Allocate lock block and set it up.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR request_offset = SRQ_REL_PTR(request);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(lock = alloc_lock(length, status_vector))) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// lock table is exhausted: release request gracefully
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&request->lrq_own_requests);
|
|
|
|
request->lrq_type = type_null;
|
|
|
|
insert_tail(&LOCK_header->lhb_free_requests,
|
|
|
|
&request->lrq_lbl_requests);
|
|
|
|
release(owner_offset);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-07-25 15:26:13 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lbl_state = type;
|
|
|
|
lock->lbl_parent = parent;
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(series <= MAX_UCHAR);
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lbl_series = (UCHAR)series;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Maintain lock series data queue
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(lock->lbl_lhb_data);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_data = data)
|
|
|
|
insert_data_que(lock);
|
|
|
|
|
|
|
|
if (series < LCK_MAX_SERIES)
|
|
|
|
++LOCK_header->lhb_operations[series];
|
|
|
|
else
|
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
|
|
|
|
lock->lbl_flags = 0;
|
|
|
|
lock->lbl_pending_lrq_count = 0;
|
|
|
|
|
2008-01-26 13:52:51 +01:00
|
|
|
memset(lock->lbl_counts, 0, sizeof(lock->lbl_counts));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-26 13:52:51 +01:00
|
|
|
lock->lbl_length = length;
|
|
|
|
memcpy(lock->lbl_key, value, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(lock->lbl_requests);
|
2001-05-23 15:26:42 +02:00
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
insert_tail(&LOCK_header->lhb_hash[hash_slot], &lock->lbl_lhb_hash);
|
|
|
|
insert_tail(&lock->lbl_requests, &request->lrq_lbl_requests);
|
2004-05-03 19:36:27 +02:00
|
|
|
request->lrq_lock = SRQ_REL_PTR(lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
grant(request, lock);
|
2008-01-17 14:40:35 +01:00
|
|
|
const SRQ_PTR lock_id = SRQ_REL_PTR(request);
|
2001-05-23 15:26:42 +02:00
|
|
|
release(request->lrq_owner);
|
|
|
|
|
|
|
|
return lock_id;
|
|
|
|
}
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
bool LOCK_set_owner_handle(SRQ_PTR request_offset,
|
|
|
|
SRQ_PTR new_owner_offset)
|
2007-04-24 16:05:46 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ s e t _ o w n e r _ h a n d l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Set new owner handle for granted request.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_set_owner_handle (%ld)\n", request_offset));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2007-04-24 16:05:46 +02:00
|
|
|
lrq* request = get_request(request_offset);
|
|
|
|
|
|
|
|
// We need not to change owner
|
|
|
|
if (request->lrq_owner == new_owner_offset)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
acquire(new_owner_offset);
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset); /* Re-init after a potential remap */
|
2008-02-11 18:30:23 +01:00
|
|
|
own* const old_owner = (own*) SRQ_ABS_PTR(request->lrq_owner);
|
2007-04-24 16:05:46 +02:00
|
|
|
fb_assert(old_owner->own_pending_request != request_offset);
|
2008-02-11 18:30:23 +01:00
|
|
|
own* const new_owner = (own*) SRQ_ABS_PTR(new_owner_offset);
|
2007-04-24 16:05:46 +02:00
|
|
|
fb_assert(new_owner->own_pending_request != request_offset);
|
2008-02-11 18:30:23 +01:00
|
|
|
const prc* const old_process = (prc*) SRQ_ABS_PTR(old_owner->own_process);
|
|
|
|
const prc* const new_process = (prc*) SRQ_ABS_PTR(new_owner->own_process);
|
|
|
|
fb_assert(old_process->prc_process_id == new_process->prc_process_id);
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl *lck = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2007-04-24 16:05:46 +02:00
|
|
|
|
|
|
|
// Make sure that change of lock owner is possible
|
|
|
|
SRQ lock_srq;
|
|
|
|
SRQ_LOOP(lck->lbl_requests, lock_srq) {
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* granted_request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_requests));
|
2007-04-24 16:05:46 +02:00
|
|
|
// One owner must have the only granted request on the same lock resource
|
|
|
|
if (granted_request->lrq_owner == new_owner_offset) {
|
|
|
|
LOCK_TRACE(("The owner already has a granted request"));
|
|
|
|
release(request->lrq_owner);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_que(&request->lrq_own_requests);
|
|
|
|
request->lrq_owner = new_owner_offset;
|
|
|
|
insert_tail(&new_owner->own_requests, &request->lrq_own_requests);
|
|
|
|
|
|
|
|
release(new_owner_offset);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
void LOCK_fini(ISC_STATUS* status_vector,
|
|
|
|
SRQ_PTR* owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ f i n i
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release the owner block and any outstanding locks.
|
|
|
|
* The exit handler will unmap the shared memory.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_fini(%ld)\n", *owner_offset));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
|
|
|
|
|
|
|
if (!LOCK_header)
|
|
|
|
return;
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR offset = *owner_offset;
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!offset || !owner->own_count)
|
|
|
|
return;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (--owner->own_count > 0)
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
acquire(offset);
|
|
|
|
owner = (own*) SRQ_ABS_PTR(offset); // Re-init after a potential remap
|
2003-03-24 15:32:34 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
purge_owner(offset, owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
release_mutex();
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
*owner_offset = (SRQ_PTR) 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
bool LOCK_init(ISC_STATUS* status_vector,
|
|
|
|
LOCK_OWNER_T owner_id,
|
|
|
|
UCHAR owner_type,
|
|
|
|
SRQ_PTR* owner_handle)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ i n i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Initialize lock manager for the given owner, if not already done.
|
|
|
|
*
|
|
|
|
* Initialize an owner block in the lock manager, if not already
|
|
|
|
* initialized.
|
|
|
|
*
|
|
|
|
* Return the offset of the owner block through owner_handle.
|
|
|
|
*
|
2002-11-14 09:33:08 +01:00
|
|
|
* Return FB_SUCCESS or FB_FAILURE.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_init (ownerid=%ld)\n", owner_id));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
|
|
|
|
|
|
|
// If everything is already initialized, just bump the use count
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
own* owner = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*owner_handle) {
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(*owner_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
owner->own_count++;
|
2008-02-11 18:30:23 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-01-16 08:40:12 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (!LOCK_header)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
// We haven't yet mapped the shared region. Do so now.
|
|
|
|
if (!init_lock_table(status_vector))
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
return create_owner(status_vector, owner_id, owner_type, owner_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
SLONG LOCK_query_data(SRQ_PTR parent_request,
|
|
|
|
USHORT series,
|
|
|
|
USHORT aggregate)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ q u e r y _ d a t a
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Query lock series data with respect to a rooted
|
|
|
|
* lock hierarchy calculating aggregates as we go.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-01-26 13:52:51 +01:00
|
|
|
if (!parent_request || series >= LCK_MAX_SERIES)
|
|
|
|
{
|
2003-09-04 23:26:15 +02:00
|
|
|
CHECK(false);
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Get root of lock hierarchy
|
2008-01-26 13:52:51 +01:00
|
|
|
|
|
|
|
lrq* parent = get_request(parent_request);
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
acquire(parent->lrq_owner);
|
2008-01-16 08:40:12 +01:00
|
|
|
parent = (lrq*) SRQ_ABS_PTR(parent_request); /* remap */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
++LOCK_header->lhb_query_data;
|
2003-12-31 06:36:12 +01:00
|
|
|
srq* data_header = &LOCK_header->lhb_data[series];
|
2004-12-16 04:03:13 +01:00
|
|
|
SLONG data = 0, count = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Simply walk the lock series data queue forward for the minimum
|
|
|
|
// and backward for the maximum -- it's maintained in sorted order.
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (aggregate) {
|
|
|
|
case LCK_MIN:
|
|
|
|
case LCK_CNT:
|
|
|
|
case LCK_AVG:
|
|
|
|
case LCK_SUM:
|
|
|
|
case LCK_ANY:
|
2004-05-03 19:36:27 +02:00
|
|
|
for (lock_srq = (SRQ) SRQ_ABS_PTR(data_header->srq_forward);
|
|
|
|
lock_srq != data_header; lock_srq = (SRQ) SRQ_ABS_PTR(lock_srq->srq_forward))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) ((UCHAR *) lock_srq - OFFSET(lbl*, lbl_lhb_data));
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(lock->lbl_series == series);
|
|
|
|
if (lock->lbl_parent != parent->lrq_lock)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (aggregate) {
|
|
|
|
case LCK_MIN:
|
|
|
|
data = lock->lbl_data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LCK_ANY:
|
|
|
|
case LCK_CNT:
|
|
|
|
++count;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LCK_AVG:
|
|
|
|
++count;
|
|
|
|
|
|
|
|
case LCK_SUM:
|
|
|
|
data += lock->lbl_data;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aggregate == LCK_MIN || aggregate == LCK_ANY)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aggregate == LCK_CNT || aggregate == LCK_ANY)
|
|
|
|
data = count;
|
|
|
|
else if (aggregate == LCK_AVG)
|
|
|
|
data = (count) ? data / count : 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LCK_MAX:
|
2004-05-03 19:36:27 +02:00
|
|
|
for (lock_srq = (SRQ) SRQ_ABS_PTR(data_header->srq_backward);
|
|
|
|
lock_srq != data_header; lock_srq = (SRQ) SRQ_ABS_PTR(lock_srq->srq_backward))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) ((UCHAR *) lock_srq - OFFSET(lbl*, lbl_lhb_data));
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(lock->lbl_series == series);
|
|
|
|
if (lock->lbl_parent != parent->lrq_lock)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
data = lock->lbl_data;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-09-04 23:26:15 +02:00
|
|
|
CHECK(false);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
release(parent->lrq_owner);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SLONG LOCK_read_data(SRQ_PTR request_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ r e a d _ d a t a
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read data associated with a lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_read_data(%ld)\n", request_offset));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
acquire(request->lrq_owner);
|
|
|
|
++LOCK_header->lhb_read_data;
|
2008-02-11 18:30:23 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset); // Re-init after a potential remap
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2003-12-31 06:36:12 +01:00
|
|
|
const SLONG data = lock->lbl_data;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_series < LCK_MAX_SERIES)
|
|
|
|
++LOCK_header->lhb_operations[lock->lbl_series];
|
|
|
|
else
|
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
|
|
|
|
release(request->lrq_owner);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SLONG LOCK_read_data2(SRQ_PTR parent_request,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT series,
|
2008-01-17 14:40:35 +01:00
|
|
|
const UCHAR* value,
|
|
|
|
USHORT length,
|
|
|
|
SRQ_PTR owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ r e a d _ d a t a 2
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read data associated with transient locks.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_read_data2(%ld)\n", parent_request));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
acquire(owner_offset);
|
|
|
|
++LOCK_header->lhb_read_data;
|
|
|
|
if (series < LCK_MAX_SERIES)
|
|
|
|
++LOCK_header->lhb_operations[series];
|
|
|
|
else
|
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ_PTR parent;
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (parent_request) {
|
|
|
|
request = get_request(parent_request);
|
|
|
|
parent = request->lrq_lock;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
parent = 0;
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SLONG data;
|
|
|
|
USHORT junk;
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = find_lock(parent, series, value, length, &junk);
|
2004-12-16 04:03:13 +01:00
|
|
|
if (lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
data = lock->lbl_data;
|
|
|
|
else
|
|
|
|
data = 0;
|
|
|
|
|
|
|
|
release(owner_offset);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
void LOCK_re_post(lock_ast_t ast,
|
|
|
|
void* arg,
|
|
|
|
SRQ_PTR owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ r e _ p o s t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Re-post an AST that was previously blocked.
|
|
|
|
* It is assumed that the routines that look
|
|
|
|
* at the re-post list only test the ast element.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
LOCK_TRACE(("LOCK_re_post(%ld)\n", owner_offset));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
acquire(owner_offset);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Allocate or reuse a lock request block
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
ASSERT_ACQUIRED;
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_EMPTY(LOCK_header->lhb_free_requests)) {
|
2008-01-16 08:40:12 +01:00
|
|
|
if (!(request = (lrq*) alloc(sizeof(lrq), NULL))) {
|
2001-05-23 15:26:42 +02:00
|
|
|
release(owner_offset);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ASSERT_ACQUIRED;
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) ((UCHAR *) SRQ_NEXT(LOCK_header->lhb_free_requests) -
|
|
|
|
OFFSET(lrq*, lrq_lbl_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&request->lrq_lbl_requests);
|
|
|
|
}
|
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_type = type_lrq;
|
|
|
|
request->lrq_flags = LRQ_repost;
|
2003-05-16 22:35:19 +02:00
|
|
|
request->lrq_ast_routine = ast;
|
|
|
|
request->lrq_ast_argument = arg;
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_requested = LCK_none;
|
|
|
|
request->lrq_state = LCK_none;
|
|
|
|
request->lrq_owner = owner_offset;
|
2004-05-03 19:36:27 +02:00
|
|
|
request->lrq_lock = (SRQ_PTR) 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
insert_tail(&owner->own_blocks, &request->lrq_own_blocks);
|
|
|
|
|
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
signal_owner((own*) SRQ_ABS_PTR(owner_offset), (SRQ_PTR) NULL);
|
2008-01-31 14:39:30 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
release(owner_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
SLONG LOCK_write_data(SRQ_PTR request_offset,
|
|
|
|
SLONG data)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* L O C K _ w r i t e _ d a t a
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write a longword into the lock block.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("LOCK_write_data (%ld)\n", request_offset));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2008-01-26 13:52:51 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
acquire(request->lrq_owner);
|
|
|
|
++LOCK_header->lhb_write_data;
|
2008-02-11 18:30:23 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset); // Re-init after a potential remap
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&lock->lbl_lhb_data);
|
|
|
|
if (lock->lbl_data = data)
|
|
|
|
insert_data_que(lock);
|
|
|
|
|
|
|
|
if (lock->lbl_series < LCK_MAX_SERIES)
|
|
|
|
++LOCK_header->lhb_operations[lock->lbl_series];
|
|
|
|
else
|
|
|
|
++LOCK_header->lhb_operations[0];
|
|
|
|
|
|
|
|
release(request->lrq_owner);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void acquire(SRQ_PTR owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a c q u i r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-01-16 08:40:12 +01:00
|
|
|
* Acquire the lock file. If it's busy, wait for it.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Measure the impact of the lock table resource as an overall
|
|
|
|
// system bottleneck. This will be useful metric for lock
|
|
|
|
// improvements and as a limiting factor for SMP. A conditional
|
|
|
|
// mutex would probably be more accurate but isn't worth the effort.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
SRQ_PTR prior_active = LOCK_header->lhb_active_owner;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Perform a spin wait on the lock table mutex. This should only
|
|
|
|
// be used on SMP machines; it doesn't make much sense otherwise.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
const SLONG acquire_spins = Config::getLockAcquireSpins();
|
|
|
|
|
|
|
|
SLONG status = FB_FAILURE;
|
|
|
|
SLONG spins = 0;
|
|
|
|
while (spins++ < acquire_spins) {
|
2003-03-11 06:53:01 +01:00
|
|
|
if ((status = ISC_mutex_lock_cond(MUTEX)) == FB_SUCCESS) {
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If the spin wait didn't succeed then wait forever
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-03-11 06:53:01 +01:00
|
|
|
if (status != FB_SUCCESS) {
|
|
|
|
if (ISC_mutex_lock(MUTEX)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
bug(NULL, "semop failed (acquire)");
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
++LOCK_header->lhb_acquires;
|
2003-03-11 06:53:01 +01:00
|
|
|
if (prior_active) {
|
2001-05-23 15:26:42 +02:00
|
|
|
++LOCK_header->lhb_acquire_blocks;
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (spins) {
|
|
|
|
++LOCK_header->lhb_acquire_retries;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (spins < acquire_spins) {
|
2001-05-23 15:26:42 +02:00
|
|
|
++LOCK_header->lhb_retry_success;
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
prior_active = LOCK_header->lhb_active_owner;
|
|
|
|
LOCK_header->lhb_active_owner = owner_offset;
|
|
|
|
|
|
|
|
if (LOCK_header->lhb_length > LOCK_data.sh_mem_length_mapped
|
2008-02-11 18:30:23 +01:00
|
|
|
#ifdef LOCK_DEBUG_REMAP
|
|
|
|
// If we're debugging remaps, force a remap every-so-often.
|
|
|
|
|| ((debug_remap_count++ % DEBUG_REMAP_INTERVAL) == 0 && LOCK_process_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2008-02-11 18:30:23 +01:00
|
|
|
)
|
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
SLONG length = LOCK_header->lhb_length;
|
2008-02-11 18:30:23 +01:00
|
|
|
|
|
|
|
#if (defined HAVE_MMAP || defined WIN_NT)
|
|
|
|
Firebird::WriteLockGuard guard(remapSync);
|
|
|
|
// Post remapping notifications
|
|
|
|
remap_local_owners();
|
|
|
|
// Remap the shared memory region
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2008-01-16 08:40:12 +01:00
|
|
|
lhb* const header =
|
2008-02-11 18:30:23 +01:00
|
|
|
(lhb*) ISC_remap_file(status_vector, &LOCK_data, length, false);
|
2008-01-16 08:40:12 +01:00
|
|
|
if (header)
|
|
|
|
LOCK_header = header;
|
|
|
|
else
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
bug(NULL, "remap failed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If we were able to acquire the MUTEX, but there is an prior owner marked
|
|
|
|
// in the the lock table, it means that someone died while owning
|
|
|
|
// the lock mutex. In that event, lets see if there is any unfinished work
|
|
|
|
// left around that we need to finish up.
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (prior_active) {
|
2004-05-03 19:36:27 +02:00
|
|
|
post_history(his_active, owner_offset, prior_active, (SRQ_PTR) 0, false);
|
2008-01-16 08:40:12 +01:00
|
|
|
shb* recover = (shb*) SRQ_ABS_PTR(LOCK_header->lhb_secondary);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (recover->shb_remove_node) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// There was a remove_que operation in progress when the prior_owner died
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_MSG(0, ("Got to the funky shb_remove_node code\n"));
|
2004-05-03 19:36:27 +02:00
|
|
|
remove_que((SRQ) SRQ_ABS_PTR(recover->shb_remove_node));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (recover->shb_insert_que && recover->shb_insert_prior) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// There was a insert_que operation in progress when the prior_owner died
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_MSG(0, ("Got to the funky shb_insert_que code\n"));
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq = (SRQ) SRQ_ABS_PTR(recover->shb_insert_que);
|
2004-05-03 19:36:27 +02:00
|
|
|
lock_srq->srq_backward = recover->shb_insert_prior;
|
|
|
|
lock_srq = (SRQ) SRQ_ABS_PTR(recover->shb_insert_prior);
|
|
|
|
lock_srq->srq_forward = recover->shb_insert_que;
|
2001-05-23 15:26:42 +02:00
|
|
|
recover->shb_insert_que = 0;
|
|
|
|
recover->shb_insert_prior = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static UCHAR* alloc(SSHORT size, ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate a block of given size.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-10-27 19:42:47 +01:00
|
|
|
size = FB_ALIGN(size, ALIGNMENT);
|
2001-05-23 15:26:42 +02:00
|
|
|
ASSERT_ACQUIRED;
|
2003-12-31 06:36:12 +01:00
|
|
|
const ULONG block = LOCK_header->lhb_used;
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header->lhb_used += size;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make sure we haven't overflowed the lock table. If so, bump the size of the table.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (LOCK_header->lhb_used > LOCK_header->lhb_length
|
|
|
|
#ifdef LOCK_DEBUG_REMAP
|
|
|
|
// If we're debugging remaps, force a remap every-so-often.
|
|
|
|
|| ((debug_remap_count++ % DEBUG_REMAP_INTERVAL) == 0 && LOCK_process_offset)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
2008-03-18 12:34:50 +01:00
|
|
|
const bool extend = (LOCK_header->lhb_used > LOCK_header->lhb_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header->lhb_used -= size;
|
2008-02-11 18:30:23 +01:00
|
|
|
|
|
|
|
#if (defined HAVE_MMAP || defined WIN_NT)
|
|
|
|
Firebird::WriteLockGuard guard(remapSync);
|
|
|
|
// Post remapping notifications
|
|
|
|
remap_local_owners();
|
|
|
|
// Remap the shared memory region
|
2008-03-04 20:07:55 +01:00
|
|
|
const ULONG length = LOCK_data.sh_mem_length_mapped +
|
2008-03-18 12:34:50 +01:00
|
|
|
(extend ? Config::getLockMemSize() : 0);
|
2008-02-11 18:30:23 +01:00
|
|
|
lhb* header = (lhb*) ISC_remap_file(status_vector, &LOCK_data, length, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (header) {
|
|
|
|
LOCK_header = header;
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
LOCK_header->lhb_length = LOCK_data.sh_mem_length_mapped;
|
|
|
|
LOCK_header->lhb_used += size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
// Do not do abort in case if there is not enough room -- just
|
|
|
|
// return an error
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (status_vector) {
|
2003-11-11 13:19:20 +01:00
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_random;
|
|
|
|
*status_vector++ = isc_arg_string;
|
2003-04-10 12:08:31 +02:00
|
|
|
*status_vector++ = (ISC_STATUS) "lock manager out of room";
|
2003-11-11 13:19:20 +01:00
|
|
|
*status_vector++ = isc_arg_end;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-08-09 23:51:33 +02:00
|
|
|
return NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
2008-02-11 18:30:23 +01:00
|
|
|
// This version of alloc() doesn't initialize memory. To shake out
|
|
|
|
// any bugs, in DEV_BUILD we initialize it to a "funny" pattern.
|
2004-05-03 19:36:27 +02:00
|
|
|
memset((void*)SRQ_ABS_PTR(block), 0xFD, size);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
return (UCHAR*) SRQ_ABS_PTR(block);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static lbl* alloc_lock(USHORT length, ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate a lock for a key of a given length. Look first to see
|
|
|
|
* if a spare of the right size is sitting around. If not, allocate
|
|
|
|
* one.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
length = (length + 3) & ~3;
|
|
|
|
|
|
|
|
ASSERT_ACQUIRED;
|
2004-05-03 19:36:27 +02:00
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(LOCK_header->lhb_free_locks, lock_srq) {
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) ((UCHAR *) lock_srq - OFFSET(lbl*, lbl_lhb_hash));
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_size == length) {
|
|
|
|
remove_que(&lock->lbl_lhb_hash);
|
|
|
|
lock->lbl_type = type_lbl;
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) alloc(sizeof(lbl) + length, status_vector);
|
2003-12-31 06:36:12 +01:00
|
|
|
if (lock) {
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lbl_size = length;
|
|
|
|
lock->lbl_type = type_lbl;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// NOTE: if the above alloc() fails do not release mutex here but rather
|
|
|
|
// release it in LOCK_enq() (as of now it is the only function that
|
|
|
|
// calls alloc_lock()). We need to hold mutex to be able
|
|
|
|
// to release a lock request block.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
static void blocking_action(SRQ_PTR blocking_owner_offset,
|
|
|
|
SRQ_PTR blocked_owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-01-26 13:52:51 +01:00
|
|
|
* b l o c k i n g _ a c t i o n
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-03-12 17:42:51 +01:00
|
|
|
* Fault handler for a blocking signal. A blocking signal
|
2001-05-23 15:26:42 +02:00
|
|
|
* is an indication (albeit a strong one) that a blocking
|
|
|
|
* AST is pending for the owner. Check in with the data
|
|
|
|
* structure for details.
|
|
|
|
* The re-post code in this routine assumes that no more
|
|
|
|
* than one thread of execution can be running in this
|
|
|
|
* routine at any time.
|
|
|
|
*
|
|
|
|
* IMPORTANT: Before calling this routine, acquire() should
|
|
|
|
* have already been done.
|
|
|
|
*
|
|
|
|
* Note that both a blocking owner offset and blocked owner
|
|
|
|
* offset are passed to this function. This is for those
|
|
|
|
* cases where the owners are not the same. If they are
|
|
|
|
* the same, then the blocked owner offset will be NULL.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(blocking_owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!blocked_owner_offset)
|
|
|
|
blocked_owner_offset = blocking_owner_offset;
|
|
|
|
|
|
|
|
while (owner->own_count) {
|
2004-05-03 19:36:27 +02:00
|
|
|
srq* lock_srq = SRQ_NEXT(owner->own_blocks);
|
|
|
|
if (lock_srq == &owner->own_blocks) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// We've processed the own_blocks queue, reset the "we've been
|
|
|
|
// signaled" flag and start winding out of here
|
|
|
|
owner->own_flags &= ~OWN_signaled;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_blocks));
|
2003-12-31 06:36:12 +01:00
|
|
|
lock_ast_t routine = request->lrq_ast_routine;
|
|
|
|
void* arg = request->lrq_ast_argument;
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&request->lrq_own_blocks);
|
|
|
|
if (request->lrq_flags & LRQ_blocking) {
|
|
|
|
request->lrq_flags &= ~LRQ_blocking;
|
|
|
|
request->lrq_flags |= LRQ_blocking_seen;
|
|
|
|
++LOCK_header->lhb_blocks;
|
|
|
|
post_history(his_post_ast, blocking_owner_offset,
|
2004-05-03 19:36:27 +02:00
|
|
|
request->lrq_lock, SRQ_REL_PTR(request), true);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (request->lrq_flags & LRQ_repost) {
|
|
|
|
request->lrq_type = type_null;
|
|
|
|
insert_tail(&LOCK_header->lhb_free_requests,
|
|
|
|
&request->lrq_lbl_requests);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (routine) {
|
|
|
|
release(blocked_owner_offset);
|
2008-02-11 18:30:23 +01:00
|
|
|
localMutex->leave();
|
2003-05-16 22:35:19 +02:00
|
|
|
(*routine)(arg);
|
2008-02-11 18:30:23 +01:00
|
|
|
localMutex->enter();
|
2001-05-23 15:26:42 +02:00
|
|
|
acquire(blocked_owner_offset);
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(blocking_owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
2004-06-08 15:41:08 +02:00
|
|
|
static THREAD_ENTRY_DECLARE blocking_action_thread(THREAD_ENTRY_PARAM arg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-01-16 08:40:12 +01:00
|
|
|
* b l o c k i n g _ a c t i o n _ t h r e a d
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Thread to handle blocking signals.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-02-11 18:30:23 +01:00
|
|
|
SRQ_PTR* process_offset_ptr = (SRQ_PTR*) arg;
|
2007-08-20 15:28:01 +02:00
|
|
|
bool atStartup = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-04 23:26:15 +02:00
|
|
|
while (true) {
|
2008-02-11 18:30:23 +01:00
|
|
|
localMutex->enter();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if the main thread has requested us to go away
|
|
|
|
if (!*process_offset_ptr ||
|
|
|
|
LOCK_process->prc_process_id != LOCK_pid)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2007-08-20 15:28:01 +02:00
|
|
|
if (atStartup)
|
|
|
|
{
|
2008-01-23 16:52:40 +01:00
|
|
|
startupSemaphore->release();
|
2007-08-20 15:28:01 +02:00
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const SLONG value = ISC_event_clear(&LOCK_process->prc_blocking);
|
2008-01-16 08:40:12 +01:00
|
|
|
|
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::HalfStaticArray<SRQ_PTR, 4> blocking_owners;
|
|
|
|
|
|
|
|
acquire(DUMMY_OWNER);
|
|
|
|
const prc* const process = (prc*) SRQ_ABS_PTR(*process_offset_ptr);
|
|
|
|
|
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(process->prc_owners, lock_srq)
|
|
|
|
{
|
|
|
|
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_prc_owners));
|
|
|
|
blocking_owners.add(SRQ_REL_PTR(owner));
|
|
|
|
}
|
2008-01-16 08:40:12 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
release_mutex();
|
|
|
|
|
|
|
|
while (blocking_owners.getCount())
|
|
|
|
{
|
|
|
|
const SRQ_PTR owner_offset = blocking_owners.pop();
|
|
|
|
acquire(owner_offset);
|
|
|
|
blocking_action(owner_offset, (SRQ_PTR) NULL);
|
|
|
|
release(owner_offset);
|
|
|
|
}
|
2007-08-20 15:28:01 +02:00
|
|
|
|
|
|
|
if (atStartup)
|
|
|
|
{
|
|
|
|
atStartup = false;
|
2008-01-23 16:52:40 +01:00
|
|
|
startupSemaphore->release();
|
2007-08-20 15:28:01 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
localMutex->leave();
|
|
|
|
|
|
|
|
event_t* event_ptr = &LOCK_process->prc_blocking;
|
2008-01-16 08:40:12 +01:00
|
|
|
ISC_event_wait(1, &event_ptr, &value, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
localMutex->leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Wakeup the main thread waiting for our exit
|
|
|
|
cleanupSemaphore->release();
|
2008-01-16 08:40:12 +01:00
|
|
|
|
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
2008-01-17 14:40:35 +01:00
|
|
|
static void bug_assert(const TEXT* string, ULONG line)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* b u g _ a s s e r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Disasterous lock manager bug. Issue message and abort process.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-12-08 07:03:05 +01:00
|
|
|
TEXT buffer[MAXPATHLEN + 100];
|
2003-09-18 12:24:03 +02:00
|
|
|
lhb LOCK_header_copy;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-01-16 17:49:15 +01:00
|
|
|
sprintf((char *) buffer, "%s %"ULONGFORMAT": lock assertion failure: %.60s\n",
|
2001-05-23 15:26:42 +02:00
|
|
|
__FILE__, line, string);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Copy the shared memory so we can examine its state when we crashed
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header_copy = *LOCK_header;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
bug(NULL, buffer); // Never returns
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void bug(ISC_STATUS* status_vector, const TEXT* string)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* b u g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Disasterous lock manager bug. Issue message and abort process.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-12-08 07:03:05 +01:00
|
|
|
TEXT s[2 * MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-30 12:01:30 +01:00
|
|
|
#ifdef WIN_NT
|
|
|
|
sprintf(s, "Fatal lock manager error: %s, errno: %ld", string, ERRNO);
|
|
|
|
#else
|
|
|
|
sprintf(s, "Fatal lock manager error: %s, errno: %d", string, ERRNO);
|
|
|
|
#endif
|
|
|
|
gds__log(s);
|
2004-04-29 00:36:29 +02:00
|
|
|
fprintf(stderr, "%s\n", s);
|
2003-10-30 12:01:30 +01:00
|
|
|
|
|
|
|
#if !(defined WIN_NT)
|
2008-02-11 18:30:23 +01:00
|
|
|
// The strerror() function returns the appropriate description string,
|
|
|
|
// or an unknown error message if the error code is unknown.
|
2004-04-29 00:36:29 +02:00
|
|
|
fprintf(stderr, "--%s\n", strerror(errno));
|
2003-10-30 12:01:30 +01:00
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!LOCK_bugcheck++) {
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
2008-02-11 18:30:23 +01:00
|
|
|
#ifndef WIN_NT
|
|
|
|
// The lock file has some problem - copy it for later analysis
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2002-11-04 12:19:21 +01:00
|
|
|
TEXT buffer[2 * MAXPATHLEN];
|
|
|
|
TEXT buffer2[2 * MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
TEXT hostname[64];
|
|
|
|
gds__prefix_lock(buffer, LOCK_FILE);
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* lock_file = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
sprintf(buffer2, lock_file,
|
|
|
|
ISC_get_host(hostname, sizeof(hostname)));
|
|
|
|
sprintf(buffer, "cp %s isc_lock1.%d", buffer2, getpid());
|
|
|
|
system(buffer);
|
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
#endif
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If the current mutex acquirer is in the same process,
|
|
|
|
// release the mutex
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (LOCK_header && (LOCK_header->lhb_active_owner > 0)) {
|
2008-02-11 18:30:23 +01:00
|
|
|
const own* const owner = (own*) SRQ_ABS_PTR(LOCK_header->lhb_active_owner);
|
|
|
|
const prc* const process = (prc*) SRQ_ABS_PTR(owner->own_process);
|
|
|
|
if (process->prc_process_id == LOCK_pid)
|
2001-05-23 15:26:42 +02:00
|
|
|
release(LOCK_header->lhb_active_owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status_vector) {
|
2003-11-11 13:19:20 +01:00
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_lockmanerr;
|
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_random;
|
|
|
|
*status_vector++ = isc_arg_string;
|
2003-04-10 12:08:31 +02:00
|
|
|
*status_vector++ = (ISC_STATUS) string;
|
2003-11-11 13:19:20 +01:00
|
|
|
*status_vector++ = isc_arg_end;
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make a core drop - we want to LOOK at this failure!
|
2001-05-23 15:26:42 +02:00
|
|
|
abort();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
exit(FINI_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static bool convert(SRQ_PTR request_offset,
|
|
|
|
UCHAR type,
|
|
|
|
SSHORT lck_wait,
|
2003-09-04 23:26:15 +02:00
|
|
|
lock_ast_t ast_routine,
|
2008-01-17 14:40:35 +01:00
|
|
|
void* ast_argument,
|
|
|
|
ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o n v e r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Perform a lock conversion, if possible. If the lock cannot be
|
|
|
|
* granted immediately, either return immediately or wait depending
|
2003-09-04 23:26:15 +02:00
|
|
|
* on a wait flag. If the lock is granted return true, otherwise
|
|
|
|
* return false. Note: if the conversion would cause a deadlock,
|
2001-05-23 15:26:42 +02:00
|
|
|
* FALSE is returned even if wait was requested.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR owner_offset = request->lrq_owner;
|
2001-05-23 15:26:42 +02:00
|
|
|
post_history(his_convert, owner_offset, request->lrq_lock, request_offset,
|
2003-09-04 23:26:15 +02:00
|
|
|
true);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_requested = type;
|
|
|
|
request->lrq_flags &= ~LRQ_blocking_seen;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Compute the state of the lock without the request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
--lock->lbl_counts[request->lrq_state];
|
2003-12-31 06:36:12 +01:00
|
|
|
const UCHAR temp = lock_state(lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If the requested lock level is compatible with the current state
|
|
|
|
// of the lock, just grant the request. Easy enough.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (compatibility[type][temp])
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
request->lrq_ast_routine = ast_routine;
|
|
|
|
request->lrq_ast_argument = ast_argument;
|
|
|
|
grant(request, lock);
|
|
|
|
post_pending(lock);
|
|
|
|
release(owner_offset);
|
2003-09-04 23:26:15 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
++lock->lbl_counts[request->lrq_state];
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If we weren't requested to wait, just forget about the whole thing.
|
|
|
|
// Otherwise wait for the request to be granted or rejected.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (lck_wait) {
|
2003-12-31 06:36:12 +01:00
|
|
|
bool new_ast;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->lrq_ast_routine != ast_routine ||
|
|
|
|
request->lrq_ast_argument != ast_argument)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2003-09-04 23:26:15 +02:00
|
|
|
new_ast = true;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-09-04 23:26:15 +02:00
|
|
|
new_ast = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (wait_for_request(request, lck_wait, status_vector))
|
2003-09-04 23:26:15 +02:00
|
|
|
return false;
|
2008-02-11 18:30:23 +01:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(request->lrq_flags & LRQ_rejected)) {
|
|
|
|
if (new_ast) {
|
|
|
|
acquire(owner_offset);
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_ast_routine = ast_routine;
|
|
|
|
request->lrq_ast_argument = ast_argument;
|
|
|
|
release(owner_offset);
|
|
|
|
}
|
2003-09-04 23:26:15 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
acquire(owner_offset);
|
|
|
|
request = get_request(request_offset);
|
2008-01-16 08:40:12 +01:00
|
|
|
lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
post_pending(lock);
|
|
|
|
}
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_requested = request->lrq_state;
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
++LOCK_header->lhb_denies;
|
|
|
|
if (lck_wait < 0)
|
|
|
|
++LOCK_header->lhb_timeouts;
|
|
|
|
release(owner_offset);
|
2003-11-11 13:19:20 +01:00
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = (lck_wait > 0) ? isc_deadlock :
|
|
|
|
((lck_wait < 0) ? isc_lock_timeout : isc_lock_conflict);
|
|
|
|
*status_vector++ = isc_arg_end;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-04 23:26:15 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
static bool create_owner(ISC_STATUS* status_vector,
|
|
|
|
LOCK_OWNER_T owner_id,
|
|
|
|
UCHAR owner_type,
|
2008-01-17 14:40:35 +01:00
|
|
|
SRQ_PTR* owner_handle)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c r e a t e _ o w n e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create an owner block.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-01-16 08:40:12 +01:00
|
|
|
if (LOCK_header->lhb_version != LHB_VERSION)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
TEXT bug_buffer[BUFFER_TINY];
|
|
|
|
sprintf(bug_buffer,
|
2001-05-23 15:26:42 +02:00
|
|
|
"inconsistent lock table version number; found %d, expected %d",
|
2008-01-16 08:40:12 +01:00
|
|
|
LOCK_header->lhb_version, LHB_VERSION);
|
|
|
|
bug(status_vector, bug_buffer);
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
acquire(DUMMY_OWNER); // acquiring owner is being created
|
|
|
|
|
|
|
|
// Allocate a process block, if required
|
|
|
|
|
|
|
|
if (!LOCK_process_offset)
|
|
|
|
{
|
|
|
|
if (!create_process(status_vector))
|
|
|
|
{
|
|
|
|
release_mutex();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look for a previous instance of owner. If we find one, get rid of it.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(LOCK_header->lhb_owners, lock_srq)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_lhb_owners));
|
2004-05-20 23:58:15 +02:00
|
|
|
if (owner->own_owner_id == owner_id &&
|
2001-05-23 15:26:42 +02:00
|
|
|
(UCHAR)owner->own_owner_type == owner_type)
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
purge_owner(DUMMY_OWNER, owner); /* purging owner_offset has not been set yet */
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Allocate an owner block
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
own* owner = 0;
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_EMPTY(LOCK_header->lhb_free_owners))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2006-04-29 02:34:06 +02:00
|
|
|
if (!(owner = (own*) alloc(sizeof(own), status_vector)))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
release_mutex();
|
2008-01-16 08:40:12 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) ((UCHAR *) SRQ_NEXT(LOCK_header->lhb_free_owners) -
|
|
|
|
OFFSET(own*, own_lhb_owners));
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&owner->own_lhb_owners);
|
|
|
|
}
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
init_owner_block(owner, owner_type, owner_id);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
insert_tail(&LOCK_header->lhb_owners, &owner->own_lhb_owners);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
prc* const process = (prc*) SRQ_ABS_PTR(owner->own_process);
|
|
|
|
insert_tail(&process->prc_owners, &owner->own_prc_owners);
|
|
|
|
|
|
|
|
probe_processes();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
*owner_handle = SRQ_REL_PTR(owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header->lhb_active_owner = *owner_handle;
|
|
|
|
|
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
|
|
|
validate_lhb(LOCK_header);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
release(*owner_handle);
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
static bool create_process(ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-02-11 18:30:23 +01:00
|
|
|
* c r e a t e _ p r o c e s s
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-02-11 18:30:23 +01:00
|
|
|
* Create a process block.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2008-02-11 18:30:23 +01:00
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(LOCK_header->lhb_processes, lock_srq)
|
|
|
|
{
|
|
|
|
prc* process = (prc*) ((UCHAR *) lock_srq - OFFSET(prc*, prc_lhb_processes));
|
|
|
|
if (process->prc_process_id == LOCK_pid)
|
|
|
|
{
|
|
|
|
purge_process(process);
|
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
prc* process = NULL;
|
|
|
|
if (SRQ_EMPTY(LOCK_header->lhb_free_processes))
|
|
|
|
{
|
|
|
|
if (!(process = (prc*) alloc(sizeof(prc), status_vector)))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
process = (prc*) ((UCHAR *) SRQ_NEXT(LOCK_header->lhb_free_processes) -
|
|
|
|
OFFSET(prc*, prc_lhb_processes));
|
|
|
|
remove_que(&process->prc_lhb_processes);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
process->prc_type = type_lpr;
|
|
|
|
process->prc_process_id = LOCK_pid;
|
|
|
|
SRQ_INIT(process->prc_owners);
|
|
|
|
SRQ_INIT(process->prc_lhb_processes);
|
|
|
|
process->prc_flags = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
insert_tail(&LOCK_header->lhb_processes, &process->prc_lhb_processes);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
|
|
|
ISC_event_init(&process->prc_blocking, 0, BLOCKING_SIGNAL);
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
LOCK_process_offset = SRQ_REL_PTR(process);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
#if defined HAVE_MMAP || defined WIN_NT
|
|
|
|
LOCK_process = (prc*) ISC_map_object(status_vector, &LOCK_data,
|
|
|
|
LOCK_process_offset, sizeof(prc));
|
|
|
|
#else
|
|
|
|
LOCK_process = process;
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (!LOCK_process)
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
|
|
|
const ULONG status =
|
|
|
|
gds__thread_start(blocking_action_thread,
|
|
|
|
&LOCK_process_offset, THREAD_high, 0, 0);
|
|
|
|
if (status)
|
|
|
|
{
|
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_lockmanerr;
|
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_sys_request;
|
|
|
|
*status_vector++ = isc_arg_string;
|
|
|
|
#ifdef WIN_NT
|
|
|
|
*status_vector++ = (ISC_STATUS) "CreateThread";
|
|
|
|
*status_vector++ = isc_arg_win32;
|
|
|
|
#else
|
|
|
|
*status_vector++ = (ISC_STATUS) "thr_create";
|
|
|
|
*status_vector++ = isc_arg_unix;
|
|
|
|
#endif
|
|
|
|
*status_vector++ = status;
|
|
|
|
*status_vector++ = isc_arg_end;
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void deadlock_clear()
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e a d l o c k _ c l e a r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Clear deadlock and scanned bits for pending requests
|
|
|
|
* in preparation for a deadlock scan.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
2004-05-03 19:36:27 +02:00
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(LOCK_header->lhb_owners, lock_srq) {
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_lhb_owners));
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR pending_offset = owner->own_pending_request;
|
2003-12-31 06:36:12 +01:00
|
|
|
if (!pending_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* pending = (lrq*) SRQ_ABS_PTR(pending_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
pending->lrq_flags &= ~(LRQ_deadlock | LRQ_scanned);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
static lrq* deadlock_scan(own* owner,
|
|
|
|
lrq* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e a d l o c k _ s c a n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Given an owner block that has been stalled for some time, find
|
|
|
|
* a deadlock cycle if there is one. If a deadlock is found, return
|
|
|
|
* the address of a pending lock request in the deadlock request.
|
|
|
|
* If no deadlock is found, return null.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(
|
2004-05-03 19:36:27 +02:00
|
|
|
("deadlock_scan: owner %ld request %ld\n", SRQ_REL_PTR(owner),
|
|
|
|
SRQ_REL_PTR(request)));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
++LOCK_header->lhb_scans;
|
|
|
|
post_history(his_scan, request->lrq_owner, request->lrq_lock,
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_REL_PTR(request), true);
|
2001-05-23 15:26:42 +02:00
|
|
|
deadlock_clear();
|
|
|
|
|
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
|
|
|
validate_lhb(LOCK_header);
|
|
|
|
#endif
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
bool maybe_deadlock = false;
|
|
|
|
lrq* victim = deadlock_walk(request, &maybe_deadlock);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Only when it is certain that this request is not part of a deadlock do we
|
|
|
|
// mark this request as 'scanned' so that we will not check this request again.
|
|
|
|
// Note that this request might be part of multiple deadlocks.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!victim && !maybe_deadlock)
|
|
|
|
owner->own_flags |= OWN_scanned;
|
|
|
|
#ifdef DEBUG
|
|
|
|
else if (!victim && maybe_deadlock)
|
|
|
|
DEBUG_MSG(0, ("deadlock_scan: not marking due to maybe_deadlock\n"));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return victim;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
static lrq* deadlock_walk(lrq* request,
|
2008-01-17 14:40:35 +01:00
|
|
|
bool* maybe_deadlock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e a d l o c k _ w a l k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Given a request that is waiting, determine whether a deadlock has
|
|
|
|
* occured.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If this request was scanned for deadlock earlier than don't visit it again
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->lrq_flags & LRQ_scanned)
|
|
|
|
return NULL;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If this request has been seen already during this deadlock-walk, then we
|
|
|
|
// detected a circle in the wait-for graph. Return "deadlock".
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->lrq_flags & LRQ_deadlock)
|
|
|
|
return request;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Remember that this request is part of the wait-for graph
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->lrq_flags |= LRQ_deadlock;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Check if this is a conversion request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
const bool conversion = (request->lrq_state > LCK_null);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Find the parent lock of the request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Loop thru the requests granted against the lock. If any granted request is
|
|
|
|
// blocking the request we're handling, recurse to find what's blocking him.
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(lock->lbl_requests, lock_srq) {
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* block = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_lbl_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (!lockOrdering() || conversion)
|
|
|
|
{
|
|
|
|
// Don't pursue our own lock-request again
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request == block)
|
|
|
|
continue;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Since lock conversions can't follow the fairness rules (to avoid
|
|
|
|
// deadlocks), only granted lock requests need to be examined.
|
|
|
|
// If lock-ordering is turned off (opening the door for starvation),
|
|
|
|
// only granted requests can block our request.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (compatibility[request->lrq_requested][block->lrq_state])
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Don't pursue our own lock-request again. In addition, don't look
|
|
|
|
// at requests that arrived after our request because lock-ordering
|
|
|
|
// is in effect.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request == block)
|
|
|
|
break;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Since lock ordering is in effect, granted locks and waiting
|
|
|
|
// requests that arrived before our request could block us
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (compatibility
|
|
|
|
[request->lrq_requested][MAX(block->lrq_state, block->lrq_requested)])
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Don't pursue lock owners that are not blocked themselves
|
|
|
|
// (they can't cause a deadlock).
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(block->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Don't pursue lock owners that still have to finish processing their AST.
|
|
|
|
// If the blocking queue is not empty, then the owner still has some
|
|
|
|
// AST's to process (or lock reposts).
|
|
|
|
// Remember this fact because they still might be part of a deadlock.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (owner->own_flags & OWN_signaled || !SRQ_EMPTY((owner->own_blocks)))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2003-09-04 23:26:15 +02:00
|
|
|
*maybe_deadlock = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// YYY: Note: can the below code be moved to the
|
|
|
|
// start of this block? Before the OWN_signaled check?
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Get pointer to the waiting request whose owner also owns a lock
|
|
|
|
// that blocks the input request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
const SRQ_PTR pending_offset = owner->own_pending_request;
|
2003-12-31 06:36:12 +01:00
|
|
|
if (!pending_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* target = (lrq*) SRQ_ABS_PTR(pending_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If this waiting request is not pending anymore, then things are changing
|
|
|
|
// and this request cannot be part of a deadlock
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(target->lrq_flags & LRQ_pending))
|
|
|
|
continue;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Check who is blocking the request whose owner is blocking the input request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (target = deadlock_walk(target, maybe_deadlock))
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// This branch of the wait-for graph is exhausted, the current waiting
|
|
|
|
// request is not part of a deadlock
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->lrq_flags &= ~LRQ_deadlock;
|
|
|
|
request->lrq_flags |= LRQ_scanned;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void dequeue(SRQ_PTR request_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e q u e u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release an outstanding lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Acquire the data structure, and compute addresses of both lock
|
|
|
|
// request and lock
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lrq* request = get_request(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
post_history(his_deq, request->lrq_owner, request->lrq_lock,
|
2003-09-04 23:26:15 +02:00
|
|
|
request_offset, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_ast_routine = NULL;
|
|
|
|
release_request(request);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
static ULONG delay_count = 0;
|
|
|
|
static ULONG last_signal_line = 0;
|
|
|
|
static ULONG last_delay_line = 0;
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void debug_delay(ULONG lineno)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e b u g _ d e l a y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* This is a debugging routine, the purpose of which is to slow
|
|
|
|
* down operations in order to expose windows of critical
|
|
|
|
* sections.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ULONG i;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Delay for a while
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
last_delay_line = lineno;
|
|
|
|
for (i = 0; i < 10000; i++)
|
2008-02-11 18:30:23 +01:00
|
|
|
; // Nothing
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Occasionally crash for robustness testing
|
2001-05-23 15:26:42 +02:00
|
|
|
/*
|
2008-02-11 18:30:23 +01:00
|
|
|
if ((delay_count % 500) == 0)
|
|
|
|
exit (-1);
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
for (i = 0; i < 10000; i++)
|
2008-02-11 18:30:23 +01:00
|
|
|
; // Nothing
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void exit_handler(void* arg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x i t _ h a n d l e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release the process block, any outstanding locks,
|
|
|
|
* and unmap the lock manager. This is usually called
|
|
|
|
* by the cleanup handler.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-03-05 03:51:42 +01:00
|
|
|
ISC_STATUS_ARRAY local_status = {0};
|
2008-03-04 20:07:55 +01:00
|
|
|
Firebird::MutexLockGuard guard(localMutex);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Get rid of all the owners belonging to the current process
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-03-04 20:07:55 +01:00
|
|
|
const SRQ_PTR process_offset = LOCK_process_offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-03-04 20:07:55 +01:00
|
|
|
if (process_offset)
|
|
|
|
{
|
|
|
|
shutdown_blocking_thread(local_status);
|
2008-02-11 18:30:23 +01:00
|
|
|
acquire(DUMMY_OWNER);
|
2008-03-04 20:07:55 +01:00
|
|
|
prc* const process = (prc*) SRQ_ABS_PTR(process_offset);
|
|
|
|
purge_process(process);
|
2001-05-23 15:26:42 +02:00
|
|
|
release_mutex();
|
|
|
|
}
|
|
|
|
|
2008-03-04 20:07:55 +01:00
|
|
|
if (LOCK_header)
|
|
|
|
{
|
|
|
|
ISC_unmap_file(local_status, &LOCK_data, 0);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static lbl* find_lock(SRQ_PTR parent,
|
|
|
|
USHORT series,
|
|
|
|
const UCHAR* value,
|
|
|
|
USHORT length,
|
|
|
|
USHORT* slot)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Find a lock block given a resource
|
|
|
|
* name. If it doesn't exist, the hash
|
|
|
|
* slot will be useful for enqueing a
|
|
|
|
* lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Hash the value preserving its distribution as much as possible
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
ULONG hash_value = 0;
|
|
|
|
{ // scope
|
2004-08-26 20:14:14 +02:00
|
|
|
UCHAR* p = NULL; // silence uninitialized warning
|
2003-12-31 06:36:12 +01:00
|
|
|
const UCHAR* q = value;
|
|
|
|
for (USHORT l = 0; l < length; l++) {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(l & 3))
|
2003-12-31 06:36:12 +01:00
|
|
|
p = (UCHAR *) &hash_value;
|
2007-09-25 22:28:20 +02:00
|
|
|
*p++ += *q++;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
} // scope
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if the lock already exists
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
const USHORT hash_slot = *slot = (USHORT) (hash_value % LOCK_header->lhb_hash_slots);
|
2001-05-23 15:26:42 +02:00
|
|
|
ASSERT_ACQUIRED;
|
2003-12-31 06:36:12 +01:00
|
|
|
srq* hash_header = &LOCK_header->lhb_hash[hash_slot];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
for (srq* lock_srq = (SRQ) SRQ_ABS_PTR(hash_header->srq_forward);
|
|
|
|
lock_srq != hash_header; lock_srq = (SRQ) SRQ_ABS_PTR(lock_srq->srq_forward))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) ((UCHAR *) lock_srq - OFFSET(lbl*, lbl_lhb_hash));
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_series != series ||
|
|
|
|
lock->lbl_length != length || lock->lbl_parent != parent)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (!length || !memcmp(value, lock->lbl_key, length))
|
|
|
|
return lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static lrq* get_request(SRQ_PTR offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ r e q u e s t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Locate and validate user supplied request offset.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT s[32];
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request = (lrq*) SRQ_ABS_PTR(offset);
|
2008-01-17 14:40:35 +01:00
|
|
|
if (offset == -1 || request->lrq_type != type_lrq) {
|
2003-04-01 13:43:47 +02:00
|
|
|
sprintf(s, "invalid lock id (%"SLONGFORMAT")", offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
bug(NULL, s);
|
|
|
|
}
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
const lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lbl_type != type_lbl) {
|
2003-04-01 13:43:47 +02:00
|
|
|
sprintf(s, "invalid lock (%"SLONGFORMAT")", offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
bug(NULL, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
return request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void grant(lrq* request, lbl* lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g r a n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Grant a lock request. If the lock is a conversion, assume the caller
|
|
|
|
* has already decremented the former lock type count in the lock block.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Request must be for THIS lock
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(SRQ_REL_PTR(lock) == request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
post_history(his_grant, request->lrq_owner, request->lrq_lock,
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_REL_PTR(request), true);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
++lock->lbl_counts[request->lrq_requested];
|
|
|
|
request->lrq_state = request->lrq_requested;
|
|
|
|
if (request->lrq_data) {
|
|
|
|
remove_que(&lock->lbl_lhb_data);
|
|
|
|
if (lock->lbl_data = request->lrq_data)
|
|
|
|
insert_data_que(lock);
|
|
|
|
request->lrq_data = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
lock->lbl_state = lock_state(lock);
|
|
|
|
if (request->lrq_flags & LRQ_pending)
|
|
|
|
{
|
|
|
|
request->lrq_flags &= ~LRQ_pending;
|
|
|
|
lock->lbl_pending_lrq_count--;
|
|
|
|
}
|
2006-04-29 02:34:06 +02:00
|
|
|
post_wakeup((own*) SRQ_ABS_PTR(request->lrq_owner));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static SRQ_PTR grant_or_que(lrq* request, lbl* lock, SSHORT lck_wait)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g r a n t _ o r _ q u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* There is a request against an existing lock. If the request
|
2004-05-03 19:36:27 +02:00
|
|
|
* is compatible with the lock, grant it. Otherwise lock_srq it.
|
|
|
|
* If the lock is lock_srq-ed, set up the machinery to do a deadlock
|
2001-05-23 15:26:42 +02:00
|
|
|
* scan in awhile.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-05-03 19:36:27 +02:00
|
|
|
const SRQ_PTR request_offset = SRQ_REL_PTR(request);
|
|
|
|
request->lrq_lock = SRQ_REL_PTR(lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Compatible requests are easy to satify. Just post the request to the lock,
|
|
|
|
// update the lock state, release the data structure, and we're done.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (compatibility[request->lrq_requested][lock->lbl_state]) {
|
|
|
|
if (!lockOrdering() ||
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_requested == LCK_null ||
|
2003-12-31 06:36:12 +01:00
|
|
|
(lock->lbl_pending_lrq_count == 0))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
grant(request, lock);
|
|
|
|
post_pending(lock);
|
|
|
|
release(request->lrq_owner);
|
|
|
|
return request_offset;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// The request isn't compatible with the current state of the lock.
|
|
|
|
// If we haven't be asked to wait for the lock, return now.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (lck_wait)
|
|
|
|
{
|
2003-08-28 15:07:29 +02:00
|
|
|
wait_for_request(request, lck_wait, NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// For performance reasons, we're going to look at the
|
|
|
|
// request's status without re-acquiring the lock table.
|
|
|
|
// This is safe as no-one can take away the request, once
|
|
|
|
// granted, and we're doing a read-only access
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Request HAS been resolved
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!(request->lrq_flags & LRQ_pending));
|
|
|
|
|
|
|
|
if (!(request->lrq_flags & LRQ_rejected))
|
|
|
|
return request_offset;
|
|
|
|
acquire(request->lrq_owner);
|
|
|
|
}
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
post_history(his_deny, request->lrq_owner, request->lrq_lock,
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_REL_PTR(request), true);
|
2001-05-23 15:26:42 +02:00
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
++LOCK_header->lhb_denies;
|
|
|
|
if (lck_wait < 0)
|
|
|
|
++LOCK_header->lhb_timeouts;
|
2004-05-03 19:36:27 +02:00
|
|
|
const SRQ_PTR owner_offset = request->lrq_owner;
|
2001-05-23 15:26:42 +02:00
|
|
|
release_request(request);
|
|
|
|
release(owner_offset);
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
return (SRQ_PTR)0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static bool init_lock_table(ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n i t _ l o c k _ t a b l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Initialize the global lock table for the first time.
|
|
|
|
* Read the config file, map the shared region, etc.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
LOCK_pid = getpid();
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
TEXT buffer[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
gds__prefix_lock(buffer, LOCK_FILE);
|
2004-12-16 04:03:13 +01:00
|
|
|
TEXT* lock_file = buffer;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (!(LOCK_header = (lhb*) ISC_map_file(status_vector, lock_file,
|
|
|
|
lock_initialize, 0,
|
|
|
|
Config::getLockMemSize(),
|
|
|
|
&LOCK_data)))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gds__register_cleanup(exit_handler, 0);
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
static void init_owner_block(own* owner,
|
2001-05-23 15:26:42 +02:00
|
|
|
UCHAR owner_type,
|
2008-01-16 08:40:12 +01:00
|
|
|
LOCK_OWNER_T owner_id)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n i t _ o w n e r _ b l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Initialize the passed owner block nice and new.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
owner->own_type = type_own;
|
|
|
|
owner->own_owner_type = owner_type;
|
|
|
|
owner->own_flags = 0;
|
|
|
|
owner->own_count = 1;
|
|
|
|
owner->own_owner_id = owner_id;
|
2008-02-11 18:30:23 +01:00
|
|
|
owner->own_process = LOCK_process_offset;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(owner->own_lhb_owners);
|
2008-02-11 18:30:23 +01:00
|
|
|
SRQ_INIT(owner->own_prc_owners);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(owner->own_requests);
|
|
|
|
SRQ_INIT(owner->own_blocks);
|
2001-05-23 15:26:42 +02:00
|
|
|
owner->own_pending_request = 0;
|
|
|
|
owner->own_acquire_time = 0;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
ISC_event_init(&owner->own_wakeup, 0, WAKEUP_SIGNAL);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
static void lock_initialize(void* arg, SH_MEM shmem_data, bool initialize)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* l o c k _ i n i t i a l i z e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Initialize the lock header block. The caller is assumed
|
|
|
|
* to have an exclusive lock on the lock file.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-10-24 16:53:49 +02:00
|
|
|
#ifdef WIN_NT
|
2003-08-18 18:53:42 +02:00
|
|
|
char buffer[MAXPATHLEN];
|
|
|
|
gds__prefix_lock(buffer, LOCK_FILE);
|
|
|
|
if (ISC_mutex_init(MUTEX, buffer)) {
|
2002-10-24 16:53:49 +02:00
|
|
|
bug(NULL, "mutex init failed");
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
2002-10-27 13:51:38 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
LOCK_header = (lhb*) shmem_data->sh_mem_address;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-03-11 06:53:01 +01:00
|
|
|
if (!initialize) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-18 12:24:03 +02:00
|
|
|
memset(LOCK_header, 0, sizeof(lhb));
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header->lhb_type = type_lhb;
|
|
|
|
LOCK_header->lhb_version = LHB_VERSION;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Mark ourselves as active owner to prevent fb_assert() checks
|
|
|
|
LOCK_header->lhb_active_owner = DUMMY_OWNER; // In init of lock system
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
SRQ_INIT(LOCK_header->lhb_processes);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(LOCK_header->lhb_owners);
|
2008-02-11 18:30:23 +01:00
|
|
|
SRQ_INIT(LOCK_header->lhb_free_processes);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT(LOCK_header->lhb_free_owners);
|
|
|
|
SRQ_INIT(LOCK_header->lhb_free_locks);
|
|
|
|
SRQ_INIT(LOCK_header->lhb_free_requests);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-10-27 13:51:38 +01:00
|
|
|
#ifndef WIN_NT
|
2008-01-16 08:40:12 +01:00
|
|
|
if (ISC_mutex_init(MUTEX)) {
|
2002-10-27 13:51:38 +01:00
|
|
|
bug(NULL, "mutex init failed");
|
2003-03-11 06:53:01 +01:00
|
|
|
}
|
2002-10-27 13:51:38 +01:00
|
|
|
#endif
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
int hash_slots = Config::getLockHashSlots();
|
|
|
|
if (hash_slots < HASH_MIN_SLOTS)
|
|
|
|
hash_slots = HASH_MIN_SLOTS;
|
|
|
|
if (hash_slots > HASH_MAX_SLOTS)
|
|
|
|
hash_slots = HASH_MAX_SLOTS;
|
|
|
|
|
|
|
|
LOCK_header->lhb_hash_slots = (USHORT) hash_slots;
|
|
|
|
LOCK_header->lhb_scan_interval = Config::getDeadlockTimeout();
|
|
|
|
LOCK_header->lhb_acquire_spins = Config::getLockAcquireSpins();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Initialize lock series data queues and lock hash chains
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
USHORT i;
|
|
|
|
SRQ lock_srq;
|
2004-05-03 19:36:27 +02:00
|
|
|
for (i = 0, lock_srq = LOCK_header->lhb_data; i < LCK_MAX_SERIES; i++, lock_srq++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT((*lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-05-03 19:36:27 +02:00
|
|
|
for (i = 0, lock_srq = LOCK_header->lhb_hash; i < LOCK_header->lhb_hash_slots;
|
|
|
|
i++, lock_srq++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT((*lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Set lock_ordering flag for the first time
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (Config::getLockGrantOrder())
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header->lhb_flags |= LHB_lock_ordering;
|
|
|
|
|
2007-01-24 20:48:58 +01:00
|
|
|
const SLONG length =
|
2003-09-18 12:24:03 +02:00
|
|
|
sizeof(lhb) +
|
2001-05-23 15:26:42 +02:00
|
|
|
(LOCK_header->lhb_hash_slots * sizeof(LOCK_header->lhb_hash[0]));
|
|
|
|
LOCK_header->lhb_length = shmem_data->sh_mem_length_mapped;
|
2003-10-27 19:42:47 +01:00
|
|
|
LOCK_header->lhb_used = FB_ALIGN(length, ALIGNMENT);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
shb* secondary_header = (shb*) alloc(sizeof(shb), NULL);
|
2004-12-16 04:03:13 +01:00
|
|
|
if (!secondary_header)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
gds__log("Fatal lock manager error: lock manager out of room");
|
|
|
|
exit(STARTUP_ERROR);
|
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
LOCK_header->lhb_secondary = SRQ_REL_PTR(secondary_header);
|
2003-09-18 12:24:03 +02:00
|
|
|
secondary_header->shb_type = type_shb;
|
|
|
|
secondary_header->shb_remove_node = 0;
|
|
|
|
secondary_header->shb_insert_que = 0;
|
|
|
|
secondary_header->shb_insert_prior = 0;
|
2008-02-11 18:30:23 +01:00
|
|
|
|
|
|
|
// Allocate a sufficiency of history blocks
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
his* history;
|
2004-12-16 04:03:13 +01:00
|
|
|
for (USHORT j = 0; j < 2; j++)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ_PTR* prior = (j == 0) ?
|
|
|
|
&LOCK_header->lhb_history : &secondary_header->shb_history;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (i = 0; i < HISTORY_BLOCKS; i++)
|
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
if (!(history = (his*) alloc(sizeof(his), NULL)))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
gds__log("Fatal lock manager error: lock manager out of room");
|
|
|
|
exit(STARTUP_ERROR);
|
|
|
|
}
|
2004-05-03 19:36:27 +02:00
|
|
|
*prior = SRQ_REL_PTR(history);
|
2001-05-23 15:26:42 +02:00
|
|
|
history->his_type = type_his;
|
|
|
|
history->his_operation = 0;
|
|
|
|
prior = &history->his_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
history->his_next =
|
2003-09-18 12:24:03 +02:00
|
|
|
(j == 0) ? LOCK_header->lhb_history : secondary_header->shb_history;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Done initializing, unmark owner information
|
2001-05-23 15:26:42 +02:00
|
|
|
LOCK_header->lhb_active_owner = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void insert_data_que(lbl* lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n s e r t _ d a t a _ q u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Insert a node in the lock series data queue
|
|
|
|
* in sorted (ascending) order by lock data.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (lock->lbl_series < LCK_MAX_SERIES && lock->lbl_parent
|
2003-12-31 06:36:12 +01:00
|
|
|
&& lock->lbl_data)
|
|
|
|
{
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ data_header = &LOCK_header->lhb_data[lock->lbl_series];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq;
|
2004-05-03 19:36:27 +02:00
|
|
|
for (lock_srq = (SRQ) SRQ_ABS_PTR(data_header->srq_forward);
|
|
|
|
lock_srq != data_header; lock_srq = (SRQ) SRQ_ABS_PTR(lock_srq->srq_forward))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock2 = (lbl*) ((UCHAR *) lock_srq - OFFSET(lbl*, lbl_lhb_data));
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(lock2->lbl_series == lock->lbl_series);
|
|
|
|
if (lock2->lbl_parent != lock->lbl_parent)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (lock->lbl_data <= lock2->lbl_data)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
insert_tail(lock_srq, &lock->lbl_lhb_data);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void insert_tail(SRQ lock_srq, SRQ node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n s e r t _ t a i l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2004-05-03 19:36:27 +02:00
|
|
|
* Insert a node at the tail of a lock_srq.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
* To handle the event of the process terminating during
|
|
|
|
* the insertion of the node, we set values in the shb to
|
|
|
|
* indicate the node being inserted.
|
|
|
|
* Then, should we be unable to complete
|
|
|
|
* the node insert, the next process into the lock table
|
|
|
|
* will notice the uncompleted work and undo it,
|
|
|
|
* eg: it will put the queue back to the state
|
|
|
|
* prior to the insertion being started.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
2008-01-16 08:40:12 +01:00
|
|
|
shb* recover = (shb*) SRQ_ABS_PTR(LOCK_header->lhb_secondary);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
recover->shb_insert_que = SRQ_REL_PTR(lock_srq);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
recover->shb_insert_prior = lock_srq->srq_backward;
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
node->srq_forward = SRQ_REL_PTR(lock_srq);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
node->srq_backward = lock_srq->srq_backward;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_DELAY;
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ prior = (SRQ) SRQ_ABS_PTR(lock_srq->srq_backward);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
prior->srq_forward = SRQ_REL_PTR(node);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
lock_srq->srq_backward = SRQ_REL_PTR(node);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
|
|
|
|
|
|
|
recover->shb_insert_que = 0;
|
|
|
|
DEBUG_DELAY;
|
|
|
|
recover->shb_insert_prior = 0;
|
|
|
|
DEBUG_DELAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static USHORT lock_state(lbl* lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* l o c k _ s t a t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Compute the current state of a lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (lock->lbl_counts[LCK_EX])
|
|
|
|
return LCK_EX;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lock->lbl_counts[LCK_PW])
|
2001-05-23 15:26:42 +02:00
|
|
|
return LCK_PW;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lock->lbl_counts[LCK_SW])
|
2001-05-23 15:26:42 +02:00
|
|
|
return LCK_SW;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lock->lbl_counts[LCK_PR])
|
2001-05-23 15:26:42 +02:00
|
|
|
return LCK_PR;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lock->lbl_counts[LCK_SR])
|
2001-05-23 15:26:42 +02:00
|
|
|
return LCK_SR;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lock->lbl_counts[LCK_null])
|
2001-05-23 15:26:42 +02:00
|
|
|
return LCK_null;
|
|
|
|
|
|
|
|
return LCK_none;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-19 03:34:55 +01:00
|
|
|
static void post_blockage(lrq* request, lbl* lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p o s t _ b l o c k a g e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* The current request is blocked. Post blocking notices to
|
|
|
|
* any process blocking the request.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-02-11 18:30:23 +01:00
|
|
|
const SRQ_PTR owner_offset = request->lrq_owner;
|
|
|
|
own* owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
ASSERT_ACQUIRED;
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(owner->own_pending_request == SRQ_REL_PTR(request));
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(request->lrq_flags & LRQ_pending);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
Firebird::HalfStaticArray<SRQ_PTR, 16> blocking_owners;
|
|
|
|
|
|
|
|
SRQ lock_srq;
|
|
|
|
SRQ_LOOP(lock->lbl_requests, lock_srq)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-03-12 17:42:51 +01:00
|
|
|
lrq* const block = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_lbl_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Figure out if this lock request is blocking our own lock request.
|
|
|
|
// Of course, our own request cannot block ourselves. Compatible
|
|
|
|
// requests don't block us, and if there is no AST routine for the
|
|
|
|
// request the block doesn't matter as we can't notify anyone.
|
|
|
|
// If the owner has marked the request with LRQ_blocking_seen
|
|
|
|
// then the blocking AST has been delivered and the owner promises
|
|
|
|
// to release the lock as soon as possible (so don't bug the owner).
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (block == request ||
|
2008-01-16 08:40:12 +01:00
|
|
|
compatibility[request->lrq_requested][block->lrq_state] ||
|
2001-05-23 15:26:42 +02:00
|
|
|
!block->lrq_ast_routine ||
|
2008-02-11 18:30:23 +01:00
|
|
|
(block->lrq_flags & LRQ_blocking_seen))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
own* blocking_owner = (own*) SRQ_ABS_PTR(block->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Add the blocking request to the list of blocks if it's not
|
|
|
|
// there already (LRQ_blocking)
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(block->lrq_flags & LRQ_blocking)) {
|
|
|
|
insert_tail(&blocking_owner->own_blocks, &block->lrq_own_blocks);
|
|
|
|
block->lrq_flags |= LRQ_blocking;
|
|
|
|
block->lrq_flags &= ~LRQ_blocking_seen;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (blocking_owner != owner)
|
|
|
|
blocking_owners.add(block->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (block->lrq_state == LCK_EX)
|
|
|
|
break;
|
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
|
|
|
|
Firebird::HalfStaticArray<SRQ_PTR, 16> dead_processes;
|
|
|
|
|
|
|
|
while (blocking_owners.getCount())
|
|
|
|
{
|
|
|
|
own* const blocking_owner = (own*) SRQ_ABS_PTR(blocking_owners.pop());
|
|
|
|
if (!signal_owner(blocking_owner, owner_offset))
|
|
|
|
{
|
|
|
|
dead_processes.add(blocking_owner->own_process);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (dead_processes.getCount())
|
|
|
|
{
|
|
|
|
prc* const process = (prc*) SRQ_ABS_PTR(dead_processes.pop());
|
|
|
|
if (process->prc_process_id)
|
|
|
|
purge_process(process);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-04 23:26:15 +02:00
|
|
|
static void post_history(USHORT operation,
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR process,
|
|
|
|
SRQ_PTR lock,
|
|
|
|
SRQ_PTR request,
|
2003-09-04 23:26:15 +02:00
|
|
|
bool old_version)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p o s t _ h i s t o r y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Post a history item.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-01-16 08:40:12 +01:00
|
|
|
his* history;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (old_version) {
|
2008-01-16 08:40:12 +01:00
|
|
|
history = (his*) SRQ_ABS_PTR(LOCK_header->lhb_history);
|
2001-05-23 15:26:42 +02:00
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
LOCK_header->lhb_history = history->his_next;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ASSERT_ACQUIRED;
|
2008-01-16 08:40:12 +01:00
|
|
|
shb* recover = (shb*) SRQ_ABS_PTR(LOCK_header->lhb_secondary);
|
|
|
|
history = (his*) SRQ_ABS_PTR(recover->shb_history);
|
|
|
|
recover->shb_history = history->his_next;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
history->his_operation = operation;
|
|
|
|
history->his_process = process;
|
|
|
|
history->his_lock = lock;
|
|
|
|
history->his_request = request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void post_pending(lbl* lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p o s t _ p e n d i n g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* There has been a change in state of a lock. Check pending
|
|
|
|
* requests to see if something can be granted. If so, do it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
USHORT pending_counter = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (lock->lbl_pending_lrq_count == 0)
|
|
|
|
return;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Loop thru granted requests looking for pending conversions. If one
|
|
|
|
// is found, check to see if it can be granted. Even if a request cannot
|
|
|
|
// be granted for compatibility reason, post_wakeup () that owner so that
|
|
|
|
// it can post_blockage() to the newly granted owner of the lock.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(lock->lbl_requests, lock_srq) {
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_lbl_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(request->lrq_flags & LRQ_pending))
|
|
|
|
continue;
|
|
|
|
if (request->lrq_state)
|
|
|
|
{
|
|
|
|
--lock->lbl_counts[request->lrq_state];
|
2004-12-16 04:03:13 +01:00
|
|
|
const UCHAR temp_state = lock_state(lock);
|
2008-01-16 08:40:12 +01:00
|
|
|
if (compatibility[request->lrq_requested][temp_state])
|
2001-05-23 15:26:42 +02:00
|
|
|
grant(request, lock);
|
|
|
|
else {
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
pending_counter++;
|
|
|
|
#endif
|
|
|
|
++lock->lbl_counts[request->lrq_state];
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(request->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
post_wakeup(owner);
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lockOrdering()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(lock->lbl_pending_lrq_count >= pending_counter);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-16 08:40:12 +01:00
|
|
|
else if (compatibility[request->lrq_requested][lock->lbl_state])
|
2001-05-23 15:26:42 +02:00
|
|
|
grant(request, lock);
|
|
|
|
else {
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
pending_counter++;
|
|
|
|
#endif
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(request->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
post_wakeup(owner);
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lockOrdering()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(lock->lbl_pending_lrq_count >= pending_counter);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(lock->lbl_pending_lrq_count == pending_counter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void post_wakeup(own* owner)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-01-16 08:40:12 +01:00
|
|
|
* p o s t _ w a k e u p
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Wakeup whoever is waiting on a lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (owner->own_flags & OWN_waiting)
|
|
|
|
{
|
|
|
|
++LOCK_header->lhb_wakeups;
|
|
|
|
owner->own_flags |= OWN_wakeup;
|
|
|
|
ISC_event_post(&owner->own_wakeup);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
static bool probe_processes()
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-02-11 18:30:23 +01:00
|
|
|
* p r o b e _ p r o c e s s e s
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-02-11 18:30:23 +01:00
|
|
|
* Probe processes to see if any has died. If one has, get rid of it.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
2008-02-11 18:30:23 +01:00
|
|
|
|
|
|
|
Firebird::HalfStaticArray<prc*, 16> dead_processes;
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq;
|
2008-02-11 18:30:23 +01:00
|
|
|
SRQ_LOOP(LOCK_header->lhb_processes, lock_srq)
|
|
|
|
{
|
|
|
|
prc* const process = (prc*) ((UCHAR *) lock_srq - OFFSET(prc*, prc_lhb_processes));
|
|
|
|
if (process->prc_process_id != LOCK_pid &&
|
2008-02-13 17:47:34 +01:00
|
|
|
!ISC_check_process_existence(process->prc_process_id))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
dead_processes.add(process);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const bool purged = (dead_processes.getCount() > 0);
|
|
|
|
|
|
|
|
while (dead_processes.getCount())
|
|
|
|
{
|
|
|
|
prc* const process = dead_processes.pop();
|
|
|
|
if (process->prc_process_id)
|
|
|
|
purge_process(process);
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return purged;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
static void purge_owner(SRQ_PTR purging_owner_offset, own* owner)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-02-11 18:30:23 +01:00
|
|
|
* p u r g e _ o w n e r
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Purge an owner and all of its associated locks.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("purge_owner (%ld)\n", purging_owner_offset));
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
post_history(his_del_owner, purging_owner_offset, SRQ_REL_PTR(owner), 0,
|
2003-09-04 23:26:15 +02:00
|
|
|
false);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Release any locks that are active
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq;
|
2004-05-03 19:36:27 +02:00
|
|
|
while ((lock_srq = SRQ_NEXT(owner->own_requests)) != &owner->own_requests) {
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
release_request(request);
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Release any repost requests left dangling on blocking queue
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
while ((lock_srq = SRQ_NEXT(owner->own_blocks)) != &owner->own_blocks) {
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_blocks));
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&request->lrq_own_blocks);
|
|
|
|
request->lrq_type = type_null;
|
|
|
|
insert_tail(&LOCK_header->lhb_free_requests,
|
|
|
|
&request->lrq_lbl_requests);
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Release owner block
|
|
|
|
|
|
|
|
remove_que(&owner->own_prc_owners);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
remove_que(&owner->own_lhb_owners);
|
|
|
|
insert_tail(&LOCK_header->lhb_free_owners, &owner->own_lhb_owners);
|
|
|
|
|
|
|
|
owner->own_owner_type = 0;
|
|
|
|
owner->own_owner_id = 0;
|
2008-02-11 18:30:23 +01:00
|
|
|
owner->own_process = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
owner->own_flags = 0;
|
2008-01-16 08:40:12 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
ISC_event_fini(&owner->own_wakeup);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void purge_process(prc* process)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p u r g e _ p r o c e s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Purge all owners of the given process.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("purge_process (%ld)\n", process->prc_process_id));
|
|
|
|
|
|
|
|
SRQ lock_srq;
|
|
|
|
while ((lock_srq = SRQ_NEXT(process->prc_owners)) != &process->prc_owners)
|
|
|
|
{
|
|
|
|
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_prc_owners));
|
|
|
|
purge_owner(SRQ_REL_PTR(owner), owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_que(&process->prc_lhb_processes);
|
|
|
|
insert_tail(&LOCK_header->lhb_free_processes, &process->prc_lhb_processes);
|
|
|
|
|
|
|
|
process->prc_process_id = 0;
|
|
|
|
process->prc_flags = 0;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
2008-02-11 18:30:23 +01:00
|
|
|
ISC_event_fini(&process->prc_blocking);
|
2008-01-16 08:40:12 +01:00
|
|
|
#endif
|
2008-02-11 18:30:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void remap_local_owners()
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e m a p _ l o c a l _ o w n e r s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Wakeup all local (in-process) waiting owners
|
|
|
|
* and prepare them for the shared region being remapped.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
fb_assert(LOCK_process_offset);
|
|
|
|
fb_assert(LOCK_process);
|
|
|
|
|
|
|
|
prc* const process = (prc*) SRQ_ABS_PTR(LOCK_process_offset);
|
|
|
|
srq* lock_srq;
|
|
|
|
SRQ_LOOP(process->prc_owners, lock_srq)
|
|
|
|
{
|
|
|
|
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_prc_owners));
|
|
|
|
if (owner->own_flags & OWN_waiting)
|
|
|
|
{
|
|
|
|
ISC_event_post(&owner->own_wakeup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (waitingOwners.value() > 0)
|
|
|
|
THREAD_SLEEP(1);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void remove_que(SRQ node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e m o v e _ q u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2004-05-03 19:36:27 +02:00
|
|
|
* Remove a node from a self-relative lock_srq.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
* To handle the event of the process terminating during
|
|
|
|
* the removal of the node, we set shb_remove_node to the
|
|
|
|
* node to be removed. Then, should we be unsuccessful
|
|
|
|
* in the node removal, the next process into the lock table
|
|
|
|
* will notice the uncompleted work and complete it.
|
|
|
|
*
|
|
|
|
* Note that the work is completed by again calling this routine,
|
|
|
|
* specifing the node to be removed. As the prior and following
|
|
|
|
* nodes may have changed prior to the crash, we need to redo the
|
|
|
|
* work only based on what is in <node>.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
2008-01-16 08:40:12 +01:00
|
|
|
shb* recover = (shb*) SRQ_ABS_PTR(LOCK_header->lhb_secondary);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
recover->shb_remove_node = SRQ_REL_PTR(node);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
SRQ lock_srq = (SRQ) SRQ_ABS_PTR(node->srq_forward);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// The next link might point back to us, or our prior link should
|
|
|
|
// the backlink change occur before a crash
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(lock_srq->srq_backward == SRQ_REL_PTR(node) ||
|
|
|
|
lock_srq->srq_backward == node->srq_backward);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
lock_srq->srq_backward = node->srq_backward;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
lock_srq = (SRQ) SRQ_ABS_PTR(node->srq_backward);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// The prior link might point forward to us, or our following link should
|
|
|
|
// the change occur before a crash
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(lock_srq->srq_forward == SRQ_REL_PTR(node) ||
|
|
|
|
lock_srq->srq_forward == node->srq_forward);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2004-05-03 19:36:27 +02:00
|
|
|
lock_srq->srq_forward = node->srq_forward;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_DELAY;
|
|
|
|
recover->shb_remove_node = 0;
|
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// To prevent trying to remove this entry a second time, which could occur
|
|
|
|
// for instance, when we're removing an owner, and crash while removing
|
|
|
|
// the owner's blocking requests, reset the lock_srq entry in this node.
|
|
|
|
// Note that if we get here, shb_remove_node has been cleared, so we
|
|
|
|
// no longer need the queue information.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_INIT((*node));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void release(SRQ_PTR owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e l e a s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release the mapped lock file. Advance the event count to wake up
|
|
|
|
* anyone waiting for it. If there appear to be blocking items
|
|
|
|
* posted.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (owner_offset && LOCK_header->lhb_active_owner != owner_offset)
|
|
|
|
bug(NULL, "release when not owner");
|
|
|
|
|
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate the lock table occasionally (every 500 releases)
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((LOCK_header->lhb_acquires % (HISTORY_BLOCKS / 2)) == 0)
|
|
|
|
validate_lhb(LOCK_header);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
release_mutex();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void release_mutex()
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e l e a s e _ m u t e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release the mapped lock file. Advance the event count to wake up
|
|
|
|
* anyone waiting for it. If there appear to be blocking items
|
|
|
|
* posted.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (!LOCK_header->lhb_active_owner)
|
|
|
|
bug(NULL, "release when not active");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
LOCK_header->lhb_active_owner = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
if (ISC_mutex_unlock(MUTEX))
|
|
|
|
bug(NULL, "semop failed (release)");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_DELAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static void release_request(lrq* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e l e a s e _ r e q u e s t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release a request. This is called both by release lock
|
|
|
|
* and by the cleanup handler.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Start by disconnecting request from both lock and process
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
remove_que(&request->lrq_lbl_requests);
|
|
|
|
remove_que(&request->lrq_own_requests);
|
|
|
|
|
|
|
|
request->lrq_type = type_null;
|
|
|
|
insert_tail(&LOCK_header->lhb_free_requests, &request->lrq_lbl_requests);
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If the request is marked as blocking, clean it up
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->lrq_flags & LRQ_blocking)
|
|
|
|
{
|
|
|
|
remove_que(&request->lrq_own_blocks);
|
|
|
|
request->lrq_flags &= ~LRQ_blocking;
|
|
|
|
}
|
|
|
|
|
|
|
|
request->lrq_flags &= ~LRQ_blocking_seen;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Update counts if we are cleaning up something we're waiting on!
|
|
|
|
// This should only happen if we are purging out an owner that died.
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->lrq_flags & LRQ_pending) {
|
|
|
|
request->lrq_flags &= ~LRQ_pending;
|
|
|
|
lock->lbl_pending_lrq_count--;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If there are no outstanding requests, release the lock
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_EMPTY(lock->lbl_requests))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
CHECK(lock->lbl_pending_lrq_count == 0);
|
2007-07-25 15:26:13 +02:00
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
2007-08-28 10:38:22 +02:00
|
|
|
if (LOCK_header->lhb_active_owner > 0)
|
|
|
|
validate_parent(LOCK_header, request->lrq_lock);
|
2007-07-25 15:26:13 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&lock->lbl_lhb_hash);
|
|
|
|
remove_que(&lock->lbl_lhb_data);
|
|
|
|
lock->lbl_type = type_null;
|
2008-01-16 08:40:12 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
insert_tail(&LOCK_header->lhb_free_locks, &lock->lbl_lhb_hash);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Re-compute the state of the lock and post any compatible pending requests
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if ((request->lrq_state != LCK_none) &&
|
|
|
|
!(--lock->lbl_counts[request->lrq_state]))
|
|
|
|
{
|
|
|
|
lock->lbl_state = lock_state(lock);
|
|
|
|
if (request->lrq_state != LCK_null)
|
|
|
|
{
|
|
|
|
post_pending(lock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If a lock enqueue failed because of a deadlock or timeout, the pending
|
|
|
|
// request may be holding up compatible, pending lock requests queued
|
|
|
|
// behind it.
|
|
|
|
// Or, even if this request had been granted, it's now being released,
|
|
|
|
// so we might be holding up requests or conversions queued up behind.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
post_pending(lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-04 20:07:55 +01:00
|
|
|
static void shutdown_blocking_thread(ISC_STATUS* status_vector)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s h u t d o w n _ b l o c k i n g _ t h r e a d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Shutdown the blocking thread and
|
|
|
|
* unmap the process pointer.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_process_offset = 0;
|
|
|
|
|
|
|
|
if (LOCK_process) {
|
|
|
|
#ifdef USE_BLOCKING_THREAD
|
|
|
|
// Wait for AST thread to start (or 5 secs)
|
|
|
|
localMutex->leave();
|
|
|
|
startupSemaphore->tryEnter(5);
|
|
|
|
localMutex->enter();
|
|
|
|
|
|
|
|
// Wakeup the AST thread - it might be blocking
|
|
|
|
ISC_event_post(&LOCK_process->prc_blocking);
|
|
|
|
|
|
|
|
// Wait for the AST thread to finish cleanup or for 5 seconds
|
|
|
|
localMutex->leave();
|
|
|
|
cleanupSemaphore->tryEnter(5);
|
|
|
|
localMutex->enter();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined HAVE_MMAP || defined WIN_NT
|
|
|
|
ISC_unmap_object(status_vector, &LOCK_data, (UCHAR**) &LOCK_process, sizeof(prc));
|
|
|
|
#else
|
|
|
|
LOCK_process = NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static bool signal_owner(own* blocking_owner, SRQ_PTR blocked_owner_offset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s i g n a l _ o w n e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Send a signal to a process.
|
|
|
|
*
|
|
|
|
* The second parameter is a possible offset to the
|
|
|
|
* blocked owner (or NULL), which is passed on to
|
2008-01-16 08:40:12 +01:00
|
|
|
* blocking_action().
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If a process, other than ourselves, hasn't yet seen a signal
|
|
|
|
// that was sent, don't bother to send another one
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
if (blocking_owner->own_flags & OWN_signaled)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
DEBUG_MSG(1,
|
|
|
|
("signal_owner (%ld) - skipped OWN_signaled\n",
|
|
|
|
blocking_owner->own_process_id));
|
2008-01-16 08:40:12 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
blocking_owner->own_flags |= OWN_signaled;
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2008-01-16 08:40:12 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
prc* process = (prc*) SRQ_ABS_PTR(blocking_owner->own_process);
|
|
|
|
|
|
|
|
// Deliver signal either locally or remotely
|
|
|
|
|
|
|
|
if (process->prc_process_id == LOCK_pid) {
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2008-01-16 08:40:12 +01:00
|
|
|
blocking_action(SRQ_REL_PTR(blocking_owner), blocked_owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
2008-01-16 08:40:12 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
DEBUG_DELAY;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
#ifdef USE_BLOCKING_THREAD
|
2008-02-11 18:30:23 +01:00
|
|
|
if (!ISC_event_post(&process->prc_blocking))
|
2008-01-16 08:40:12 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
DEBUG_MSG(1, ("signal_owner - direct delivery failed\n"));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
blocking_owner->own_flags &= ~OWN_signaled;
|
2001-05-23 15:26:42 +02:00
|
|
|
DEBUG_DELAY;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// We couldn't deliver signal. Let someone to purge the process.
|
2008-01-16 08:40:12 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VALIDATE_LOCK_TABLE
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const USHORT EXPECT_inuse = 0;
|
|
|
|
const USHORT EXPECT_freed = 1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const USHORT RECURSE_yes = 0;
|
|
|
|
const USHORT RECURSE_not = 1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_history(const SRQ_PTR history_header)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ h i s t o r y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate a circular list of history blocks.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
ULONG count = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
LOCK_TRACE(("validate_history: %ld\n", history_header));
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
for (const his* history = (his*) SRQ_ABS_PTR(history_header); true;
|
|
|
|
history = (his*) SRQ_ABS_PTR(history->his_next))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
count++;
|
|
|
|
CHECK(history->his_type == type_his);
|
|
|
|
CHECK(history->his_operation <= his_MAX);
|
|
|
|
if (history->his_next == history_header)
|
|
|
|
break;
|
|
|
|
CHECK(count <= HISTORY_BLOCKS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_parent(const lhb* alhb, const SRQ_PTR isSomeoneParent)
|
2007-07-25 15:26:13 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ p a r e n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate lock under release not to be someone parent.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-01-16 08:40:12 +01:00
|
|
|
if (alhb->lhb_active_owner == 0)
|
|
|
|
return;
|
2007-07-25 15:26:13 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const own* const owner = (own*) SRQ_ABS_PTR(alhb->lhb_active_owner);
|
2007-07-25 15:26:13 +02:00
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
const srq* lock_srq;
|
2007-07-25 15:26:13 +02:00
|
|
|
SRQ_LOOP(owner->own_requests, lock_srq)
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_requests));
|
2007-07-25 15:26:13 +02:00
|
|
|
|
|
|
|
if (!(request->lrq_flags & LRQ_repost))
|
|
|
|
{
|
|
|
|
if (request->lrq_lock != isSomeoneParent)
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
const lbl* const lock = (lbl*) SRQ_ABS_PTR(request->lrq_lock);
|
2007-07-25 15:26:13 +02:00
|
|
|
|
|
|
|
if (lock->lbl_parent == isSomeoneParent)
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
bug_assert("deleting someone's parent", __LINE__);
|
2007-07-25 15:26:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_lhb(const lhb* alhb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ l h b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate the LHB structure and everything that hangs off of it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
LOCK_TRACE(("validate_lhb:\n"));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Prevent recursive reporting of validation errors
|
2001-05-23 15:26:42 +02:00
|
|
|
if (LOCK_bugcheck)
|
|
|
|
return;
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
CHECK(alhb != NULL);
|
|
|
|
CHECK(alhb->lhb_type == type_lhb);
|
|
|
|
CHECK(alhb->lhb_version == LHB_VERSION);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
validate_shb(alhb->lhb_secondary);
|
|
|
|
if (alhb->lhb_active_owner > 0)
|
|
|
|
validate_owner(alhb->lhb_active_owner, EXPECT_inuse);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
const srq* lock_srq;
|
|
|
|
SRQ_LOOP(alhb->lhb_owners, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const own* const owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_lhb_owners));
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_owner(SRQ_REL_PTR(owner), EXPECT_inuse);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
SRQ_LOOP(alhb->lhb_free_owners, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const own* const owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_lhb_owners));
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_owner(SRQ_REL_PTR(owner), EXPECT_freed);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
SRQ_LOOP(alhb->lhb_free_locks, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lbl* const lock = (lbl*) ((UCHAR *) lock_srq - OFFSET(lbl*, lbl_lhb_hash));
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_lock(SRQ_REL_PTR(lock), EXPECT_freed, (SRQ_PTR) 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
SRQ_LOOP(alhb->lhb_free_requests, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_lbl_requests));
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_request(SRQ_REL_PTR(request), EXPECT_freed, RECURSE_not);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
CHECK(alhb->lhb_used <= alhb->lhb_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 14:07:46 +01:00
|
|
|
validate_history(alhb->lhb_history);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_MSG(0, ("validate_lhb completed:\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_lock(const SRQ_PTR lock_ptr, USHORT freed, const SRQ_PTR lrq_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate the lock structure and everything that hangs off of it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("validate_lock: %ld\n", lock_ptr));
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
const lbl* lock = (lbl*) SRQ_ABS_PTR(lock_ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (freed == EXPECT_freed)
|
|
|
|
CHECK(lock->lbl_type == type_null)
|
2007-07-29 04:32:41 +02:00
|
|
|
else
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(lock->lbl_type == type_lbl);
|
|
|
|
|
|
|
|
CHECK(lock->lbl_state < LCK_max);
|
|
|
|
|
|
|
|
CHECK(lock->lbl_length <= lock->lbl_size);
|
|
|
|
|
2007-08-02 04:00:37 +02:00
|
|
|
// The lbl_count's should never roll over to be negative
|
2007-07-29 04:32:41 +02:00
|
|
|
for (ULONG i = 0; i < FB_NELEM(lock->lbl_counts); i++)
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!(lock->lbl_counts[i] & 0x8000))
|
|
|
|
|
2007-08-02 04:00:37 +02:00
|
|
|
// The count of pending locks should never roll over to be negative
|
2006-04-29 02:34:06 +02:00
|
|
|
CHECK(!(lock->lbl_pending_lrq_count & 0x8000));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
USHORT direct_counts[LCK_max];
|
2001-05-23 15:26:42 +02:00
|
|
|
memset(direct_counts, 0, sizeof(direct_counts));
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
ULONG found = 0;
|
|
|
|
ULONG found_pending = 0;
|
2004-12-16 04:03:13 +01:00
|
|
|
UCHAR highest_request = LCK_none;
|
2007-07-29 04:32:41 +02:00
|
|
|
const srq* lock_srq;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(lock->lbl_requests, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Any requests of a freed lock should also be free
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(freed == EXPECT_inuse);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_lbl_requests));
|
|
|
|
// Note: Don't try to validate_request here, it leads to recursion
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_REL_PTR(request) == lrq_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
found++;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(found <= 1); // check for a loop in the queue
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Request must be for this lock
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(request->lrq_lock == lock_ptr);
|
|
|
|
|
|
|
|
if (request->lrq_requested > highest_request)
|
|
|
|
highest_request = request->lrq_requested;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If the request is pending, then it must be incompatible with current
|
|
|
|
// state of the lock - OR lock_ordering is enabled and there is at
|
|
|
|
// least one pending request in the queue (before this request
|
|
|
|
// but not including it).
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->lrq_flags & LRQ_pending) {
|
2008-01-16 08:40:12 +01:00
|
|
|
CHECK(!compatibility[request->lrq_requested][lock->lbl_state] ||
|
|
|
|
(lockOrdering() && found_pending));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// The above condition would probably be more clear if we
|
|
|
|
// wrote it as the following:
|
|
|
|
//
|
|
|
|
// CHECK (!compatibility[request->lrq_requested][lock->lbl_state] ||
|
|
|
|
// (lockOrdering() && found_pending &&
|
|
|
|
// compatibility[request->lrq_requested][lock->lbl_state]));
|
|
|
|
//
|
|
|
|
// but that would be redundant
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
found_pending++;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If the request is NOT pending, then it must be rejected or
|
|
|
|
// compatible with the current state of the lock
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(request->lrq_flags & LRQ_pending)) {
|
|
|
|
CHECK((request->lrq_flags & LRQ_rejected) ||
|
|
|
|
(request->lrq_requested == lock->lbl_state) ||
|
2008-01-16 08:40:12 +01:00
|
|
|
compatibility[request->lrq_requested][lock->lbl_state]);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
direct_counts[request->lrq_state]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((freed == EXPECT_inuse) && (lrq_ptr != 0))
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(found == 1); // request is in lock's queue
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
if (freed == EXPECT_inuse) {
|
|
|
|
CHECK(found_pending == lock->lbl_pending_lrq_count);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// The counter in the lock header should match the actual counts
|
|
|
|
// lock->lbl_counts [LCK_null] isn't maintained, so don't check it
|
2004-12-16 04:03:13 +01:00
|
|
|
for (USHORT j = LCK_null; j < LCK_max; j++)
|
|
|
|
CHECK(direct_counts[j] == lock->lbl_counts[j]);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lock->lbl_parent && (freed == EXPECT_inuse))
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_lock(lock->lbl_parent, EXPECT_inuse, (SRQ_PTR) 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_owner(const SRQ_PTR own_ptr, USHORT freed)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ o w n e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate the owner structure and everything that hangs off of it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("validate_owner: %ld\n", own_ptr));
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
const own* owner = (own*) SRQ_ABS_PTR(own_ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Note that owner->own_pending_request can be reset without the lock
|
|
|
|
// table being acquired - eg: by another process. That being the case,
|
|
|
|
// we need to stash away a copy of it for validation.
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
const SRQ_PTR owner_own_pending_request = owner->own_pending_request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
CHECK(owner->own_type == type_own);
|
|
|
|
if (freed == EXPECT_freed)
|
|
|
|
CHECK(owner->own_owner_type == 0)
|
|
|
|
else {
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(owner->own_owner_type <= 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(owner->own_acquire_time <= LOCK_header->lhb_acquires);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Check that no invalid flag bit is set
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!
|
2004-12-16 04:03:13 +01:00
|
|
|
(owner->own_flags &
|
2008-02-11 18:30:23 +01:00
|
|
|
~(OWN_blocking | OWN_scanned | OWN_waiting | OWN_wakeup | OWN_signaled)));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
const srq* lock_srq;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(owner->own_requests, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(freed == EXPECT_inuse); // should not be in loop for freed owner
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_requests));
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_request(SRQ_REL_PTR(request), EXPECT_inuse, RECURSE_not);
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(request->lrq_owner == own_ptr);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make sure that request marked as blocking also exists in the blocking list
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->lrq_flags & LRQ_blocking) {
|
2007-07-29 04:32:41 +02:00
|
|
|
ULONG found = 0;
|
|
|
|
const srq* que2;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(owner->own_blocks, que2) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que2_next = SRQ_NEXT((*que2));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que2_next->srq_backward == SRQ_REL_PTR(que2));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request2 =
|
2008-01-16 08:40:12 +01:00
|
|
|
(lrq*) ((UCHAR *) que2 - OFFSET(lrq*, lrq_own_blocks));
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(request2->lrq_owner == own_ptr);
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_REL_PTR(request2) == SRQ_REL_PTR(request))
|
2001-05-23 15:26:42 +02:00
|
|
|
found++;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(found <= 1); // watch for loops in queue
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(found == 1); // request marked as blocking must be in blocking queue
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Check each item in the blocking queue
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(owner->own_blocks, lock_srq) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que_next = SRQ_NEXT((*lock_srq));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que_next->srq_backward == SRQ_REL_PTR(lock_srq));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(freed == EXPECT_inuse); // should not be in loop for freed owner
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request = (lrq*) ((UCHAR *) lock_srq - OFFSET(lrq*, lrq_own_blocks));
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_request(SRQ_REL_PTR(request), EXPECT_inuse, RECURSE_not);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
LOCK_TRACE(("Validate own_block: %ld\n", SRQ_REL_PTR(request)));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
CHECK(request->lrq_owner == own_ptr);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// A repost won't be in the request list
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->lrq_flags & LRQ_repost)
|
|
|
|
continue;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make sure that each block also exists in the request list
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
ULONG found = 0;
|
|
|
|
const srq* que2;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(owner->own_requests, que2) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Validate that the next backpointer points back to us
|
|
|
|
const srq* const que2_next = SRQ_NEXT((*que2));
|
2004-05-03 19:36:27 +02:00
|
|
|
CHECK(que2_next->srq_backward == SRQ_REL_PTR(que2));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const request2 = (lrq*) ((UCHAR *) que2 - OFFSET(lrq*, lrq_own_requests));
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(request2->lrq_owner == own_ptr);
|
|
|
|
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_REL_PTR(request2) == SRQ_REL_PTR(request))
|
2001-05-23 15:26:42 +02:00
|
|
|
found++;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(found <= 1); // watch for loops in queue
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
CHECK(found == 1); // blocking request must be in request queue
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If there is a pending request, make sure it is valid, that it
|
|
|
|
// exists in the queue for the lock.
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (owner_own_pending_request && (freed == EXPECT_inuse)) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make sure pending request is valid, and we own it
|
|
|
|
const lrq* const request3 = (lrq*) SRQ_ABS_PTR(owner_own_pending_request);
|
2004-05-12 21:23:17 +02:00
|
|
|
validate_request(SRQ_REL_PTR(request3), EXPECT_inuse, RECURSE_not);
|
|
|
|
CHECK(request3->lrq_owner == own_ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make sure the lock the request is for is valid
|
|
|
|
const lbl* const lock = (lbl*) SRQ_ABS_PTR(request3->lrq_lock);
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_lock(SRQ_REL_PTR(lock), EXPECT_inuse, (SRQ_PTR) 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Make sure the pending request is on the list of requests for the lock
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
bool found_pending = false;
|
2007-07-29 04:32:41 +02:00
|
|
|
const srq* que_of_lbl_requests;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_LOOP(lock->lbl_requests, que_of_lbl_requests) {
|
2008-02-11 18:30:23 +01:00
|
|
|
const lrq* const pending =
|
2008-01-16 08:40:12 +01:00
|
|
|
(lrq*) ((UCHAR *) que_of_lbl_requests -
|
|
|
|
OFFSET(lrq*, lrq_lbl_requests));
|
2004-05-03 19:36:27 +02:00
|
|
|
if (SRQ_REL_PTR(pending) == owner_own_pending_request) {
|
2003-09-04 23:26:15 +02:00
|
|
|
found_pending = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// pending request must exist in the lock's request queue
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(found_pending);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Either the pending request is the same as what we stashed away, or it's
|
|
|
|
// been cleared by another process without the lock table acquired
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK((owner_own_pending_request == owner->own_pending_request) ||
|
|
|
|
!owner->own_pending_request);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_request(const SRQ_PTR lrq_ptr, USHORT freed, USHORT recurse)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ r e q u e s t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate the request structure and everything that hangs off of it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("validate_request: %ld\n", lrq_ptr));
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
const lrq* request = (lrq*) SRQ_ABS_PTR(lrq_ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (freed == EXPECT_freed)
|
|
|
|
CHECK(request->lrq_type == type_null)
|
2007-07-29 04:32:41 +02:00
|
|
|
else
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(request->lrq_type == type_lrq);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Check that no invalid flag bit is set
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!
|
2004-12-16 04:03:13 +01:00
|
|
|
(request->lrq_flags &
|
|
|
|
~(LRQ_blocking | LRQ_pending | LRQ_converting |
|
|
|
|
LRQ_rejected | LRQ_timed_out | LRQ_deadlock |
|
|
|
|
LRQ_repost | LRQ_scanned | LRQ_blocking_seen)));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// LRQ_converting & LRQ_timed_out are defined, but never actually used
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!(request->lrq_flags & (LRQ_converting | LRQ_timed_out)));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Once a request is rejected, it CAN'T be pending any longer
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->lrq_flags & LRQ_rejected)
|
|
|
|
CHECK(!(request->lrq_flags & LRQ_pending));
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Can't both be scanned & marked for deadlock walk
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK((request->lrq_flags & (LRQ_deadlock | LRQ_scanned)) !=
|
|
|
|
(LRQ_deadlock | LRQ_scanned));
|
|
|
|
|
|
|
|
CHECK(request->lrq_requested < LCK_max);
|
|
|
|
CHECK(request->lrq_state < LCK_max);
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
if (freed == EXPECT_inuse)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (recurse == RECURSE_yes)
|
|
|
|
validate_owner(request->lrq_owner, EXPECT_inuse);
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Reposted request are pseudo requests, not attached to any real lock
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(request->lrq_flags & LRQ_repost))
|
2004-05-03 19:36:27 +02:00
|
|
|
validate_lock(request->lrq_lock, EXPECT_inuse, SRQ_REL_PTR(request));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 04:32:41 +02:00
|
|
|
static void validate_shb(const SRQ_PTR shb_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* v a l i d a t e _ s h b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate the SHB structure and everything that hangs off of
|
|
|
|
* it.
|
|
|
|
* Of course, it would have been a VERY good thing if someone
|
|
|
|
* had moved this into lhb when we made a unique v4 lock
|
|
|
|
* manager....
|
|
|
|
* 1995-April-13 David Schnepper
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
LOCK_TRACE(("validate_shb: %ld\n", shb_ptr));
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
const shb* secondary_header = (shb*) SRQ_ABS_PTR(shb_ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-18 12:24:03 +02:00
|
|
|
CHECK(secondary_header->shb_type == type_shb);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-18 12:24:03 +02:00
|
|
|
validate_history(secondary_header->shb_history);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
|
|
|
|
#endif // VALIDATE_LOCK_TABLE
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2008-01-17 14:40:35 +01:00
|
|
|
static USHORT wait_for_request(lrq* request,
|
|
|
|
SSHORT lck_wait,
|
|
|
|
ISC_STATUS* status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w a i t _ f o r _ r e q u e s t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* There is a request that needs satisfaction, but is waiting for
|
|
|
|
* somebody else. Mark the request as pending and go to sleep until
|
|
|
|
* the lock gets poked. When we wake up, see if somebody else has
|
|
|
|
* cleared the pending flag. If not, go back to sleep.
|
|
|
|
* Returns
|
2002-11-14 09:33:08 +01:00
|
|
|
* FB_SUCCESS - we waited until the request was granted or rejected
|
|
|
|
* FB_FAILURE - Insufficient resouces to wait (eg: no semaphores)
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
ASSERT_ACQUIRED;
|
|
|
|
|
|
|
|
++LOCK_header->lhb_waits;
|
2004-12-16 04:03:13 +01:00
|
|
|
const SLONG scan_interval = LOCK_header->lhb_scan_interval;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// lrq_count will be off if we wait for a pending request
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!(request->lrq_flags & LRQ_pending));
|
|
|
|
|
|
|
|
request->lrq_flags &= ~LRQ_rejected;
|
|
|
|
request->lrq_flags |= LRQ_pending;
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR owner_offset = request->lrq_owner;
|
|
|
|
SRQ_PTR lock_offset = request->lrq_lock;
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* lock = (lbl*) SRQ_ABS_PTR(lock_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lbl_pending_lrq_count++;
|
2008-01-16 08:40:12 +01:00
|
|
|
if (lockOrdering()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!request->lrq_state) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// If ordering is in effect, and this is a conversion of
|
|
|
|
// an existing lock in LCK_none state - put the lock to the
|
|
|
|
// end of the list so it's not taking cuts in the lineup
|
2001-05-23 15:26:42 +02:00
|
|
|
remove_que(&request->lrq_lbl_requests);
|
|
|
|
insert_tail(&lock->lbl_requests, &request->lrq_lbl_requests);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
own* owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2004-05-03 19:36:27 +02:00
|
|
|
SRQ_PTR request_offset = SRQ_REL_PTR(request);
|
2003-12-31 06:36:12 +01:00
|
|
|
owner->own_pending_request = request_offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
owner->own_flags &= ~(OWN_scanned | OWN_wakeup);
|
2008-01-16 08:40:12 +01:00
|
|
|
owner->own_flags |= OWN_waiting;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
event_t* event_ptr = &owner->own_wakeup;
|
|
|
|
SLONG value = ISC_event_clear(event_ptr);
|
|
|
|
|
|
|
|
// Post blockage. If the blocking owner has disappeared, the blockage
|
|
|
|
// may clear spontaneously.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
post_blockage(request, lock);
|
2004-05-03 19:36:27 +02:00
|
|
|
post_history(his_wait, owner_offset, lock_offset, SRQ_REL_PTR(request), true);
|
2001-05-23 15:26:42 +02:00
|
|
|
release(owner_offset);
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
time_t current_time = time(NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If a lock timeout was requested (wait < 0) then figure
|
|
|
|
// out the time when the lock request will timeout
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
const time_t lock_timeout = (lck_wait < 0) ? current_time + (-lck_wait) : 0;
|
|
|
|
time_t deadlock_timeout = current_time + scan_interval;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Wait in a loop until the lock becomes available
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
ULONG repost_counter = 0;
|
|
|
|
#endif
|
|
|
|
|
2004-12-16 04:03:13 +01:00
|
|
|
int ret;
|
2003-09-04 23:26:15 +02:00
|
|
|
while (true) {
|
2008-02-11 18:30:23 +01:00
|
|
|
// Before starting to wait - look to see if someone resolved
|
|
|
|
// the request for us - if so we're out easy!
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
|
|
|
if (!(request->lrq_flags & LRQ_pending)) {
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Recalculate when we next want to wake up, the lesser of a
|
|
|
|
// deadlock scan interval or when the lock request wanted a timeout
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
time_t timeout = deadlock_timeout;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lck_wait < 0 && lock_timeout < deadlock_timeout)
|
|
|
|
timeout = lock_timeout;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Prepare to wait for a timeout or a wakeup from somebody else
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(owner->own_flags & OWN_wakeup))
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
// Re-initialize value each time thru the loop to make sure that the
|
|
|
|
// semaphore looks 'un-poked'
|
|
|
|
|
|
|
|
localMutex->leave();
|
|
|
|
{ // scope
|
|
|
|
Firebird::ReadLockGuard guard(remapSync);
|
|
|
|
owner = (own*) SRQ_ABS_PTR(owner_offset);
|
|
|
|
event_ptr = &owner->own_wakeup;
|
|
|
|
++waitingOwners;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
ret = ISC_event_wait(1, &event_ptr, &value,
|
|
|
|
(timeout - current_time) * 1000000);
|
|
|
|
--waitingOwners;
|
|
|
|
localMutex->enter();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-03-24 15:32:34 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// We've woken up from the wait - now look around and see why we wokeup
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If somebody else has resolved the lock, we're done
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
|
|
|
if (!(request->lrq_flags & LRQ_pending)) {
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if we wokeup due to another owner deliberately waking us up
|
|
|
|
// ret==FB_SUCCESS --> we were deliberately woken up
|
|
|
|
// ret==FB_FAILURE --> we still don't know why we woke up
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Only if we came out of the ISC_event_wait() because of a post_wakeup()
|
|
|
|
// by another owner is OWN_wakeup set. This is the only FB_SUCCESS case.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (owner->own_flags & OWN_wakeup)
|
2002-11-14 09:33:08 +01:00
|
|
|
ret = FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2002-11-14 09:33:08 +01:00
|
|
|
ret = FB_FAILURE;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
current_time = time(NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if we woke up for a bogus reason - if so
|
|
|
|
// go right back to sleep. We wokeup bogus unless
|
|
|
|
// - we weren't deliberatly woken up
|
|
|
|
// - it's not time for a deadlock scan
|
|
|
|
// - it's not time for the lock timeout to expire
|
|
|
|
// Bogus reasons for wakeups include signal reception on some
|
|
|
|
// platforms (eg: SUN4) and remapping notification.
|
|
|
|
// Note: we allow a 1 second leaway on declaring a bogus
|
|
|
|
// wakeup due to timing differences (we use seconds here,
|
|
|
|
// ISC_event_wait() uses finer granularity)
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-14 09:33:08 +01:00
|
|
|
if ((ret != FB_SUCCESS) && (current_time + 1 < timeout)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// We apparently woke up for some real reason.
|
|
|
|
// Make sure everyone is still with us. Then see if we're still blocked.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
acquire(owner_offset);
|
2008-02-11 18:30:23 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2008-01-16 08:40:12 +01:00
|
|
|
lock = (lbl*) SRQ_ABS_PTR(lock_offset);
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
owner->own_flags &= ~OWN_wakeup;
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// Now that we own the lock table, see if the request was resolved
|
|
|
|
// while we were waiting for the lock table
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(request->lrq_flags & LRQ_pending)) {
|
|
|
|
release(owner_offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
current_time = time(NULL); // refetch due to wait in acquire()
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if we've waited beyond the lock timeout -
|
|
|
|
// if so we mark our own request as rejected
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (lck_wait < 0 && lock_timeout <= current_time)
|
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
// We're going to reject our lock - it's the callers responsibility
|
|
|
|
// to do cleanup and make sure post_pending() is called to wakeup
|
|
|
|
// other owners we might be blocking
|
2001-05-23 15:26:42 +02:00
|
|
|
request->lrq_flags |= LRQ_rejected;
|
|
|
|
request->lrq_flags &= ~LRQ_pending;
|
|
|
|
lock->lbl_pending_lrq_count--;
|
|
|
|
release(owner_offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// We're going to do some real work - reset when we next want to
|
|
|
|
// do a deadlock scan
|
2001-05-23 15:26:42 +02:00
|
|
|
deadlock_timeout = current_time + scan_interval;
|
|
|
|
|
2008-01-16 08:40:12 +01:00
|
|
|
lrq* blocking_request;
|
2008-02-11 18:30:23 +01:00
|
|
|
// Handle lock event first
|
2003-05-16 22:35:19 +02:00
|
|
|
if (ret == FB_SUCCESS)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
event_ptr = &owner->own_wakeup;
|
|
|
|
value = ISC_event_clear(event_ptr);
|
|
|
|
|
|
|
|
// Someone posted our wakeup event, but DIDN'T grant our request.
|
|
|
|
// Re-post what we're blocking on and continue to wait.
|
|
|
|
// This could happen if the lock was granted to a different request,
|
|
|
|
// we have to tell the new owner of the lock that they are blocking us.
|
2003-03-24 15:32:34 +01:00
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
post_blockage(request, lock);
|
2003-03-24 15:32:34 +01:00
|
|
|
release(owner_offset);
|
|
|
|
continue;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// See if all the other owners are still alive. Dead ones will be purged,
|
|
|
|
// purging one might resolve our lock request.
|
|
|
|
// Do not do rescan of owners if we received notification that
|
|
|
|
// blocking ASTs have completed - will do it next time if needed.
|
|
|
|
|
|
|
|
else if (probe_processes() && !(request->lrq_flags & LRQ_pending))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
release(owner_offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// If we've not previously been scanned for a deadlock, go do a deadlock scan
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
else if (!(owner->own_flags & OWN_scanned) &&
|
2008-02-11 18:30:23 +01:00
|
|
|
(blocking_request = deadlock_scan(owner, request)))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
// Something has been selected for rejection to prevent a
|
|
|
|
// deadlock. Clean things up and go on. We still have to
|
|
|
|
// wait for our request to be resolved.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_MSG(0, ("wait_for_request: selecting something for deadlock kill\n"));
|
|
|
|
|
|
|
|
++LOCK_header->lhb_deadlocks;
|
|
|
|
blocking_request->lrq_flags |= LRQ_rejected;
|
|
|
|
blocking_request->lrq_flags &= ~LRQ_pending;
|
2008-01-16 08:40:12 +01:00
|
|
|
lbl* blocking_lock = (lbl*) SRQ_ABS_PTR(blocking_request->lrq_lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
blocking_lock->lbl_pending_lrq_count--;
|
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
own* blocking_owner = (own*) SRQ_ABS_PTR(blocking_request->lrq_owner);
|
2001-05-23 15:26:42 +02:00
|
|
|
blocking_owner->own_pending_request = 0;
|
|
|
|
blocking_owner->own_flags &= ~OWN_scanned;
|
|
|
|
if (blocking_request != request)
|
|
|
|
post_wakeup(blocking_owner);
|
2008-02-11 18:30:23 +01:00
|
|
|
// else
|
|
|
|
// We rejected our own request to avoid a deadlock.
|
|
|
|
// When we get back to the top of the master loop we
|
|
|
|
// fall out and start cleaning up.
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-05-16 22:35:19 +02:00
|
|
|
else
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-02-11 18:30:23 +01:00
|
|
|
// Our request is not resolved, all the owners are alive, there's
|
|
|
|
// no deadlock -- there's nothing else to do. Let's
|
|
|
|
// make sure our request hasn't been forgotten by reminding
|
|
|
|
// all the owners we're waiting - some plaforms under CLASSIC
|
|
|
|
// architecture had problems with "missing signals" - which is
|
|
|
|
// another reason to repost the blockage.
|
|
|
|
// Also, the ownership of the lock could have changed, and we
|
|
|
|
// weren't woken up because we weren't next in line for the lock.
|
|
|
|
// We need to inform the new owner.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DEBUG_MSG(0, ("wait_for_request: forcing a resignal of blockers\n"));
|
2008-02-11 18:30:23 +01:00
|
|
|
post_blockage(request, lock);
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
repost_counter++;
|
|
|
|
if (repost_counter % 50 == 0) {
|
|
|
|
gds__log("wait_for_request: owner %d reposted %ld times for lock %d",
|
|
|
|
owner_offset,
|
|
|
|
repost_counter,
|
|
|
|
lock_offset);
|
|
|
|
DEBUG_MSG(0,
|
|
|
|
("wait_for_request: reposted %ld times for this lock!\n",
|
|
|
|
repost_counter));
|
|
|
|
}
|
2008-02-11 18:30:23 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
release(owner_offset);
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:30:23 +01:00
|
|
|
// NOTE: lock table is not acquired at this point
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
2008-01-16 08:40:12 +01:00
|
|
|
request = (lrq*) SRQ_ABS_PTR(request_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
CHECK(!(request->lrq_flags & LRQ_pending));
|
2008-02-11 18:30:23 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-04-29 02:34:06 +02:00
|
|
|
owner = (own*) SRQ_ABS_PTR(owner_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
owner->own_pending_request = 0;
|
2008-01-16 08:40:12 +01:00
|
|
|
owner->own_flags &= ~OWN_waiting;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|