Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

semantics of pthread_kill()...

209 views
Skip to first unread message

Chris Thomasson

unread,
Apr 23, 2006, 3:08:18 AM4/23/06
to
My question is simple... If this function returns 0, does POSIX guarantee
that a signal was actually sent to the target thread?

Is so, I would also assume that even though the signal was sent, it can't be
100% guaranteed that the target threads handler will fire... Is my
assumption correct?


Chris Thomasson

unread,
Apr 23, 2006, 3:45:59 AM4/23/06
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:99Cdnb8WEp1...@comcast.com...

I am tinkering around with a toy proxy garbage collector that is based on
signals. Yikes!

:)


Alls a mutator threads signal handler has to do is this:


static int volatile g_epoch = 0;


/* mutator thread(s) sig handlers */
void pgc_sig_epoch( int sig ) {
atomic_dec_release/fence( &g_epoch );
}


And alls a collector has to do is this:


/* "single" collector thread */
void* pgc( void *s ) {

for ( ;; ) {

/* 1: Wait for polling interval */

/* 2: Detect sync epochs */

/* 2a. notify mutators */
for_each_mutator{
atomic_inc( &g_epoch );
pthread_kill( this_thread, ... );
}

/* 2b. wait for mutators */
while ( g_epoch ) {
/* pause yield, exponential backoff, ect... */
}

/* 3: Process sync epoch */
(...)
}

return 0;
}


This can get around thread specific data in signal handlers, which AFAICT
seems to be a bit of a problem? Am I correct on this?


Chris Thomasson

unread,
Apr 23, 2006, 6:14:27 AM4/23/06
to
> Alls a mutator threads signal handler has to do is this:

Another way to set this up is:


static int volatile g_epoch_now_serving = 0;


/* mutator thread(s) sig handlers */
void pgc_sig_epoch( int sig ) {

atomic_inc_release/fence( &g_epoch_now_serving );
}


/* "single" collector thread */
void* pgc( void *s ) {

int epoch_ticket = 0;

for ( ;; ) {

/* 1: Wait for polling interval */

/* 2: Detect sync epochs */

/* 2a. notify mutators */
for_each_mutator{

int ticket = epoch_ticket++;
pthread_kill( this_thread, ... );
while ( ticket != g_epoch_now_serving ) {

Chris Thomasson

unread,
Apr 23, 2006, 6:25:28 AM4/23/06
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:r_KdnYFBy_A...@comcast.com...

>> Alls a mutator threads signal handler has to do is this:
>
[...]

> /* "single" collector thread */
> void* pgc( void *s ) {
>
> int epoch_ticket = 0;
>
> for ( ;; ) {
>
> /* 1: Wait for polling interval */
>
> /* 2: Detect sync epochs */
>
> /* 2a. notify mutators */
> for_each_mutator{
> int ticket = epoch_ticket++;
> pthread_kill( this_thread, ... );


Yikes!!!


This:

> while ( ticket != g_epoch_now_serving ) {

has to be this:


while ( ticket == g_epoch_now_serving ) {


> /* pause yield, exponential backoff, ect... */
> }
> }

[...]


Sorry!


Chris Thomasson

unread,
Apr 23, 2006, 7:07:17 AM4/23/06
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:99Cdnb8WEp1...@comcast.com...

Sorry for posting all of this, but I need to ask one more question...

pthread_kill does not act as a release barrier for the calling thread,
correct? pthread_kill does not have to wait until all of the calling threads
pending stores are made visible before the signal is issued? I assume the
answer is no. Luckily, my stuff does not require anything from the collector
thread to be visible to its mutators before signals are sent...

Thank you.


Joe Seigh

unread,
Apr 23, 2006, 7:59:00 AM4/23/06
to
Yes, AFAIK. Although some signals aren't guaranteed to be delivered in the
case of multiple pending signals.

The signal is send meaning it's queued or pending. Checking for pending signals
by the target thread is typically only done at time slice end and on syscalls.
So for instance, a thread could spend 5 minutes on the run queue, get dispatched,
and only "see" the signal when it preempted on a syscall or time slice end.

So you need something in the target threads signal handler to be able to tell when
the signal was actually delivered.

pthread_kill synchronizes if it the the list of functions that synchronize. There's
a list but I'd have to spend 10 or 15 minutes trying to find the obscure section of
the spec they buried it in. "list of functions" is mentioned in the section on
memory synchronization but of course there's no link to it. (Hey Posix documentation
writers! There's these things called URL's! Check them out.) Just put a wrapper
around your signaling function and define it as having release semantics. You can
then add a memory barrier if needed.

I tried using signals in an early version of RCU for preemptive threads. I guess you
can use them for quiescent states but if the threads don't get dispatched on a timely
manner due to thread priority or system load there's nothing you can do about it.


--
Joe Seigh

When you get lemons, you make lemonade.
When you get hardware, you make software.

David Hopwood

unread,
Apr 23, 2006, 11:11:43 AM4/23/06
to
Chris Thomasson wrote:
> "Chris Thomasson" <cri...@comcast.net> wrote in message
> news:99Cdnb8WEp1...@comcast.com...
>
>>My question is simple... If this function returns 0, does POSIX guarantee
>>that a signal was actually sent to the target thread?
>>
>>Is so, I would also assume that even though the signal was sent, it can't
>>be 100% guaranteed that the target threads handler will fire... Is my
>>assumption correct?
>
> Sorry for posting all of this, but I need to ask one more question...
>
> pthread_kill does not act as a release barrier for the calling thread,
> correct? pthread_kill does not have to wait until all of the calling threads
> pending stores are made visible before the signal is issued?

No, it doesn't.

<http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html>

# 4.10 Memory Synchronization
# [...]
# The following functions synchronize memory with respect to other threads:
#
# [list not including pthread_kill]

--
David Hopwood <david.nosp...@blueyonder.co.uk>

Chris Thomasson

unread,
Apr 23, 2006, 5:05:47 PM4/23/06
to
Joe Seigh wrote:
> Chris Thomasson wrote:
>
>> "Chris Thomasson" <cri...@comcast.net> wrote in message
>> news:99Cdnb8WEp1...@comcast.com...
>>
>>> My question is simple... If this function returns 0, does POSIX
>>> guarantee that a signal was actually sent to the target thread?
>>>
>>> Is so, I would also assume that even though the signal was sent, it
>>> can't be 100% guaranteed that the target threads handler will fire...
>>> Is my assumption correct?
>>
>>
>>
>> Sorry for posting all of this, but I need to ask one more question...
>>
>> pthread_kill does not act as a release barrier for the calling thread,
>> correct? pthread_kill does not have to wait until all of the calling
>> threads pending stores are made visible before the signal is issued? I
>> assume the answer is no. Luckily, my stuff does not require anything
>> from the collector thread to be visible to its mutators before signals
>> are sent...
>>
>>
> Yes, AFAIK. Although some signals aren't guaranteed to be delivered in the
> case of multiple pending signals.

OK. What about a dedicated single thread that issues a single
pthread_kill() at a specific thread, and then waits on the response
(e.g.,spin on value,ect...) before it issues another signal. Could this
deadlock?

Is this "multiple pending" thing per-issue-thread or per-process?


> The signal is send meaning it's queued or pending. Checking for pending
> signals
> by the target thread is typically only done at time slice end and on
> syscalls.
> So for instance, a thread could spend 5 minutes on the run queue, get
> dispatched,
> and only "see" the signal when it preempted on a syscall or time slice end.
>
> So you need something in the target threads signal handler to be able to
> tell when
> the signal was actually delivered.

I am only worried about if handler will be called or not... If a syscall
is all that it takes, then that "should" cover "typical" application
usage... Most existing application threads have some sort of
periodic/episodic syscall pattern...


;)

[...]

> I tried using signals in an early version of RCU for preemptive
> threads. I guess you
> can use them for quiescent states but if the threads don't get
> dispatched on a timely
> manner due to thread priority or system load there's nothing you can do
> about it.

Humm... I will have to experiment a little bit. I am basically trying to
use signals to emulate an existing sync pattern that the POSIX version
of my vzoom collector uses. Basically, it goes like this pseudo-code:


worker_thread_loop( void ) {
int vzepoch = 2500, vzmsgwait = 250ms;

vzepoch_cfg( vzepoch );

/* threads "server" loop */
for ( int vzsync = 1 ;; ++vzsync ) {


application_code( void ) {

acquire messages( void ) {

/* try to acquire message */
if ( ! msg_timedwait( vzmsgwait ) ) {
vzepoch_disable();
msg_wait();
vzepoch_enable();
}
}

/* access data-structures */

/* whatever */
}


/* check for sync /w fence membar */
vzepoch_sync_fence( vzsync ) {
if ( ! ( vzsync % vzthis->cfg.epoch ) ) {
vzthis->sync1 = 1;
// fence
vzthis->sync2 = 1;
}
}
}
}


Instead of threads calling vzepoch_sync_xxx(), I was thinking about
using signals to do something similar...

Joe Seigh

unread,
Apr 23, 2006, 6:54:29 PM4/23/06
to
Chris Thomasson wrote:

> Joe Seigh wrote:
>
>>>
>>>
>> Yes, AFAIK. Although some signals aren't guaranteed to be delivered
>> in the
>> case of multiple pending signals.
>
>
> OK. What about a dedicated single thread that issues a single
> pthread_kill() at a specific thread, and then waits on the response
> (e.g.,spin on value,ect...) before it issues another signal. Could this
> deadlock?

Only if the target thread somehow terminates before handling the signal.


>
> Is this "multiple pending" thing per-issue-thread or per-process?
>

Per signal number, ie. multiple instances of the same signal for the same
thread or for the same process AFAIK. Some signals aren't guaranteed
to be delivered to a thread if one is already pending.

0 new messages