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. 【linux之链接,函数,随机数】

    一.链接 硬链接(hard link):同一个文件使用了多个别名.新建文件是已经存在的一个别名,,当原文件删除时,新建的文件仍然可以使用.硬链接和原来的文件没有什么区别,而且共享一个inode号.通过 ...

  2. 环境变量配置为jdk8,显示的java版本为jdk7

    经查找发现是jdk版本的问题,我系统环境变量配置的是jdk7,可是这个war包需要在jdk8的环境下运行.于是我就手动将环境变量的jdk7换成jdk8,结果发现依然还是会出现以上问题.于是我打开cmd ...

  3. 异步解决方案promise及源码实现

    js语言的特性,造就了特别的异步处理方式,我记得以前用的最多的就是回调函数,那个时候写jquery的ajax时候,特别喜欢写这种代码: $.ajax({ method:'get', url:" ...

  4. Postman使用小技巧

    Postman使用小技巧 2017-09-13 目录: 1 自动生成流水号2 保存响应结果 1 自动生成流水号 返回 为了让接口具有幂等性,在设计时,往往有一个字段是唯一的(比如流水号,交易编号等), ...

  5. 使用Dreamweaver正则表达式替换href中的内容

    在Dreamweaver中使用正则表达式替换href中的内容,就像下面这些href中的内容复杂多样的情况下,href="/html/u.html",href="/tuho ...

  6. Node与apidoc的邂逅——NodeJS Restful 的API文档生成

    作为后台根据需求文档开发完成接口后,交付给前台(angular vue等)做开发,不可能让前台每个接口调用都去查看你的后台代码一点点查找.前台开发若不懂你的代码呢?让他一个接口一个接口去问你怎么调用, ...

  7. Php显示中文时乱码

    <?php echo "你们好哈"; ?> 显示乱码,解决办法 <?php header("content-type:text/html; charse ...

  8. WordPress让文本小工具支持简码

    WordPress 的 “文本” 小工具是非常常用的,可以添加一些自定义的文本或者 Html 代码.但很多时候,我们需要在文本小工具里使用简码来添加一些更加丰富的内容. 默认情况下,文本小工具是不支持 ...

  9. ajax 图片上传

    html 部分: <form action="" id='myForm' enctype="multipart/form-data"> <di ...

  10. 邮箱&&密码验证-原理

    原理版: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...