guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 01/02: Don't hold lock during scm_async_tick in readdir


From: Rob Browning
Subject: [Guile-commits] 01/02: Don't hold lock during scm_async_tick in readdir and ttyname
Date: Thu, 23 Jan 2025 13:53:15 -0500 (EST)

rlb pushed a commit to branch main
in repository guile.

commit 63756efbc5d015a17627fdc446992fc0f7aa6a49
Author: Rob Browning <rlb@defaultvalue.org>
AuthorDate: Wed Jan 22 12:55:06 2025 -0600

    Don't hold lock during scm_async_tick in readdir and ttyname
    
    Only hold scm_i_misc_mutex while making the C calls.  This also avoids
    the need for a dynamic-wind.  Add SCM_I_LOCKED_SYSCALL (similar to
    SCM_SYSCALL) to handle the locking and EINTR loop.
    
    libguile/filesys.c (scm_readdir): rely on SCM_I_LOCKED_SYSCALL to limit
    locking.
    libguile/filesys.c (scm_ttyname): rely on SCM_I_LOCKED_SYSCALL to limit
    locking.
    libguile/syscalls.h: add SCM_I_LOCKED_SYSCALL.
---
 NEWS                |  2 ++
 libguile/filesys.c  | 32 ++++++++++++--------------------
 libguile/posix.c    | 37 ++++++++++++-------------------------
 libguile/syscalls.h | 18 ++++++++++++++++++
 4 files changed, 44 insertions(+), 45 deletions(-)

diff --git a/NEWS b/NEWS
index 3328a03cf..f042188c1 100644
--- a/NEWS
+++ b/NEWS
@@ -69,6 +69,8 @@ every line in a file.
 ** Immutable stringbufs are now 8-byte aligned on all systems
    Previously they could end up with an alignment that violated the type
    tag for their type (e.g. ending up tagged as immediates SCM_IMP()).
+** `readdir` and `ttyname` now release scm_i_misc_mutex during asyncs
+   This avoids potential deadlocks.
 
 
 Changes in 3.0.10 (since 3.0.9)
diff --git a/libguile/filesys.c b/libguile/filesys.c
index b70fbb1ce..0e7078cf0 100644
--- a/libguile/filesys.c
+++ b/libguile/filesys.c
@@ -2231,30 +2231,22 @@ SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0,
            "end of file object is returned.")
 #define FUNC_NAME s_scm_readdir
 {
-  SCM ret;
-  scm_i_pthread_mutex_t *mutex;
-  struct dirent_or_dirent64 *rdent;
-
   SCM_VALIDATE_DIR (1, port);
   if (!SCM_DIR_OPEN_P (port))
     SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
 
-  mutex = (scm_i_pthread_mutex_t *) SCM_SMOB_DATA_2 (port);
-
-  scm_dynwind_begin (0);
-  scm_i_dynwind_pthread_mutex_lock (mutex);
-
-  errno = 0;
-  SCM_SYSCALL (rdent = readdir_or_readdir64 ((DIR *) SCM_SMOB_DATA_1 (port)));
-  if (errno != 0)
-    SCM_SYSERROR;
-
-  ret = (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
-         : SCM_EOF_VAL);
-
-  scm_dynwind_end ();
-
-  return ret;
+  scm_i_pthread_mutex_t *mutex = (scm_i_pthread_mutex_t *) SCM_SMOB_DATA_2 
(port);
+  DIR *dir = (DIR *) SCM_SMOB_DATA_1 (port);
+  char *name = 0;
+  SCM_I_LOCKED_SYSCALL
+    (mutex,
+     struct dirent_or_dirent64 *rdent = readdir_or_readdir64 (dir);
+     if (rdent) name = strdup (rdent->d_name));
+  if (name)
+    return scm_take_locale_string (name);
+  if (!errno)
+    return SCM_EOF_VAL;
+  SCM_SYSERROR;
 }
 #undef FUNC_NAME
 
diff --git a/libguile/posix.c b/libguile/posix.c
index 0e57f012b..61b5523af 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1048,8 +1048,10 @@ SCM_DEFINE (scm_getsid, "getsid", 1, 0, 0,
    continuously calling ttyname will otherwise get an overwrite quite
    easily.
 
-   ttyname_r (when available) could be used instead of scm_i_misc_mutex, but
-   there's probably little to be gained in either speed or parallelism.  */
+   ttyname_r (when available) could be used instead of scm_i_misc_mutex
+   if it doesn't restrict the maximum name length the way readdir_r can,
+   but there's probably little to be gained in either speed or
+   parallelism.  */
 
 #ifdef HAVE_TTYNAME
 SCM_DEFINE (scm_ttyname, "ttyname", 1, 0, 0, 
@@ -1058,34 +1060,19 @@ SCM_DEFINE (scm_ttyname, "ttyname", 1, 0, 0,
            "underlying @var{port}.")
 #define FUNC_NAME s_scm_ttyname
 {
-  char *result;
-  int fd, err;
-  SCM ret = SCM_BOOL_F;
-
   port = SCM_COERCE_OUTPORT (port);
   SCM_VALIDATE_OPPORT (1, port);
   if (!SCM_FPORTP (port))
     return SCM_BOOL_F;
-  fd = SCM_FPORT_FDES (port);
-
-  scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
-
-  SCM_SYSCALL (result = ttyname (fd));
-  err = errno;
-  if (result != NULL)
-    result = strdup (result);
 
-  scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
-
-  if (!result)
-    {
-      errno = err;
-      SCM_SYSERROR;
-    }
-  else
-    ret = scm_take_locale_string (result);
-
-  return ret;
+  int fd = SCM_FPORT_FDES (port);
+  char *name = 0;
+  SCM_I_LOCKED_SYSCALL(&scm_i_misc_mutex,
+                       char *n = ttyname (fd);
+                       if (n) name = strdup (n));
+  if (name)
+    return scm_take_locale_string (name);
+  SCM_SYSERROR;
 }
 #undef FUNC_NAME
 #endif /* HAVE_TTYNAME */
diff --git a/libguile/syscalls.h b/libguile/syscalls.h
index 6f4061138..e10cc4870 100644
--- a/libguile/syscalls.h
+++ b/libguile/syscalls.h
@@ -37,6 +37,24 @@
     }                                          \
   while (errno == EINTR)
 
+/* A SCM_SYSCALL for calls that need mutex serialization.  The body must
+   ensure to leave an appropriate errno. */
+#define SCM_I_LOCKED_SYSCALL(lock, body)                             \
+  while(1)                                                           \
+    {                                                                \
+      scm_i_pthread_mutex_t *lock___ = (lock);                       \
+      scm_i_pthread_mutex_lock (lock___);                            \
+      errno = 0;                                                     \
+      { body; }                                                      \
+      int err___ = errno;                                            \
+      scm_i_pthread_mutex_unlock (lock___);                          \
+      if (err___ != EINTR)                                           \
+        {                                                            \
+          errno = err___;                                            \
+          break;                                                     \
+        }                                                            \
+      scm_async_tick ();                                             \
+    }
 
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]