about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--hurd/hurd/port.h25
-rw-r--r--hurd/hurd/userlink.h24
-rw-r--r--sysdeps/mach/hurd/spawni.c12
4 files changed, 64 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 0b7752345b..8546c2d336 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,10 @@
 	(reauthenticate): Test and use ccwdir.
 	(child_init_port): In non-resetids case, test and use ccwdir.
 	(child_chdir): New nested function to set ccwdir.
+	* hurd/hurd/userlink.h (_hurd_userlink_move): New function.
+	* hurd/hurd/port.h (_hurd_port_move): New function.
+	* sysdeps/mach/hurd/spawni.c (NEW_ULINK_TABLE): New macro.
+	(EXPAND_DTABLE): Use NEW_ULINK_TABLE macro for ulink_dtable.
 
 2018-11-09  Martin Sebor  <msebor@redhat.com>
 
diff --git a/hurd/hurd/port.h b/hurd/hurd/port.h
index 0779578d03..769e44b5cc 100644
--- a/hurd/hurd/port.h
+++ b/hurd/hurd/port.h
@@ -127,6 +127,31 @@ _hurd_port_get (struct hurd_port *port,
 #endif
 
 
+/* Relocate LINK to NEW_LINK.
+   To be used when e.g. reallocating a link array.  */
+
+extern void
+_hurd_port_move (struct hurd_port *port,
+		 struct hurd_userlink *new_link,
+		 struct hurd_userlink *link);
+
+#if defined __USE_EXTERN_INLINES && defined _LIBC
+# if IS_IN (libc)
+_HURD_PORT_H_EXTERN_INLINE void
+_hurd_port_move (struct hurd_port *port,
+		 struct hurd_userlink *new_link,
+		 struct hurd_userlink *link)
+{
+  HURD_CRITICAL_BEGIN;
+  __spin_lock (&port->lock);
+  _hurd_userlink_move (new_link, link);
+  __spin_unlock (&port->lock);
+  HURD_CRITICAL_END;
+}
+# endif
+#endif
+
+
 /* Free a reference gotten with `USED_PORT = _hurd_port_get (PORT, LINK);' */
 
 extern void
diff --git a/hurd/hurd/userlink.h b/hurd/hurd/userlink.h
index f9362557cb..484706a67a 100644
--- a/hurd/hurd/userlink.h
+++ b/hurd/hurd/userlink.h
@@ -142,6 +142,30 @@ _hurd_userlink_unlink (struct hurd_userlink *link)
 # endif
 #endif
 
+/* Relocate LINK to NEW_LINK.
+   To be used when e.g. reallocating a link array.  */
+
+extern void _hurd_userlink_move (struct hurd_userlink *new_link,
+                                struct hurd_userlink *link);
+
+#if defined __USE_EXTERN_INLINES && defined _LIBC
+# if IS_IN (libc)
+_HURD_USERLINK_H_EXTERN_INLINE void
+_hurd_userlink_move (struct hurd_userlink *new_link,
+                     struct hurd_userlink *link)
+{
+  *new_link = *link;
+
+  if (new_link->resource.next != NULL)
+    new_link->resource.next->resource.prevp = &new_link->resource.next;
+  *new_link->resource.prevp = link;
+
+  if (new_link->thread.next != NULL)
+    new_link->thread.next->thread.prevp = &new_link->thread.next;
+  *new_link->thread.prevp = link;
+}
+# endif
+#endif
 
 /* Clear all users from *CHAINP.  Call this when the resource *CHAINP
    protects is changing.  If the return value is nonzero, no users are on
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 4fd0cdd520..c08f2a5b5a 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -457,7 +457,7 @@ __spawni (pid_t *pid, const char *file,
 	    {								      \
 	      /* We need to expand the dtable for the child.  */	      \
 	      NEW_TABLE (dtable, newfd);				      \
-	      NEW_TABLE (ulink_dtable, newfd);				      \
+	      NEW_ULINK_TABLE (ulink_dtable, newfd);			      \
 	      NEW_TABLE (dtable_cells, newfd);				      \
 	      dtablesize = newfd + 1;					      \
 	    }								      \
@@ -468,6 +468,16 @@ __spawni (pid_t *pid, const char *file,
   memcpy (new_##x, x, dtablesize * sizeof (x[0]));			      \
   memset (&new_##x[dtablesize], 0, (newfd + 1 - dtablesize) * sizeof (x[0])); \
   x = new_##x; } while (0)
+#define NEW_ULINK_TABLE(x, newfd) \
+  do { __typeof (x) new_##x = __alloca ((newfd + 1) * sizeof (x[0]));	      \
+  unsigned i;								      \
+  for (i = 0; i < dtablesize; i++)					      \
+    if (dtable_cells[i] != NULL)					      \
+      _hurd_port_move (dtable_cells[i], &new_##x[i], &x[i]);		      \
+    else								      \
+      memset(&new_##x[i], 0, sizeof(new_##x[i]));			      \
+  memset (&new_##x[dtablesize], 0, (newfd + 1 - dtablesize) * sizeof (x[0])); \
+  x = new_##x; } while (0)
 
 	struct __spawn_action *action = &file_actions->__actions[i];