summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog64
-rw-r--r--stdlib/mbstowcs.c2
-rw-r--r--stdlib/wcstombs.c2
-rw-r--r--sysdeps/gnu/errlist.c147
-rw-r--r--sysdeps/mach/hurd/closedir.c20
-rw-r--r--sysdeps/mach/hurd/dirstream.h5
-rw-r--r--sysdeps/mach/hurd/opendir.c6
-rw-r--r--sysdeps/mach/hurd/readdir.c19
-rw-r--r--sysdeps/mach/hurd/seekdir.c4
-rw-r--r--sysdeps/mach/libc-lock.h60
-rw-r--r--sysdeps/stub/libc-lock.h10
-rw-r--r--sysdeps/unix/bsd/telldir.c30
-rw-r--r--sysdeps/unix/closedir.c6
-rw-r--r--sysdeps/unix/dirstream.h4
-rw-r--r--sysdeps/unix/opendir.c3
-rw-r--r--sysdeps/unix/readdir.c9
-rw-r--r--sysdeps/unix/rewinddir.c2
-rw-r--r--sysdeps/unix/seekdir.c2
18 files changed, 371 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index e21f365e1f..a619747dbf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,67 @@
+Tue Jul  9 09:37:55 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
+
+	* sysdeps/mach/libc-lock.h: New file.
+	* sysdeps/unix/readdir.c: Do locking.
+	* sysdeps/unix/seekdir.c: Likewise.
+	* sysdeps/unix/rewinddir.c:  Likewise.
+	* sysdeps/unix/closedir.c: Likewise.
+	* sysdeps/unix/bsd/telldir.c: Likewise.
+	* sysdeps/mach/hurd/seekdir.c: Likewise.
+	* sysdeps/mach/hurd/readdir.c: Likewise.
+	* sysdeps/mach/hurd/closedir.c: Likewise.
+	* sysdeps/mach/hurd/opendir.c: Initialize the lock.
+	* sysdeps/unix/opendir.c: Likewise.
+	* sysdeps/mach/hurd/dirstream.h: Include <libc-lock.h>.
+	(struct __dirstream): Add lock member using __libc_lock_define.
+	* sysdeps/unix/dirstream.h: Likewise.
+
+	* sysdeps/stub/libc-lock.h (__libc_lock_fini): New macro.
+
+	* stdlib/mbstowcs.c: Pass address of pointer to mbsrtowcs.
+
+	* stdlib/wcstombs.c: Use wcsrtombs instead of mbsrtowcs.
+
+Thu Jul  4 01:34:04 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* locale/programs/stringtrans.c: Fix typo in copyright.
+
+	* stdio-common/printf-prs.c: Add casts to prevent
+        signed<->unsigned warnings.
+
+	* stdio-common/printf-parse.h: Initialize state variable before
+	calling mbrlen.
+	* stdio-common/printf-prs.c: Don't initialize state variable here.
+	* stdio-common/vfprintf.c: Don't initialize state variable.
+	(vfprintf): While determining length of multibyte string don't
+	try to be clever in determining characters to use for first
+	call.
+
+	Add real implementation of multibyte<->wide char conversion
+	functions.  The functions always convert between the fixed wide
+	char format (ISO 10646 in UCS4) and the UTF8 representation of
+	this character set.  Conversion between the currently used
+	8bit character set and ISO 10646 will not take place.  This is
+	what iconv() is for.
+	* wcsmbs/wchar.h (mbstate_t): Define as structure to replace
+	dummy definition.
+	Add optimized version of `mbrlen' function.
+	* wcsmbs/btowc.c (btowc): Restrict range of legal characters
+	to 0...0x7f.
+	* wcsmbs/wctob.c (wctob): Restrict range of legal characters
+	to 0..0x7f.
+	* wcsmbs/mbrlen.c: Make mbrlen a weak alias of __mbrlen.
+	This is needed in the wchar.h header.
+	* wcsmbs/mbrtowc.c: Replace dummy implementation.  Convert UTF8
+	encoded character to UCS4.
+	* wcsmbs/mbsinit.c: Replace dummy implementation.  Test COUNT
+	element of `mbstate_t' for initial state.
+	* wcsmbs/mbsrtowcs.c: Replace dummy implementation.  Convert UTF8
+	encoded string to UCS4 string.
+	* wcsmbs/wcrtomb.c: Replace dummy implementation.  Convert UCS4
+	character to UTF8 encoded form.
+	* wcsmbs/wcsrtombs.c: Replace dummy implementation.  Convert UCS4
+	encoded string to UTF8 encoded form.
+
 Tue Jul  9 06:19:29 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
 
 	* sysdeps/unix/sysv/linux/configure.in: Use version number in cache
diff --git a/stdlib/mbstowcs.c b/stdlib/mbstowcs.c
index 8eda3ba41d..da3ae6b19d 100644
--- a/stdlib/mbstowcs.c
+++ b/stdlib/mbstowcs.c
@@ -36,7 +36,7 @@ mbstowcs (wchar_t *pwcs, const char *s, size_t n)
   mbstate_t save_shift = __no_r_state;
   size_t written;
 
-  written = mbsrtowcs (pwcs, s, n, &__no_r_state);
+  written = mbsrtowcs (pwcs, &s, n, &__no_r_state);
 
   /* Restore the old shift state.  */
   __no_r_state = save_shift;
diff --git a/stdlib/wcstombs.c b/stdlib/wcstombs.c
index 6518308181..73f015bf7e 100644
--- a/stdlib/wcstombs.c
+++ b/stdlib/wcstombs.c
@@ -36,7 +36,7 @@ wcstombs (char *s, const wchar_t *pwcs, size_t n)
   mbstate_t save_shift = __no_r_state;
   size_t written;
 
-  written = mbsrtowcs (pwcs, s, n, &__no_r_state);
+  written = wcsrtombs (s, &pwcs, n, &__no_r_state);
 
   /* Restore the old shift state.  */
   __no_r_state = save_shift;
diff --git a/sysdeps/gnu/errlist.c b/sysdeps/gnu/errlist.c
index dd2593bdc7..fa56553712 100644
--- a/sysdeps/gnu/errlist.c
+++ b/sysdeps/gnu/errlist.c
@@ -110,6 +110,9 @@ const char *_sys_errlist[] =
 #ifdef EAGAIN
     [EAGAIN] = N_("Resource temporarily unavailable"),
 #endif
+#if defined (EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+    [EWOULDBLOCK] = N_("Operation would block"),
+#endif
 #ifdef EINPROGRESS
     [EINPROGRESS] = N_("Operation now in progress"),
 #endif
@@ -269,6 +272,150 @@ const char *_sys_errlist[] =
 #ifdef EGRATUITOUS
     [EGRATUITOUS] = N_("Gratuitous error"),
 #endif
+#ifdef ERESTART
+    [ERESTART] = N_("Interrupted system call should be restarted"),
+#endif
+#ifdef ENOMSG
+    [ENOMSG] = N_("No message of desired type"),
+#endif
+#ifdef EIDRM
+    [EIDRM] = N_("Identifier removed"),
+#endif
+#ifdef ECHRNG
+    [ECHRNG] = N_("Channel number out of range"),
+#endif
+#ifdef EL2NSYNC
+    [EL2NSYNC] = N_("Level 2 not synchronized"),
+#endif
+#ifdef EL3HLT
+    [EL3HLT] = N_("Level 3 halted"),
+#endif
+#ifdef EL3RST
+    [EL3RST] = N_("Level 3 reset"),
+#endif
+#ifdef ELNRNG
+    [ELNRNG] = N_("Link number out of range"),
+#endif
+#ifdef EUNATCH
+    [EUNATCH] = N_("Protocol driver not attached"),
+#endif
+#ifdef ENOCSI
+    [ENOCSI] = N_("No CSI structure available"),
+#endif
+#ifdef EL2HLT
+    [EL2HLT] = N_("Level 2 halted"),
+#endif
+#ifdef EBADE
+    [EBADE] = N_("Invalid exchange"),
+#endif
+#ifdef EBADR
+    [EBADR] = N_("Invalid request descriptor"),
+#endif
+#ifdef EXFULL
+    [EXFULL] = N_("Exchange full"),
+#endif
+#ifdef ENOANO
+    [ENOANO] = N_("No anode"),
+#endif
+#ifdef EBADRQC
+    [EBADRQC] = N_("Invalid request code"),
+#endif
+#ifdef EBADSLT
+    [EBADSLT] = N_("Invalid slot"),
+#endif
+#if defined (EDEADLOCK) && EDEADLOCK != EDEADLK
+    [EDEADLOCK] = N_("File locking deadlock error"),
+#endif
+#ifdef EBFONT
+    [EBFONT] = N_("Bad font file format"),
+#endif
+#ifdef ENOSTR
+    [ENOSTR] = N_("Device not a stream"),
+#endif
+#ifdef ENODATA
+    [ENODATA] = N_("No data available"),
+#endif
+#ifdef ETIME
+    [ETIME] = N_("Timer expired"),
+#endif
+#ifdef ENOSR
+    [ENOSR] = N_("Out of streams resources"),
+#endif
+#ifdef ENONET
+    [ENONET] = N_("Machine is not on the network"),
+#endif
+#ifdef ENOPKG
+    [ENOPKG] = N_("Package not installed"),
+#endif
+#ifdef ENOLINK
+    [ENOLINK] = N_("Link has been severed"),
+#endif
+#ifdef EADV
+    [EADV] = N_("Advertise error"),
+#endif
+#ifdef ESRMNT
+    [ESRMNT] = N_("Srmount error"),
+#endif
+#ifdef ECOMM
+    [ECOMM] = N_("Communication error on send"),
+#endif
+#ifdef EPROTO
+    [EPROTO] = N_("Protocol error"),
+#endif
+#ifdef EMULTIHOP
+    [EMULTIHOP] = N_("Multihop attempted"),
+#endif
+#ifdef EDOTDOT
+    [EDOTDOT] = N_("RFS specific error"),
+#endif
+#ifdef EBADMSG
+    [EBADMSG] = N_("Not a data message"),
+#endif
+#ifdef EOVERFLOW
+    [EOVERFLOW] = N_("Value too large for defined data type"),
+#endif
+#ifdef ENOTUNIQ
+    [ENOTUNIQ] = N_("Name not unique on network"),
+#endif
+#ifdef EBADFD
+    [EBADFD] = N_("File descriptor in bad state"),
+#endif
+#ifdef EREMCHG
+    [EREMCHG] = N_("Remote address changed"),
+#endif
+#ifdef ELIBACC
+    [ELIBACC] = N_("Can not access a needed shared library"),
+#endif
+#ifdef ELIBBAD
+    [ELIBBAD] = N_("Accessing a corrupted shared library"),
+#endif
+#ifdef ELIBSCN
+    [ELIBSCN] = N_(".lib section in a.out corrupted"),
+#endif
+#ifdef ELIBMAX
+    [ELIBMAX] = N_("Attempting to link in too many shared libraries"),
+#endif
+#ifdef ELIBEXEC
+    [ELIBEXEC] = N_("Cannot exec a shared library directly"),
+#endif
+#ifdef ESTRPIPE
+    [ESTRPIPE] = N_("Streams pipe error"),
+#endif
+#ifdef EUCLEAN
+    [EUCLEAN] = N_("Structure needs cleaning"),
+#endif
+#ifdef ENOTNAM
+    [ENOTNAM] = N_("Not a XENIX named type file"),
+#endif
+#ifdef ENAVAIL
+    [ENAVAIL] = N_("No XENIX semaphores available"),
+#endif
+#ifdef EISNAM
+    [EISNAM] = N_("Is a named type file"),
+#endif
+#ifdef EREMOTEIO
+    [EREMOTEIO] = N_("Remote I/O error"),
+#endif
   };
 
 const int _sys_nerr = sizeof _sys_errlist / sizeof _sys_errlist[0];
diff --git a/sysdeps/mach/hurd/closedir.c b/sysdeps/mach/hurd/closedir.c
index 521787d02d..4c62783584 100644
--- a/sysdeps/mach/hurd/closedir.c
+++ b/sysdeps/mach/hurd/closedir.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -39,14 +39,22 @@ DEFUN(closedir, (dirp), DIR *dirp)
       return -1;
     }
 
-  if (err = __vm_deallocate (__mach_task_self (),
-			     (vm_address_t) dirp->__data, dirp->__allocation))
-    return __hurd_fail (err);
+  __libc_lock_lock (dirp->__lock);
+  err = __vm_deallocate (__mach_task_self (),
+			 (vm_address_t) dirp->__data, dirp->__allocation);
   dirp->__data = NULL;
+  err = _hurd_fd_close (dirp->__fd);
 
-  if (err = _hurd_fd_close (dirp->__fd))
-    return __hurd_fail (err);
+  if (err)
+    {
+      /* Unlock the DIR.  A failing closedir can be repeated (and may fail
+	 again, but shouldn't deadlock).  */
+      __libc_lock_unlock (dirp->__lock);
+      return __hurd_fail (err);
+    }
 
+  /* Clean up the lock and free the structure.  */
+  __libc_lock_fini (dirp->__lock);
   free (dirp);
 
   return 0;
diff --git a/sysdeps/mach/hurd/dirstream.h b/sysdeps/mach/hurd/dirstream.h
index a8c5fd12cb..d17baf2b03 100644
--- a/sysdeps/mach/hurd/dirstream.h
+++ b/sysdeps/mach/hurd/dirstream.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -20,6 +20,8 @@ Cambridge, MA 02139, USA.  */
 
 #define	_DIRSTREAM_H	1
 
+#include <libc-lock.h>
+
 /* Directory stream type.
 
    The Hurd directory format is the same as `struct dirent', so `readdir'
@@ -34,6 +36,7 @@ struct __dirstream
     int __entry_ptr;		/* Entry number `__ptr' corresponds to.  */
     unsigned long int __allocation; /* Space allocated for the block.  */
     unsigned long int __size;	/* Total valid data in the block.  */
+    __libc_lock_define (, __lock); /* Mutex lock for this structure.  */
   };
 
 #endif	/* dirstream.h */
diff --git a/sysdeps/mach/hurd/opendir.c b/sysdeps/mach/hurd/opendir.c
index 8ab964a11d..bab84d52f0 100644
--- a/sysdeps/mach/hurd/opendir.c
+++ b/sysdeps/mach/hurd/opendir.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -49,7 +49,7 @@ DEFUN(opendir, (name), CONST char *name)
     {
       __close (fd);
       return NULL;
-    }    
+    }
 
   /* Extract the pointer to the descriptor structure.  */
   __mutex_lock (&_hurd_dtable_lock);
@@ -66,5 +66,7 @@ DEFUN(opendir, (name), CONST char *name)
   dirp->__allocation = 0;
   dirp->__size = 0;
 
+  __libc_lock_init (dirp->__lock);
+
   return dirp;
 }
diff --git a/sysdeps/mach/hurd/readdir.c b/sysdeps/mach/hurd/readdir.c
index 3c17d248e1..715f9278a2 100644
--- a/sysdeps/mach/hurd/readdir.c
+++ b/sysdeps/mach/hurd/readdir.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -41,6 +41,8 @@ DEFUN(readdir, (dirp), DIR *dirp)
       return NULL;
     }
 
+  __libc_lock_lock (dirp->__lock);
+
   do
     {
       if (dirp->__ptr - dirp->__data >= dirp->__size)
@@ -56,7 +58,11 @@ DEFUN(readdir, (dirp), DIR *dirp)
 						     &data, &dirp->__size,
 						     dirp->__entry_ptr,
 						     -1, 0, &nentries)))
-	    return __hurd_fail (err), NULL;
+	    {
+	      __hurd_fail (err);
+	      dp = NULL;
+	      break;
+	    }
 
 	  /* DATA now corresponds to entry index DIRP->__entry_ptr.  */
 	  dirp->__entry_data = dirp->__entry_ptr;
@@ -77,8 +83,11 @@ DEFUN(readdir, (dirp), DIR *dirp)
 	  dirp->__ptr = dirp->__data;
 
 	  if (nentries == 0)
-	    /* End of file.  */
-	    return NULL;
+	    {
+	      /* End of file.  */
+	      dp = NULL;
+	      break;
+	    }
 
 	  /* We trust the filesystem to return correct data and so we
 	     ignore NENTRIES.  */
@@ -91,5 +100,7 @@ DEFUN(readdir, (dirp), DIR *dirp)
       /* Loop to ignore deleted files.  */
     } while (dp->d_fileno == 0);
 
+  __libc_lock_unlock (dirp->__lock);
+
   return dp;
 }
diff --git a/sysdeps/mach/hurd/seekdir.c b/sysdeps/mach/hurd/seekdir.c
index fa4f1f4f52..a44ac7d246 100644
--- a/sysdeps/mach/hurd/seekdir.c
+++ b/sysdeps/mach/hurd/seekdir.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -27,10 +27,12 @@ Cambridge, MA 02139, USA.  */
 void
 DEFUN(seekdir, (dirp, pos), DIR *dirp AND __off_t pos)
 {
+  __libc_lock_lock (dirp->__lock);
   /* Change our entry index pointer to POS and discard any data already
      read.  The next `readdir' call will notice the empty block and read
      anew from the location in DIRP->__entry_ptr and reset the other state
      variables.  */
   dirp->__entry_ptr = pos;
   dirp->__size = 0;
+  __libc_lock_unlock (dirp->__lock);
 }
diff --git a/sysdeps/mach/libc-lock.h b/sysdeps/mach/libc-lock.h
new file mode 100644
index 0000000000..0639fc6b22
--- /dev/null
+++ b/sysdeps/mach/libc-lock.h
@@ -0,0 +1,60 @@
+/* libc-internal interface for mutex locks.  Mach cthreads version.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _LIBC_LOCK_H
+#define _LIBC_LOCK_H 1
+
+#ifdef _LIBC
+#include <cthreads.h>
+#define __libc_lock_t struct mutex
+#else
+typedef struct __libc_lock_opaque__ __libc_lock_t;
+#endif
+
+/* Define a lock variable NAME with storage class CLASS.  The lock must be
+   initialized with __libc_lock_init before it can be used (or define it
+   with __libc_lock_define_initialized, below).  Use `extern' for CLASS to
+   declare a lock defined in another module.  In public structure
+   definitions, the lock element must come last, because its storage size
+   will not be known outside of libc.  (Or you can use a pointer to the
+   lock structure; i.e. NAME begins with a `*'.)  */
+#define __libc_lock_define(CLASS,NAME)
+  CLASS __libc_lock_t NAME;
+
+/* Define an initialized lock variable NAME with storage class CLASS.  */
+#define __libc_lock_define_initialized(CLASS,NAME) \
+  CLASS __libc_lock_t NAME = MUTEX_INITIALIZER;
+
+/* Initialize the named lock variable, leaving it in a consistent, unlocked
+   state.  */
+#define __libc_lock_init(NAME) __mutex_init (&(NAME))
+
+/* Finalize the named lock variable, which must be locked.  It cannot be
+   used again until __libc_lock_init is called again on it.  This must be
+   called on a lock variable before the containing storage is reused.  */
+#define __libc_lock_fini(NAME) __mutex_unlock (&(NAME))
+
+/* Lock the named lock variable.  */
+#define __libc_lock_lock(NAME) __mutex_lock (&(NAME))
+
+/* Unlock the named lock variable.  */
+#define __libc_lock_unlock(NAME) __mutex_unlock (&(NAME))
+
+
+#endif	/* libc-lock.h */
diff --git a/sysdeps/stub/libc-lock.h b/sysdeps/stub/libc-lock.h
index ce6cab0f3f..a8608df791 100644
--- a/sysdeps/stub/libc-lock.h
+++ b/sysdeps/stub/libc-lock.h
@@ -24,7 +24,10 @@ Cambridge, MA 02139, USA.  */
 /* Define a lock variable NAME with storage class CLASS.  The lock must be
    initialized with __libc_lock_init before it can be used (or define it
    with __libc_lock_define_initialized, below).  Use `extern' for CLASS to
-   declare a lock defined in another module.  */
+   declare a lock defined in another module.  In public structure
+   definitions, the lock element must come last, because its storage size
+   will not be known outside of libc.  (Or you can use a pointer to the
+   lock structure; i.e. NAME begins with a `*'.)  */
 #define __libc_lock_define(CLASS,NAME)
 
 /* Define an initialized lock variable NAME with storage class CLASS.  */
@@ -34,6 +37,11 @@ Cambridge, MA 02139, USA.  */
    state.  */
 #define __libc_lock_init(NAME)
 
+/* Finalize the named lock variable, which must be locked.  It cannot be
+   used again until __libc_lock_init is called again on it.  This must be
+   called on a lock variable before the containing storage is reused.  */
+#define __libc_lock_fini(NAME)
+
 /* Lock the named lock variable.  */
 #define __libc_lock_lock(NAME)
 
diff --git a/sysdeps/unix/bsd/telldir.c b/sysdeps/unix/bsd/telldir.c
index 06580937e4..4400883357 100644
--- a/sysdeps/unix/bsd/telldir.c
+++ b/sysdeps/unix/bsd/telldir.c
@@ -36,6 +36,7 @@ struct record
 #define NBUCKETS 32
 static struct record *records[32];
 static off_t lastpos;
+__libc_lock_define_initialized(static, lock); /* Locks above data.  */
 
 
 /* Return the current position of DIRP.  */
@@ -43,6 +44,9 @@ off_t
 DEFUN(telldir, (dirp), DIR *dirp)
 {
   struct record *new;
+  off_t pos;
+
+  __libc_lock_lock (lock);
 
   new = malloc (sizeof *new);
   if (new == NULL)
@@ -54,7 +58,11 @@ DEFUN(telldir, (dirp), DIR *dirp)
   new->next = records[new->cookie % NBUCKETS];
   records[new->cookie % NBUCKETS] = new;
 
-  return new->cookie;
+  pos = new->cookie;
+
+  __libc_lock_unlock (lock);
+
+  return pos;
 }
 
 
@@ -65,11 +73,14 @@ DEFUN(seekdir, (dirp, pos), DIR *dirp AND __off_t pos)
 {
   struct record *r, **prevr;
 
+  __libc_lock_lock (lock);
+
   for (prevr = &records[pos % NBUCKETS], r = *prevr;
        r != NULL;
        prevr = &r->next, r = r->next)
     if (r->cookie == pos)
       {
+	__libc_lock_lock (dirp->__lock);
 	if (dirp->filepos != r->pos || dirp->offset != r->offset)
 	  {
 	    dirp->size = 0;	/* Must read a fresh buffer.  */
@@ -79,16 +90,25 @@ DEFUN(seekdir, (dirp, pos), DIR *dirp AND __off_t pos)
 	    dirp->offset = 0;
 	    /* Read entries until we reach the saved offset.  */
 	    while (dirp->offset < r->offset)
-	      if (readdir (dirp) == NULL)
-		break;
+	      {
+		struct dirent *scan;
+		__libc_lock_unlock (dirp->__lock);
+		scan = readdir (dirp);
+		__libc_lock_lock (dirp->__lock);
+		if (! scan)
+		  break;
+	      }
 	  }
+	__libc_lock_unlock (dirp->__lock);
 
 	/* To prevent leaking memory, cookies returned from telldir
 	   can only be used once.  So free this one's record now.  */
 	*prevr = r->next;
 	free (r);
-	return;
+	break;
       }
 
-  /* We lost, but have no way to indicate it.  Oh well.  */
+  __libc_lock_unlock (lock);
+
+  /* If we lost there is no way to indicate it.  Oh well.  */
 }
diff --git a/sysdeps/unix/closedir.c b/sysdeps/unix/closedir.c
index 791eaad250..1d4fd8eef0 100644
--- a/sysdeps/unix/closedir.c
+++ b/sysdeps/unix/closedir.c
@@ -37,9 +37,13 @@ DEFUN(closedir, (dirp), DIR *dirp)
       return -1;
     }
 
-  fd = dirp->fd;
+  __libc_lock_lock (dirp->lock);
 
+  fd = dirp->fd;
   free ((PTR) dirp->data);
+
+  __libc_lock_fini (dirp->lock);
+
   free ((PTR) dirp);
 
   return __close (fd);
diff --git a/sysdeps/unix/dirstream.h b/sysdeps/unix/dirstream.h
index 87e78b61ad..3d2796778a 100644
--- a/sysdeps/unix/dirstream.h
+++ b/sysdeps/unix/dirstream.h
@@ -22,6 +22,8 @@ Cambridge, MA 02139, USA.  */
 
 #include <sys/types.h>
 
+#include <libc-lock.h>
+
 /* Directory stream type.
 
    The miscellaneous Unix `readdir' implementations read directory data
@@ -37,6 +39,8 @@ struct __dirstream
     size_t offset;		/* Current offset into the block.  */
 
     off_t filepos;		/* Position of next entry to read.  */
+
+    __libc_lock_define (, lock); /* Mutex lock for this structure.  */
   };
 
 #define _DIR_dirfd(dirp)	((dirp)->fd)
diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c
index df20b9c131..8dca80b3ae 100644
--- a/sysdeps/unix/opendir.c
+++ b/sysdeps/unix/opendir.c
@@ -90,5 +90,8 @@ opendir (const char *name)
     }
 
   dirp->fd = fd;
+
+  __libc_lock_init (dirp->lock);
+
   return dirp;
 }
diff --git a/sysdeps/unix/readdir.c b/sysdeps/unix/readdir.c
index 00446a2d2b..5d0c40fdc1 100644
--- a/sysdeps/unix/readdir.c
+++ b/sysdeps/unix/readdir.c
@@ -40,6 +40,8 @@ readdir (DIR *dirp)
       return NULL;
     }
 
+  __libc_lock_lock (dirp->lock);
+
   do
     {
       size_t reclen;
@@ -62,7 +64,10 @@ readdir (DIR *dirp)
 	  base = dirp->filepos;
 	  bytes = __getdirentries (dirp->fd, dirp->data, maxread, &base);
 	  if (bytes <= 0)
-	    return NULL;
+	    {
+	      dp = NULL;
+	      break;
+	    }
 	  dirp->size = (size_t) bytes;
 
 	  /* Reset the offset into the buffer.  */
@@ -96,5 +101,7 @@ readdir (DIR *dirp)
       /* Skip deleted files.  */
     } while (dp->d_ino == 0);
 
+  __libc_lock_unlock (dirp->lock);
+
   return dp;
 }
diff --git a/sysdeps/unix/rewinddir.c b/sysdeps/unix/rewinddir.c
index 791ecc1a4b..3a91b06f4a 100644
--- a/sysdeps/unix/rewinddir.c
+++ b/sysdeps/unix/rewinddir.c
@@ -27,7 +27,9 @@ Cambridge, MA 02139, USA.  */
 void
 DEFUN(rewinddir, (dirp), DIR *dirp)
 {
+  __libc_lock_lock (dirp->lock);
   (void) lseek(dirp->fd, (off_t) 0, SEEK_SET);
   dirp->offset = 0;
   dirp->size = 0;
+  __libc_lock_unlock (dirp->lock);
 }
diff --git a/sysdeps/unix/seekdir.c b/sysdeps/unix/seekdir.c
index 9ce332b400..b1201f6b6c 100644
--- a/sysdeps/unix/seekdir.c
+++ b/sysdeps/unix/seekdir.c
@@ -27,7 +27,9 @@ Cambridge, MA 02139, USA.  */
 void
 DEFUN(seekdir, (dirp, pos), DIR *dirp AND __off_t pos)
 {
+  __libc_lock_lock (dirp->lock);
   (void) __lseek(dirp->fd, pos, SEEK_SET);
   dirp->size = 0;
   dirp->offset = 0;
+  __libc_lock_unlock (dirp->lock);
 }