[PATCH] Hurd: make sigstates hold a reference on thread ports
authorRichard Braun <rbraun@sceen.net>
Tue, 5 May 2020 18:12:38 +0000 (19:12 +0100)
committerAurelien Jarno <aurel32@debian.org>
Tue, 5 May 2020 18:12:38 +0000 (19:12 +0100)
This change is required in order to correctly release per-thread
resources. Directly reusing the threading library reference isn't
possible since the sigstate is also used early in the main thread,
before threading is initialized.

* hurd/hurd/signal.h (_hurd_self_sigstate): Drop thread reference after
calling _hurd_thread_sigstate.
(_hurd_critical_section_lock): Likewise.
* hurd/hurdsig.c (_hurd_thread_sigstate): Add a reference on the thread.
(_hurd_sigstate_delete): Drop thread reference.

Gbp-Pq: Topic hurd-i386
Gbp-Pq: Name tg-sigstate_thread_reference.diff

hurd/hurd/signal.h
hurd/hurdsig.c

index 3de0112555ef43fd786b073f62b89095457210fc..677873d71d42ff259d2fc39a8e1e089d006c51b0 100644 (file)
@@ -68,7 +68,9 @@ struct hurd_sigstate
 
     spin_lock_t lock;          /* Locks most of the rest of the structure.  */
 
+    /* The signal state holds a reference on the thread port.  */
     thread_t thread;
+
     struct hurd_sigstate *next; /* Linked-list of thread sigstates.  */
 
     sigset_t blocked;          /* What signals are blocked.  */
@@ -122,7 +124,9 @@ extern struct hurd_sigstate *_hurd_sigstates;
 
 extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */
 
-/* Get the sigstate of a given thread, taking its lock.  */
+/* Get the sigstate of a given thread.  If there was no sigstate for
+   the thread, one is created, and the thread gains a reference.  If
+   the given thread is MACH_PORT_NULL, return the global sigstate.  */
 
 extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t);
 
@@ -165,7 +169,11 @@ _HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
 _hurd_self_sigstate (void)
 {
   if (THREAD_SELF->_hurd_sigstate == NULL)
-    THREAD_SELF->_hurd_sigstate = _hurd_thread_sigstate (__mach_thread_self ());
+    {
+      thread_t self = __mach_thread_self ();
+      THREAD_SELF->_hurd_sigstate = _hurd_thread_sigstate (self);
+      __mach_port_deallocate (__mach_task_self (), self);
+    }
   return THREAD_SELF->_hurd_sigstate;
 }
 # endif
@@ -213,11 +221,14 @@ _hurd_critical_section_lock (void)
   ss = THREAD_SELF->_hurd_sigstate;
   if (ss == NULL)
     {
+      thread_t self = __mach_thread_self ();
+
       /* The thread variable is unset; this must be the first time we've
         asked for it.  In this case, the critical section flag cannot
         possible already be set.  Look up our sigstate structure the slow
         way.  */
-      ss = THREAD_SELF->_hurd_sigstate = _hurd_thread_sigstate (__mach_thread_self ());
+      ss = THREAD_SELF->_hurd_sigstate = _hurd_thread_sigstate (self);
+      __mach_port_deallocate (__mach_task_self (), self);
     }
 
   if (! __spin_try_lock (&ss->critical_section_lock))
index 3efceb6fde96f921450ed9b94d5ce7bffb44e1c4..940f8408565846abf0ca5f9fe6ecfbe3391545f0 100644 (file)
@@ -109,6 +109,8 @@ _hurd_thread_sigstate (thread_t thread)
        }
       else
        {
+         error_t err;
+
          /* Use the global actions as a default for new threads.  */
          struct hurd_sigstate *s = _hurd_global_sigstate;
          if (s)
@@ -122,6 +124,11 @@ _hurd_thread_sigstate (thread_t thread)
 
          ss->next = _hurd_sigstates;
          _hurd_sigstates = ss;
+
+         err = __mach_port_mod_refs (__mach_task_self (), thread,
+                                     MACH_PORT_RIGHT_SEND, 1);
+         if (err)
+           __libc_fatal ("hurd: Can't add reference on Mach thread\n");
        }
     }
   __mutex_unlock (&_hurd_siglock);
@@ -130,8 +137,7 @@ _hurd_thread_sigstate (thread_t thread)
 libc_hidden_def (_hurd_thread_sigstate)
 
 /* Destroy a sigstate structure.  Called by libpthread just before the
- * corresponding thread is terminated (the kernel thread port must remain valid
- * until this function is called.) */
+ * corresponding thread is terminated.  */
 void
 _hurd_sigstate_delete (thread_t thread)
 {
@@ -148,7 +154,12 @@ _hurd_sigstate_delete (thread_t thread)
 
   __mutex_unlock (&_hurd_siglock);
   if (ss)
-    free (ss);
+    {
+      if (ss->thread != MACH_PORT_NULL)
+       __mach_port_deallocate (__mach_task_self (), ss->thread);
+
+      free (ss);
+    }
 }
 
 /* Make SS a global receiver, with pthread signal semantics.  */