📄 lock.c
字号:
DEBUG_DELAY;
--LOCK_asts;
DEBUG_DELAY;
#endif
}
static void blocking_action2 (
PTR blocking_owner_offset,
PTR blocked_owner_offset)
{
/**************************************
*
* b l o c k i n g _ a c t i o n 2
*
**************************************
*
* Functional description
* Fault hander for a blocking signal. A blocking signal
* 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.
*
**************************************/
OWN owner;
SRQ que;
LRQ request;
int (*routine)(), *arg;
ASSERT_ACQUIRED;
owner = (OWN) ABS_PTR (blocking_owner_offset);
if (!blocked_owner_offset)
blocked_owner_offset = blocking_owner_offset;
while (owner->own_count)
{
que = QUE_NEXT (owner->own_blocks);
if (que == &owner->own_blocks)
{
/* We've processed the own_blocks queue, reset the "we've been
* signaled" flag and start winding out of here
*/
owner->own_ast_flags &= ~OWN_signaled;
/*post_history (his_leave_ast, blocking_owner_offset, 0, 0, TRUE);*/
break;
}
request = (LRQ) ((UCHAR*) que - OFFSET (LRQ, lrq_own_blocks));
routine = request->lrq_ast_routine;
arg = request->lrq_ast_argument;
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, request->lrq_lock, REL_PTR (request), TRUE);
}
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);
(*routine) (arg);
#ifdef NeXT
/* make sure we're not shut down */
if (getout)
break;
#endif
acquire (blocked_owner_offset);
owner = (OWN) ABS_PTR (blocking_owner_offset);
}
}
}
#if (defined WIN_NT && !defined SUPERSERVER)
static void THREAD_ROUTINE blocking_action_thread (
PTR *owner_offset_ptr)
{
/**************************************
*
* b l o c k i n g _ a c t i o n _ t h r e a d ( W I N _ N T )
*
**************************************
*
* Functional description
* Thread to handle blocking signals that a process
* will send to itself.
*
**************************************/
SLONG ret;
OWN owner;
AST_INIT; /* Check into scheduler as AST thread */
while (TRUE)
{
ret = WaitForSingleObject (blocking_event [0], INFINITE);
AST_ENTER;
owner = (OWN) ABS_PTR (*owner_offset_ptr);
if ((ret && ret != WAIT_ABANDONED) ||
!*owner_offset_ptr ||
owner->own_process_id != LOCK_pid ||
owner->own_owner_id == 0)
break;
blocking_action (*owner_offset_ptr);
AST_EXIT;
}
AST_EXIT;
AST_FINI; /* Check out of scheduler as AST thread */
}
#endif
#ifdef OS2_ONLY
static void THREAD_ROUTINE blocking_action_thread (
PTR *owner_offset_ptr)
{
/**************************************
*
* b l o c k i n g _ a c t i o n _ t h r e a d ( O S 2 )
*
**************************************
*
* Functional description
* Thread to handle blocking signals that a process
* will send to itself.
*
**************************************/
ULONG status, count;
OWN owner;
while (TRUE)
{
status = DosWaitEventSem (blocking_event [0], SEM_INDEFINITE_WAIT);
owner = (OWN) ABS_PTR (*owner_offset_ptr);
if ((status && status != ERROR_INTERRUPT) ||
!*owner_offset_ptr ||
owner->own_process_id != LOCK_pid ||
owner->own_owner_id == 0)
break;
DosResetEventSem (blocking_event [0], &count);
blocking_action (*owner_offset_ptr);
}
}
#endif
#if (defined SOLARIS_MT && !defined SUPERSERVER)
static void THREAD_ROUTINE blocking_action_thread (
PTR *owner_offset_ptr)
{
/**************************************
*
* b l o c k i n g _ a c t i o n _ t h r e a d ( S O L A R I S _ M T )
*
**************************************
*
* Functional description
* Thread to handle blocking signals.
*
**************************************/
SLONG value;
EVENT event_ptr;
AST_INIT; /* Check into scheduler as AST thread */
while (TRUE)
{
AST_ENTER;
/* See if main thread has requested us to go away */
if (!*owner_offset_ptr ||
LOCK_owner->own_process_id != LOCK_pid ||
!LOCK_owner->own_owner_id)
break;
value = ISC_event_clear (LOCK_owner->own_blocking);
blocking_action (*owner_offset_ptr);
AST_EXIT;
event_ptr = LOCK_owner->own_blocking;
ISC_event_wait (1, &event_ptr, &value, 0, NULL, NULL_PTR);
}
/* Main thread asked us to go away, do our cleanup, then tell
* main thread we're done (see shutdown_blocking_action()).
*/
AST_EXIT;
AST_FINI; /* Check out of scheduler as AST thread */
/* Wakeup the main thread waiting for our exit. */
/* Main thread won't wait forever, so check LOCK_owner is still mapped */
if (LOCK_owner)
ISC_event_post (LOCK_owner->own_wakeup);
}
#endif
#ifdef DEV_BUILD
static void bug_assert (
CONST TEXT *string,
ULONG line)
{
/**************************************
*
* b u g _ a s s e r t
*
**************************************
*
* Functional description
* Disasterous lock manager bug. Issue message and abort process.
*
**************************************/
TEXT buffer [100];
struct lhb LOCK_header_copy;
sprintf ((char *) buffer, "%s %ld: lock assertion failure: %s\n",
__FILE__, line, string);
/* Copy the shared memory so we can examine its state when we crashed */
LOCK_header_copy = *LOCK_header;
bug (NULL, buffer); /* Never returns */
}
#endif
static void bug (
STATUS *status_vector,
CONST TEXT *string)
{
/**************************************
*
* b u g
*
**************************************
*
* Functional description
* Disasterous lock manager bug. Issue message and abort process.
*
**************************************/
TEXT s [128];
OWN owner;
if (!LOCK_bugcheck++)
{
#ifdef DEV_BUILD
#if !(defined WIN_NT || defined WINDOWS_ONLY)
/* The lock file has some problem - copy it for later analysis */
{
TEXT *lock_file;
TEXT buffer [256];
TEXT buffer2 [256];
TEXT hostname [64];
gds__prefix_lock (buffer, LOCK_FILE);
lock_file = buffer;
sprintf (buffer2, lock_file, ISC_get_host (hostname, sizeof (hostname)));
sprintf (buffer, "cp %s isc_lock1.%d", buffer2, getpid());
system (buffer);
}
#endif /* WIN_NT || WINDOWS_ONLY */
#endif /* DEV_BUILD */
/* If the current mutex acquirer is in the same process,
release the mutex */
if (LOCK_header && (LOCK_header->lhb_active_owner > 0))
{
owner = (OWN) ABS_PTR (LOCK_header->lhb_active_owner);
if (owner->own_process_id == LOCK_pid)
release (LOCK_header->lhb_active_owner);
}
if (status_vector)
{
*status_vector++ = gds_arg_gds;
*status_vector++ = gds__lockmanerr;
*status_vector++ = gds_arg_gds;
*status_vector++ = gds__random;
*status_vector++ = gds_arg_string;
*status_vector++ = (STATUS) string;
*status_vector++ = gds_arg_end;
return;
}
}
sprintf (s, "Fatal lock manager error: %s, errno: %d", string, ERRNO);
gds__log (s);
ib_fprintf (ib_stderr, "%s\n", s);
#if !(defined NETWARE_386 || defined WIN_NT || defined OS2_ONLY || defined mpexl)
if (errno > 0)
ib_fprintf (ib_stderr, "--%s\n", sys_errlist [errno]);
#endif
#ifdef DEV_BUILD
/* Make a core drop - we want to LOOK at this failure! */
abort();
#endif
exit (FINI_ERROR);
}
static BOOLEAN convert (
PTR request_offset,
UCHAR type,
SSHORT lck_wait,
int (*ast_routine)(),
int *ast_argument,
STATUS *status_vector)
{
/**************************************
*
* 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
* on a wait flag. If the lock is granted return TRUE, otherwise
* return FALSE. Note: if the conversion would cause a deadlock,
* FALSE is returned even if wait was requested.
*
**************************************/
LBL lock;
LRQ request;
UCHAR temp;
BOOLEAN new_ast;
PTR owner_offset;
ASSERT_ACQUIRED;
request = get_request (request_offset);
lock = (LBL) ABS_PTR (request->lrq_lock);
owner_offset = request->lrq_owner;
post_history (his_convert, owner_offset, request->lrq_lock, request_offset, TRUE);
request->lrq_requested = type;
request->lrq_flags &= ~LRQ_blocking_seen;
/* Compute the state of the lock without the request. */
--lock->lbl_counts [request->lrq_state];
temp = lock_state (lock);
/* If the requested lock level is compatible with the current state
of the lock, just grant the request. Easy enough. */
if (COMPATIBLE (type, temp))
{
request->lrq_ast_routine = ast_routine;
request->lrq_ast_argument = ast_argument;
grant (request, lock);
post_pending (lock);
release (owner_offset);
return TRUE;
}
++lock->lbl_counts [request->lrq_state];
/* If we weren't requested to wait, just forget about the whole thing.
Otherwise wait for the request to be granted or rejected */
if (lck_wait)
{
if (request->lrq_ast_routine != ast_routine ||
request->lrq_ast_argument != ast_argument)
new_ast = TRUE;
else
new_ast = FALSE;
if (wait_for_request (request, lck_wait, status_vector))
{
ASSERT_RELEASED;
return FALSE;
}
request = (LRQ) ABS_PTR (request_offset);
if (!(request->lrq_flags & LRQ_rejected))
{
if (new_ast)
{
acquire (owner_offset);
request = (LRQ) ABS_PTR (request_offset);
request->lrq_ast_routine = ast_routine;
request->lrq_ast_argument = ast_argument;
release (owner_offset);
}
ASSERT_RELEASED;
return TRUE;
}
acquire (owner_offset);
request = get_request (request_offset);
lock = (LBL) ABS_PTR (request->lrq_lock);
post_pending (lock);
}
request = (LRQ) ABS_PTR (request_offset);
request->lrq_requested = request->lrq_state;
ASSERT_ACQUIRED;
++LOCK_header->lhb_denies;
if (lck_wait < 0)
++LOCK_header->lhb_timeouts;
release (owner_offset);
*status_vector++ = gds_arg_gds;
*status_vector++ = (lck_wait > 0) ? gds__deadlock :
((lck_wait < 0) ? gds__lock_timeout : gds__lock_conflict);
*status_vector++ = gds_arg_end;
return FALSE;
}
static USHORT create_owner (
STATUS *status_vector,
SLONG owner_id,
UCHAR owner_type,
SLONG *owner_handle)
{
/**************************************
*
* c r e a t e _ o w n e r
*
**************************************
*
* Functional description
* Create an owner block.
*
**************************************/
SRQ que;
OWN owner;
USHORT new_block;
LOCK_version = LOCK_header->lhb_version;
if (LOCK_version != LHB_VERSION)
{
sprintf (LOCK_bug_buffer, "inconsistent lock table version number; found %d, expected %d",
LOCK_version, LHB_VERSION);
bug (status_vector, LOCK_bug_buffer);
return FAILURE;
}
acquire (DUMMY_OWNER_CREATE); /* acquiring owner is being created */
/* Look for a previous instance of owner. If we find one, get rid of it. */
QUE_LOOP (LOCK_header->lhb_owners, que)
{
owner = (OWN) ((UCHAR*) que - OFFSET (OWN, own_lhb_owners));
if (owner->own_owner_id == owner_id && owner->own_owner_type == owner_type)
{
purge_owner (DUMMY_OWNER_CREATE, owner); /* purging owner_offset has not been set yet */
break;
}
}
/* Allocate an owner block */
if (QUE_EMPTY (LOCK_header->lhb_free_owners))
{
if (!(owner = (OWN) alloc (sizeof (struct own), status_vector)))
{
release_mutex();
return FAILURE;
}
new_block = OWN_BLOCK_new;
}
else
{
owner = (OWN) ((UCHAR*) QUE_NEXT (LOCK_header->lhb_free_owners) -
OFFSET (OWN, own_lhb_owners));
remove_que (&owner->own_lhb_owners);
new_block = OWN_BLOCK_reused;
}
init_owner_block (owner, owner_type, owner_id, new_block);
/* cannot ASSERT_ACQUIRED; here - owner not setup */
insert_tail (&LOCK_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -