1 /* flock.cc. NT specific implementation of advisory file locking.
3 Copyright 2003, 2008, 2009 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 /* The basic mechanism as well as the datastructures used in the below
12 implementation are taken from the FreeBSD repository on 2008-03-18.
13 The essential code of the lf_XXX functions has been taken from the
14 module src/sys/kern/kern_lockf.c. It has been adapted to use NT
15 global namespace subdirs and event objects for synchronization
18 So, the following copyright applies to most of the code in the lf_XXX
21 * Copyright (c) 1982, 1986, 1989, 1993
22 * The Regents of the University of California. All rights reserved.
24 * This code is derived from software contributed to Berkeley by
25 * Scooter Morris at Genentech Inc.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 4. Neither the name of the University nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
39 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94
55 * The flock() function is based upon source taken from the Red Hat
56 * implementation used in their imap-2002d SRPM.
58 * $RH: flock.c,v 1.2 2000/08/23 17:07:00 nalin Exp $
61 /* The lockf function is based upon FreeBSD sources with the following
65 * Copyright (c) 1997 The NetBSD Foundation, Inc.
66 * All rights reserved.
68 * This code is derived from software contributed to The NetBSD Foundation
71 * Redistribution and use in source and binary forms, with or without
72 * modification, are permitted provided that the following conditions
74 * 1. Redistributions of source code must retain the above copyright
75 * notice, this list of conditions and the following disclaimer.
76 * 2. Redistributions in binary form must reproduce the above copyright
77 * notice, this list of conditions and the following disclaimer in the
78 * documentation and/or other materials provided with the distribution.
80 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
81 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
82 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
83 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
84 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
85 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
86 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
87 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
88 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
89 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
90 * POSSIBILITY OF SUCH DAMAGE.
100 #include "shared_info.h"
102 #include "fhandler.h"
108 #include "tls_pbuf.h"
110 #include <sys/queue.h>
113 #define F_WAIT 0x10 /* Wait until lock is granted */
114 #define F_FLOCK 0x20 /* Use flock(2) semantics for lock */
115 #define F_POSIX 0x40 /* Use POSIX semantics for lock */
118 #define OFF_MAX LLONG_MAX
121 static NO_COPY muto lockf_guard;
123 #define INODE_LIST_LOCK() (lockf_guard.init ("lockf_guard")->acquire ())
124 #define INODE_LIST_UNLOCK() (lockf_guard.release ())
126 #define LOCK_OBJ_NAME_LEN 64
128 #define FLOCK_INODE_DIR_ACCESS (DIRECTORY_QUERY \
129 | DIRECTORY_TRAVERSE \
130 | DIRECTORY_CREATE_OBJECT \
133 #define FLOCK_EVENT_ACCESS (EVENT_QUERY_STATE \
137 /* This function takes the own process security descriptor DACL and adds
138 SYNCHRONIZE permissions for everyone. This allows all processes
139 to wait for this process to die when blocking in a F_SETLKW on a lock
140 which is hold by this process. */
142 allow_others_to_sync ()
144 static NO_COPY bool done;
154 /* Get this process DACL. We use a temporary path buffer in TLS space
155 to avoid having to alloc 64K from the stack. */
157 PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) tp.w_get ();
158 status = NtQuerySecurityObject (NtCurrentProcess (),
159 DACL_SECURITY_INFORMATION, sd,
160 NT_MAX_PATH * sizeof (WCHAR), &len);
161 if (!NT_SUCCESS (status))
163 debug_printf ("NtQuerySecurityObject: %p", status);
166 /* Create a valid dacl pointer and set it's size to be as big as
167 there's room in the temporary buffer. Note that the descriptor
168 is in self-relative format. */
169 dacl = (PACL) ((char *) sd + (uintptr_t) sd->Dacl);
170 dacl->AclSize = NT_MAX_PATH * sizeof (WCHAR) - ((char *) dacl - (char *) sd);
171 /* Allow everyone to SYNCHRONIZE with this process. */
172 if (!AddAccessAllowedAce (dacl, ACL_REVISION, SYNCHRONIZE,
173 well_known_world_sid))
175 debug_printf ("AddAccessAllowedAce: %lu", GetLastError ());
178 /* Set the size of the DACL correctly. */
179 if (!FindFirstFreeAce (dacl, &ace))
181 debug_printf ("FindFirstFreeAce: %lu", GetLastError ());
184 dacl->AclSize = (char *) ace - (char *) dacl;
185 /* Write the DACL back. */
186 status = NtSetSecurityObject (NtCurrentProcess (), DACL_SECURITY_INFORMATION, sd);
187 if (!NT_SUCCESS (status))
189 debug_printf ("NtSetSecurityObject: %p", status);
195 /* Get the handle count of an object. */
197 get_obj_handle_count (HANDLE h)
199 OBJECT_BASIC_INFORMATION obi;
203 status = NtQueryObject (h, ObjectBasicInformation, &obi, sizeof obi, NULL);
204 if (!NT_SUCCESS (status))
205 debug_printf ("NtQueryObject: %p\n", status);
207 hdl_cnt = obi.HandleCount;
211 /* Per lock class. */
215 short lf_flags; /* Semantics: F_POSIX, F_FLOCK, F_WAIT */
216 short lf_type; /* Lock type: F_RDLCK, F_WRLCK */
217 _off64_t lf_start; /* Byte # of the start of the lock */
218 _off64_t lf_end; /* Byte # of the end of the lock (-1=EOF) */
219 long long lf_id; /* Cygwin PID for POSIX locks, a unique id per
220 file table entry for BSD flock locks. */
221 DWORD lf_wid; /* Win PID of the resource holding the lock */
222 class lockf_t **lf_head; /* Back pointer to the head of the lockf_t list */
223 class inode_t *lf_inode; /* Back pointer to the inode_t */
224 class lockf_t *lf_next; /* Pointer to the next lock on this inode_t */
225 HANDLE lf_obj; /* Handle to the lock event object. */
228 : lf_flags (0), lf_type (0), lf_start (0), lf_end (0), lf_id (0),
229 lf_wid (0), lf_head (NULL), lf_inode (NULL),
230 lf_next (NULL), lf_obj (NULL)
232 lockf_t (class inode_t *node, class lockf_t **head, short flags, short type,
233 _off64_t start, _off64_t end, long long id, DWORD wid)
234 : lf_flags (flags), lf_type (type), lf_start (start), lf_end (end),
235 lf_id (id), lf_wid (wid), lf_head (head), lf_inode (node),
236 lf_next (NULL), lf_obj (NULL)
240 /* Used to create all locks list in a given TLS buffer. */
241 void *operator new (size_t size, void *p)
243 /* Used to store own lock list in the cygheap. */
244 void *operator new (size_t size)
245 { return cmalloc (HEAP_FHANDLER, sizeof (lockf_t)); }
246 /* Never call on node->i_all_lf! */
247 void operator delete (void *p)
250 void create_lock_obj ();
251 bool open_lock_obj ();
252 void del_lock_obj (HANDLE fhdl, bool signal = false);
255 /* Per inode_t class */
258 friend class lockf_t;
261 LIST_ENTRY (inode_t) i_next;
262 lockf_t *i_lockf; /* List of locks of this process. */
263 lockf_t *i_all_lf; /* Temp list of all locks for this file. */
265 __dev32_t i_dev; /* Device ID */
266 __ino64_t i_ino; /* inode number */
271 unsigned long i_wait; /* Number of blocked threads waiting for
275 inode_t (__dev32_t dev, __ino64_t ino);
278 void *operator new (size_t size)
279 { return cmalloc (HEAP_FHANDLER, sizeof (inode_t)); }
280 void operator delete (void *p)
283 static inode_t *get (__dev32_t dev, __ino64_t ino, bool create_if_missing);
285 void LOCK () { WaitForSingleObject (i_mtx, INFINITE); }
286 void UNLOCK () { ReleaseMutex (i_mtx); }
288 void wait () { ++i_wait; }
289 void unwait () { if (i_wait > 0) --i_wait; }
290 bool waiting () { return i_wait > 0; }
292 lockf_t *get_all_locks_list ();
294 bool del_my_locks (long long id, HANDLE fhdl);
299 lockf_t *lock, *n_lock;
300 for (lock = i_lockf; lock && (n_lock = lock->lf_next, 1); lock = n_lock)
307 inode_t::del_my_locks (long long id, HANDLE fhdl)
309 lockf_t *lock, *n_lock;
310 lockf_t **prev = &i_lockf;
312 for (lock = *prev; lock && (n_lock = lock->lf_next, 1); lock = n_lock)
314 if (lock->lf_flags & F_POSIX)
316 /* Delete all POSIX locks. */
321 else if (id && lock->lf_id == id)
324 cygheap_fdenum cfd (true);
325 while (cfd.next () >= 0)
326 if (cfd->get_unique_id () == lock->lf_id && ++cnt > 1)
328 /* Delete BSD flock lock when no other fd in this process references
333 lock->del_lock_obj (fhdl);
338 prev = &lock->lf_next;
340 return i_lockf == NULL;
343 /* Used to delete the locks on a file hold by this process. Called from
344 close(2) and fixup_after_fork, as well as from fixup_after_exec in
345 case the close_on_exec flag is set. The whole inode is deleted as
346 soon as no lock exists on it anymore. */
348 fhandler_base::del_my_locks (del_lock_called_from from)
351 inode_t *node = inode_t::get (get_dev (), get_ino (), false);
354 /* When we're called from fixup_after_exec, the fhandler is a
355 close-on-exec fhandler. In this case our io handle is already
356 invalid. We can't use it to test for the object reference count.
357 However, that shouldn't be necessary for the following reason.
358 After exec, there are no threads in the current process waiting for
359 the lock. So, either we're the only process accessing the file table
360 entry and there are no threads which require signalling, or we have
361 a parent process still accessing the file object and signalling the
362 lock event would be premature. */
364 node->del_my_locks (from == after_fork ? 0 : get_unique_id (),
365 from == after_exec ? NULL : get_handle ());
368 LIST_REMOVE (node, i_next);
375 INODE_LIST_UNLOCK ();
378 /* Called in an execed child. The exec'ed process must allow SYNCHRONIZE
379 access to everyone if at least one inode exists.
380 The lock owner's Windows PID changed and all POSIX lock event objects
381 have to be relabeled so that waiting processes know which process to
382 wait on. If the node has been abandoned due to close_on_exec on the
383 referencing fhandlers, remove the inode entirely. */
385 fixup_lockf_after_exec ()
387 inode_t *node, *next_node;
390 if (LIST_FIRST (&cygheap->inode_list))
391 allow_others_to_sync ();
392 LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node)
395 cygheap_fdenum cfd (true);
396 while (cfd.next () >= 0)
397 if (cfd->get_dev () == node->i_dev
398 && cfd->get_ino () == node->i_ino
403 LIST_REMOVE (node, i_next);
409 for (lockf_t *lock = node->i_lockf; lock; lock = lock->lf_next)
410 if (lock->lf_flags & F_POSIX)
412 lock->del_lock_obj (NULL);
413 lock->lf_wid = myself->dwProcessId;
414 lock->create_lock_obj ();
419 INODE_LIST_UNLOCK ();
422 /* static method to return a pointer to the inode_t structure for a specific
423 file. The file is specified by the device and inode_t number. If inode_t
424 doesn't exist, create it. */
426 inode_t::get (__dev32_t dev, __ino64_t ino, bool create_if_missing)
431 LIST_FOREACH (node, &cygheap->inode_list, i_next)
432 if (node->i_dev == dev && node->i_ino == ino)
434 if (!node && create_if_missing)
436 node = new inode_t (dev, ino);
438 LIST_INSERT_HEAD (&cygheap->inode_list, node, i_next);
442 INODE_LIST_UNLOCK ();
446 inode_t::inode_t (__dev32_t dev, __ino64_t ino)
447 : i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_wait (0L)
451 UNICODE_STRING uname;
452 OBJECT_ATTRIBUTES attr;
455 parent_dir = get_shared_parent_dir ();
456 /* Create a subdir which is named after the device and inode_t numbers
457 of the given file, in hex notation. */
458 int len = __small_swprintf (name, L"flock-%08x-%016X", dev, ino);
459 RtlInitCountedUnicodeString (&uname, name, len * sizeof (WCHAR));
460 InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
461 parent_dir, everyone_sd (FLOCK_INODE_DIR_ACCESS));
462 status = NtCreateDirectoryObject (&i_dir, FLOCK_INODE_DIR_ACCESS, &attr);
463 if (!NT_SUCCESS (status))
464 api_fatal ("NtCreateDirectoryObject(inode): %p", status);
465 /* Create a mutex object in the file specific dir, which is used for
466 access synchronization on the dir and its objects. */
467 InitializeObjectAttributes (&attr, &ro_u_mtx, OBJ_INHERIT | OBJ_OPENIF, i_dir,
468 everyone_sd (CYG_MUTANT_ACCESS));
469 status = NtCreateMutant (&i_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
470 if (!NT_SUCCESS (status))
471 api_fatal ("NtCreateMutant(inode): %p", status);
474 /* Enumerate all lock event objects for this file and create a lockf_t
475 list in the i_all_lf member. This list is searched in lf_getblock
476 for locks which potentially block our lock request. */
478 /* Number of lockf_t structs which fit in the temporary buffer. */
479 #define MAX_LOCKF_CNT ((intptr_t)((NT_MAX_PATH * sizeof (WCHAR)) \
483 inode_t::get_all_locks_list ()
487 DIRECTORY_BASIC_INFORMATION dbi;
488 WCHAR buf[2][NAME_MAX + 1];
492 lockf_t *lock = i_all_lf;
494 for (BOOLEAN restart = TRUE;
495 NT_SUCCESS (status = NtQueryDirectoryObject (i_dir, &f, sizeof f, TRUE,
496 restart, &context, NULL));
499 if (f.dbi.ObjectName.Length != LOCK_OBJ_NAME_LEN * sizeof (WCHAR))
501 wchar_t *wc = f.dbi.ObjectName.Buffer, *endptr;
502 /* "%02x-%01x-%016X-%016X-%016X-%08x",
503 lf_flags, lf_type, lf_start, lf_end, lf_id, lf_wid */
504 wc[LOCK_OBJ_NAME_LEN] = L'\0';
505 short flags = wcstol (wc, &endptr, 16);
506 if ((flags & ~(F_FLOCK | F_POSIX)) != 0
507 || ((flags & (F_FLOCK | F_POSIX)) == (F_FLOCK | F_POSIX)))
509 short type = wcstol (endptr + 1, &endptr, 16);
510 if ((type != F_RDLCK && type != F_WRLCK) || !endptr || *endptr != L'-')
512 _off64_t start = (_off64_t) wcstoull (endptr + 1, &endptr, 16);
513 if (start < 0 || !endptr || *endptr != L'-')
515 _off64_t end = (_off64_t) wcstoull (endptr + 1, &endptr, 16);
516 if (end < -1LL || (end > 0 && end < start) || !endptr || *endptr != L'-')
518 long long id = wcstoll (endptr + 1, &endptr, 16);
519 if (!endptr || *endptr != L'-'
520 || ((flags & F_POSIX) && (id < 1 || id > ULONG_MAX)))
522 DWORD wid = wcstoul (endptr + 1, &endptr, 16);
523 if (endptr && *endptr != L'\0')
525 if (lock - i_all_lf >= MAX_LOCKF_CNT)
527 system_printf ("Warning, can't handle more than %d locks per file.",
532 lock[-1].lf_next = lock;
533 new (lock++) lockf_t (this, &i_all_lf, flags, type, start, end, id, wid);
535 /* If no lock has been found, return NULL. */
536 if (lock == i_all_lf)
541 /* Create the lock event object in the file's subdir in the NT global
542 namespace. The name is constructed from the lock properties which
543 identify it uniquely, all values in hex. See the __small_swprintf
544 call right at the start. */
546 lockf_t::create_lock_obj ()
548 WCHAR name[LOCK_OBJ_NAME_LEN + 1];
549 UNICODE_STRING uname;
550 OBJECT_ATTRIBUTES attr;
553 __small_swprintf (name, L"%02x-%01x-%016X-%016X-%016X-%08x",
554 lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start,
555 lf_end, lf_id, lf_wid);
556 RtlInitCountedUnicodeString (&uname, name,
557 LOCK_OBJ_NAME_LEN * sizeof (WCHAR));
558 InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT, lf_inode->i_dir,
559 everyone_sd (FLOCK_EVENT_ACCESS));
560 status = NtCreateEvent (&lf_obj, CYG_EVENT_ACCESS, &attr,
561 NotificationEvent, FALSE);
562 if (!NT_SUCCESS (status))
563 api_fatal ("NtCreateEvent(lock): %p", status);
566 /* Open a lock event object for SYNCHRONIZE access (to wait for it). */
568 lockf_t::open_lock_obj ()
570 WCHAR name[LOCK_OBJ_NAME_LEN + 1];
571 UNICODE_STRING uname;
572 OBJECT_ATTRIBUTES attr;
575 __small_swprintf (name, L"%02x-%01x-%016X-%016X-%016X-%08x",
576 lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start,
577 lf_end, lf_id, lf_wid);
578 RtlInitCountedUnicodeString (&uname, name,
579 LOCK_OBJ_NAME_LEN * sizeof (WCHAR));
580 InitializeObjectAttributes (&attr, &uname, 0, lf_inode->i_dir, NULL);
581 status = NtOpenEvent (&lf_obj, FLOCK_EVENT_ACCESS, &attr);
582 if (!NT_SUCCESS (status))
584 SetLastError (RtlNtStatusToDosError (status));
585 lf_obj = NULL; /* Paranoia... */
587 return lf_obj != NULL;
590 /* Close a lock event handle. The important thing here is to signal it
591 before closing the handle. This way all threads waiting for this
594 lockf_t::del_lock_obj (HANDLE fhdl, bool signal)
598 /* Only signal the event if it's either a POSIX lock, or, in case of
599 BSD flock locks, if it's an explicit unlock or if the calling fhandler
600 holds the last reference to the file table entry. The file table
601 entry in UNIX terms is equivalent to the FILE_OBJECT in Windows NT
602 terms. It's what the handle/descriptor references when calling
603 CreateFile/open. Calling DuplicateHandle/dup only creates a new
604 handle/descriptor to the same FILE_OBJECT/file table entry. */
605 if ((lf_flags & F_POSIX) || signal
606 || (fhdl && get_obj_handle_count (fhdl) <= 1))
619 * This variable controls the maximum number of processes that will
620 * be checked in doing deadlock detection.
624 static int maxlockdepth = MAXDEPTH;
627 #define NOLOCKF (struct lockf_t *)0
630 static int lf_clearlock (lockf_t *, lockf_t **, HANDLE);
631 static int lf_findoverlap (lockf_t *, lockf_t *, int, lockf_t ***, lockf_t **);
632 static lockf_t *lf_getblock (lockf_t *, inode_t *node);
633 static int lf_getlock (lockf_t *, inode_t *, struct __flock64 *);
634 static int lf_setlock (lockf_t *, inode_t *, lockf_t **, HANDLE);
635 static void lf_split (lockf_t *, lockf_t *, lockf_t **);
636 static void lf_wakelock (lockf_t *, HANDLE);
639 fhandler_disk_file::lock (int a_op, struct __flock64 *fl)
641 _off64_t start, end, oadd;
645 short a_flags = fl->l_type & (F_POSIX | F_FLOCK);
646 short type = fl->l_type & (F_RDLCK | F_WRLCK | F_UNLCK);
649 a_flags = F_POSIX; /* default */
650 if (a_op == F_SETLKW)
662 /* flock semantics don't specify a requirement that the file has
663 been opened with a specific open mode, in contrast to POSIX locks
664 which require that a file is opened for reading to place a read
665 lock and opened for writing to place a write lock. */
666 if ((a_flags & F_POSIX) && !(get_access () & GENERIC_READ))
673 /* See above comment. */
674 if ((a_flags & F_POSIX) && !(get_access () & GENERIC_WRITE))
686 * Convert the flock structure into a start and end.
688 switch (fl->l_whence)
695 if ((start = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK)
703 FILE_STANDARD_INFORMATION fsi;
705 status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
706 FileStandardInformation);
707 if (!NT_SUCCESS (status))
709 __seterrno_from_nt_status (status);
712 if (fl->l_start > 0 && fsi.EndOfFile.QuadPart > OFF_MAX - fl->l_start)
714 set_errno (EOVERFLOW);
717 start = fsi.EndOfFile.QuadPart + fl->l_start;
744 else if (fl->l_len == 0)
748 oadd = fl->l_len - 1;
749 if (oadd > OFF_MAX - start)
751 set_errno (EOVERFLOW);
757 inode_t *node = inode_t::get (get_dev (), get_ino (), true);
763 need_fork_fixup (true);
765 /* Unlock the fd table which has been locked in fcntl_worker/lock_worker,
766 otherwise a blocking F_SETLKW never wakes up on a signal. */
767 cygheap->fdtab.unlock ();
769 lockf_t **head = &node->i_lockf;
773 * Avoid the common case of unlocking when inode_t has no locks.
775 * This shortcut is invalid for Cygwin because the above inode_t::get
776 * call returns with an empty lock list if this process has no locks
784 fl->l_type = F_UNLCK;
790 * Allocate a spare structure in case we have to split.
792 lockf_t *clean = NULL;
793 if (a_op == F_SETLK || a_op == F_UNLCK)
795 clean = new lockf_t ();
804 * Create the lockf_t structure
806 lockf_t *lock = new lockf_t (node, head, a_flags, type, start, end,
807 (a_flags & F_FLOCK) ? get_unique_id ()
809 myself->dwProcessId);
820 error = lf_setlock (lock, node, &clean, get_handle ());
824 error = lf_clearlock (lock, &clean, get_handle ());
825 lock->lf_next = clean;
830 error = lf_getlock (lock, node, fl);
831 lock->lf_next = clean;
836 lock->lf_next = clean;
841 for (lock = clean; lock != NULL; )
844 lock->del_lock_obj (get_handle (), a_op == F_UNLCK);
848 if (node->i_lockf == NULL && !node->waiting ())
851 LIST_REMOVE (node, i_next);
854 INODE_LIST_UNLOCK ();
867 * Set a byte-range lock.
870 lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
873 lockf_t **head = lock->lf_head;
874 lockf_t **prev, *overlap;
875 int ovcase, priority, old_prio, needtolink;
881 priority = old_prio = GetThreadPriority (GetCurrentThread ());
882 if (lock->lf_type == F_WRLCK && priority <= THREAD_PRIORITY_ABOVE_NORMAL)
883 priority = THREAD_PRIORITY_HIGHEST;
885 * Scan lock list for this file looking for locks that would block us.
887 /* Create temporary space for the all locks list. */
888 node->i_all_lf = (lockf_t *) tp.w_get ();
889 while ((block = lf_getblock(lock, node)))
892 HANDLE obj = block->lf_obj;
893 block->lf_obj = NULL;
896 * Free the structure and return if nonblocking.
898 if ((lock->lf_flags & F_WAIT) == 0)
900 lock->lf_next = *clean;
907 * We are blocked. Since flock style locks cover
908 * the whole file, there is no chance for deadlock.
909 * For byte-range locks we must check for deadlock.
911 * Deadlock detection is done by looking through the
912 * wait channels to see if there are any cycles that
913 * involve us. MAXDEPTH is set just to make sure we
914 * do not go off into neverland.
916 /* FIXME: We check the handle count of all the lock event objects
917 this process holds. If it's > 1, another process is
918 waiting for one of our locks. This method isn't overly
919 intelligent. If it turns out to be too dumb, we might
920 have to remove it or to find another method. */
921 for (lockf_t *lk = node->i_lockf; lk; lk = lk->lf_next)
922 if ((lk->lf_flags & F_POSIX) && get_obj_handle_count (lk->lf_obj) > 1)
930 * For flock type locks, we must first remove
931 * any shared locks that we hold before we sleep
932 * waiting for an exclusive lock.
934 if ((lock->lf_flags & F_FLOCK) && lock->lf_type == F_WRLCK)
936 lock->lf_type = F_UNLCK;
937 (void) lf_clearlock (lock, clean, fhdl);
938 lock->lf_type = F_WRLCK;
942 * Add our lock to the blocked list and sleep until we're free.
943 * Remember who blocked us (for deadlock detection).
945 /* Cygwin: No locked list. See deadlock recognition above. */
947 /* Wait for the blocking object and its holding process. */
950 /* We can't synchronize on the lock event object.
951 Treat this as a deadlock-like situation for now. */
952 system_printf ("Can't sync with lock object hold by "
953 "Win32 pid %lu: %E", block->lf_wid);
956 SetThreadPriority (GetCurrentThread (), priority);
957 if (lock->lf_flags & F_POSIX)
959 HANDLE proc = OpenProcess (SYNCHRONIZE, FALSE, block->lf_wid);
962 /* If we can't synchronize on the process holding the lock,
963 we will never recognize when the lock has been abandoned.
964 Treat this as a deadlock-like situation for now. */
965 system_printf ("Can't sync with process holding a lock "
966 "(Win32 pid %lu): %E", block->lf_wid);
970 HANDLE w4[3] = { obj, proc, signal_arrived };
973 ret = WaitForMultipleObjects (3, w4, FALSE, INFINITE);
978 HANDLE w4[2] = { obj, signal_arrived };
981 /* Unfortunately, since BSD flock locks are not attached to a
982 specific process, we can't recognize an abandoned lock by
983 sync'ing with a process. We have to find out if we're the only
984 process left accessing this event object. */
987 ret = WaitForMultipleObjects (2, w4, FALSE, 100L);
989 while (ret == WAIT_TIMEOUT && get_obj_handle_count (obj) > 1);
990 /* There's a good chance that the above loop is left with
991 ret == WAIT_TIMEOUT if another process closes the file handle
992 associated with this lock. This is for all practical purposes
993 equivalent to a signalled lock object. */
994 if (ret == WAIT_TIMEOUT)
1000 SetThreadPriority (GetCurrentThread (), old_prio);
1004 /* The lock object has been set to signalled. */
1006 case WAIT_OBJECT_0 + 1:
1007 /* For POSIX locks, the process holding the lock has exited. */
1008 if (lock->lf_flags & F_POSIX)
1011 case WAIT_OBJECT_0 + 2:
1012 /* A signal came in. */
1013 _my_tls.call_signal_handler ();
1016 system_printf ("Shouldn't happen! ret = %lu, error: %lu\n",
1017 ret, GetLastError ());
1018 return geterrno_from_win_error ();
1021 allow_others_to_sync ();
1023 * No blocks!! Add the lock. Note that we will
1024 * downgrade or upgrade any overlapping locks this
1025 * process already owns.
1027 * Handle any locks that overlap.
1034 ovcase = lf_findoverlap (block, lock, SELF, &prev, &overlap);
1036 block = overlap->lf_next;
1040 * 1) overlap == lock
1041 * 2) overlap contains lock
1042 * 3) lock contains overlap
1043 * 4) overlap starts before lock
1044 * 5) overlap ends after lock
1048 case 0: /* no overlap */
1052 lock->lf_next = overlap;
1053 lock->create_lock_obj ();
1057 case 1: /* overlap == lock */
1059 * If downgrading lock, others may be
1060 * able to acquire it.
1061 * Cygwin: Always wake lock.
1063 lf_wakelock (overlap, fhdl);
1064 overlap->lf_type = lock->lf_type;
1065 overlap->create_lock_obj ();
1066 lock->lf_next = *clean;
1070 case 2: /* overlap contains lock */
1072 * Check for common starting point and different types.
1074 if (overlap->lf_type == lock->lf_type)
1076 lock->lf_next = *clean;
1080 if (overlap->lf_start == lock->lf_start)
1083 lock->lf_next = overlap;
1084 overlap->lf_start = lock->lf_end + 1;
1087 lf_split (overlap, lock, clean);
1088 lf_wakelock (overlap, fhdl);
1089 overlap->create_lock_obj ();
1090 lock->create_lock_obj ();
1091 if (lock->lf_next && !lock->lf_next->lf_obj)
1092 lock->lf_next->create_lock_obj ();
1095 case 3: /* lock contains overlap */
1097 * If downgrading lock, others may be able to
1098 * acquire it, otherwise take the list.
1099 * Cygwin: Always wake old lock and create new lock.
1101 lf_wakelock (overlap, fhdl);
1103 * Add the new lock if necessary and delete the overlap.
1108 lock->lf_next = overlap->lf_next;
1109 prev = &lock->lf_next;
1110 lock->create_lock_obj ();
1114 *prev = overlap->lf_next;
1115 overlap->lf_next = *clean;
1119 case 4: /* overlap starts before lock */
1121 * Add lock after overlap on the list.
1123 lock->lf_next = overlap->lf_next;
1124 overlap->lf_next = lock;
1125 overlap->lf_end = lock->lf_start - 1;
1126 prev = &lock->lf_next;
1127 lf_wakelock (overlap, fhdl);
1128 overlap->create_lock_obj ();
1129 lock->create_lock_obj ();
1133 case 5: /* overlap ends after lock */
1135 * Add the new lock before overlap.
1139 lock->lf_next = overlap;
1141 overlap->lf_start = lock->lf_end + 1;
1142 lf_wakelock (overlap, fhdl);
1143 lock->create_lock_obj ();
1144 overlap->create_lock_obj ();
1153 * Remove a byte-range lock on an inode_t.
1155 * Generally, find the lock (or an overlap to that lock)
1156 * and remove it (or shrink it), then wakeup anyone we can.
1159 lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl)
1161 lockf_t **head = unlock->lf_head;
1162 lockf_t *lf = *head;
1163 lockf_t *overlap, **prev;
1169 while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap)))
1172 * Wakeup the list of locks to be retried.
1174 lf_wakelock (overlap, fhdl);
1178 case 1: /* overlap == lock */
1179 *prev = overlap->lf_next;
1180 overlap->lf_next = *clean;
1184 case 2: /* overlap contains lock: split it */
1185 if (overlap->lf_start == unlock->lf_start)
1187 overlap->lf_start = unlock->lf_end + 1;
1188 overlap->create_lock_obj ();
1191 lf_split (overlap, unlock, clean);
1192 overlap->lf_next = unlock->lf_next;
1193 overlap->create_lock_obj ();
1194 if (overlap->lf_next && !overlap->lf_next->lf_obj)
1195 overlap->lf_next->create_lock_obj ();
1198 case 3: /* lock contains overlap */
1199 *prev = overlap->lf_next;
1200 lf = overlap->lf_next;
1201 overlap->lf_next = *clean;
1205 case 4: /* overlap starts before lock */
1206 overlap->lf_end = unlock->lf_start - 1;
1207 prev = &overlap->lf_next;
1208 lf = overlap->lf_next;
1209 overlap->create_lock_obj ();
1212 case 5: /* overlap ends after lock */
1213 overlap->lf_start = unlock->lf_end + 1;
1214 overlap->create_lock_obj ();
1223 * Check whether there is a blocking lock,
1224 * and if so return its process identifier.
1227 lf_getlock (lockf_t *lock, inode_t *node, struct __flock64 *fl)
1232 /* Create temporary space for the all locks list. */
1233 node->i_all_lf = (lockf_t *) tp.w_get ();
1234 if ((block = lf_getblock (lock, node)))
1237 NtClose (block->lf_obj);
1238 fl->l_type = block->lf_type;
1239 fl->l_whence = SEEK_SET;
1240 fl->l_start = block->lf_start;
1241 if (block->lf_end == -1)
1244 fl->l_len = block->lf_end - block->lf_start + 1;
1245 if (block->lf_flags & F_POSIX)
1246 fl->l_pid = (pid_t) block->lf_id;
1251 fl->l_type = F_UNLCK;
1256 * Walk the list of locks for an inode_t and
1257 * return the first blocking lock.
1260 lf_getblock (lockf_t *lock, inode_t *node)
1262 lockf_t **prev, *overlap;
1263 lockf_t *lf = node->get_all_locks_list ();
1266 EVENT_BASIC_INFORMATION ebi;
1268 prev = lock->lf_head;
1269 while ((ovcase = lf_findoverlap (lf, lock, OTHERS, &prev, &overlap)))
1272 * We've found an overlap, see if it blocks us
1274 if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK))
1276 /* Open the event object for synchronization. */
1277 if (!overlap->open_lock_obj () || (overlap->lf_flags & F_POSIX))
1279 /* In case of BSD flock locks, check if the event object is
1280 signalled. If so, the overlap doesn't actually exist anymore.
1281 There are just a few open handles left. */
1282 status = NtQueryEvent (overlap->lf_obj, EventBasicInformation,
1283 &ebi, sizeof ebi, NULL);
1284 if (!NT_SUCCESS (status) || ebi.SignalState == 0)
1286 NtClose (overlap->lf_obj);
1287 overlap->lf_obj = NULL;
1290 * Nope, point to the next one on the list and
1291 * see if it blocks us
1293 lf = overlap->lf_next;
1299 * Walk the list of locks for an inode_t to
1300 * find an overlapping lock (if any).
1302 * NOTE: this returns only the FIRST overlapping lock. There
1303 * may be more than one.
1306 lf_findoverlap (lockf_t *lf, lockf_t *lock, int type, lockf_t ***prev,
1309 _off64_t start, end;
1315 start = lock->lf_start;
1317 while (lf != NOLOCKF)
1319 if (((type & SELF) && lf->lf_id != lock->lf_id)
1320 || ((type & OTHERS) && lf->lf_id == lock->lf_id)
1321 /* As on Linux: POSIX locks and BSD flock locks don't interact. */
1322 || (lf->lf_flags & (F_POSIX | F_FLOCK))
1323 != (lock->lf_flags & (F_POSIX | F_FLOCK)))
1325 *prev = &lf->lf_next;
1326 *overlap = lf = lf->lf_next;
1330 * OK, check for overlap
1334 * 1) overlap == lock
1335 * 2) overlap contains lock
1336 * 3) lock contains overlap
1337 * 4) overlap starts before lock
1338 * 5) overlap ends after lock
1340 if ((lf->lf_end != -1 && start > lf->lf_end) ||
1341 (end != -1 && lf->lf_start > end))
1344 if ((type & SELF) && end != -1 && lf->lf_start > end)
1346 *prev = &lf->lf_next;
1347 *overlap = lf = lf->lf_next;
1350 if ((lf->lf_start == start) && (lf->lf_end == end))
1355 if ((lf->lf_start <= start) && (end != -1) &&
1356 ((lf->lf_end >= end) || (lf->lf_end == -1)))
1361 if (start <= lf->lf_start && (end == -1 ||
1362 (lf->lf_end != -1 && end >= lf->lf_end)))
1367 if ((lf->lf_start < start) &&
1368 ((lf->lf_end >= start) || (lf->lf_end == -1)))
1373 if ((lf->lf_start > start) && (end != -1) &&
1374 ((lf->lf_end > end) || (lf->lf_end == -1)))
1379 api_fatal ("lf_findoverlap: default\n");
1385 * Split a lock and a contained region into
1386 * two or three locks as necessary.
1389 lf_split (lockf_t *lock1, lockf_t *lock2, lockf_t **split)
1394 * Check to see if spliting into only two pieces.
1396 if (lock1->lf_start == lock2->lf_start)
1398 lock1->lf_start = lock2->lf_end + 1;
1399 lock2->lf_next = lock1;
1402 if (lock1->lf_end == lock2->lf_end)
1404 lock1->lf_end = lock2->lf_start - 1;
1405 lock2->lf_next = lock1->lf_next;
1406 lock1->lf_next = lock2;
1410 * Make a new lock consisting of the last part of
1411 * the encompassing lock. We use the preallocated
1412 * splitlock so we don't have to block.
1415 assert (splitlock != NULL);
1416 *split = splitlock->lf_next;
1417 memcpy (splitlock, lock1, sizeof *splitlock);
1418 /* We have to unset the obj HANDLE here which has been copied by the
1419 above memcpy, so that the calling function recognizes the new object.
1420 See post-lf_split handling in lf_setlock and lf_clearlock. */
1421 splitlock->lf_obj = NULL;
1422 splitlock->lf_start = lock2->lf_end + 1;
1423 lock1->lf_end = lock2->lf_start - 1;
1425 * OK, now link it in
1427 splitlock->lf_next = lock1->lf_next;
1428 lock2->lf_next = splitlock;
1429 lock1->lf_next = lock2;
1433 * Wakeup a blocklist
1434 * Cygwin: Just signal the lock which gets removed. This unblocks
1435 * all threads waiting for this lock.
1438 lf_wakelock (lockf_t *listhead, HANDLE fhdl)
1440 listhead->del_lock_obj (fhdl, true);
1444 flock (int fd, int operation)
1448 struct __flock64 fl = { 0, SEEK_SET, 0, 0, 0 };
1451 if (efault.faulted (EFAULT))
1454 cygheap_fdget cfd (fd, true);
1458 cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW;
1459 switch (operation & (~LOCK_NB))
1462 fl.l_type = F_WRLCK | F_FLOCK;
1465 fl.l_type = F_RDLCK | F_FLOCK;
1468 fl.l_type = F_UNLCK | F_FLOCK;
1474 res = cfd->lock (cmd, &fl);
1475 if ((res == -1) && ((get_errno () == EAGAIN) || (get_errno () == EACCES)))
1476 set_errno (EWOULDBLOCK);
1478 syscall_printf ("%d = flock (%d, %d)", res, fd, operation);
1483 lockf (int filedes, int function, _off64_t size)
1487 struct __flock64 fl;
1490 if (efault.faulted (EFAULT))
1493 cygheap_fdget cfd (filedes, true);
1499 fl.l_whence = SEEK_CUR;
1505 fl.l_type = F_UNLCK;
1509 fl.l_type = F_WRLCK;
1513 fl.l_type = F_WRLCK;
1516 fl.l_type = F_WRLCK;
1517 if (cfd->lock (F_GETLK, &fl) == -1)
1519 if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
1530 res = cfd->lock (cmd, &fl);
1532 syscall_printf ("%d = lockf (%d, %d, %D)", res, filedes, function, size);