?? lock.c
字號(hào):
/*
* PROGRAM: JRD Lock Manager
* MODULE: lock.c
* 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): ______________________________________.
*/
#include "../jrd/time.h"
#include "../jrd/ib_stdio.h"
#include "../jrd/common.h"
#include "../jrd/thd.h"
#include "../jrd/isc.h"
#ifdef LINKS_EXIST
#include "../isc_lock/lock.h"
#include "../isc_lock/lock_proto.h"
#else
#include "../lock/lock.h"
#include "../lock/lock_proto.h"
#endif /* LINKS_EXIST */
#include "../jrd/codes.h"
#include "../jrd/gds_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/isc_i_proto.h"
#include "../jrd/isc_s_proto.h"
#include "../jrd/sch_proto.h"
#include "../jrd/thd_proto.h"
#include <errno.h>
#ifdef WINDOWS_ONLY
#include "../jrd/loiter.h"
#define getpid GetCurrentTask
#endif
#ifdef sparc
#ifndef SOLARIS
#include <vfork.h>
#endif
#endif
#ifdef NeXT
#include <mach/message.h>
#include <mach/port.h>
#include <mach/kern_return.h>
#endif
#ifdef mpexl
#include <mpe.h>
#include "../jrd/mpexl.h"
#define MUTEX lock_manager_mutex
#endif
#if ( defined DELTA || defined IMP )
#define waitpid(x,y,z) wait (y)
#endif
#ifdef NETWARE_386
#define getpid GetNLMID
#define USE_EVENTS
#endif
#ifdef OS2_ONLY
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS
#include <os2.h>
#include <process.h>
#define MUTEX lock_manager_mutex
#define USE_EVENTS
#endif
#if (defined UNIX && !defined NeXT)
#define USE_EVENTS
#ifndef ANY_THREADING /* #if !(defined SOLARIS || defined POSIX_THREADS) */
#define STATIC_SEMAPHORES
#endif /* ANY_THREADING */
#endif /* (defined UNIX && !defined NeXT) */
#ifdef WIN_NT
#include <process.h>
#define MUTEX lock_manager_mutex
#define ERRNO GetLastError()
#endif
#ifdef MANAGER_PROCESS
#include <sys/stat.h>
#define statistics stat
static BOOLEAN LOCK_post_manager;
#endif
#ifdef DEV_BUILD
#define ASSERT_ACQUIRED current_is_active_owner (TRUE, __LINE__)
#define ASSERT_RELEASED current_is_active_owner (FALSE, __LINE__)
#define VALIDATE_LOCK_TABLE
#if ((defined MMAP_SUPPORTED) && !(defined SUPERSERVER))
#define LOCK_DEBUG_ACQUIRE
#endif
#endif
#ifdef LOCK_DEBUG_ACQUIRE
#define DEBUG_ACQUIRE_INTERVAL 5000
static ULONG debug_acquire_count = 0;
#endif
#ifndef ASSERT_ACQUIRED
#define ASSERT_ACQUIRED /* nothing */
#endif
#ifndef ASSERT_RELEASED
#define ASSERT_RELEASED /* nothing */
#endif
#ifdef DEV_BUILD
#define CHECK(x) { if (!(x)) bug_assert ("consistency check", __LINE__); }
#endif
#ifndef CHECK
#define CHECK(x) /* nothing */
#endif
#ifdef DEBUG
#define DEBUG_MANAGER "manager"
#define DEBUG_TRACE
#endif
#ifdef DEBUG_TRACE
#define LOCK_TRACE(x) { time_t t; (void) time (&t); ib_printf ("%s", ctime(&t) ); ib_printf x ; ib_fflush (ib_stdout); }
#endif
#ifdef DEBUG
SSHORT LOCK_debug_level = 0;
#define DEBUG_MSG(l,x) if ((l) <= LOCK_debug_level) { time_t t; (void) time (&t); ib_printf ("%s", ctime(&t) ); ib_printf x ; ib_fflush (ib_stdout); gds__log x ; }
#endif
#ifndef DEBUG_MSG
#define DEBUG_MSG(l,x) /* nothing */
#endif
#ifndef LOCK_TRACE
#define LOCK_TRACE(x) /* nothing */
#endif
/* 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
*/
#ifdef DEBUG
#define DEBUG_DELAY debug_delay (__LINE__)
#endif
#ifndef DEBUG_DELAY
#define DEBUG_DELAY /* nothing */
#endif
#ifndef ERRNO
#define ERRNO errno
#endif
#ifndef MUTEX
#define MUTEX LOCK_header->lhb_mutex
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif
#ifndef SV_INTERRUPT
#define SV_INTERRUPT 0
#endif
#define DUMMY_OWNER_CREATE ((PTR) -1)
#define DUMMY_OWNER_DELETE ((PTR) -2)
#define DUMMY_OWNER_SHUTDOWN ((PTR) -3)
#if !(defined linux || defined NETWARE_386 || defined WIN_NT || defined OS2_ONLY || defined mpexl)
extern SCHAR *sys_errlist[];
#endif
static void acquire (PTR);
static UCHAR *alloc (SSHORT, STATUS *);
static LBL alloc_lock (USHORT, STATUS *);
static USHORT alloc_semaphore (OWN, STATUS *);
static void blocking_action (PTR);
static void blocking_action2 (PTR, PTR);
static void THREAD_ROUTINE blocking_action_thread (PTR *);
static void bug (STATUS *, CONST TEXT *);
#ifdef DEV_BUILD
static void bug_assert (CONST TEXT *, ULONG);
#endif
static BOOLEAN convert (PTR, UCHAR, SSHORT, FPTR_INT, int *, STATUS *);
static USHORT create_owner (STATUS *, SLONG, UCHAR, SLONG *);
#ifdef DEV_BUILD
static void current_is_active_owner (BOOLEAN, ULONG);
#endif
static void deadlock_clear (void);
static LRQ deadlock_scan (OWN, LRQ);
static LRQ deadlock_walk (LRQ, BOOLEAN *);
static void dequeue (PTR);
#ifdef DEBUG
static void debug_delay (ULONG);
#endif
static void exit_handler (void *);
static LBL find_lock (PTR, USHORT, UCHAR *, USHORT, USHORT *);
static USHORT fork_lock_manager (STATUS *);
static OWN get_manager (BOOLEAN);
static LRQ get_request (PTR);
static void grant (LRQ, LBL);
static PTR grant_or_que (LRQ, LBL, SSHORT);
static STATUS init_lock_table (STATUS *);
static void init_owner_block (OWN, UCHAR, ULONG, USHORT);
static void lock_alarm_handler (EVENT);
static void lock_initialize (void *, SH_MEM, int);
static void insert_data_que (LBL);
static void insert_tail (SRQ, SRQ);
static USHORT lock_state (LBL);
static void port_waker (PTR *);
static void post_blockage (LRQ, LBL, BOOLEAN);
static void post_history (USHORT, PTR, PTR, PTR, BOOLEAN);
static void post_pending (LBL);
static void post_wakeup (OWN);
#ifndef SUPERSERVER
static BOOLEAN probe_owners (PTR);
#endif
static void purge_owner (PTR, OWN);
static void remove_que (SRQ);
static void release (PTR);
static void release_mutex (void);
static void release_request (LRQ);
static void release_semaphore (OWN);
static void shutdown_blocking_thread (STATUS *);
static int signal_owner (OWN, PTR);
#ifdef VALIDATE_LOCK_TABLE
static void validate_lhb (LHB);
static void validate_shb (PTR);
static void validate_owner (PTR, USHORT);
static void validate_lock (PTR, USHORT, PTR);
static void validate_request (PTR, USHORT, USHORT);
static void validate_block (PTR);
#endif
static USHORT wait_for_request (LRQ, SSHORT, STATUS *);
static void wakeup_action (PTR *);
static struct own LOCK_process_owner; /* Place holder */
static SSHORT LOCK_bugcheck = 0;
static LHB VOLATILE LOCK_header = NULL;
static PTR LOCK_owner_offset = 0;
static OWN LOCK_owner = NULL_PTR;
static SSHORT VOLATILE LOCK_asts = -1;
static int LOCK_pid = 0, LOCK_version = 0;
static SLONG LOCK_shm_size = 0, LOCK_sem_count = 0;
#if (defined SOLARIS_MT && !defined SUPERSERVER)
static SLONG LOCK_solaris_stall = 60; /* seconds - def value for solaris stall */
#endif
static SLONG LOCK_block_signal = 0;
#ifdef WAKEUP_SIGNAL
static SLONG LOCK_wakeup_signal = 0;
#endif
static SLONG LOCK_ordering = 0;
static SLONG LOCK_hash_slots;
static SLONG LOCK_scan_interval;
static SLONG LOCK_acquire_spins = 0;
static SH_MEM_T LOCK_data;
static BOOLEAN start_manager = FALSE;
static TEXT LOCK_bug_buffer [128];
#ifdef mpexl
static MTX_T lock_manager_mutex [1];
#endif
#ifdef NeXT
static int condition_set; /* flag used between threads */
static port_t alarm_port; /* alarm thread's port */
static SCHAR message_buf [24]; /* used to send messages to alarm thd */
static SCHAR message_buf1 [24]; /* used to receive above messages */
static msg_header_t *null_msg;
static msg_header_t *null_msg1;
static int VOLATILE getout = 0; /* flag used to stop alarm and blocking
threads from continuing after the
main thread shuts down (LOCK_fini) */
#endif
#ifdef OS2_ONLY
static MTX_T lock_manager_mutex [1];
static HEV blocking_event [1];
#endif
#ifdef WIN_NT
static MTX_T lock_manager_mutex [1];
#ifndef SUPERSERVER
static HANDLE blocking_event [1], wakeup_event [1];
#endif
#endif
static struct ipccfg LOCK_hdrtbl [] = {
/* 5.5 SCO Port: Classic server on SCO - following is not supported */
#if (!(defined WIN_NT) && !(defined SCO_EV))
"V4_LOCK_MEM_SIZE", -1, &LOCK_shm_size, 0, 0,
"ANY_LOCK_MEM_SIZE", -1, &LOCK_shm_size, -1, 0,
#endif
#ifdef STATIC_SEMAPHORES
"V4_LOCK_SEM_COUNT", -1, &LOCK_sem_count, 0, 0,
"ANY_LOCK_SEM_COUNT", -1, &LOCK_sem_count, -1, 0,
#endif
"V4_LOCK_SIGNAL", -1, &LOCK_block_signal, 0, 0,
"ANY_LOCK_SIGNAL", -1, &LOCK_block_signal, -1, 0,
"V4_LOCK_GRANT_ORDER", -1, &LOCK_ordering, 0, 0,
"LOCK_HASH_SLOTS", -1, &LOCK_hash_slots, 0, 0,
"DEADLOCK_TIMEOUT", -1, &LOCK_scan_interval, 0, 0,
"LOCK_ACQUIRE_SPINS", -1, &LOCK_acquire_spins, 0, 0,
#if (defined SOLARIS_MT && !defined SUPERSERVER)
"V4_SOLARIS_STALL_VALUE",-1, &LOCK_solaris_stall, 0, 0,
#endif
NULL, 0, NULL, 0, 0
};
#ifndef mpexl
#define GET_TIME time (NULL)
#else
#define GET_TIME TIMER()
#endif
#define WAIT_TIME 10
#define HASH_MIN_SLOTS 101
#define HASH_MAX_SLOTS 2048
#define HISTORY_BLOCKS 256
#define LOCKMANTIMEOUT 300
#if (defined SOLARIS_MT && !defined SUPERSERVER)
#define STARVATION_THRESHHOLD 500 /* acquires of lock table */
#define SOLARIS_MIN_STALL 0
#define SOLARIS_MAX_STALL 200
#define SOLARIS_MAX_STALL 200 /* Seconds */
#endif
#define OWN_BLOCK_new 1
#define OWN_BLOCK_reused 2
#define OWN_BLOCK_dummy 3
#ifndef LOCK_MANAGER
#define LOCK_MANAGER "bin/gds_lock_mgr"
#endif
#ifdef SHLIB_DEFS
#define sys_errlist (*_libgds_sys_errlist)
#ifdef IMP
#define wait (*_libgds_wait)
#else
#define waitpid (*_libgds_waitpid)
#endif
#define execl (*_libgds_execl)
#define _exit (*_libgds__exit)
#define statistics (*_libgds_stat)
#define chmod (*_libgds_chmod)
extern SCHAR *sys_errlist [];
#ifdef IMP
extern int wait();
#else
extern int waitpid();
#endif
extern int execl();
extern void _exit();
extern int statistics();
extern int chmod();
#endif
static CONST UCHAR compatibility[] = {
/* Shared Prot Shared Prot
none null Read Read Write Write Exclusive */
/* none */ 1, 1, 1, 1, 1, 1, 1,
/* null */ 1, 1, 1, 1, 1, 1, 1,
/* SR */ 1, 1, 1, 1, 1, 1, 0,
/* PR */ 1, 1, 1, 1, 0, 0, 0,
/* SW */ 1, 1, 1, 0, 1, 0, 0,
/* PW */ 1, 1, 1, 0, 0, 0, 0,
/* EX */ 1, 1, 0, 0, 0, 0, 0 };
#define COMPATIBLE(st1, st2) compatibility [st1 * LCK_max + st2]
int LOCK_convert (
PTR request_offset,
UCHAR type,
SSHORT lck_wait,
int (*ast_routine)(void *),
void *ast_argument,
STATUS *status_vector)
{
/**************************************
*
* L O C K _ c o n v e r t
*
**************************************
*
* Functional description
* Perform a lock conversion, if possible.
*
**************************************/
LRQ request;
OWN owner;
LBL lock;
#ifdef WINDOWS_ONLY
lck_wait = 0; /* LIBS is always no wait */
#endif
LOCK_TRACE (("LOCK_convert (%d, %d)\n", type, lck_wait));
request = get_request (request_offset);
owner = (OWN) ABS_PTR (request->lrq_owner);
if (!owner->own_count)
return FALSE;
acquire (request->lrq_owner);
owner = NULL; /* remap */
++LOCK_header->lhb_converts;
request = (LRQ) ABS_PTR (request_offset); /* remap */
lock = (LBL) ABS_PTR (request->lrq_lock);
if (lock->lbl_series < LCK_MAX_SERIES)
++LOCK_header->lhb_operations [lock->lbl_series];
else
++LOCK_header->lhb_operations [0];
return (convert (request_offset, type, lck_wait, ast_routine, ast_argument, status_vector));
}
int LOCK_deq (
PTR request_offset)
{
/**************************************
*
* L O C K _ d e q
*
**************************************
*
* Functional description
* Release an outstanding lock.
*
**************************************/
LRQ request;
OWN owner;
PTR owner_offset;
LBL lock;
LOCK_TRACE (("LOCK_deq (%d)\n", request_offset));
request = get_request (request_offset);
owner_offset = request->lrq_owner;
owner = (OWN) ABS_PTR (owner_offset);
if (!owner->own_count)
return FALSE;
acquire (owner_offset);
owner = NULL; /* remap */
++LOCK_header->lhb_deqs;
request = (LRQ) ABS_PTR (request_offset); /* remap */
lock = (LBL) ABS_PTR (request->lrq_lock);
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);
return TRUE;
}
UCHAR LOCK_downgrade (
PTR request_offset,
STATUS *status_vector)
{
/**************************************
*
* L O C K _ d o w n g r a d e
*
**************************************
*
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -