Re: perf_counters issue with self-sampling threads

From: Peter Zijlstra
Date: Wed Jul 29 2009 - 08:16:28 EST


On Mon, 2009-07-27 at 18:51 +0200, stephane eranian wrote:
> I believe there is a problem with the current perf_counters (PCL)
> code for self-sampling threads. The problem is related to sample
> notifications via signal.
>
> PCL (just like perfmon) is using SIGIO, an asynchronous signal,
> to notify user applications of the availability of data in the event
> buffer.
>
> POSIX does not mandate that asynchronous signals be delivered
> to the thread in which they originated. Any thread in the process
> may process the signal, assuming it does not have the signal
> blocked.

This signal stuff makes my head spin a little, however:

fcntl(2) for F_SETOWN says:

If a non-zero value is given to F_SETSIG in a multiâ threaded
process running with a threading library that supports thread groups
(e.g., NPTL), then a positive value given to F_SETOWN has a
different meaning: instead of being a process ID identifying a whole
proâ cess, it is a thread ID identifying a specific thread within a
process. Consequently, it may be necessary to pass F_SETOWN the
result of gettid(2) instead of getâ pid(2) to get sensible results
when F_SETSIG is used. (In current Linux threading
implementations, a main threadâs thread ID is the same as its process
ID. This means that a single-threaded program can equally use
gettid(2) or getpid(2) in this scenario.) Note, howâ ever, that
the statements in this paragraph do not apply to the SIGURG signal
generated for out-of-band data on a socket: this signal is always
sent to either a process or a process group, depending on the value
given to F_SETOWN. Note also that Linux imposes a limit on the
number of real-time signals that may be queued to a process (see
getrlimit(2) and signal(7)) and if this limit is reached, then the
kernel reverts to delivering SIGIO, and this signal is delivered
to the entire process rather than to a specific thread.


Which seems to imply that when we feed fcntl(F_SETOWN) a TID instead of
a PID it should deliver SIGIO to the thread instead of the whole process
-- which, to me, seems a sane semantic.

However,

kill_fasync(SIGIO)
__kill_fasync()
send_sigio()
/* if pid_type is a PIDTYPE_PID and pid a TID this should
only iterate the one thread, I think */
do_each_pid_task() {
send_sigio_to_task();
} while_each_pid_task();

where:

send_sigio_to_task()
group_send_sig_info()
__group_send_sig_info()
send_signal(.group = 1) /* uh-ow trouble */
__send_signal()
if (group)
pending = &t->signal->shared_pending

which will result in the signal being send to the whole process anyway.


Now I was considering teaching send_sigio_to_task() to use
specific_send_sig_info() when fown->pid != fown->group_leader->pid or
something, but I'm not sure that won't break anything.

Alternatively, I've missed a detail and I either read the manpage wrong,
or the code, or both of them.



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/