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:
parent
53432762ac
commit
5c06743c8a
|
@ -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))
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
Loading…
Reference in a new issue