GNU/Hurd笔记整理
patch 0
关于文件锁支持的解决方案,大部分是由Neal Walfield在2001年完成的。这些补丁由Marcus Brinkmann发表,随后被Michael Banck于2002年修改了部分。现如今的修改部分主要是用libpthread
替换之前的cthread
。
这些补丁实现的功能分为6部分:
- hurd_new_RPC.patch:添加了新的RPC,
file_record_lock
- libdiskfs_file_record_lock.patch:实现
diskfs_S_file_record_lock
并且对diskfs_S_*
进行相应的修改,初始化并释放lock_status
- libfshelp_rlock.patch:实现
fshelp_rlock_*
函数 - libfshelp-tests_rlock.patch:对
libfshelp-tests_rlock.patch
进行测试 - libnetfs_file_record_lock.patch:实现
netfs_S_file_record_lock
- libtrivfs_file_record_lock.patch:实现
trivfs_S_file_record_lock
不过还遗留了2部分bug有待解决:
- 结构体flock中的l_pid没有被声明。可以通过在glic中共享内存或者在1022号任务中声明;
- 在子进程锁未被设定的情况下,系统调用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个inthurd_types.h
:将flock64描述为flock_t
2001-04-10
fs.defs
:新的RPCfile_record_lock
hurd_types.defs
:Import <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更换为Libpthreadsfile-lock.c
:同上file-record-lock
:同上
2001-04-11
Makefile
(FSSRCS):添加file-record-lock.cdiskfs.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_rlockfile-lock-stat.c
(diskfs_S_file_lock_stat):记录锁部分重写file-record-lock.c
:创建的新文件,实现了diskfs_S_file_record_locknode-make.c
(diskfs_make_node):利用fshelp_rlock_init初始化userboxperopen-make.c
(diskfs_make_peropen):利用fshelp_rlock_po_init初始化lock_statusperopen-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端口转换到libpthreadrlock-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_peropenrlock-status.c
:新文件,实现fshelp_rlock_peropen_status和fshelp_rlock_node_statusrlock-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笔记整理的更多相关文章
- [转帖](整理)GNU Hurd项目详解
(整理)GNU Hurd项目详解 http://www.ha97.com/3188.html 发表于: 开源世界 | 作者: 博客教主 标签: GNU,Hurd,详解,项目 Hurd原本是要成为GNU ...
- python学习笔记整理——字典
python学习笔记整理 数据结构--字典 无序的 {键:值} 对集合 用于查询的方法 len(d) Return the number of items in the dictionary d. 返 ...
- 从0开始学Swift笔记整理(五)
这是跟在上一篇博文后续内容: --Core Foundation框架 Core Foundation框架是苹果公司提供一套概念来源于Foundation框架,编程接口面向C语言风格的API.虽然在Sw ...
- Deep Learning(深度学习)学习笔记整理系列之(五)
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
- 学习ReactNative笔记整理一___JavaScript基础
学习ReactNative笔记整理一___JavaScript基础 ★★★笔记时间- 2017-1-9 ★★★ 前言: 现在跨平台是一个趋势,这样可以减少开发和维护的成本.第一次看是看的ReactNa ...
- Deep Learning(深度学习)学习笔记整理系列之(八)
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
- Deep Learning(深度学习)学习笔记整理系列之(七)
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
- Deep Learning(深度学习)学习笔记整理系列之(六)
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
- Deep Learning(深度学习)学习笔记整理系列之(四)
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
随机推荐
- JavaScript设计模式(4)-桥接模式
桥接模式 在设计一个 Js API 时,可用来弱化它与使用它的类和对象之间的耦合 1. 事件监听器的回调函数 function getBeerById(id, callback) { asyncReq ...
- Educational Codeforces Round 37
Educational Codeforces Round 37 这场有点炸,题目比较水,但只做了3题QAQ.还是实力不够啊! 写下题解算了--(写的比较粗糙,细节或者bug可以私聊2333) A. W ...
- 我对asp.net运行机制的理解
有一本书叫<asp.net 本质论>,作者名叫冠军.我看了几次,都没有坚持看下来.这次连续看完了前三章,然后参考网上的资料,总结下我对.net运行机制的理解. 先上两张图: 看着这两张图, ...
- jsp常见jstl语法(二)
<c:choose>标签与Javascript switch语句的功能一样,用于在众多选项中做出选择. 语法格式 <c:choose> <c:when test=&quo ...
- Prototype模式
浅克隆:对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.深克隆:对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制. /** * Created ...
- memcache搭建
memcache搭建步骤: 个人原创,允许转载,请注明出处,作者,否则追究法律责任. 0.1 memcache的服务端0.2 mysql的服务端0.3 memcache 的客户端:lamp架构 1,环 ...
- java 连接 elasticsearch 报错java.lang.NoClassDefFoundError: org/apache/http/auth/Credentials 解决
您的问题是您在应用程序类路径中缺少必需的JAR(这导致ClassNotFound异常).如果您下载了包含IP Camera驱动程序(webcam-capture-driver-ipcam-0.3.10 ...
- C语言第八次博客作业--字符数组
一.PTA实验作业 题目1:查验身份证 1. 本题PTA提交列表 2. 设计思路 定义i,flag=1,z,m[11],a[19] 输入次数n for i=1 to n+1 gets(a) 加权求和在 ...
- 简单使用git和github来管理代码----配置与使用
在以前没听说过github之前,自己写的代码很容易丢或者遗失,等到用时才知码到用时方恨丢,现在用了github,真的是替自己生省不少的事,闲话不多说,上教程. 1 在github上注册账号 https ...
- shell 文本操作命令
vi 编辑器中有三种状态模式 [vi 文件名(或路径+文件名)] 1.命令模式 2.输入模式 3.末行模式 三种模式间的相互转换 vi编辑器的启动与退出 直接进入编辑环境 $ vi 进入编辑环境并打 ...