Additional memory handler features.
David M. Warme
David at Warme.net
Mon Jan 5 04:09:57 UTC 2015
I completely agree with Niel's assessment of Victor's options (1) - (4)
for handling errors.
Recall the following from Torbjörn's original post:
> There are real scenarios where one would want different sets of
> allocation functions. E.g., many libraries use GMP. Some of them have
> their own error reporting mechanisms, and memory handles. But then the
> user might use GMP directly, or she might from the same program use
> several libraries which use GMP. The current GMP memory allocation
> mechanism is not suitable here.
Correct. Single global pointer -- bothersome to share in a multi-library
context, impossible to share in a multi-library + multi-threaded context.
> [Torbjörn]
> I am not too fond of these global pointers. It would be better design
> to refer the memory handling and error handling functions from each GMP
> user variable, akin to object oriented languages' vtables. Except that
> this would make these small structures 3 times larger.
> ...
> That would cost a lot in cache load for applications which e.g. use
> arrays of GMP numbers.
I use large (potentially huge) arrays of GMP numbers, and would suffer
greatly from such a design choice. This is why I entered the discussion.
This is a poor resource utilization trade-off -- i.e., making these objects
3 times larger for functionality that is executed very rarely (if at all)
in normal operation. It is still a poor trade-off at 25% overhead,
and perhaps even at 4 bits if the main functionality suffers too much.
> [Niels]
> I think we should also keep in mind other types of exceptions than those
> provided by C++, e.g., guile exceptions or objc exceptions.
>
> I'd strongly prefer if we can define an interface for error handling and
> clean up temporary storage which works fine if gmp is compiled as plain
> C, and is language agnostic, e.g., based on memory pools. But if that
> turns out to be too difficult, I guess it's not too unreasonable to have
> proper cleanup on C++ exceptions require that gmp is compiled with a C++
> compiler.
I agree completely. While I do not mind compiling GMP as C++ code, I
vigorously reject the recent suggestion of migrating GMP toward a "C++ only"
code base. There is too much C code out there that uses GMP, mine included.
Although it is relatively simple for C++ to call a C library, the reverse is
indescribably ugly, difficult and non-portable.
> [Niels]
> I'd strongly prefer if we can define an interface for error handling and
> clean up temporary storage which works fine if gmp is compiled as plain
> C, and is language agnostic...
Consider my "dynamically scoped" exception handler example -- upon further
reflection, I realize that it is "possible" to implement this completely
outside of GMP using only a single static function pointer that GMP invokes
to report exceptions. This would even work in a multi-threaded context.
[The handler record resides in the application's stack frame, and the
signal raising/propagation loop resides in the application's handler
function invoked via pointer from GMP.]
The reason you would want to build it all into GMP is to address Torbjörn's
"several libraries" requirement. If this is built into GMP, then every
well-behaved library that uses GMP will choose to receive exceptions using
dynamically-scoped handlers, and the "handler of last resort" can/should be
set by the top-level application. This works well even in contexts that are
both multi-library and multi-threaded.
If you don't build it into GMP, there would be no standard for libraries
and applications to adhere to and each library would still fight over the
global function pointer -- and it wouldn't work at all if you add multiple
threads to the mix.
The cost of this mechanism (both in space and time) yields an efficient
utilization of resources, especially for a mechanism that is almost never
used under normal conditions.
One piece missing from my example code: a GMP "longjmp cleanup" function
that takes a prospective "jmp_buf *" as an argument. It would perform
cleanup / popping of both the stack temporaries, and pop any intervening
handler records (while possibly delivering "unwind-protect" exceptions)
from the dynamic chain. Applications could call this before doing
longjmp(). It would take care of the platform-dependent problem of
choosing how far to traverse/pop each chain (TMP_ALLOC and exception).
Details of what to pass to the handler (and how) are an independent issue.
A proposal, based on Unix/Linux signal handler interface:
- An integer code indicating the type of exception (#define's in gmp.h).
- A pointer to the "struct gmp_exception_handler_record" whose handler
is being invoked (NULL when invoking the static pointer handler).
The user can embed her gmp_exception_handler_record inside of a larger
structure in the stack frame. The handler can know this and use it
to gain access to arbitrary local state -- even cleanup when handling
unwind-protect "exceptions".
- A "void *" pointer to info provided by the context raising the
exception. Structure and interpretation of this data depend
upon the integer code. At the very least it should describe the
problem and include a pointer to the offending GMP object(s).
Various flavors of structure, defined in gmp.h.
The above framework could achieve Niels' stated objectives.
Option (1) is of course trivial. Victor could write C wrappers
around each GMP function using these mechanisms to obtain his option (2).
It also allows option (4).
Option (3): compile GMP as C++. But it might also be an interesting
exercise to see if these mechanisms can be used to translate "raw C"
GMP exceptions into corresponding C++ exceptions. This is probably
already done for certain OS signals (SIGFPE, etc.).
David
More information about the gmp-devel
mailing list