[GRASS-dev] Using GRASS in long running and multithreaded applications Was: Re: The tomcat shut down ...

Glynn Clements glynn at gclements.plus.com
Thu Oct 1 14:44:20 EDT 2009

Soeren Gebbert wrote:

> After reading some documentation and asking "silly" questions to
> my poor informatics colleagues, i understand the concept of thread local and
> the setjmp()/longjmp() approach a bit better.
> I would suggest to add longjmp() to G_fatal_error().
> It should be set at runtime by an application if longjmp() should be
> chosen or not.
> So G_fatal_error() will either call longjmp() or exit().

There's no need to modify G_fatal_error(). The application can install
an error handler with G_set_error_routine(), and the error handler can
use longjmp() to avoid returning.

> The linux threaded errno definition scared me, so i have chosen a
> different approach.
> We define thread local support and two extern variables in gis.h to
> choose at runtime if
> G_fatal_error() will call exit() or longjmp() and to add thread local support.
> Example which works for me in my test code:
> /*Thread local and setjmp() exception support*/
> #include <setjmp.h>
> #ifdef WIN32
> #define Thread   __declspec( thread )
> #else
> #define Thread   __thread
> #endif

The __thread qualifier is a gcc extension.

> extern Thread jmp_buf G_stack_buffer;    /*to save the most important
> CPU register for each thread*/

In order to use a GRASS library from multiple threads, the entire
library state needs to be thread-specific. That would include the
current error handler.

Also: do you actually need to resume a thread in which an error
occurs? If not, you can just make the error handler terminate the
current thread. That will prevent the error handler from returning and
thus prevent exit() being called.

> Is this approach ok or to simple or just naive? :)

It's too invasive. The longjmp() should go into an application-defined
error handler, rather than the GRASS libraries.

The only changes to the GRASS libraries regarding error handling
should be to ensure that it is safe to continue using them after the
application recovers from a fatal error.

Supporting thread-local state requires some changes to the GRASS
libraries, i.e. moving most[1] static variables for a library into a
state structure, and referencing all such variables through a pointer.

[1] Some variables will contain immutable data, e.g. tables which are
read from files. These don't need to be initialised for each thread,
although concurrent initialisation has to be protected against.

> If this is ok, i would like to test this approach to identify possible
> nested setjmp()/longjmp()
> calls in libgis, libraster and libvector.

I'd prefer to avoid putting any setjmp()s into the GRASS libraries. 
I'd rather see low-level functions split into an "internal" version
which returns an error status, and a "public" version which calls
G_fatal_error(), and have intermediate functions use the internal
version if they need to catch errors.

Ultimately, the GRASS libraries exist for the benefit of GRASS
modules. Minor changes to facilitate other uses (e.g. persistent
applications) are reasonable, but I'm opposed to substantial
architectural changes, particularly if it makes the coding process
more complex.

Glynn Clements <glynn at gclements.plus.com>

More information about the grass-dev mailing list