patch 0

关于文件锁支持的解决方案,大部分是由Neal Walfield在2001年完成的。这些补丁由Marcus Brinkmann发表,随后被Michael Banck于2002年修改了部分。现如今的修改部分主要是用libpthread替换之前的cthread

这些补丁实现的功能分为6部分:

  1. hurd_new_RPC.patch:添加了新的RPC,file_record_lock
  1. libdiskfs_file_record_lock.patch:实现diskfs_S_file_record_lock并且对diskfs_S_*进行相应的修改,初始化并释放lock_status
  2. libfshelp_rlock.patch:实现fshelp_rlock_*函数
  3. libfshelp-tests_rlock.patch:对libfshelp-tests_rlock.patch进行测试
  4. libnetfs_file_record_lock.patch:实现netfs_S_file_record_lock
  5. libtrivfs_file_record_lock.patch:实现trivfs_S_file_record_lock

不过还遗留了2部分bug有待解决:

  1. 结构体flock中的l_pid没有被声明。可以通过在glic中共享内存或者在1022号任务中声明;
  1. 在子进程锁未被设定的情况下,系统调用fork无法生成子进程。根据系统调用fcntl的用法,在通过fork创建子进程时,记录锁将不被继承。fork的功能在libfshelp-tests/fork.c中被测试。建议的解决方案在1022号任务中提到过。这个问题可能是在当前的补丁下tdb中的

    tdbtorture不能正常运行的关键原因。

patch 1


2014-08-21

  • fs.defs中添加了描述
  • hurd_types.defs:由于l_start和l_len都是64位的,所以修改结构体flock_t的长度为7个int
  • hurd_types.h:将flock64描述为flock_t

2001-04-10

  • fs.defs:新的RPCfile_record_lock
  • hurd_types.defsImport <fcntl.h>

综上,共有3个文件被修改,如下:

hurd/hurd_types.defs

/*
type flock_t = struct[5] of int;
这行要注释
然后添加下一行
*/
type flock_t = struct[7] of int;
/*
在最后一行添加一个import语句
*/
import <fcntl.h>;

hurd/fs.defs

/*
添加以下部分
*/ /* Do fcntl type locking on FILE. CMD is from the set
F_GETLK64, F_SETLK64, F_SETLKW64. FLOCK64 is passed
by the user and is as defined by <fcntl.h>. */ routine file_record_lock (
file: file_t;
RPT
cmd: int;
inout flock64: flock_t);

hurd/hurd_types.h

/*
typedef struct flock flock_t;
这行要注释
然后添加下一行
*/
typedef struct flock64 flock_t;

patch 2


2014-08-21

  • 定义宏变量CPP_FLAGS直到glibc被更新
  • file-lock-stat.c:将cthreds更换为Libpthreads
  • file-lock.c:同上
  • file-record-lock:同上

2001-04-11

  • Makefile (FSSRCS):添加file-record-lock.c
  • diskfs.h
    • struct peropen:将lock_status的类型从int更换为rlock_peropen
    • sturct node:将userbox的类型从lock_box更换为rlock_box
  • dir-lookup.c (diskfs_S_di_lookup):由于fshelp_acquire_lock被废弃,使用fshelp_tweak_rlock
  • file-lock-stat.c (diskfs_S_file_lock_stat):记录锁部分重写
  • file-record-lock.c:创建的新文件,实现了diskfs_S_file_record_lock
  • node-make.c (diskfs_make_node):利用fshelp_rlock_init初始化userbox
  • peropen-make.c (diskfs_make_peropen):利用fshelp_rlock_po_init初始化lock_status
  • peropen-rele.c (diskfs_release_peropen):利用fshelp_rlock_drop_peropen来释放lock_status

综上,共有9个文件被修改,如下:

libdiskfs/Makefile

 	file-lock.c file-set-size.c file-set-trans.c file-statfs.c \
- file-sync.c file-syncfs.c file-utimes.c file-reparent.c
+ file-sync.c file-syncfs.c file-utimes.c file-record-lock.c \
+ file-reparent.c
IOSRCS= io-async-icky.c io-async.c io-duplicate.c io-get-conch.c io-revoke.c \
io-map-cntl.c io-map.c io-modes-get.c io-modes-off.c \
io-modes-on.c io-modes-set.c io-owner-mod.c io-owner-get.c \
ifsock-MIGSFLAGS = -imacros $(srcdir)/fs
exec_startup-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
MIGCOMSFLAGS = -prefix diskfs_ +# 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
+dir-lookup-CPPFLAGS += $(EXTRA_CPP_FLAGS)
+file-lock-CPPFLAGS += $(EXTRA_CPP_FLAGS)

libdiskfs/diskfs.h

 struct peropen
{
- off_t filepointer;
- int lock_status;
+ loff_t filepointer;
+ struct rlock_peropen lock_status;
refcount_t refcnt;
int openstat; struct transbox transbox; - struct lock_box userlock;
+ struct rlock_box userlock; struct conch conch;

libdiskfs/dir-lookup.c

if (! error)
{
newpo = 0;
+ struct flock64 lock =
+ {
+ l_start: 0,
+ l_len: 0,
+ l_whence: SEEK_SET
+ };
+
if (flags & O_EXLOCK)
- error = fshelp_acquire_lock (&np->userlock, &newpi->po->lock_status,
- &np->lock, LOCK_EX);
+ {
+ lock.l_type = F_WRLCK;
+ error = fshelp_rlock_tweak (&np->userlock, &np->lock,
+ &newpi->po->lock_status, flags, 0, 0,
+ F_SETLK64, &lock);
+ }
else if (flags & O_SHLOCK)
- error = fshelp_acquire_lock (&np->userlock, &newpi->po->lock_status,
- &np->lock, LOCK_SH);
+ {
+ lock.l_type = F_RDLCK;
+ error = fshelp_rlock_tweak (&np->userlock, &np->lock,
+ &newpi->po->lock_status, flags, 0, 0,
+ F_SETLK64, &lock);
+ }
}

libdiskfs/file-lock-stat.c

-/*
- Copyright (C) 1994, 1995 Free Software Foundation
+/* Copyright (C) 2001, 2014 Free Software Foundation, Inc. -This file is part of the GNU Hurd.
+ Written by Neal H Walfield <neal@cs.uml.edu> -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. */
-
-/* Written by Michael I. Bushnell. */
+ 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 "priv.h"
#include "fs_S.h" +#include <fcntl.h>
+#include <sys/file.h>
+
kern_return_t
diskfs_S_file_lock_stat (struct protid *cred,
int *mystatus,
int *otherstatus)
{
+ struct node *node;
+
if (!cred)
return EOPNOTSUPP;
-
- pthread_mutex_lock (&cred->po->np->lock);
- *mystatus = cred->po->lock_status;
- *otherstatus = cred->po->np->userlock.type;
- pthread_mutex_unlock (&cred->po->np->lock);
+
+ node = cred->po->np;
+
+ pthread_mutex_lock (&node->lock);
+ *mystatus = fshelp_rlock_peropen_status (&cred->po->lock_status);
+ *otherstatus = fshelp_rlock_node_status (&node->userlock);
+ pthread_mutex_unlock (&node->lock);
+
return 0;
}

libdiskfs/file-lock.c

-/*
- Copyright (C) 1993, 1994 Free Software Foundation
+/* Copyright (C) 2001, 2014 Free Software Foundation, Inc. -This file is part of the GNU Hurd.
+ Written by Neal H Walfield <neal@cs.uml.edu> -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. */
-
-/* Written by Michael I. Bushnell. */
+ 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 "priv.h"
#include "fs_S.h" +#include <fcntl.h>
+#include <sys/file.h>
+
kern_return_t
diskfs_S_file_lock (struct protid *cred, int flags)
{
error_t err;
- if (!cred)
+ struct flock64 lock;
+ struct node *node;
+
+ if (! cred)
return EOPNOTSUPP;
- pthread_mutex_lock (&cred->po->np->lock);
- err = fshelp_acquire_lock (&cred->po->np->userlock, &cred->po->lock_status,
- &cred->po->np->lock, flags);
- pthread_mutex_unlock (&cred->po->np->lock);
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ if (flags & LOCK_UN)
+ lock.l_type = F_UNLCK;
+ else if (flags & LOCK_SH)
+ lock.l_type = F_RDLCK;
+ else if (flags & LOCK_EX)
+ lock.l_type = F_WRLCK;
+ else
+ return EINVAL;
+
+ node = cred->po->np;
+ pthread_mutex_lock (&node->lock);
+ err = fshelp_rlock_tweak (&node->userlock, &node->lock,
+ &cred->po->lock_status, cred->po->openstat,
+ 0, 0, flags & LOCK_NB ? F_SETLK64 : F_SETLKW64,
+ &lock);
+ pthread_mutex_unlock (&node->lock);
return err;
}

libdiskfs/file-record-lock.c

+/* 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 "priv.h"
+#include "diskfs.h"
+
+#include <errno.h>
+#include <hurd/fshelp.h>
+
+error_t
+diskfs_S_file_record_lock (struct protid *cred, int cmd, struct flock64 *lock)
+{
+ struct node *node;
+ error_t err;
+
+ if (! cred)
+ return EOPNOTSUPP;
+
+ node = cred->po->np;
+ pthread_mutex_lock (&node->lock);
+ err = fshelp_rlock_tweak (&node->userlock, &node->lock,
+ &cred->po->lock_status, cred->po->openstat,
+ node->dn_stat.st_size, cred->po->filepointer,
+ cmd, lock);
+ pthread_mutex_unlock (&node->lock);
+ return err;
+}

libdiskfs/node-make.c

    fshelp_transbox_init (&np->transbox, &np->lock, np);
iohelp_initialize_conch (&np->conch, &np->lock);
- fshelp_lock_init (&np->userlock);
+ fshelp_rlock_init (&np->userlock); return np;
}

libdiskfs/peropen-make.c

 #include "priv.h"
+#include <errno.h>
+#include <stdlib.h>
#include <sys/file.h>
+#include <hurd/fshelp.h> /* Create and return a new peropen structure on node NP with open
flags FLAGS. */
error_t
diskfs_make_peropen (struct node *np, int flags, struct peropen *context,
struct peropen **ppo)
{
+ error_t err;
struct peropen *po = *ppo = malloc (sizeof (struct peropen)); if (! po)
return ENOMEM; + err = fshelp_rlock_po_init (&po->lock_status);
+ if (err)
+ return err;
+
po->filepointer = 0;
- po->lock_status = LOCK_UN;
refcount_init (&po->refcnt, 1);
po->openstat = flags;
po->np = np;

libdiskfs/peropen-rele.c

diskfs_release_peropen (struct peropen *

   if (po->shadow_root_parent)
mach_port_deallocate (mach_task_self (), po->shadow_root_parent);
-
- if (po->lock_status != LOCK_UN)
- {
- pthread_mutex_lock (&po->np->lock);
- fshelp_acquire_lock (&po->np->userlock, &po->lock_status,
- &po->np->lock, LOCK_UN);
- diskfs_nput (po->np);
- }
- else
- diskfs_nrele (po->np);
+ fshelp_rlock_drop_peropen (&po->lock_status);
+ diskfs_nput (po->np); free (po->path);
free (po);

patch 3


2014-08-21

  • Makefile:和pthread关联
  • 定义宏变量CPP_FLAGS直到glibc被更新
  • rlock-drop-peropen.c:从cthread端口转换到libpthread
  • rlock-drop-peropen.c:同上
  • rlock-tweak.c:同上
  • fshelp.h:同上
  • rlock.h:同上
  • FIXME:移除FIXMEs

2001-04-12

  • fshelp.h

    • struct rlock_box:定义的新结构体
    • struct rlock_peropen:同上
    • fshelp_rlock_init:新函数
    • fshelp_rlock_po_init:同上
    • fshelp_rlock_drop_peropen:同上
    • fshelp_rlock_tweak:同上
    • fshelp_rlock_peropen_status:同上
    • fshelp_rlock_node_status:同上
  • rlock-drop-peropen.c:新文件,实现fshelp_rlock_drop_peropen
  • rlock-status.c:新文件,实现fshelp_rlock_peropen_status和fshelp_rlock_node_status
  • rlock-tweak.c:新文件,实现fshelp_rlock_tweak函数
  • rlock.h:新文件
  • extern-inline.c:新文件
  • Makefile
    • LCLHDRS:添加rlock.h
    • SRCS:添加extern-inline.c,rlock-drop-peropen.c,rlock-tweak.c和rlock-status.c

综上,共有7个文件被修改,如下:

libfshelp/Makefile

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)
+

libfshelp/fshelp.h

 #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);

libfshelp/rlock-drop-peropen.c

+/*
+ 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;
+}

libfshelp/rlock-status.c

+/* 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;
+}

libfshelp/rlock-tweak.c

+/*
+ 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;
+ }
+ }
+}

libfshelp/rlock.h

+/*
+ 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 */

libfshelp/extern-inline.c

+/*
+ 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"
+

GNU/Hurd笔记整理的更多相关文章

  1. [转帖](整理)GNU Hurd项目详解

    (整理)GNU Hurd项目详解 http://www.ha97.com/3188.html 发表于: 开源世界 | 作者: 博客教主 标签: GNU,Hurd,详解,项目 Hurd原本是要成为GNU ...

  2. python学习笔记整理——字典

    python学习笔记整理 数据结构--字典 无序的 {键:值} 对集合 用于查询的方法 len(d) Return the number of items in the dictionary d. 返 ...

  3. 从0开始学Swift笔记整理(五)

    这是跟在上一篇博文后续内容: --Core Foundation框架 Core Foundation框架是苹果公司提供一套概念来源于Foundation框架,编程接口面向C语言风格的API.虽然在Sw ...

  4. Deep Learning(深度学习)学习笔记整理系列之(五)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

  5. 学习ReactNative笔记整理一___JavaScript基础

    学习ReactNative笔记整理一___JavaScript基础 ★★★笔记时间- 2017-1-9 ★★★ 前言: 现在跨平台是一个趋势,这样可以减少开发和维护的成本.第一次看是看的ReactNa ...

  6. Deep Learning(深度学习)学习笔记整理系列之(八)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

  7. Deep Learning(深度学习)学习笔记整理系列之(七)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

  8. Deep Learning(深度学习)学习笔记整理系列之(六)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

  9. Deep Learning(深度学习)学习笔记整理系列之(四)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

随机推荐

  1. 阿里云ECS+CentOS 7.0+Docker+Redmine环境搭建

    前言 搭建Redmine环境可以选择使用分别安装Ruby+Rails+Redmine+MySQL的方式, 但是过程中需要解决各种扰人的依赖问题.Docker为我们提供的Plan B,方便,快捷. 安装 ...

  2. [Luogu2664]树上游戏

    题面戳我 sol 点分.我们面临的最主要一个问题,就是如何在\(O(n)\)的时间内算出所有LCA为根的点对的贡献,还要分别累加到它们自己的答案中去. \(num_i\):每一种颜色的数量.你可以认为 ...

  3. [.NET]使用十年股价对比各种序列化技术

    1. 前言 上一家公司有搞股票,当时很任性地直接从服务器读取一个股票10年份的股价(还有各种指标)在客户端的图表上显示,而且因为是桌面客户端,传输的数据也是简单粗暴地使用Soap序列化.获取报价的接口 ...

  4. 厉害了!阿里安全图灵实验室在ICDAR2017 MLT竞赛刷新世界最好成绩

    近日,阿里安全图灵实验室(Alibaba Turing Lab)的ATL Cangjie OCR算法在ICDAR2017的MLT(Competition on Multi-lingual scene ...

  5. Redis 基础(一)

    Remote Dictionary Server(Redis)是一个由Salvatore Sanfilippo写的key-value存储系统.Redis是一个开源的使用ANSI C语言编写.遵守BSD ...

  6. 【Unity3D与23种设计模式】外观模式(Facade)

    GoF中定义: "为子系统定义一组统一的接口,这个高级的接口会让子系统更容易被使用" 其实这个模式虽然很少听过 但我们在敲代码的时候却是经常使用 比如: 在游戏初始化时 要初始化很 ...

  7. R语言学习 第八篇:常用的数据处理函数

    Basic包是R语言预装的开发包,包含了常用的数据处理函数,可以对数据进行简单地清理和转换,也可以在使用其他转换函数之前,对数据进行预处理,必须熟练掌握常用的数据处理函数,本文分享在数据处理时,经常使 ...

  8. Cesium 一个导致浏览器内存一直增长的方法

    为了实时更改模型的位置,给模型附上ID,后面判断如果传来的数据中没有已经创建的模型,删掉该模型时用到方法:viewer.entities.removeById(modelId);和viewer.ent ...

  9. Django基本命令

    下载Django pip3 install django #默认下载最新版 pip3 install django==1.11.1 #手动选择版本 创建Django项目 格式:django-admin ...

  10. js中==和===区别

    简单来说: == 代表相同, ===代表严格相同, 为啥这么说呢, 这么理解: 当进行双等号比较时候: 先检查两个操作数数据类型,如果相同, 则进行===比较, 如果不同, 则愿意为你进行一次类型转换 ...