[m-dev.] ODBC interface
Simon Taylor
stayl at cs.mu.oz.au
Thu Oct 2 10:38:03 AEST 1997
Hi Fergus,
> But restoring hp -- is that safe?
> I guess so, but you should document that any heap memory
> allocated between the MR_setjmp() and the MR_longjmp()
> will not be valid after the MR_longjmp() call.
> [Or alternatively we could leave it up to the call to save/restore
> hp -- again you should document that it is the caller's responsibility
> to do this.]
Leaving it to the caller is probably best. On an exception the caller
will probably want to copy out some data (e.g. error messages) before
reclaiming the memory.
> In addition, with the new implementation of builtin_aggregate(),
> the heap and the solutions_heap may have been swapped.
> If so, then they need to be unswapped.
> Perhaps the simplest way of handling this is to also save/restore
> solutions_heap_pointer, heap_zone, and solutions_heap_zone.
This can be left up to the caller as well. It isn't a problem
for the ODBC interface since the threaded odbc__states ensure
that an exception can't happen within builtin_aggregate.
> For grades that support trailing, we also need to save/restore
> MR_trail_ptr and MR_ticket_counter.
Is just saving and restoring the pointers OK, or should it try to
unwind the trail on an exception?
> > odbc__rollback(Error) -->
> > odbc__add_message(error(user_requested_rollback) - Error),
> > odbc__throw.
>
> Oh-oh, here you are allocating memory on the heap before a throw,
> and expecting that data to persist after the throw.
> This will only work in conservative-gc grades.
> You should document that.
This is already pretty well documented:
% This requires a compilation grade with conservative garbage
% collection. Any grade containing .gc in its name, such as asm_fast.gc,
% will do. See the section "Compilation model options" in the Mercury
% User's Guide for more information.
%
and also:
/*
** odbc.m allocates memory within may_call_mercury pragma C code,
** which is a bit dodgy in non-GC grades. Allowing non-GC grades would
** require a bit of fairly error-prone code to save/restore the heap
** pointer in the right places. When accurate garbage collection is
** implemented and a nicer way of allocating heap space from within
** C code is available, this should be revisited.
*/
#ifndef CONSERVATIVE_GC
#error The OBDC interface requires conservative garbage collection. \\
Use a compilation grade containing .gc.
#endif /* ! CONSERVATIVE_GC */
Here's a diff compared to the versions I sent before:
===================================================================
RCS file: RCS/engine.h,v
retrieving revision 1.1
diff -u -r1.1 engine.h
--- engine.h 1997/10/01 23:05:06 1.1
+++ engine.h 1997/10/02 00:14:43
@@ -51,7 +51,8 @@
** to ensure that
** call C -> setjmp -> call Mercury -> call C -> longjmp
** works correctly. This is used by the exception handling code for
- ** the ODBC interface.
+ ** the ODBC interface, and probably shouldn't be used for anything
+ ** else.
*/
typedef struct {
@@ -62,11 +63,16 @@
** used by calls to setjmp and longjmp
*/
Word *saved_succip;
- Word *saved_hp;
Word *saved_sp;
Word *saved_curfr;
Word *saved_maxfr;
+ MR_IF_USE_TRAIL(Word *saved_trail_ptr;)
+ MR_IF_USE_TRAIL(Word *saved_ticket_counter;)
+
+#if NUM_REAL_REGS > 0
Word regs[NUM_REAL_REGS];
+#endif /* NUM_REAL_REGS > 0 */
+
} MR_jmp_buf;
/*
@@ -74,39 +80,51 @@
**
** Save MR_engine_jmp_buf, save the Mercury state, call setjmp(env),
** then fall through.
+ **
** When setjmp returns via a call to longjmp, control will pass to
** longjmp_label.
- ** Note that the Mercury registers must be valid before the call
- ** to MR_setjmp.
+ **
+ ** Notes:
+ ** - The Mercury registers must be valid before the call to MR_setjmp.
+ ** - The general-purpose registers r1, r2... are not restored and must
+ ** be saved by the caller.
+ ** - In grades without conservative garbage collection, the caller
+ ** must save and restore hp, solutions_heap_pointer, heap_zone
+ ** and solutions_heap_zone.
*/
#define MR_setjmp(setjmp_env, longjmp_label) \
do { \
(setjmp_env)->mercury_env = MR_engine_jmp_buf; \
save_regs_to_mem((setjmp_env)->regs); \
(setjmp_env)->saved_succip = succip; \
- (setjmp_env)->saved_hp = hp; \
(setjmp_env)->saved_sp = sp; \
(setjmp_env)->saved_curfr = curfr; \
(setjmp_env)->saved_maxfr = maxfr; \
+ MR_IF_USE_TRAIL((setjmp_env)->saved_trail_ptr = \
+ MR_trail_ptr); \
+ MR_IF_USE_TRAIL((setjmp_env)->saved_ticket_counter = \
+ MR_ticket_counter); \
if (setjmp((setjmp_env)->env)) { \
MR_engine_jmp_buf = (setjmp_env)->mercury_env; \
restore_regs_from_mem((setjmp_env)->regs); \
succip = (setjmp_env)->saved_succip; \
- hp = (setjmp_env)->saved_hp; \
sp = (setjmp_env)->saved_sp; \
curfr = (setjmp_env)->saved_curfr; \
maxfr = (setjmp_env)->saved_maxfr; \
+ MR_IF_USE_TRAIL(MR_trail_ptr = \
+ (setjmp_env)->saved_trail_ptr); \
+ MR_IF_USE_TRAIL(MR_ticket_counter = \
+ (setjmp_env)->saved_ticket_counter); \
goto longjmp_label; \
} \
} while (0)
/*
- ** MR_longjmp(MR_jmp_buf *env, int return)
- **
- ** Reset MR_engine_jmp_buf to the value stored in env, restore the
- ** Mercury registers, then call longjmp().
+ ** MR_longjmp(MR_jmp_buf *env)
+ **
+ ** Call longjmp(), MR_setjmp() will handle the rest.
*/
-#define MR_longjmp(setjmp_env, ret) longjmp((setjmp_env)->env, ret)
+#define MR_longjmp(setjmp_env) longjmp((setjmp_env)->env, 1)
/*
** engine_jmp_buf should only be referred to in engine.c
Index: mercury_trail.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_trail.h,v
retrieving revision 1.10
diff -u -r1.10 mercury_trail.h
--- mercury_trail.h 1997/09/23 16:47:44 1.10
+++ mercury_trail.h 1997/10/02 00:11:58
@@ -16,6 +16,12 @@
#include "memory.h"
+#ifdef MR_USE_TRAIL
+#define MR_IF_USE_TRAIL(x) x
+#else /* ! MR_USE_TRAIL */
+#define MR_IF_USE_TRAIL(x)
+#endif /* ! MR_USE_TRAIL */
+
/*---------------------------------------------------------------------------*/
/*
** The following macros define how to store and retrieve a 'ticket' -
===================================================================
RCS file: RCS/odbc.m,v
retrieving revision 1.4
diff -u -r1.4 odbc.m
--- odbc.m 1997/10/01 23:05:23 1.4
+++ odbc.m 1997/10/01 23:59:56
@@ -23,7 +23,7 @@
% Notes:
%
% Binary data is converted to a string of hexadecimal digits.
-
+%
% This requires a compilation grade with conservative garbage
% collection. Any grade containing .gc in its name, such as asm_fast.gc,
% will do. See the section "Compilation model options" in the Mercury
@@ -275,11 +275,14 @@
/*
** odbc.m allocates memory within may_call_mercury pragma C code,
- ** which is a bit dodgy in non-GC grades. Allowing non-GC grades would
- ** require a bit of fairly error-prone code to save/restore the heap
- ** pointer in the right places. When accurate garbage collection is
- ** implemented and a nicer way of allocating heap space from within
- ** C code is available, this should be revisited.
+ ** which is a bit dodgy in non-conservative GC grades.
+ ** Allowing non-convservative GC grades would require a bit of fairly
+ ** error-prone code to save/restore the heap pointer in the right
+ ** places. When accurate garbage collection is implemented and a
+ ** nicer way of allocating heap space from within C code is available,
+ ** this should be revisited.
+ ** Conservative garbage collection also makes restoring the state
+ ** after an exception a bit simpler.
*/
#ifndef CONSERVATIVE_GC
#error The OBDC interface requires conservative garbage collection. \\
@@ -343,13 +346,14 @@
** handling. We need to use MR_setjmp and MR_longjmp because we'll
** be longjmping across C->Mercury calls, so we need to restore
** some state in runtime/engine.c.
- ** Beware: the Mercury registers must be valid
- ** when odbc_catch is called.
+ ** Beware: the Mercury registers must be valid when odbc_catch
+ ** is called. odbc_throw will clobber the general-purpose registers
+ ** r1, r2, etc.
*/
#define odbc_catch(longjmp_label) \
MR_setjmp(&odbc_trans_jmp_buf, longjmp_label)
-#define odbc_throw() MR_longjmp(&odbc_trans_jmp_buf, 1)
+#define odbc_throw() MR_longjmp(&odbc_trans_jmp_buf)
/*
** odbc_trans_jmp_buf stores information saved by odbc_catch (setjmp)
@@ -432,6 +436,10 @@
/*
** The Mercury registers must be valid at the call to odbc_catch
** in odbc_transaction_c_code().
+ ** odbc_transaction_c_code() may clobber the Mercury general-purpose
+ ** registers r1, r2, ..., but that is OK, because this C code is
+ ** declared as 'may_call_mercury', so the compiler assumes that it
+ ** is allowed to clobber those registers.
*/
save_transient_registers();
odbc_transaction_c_code(TypeInfo_for_T, Connection, Closure,
===================================================================
RCS file: RCS/odbc_test.m,v
retrieving revision 1.1
diff -u -r1.1 odbc_test.m
--- odbc_test.m 1997/10/01 23:05:23 1.1
+++ odbc_test.m 1997/10/02 00:24:24
@@ -72,17 +72,18 @@
odbc__state::di, odbc__state::uo) is det.
test_trans(Results) -->
- { String = "select * from test" },
- odbc__execute(String, Results).
+ odbc__execute("select * from test", Results).
:- pred output_results(list(odbc__row)::in,
io__state::di, io__state::uo) is det.
output_results(Rows) -->
- { WriteRow = lambda([Row::in, IO0::di, IO::uo] is det, (
- io__write_list(Row, " ", output_attribute, IO0, IO)
- )) },
- io__write_list(Rows, "\n", WriteRow).
+ io__write_list(Rows, "\n", output_row).
+
+:- pred output_row(odbc__row::in, io__state::di, io__state::uo) is det.
+
+output_row(Row) -->
+ io__write_list(Row, " ", output_attribute).
:- pred output_attribute(odbc__attribute::in,
io__state::di, io__state::uo) is det.
Simon.
More information about the developers
mailing list