nothrow function callbacks in extern(C) code - solution

Rainer Schuetze via Digitalmars-d digitalmars-d at puremagic.com
Fri Jun 20 03:14:51 PDT 2014



On 19.06.2014 21:59, Walter Bright wrote:
> With nothrow and @nogc annotations, we've been motivated to add these
> annotations to C system API functions, because obviously such functions
> aren't going to throw D exceptions or call the D garbage collector.
>
> But this exposed a problem - functions like C's qsort() take a pointer
> to a callback function. The callback function, being supplied by the D
> programmer, may throw and may call the garbage collector. By requiring
> the callback function to be also nothrow @nogc, this is an unreasonable
> requirement besides breaking most existing D code that uses qsort().
>
> This problem applies as well to the Windows APIs and the Posix APIs with
> callbacks.
>
> The solution is to use overloading so that if your callback is nothrow,
> it will call the nothrow version of qsort, if it is throwable, it calls
> the throwable version of qsort.
>
> Never mind that those two versions of qsort are actually the same
> function (!), even though D's type system regards them as different.
> Although this looks like an usafe hack, it actually is quite safe,
> presuming that the rest of the qsort code itself does not throw. This
> technique relies on the fact that extern(C) functions do not get their
> types mangled into the names.
>
> Some example code:
>
>    extern (C)         { alias int function() fp_t; }
>    extern (C) nothrow { alias int function() fpnothrow_t; }
>
>    extern (C)         int foo(int a, fp_t fp);
>    extern (C) nothrow int foo(int a, fpnothrow_t fp);
>
>    extern (C)         int bar();
>    extern (C) nothrow int barnothrow();
>
>    void test() {
>      foo(1, &bar);         // calls the 'throwing' foo()
>      foo(1, &barnothrow);  // calls the 'nothrow' foo()
>    }

This only works for those functions that call the callback function 
directly.

OS function do not always work this way. They register callbacks for 
later use like a windows procedure or a signal handler.

This causes innocent looking functions to not behave as annotated 
because they internally use the callback functions. E.g. a lot of the 
Windows API functions might use message sending/dispatching internally, 
which might execute both throwing or GC allocating callbacks. These are 
currently not meeting the promise of their annotations.

We either have to be more conservative with annotating OS functions or 
relax the guarantees of nothrow or @nogc. Both alternatives are not very 
compelling.


More information about the Digitalmars-d mailing list