Browse Source

Code issues notes on setjmp/longjmp and volatile

pull/113/head
Sami Vaarala 10 years ago
parent
commit
f376233870
  1. 70
      doc/code-issues.rst

70
doc/code-issues.rst

@ -1043,6 +1043,76 @@ EBCDIC
See separate section below.
Setjmp, longjmp, and volatile
=============================
When a local variable in the function containing a ``setjmp()`` gets changed
between ``setjmp()`` and ``longjmp()`` there is no guarantee that the change
is visible after a ``longjmp()`` unless the variable is declared volatile.
It should be safe to:
* Use non-volatile variables that are written before ``setjmp()`` and then
only read.
* Use volatile variables which can be read and written at any point.
When pointer values are changed, be careful with placement of "volatile"::
/* Non-volatile pointer, which points to a volatile integer. */
volatile int *ptr_x;
/* Volatile pointer, which points to a non-volatile integer. */
int * volatile x;
When a pointer itself may be reassigned, the latter is correct, e.g.::
duk_hthread * volatile curr_thread;
curr_thread = thr;
In practice it seems that some compilers have trouble guaranteeing these
semantics for variables that are assigned to before ``setjmp()`` and not
changed before ``longjmp()``. For instance, there are crashes on OSX when
using ``_setjmp()`` in such cases. These crashes can be eliminated by
declaring the variables volatile. (It might be that adding the "volatile"
changes the compiler output enough to mask a different bug though.)
Optimizations may also cause odd situations, see e.g.:
* http://blog.sam.liddicott.com/2013/09/why-are-setjmp-volatile-hacks-still.html
To minimize the chances of the compiler handling setjmp/longjmp incorrectly,
the cleanest approach would probable be to:
* Declare all variables used in the ``setjmp()`` non-zero return case (when
called through ``longjmp()``) as volatile, so that we don't ever rely on
non-volatile variable values in that code path.
Because volatile variables are slow (explicit read/write operations are
generated for each access) it may be more practical to use explicit "save"
variables, e.g.::
volatile int save_x;
int x;
if (setjmp(...)) {
x = save_x;
/* use 'x' normally */
return;
}
/* Assume foo(), bar(), quux() never longjmp(). */
x = foo();
x += bar();
x += quux();
save_x = x; /* Save before any potential longjmp(). */
/* ... */
(As of Duktape 1.1 this has not yet been done for all setjmp/longjmp
functions. Rather, volatile declarations have been added where they
seem to be needed in practice.)
Numeric types
=============

Loading…
Cancel
Save