* flock.cc (LOCK_OBJ_NAME_LEN): Change to accommodate extra lf_ver

field.
	(class lockf_t): Add lf_ver field.
	(lockf_t::lockf_t): Initialize lf_ver to 0.
	(class inode_t): Change i_wait to i_cnt.  Change comment to explain
	change in usage.
	(inode_t:use): Rename from wait.  Make private.
	(inode_t::unuse): Rename from unwait.  Make private.
	(inode_t::inuse): Rename from waiting.  Make private.
	(inode_t::notused): New public method to set use count to 0.
	(inode_t::unlock_and_remove): New method to unlock node and to delete
	it if it's unused in current process.
	(fhandler_base::del_my_locks): Drop global list lock.  Drop variable
	no_locks_left.  Simpify unlocking and removing node by just calling
	unlock_and_remove.
	(fixup_lockf_after_exec): Call notused method for each node.
	(inode_t::get): Call use method.  Lock node only if outside of list
	lock.
	(inode_t::get_all_locks_list): Accommodate additional lf_ver field
	when creating lockf_t structure from object name.
	(lockf_t::create_lock_obj_attr): Accommodate additional lf_ver field
	when creating object name from lockf_t structure.  Handle
	STATUS_OBJECT_NAME_COLLISION gracefully in F_POSIX case as well.
	Change comment accordingly.  Increment lf_ver field rather than high
	byte of lf_wid field.  Simplify comment.
	(fhandler_disk_file::lock): Always call unlock_and_remove rather than
	just UNLOCK on node.
	(lf_setlock): Move ret definition where it's used.  Drop unneeded
	tests for obj being not NULL.  Only check for deadlock condition if the
	lock we're trying to establish is a POSIX lock.  Revamp object
	collecting and wait code to cover all cases.  Don't return with EDEADLK
	if blocking process can't be opened for synchronization in F_POSIX case,
	rather just wait like in F_FLOCK case.  Change system_printf to
	debug_printf in that case.  Only run WaitForMultipleObjects with high
	priority.  Close obj and process handles prior to locking node.
This commit is contained in:
Corinna Vinschen 2011-08-29 13:50:25 +00:00
parent 36ccb620ec
commit 2e560a092c
2 changed files with 152 additions and 136 deletions

View File

@ -1,3 +1,41 @@
2011-08-29 Corinna Vinschen <corinna@vinschen.de>
* flock.cc (LOCK_OBJ_NAME_LEN): Change to accommodate extra lf_ver
field.
(class lockf_t): Add lf_ver field.
(lockf_t::lockf_t): Initialize lf_ver to 0.
(class inode_t): Change i_wait to i_cnt. Change comment to explain
change in usage.
(inode_t:use): Rename from wait. Make private.
(inode_t::unuse): Rename from unwait. Make private.
(inode_t::inuse): Rename from waiting. Make private.
(inode_t::notused): New public method to set use count to 0.
(inode_t::unlock_and_remove): New method to unlock node and to delete
it if it's unused in current process.
(fhandler_base::del_my_locks): Drop global list lock. Drop variable
no_locks_left. Simpify unlocking and removing node by just calling
unlock_and_remove.
(fixup_lockf_after_exec): Call notused method for each node.
(inode_t::get): Call use method. Lock node only if outside of list
lock.
(inode_t::get_all_locks_list): Accommodate additional lf_ver field
when creating lockf_t structure from object name.
(lockf_t::create_lock_obj_attr): Accommodate additional lf_ver field
when creating object name from lockf_t structure. Handle
STATUS_OBJECT_NAME_COLLISION gracefully in F_POSIX case as well.
Change comment accordingly. Increment lf_ver field rather than high
byte of lf_wid field. Simplify comment.
(fhandler_disk_file::lock): Always call unlock_and_remove rather than
just UNLOCK on node.
(lf_setlock): Move ret definition where it's used. Drop unneeded
tests for obj being not NULL. Only check for deadlock condition if the
lock we're trying to establish is a POSIX lock. Revamp object
collecting and wait code to cover all cases. Don't return with EDEADLK
if blocking process can't be opened for synchronization in F_POSIX case,
rather just wait like in F_FLOCK case. Change system_printf to
debug_printf in that case. Only run WaitForMultipleObjects with high
priority. Close obj and process handles prior to locking node.
2011-08-27 Corinna Vinschen <corinna@vinschen.de> 2011-08-27 Corinna Vinschen <corinna@vinschen.de>
* fhandler.cc (fhandler_base::open): Fix typo in comment. * fhandler.cc (fhandler_base::open): Fix typo in comment.

View File

@ -124,7 +124,7 @@ static NO_COPY muto lockf_guard;
#define INODE_LIST_LOCK() (lockf_guard.init ("lockf_guard")->acquire ()) #define INODE_LIST_LOCK() (lockf_guard.init ("lockf_guard")->acquire ())
#define INODE_LIST_UNLOCK() (lockf_guard.release ()) #define INODE_LIST_UNLOCK() (lockf_guard.release ())
#define LOCK_OBJ_NAME_LEN 64 #define LOCK_OBJ_NAME_LEN 69
#define FLOCK_INODE_DIR_ACCESS (DIRECTORY_QUERY \ #define FLOCK_INODE_DIR_ACCESS (DIRECTORY_QUERY \
| DIRECTORY_TRAVERSE \ | DIRECTORY_TRAVERSE \
@ -232,6 +232,10 @@ class lockf_t
long long lf_id; /* Cygwin PID for POSIX locks, a unique id per long long lf_id; /* Cygwin PID for POSIX locks, a unique id per
file table entry for BSD flock locks. */ file table entry for BSD flock locks. */
DWORD lf_wid; /* Win PID of the resource holding the lock */ DWORD lf_wid; /* Win PID of the resource holding the lock */
uint16_t lf_ver; /* Version number of the lock. If a released
lock event yet exists because another process
is still waiting for it, we use the version
field to distinguish old from new locks. */
class lockf_t **lf_head; /* Back pointer to the head of the lockf_t list */ class lockf_t **lf_head; /* Back pointer to the head of the lockf_t list */
class inode_t *lf_inode; /* Back pointer to the inode_t */ class inode_t *lf_inode; /* Back pointer to the inode_t */
class lockf_t *lf_next; /* Pointer to the next lock on this inode_t */ class lockf_t *lf_next; /* Pointer to the next lock on this inode_t */
@ -239,13 +243,14 @@ class lockf_t
lockf_t () lockf_t ()
: lf_flags (0), lf_type (0), lf_start (0), lf_end (0), lf_id (0), : lf_flags (0), lf_type (0), lf_start (0), lf_end (0), lf_id (0),
lf_wid (0), lf_head (NULL), lf_inode (NULL), lf_wid (0), lf_ver (0), lf_head (NULL), lf_inode (NULL),
lf_next (NULL), lf_obj (NULL) lf_next (NULL), lf_obj (NULL)
{} {}
lockf_t (class inode_t *node, class lockf_t **head, short flags, short type, lockf_t (class inode_t *node, class lockf_t **head,
_off64_t start, _off64_t end, long long id, DWORD wid) short flags, short type, _off64_t start, _off64_t end,
long long id, DWORD wid, uint16_t ver)
: lf_flags (flags), lf_type (type), lf_start (start), lf_end (end), : lf_flags (flags), lf_type (type), lf_start (start), lf_end (end),
lf_id (id), lf_wid (wid), lf_head (head), lf_inode (node), lf_id (id), lf_wid (wid), lf_ver (ver), lf_head (head), lf_inode (node),
lf_next (NULL), lf_obj (NULL) lf_next (NULL), lf_obj (NULL)
{} {}
~lockf_t (); ~lockf_t ();
@ -285,8 +290,11 @@ class inode_t
private: private:
HANDLE i_dir; HANDLE i_dir;
HANDLE i_mtx; HANDLE i_mtx;
unsigned long i_wait; /* Number of blocked threads waiting for uint32_t i_cnt; /* # of threads referencing this instance. */
a blocking lock. */
void use () { ++i_cnt; }
void unuse () { if (i_cnt > 0) --i_cnt; }
bool inuse () { return i_cnt > 0; }
public: public:
inode_t (__dev32_t dev, __ino64_t ino); inode_t (__dev32_t dev, __ino64_t ino);
@ -302,9 +310,9 @@ class inode_t
void LOCK () { WaitForSingleObject (i_mtx, INFINITE); } void LOCK () { WaitForSingleObject (i_mtx, INFINITE); }
void UNLOCK () { ReleaseMutex (i_mtx); } void UNLOCK () { ReleaseMutex (i_mtx); }
void wait () { ++i_wait; } void notused () { i_cnt = 0; }
void unwait () { if (i_wait > 0) --i_wait; }
bool waiting () { return i_wait > 0; } void unlock_and_remove ();
lockf_t *get_all_locks_list (); lockf_t *get_all_locks_list ();
@ -320,6 +328,20 @@ inode_t::~inode_t ()
NtClose (i_dir); NtClose (i_dir);
} }
void
inode_t::unlock_and_remove ()
{
UNLOCK ();
INODE_LIST_LOCK ();
unuse ();
if (i_lockf == NULL && !inuse ())
{
LIST_REMOVE (this, i_next);
delete this;
}
INODE_LIST_UNLOCK ();
}
bool bool
inode_t::del_my_locks (long long id, HANDLE fhdl) inode_t::del_my_locks (long long id, HANDLE fhdl)
{ {
@ -364,7 +386,6 @@ inode_t::del_my_locks (long long id, HANDLE fhdl)
void void
fhandler_base::del_my_locks (del_lock_called_from from) fhandler_base::del_my_locks (del_lock_called_from from)
{ {
INODE_LIST_LOCK ();
inode_t *node = inode_t::get (get_dev (), get_ino (), false); inode_t *node = inode_t::get (get_dev (), get_ino (), false);
if (node) if (node)
{ {
@ -377,19 +398,10 @@ fhandler_base::del_my_locks (del_lock_called_from from)
entry and there are no threads which require signalling, or we have entry and there are no threads which require signalling, or we have
a parent process still accessing the file object and signalling the a parent process still accessing the file object and signalling the
lock event would be premature. */ lock event would be premature. */
bool no_locks_left =
node->del_my_locks (from == after_fork ? 0 : get_unique_id (), node->del_my_locks (from == after_fork ? 0 : get_unique_id (),
from == after_exec ? NULL : get_handle ()); from == after_exec ? NULL : get_handle ());
if (no_locks_left) node->unlock_and_remove ();
{
LIST_REMOVE (node, i_next);
node->UNLOCK ();
delete node;
} }
else
node->UNLOCK ();
}
INODE_LIST_UNLOCK ();
} }
/* Called in an execed child. The exec'ed process must allow SYNCHRONIZE /* Called in an execed child. The exec'ed process must allow SYNCHRONIZE
@ -408,6 +420,7 @@ fixup_lockf_after_exec ()
allow_others_to_sync (); allow_others_to_sync ();
LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node) LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node)
{ {
node->notused ();
int cnt = 0; int cnt = 0;
cygheap_fdenum cfd (true); cygheap_fdenum cfd (true);
while (cfd.next () >= 0) while (cfd.next () >= 0)
@ -428,6 +441,7 @@ fixup_lockf_after_exec ()
{ {
lock->del_lock_obj (NULL); lock->del_lock_obj (NULL);
lock->lf_wid = myself->dwProcessId; lock->lf_wid = myself->dwProcessId;
lock->lf_ver = 0;
lock->create_lock_obj (); lock->create_lock_obj ();
} }
node->UNLOCK (); node->UNLOCK ();
@ -455,13 +469,15 @@ inode_t::get (__dev32_t dev, __ino64_t ino, bool create_if_missing)
LIST_INSERT_HEAD (&cygheap->inode_list, node, i_next); LIST_INSERT_HEAD (&cygheap->inode_list, node, i_next);
} }
if (node) if (node)
node->LOCK (); node->use ();
INODE_LIST_UNLOCK (); INODE_LIST_UNLOCK ();
if (node)
node->LOCK ();
return node; return node;
} }
inode_t::inode_t (__dev32_t dev, __ino64_t ino) inode_t::inode_t (__dev32_t dev, __ino64_t ino)
: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_wait (0L) : i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L)
{ {
HANDLE parent_dir; HANDLE parent_dir;
WCHAR name[48]; WCHAR name[48];
@ -516,8 +532,8 @@ inode_t::get_all_locks_list ()
if (f.dbi.ObjectName.Length != LOCK_OBJ_NAME_LEN * sizeof (WCHAR)) if (f.dbi.ObjectName.Length != LOCK_OBJ_NAME_LEN * sizeof (WCHAR))
continue; continue;
wchar_t *wc = f.dbi.ObjectName.Buffer, *endptr; wchar_t *wc = f.dbi.ObjectName.Buffer, *endptr;
/* "%02x-%01x-%016X-%016X-%016X-%08x", /* "%02x-%01x-%016X-%016X-%016X-%08x-%04x",
lf_flags, lf_type, lf_start, lf_end, lf_id, lf_wid */ lf_flags, lf_type, lf_start, lf_end, lf_id, lf_wid, lf_ver */
wc[LOCK_OBJ_NAME_LEN] = L'\0'; wc[LOCK_OBJ_NAME_LEN] = L'\0';
short flags = wcstol (wc, &endptr, 16); short flags = wcstol (wc, &endptr, 16);
if ((flags & ~(F_FLOCK | F_POSIX)) != 0 if ((flags & ~(F_FLOCK | F_POSIX)) != 0
@ -537,6 +553,9 @@ inode_t::get_all_locks_list ()
|| ((flags & F_POSIX) && (id < 1 || id > ULONG_MAX))) || ((flags & F_POSIX) && (id < 1 || id > ULONG_MAX)))
continue; continue;
DWORD wid = wcstoul (endptr + 1, &endptr, 16); DWORD wid = wcstoul (endptr + 1, &endptr, 16);
if (!endptr || *endptr != L'-')
continue;
uint16_t ver = wcstoul (endptr + 1, &endptr, 16);
if (endptr && *endptr != L'\0') if (endptr && *endptr != L'\0')
continue; continue;
if (lock - i_all_lf >= MAX_LOCKF_CNT) if (lock - i_all_lf >= MAX_LOCKF_CNT)
@ -547,7 +566,8 @@ inode_t::get_all_locks_list ()
} }
if (lock > i_all_lf) if (lock > i_all_lf)
lock[-1].lf_next = lock; lock[-1].lf_next = lock;
new (lock++) lockf_t (this, &i_all_lf, flags, type, start, end, id, wid); new (lock++) lockf_t (this, &i_all_lf,
flags, type, start, end, id, wid, ver);
} }
/* If no lock has been found, return NULL. */ /* If no lock has been found, return NULL. */
if (lock == i_all_lf) if (lock == i_all_lf)
@ -560,9 +580,9 @@ inode_t::get_all_locks_list ()
POBJECT_ATTRIBUTES POBJECT_ATTRIBUTES
lockf_t::create_lock_obj_attr (lockfattr_t *attr, ULONG flags) lockf_t::create_lock_obj_attr (lockfattr_t *attr, ULONG flags)
{ {
__small_swprintf (attr->name, L"%02x-%01x-%016X-%016X-%016X-%08x", __small_swprintf (attr->name, L"%02x-%01x-%016X-%016X-%016X-%08x-%04x",
lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start, lf_end, lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start, lf_end,
lf_id, lf_wid); lf_id, lf_wid, lf_ver);
RtlInitCountedUnicodeString (&attr->uname, attr->name, RtlInitCountedUnicodeString (&attr->uname, attr->name,
LOCK_OBJ_NAME_LEN * sizeof (WCHAR)); LOCK_OBJ_NAME_LEN * sizeof (WCHAR));
InitializeObjectAttributes (&attr->attr, &attr->uname, flags, lf_inode->i_dir, InitializeObjectAttributes (&attr->attr, &attr->uname, flags, lf_inode->i_dir,
@ -585,27 +605,22 @@ lockf_t::create_lock_obj ()
NotificationEvent, FALSE); NotificationEvent, FALSE);
if (!NT_SUCCESS (status)) if (!NT_SUCCESS (status))
{ {
if (status != STATUS_OBJECT_NAME_COLLISION || (lf_flags & F_POSIX)) if (status != STATUS_OBJECT_NAME_COLLISION)
api_fatal ("NtCreateEvent(lock): %p", status); api_fatal ("NtCreateEvent(lock): %p", status);
/* If we get a STATUS_OBJECT_NAME_COLLISION in the F_FLOCK case, the /* If we get a STATUS_OBJECT_NAME_COLLISION, the event still exists
event still exists because some other process is waiting for it because some other process is waiting for it in lf_setlock.
in lf_setlock. If so, open the event and check the signal state. If so, check the event's signal state. If we can't open it, it
If we can't open it, it has been closed in the meantime, so just has been closed in the meantime, so just try again. If we can
try again. If we can open it and the object is not signalled, open it and the object is not signalled, it's surely a bug in the
it's surely a bug in the code somewhere. Otherwise, close the code somewhere. Otherwise, close the event and retry to create
event and retry to create an event with another name. */ a new event with another name. */
if (open_lock_obj ()) if (open_lock_obj ())
{ {
if (!IsEventSignalled (lf_obj)) if (!IsEventSignalled (lf_obj))
api_fatal ("NtCreateEvent(lock): %p", status); api_fatal ("NtCreateEvent(lock): %p", status);
close_lock_obj (); close_lock_obj ();
/* Change the lf_wid member to generate another name for the /* Increment the lf_ver field until we have no collision. */
event, so as not to colide with the still-in-use event. ++lf_ver;
Changing lf_wid is ok, because the Windows PID is not used
for synchronization in the F_FLOCK case.
What we do here is to increment the highest byte in lf_wid. */
lf_wid = ((lf_wid & 0xff000000) + (1 << 24))
| (lf_wid & 0xffffff);
} }
} }
} }
@ -836,7 +851,7 @@ restart: /* Entry point after a restartable signal came in. */
clean = new lockf_t (); clean = new lockf_t ();
if (!clean) if (!clean)
{ {
node->UNLOCK (); node->unlock_and_remove ();
set_errno (ENOLCK); set_errno (ENOLCK);
return -1; return -1;
} }
@ -847,10 +862,10 @@ restart: /* Entry point after a restartable signal came in. */
lockf_t *lock = new lockf_t (node, head, a_flags, type, start, end, lockf_t *lock = new lockf_t (node, head, a_flags, type, start, end,
(a_flags & F_FLOCK) ? get_unique_id () (a_flags & F_FLOCK) ? get_unique_id ()
: getpid (), : getpid (),
myself->dwProcessId); myself->dwProcessId, 0);
if (!lock) if (!lock)
{ {
node->UNLOCK (); node->unlock_and_remove ();
set_errno (ENOLCK); set_errno (ENOLCK);
return -1; return -1;
} }
@ -886,16 +901,7 @@ restart: /* Entry point after a restartable signal came in. */
delete lock; delete lock;
lock = n; lock = n;
} }
if (node->i_lockf == NULL && !node->waiting ()) node->unlock_and_remove ();
{
INODE_LIST_LOCK ();
LIST_REMOVE (node, i_next);
node->UNLOCK ();
delete node;
INODE_LIST_UNLOCK ();
}
else
node->UNLOCK ();
switch (error) switch (error)
{ {
case 0: /* All is well. */ case 0: /* All is well. */
@ -940,7 +946,6 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
node->i_all_lf = (lockf_t *) (void *) tp.w_get (); node->i_all_lf = (lockf_t *) (void *) tp.w_get ();
while ((block = lf_getblock(lock, node))) while ((block = lf_getblock(lock, node)))
{ {
DWORD ret;
HANDLE obj = block->lf_obj; HANDLE obj = block->lf_obj;
block->lf_obj = NULL; block->lf_obj = NULL;
@ -949,10 +954,9 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
*/ */
if ((lock->lf_flags & F_WAIT) == 0) if ((lock->lf_flags & F_WAIT) == 0)
{ {
NtClose (obj);
lock->lf_next = *clean; lock->lf_next = *clean;
*clean = lock; *clean = lock;
if (obj)
NtClose (obj);
return EAGAIN; return EAGAIN;
} }
/* /*
@ -970,10 +974,10 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
waiting for one of our locks. This method isn't overly waiting for one of our locks. This method isn't overly
intelligent. If it turns out to be too dumb, we might intelligent. If it turns out to be too dumb, we might
have to remove it or to find another method. */ have to remove it or to find another method. */
if (lock->lf_flags & F_POSIX)
for (lockf_t *lk = node->i_lockf; lk; lk = lk->lf_next) for (lockf_t *lk = node->i_lockf; lk; lk = lk->lf_next)
if ((lk->lf_flags & F_POSIX) && get_obj_handle_count (lk->lf_obj) > 1) if ((lk->lf_flags & F_POSIX) && get_obj_handle_count (lk->lf_obj) > 1)
{ {
if (obj)
NtClose (obj); NtClose (obj);
return EDEADLK; return EDEADLK;
} }
@ -996,76 +1000,50 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
*/ */
/* Cygwin: No locked list. See deadlock recognition above. */ /* Cygwin: No locked list. See deadlock recognition above. */
/* Wait for the blocking object and its holding process. */ node->UNLOCK ();
if (!obj)
{
/* We can't synchronize on the lock event object.
Treat this as a deadlock-like situation for now. */
system_printf ("Can't sync with lock object hold by "
"Win32 pid %lu: %E", block->lf_wid);
return EDEADLK;
}
HANDLE cancel_event = pthread::get_cancel_event (); /* Create list of objects to wait for. */
HANDLE w4[4] = { obj, NULL, NULL, NULL };
DWORD wait_count = 1;
int wait_count = 0; HANDLE proc = NULL;
/* The lock event is always the first object, all other wait objects
are variable. */
DWORD WAIT_SIGNAL_ARRIVED = WAIT_TIMEOUT + 1;
DWORD WAIT_THREAD_CANCELED = WAIT_TIMEOUT + 1;
SetThreadPriority (GetCurrentThread (), priority);
if (lock->lf_flags & F_POSIX) if (lock->lf_flags & F_POSIX)
{ {
HANDLE proc = OpenProcess (SYNCHRONIZE, FALSE, block->lf_wid); proc = OpenProcess (SYNCHRONIZE, FALSE, block->lf_wid);
if (!proc) if (!proc)
{ debug_printf ("Can't sync with process holding a POSIX lock "
/* If we can't synchronize on the process holding the lock,
we will never recognize when the lock has been abandoned.
Treat this as a deadlock-like situation for now. */
system_printf ("Can't sync with process holding a lock "
"(Win32 pid %lu): %E", block->lf_wid); "(Win32 pid %lu): %E", block->lf_wid);
NtClose (obj);
return EDEADLK;
}
HANDLE w4[4] = { obj, proc, signal_arrived, cancel_event };
wait_count = 3;
WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + 2;
if (cancel_event)
{
wait_count = 4;
WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + 3;
}
node->wait ();
node->UNLOCK ();
ret = WaitForMultipleObjects (wait_count, w4, FALSE, INFINITE);
CloseHandle (proc);
}
else else
{ w4[wait_count++] = proc;
HANDLE w4[3] = { obj, signal_arrived, cancel_event }; }
wait_count = 2; DWORD WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + wait_count;
WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + 1; w4[wait_count++] = signal_arrived;
DWORD WAIT_THREAD_CANCELED = WAIT_TIMEOUT + 1;
HANDLE cancel_event = pthread::get_cancel_event ();
if (cancel_event) if (cancel_event)
{ {
wait_count = 3; WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + wait_count;
WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + 2; w4[wait_count++] = cancel_event;
} }
node->wait (); /* Wait for the blocking object and, for POSIX locks, its holding process.
node->UNLOCK (); Unfortunately, since BSD flock locks are not attached to a specific
/* Unfortunately, since BSD flock locks are not attached to a process, we can't recognize an abandoned lock by sync'ing with the
specific process, we can't recognize an abandoned lock by creator process. We have to make sure the event object is in a
sync'ing with a process. We have to make sure we're the only signalled state, or that it has gone away. The latter we can only
process left accessing this event object, or that the event recognize by retrying to fetch the block list, so we must not wait
object is in a signalled state. */ infinitely. Same problem for POSIX locks if the process has already
ret = WaitForMultipleObjects (wait_count, w4, FALSE, 100L); exited at the time we're trying to open the process. */
} SetThreadPriority (GetCurrentThread (), priority);
node->LOCK (); DWORD ret = WaitForMultipleObjects (wait_count, w4, FALSE,
node->unwait (); proc ? INFINITE : 100L);
NtClose (obj);
SetThreadPriority (GetCurrentThread (), old_prio); SetThreadPriority (GetCurrentThread (), old_prio);
/* Always close handles before locking the node. */
NtClose (obj);
if (proc)
CloseHandle (proc);
node->LOCK ();
if (ret == WAIT_SIGNAL_ARRIVED) if (ret == WAIT_SIGNAL_ARRIVED)
{ {
/* A signal came in. */ /* A signal came in. */
@ -1083,7 +1061,7 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
else else
/* The lock object has been set to signalled or ... /* The lock object has been set to signalled or ...
for POSIX locks, the process holding the lock has exited, or ... for POSIX locks, the process holding the lock has exited, or ...
Just a timeout. Just retry. */ just a timeout. Just retry. */
continue; continue;
} }
allow_others_to_sync (); allow_others_to_sync ();