Hurd: make sigstates hold a reference on thread ports

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.
This commit is contained in:
Richard Braun 2020-12-21 02:10:16 +01:00 committed by Samuel Thibault
parent 53432762ac
commit 5c06743c8a
2 changed files with 29 additions and 7 deletions

View file

@ -67,7 +67,9 @@ struct hurd_sigstate
spin_lock_t lock; /* Locks most of the rest of the structure. */ 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; thread_t thread;
struct hurd_sigstate *next; /* Linked-list of thread sigstates. */ struct hurd_sigstate *next; /* Linked-list of thread sigstates. */
sigset_t blocked; /* What signals are blocked. */ sigset_t blocked; /* What signals are blocked. */
@ -119,7 +121,9 @@ struct hurd_sigstate
extern struct hurd_sigstate *_hurd_sigstates; extern struct hurd_sigstate *_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); extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t);
@ -162,7 +166,11 @@ _HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
_hurd_self_sigstate (void) _hurd_self_sigstate (void)
{ {
if (THREAD_GETMEM (THREAD_SELF, _hurd_sigstate) == NULL) if (THREAD_GETMEM (THREAD_SELF, _hurd_sigstate) == NULL)
THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, _hurd_thread_sigstate (__mach_thread_self ())); {
thread_t self = __mach_thread_self ();
THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, _hurd_thread_sigstate (self));
__mach_port_deallocate (__mach_task_self (), self);
}
return THREAD_GETMEM (THREAD_SELF, _hurd_sigstate); return THREAD_GETMEM (THREAD_SELF, _hurd_sigstate);
} }
# endif # endif
@ -210,12 +218,15 @@ _hurd_critical_section_lock (void)
ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate); ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate);
if (ss == NULL) if (ss == NULL)
{ {
thread_t self = __mach_thread_self ();
/* The thread variable is unset; this must be the first time we've /* The thread variable is unset; this must be the first time we've
asked for it. In this case, the critical section flag cannot asked for it. In this case, the critical section flag cannot
possible already be set. Look up our sigstate structure the slow possible already be set. Look up our sigstate structure the slow
way. */ way. */
ss = _hurd_thread_sigstate (__mach_thread_self ()); ss = _hurd_thread_sigstate (self);
THREAD_SETMEM(THREAD_SELF, _hurd_sigstate, ss); THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, ss);
__mach_port_deallocate (__mach_task_self (), self);
} }
if (! __spin_try_lock (&ss->critical_section_lock)) if (! __spin_try_lock (&ss->critical_section_lock))

View file

@ -114,6 +114,8 @@ _hurd_thread_sigstate (thread_t thread)
} }
else else
{ {
error_t err;
/* Use the global actions as a default for new threads. */ /* Use the global actions as a default for new threads. */
struct hurd_sigstate *s = _hurd_global_sigstate; struct hurd_sigstate *s = _hurd_global_sigstate;
if (s) if (s)
@ -127,6 +129,11 @@ _hurd_thread_sigstate (thread_t thread)
ss->next = _hurd_sigstates; ss->next = _hurd_sigstates;
_hurd_sigstates = ss; _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); __mutex_unlock (&_hurd_siglock);
@ -135,8 +142,7 @@ _hurd_thread_sigstate (thread_t thread)
libc_hidden_def (_hurd_thread_sigstate) libc_hidden_def (_hurd_thread_sigstate)
/* Destroy a sigstate structure. Called by libpthread just before the /* Destroy a sigstate structure. Called by libpthread just before the
* corresponding thread is terminated (the kernel thread port must remain valid * corresponding thread is terminated. */
* until this function is called.) */
void void
_hurd_sigstate_delete (thread_t thread) _hurd_sigstate_delete (thread_t thread)
{ {
@ -153,7 +159,12 @@ _hurd_sigstate_delete (thread_t thread)
__mutex_unlock (&_hurd_siglock); __mutex_unlock (&_hurd_siglock);
if (ss) 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. */ /* Make SS a global receiver, with pthread signal semantics. */