This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: How to benefit from asynchronous unwind tables?


Ewgenij Gawrilow wrote:
> Andrew Haley wrote:
> 
>>>> With SIGFPE and SIGSEGV, the compiler knows exactly where they might be
>>>> generated and only needs accurate unwind tables at those locations.
>>>>
>>> Well, these signals can be triggered at every instruction referring to memory or working with
>>> floats, that is, practically everywhere.
>> That is not practically everywhere: the compiler knows that some operations trap,
>> and generates abnormal edges in the control flow graph for them.  Without these
>> edges it's impossible to generate correct code.
>>
>> If every instruction may trap and an exception may be thrown from them, then there is
>> an abnormal edge from every instruction to an exception handler.
> 
> OK, I see. Does the function call count as trap too?

Yes, there is always a possible edge from a call to an exception handler.

>> libc does support thread cancellation points, and it's always
>> safe to unwind the stack from one of these.
> 
> Well, thread cancellation points are indeed nice, but they occur too rare, at least in the code I'm
> now concerned about.  When you say, you understand the mechanics of signal handling right into the
> kernel guts, you can perhaps help me with my original concern too, namely how to convert SIGINT and
> SIGALRM to properly catchable C++ exceptions.

I'm not sure that is possible.  It may be, but it would be fragile and non-portable.

> If you wonder what it might be good for: since years I'm writing on an open source software for
> discrete mathematics called polymake.  It consists of an interactive core written in perl and
> modules performing massive calculations written, for the sake of efficiency, in C++.  The C++
> routines are called directly from the perl code via the special interface, similar to JNI (although
> much uglier, but it doesn't matter now).  Thus everything lives in a single process and even in the
> single thread (there may exist other threads too, but they are masking these signals away and hence
> don't matter).
> 
> The signal handling in perl is rather primitive: the handler sets a flag, which is regularly polled
> from the main interpreter loop.  For a scripting language it's a sufficient solution.  But not for
> the code trimmed for efficiency.
> 
> Arrival of the asynchronous signal means that the user has changed his mind and pressed Control-C to
> break the current lengthy calculation, or some pre-selected timeout for such calculations has
> elapsed.  In both cases the program should return to the interactive shell and wait for the next
> user's input, or do something else it might find useful; at any rate, the frames of the interrupted
> C++ functions must be properly unwound to avoid memory leaks and other unpleasant surprises.
> 
> That's what I need; unfortunately, I have only the utterly faint idea how to implement it.  The
> vague plan as for tonight goes as follows: the signal handler analyzes the call stack, finds the
> topmost frame belonging to a C++ function and determines the next accessible trap point in it.  Then
> it arranges somehow that the execution stops there with a trap, and the trap handler raises a
> regular exception.
> 
> This plan has two obvious weak points:
> 
> 1. Until now I had no experience with fiddling stack frames and DWARF data in Linux.  I've got to
> read some specs and code; could you give a hint where to begin?

There's the ABI spec, but the main source of real knowledge is the unwinder
itself.

But in general, your plan cannot work in the presence of optimization.  The
compiler knows that only certain instructions may trap, and uses that
knowledge to direct optimization.  And, as the saying goes, "Do not lie
to gcc: it will bite you."  Doing things behind gcc's back is always to
invite disaster.

Apart from any other problems, gcc-generated code might not always even have a
valid stack from which in can unwind.

> 2. It's unclear how to make the program to trap at a prescribed location.  Temporarily modify the
> instruction?  Use the debugging registers?  Something else???
> 
> If you can give any helpful advices on these topics, you can be sure of an eternal appreciation and
> admiration from the discrete geometry community :-)
> 
> The "boundary constraints" for the solution are moderate:
> 
> 1. The signal handling may be slow and clumsy, but shouldn't affect the execution speed in the
> uninterrupted case (like the current try & catch implementation in GCC).
> 
> 2. It should run under modern Linux kernels on Intel/AMD platforms.  MacOS and FreeBSD would be nice
> to have, but this can wait.
> 
> 3. The code to be interrupted is either self-compiled (hence with full control over compiler options
> etc.) or is a standard library - no third-party black boxes built by unknown compilers with unknown
> options.

The fastest trick is do do what Sun's Java does: have a special page in memory.

volatile int *my_page = mmap one page;

In your loops, do this:

int foo = *my_page;

When you need to interrupt a loop, turn off read access to that page.
You'll get a segfault from which you can throw an exception.  This is
safe when compiling with -fnon-call-exceptions.

This is AFAIK the least intrusive thing you can do.

Andrew.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]