[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH hurd 3/6] Add file record locking support



libfshelp: implement fshelp_rlock_* functions
libfshelp/ChangeLog
2014-08-21  Svante Signell <svante.signell@gmail.com>

	* Makefile: Link with pthread
	* define temporary CPP_FLAGS until glibc is updated
	* rlock-drop-peropen.c: Port from cthreads to libpthread.
	* rlock-tweak.c: Likewise
	* fshelp.h: Likewise
	* rlock.h: Likewise
	* FIXME: remove FIXMEs

2001-04-12  Neal H Walfield  <neal@cs.uml.edu>

	* fshelp.h (struct rlock_box): New structure.
	(struct rlock_peropen): Likewise.
	(fshelp_rlock_init): New funtion.
	(fshelp_rlock_po_init): Likewise.
	(fshelp_rlock_drop_peropen): Likewise.
	(fshelp_rlock_tweak): Likewise.
	(fshelp_rlock_peropen_status): Likewise.
	(fshelp_rlock_node_status): Likewise.
	* rlock-drop-peropen.c: New file.  Implement
	fshelp_rlock_drop_peropen.
	* rlock-status.c: New file.  Implement
	fshelp_rlock_peropen_status and fshelp_rlock_node_status.
	* rlock-tweak.c: New file.  Implement fshelp_rlock_tweak.
	* rlock.h: New file.
	* extern-inline.c: New file.
	* Makefile (LCLHDRS): Add rlock.h.
	(SRCS): Add extern-inline.c, rlock-drop-peropen.c, rlock-tweak.c
	and rlock-status.c.

Index: hurd-0.5.git20141210/libfshelp/Makefile
===================================================================
--- hurd-0.5.git20141210.orig/libfshelp/Makefile
+++ hurd-0.5.git20141210/libfshelp/Makefile
@@ -30,11 +30,19 @@ SRCS =	lock-acquire.c lock-init.c \
 	get-identity.c \
 	perms-isowner.c perms-iscontroller.c perms-access.c \
 	perms-checkdirmod.c \
-	touch.c
-installhdrs = fshelp.h
+	touch.c \
+	extern-inline.c \
+	rlock-drop-peropen.c rlock-tweak.c rlock-status.c
+
+installhdrs = fshelp.h locks.h trans.h rlock.h
 
 HURDLIBS = shouldbeinlibc iohelp ports ihash
 LDLIBS += -lpthread
 OBJS = $(subst .c,.o,$(SRCS))
 
+# Define the 64 bit versions of the second argument to fcntl()
+# Can safely be removed when glibc is updated
+EXTRA_CPP_FLAGS= -DF_GETLK64=10 -DF_SETLK64=11 -DF_SETLKW64=12
+rlock-tweak-CPPFLAGS += $(EXTRA_CPP_FLAGS)
+
 include ../Makeconf
Index: hurd-0.5.git20141210/libfshelp/fshelp.h
===================================================================
--- hurd-0.5.git20141210.orig/libfshelp/fshelp.h
+++ hurd-0.5.git20141210/libfshelp/fshelp.h
@@ -19,18 +19,24 @@
 #ifndef _HURD_FSHELP_
 #define _HURD_FSHELP_
 
+#ifndef FSHELP_EXTERN_INLINE
+#define FSHELP_EXTERN_INLINE extern inline
+#endif
+
 /* This library implements various things that are generic to
    all or most implementors of the filesystem protocol.  It
    presumes that you are using the iohelp library as well.  It
    is divided into separate facilities which may be used independently.  */
 
 #include <errno.h>
+#include <stdlib.h>
 #include <mach.h>
 #include <hurd/hurd_types.h>
 #include <pthread.h>
 #include <hurd/iohelp.h>
 #include <sys/stat.h>
 #include <maptime.h>
+#include <fcntl.h>
 
 
 /* Keeping track of active translators */
@@ -208,7 +214,11 @@ struct lock_box
   int shcount;
 };
 
-/* Call when a user makes a request to acquire an lock via file_lock.
+/* Initialize lock_box BOX.  (The user int passed to fshelp_acquire_lock
+   should be initialized with LOCK_UN.).  */
+void fshelp_lock_init (struct lock_box *box);
+
+/* Call when a user makes a request to acquire a lock via file_lock.
    There should be one lock box per object and one int per open; these
    are passed as arguments BOX and USER respectively.  FLAGS are as
    per file_lock.  MUT is a mutex which will be held whenever this
@@ -216,11 +226,71 @@ struct lock_box
 error_t fshelp_acquire_lock (struct lock_box *box, int *user,
 			     pthread_mutex_t *mut, int flags);
 
+
+/* Record locking.  */
 
-/* Initialize lock_box BOX.  (The user int passed to fshelp_acquire_lock
-   should be initialized with LOCK_UN.).  */
-void fshelp_lock_init (struct lock_box *box);
+/* Unique to a node; initialize with fshelp_rlock_init.  */
+struct rlock_box
+{
+  struct rlock_list *locks;	/* List of locks on the file.  */
+};
+
+/* Initialize the rlock_box BOX.  */
+FSHELP_EXTERN_INLINE
+error_t fshelp_rlock_init (struct rlock_box *box)
+{
+  box->locks = NULL;
+  return 0;
+}
+
+/* Unique to a peropen.  */
+struct rlock_peropen
+{
+  /* This is a pointer to a pointer to a rlock_lock (and not a pointer
+     to a rlock_list) as it really serves two functions:
+       o the list of locks owned by this peropen
+       o the unique peropen identifier that all locks on this peropen share.  */
+  struct rlock_list **locks;
+};
+
+FSHELP_EXTERN_INLINE
+error_t fshelp_rlock_po_init (struct rlock_peropen *po)
+{
+  po->locks = malloc (sizeof (struct rlock_list *));
+  if (! po->locks)
+    return ENOMEM;
+
+  *po->locks = NULL;
+  return 0;
+}
+
+/* Release all of the locks held by a given peropen.  */
+error_t fshelp_rlock_drop_peropen (struct rlock_peropen *po);
+
+/* Call when a user makes a request to tweak a lock as via fcntl.  There
+   should be one rlock box per object.  BOX is the rlock box associated
+   with the object.  MUT is a mutex which should be held whenever this
+   routine is called; it should be unique on a pernode basis.  PO is the
+   peropen identifier.  OPEN_MODE is how the file was opened (from the O_*
+   set).  SIZE is the size of the object in question.  CURPOINTER is the
+   current position of the file pointer.  CMD is from the set F_GETLK64,
+   F_SETLK64, F_SETLKW64.  LOCK is passed by the user and is as defined by
+   <fcntl.h>.  */
+error_t fshelp_rlock_tweak (struct rlock_box *box,
+			    pthread_mutex_t *mutex,
+			    struct rlock_peropen *po, int open_mode,
+			    loff_t size, loff_t curpointer, int cmd,
+			    struct flock64 *lock);
+
+/* These functions allow for easy emulation of file_lock and
+   file_lock_stat.  */
+
+/* Returns the type (from the set LOCK_UN, LOCK_SH, LOCK_EX) of the most
+   restictive lock held by the PEROPEN.  */
+int fshelp_rlock_peropen_status (struct rlock_peropen *po);
 
+/* Like fshelp_rlock_peropen_status except for all users of BOX.  */
+int fshelp_rlock_node_status (struct rlock_box *box);
 
 
 struct port_bucket;		/* shut up C compiler */
Index: hurd-0.5.git20141210/libfshelp/rlock-drop-peropen.c
===================================================================
--- /dev/null
+++ hurd-0.5.git20141210/libfshelp/rlock-drop-peropen.c
@@ -0,0 +1,49 @@
+/*
+   Copyright (C) 2001, 2014 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "fshelp.h"
+#include "rlock.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+error_t
+fshelp_rlock_drop_peropen (struct rlock_peropen *po)
+{
+  struct rlock_list *l;
+  struct rlock_list *t;
+
+  for (l = *po->locks; l; l = t)
+    {
+      if (l->waiting)
+	{
+	  l->waiting = 0;
+	  pthread_cond_broadcast (&l->wait);
+	}
+
+      list_unlink (node, l);
+
+      t = l->po.next;
+      free (l);
+    }
+
+  return 0;
+}
Index: hurd-0.5.git20141210/libfshelp/rlock-status.c
===================================================================
--- /dev/null
+++ hurd-0.5.git20141210/libfshelp/rlock-status.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2001, 2014 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+#include "rlock.h"
+#include <fcntl.h>
+#include <sys/file.h>
+
+int fshelp_rlock_peropen_status (struct rlock_peropen *po)
+{
+  struct rlock_list *l;
+
+  if (! *po->locks)
+    return LOCK_UN;
+
+  for (l = *po->locks; l; l = l->po.next)
+    if (l->type == F_WRLCK)
+      return LOCK_EX;
+
+  return LOCK_SH;
+}
+
+/* Like fshelp_rlock_peropen_status except for all users of NODE.  */
+int fshelp_rlock_node_status (struct rlock_box *box)
+{
+  struct rlock_list *l;
+
+  if (! box->locks)
+    return LOCK_UN;
+
+  for (l = box->locks; l; l = l->node.next)
+    if (l->type == F_WRLCK)
+      return LOCK_EX;
+
+  return LOCK_SH;
+}
+
Index: hurd-0.5.git20141210/libfshelp/rlock-tweak.c
===================================================================
--- /dev/null
+++ hurd-0.5.git20141210/libfshelp/rlock-tweak.c
@@ -0,0 +1,551 @@
+/*
+  Copyright (C) 2001, 2014 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "fshelp.h"
+#include "rlock.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <hurd.h>
+#include <hurd/process.h>
+
+//#include <stdio.h> /* printf */
+
+static inline long overlap (loff_t start, loff_t len, struct rlock_list *l)
+{
+  return ((len == 0 && l->len == 0)
+	  || (len == 0 && l->start + l->len > start)
+	  || (l->len == 0 && start + len > l->start)
+	  || (l->start + l->len > start && start + len > l->start));
+}
+
+error_t
+fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t *mutex,
+		    struct rlock_peropen *po, int open_mode,
+		    loff_t obj_size, loff_t cur_pointer, int cmd,
+		    struct flock64 *lock)
+{
+  inline struct rlock_list *
+  gen_lock (loff_t start, loff_t len, int type)
+    {
+      struct rlock_list *l = malloc (sizeof (struct rlock_list));
+      if (! l)
+        return NULL;
+
+      rlock_list_init (po, l);
+      l->start = start;
+      l->len = len;
+      l->type = type;
+
+      list_link (po, po->locks, l);
+      list_link (node, &box->locks, l);
+      return l;
+    }
+
+  inline void
+  rele_lock (struct rlock_list *l, int wake_waiters)
+    {
+      list_unlink (po, l);
+      list_unlink (node, l);
+
+      if (wake_waiters && l->waiting)
+	pthread_cond_broadcast (&l->wait);
+
+      free (l);
+    }
+
+  error_t
+  unlock_region (loff_t start, loff_t len)
+    {
+      struct rlock_list *l;
+
+      for (l = *po->locks; l; l = l->po.next)
+	{
+	  if (l->len != 0 && l->start + l->len <= start)
+	    /* We start after the locked region ends.  */
+	    {
+	      continue;
+	    }
+	  else if (len != 0 && start + len <= l->start)
+	    /* We end before this region starts.  Since we are sorted,
+	       we are done.  */
+	    {
+	      return 0;
+	    }
+	  else if (start <= l->start
+		   && (len == 0
+		       || (l->len != 0
+			   && l->start + l->len <= start + len)))
+	    /* We wrap the locked region; consume it.  */
+	    {
+	      rele_lock (l, 1);
+	      continue;
+	    }
+	  else if (start <= l->start
+		   && (l->len == 0
+		       || (l->start < start + len)))
+	    /* The locked region is having its head unlocked.  */
+	    {
+	      assert (len != 0);
+	      assert (l->len == 0 || start + len < l->start + l->len);
+
+	      if (l->len != 0)
+		l->len -= start + len - l->start;
+	      l->start = start + len;
+
+	      if (l->waiting)
+		{
+		  l->waiting = 0;
+		  pthread_cond_broadcast (&l->wait);
+		}
+	    }
+	  else if (l->start < start
+		   && ((start < l->start + l->len
+		        && (len == 0 || l->start + l->len <= start + len))
+		       || (len == 0 && l->len == 0)))
+	    /* The locked region needs its tail unlocked.  */
+	    {
+	      assert (len == 0
+		      || (l->len != 0 && l->start + l->len <= start + len));
+
+	      l->len = start - l->start;
+
+	      if (l->waiting)
+		{
+		  l->waiting = 0;
+		  pthread_cond_broadcast (&l->wait);
+		}
+
+	      continue;
+	    }
+	  else if (l->start < start
+		   && (l->len == 0
+		       || (len != 0
+			   && start + len < l->start + l->len)))
+	    /* The locked region wraps us (absolutely); crave out the
+	       middle.  */
+	    {
+	      struct rlock_list *upper_half;
+
+	      assert (len != 0);
+
+	      upper_half = gen_lock (start + len,
+				     l->len
+				       ? l->start + l->len - (start + len)
+				       : 0,
+				     l->type);
+	      if (! upper_half)
+		return ENOMEM;
+
+	      l->len = start - l->start;
+
+	      return 0;
+	    }
+	  else if (start < l->start
+		   && len != 0
+		   && start + len <= l->start)
+	    /* The locked region starts after our end.  */
+	    {
+	      return 0;
+	    }
+	  else
+	    assert (! "Impossible!");
+	}
+
+      return 0;
+    }
+
+  inline struct rlock_list *
+  find_conflict (loff_t start, loff_t len, int type)
+    {
+      struct rlock_list *l;
+
+      for (l = box->locks; l; l = l->node.next)
+	{
+	  if (po->locks == l->po_id)
+	    continue;
+
+	  if ((l->type == F_WRLCK || type == F_WRLCK)
+	      && overlap (start, len, l))
+	    return l;
+	}
+
+      return NULL;
+    }
+
+  inline error_t
+  merge_in (loff_t start, loff_t len, int type)
+    {
+      struct rlock_list *l;
+
+      for (l = *po->locks; l; l = l->po.next)
+	{
+	  if (l->start <= start
+	      && (l->len == 0
+		  || (len != 0
+		      && start + len <= l->start + l->len)))
+	    /* Our start and end fall between the locked region
+	       (i.e. we are wrapped).  */
+	    {
+	      struct rlock_list *head = NULL;
+	      struct rlock_list *tail = NULL;
+
+	      if (type == l->type || type == F_RDLCK)
+		return 0;
+
+	      assert (type == F_WRLCK && l->type == F_RDLCK);
+
+	      if (l->start < start)
+	        /* We need to split the head off.  */
+		{
+		  head = gen_lock (l->start, start - l->start, F_RDLCK);
+		  if (! head)
+		    return ENOMEM;
+		}
+
+	      if ((l->len == 0 && len != 0)
+		  || start + len < l->start + l->len)
+		/* We need to split the tail off.  */
+	        {
+		  tail = gen_lock (start + len,
+				   l->len
+				     ? l->start + l->len - (start + len)
+				     : 0,
+				   F_RDLCK);
+		  if (! tail)
+		    {
+		      if (head)
+			rele_lock (head, 0);
+		      return ENOMEM;
+		    }
+		}
+
+	      if (head)
+		{
+		  loff_t shift = start - l->start;
+
+		  if (l->len != 0)
+		    l->len -= shift;
+		  l->start += shift;
+		}
+
+	      if (tail)
+	        l->len = tail->start - l->start;
+
+	      if (! tail)
+		/* There is a chance we can merge some more.  */
+	        {
+		  start = l->start;
+		  len = l->len;
+
+		  rele_lock (l, 1);
+		  continue;
+		}
+	      else
+	        {
+	          l->type = F_WRLCK;
+		  return 0;
+		}
+	    }
+	  else if (start <= l->start
+		   && (len == 0
+		       || (l->len != 0
+			   && l->start + l->len <= start + len)))
+	    /* We fully wrap the locked region.  */
+	    {
+	      struct rlock_list *head;
+
+	      if (type == l->type || type == F_WRLCK)
+		{
+		  rele_lock (l, 1);
+		  /* Try to merge more.  */
+		  continue;
+		}
+
+	      assert (type == F_RDLCK && l->type == F_WRLCK);
+
+	      if (start < l->start)
+		/* Generate our head.  */
+		{
+		  head = gen_lock (start, l->start - start, F_RDLCK);
+		  if (! head)
+		    return ENOMEM;
+		}
+	      else
+		head = NULL;
+
+	      if (l->len != 0
+		  && (len == 0 || l->start + l->len < start + len))
+		/* We have a tail, try to merge it also.  */
+		{
+		  if (len != 0)
+		    len = start + len - (l->start + l->len);
+		  start = l->start + l->len;
+
+		  continue;
+		}
+	      else
+		/* Our end is silently consumed.  */
+	        {
+		  /* If we do not have a tail, we must have had a head
+		     (if not, the first case would have caught us).  */
+		  assert (head);
+	          return 0;
+		}
+	    }
+	  else if (l->start < start
+		   && (len == 0
+		       || (start <= l->start + l->len
+			   && start + len > l->start + l->len)))
+	    /* Our start falls within the locked region or exactly one
+	       byte after it and our end falls beyond it.  We know that
+	       we cannot consume the entire region.  */
+	    {
+	      assert (l->len != 0);
+
+	      if (type == l->type)
+		/* Merge the two areas.  */
+		{
+		  if (len != 0)
+		    len += start - l->start;
+		  start = l->start;
+
+		  rele_lock (l, 1);
+
+		  /* Try to merge in more.  */
+		  continue;
+		}
+	      else if (start == l->start + l->len)
+		  /* We fall just after the locked region (there is no
+		     intersection) and we are not the same type.  */
+		{
+		  /* The is nothing to do except continue the search.  */
+		  continue;
+		}
+	      else if (type == F_WRLCK)
+		/* We comsume the intersection.  */
+		{
+		  assert (l->type == F_RDLCK);
+
+		  l->len -= l->start + l->len - start;
+
+		  /* Don't create the lock now; we might be able to
+		     consume more locks.  */
+		  continue;
+		}
+	      else
+		/* We are dominated; the locked region comsumes the
+		   intersection.  */
+		{
+		  loff_t common = l->start + l->len - start;
+
+		  assert (type == F_RDLCK);
+		  assert (l->type == F_WRLCK);
+
+		  start += common;
+		  if (len != 0)
+		    len -= common;
+
+		  /* There is still a chance that we can consume more
+		     locks.  */
+		  continue;
+		}
+	    }
+	  else if (start < l->start
+		   && (l->len == 0
+		       || l->start <= start + len))
+	    /* Our start falls before the locked region and our
+	       end falls (inclusively) between it or one byte before it.
+	       Note, we know that we do not consume the entire locked
+	       area.  */
+	    {
+	      assert (len != 0);
+	      assert (l->len == 0 || start + len < l->start + l->len);
+
+	      if (type == l->type)
+		/* Merge the two areas.  */
+		{
+		  if (l->len)
+		    l->len += l->start - start;
+		  l->start = start;
+		  return 0;
+		}
+	      else if (l->start == start + len)
+		/* Our end falls just before the start of the locked
+		   region, however, we are not the same type.  Just
+		   insert it.  */
+		{
+		  continue;
+		}
+	      else if (type == F_WRLCK)
+		/* We consume the intersection.  */
+		{
+		  struct rlock_list *e;
+		  loff_t common = start + len - l->start;
+
+		  assert (l->type == F_RDLCK);
+
+		  e = gen_lock (start, len, F_WRLCK);
+		  if (! e)
+		    return ENOMEM;
+
+		  if (l->len)
+		    l->len -= common;
+		  l->start += common;
+
+		  return 0;
+		}
+	      else
+		/* The locked region comsumes the intersection.  */
+		{
+		  struct rlock_list *e;
+
+		  assert (l->type == F_WRLCK);
+		  assert (type == F_RDLCK);
+
+		  e = gen_lock (start, l->start - start, F_RDLCK);
+		  if (! e)
+		    return ENOMEM;
+
+		  return 0;
+		}
+	    }
+	  else if (start < l->start
+		   && len != 0
+		   && start + len <= l->start)
+	    /* We start and end before this locked region.  Therefore,
+	       knowing that the list is sorted, the merge is done.  */
+	    {
+	      break;
+	    }
+	  else
+	    /* We start beyond the end of this locked region.  */
+	    {
+	      assert (start >= l->start + l->len);
+	      assert (l->len != 0);
+	      continue;
+	    }
+	}
+
+      return (gen_lock (start, len, type) ? 0 : ENOMEM);
+    }
+
+  struct rlock_list *e;
+  loff_t start;
+  loff_t len;
+
+  if (cmd != F_GETLK64
+      && cmd != F_SETLK64
+      && cmd != F_SETLKW64)
+    return EOPNOTSUPP;
+
+  if (lock->l_type != F_UNLCK
+      && lock->l_type != F_RDLCK
+      && lock->l_type != F_WRLCK)
+    return EINVAL;
+
+  if (lock->l_type == F_UNLCK)
+    {
+      if (cmd == F_SETLKW64)
+        /* If we are unlocking a region, map F_SETLKW64 to F_SETLK64.  */
+        cmd = F_SETLK64;
+      else if (cmd == F_GETLK64)
+	/* Impossible!  */
+	return EINVAL;
+    }
+
+  if (lock->l_type == F_RDLCK && !(open_mode & O_READ))
+    return EACCES;
+  if (lock->l_type == F_WRLCK && !(open_mode & O_WRITE))
+    return EACCES;
+
+  switch (lock->l_whence)
+    {
+    case SEEK_SET:
+      start = lock->l_start;
+      break;
+
+    case SEEK_CUR:
+      start = cur_pointer + lock->l_start;
+      break;
+
+    case SEEK_END:
+      start = obj_size + lock->l_start;
+      break;
+
+    default:
+      return EINVAL;
+    }
+
+  if (start < 0)
+    return EINVAL;
+
+  len = lock->l_len;
+  if (len < 0)
+    return EINVAL;
+
+  if (cmd == F_SETLK64 && lock->l_type == F_UNLCK)
+    return unlock_region (start, len);
+
+retry:
+  e = find_conflict (start, len, lock->l_type);
+
+  if (cmd == F_GETLK64)
+    {
+      if (e)
+	{
+	  lock->l_type = e->type;
+	  lock->l_start = e->start;
+	  lock->l_whence = SEEK_SET;
+	  lock->l_len = e->len;
+	  lock->l_pid = -1;  /* XXX: This is so wrong it makes me puke.  */
+	  return 0;
+	}
+      else
+	{
+	  lock->l_type = F_UNLCK;
+	  return 0;
+	}
+    }
+  else
+    {
+      assert (cmd == F_SETLK64 || cmd == F_SETLKW64);
+
+      if (! e)
+	return merge_in (start, len, lock->l_type);
+      else
+        {
+	  if (cmd == F_SETLKW64)
+	    {
+	      e->waiting = 1;
+	      if (pthread_cond_wait (&e->wait, mutex))
+	        return EINTR;
+	      goto retry;
+	    }
+	  else
+	    return EAGAIN;
+	}
+    }
+}
Index: hurd-0.5.git20141210/libfshelp/rlock.h
===================================================================
--- /dev/null
+++ hurd-0.5.git20141210/libfshelp/rlock.h
@@ -0,0 +1,118 @@
+/*
+   Copyright (C) 2001, 2014 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef FSHELP_RLOCK_H
+#define FSHELP_RLOCK_H
+
+//#include <pthread.h>
+//#include <fcntl.h>
+
+#include <string.h>
+#//include "ports.h"
+
+struct rlock_linked_list
+{
+  struct rlock_list *next;
+  struct rlock_list **prevp;
+};
+
+/*
+libthreads/cthreads.h:
+typedef struct condition {
+        spin_lock_t lock;
+        struct cthread_queue queue;
+        const char *name; <-- differs
+        struct cond_imp *implications;
+} *condition_t;
+rlock.h:
+  struct condition wait;
+here replaced by
+  struct pthread_cond_t wait;
+/usr/include/pthread/pthreadtypes.h:typedef struct __pthread_cond pthread_cond_t;
+/usr/include/i386-gnu/bits/condition.h:struct __pthread_cond
+struct __pthread_cond
+{
+  __pthread_spinlock_t __lock;
+  struct __pthread *__queue;
+  struct __pthread_condattr *__attr; <-- differs
+  struct __pthread_condimpl *__impl;
+  void *__data; <-- differs
+};
+ */
+
+struct rlock_list
+{
+  loff_t start;
+  loff_t len;
+  int type;
+
+  struct rlock_linked_list node;
+  struct rlock_linked_list po;
+
+  pthread_cond_t wait;
+  int waiting;
+
+  void *po_id;
+};
+
+extern int pthread_cond_init (pthread_cond_t *__restrict cond,
+                              const pthread_condattr_t *__restrict attr);
+
+extern inline error_t
+rlock_list_init (struct rlock_peropen *po, struct rlock_list *l)
+{
+  memset (l, 0, sizeof (struct rlock_list));
+  pthread_cond_init (&l->wait, NULL);
+  l->po_id = po->locks;
+  return 0;
+}
+
+/* void list_list (X ={po,node}, struct rlock_list **head,
+		   struct rlock_list *node)
+
+   Insert a node in the given list, X, in sorted order.  */
+#define list_link(X, head, node)				\
+	do							\
+	  {							\
+	    struct rlock_list **e;				\
+	    for (e = head;					\
+		 *e && ((*e)->start < node->start);		\
+		 e = &(*e)->X.next)				\
+	      ;							\
+	    node->X.next = *e;					\
+	    if (node->X.next)					\
+	      node->X.next->X.prevp = &node->X.next;		\
+	    node->X.prevp = e;					\
+	    *e = node;						\
+	  }							\
+	while (0)
+
+/* void list_unlock (X = {po,node}, struct rlock_list *node)  */
+#define list_unlink(X, node)					\
+  	do							\
+	  {							\
+	    *node->X.prevp = node->X.next;			\
+	    if (node->X.next)					\
+	      node->X.next->X.prevp = node->X.prevp;		\
+	  }							\
+	while (0)
+
+#endif /* FSHELP_RLOCK_H */
Index: hurd-0.5.git20141210/libfshelp/extern-inline.c
===================================================================
--- /dev/null
+++ hurd-0.5.git20141210/libfshelp/extern-inline.c
@@ -0,0 +1,25 @@
+/*
+   Copyright (C) 2001, 2014 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define FSHELP_EXTERN_INLINE
+
+#include "fshelp.h"
+

Reply to: