Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 04 Dec 2000 16:11:39 -0500
From:      Dan Eischen <eischen@vigrid.com>
To:        current@freebsd.org
Subject:   Making {open,close,read,tell,seek}dir thread-safe.
Message-ID:  <3A2C088B.B9D23B7@vigrid.com>

next in thread | raw e-mail | index | archive | help
I started a cleanup of libc to make it thread-safe.  I would
like to get rid of the hash table in libc/gen/telldir.c and
maintain telldir position information on a per-DIR basis.  A
summary of the changes are as follows:

  o Add a LIST_HEAD to DIR to contain a queue of telldir
    positions.  Also add a location count (used as the magic
    for telldir) to DIR.  A future change may also add a
    mutex/lock.

  o Remove the hash table from telldir.c.  Recode to use
    queue macros.

  o Remove 'const' from 'telldir(const DIR *)'.

  o Remove 'register' variables as suggested in another
    recent thread.

Question: Is there a reason to use a hash table in each DIR
instead of a list (for performance reasons)?

Proposed diffs below.

-- 
Dan Eischen

Index: dirent.h
===================================================================
RCS file: /opt/FreeBSD/cvs/src/include/dirent.h,v
retrieving revision 1.7
diff -u -r1.7 dirent.h
--- dirent.h	1999/12/29 05:01:20	1.7
+++ dirent.h	2000/12/04 20:03:49
@@ -46,12 +46,15 @@
 #ifdef _POSIX_SOURCE
 typedef void *	DIR;
 #else
+#include <sys/queue.h>
 
 #define	d_ino		d_fileno	/* backward compatibility */
 
 /* definitions for library routines operating on directories. */
 #define	DIRBLKSIZ	1024
 
+struct ddloc;
+
 /* structure describing an open directory. */
 typedef struct _dirdesc {
 	int	dd_fd;		/* file descriptor associated with directory */
@@ -61,7 +64,9 @@
 	int	dd_len;		/* size of data buffer */
 	long	dd_seek;	/* magic cookie returned by getdirentries */
 	long	dd_rewind;	/* magic cookie for rewinding */
-	int	dd_flags;	/* flags for readdir */
+	int	dd_flags;	/* flags for readdir */\
+	long	dd_loccnt;	/* current key for dd_locq entry */
+	LIST_HEAD(, ddloc) dd_locq; /* telldir position recording */
 } DIR;
 
 #define	dirfd(dirp)	((dirp)->dd_fd)
@@ -89,7 +94,7 @@
 int closedir __P((DIR *));
 #ifndef _POSIX_SOURCE
 DIR *__opendir2 __P((const char *, int));
-long telldir __P((const DIR *));
+long telldir __P((DIR *));
 void seekdir __P((DIR *, long));
 int scandir __P((const char *, struct dirent ***,
     int (*)(struct dirent *), int (*)(const void *, const void *)));
Index: libc/gen/closedir.c
===================================================================
RCS file: /opt/FreeBSD/cvs/src/lib/libc/gen/closedir.c,v
retrieving revision 1.6
diff -u -r1.6 closedir.c
--- libc/gen/closedir.c	2000/01/27 23:06:14	1.6
+++ libc/gen/closedir.c	2000/12/04 20:03:30
@@ -58,7 +58,7 @@
 	dirp->dd_fd = -1;
 	dirp->dd_loc = 0;
 	free((void *)dirp->dd_buf);
-	free((void *)dirp);
 	_reclaim_telldir(dirp);
+	free((void *)dirp);
 	return(_close(fd));
 }
Index: libc/gen/opendir.c
===================================================================
RCS file: /opt/FreeBSD/cvs/src/lib/libc/gen/opendir.c,v
retrieving revision 1.10
diff -u -r1.10 opendir.c
--- libc/gen/opendir.c	2000/01/27 23:06:18	1.10
+++ libc/gen/opendir.c	2000/12/04 20:03:13
@@ -259,6 +259,8 @@
 	dirp->dd_loc = 0;
 	dirp->dd_fd = fd;
 	dirp->dd_flags = flags;
+	dirp->dd_loccnt = 0;
+	LIST_INIT(&dirp->dd_locq);
 
 	/*
 	 * Set up seek point for rewinddir.
Index: libc/gen/telldir.c
===================================================================
RCS file: /opt/FreeBSD/cvs/src/lib/libc/gen/telldir.c,v
retrieving revision 1.4
diff -u -r1.4 telldir.c
--- libc/gen/telldir.c	1995/05/30 05:40:26	1.4
+++ libc/gen/telldir.c	2000/12/04 20:18:22
@@ -54,39 +54,28 @@
  * associated with that return value.
  */
 struct ddloc {
-	struct	ddloc *loc_next;/* next structure in list */
+	LIST_ENTRY(ddloc) loc_lqe; /* list entry */
 	long	loc_index;	/* key associated with structure */
 	long	loc_seek;	/* magic cookie returned by getdirentries */
 	long	loc_loc;	/* offset of entry in buffer */
-	const DIR* loc_dirp;	/* directory which used this entry */
 };
 
-#define	NDIRHASH	32	/* Num of hash lists, must be a power of 2 */
-#define	LOCHASH(i)	((i)&(NDIRHASH-1))
-
-static long	dd_loccnt;	/* Index of entry for sequential readdir's */
-static struct	ddloc *dd_hash[NDIRHASH];   /* Hash list heads for ddlocs */
-
 /*
  * return a pointer into a directory
  */
 long
 telldir(dirp)
-	const DIR *dirp;
+	DIR *dirp;
 {
-	register int index;
-	register struct ddloc *lp;
+	struct ddloc *lp;
 
 	if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
 		return (-1);
-	index = dd_loccnt++;
-	lp->loc_index = index;
+	lp->loc_index = dirp->dd_loccnt++;
 	lp->loc_seek = dirp->dd_seek;
 	lp->loc_loc = dirp->dd_loc;
-	lp->loc_dirp = dirp;
-	lp->loc_next = dd_hash[LOCHASH(index)];
-	dd_hash[LOCHASH(index)] = lp;
-	return (index);
+	LIST_INSERT_HEAD(&dirp->dd_locq, lp, loc_lqe);
+	return (lp->loc_index);
 }
 
 /*
@@ -95,20 +84,15 @@
  */
 void
 _seekdir(dirp, loc)
-	register DIR *dirp;
+	DIR *dirp;
 	long loc;
 {
-	register struct ddloc *lp;
-	register struct ddloc **prevlp;
+	struct ddloc *lp;
 	struct dirent *dp;
 
-	prevlp = &dd_hash[LOCHASH(loc)];
-	lp = *prevlp;
-	while (lp != NULL) {
+	LIST_FOREACH(lp, &dirp->dd_locq, loc_lqe) {
 		if (lp->loc_index == loc)
 			break;
-		prevlp = &lp->loc_next;
-		lp = lp->loc_next;
 	}
 	if (lp == NULL)
 		return;
@@ -124,7 +108,7 @@
 	}
 found:
 #ifdef SINGLEUSE
-	*prevlp = lp->loc_next;
+	LIST_REMOVE(lp, loc_lqe);
 	free((caddr_t)lp);
 #endif
 }
@@ -134,24 +118,16 @@
  */
 void
 _reclaim_telldir(dirp)
-	register const DIR *dirp;
+	DIR *dirp;
 {
-	register struct ddloc *lp;
-	register struct ddloc **prevlp;
-	int i;
-
-	for (i = 0; i < NDIRHASH; i++) {
-		prevlp = &dd_hash[i];
-		lp = *prevlp;
-		while (lp != NULL) {
-			if (lp->loc_dirp == dirp) {
-				*prevlp = lp->loc_next;
-				free((caddr_t)lp);
-				lp = *prevlp;
-				continue;
-			}
-			prevlp = &lp->loc_next;
-			lp = lp->loc_next;
-		}
+	struct ddloc *lp;
+	struct ddloc *templp;
+
+	lp = LIST_FIRST(&dirp->dd_locq);
+	while (lp != NULL) {
+		templp = lp;
+		lp = LIST_NEXT(lp, loc_lqe);
+		free(templp);
 	}
+	LIST_INIT(&dirp->dd_locq);
 }


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3A2C088B.B9D23B7>