diff --git a/mps/code/abqtest.c b/mps/code/abqtest.c index 7de0ee537a7..df9953e8585 100644 --- a/mps/code/abqtest.c +++ b/mps/code/abqtest.c @@ -10,6 +10,7 @@ #include "mps.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include #include #include "mpstd.h" @@ -153,6 +154,7 @@ extern int main(int argc, char *argv[]) int i; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); abqSize = 0; diff --git a/mps/code/amcss.c b/mps/code/amcss.c index ee91223660f..e3bb32627eb 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -8,6 +8,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" @@ -15,6 +16,7 @@ #include "mpsw3.h" #endif #include "mps.h" +#include "mpslib.h" #include #include @@ -305,7 +307,8 @@ int main(int argc, char *argv[]) mps_thr_t thread; randomize(argc, argv); - + mps_lib_assert_fail_install(assert_die); + die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE), "arena_create"); mps_message_type_enable(arena, mps_message_type_gc()); diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c index ee8d9edbeb4..1198f8be978 100644 --- a/mps/code/amcsshe.c +++ b/mps/code/amcsshe.c @@ -8,6 +8,7 @@ #include "fmthe.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" @@ -261,6 +262,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), 3*testArenaSIZE), "arena_create\n"); diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index e5ed673c80c..5fc28728247 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -12,6 +12,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" #include @@ -320,6 +321,7 @@ int main(int argc, char *argv[]) int childIsFinished = 0; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); diff --git a/mps/code/amsss.c b/mps/code/amsss.c index 29f0aa47e3b..657faebe3b3 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -11,6 +11,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscams.h" #include "mpsavm.h" #include "mpstd.h" @@ -207,6 +208,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); diff --git a/mps/code/amssshe.c b/mps/code/amssshe.c index 29a9fd2ebbf..ddbda607017 100644 --- a/mps/code/amssshe.c +++ b/mps/code/amssshe.c @@ -9,6 +9,7 @@ #include "fmthe.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscams.h" #include "mpsavm.h" #include "mpstd.h" @@ -162,6 +163,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); diff --git a/mps/code/apss.c b/mps/code/apss.c index 3fcc7388437..9199d776ef6 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -12,6 +12,7 @@ #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include #include @@ -179,6 +180,7 @@ int main(int argc, char *argv[]) bothOptions = MPS_PF_ALIGN == 8 ? &bothOptions8 : &bothOptions16; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE), "mps_arena_create"); diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c index e837a596767..b0ea6c08040 100644 --- a/mps/code/arenacv.c +++ b/mps/code/arenacv.c @@ -19,6 +19,7 @@ #include "mpm.h" #include "poolmv.h" #include "testlib.h" +#include "mpslib.h" #include "mpsavm.h" #include "mpsacl.h" diff --git a/mps/code/awlut.c b/mps/code/awlut.c index 35036b2cbaf..7e417c18658 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -13,6 +13,7 @@ #include "mpsavm.h" #include "fmtdy.h" #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpstd.h" #ifdef MPS_OS_W3 @@ -306,6 +307,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); initialise_wrapper(wrapper_wrapper); initialise_wrapper(string_wrapper); diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c index 7ee5a0c077c..a0d2bf85ab9 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -14,6 +14,7 @@ #include "fmthe.h" #include "fmtdy.h" #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpstd.h" #ifdef MPS_OS_W3 @@ -305,6 +306,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); initialise_wrapper(wrapper_wrapper); initialise_wrapper(string_wrapper); diff --git a/mps/code/awlutth.c b/mps/code/awlutth.c index cfe94ea7ca3..2dc59698312 100644 --- a/mps/code/awlutth.c +++ b/mps/code/awlutth.c @@ -13,6 +13,7 @@ #include "mpsavm.h" #include "fmtdy.h" #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpstd.h" #ifdef MPS_OS_W3 @@ -315,6 +316,7 @@ int main(int argc, char *argv[]) pthread_t pthread1; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); initialise_wrapper(wrapper_wrapper); initialise_wrapper(string_wrapper); diff --git a/mps/code/btcv.c b/mps/code/btcv.c index b119a217d5d..72256a5f693 100644 --- a/mps/code/btcv.c +++ b/mps/code/btcv.c @@ -16,6 +16,7 @@ #include "mpsavm.h" #include "mps.h" #include "testlib.h" +#include "mpslib.h" #include diff --git a/mps/code/bttest.c b/mps/code/bttest.c index c119fe70a34..165a4fd1cba 100644 --- a/mps/code/bttest.c +++ b/mps/code/bttest.c @@ -9,6 +9,7 @@ #include "mps.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include #include diff --git a/mps/code/cbstest.c b/mps/code/cbstest.c index cb5744238dc..c213ce9cee0 100644 --- a/mps/code/cbstest.c +++ b/mps/code/cbstest.c @@ -9,6 +9,7 @@ #include "mpsavm.h" #include "mps.h" #include "testlib.h" +#include "mpslib.h" #include #include @@ -574,6 +575,7 @@ extern int main(int argc, char *argv[]) CBSFindDelete findDelete = CBSFindDeleteNONE; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); NAllocateTried = NAllocateSucceeded = NDeallocateTried = NDeallocateSucceeded = NNewBlocks = NDeleteBlocks = diff --git a/mps/code/check.h b/mps/code/check.h index 58e62255102..1f03c72f300 100644 --- a/mps/code/check.h +++ b/mps/code/check.h @@ -52,7 +52,7 @@ #define ASSERT(cond, condstring) \ BEGIN \ if (cond) NOOP; else \ - mps_lib_assert_fail(condstring "\n" __FILE__ "\n" STR(__LINE__)); \ + mps_lib_assert_fail(__FILE__ , __LINE__, (condstring)); \ END #define ASSERT_TYPECHECK(type, val) \ @@ -158,7 +158,7 @@ extern unsigned CheckLevel; #define NOTREACHED \ BEGIN \ - mps_lib_assert_fail("unreachable code" "\n" __FILE__ "\n" STR(__LINE__)); \ + mps_lib_assert_fail(__FILE__, __LINE__, "unreachable code"); \ END #endif diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 5ae4ffb49aa..47c66943164 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -130,7 +130,7 @@ CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) # %%VARIETY: When adding a new variety, define a macro containing the flags # for the new variety LINKER = link -LINKFLAGSCOMMON = /nologo +LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE LINKFLAGSINTERNAL = /DEBUG # ( Internal flags used to be set to /DEBUG:full ) LINKFLAGSEXTERNAL = /RELEASE diff --git a/mps/code/config.h b/mps/code/config.h index fefd57ed266..37741355502 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -48,6 +48,7 @@ #elif defined(CONFIG_VAR_DIAG) /* Diagnostic variety */ #define CONFIG_ASSERT +#define CONFIG_ASSERT_ABORT #ifndef CHECKLEVEL #define CHECKLEVEL CheckLevelMINIMAL #endif @@ -72,6 +73,7 @@ #elif defined(CONFIG_VAR_COOL) #define CONFIG_ASSERT #define CONFIG_ASSERT_ALL +#define CONFIG_ASSERT_ABORT #define CONFIG_STATS #ifndef CHECKLEVEL #define CHECKLEVEL CheckLevelSHALLOW @@ -91,6 +93,7 @@ /* #elif defined(CONFIG_VAR_HOT) */ #define CONFIG_ASSERT +/* Note, not CONFIG_ASSERT_ABORT */ #ifndef CHECKLEVEL #define CHECKLEVEL CheckLevelMINIMAL #endif @@ -117,6 +120,11 @@ #define AVER_AND_CHECK_NONE #define MPS_ASSERT_STRING "nonasserted" #endif +#if defined(CONFIG_ASSERT_ABORT) +#define ASSERT_ABORT() abort() +#else +#define ASSERT_ABORT() NOOP +#endif #if defined(CONFIG_STATS) diff --git a/mps/code/event.c b/mps/code/event.c index 96e78b24061..4afa03c63ab 100644 --- a/mps/code/event.c +++ b/mps/code/event.c @@ -40,9 +40,12 @@ static Serial EventInternSerial; /* Buffers in which events are recorded, from the top down. */ char EventBuffer[EventKindLIMIT][EventBufferSIZE]; -/* Pointers to last written event in each buffer. */ +/* Pointers to last event logged into each buffer. */ char *EventLast[EventKindLIMIT]; +/* Pointers to the last even written out of each buffer. */ +char *EventWritten[EventKindLIMIT]; + EventControlSet EventKindControl; /* Bit set used to control output. */ @@ -71,65 +74,24 @@ failWrite: return res; } -/* EventFlush -- flush event buffer to the event stream */ -Res EventFlush(EventKind kind) +/* EventFlush -- flush event buffer (perhaps to the event stream) */ + +void EventFlush(EventKind kind) { - Res res; - size_t size; - AVER(eventInited); AVER(0 <= kind && kind < EventKindLIMIT); AVER(EventBuffer[kind] <= EventLast[kind]); - AVER(EventLast[kind] <= EventBuffer[kind] + EventBufferSIZE); + AVER(EventLast[kind] <= EventWritten[kind]); + AVER(EventWritten[kind] <= EventBuffer[kind] + EventBufferSIZE); - /* Is event logging enabled for this kind of event, or are or are we just - writing to the buffer for backtraces, cores, and other debugging? */ - if (BS_IS_MEMBER(EventKindControl, kind)) { - - size = (size_t)(EventBuffer[kind] + EventBufferSIZE - EventLast[kind]); - - /* Checking the size avoids creating the event stream when the arena is - destroyed and no events have been logged. */ - if (size == 0) - return ResOK; - - /* Ensure the IO stream is open. We do this late so that no stream is - created if no events are enabled by telemetry control. */ - if (!eventIOInited) { - res = (Res)mps_io_create(&eventIO); - if(res != ResOK) - goto failCreate; - eventIOInited = TRUE; - } + /* Send all pending events to the event stream. */ + EventSync(); - /* Send an EventClockSync event */ - res = eventClockSync(); - if (res != ResOK) - goto failClockSync; - - /* Writing might be faster if the size is aligned to a multiple of the - C library or kernel's buffer size. We could pad out the buffer with - a marker for this purpose. */ - - res = (Res)mps_io_write(eventIO, (void *)EventLast[kind], size); - if (res != ResOK) - goto failWrite; - - } - - res = ResOK; - -failClockSync: -failWrite: -failCreate: - - /* Flush the in-memory buffer whether or not we succeeded, so that we can - record recent events there. */ - EventLast[kind] = EventBuffer[kind] + EventBufferSIZE; - - return res; + /* Flush the in-memory buffer whether or not we send this buffer, so + that we can continue to record recent events. */ + EventLast[kind] = EventWritten[kind] = EventBuffer[kind] + EventBufferSIZE; } @@ -138,8 +100,52 @@ failCreate: void EventSync(void) { EventKind kind; - for (kind = 0; kind < EventKindLIMIT; ++kind) - (void)EventFlush(kind); + Bool wrote = FALSE; + + for (kind = 0; kind < EventKindLIMIT; ++kind) { + + /* Is event logging enabled for this kind of event, or are or are we just + writing to the buffer for backtraces, cores, and other debugging? */ + if (BS_IS_MEMBER(EventKindControl, kind)) { + size_t size; + Res res; + + AVER(EventBuffer[kind] <= EventLast[kind]); + AVER(EventLast[kind] <= EventWritten[kind]); + AVER(EventWritten[kind] <= EventBuffer[kind] + EventBufferSIZE); + + size = (size_t)(EventWritten[kind] - EventLast[kind]); + if (size > 0) { + + /* Ensure the IO stream is open. We do this late so that no stream is + created if no events are enabled by telemetry control. */ + if (!eventIOInited) { + res = (Res)mps_io_create(&eventIO); + if(res != ResOK) { + /* TODO: Consider taking some other action if open fails. */ + return; + } + eventIOInited = TRUE; + } + + /* Writing might be faster if the size is aligned to a multiple of the + C library or kernel's buffer size. We could pad out the buffer with + a marker for this purpose. */ + + res = (Res)mps_io_write(eventIO, (void *)EventLast[kind], size); + if (res == ResOK) { + /* TODO: Consider taking some other action if a write fails. */ + EventWritten[kind] = EventLast[kind]; + wrote = TRUE; + } + } + } + } + + /* If we wrote out events, send an EventClockSync event */ + if (wrote) + (void)eventClockSync(); + (void)mps_io_flush(eventIO); } @@ -202,7 +208,8 @@ void EventInit(void) EventKind kind; for (kind = 0; kind < EventKindLIMIT; ++kind) { AVER(EventLast[kind] == NULL); - EventLast[kind] = EventBuffer[kind] + EventBufferSIZE; + AVER(EventWritten[kind] == NULL); + EventLast[kind] = EventWritten[kind] = EventBuffer[kind] + EventBufferSIZE; } eventUserCount = (Count)1; eventInited = TRUE; diff --git a/mps/code/event.h b/mps/code/event.h index c54193b367d..b16e2af4b9c 100644 --- a/mps/code/event.h +++ b/mps/code/event.h @@ -32,7 +32,7 @@ extern EventControlSet EventControl(EventControlSet resetMask, extern EventStringId EventInternString(const char *label); extern EventStringId EventInternGenString(size_t, const char *label); extern void EventLabelAddr(Addr addr, Word id); -extern Res EventFlush(EventKind kind); +extern void EventFlush(EventKind kind); extern Res EventDescribe(Event event, mps_lib_FILE *stream); extern Res EventWrite(Event event, mps_lib_FILE *stream); extern void EventDump(mps_lib_FILE *stream); diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 5c6c3b0f2e1..ca5609962f8 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -38,7 +38,7 @@ #define EVENT_VERSION_MAJOR ((unsigned)1) #define EVENT_VERSION_MEDIAN ((unsigned)1) -#define EVENT_VERSION_MINOR ((unsigned)3) +#define EVENT_VERSION_MINOR ((unsigned)4) /* EVENT_LIST -- list of event types and general properties @@ -99,8 +99,8 @@ EVENT(X, CBSInit , 0x0019, TRUE, Pool) \ EVENT(X, Intern , 0x001a, TRUE, User) \ EVENT(X, Label , 0x001b, TRUE, User) \ - /* EVENT(X, TraceStart , 0x001c, TRUE, Trace) */ \ - /* EVENT(X, TraceCreate , 0x001d, TRUE, Trace) */ \ + EVENT(X, TraceStart , 0x001c, TRUE, Trace) \ + EVENT(X, TraceCreate , 0x001d, TRUE, Trace) \ EVENT(X, TraceDestroy , 0x001e, TRUE, Trace) \ EVENT(X, SegSetGrey , 0x001f, TRUE, Seg) \ EVENT(X, TraceFlipBegin , 0x0020, TRUE, Trace) \ @@ -653,6 +653,22 @@ PARAM(X, 0, P, arena) \ PARAM(X, 1, B, emergency) +#define EVENT_TraceCreate_PARAMS(PARAM, X) \ + PARAM(X, 0, P, trace) /* trace that was created */ \ + PARAM(X, 1, P, arena) /* arena in which created */ \ + PARAM(X, 2, U, why) /* reason for creation */ + +#define EVENT_TraceStart_PARAMS(PARAM, X) \ + PARAM(X, 0, P, trace) /* trace being started */ \ + PARAM(X, 1, D, mortality) /* as passed to TraceStart */ \ + PARAM(X, 2, D, finishingTime) /* as passed to TraceStart */ \ + PARAM(X, 3, W, condemned) /* condemned bytes */ \ + PARAM(X, 4, W, notCondemned) /* collectible but not condemned bytes */ \ + PARAM(X, 5, W, foundation) /* foundation size */ \ + PARAM(X, 6, W, white) /* white reference set */ \ + PARAM(X, 7, W, rate) /* segs to scan per increment */ + + #endif /* eventdef_h */ /* C. COPYRIGHT AND LICENSE diff --git a/mps/code/exposet0.c b/mps/code/exposet0.c index 6cbf57488d8..8bc0a190d73 100644 --- a/mps/code/exposet0.c +++ b/mps/code/exposet0.c @@ -15,6 +15,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" @@ -255,6 +256,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE), "arena_create"); diff --git a/mps/code/expt825.c b/mps/code/expt825.c index 26e99aa63d8..e925583e486 100644 --- a/mps/code/expt825.c +++ b/mps/code/expt825.c @@ -27,6 +27,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpscamc.h" #include "mpsavm.h" diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c index 8380363350b..8236df4279b 100644 --- a/mps/code/finalcv.c +++ b/mps/code/finalcv.c @@ -19,6 +19,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpscamc.h" #include "mpsavm.h" @@ -217,6 +218,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create\n"); diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index 38acb455d0f..f5ef8a9a99f 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -17,6 +17,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpscamc.h" #include "mpsavm.h" diff --git a/mps/code/fmtdytst.c b/mps/code/fmtdytst.c index c98fc4b9f73..83ab1f4b81a 100644 --- a/mps/code/fmtdytst.c +++ b/mps/code/fmtdytst.c @@ -10,6 +10,7 @@ #include "fmtdytst.h" #include "mps.h" #include "testlib.h" +#include "mpslib.h" #include #include #include diff --git a/mps/code/libcbt.c b/mps/code/libcbt.c index 7c9897ec2e4..4c7bb3698b0 100644 --- a/mps/code/libcbt.c +++ b/mps/code/libcbt.c @@ -12,6 +12,7 @@ #include "mpslibcb.h" #include "testlib.h" +#include "mpslib.h" #include #include diff --git a/mps/code/locbwcss.c b/mps/code/locbwcss.c index 221d1cca856..a731bc47198 100644 --- a/mps/code/locbwcss.c +++ b/mps/code/locbwcss.c @@ -8,6 +8,7 @@ #include "mpslib.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include @@ -193,6 +194,7 @@ int main(int argc, char *argv[]) mps_arena_t arena; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vmnz(), testArenaSIZE), "mps_arena_create"); diff --git a/mps/code/lockcov.c b/mps/code/lockcov.c index 45aeb1189a0..28c398e4bba 100644 --- a/mps/code/lockcov.c +++ b/mps/code/lockcov.c @@ -6,6 +6,7 @@ #include "mpm.h" #include "testlib.h" +#include "mpslib.h" #include /* for malloc & free */ diff --git a/mps/code/lockutw3.c b/mps/code/lockutw3.c index 51a1206a37d..c66db7edd77 100644 --- a/mps/code/lockutw3.c +++ b/mps/code/lockutw3.c @@ -6,6 +6,7 @@ #include "mpm.h" #include "testlib.h" +#include "mpslib.h" #include "mpswin.h" diff --git a/mps/code/locusss.c b/mps/code/locusss.c index 81053608fbf..c9a86fa37dc 100644 --- a/mps/code/locusss.c +++ b/mps/code/locusss.c @@ -9,6 +9,7 @@ #include "mpslib.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include @@ -233,6 +234,7 @@ int main(int argc, char *argv[]) { randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); printf("\nRunning test with no information about peak usage.\n"); runArenaTest(smallArenaSize, FALSE, FALSE); diff --git a/mps/code/locv.c b/mps/code/locv.c index 2e906093e3f..29881f6c54e 100644 --- a/mps/code/locv.c +++ b/mps/code/locv.c @@ -8,6 +8,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpsclo.h" #include "mpsavm.h" diff --git a/mps/code/messtest.c b/mps/code/messtest.c index de60f93fdec..6382a54233f 100644 --- a/mps/code/messtest.c +++ b/mps/code/messtest.c @@ -8,6 +8,7 @@ #include "mpsavm.h" #include "mps.h" #include "testlib.h" +#include "mpslib.h" #include #include diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index 4cc85712946..83056fce707 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -10,6 +10,7 @@ #include "mpslib.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include #include @@ -188,6 +189,7 @@ int main(int argc, char *argv[]) bothOptions = MPS_PF_ALIGN == 8 ? &bothOptions8 : &bothOptions16; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index 2ddd4344c59..4a3c95abe83 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -6,6 +6,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" #include "mpscmv.h" @@ -582,6 +583,7 @@ int main(int argc, char *argv[]) void *marker = ▮ randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), TEST_ARENA_SIZE), "arena_create"); diff --git a/mps/code/mpslib.h b/mps/code/mpslib.h index f74bd986fa6..323cfa55f5c 100644 --- a/mps/code/mpslib.h +++ b/mps/code/mpslib.h @@ -16,30 +16,60 @@ #include #include "mps.h" /* mps_clock_t */ +/* Return the token that will be returned by I/O functions when the end + of file is reached. Analogous to `EOF` from stdio.h. */ extern int mps_lib_get_EOF(void); #define mps_lib_EOF (mps_lib_get_EOF()) +/* An anonymous structure type used to represent files. Analagous to + `FILE *` from stdio.h. */ typedef struct mps_lib_stream_s mps_lib_FILE; +/* Return the standard output and standard error streams. Analagous to + `stdout` and `stderr` from stdio.h. */ extern mps_lib_FILE *mps_lib_get_stderr(void); extern mps_lib_FILE *mps_lib_get_stdout(void); #define mps_lib_stderr (mps_lib_get_stderr()) #define mps_lib_stdout (mps_lib_get_stdout()) +/* Send a character or string to a stream. Analagous to `fputc` and `fputs` + from stdio.h. */ extern int mps_lib_fputc(int, mps_lib_FILE *); extern int mps_lib_fputs(const char *, mps_lib_FILE *); -extern void mps_lib_assert_fail(const char *); +/* Assertion handler. When the MPS detects an illegal condition, it calls + `mps_lib_assert_fail` with the source code filename, line number, and + a string representing the condition. That function should log or report + the condition, and preferably allow for debugging, though in a production + environment it can return and the MPS will attempt to continue, though + this may cause failure of the process soon after. */ +extern void mps_lib_assert_fail(const char *, unsigned, const char *); +/* The default ANSI plinth in mpsliban.c allows the assertion handler to be + replaced by passing a replacement to `mps_lib_assert_fail_install`, + which returns the previous handler. This is for convenience so that + a complete replacement plinth need not be supplied just to achieve the + same thing. The MPS itself does not use `mps_lib_assert_fail_install` + and so it need not be supplied by the plinth. */ +typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *); +extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t); + + +/* Set, copy, or compare memory. Analagous to `memset`, `memcpy`, and + `memcmp` from string.h. */ extern void *(mps_lib_memset)(void *, int, size_t); extern void *(mps_lib_memcpy)(void *, const void *, size_t); extern int (mps_lib_memcmp)(const void *, const void *, size_t); - +/* Return a measure of time since process start. Equivalent to `clock` + from time.h. */ extern mps_clock_t mps_clock(void); extern mps_clock_t mps_clocks_per_sec(void); +/* Return a telemetry control word from somewhere. This controls which kinds + of events get output to the telemetry stream. Each bit in the word + switches on the corresponding EventKind defined in eventcom.h. */ extern unsigned long mps_lib_telemetry_control(void); diff --git a/mps/code/mpsliban.c b/mps/code/mpsliban.c index deca56d630f..4ca88a7c7ed 100644 --- a/mps/code/mpsliban.c +++ b/mps/code/mpsliban.c @@ -66,13 +66,30 @@ int mps_lib_fputs(const char *s, mps_lib_FILE *stream) } -void mps_lib_assert_fail(const char *message) +static void mps_lib_assert_fail_default(const char *file, + unsigned line, + const char *condition) { fflush(stdout); /* synchronize */ - fprintf(stderr, "\nMPS ASSERTION FAILURE: %s\n\nRECENT EVENTS:\n", message); - EventDump((mps_lib_FILE *)stderr); + fprintf(stderr, "%s:%u: MPS ASSERTION FAILED: %s\n", file, line, condition); fflush(stderr); /* make sure the message is output */ - abort(); + ASSERT_ABORT(); /* see config.h */ +} + +static mps_lib_assert_fail_t mps_lib_assert_handler = mps_lib_assert_fail_default; + +void mps_lib_assert_fail(const char *file, + unsigned line, + const char *condition) +{ + mps_lib_assert_handler(file, line, condition); +} + +mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler) +{ + mps_lib_assert_fail_t old_handler = mps_lib_assert_handler; + mps_lib_assert_handler = handler; + return old_handler; } @@ -181,6 +198,7 @@ unsigned long mps_lib_telemetry_control(void) if (striequal(word, #name)) \ mask |= (1ul << EventKind##name); EventKindENUM(TELEMATCH, X) +#undef TELEMATCH } return mask; diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 823455abbd2..1558c9c18f2 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1146,6 +1146,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, amcGen gen; Serial genNr; SegPrefStruct segPrefStruct; + PoolGen pgen; AVERT(Pool, pool); amc = Pool2AMC(pool); @@ -1161,6 +1162,8 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, gen = amcBufGen(buffer); AVERT(amcGen, gen); + pgen = &gen->pgen; + /* Create and attach segment. The location of this segment is */ /* expressed as a generation number. We rely on the arena to */ /* organize locations appropriately. */ @@ -1168,7 +1171,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, alignedSize = SizeAlignUp(size, ArenaAlign(arena)); segPrefStruct = *SegPrefDefault(); SegPrefExpress(&segPrefStruct, SegPrefCollected, NULL); - genNr = PoolGenNr(&gen->pgen); + genNr = PoolGenNr(pgen); SegPrefExpress(&segPrefStruct, SegPrefGen, &genNr); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD_FIELD(args, amcKeySegType, p, &gen->type); /* .segtype */ @@ -1188,17 +1191,25 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, /* Put the segment in the generation indicated by the buffer. */ ++gen->segs; - gen->pgen.totalSize += alignedSize; - /* If ramping, don't count survivors in newSize. */ - if(amc->rampMode != RampRAMPING - || buffer != amc->rampGen->forward - || gen != amc->rampGen) + pgen->totalSize += alignedSize; + + /* If ramping, or if the buffer is a large proportion of the + * generation size, don't count it towards newSize. */ + + /* TODO: Find a better hack for this, which is really a work-around + * for a nasty problem in the collection scheduling strategy. + * See job003435. NB 2013-03-07. */ + + if((size < (pgen->chain->gens[genNr].capacity * 1024.0 / 4.0)) && + (amc->rampMode != RampRAMPING + || buffer != amc->rampGen->forward + || gen != amc->rampGen)) { - gen->pgen.newSize += alignedSize; + pgen->newSize += alignedSize; } else { Seg2amcSeg(seg)->new = FALSE; } - PoolGenUpdateZones(&gen->pgen, seg); + PoolGenUpdateZones(pgen, seg); base = SegBase(seg); *baseReturn = base; diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 68675722aa8..652a2ce52d3 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -351,7 +351,7 @@ static Bool AWLCanTrySingleAccess(Arena arena, AWL awl, Seg seg, Addr addr) if(AWLHaveTotalSALimit) { if(awl->succAccesses >= AWLTotalSALimit) { STATISTIC(awl->stats.declined++); - EVENT2(AWLDeclineTotal, seg, awl->succAccesses); + EVENT2(AWLDeclineTotal, seg, (EventFU)awl->succAccesses); return FALSE; /* decline single access because of total limit */ } } @@ -362,7 +362,7 @@ static Bool AWLCanTrySingleAccess(Arena arena, AWL awl, Seg seg, Addr addr) if(AWLHaveSegSALimit) { if(awlseg->singleAccesses >= AWLSegSALimit) { STATISTIC(awl->stats.declined++); - EVENT2(AWLDeclineSeg, seg, awlseg->singleAccesses); + EVENT2(AWLDeclineSeg, seg, (EventFU)awlseg->singleAccesses); return FALSE; /* decline single access because of segment limit */ } } diff --git a/mps/code/poolncv.c b/mps/code/poolncv.c index ef0b67eb75e..3df734a3df8 100644 --- a/mps/code/poolncv.c +++ b/mps/code/poolncv.c @@ -8,6 +8,7 @@ #include "pooln.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" static void testit(ArenaClass class, ArgList args) diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 72235a763a5..37d886644f6 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -44,7 +44,6 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) LONG WINAPI ProtSEHfilter(LPEXCEPTION_POINTERS info) { LPEXCEPTION_RECORD er; - ULONG_PTR iswrite; ULONG_PTR address; AccessSet mode; Addr base, limit; @@ -68,15 +67,22 @@ LONG WINAPI ProtSEHfilter(LPEXCEPTION_POINTERS info) AVER(er->NumberParameters >= 2); - iswrite = er->ExceptionInformation[0]; /* 0 read; 1 write */ - AVER(iswrite == 0 || iswrite == 1); - - /* Pages cannot be made write-only, so an attempt to write must - * also cause a read-access if necessary */ - if(iswrite) - mode = AccessREAD | AccessWRITE; - else + switch (er->ExceptionInformation[0]) { + case 0: /* read */ + case 8: /* execute */ mode = AccessREAD; + break; + case 1: /* write */ + /* Pages cannot be made write-only, so an attempt to write must + also cause a read-access if necessary */ + mode = AccessREAD | AccessWRITE; + break; + default: + /* */ + NOTREACHED; + mode = AccessREAD | AccessWRITE; + break; + } address = er->ExceptionInformation[1]; diff --git a/mps/code/qs.c b/mps/code/qs.c index 2bf41c4c8f4..13b2070da19 100644 --- a/mps/code/qs.c +++ b/mps/code/qs.c @@ -23,6 +23,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpsavm.h" #include "mpscamc.h" @@ -528,6 +529,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); diff --git a/mps/code/sacss.c b/mps/code/sacss.c index 6501a12e952..1241caff19c 100644 --- a/mps/code/sacss.c +++ b/mps/code/sacss.c @@ -12,6 +12,7 @@ #include "mps.h" #include "testlib.h" +#include "mpslib.h" #include #include "mpstd.h" @@ -191,6 +192,7 @@ int main(int argc, char *argv[]) mps_arena_t arena; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vmnz(), testArenaSIZE), "mps_arena_create"); diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 5f325a30e8f..f5f064cc59f 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -16,6 +16,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "chain.h" #include "mpscams.h" #include "mpsavm.h" @@ -855,6 +856,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); diff --git a/mps/code/steptest.c b/mps/code/steptest.c index 61ec888801b..159ecda4096 100644 --- a/mps/code/steptest.c +++ b/mps/code/steptest.c @@ -9,6 +9,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpm.h" #include "mpscamc.h" #include "mpsavm.h" @@ -492,6 +493,7 @@ int main(int argc, char *argv[]) prepare_clock(); randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); while (test_number < TESTS) { mps_arena_t arena; diff --git a/mps/code/teletest.c b/mps/code/teletest.c index b857494da73..5b74a2a8908 100644 --- a/mps/code/teletest.c +++ b/mps/code/teletest.c @@ -10,6 +10,7 @@ #include "mps.h" #include "mpsavm.h" #include "testlib.h" +#include "mpslib.h" #include diff --git a/mps/code/testlib.c b/mps/code/testlib.c index 167a3aa11db..ae04030c72c 100644 --- a/mps/code/testlib.c +++ b/mps/code/testlib.c @@ -322,6 +322,7 @@ void verror(const char *format, va_list args) fflush(stdout); /* synchronize */ vfprintf(stderr, format, args); fprintf(stderr, "\n"); + fflush(stderr); /* make sure the message is output */ exit(1); } @@ -368,6 +369,15 @@ void cdie(int res, const char *s) } +/* assert_die -- always die on assertion */ + +void assert_die(const char *file, unsigned line, const char *condition) +{ + error("%s:%u: MPS ASSERTION FAILED: %s\n", file, line, condition); +} + + + /* C. COPYRIGHT AND LICENSE * * Copyright (c) 2001-2013 Ravenbrook Limited . diff --git a/mps/code/testlib.h b/mps/code/testlib.h index cc4bcce8006..5a58e0b1d78 100644 --- a/mps/code/testlib.h +++ b/mps/code/testlib.h @@ -159,6 +159,15 @@ extern void die_expect(mps_res_t res, mps_res_t expected, const char *s); extern void cdie(int res, const char *s); +/* assert_die -- always die on assertion + * + * The MPS assertion handler may not stop in the HOT variety, + * preventing tests from detecting defects. This one does. + */ + +void assert_die(const char *file, unsigned line, const char *condition); + + /* error, verror -- die with message */ extern void error(const char *format, ...); diff --git a/mps/code/trace.c b/mps/code/trace.c index 9401696ba2d..041b136711f 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -732,6 +732,8 @@ found: arena->busyTraces = TraceSetAdd(arena->busyTraces, trace); AVERT(Trace, trace); + EVENT3(TraceCreate, trace, arena, (EventFU)why); + /* We suspend the mutator threads so that the PoolWhiten methods */ /* can calculate white sets without the mutator allocating in */ /* buffers under our feet. */ @@ -1681,7 +1683,7 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) AVER(finishingTime >= 0.0); arena = trace->arena; - + /* From the already set up white set, derive a grey set. */ /* @@@@ Instead of iterating over all the segments, we could */ @@ -1789,6 +1791,11 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) /* @@ DIAG for rate of scanning here. */ + EVENT8(TraceStart, trace, mortality, finishingTime, + trace->condemned, trace->notCondemned, + trace->foundation, trace->white, + trace->rate); + STATISTIC_STAT(EVENT7(TraceStatCondemn, trace, trace->condemned, trace->notCondemned, trace->foundation, trace->rate, diff --git a/mps/code/walkt0.c b/mps/code/walkt0.c index 83170ec4929..3e8c8ce8293 100644 --- a/mps/code/walkt0.c +++ b/mps/code/walkt0.c @@ -9,6 +9,7 @@ #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" +#include "mpslib.h" #include "mpscamc.h" #include "mpsavm.h" #include "mpstd.h" @@ -201,6 +202,7 @@ int main(int argc, char *argv[]) void *r; randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index ad2f272ceb4..66b4d268b8d 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -55,6 +55,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpscamc.h" #include "mpsavm.h" @@ -838,6 +839,7 @@ static void testscriptA(const char *script) int main(int argc, char *argv[]) { randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); /* 1<<19 == 524288 == 1/2 Mebibyte */ /* 16<<20 == 16777216 == 16 Mebibyte */ diff --git a/mps/code/zmess.c b/mps/code/zmess.c index cd4ef83dd7c..6a117eb985b 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -100,6 +100,7 @@ */ #include "testlib.h" +#include "mpslib.h" #include "mps.h" #include "mpscamc.h" #include "mpsavm.h" @@ -490,6 +491,7 @@ int main(int argc, char *argv[]) { randomize(argc, argv); + mps_lib_assert_fail_install(assert_die); /* Scripts that should fail (uncomment to show failure is detected) */ /*testscriptA("C.");*/ diff --git a/mps/configure b/mps/configure index 50885dcc35a..2f1113baece 100755 --- a/mps/configure +++ b/mps/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Memory Pool System Kit release 1.111.0. +# Generated by GNU Autoconf 2.69 for Memory Pool System Kit master. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Memory Pool System Kit' PACKAGE_TARNAME='mps-kit' -PACKAGE_VERSION='release 1.111.0' -PACKAGE_STRING='Memory Pool System Kit release 1.111.0' +PACKAGE_VERSION='master' +PACKAGE_STRING='Memory Pool System Kit master' PACKAGE_BUGREPORT='mps-questions@ravenbrook.com' PACKAGE_URL='http://www.ravenbrook.com/project/mps/' @@ -1243,7 +1243,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Memory Pool System Kit release 1.111.0 to adapt to many kinds of systems. +\`configure' configures Memory Pool System Kit master to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1308,7 +1308,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Memory Pool System Kit release 1.111.0:";; + short | recursive ) echo "Configuration of Memory Pool System Kit master:";; esac cat <<\_ACEOF @@ -1389,7 +1389,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Memory Pool System Kit configure release 1.111.0 +Memory Pool System Kit configure master generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1645,7 +1645,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Memory Pool System Kit $as_me release 1.111.0, which was +It was created by Memory Pool System Kit $as_me master, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4056,7 +4056,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Memory Pool System Kit $as_me release 1.111.0, which was +This file was extended by Memory Pool System Kit $as_me master, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4110,7 +4110,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Memory Pool System Kit config.status release 1.111.0 +Memory Pool System Kit config.status master configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/mps/manual/html/_sources/topic/error.txt b/mps/manual/html/_sources/topic/error.txt index 296ddb9fa30..805f50af3bf 100644 --- a/mps/manual/html/_sources/topic/error.txt +++ b/mps/manual/html/_sources/topic/error.txt @@ -188,16 +188,6 @@ than the client program, but it is not unknown, so if you have made every effort to track down the cause (see :ref:`guide-debug`) without luck, :ref:`get in touch `. -If you are running your MPS-enabled program from Emacs via the -``compile`` command, you will probably want to recognize MPS -assertions automatically, by adding the following to your ``.emacs``: - -.. code-block:: scheme - - (add-to-list 'compilation-error-regexp-alist - '("MPS ASSERTION FAILURE: .*\n\\(.*\\)\n\\([0-9]+\\)" 1 2)) - - .. index:: single: assertion; common causes @@ -274,6 +264,30 @@ this documentation. condition? +.. index:: + single: assertion + single: error handling; assertion; assertion handling + +.. _topic-error-assertion-handling: + +Assertion Handling +------------------ + +When the MPS detects an assertion failure, it calls the :term:`plinth` +function :c:func:`mps_lib_assert_fail`. If you have not replaced the +plinth, this will print the assertion message and terminate the program +in the :term:`cool` :term:`variety`, but *not* in the :term:`hot` or +:term:`rash` varieties. You can change this behaviour by providing your +own plinth, or using :c:func:`mps_lib_assert_fail_install`. + +In many applications, users don't want their program terminated when the +MPS detects an error, no matter how severe. A lot of MPS assertions +indicate that the program is going to crash very soon, but there still +may be a chance for a user to get some useful results or save their +work. This is why the default assertion handler only terminates in the +:term:`cool` :term:`variety`. + + .. index:: single: error handling; varieties single: variety @@ -296,8 +310,11 @@ default. The cool variety is intended for development and testing. - All functions check the consistency of their data structures and - may assert, including functions on the :term:`critical path`. + All functions check the consistency of their data structures and may + assert, including functions on the :term:`critical path`. + Furthermore, in the default ANSI Library the default assertion + handler will terminate the program. See + :c:func:`mps_lib_assert_fail_install`. All events are sent to the :term:`telemetry stream`, including events on the :term:`critical path`. @@ -312,7 +329,9 @@ default. The hot variety is intended for production and deployment. Some functions check the consistency of their data structures and - may assert, namely those not on the :term:`critical path`. + may assert, namely those not on the :term:`critical path`. However, + in the default ANSI Library, the default assertion handler will not + terminate the program. See :c:func:`mps_lib_assert_fail_install`. Some events are sent to the telemetry stream, namely those not on the :term:`critical path`. diff --git a/mps/manual/html/_sources/topic/plinth.txt b/mps/manual/html/_sources/topic/plinth.txt index ce6beebf423..fc50e847a0e 100644 --- a/mps/manual/html/_sources/topic/plinth.txt +++ b/mps/manual/html/_sources/topic/plinth.txt @@ -236,7 +236,7 @@ Library module .. c:function:: void mps_lib_assert_fail(const char *message) - Report an assertion failure and abort. + Report an assertion failure. ``message`` is a NUL-terminated string describing the assertion failure. @@ -244,9 +244,31 @@ Library module .. note:: In the ANSI Library module, ``mpsliban.c``, this reports the - failure using ``fprintf(stderr, "...%s...", message)`` and - terminates the program by calling ``abort``. + failure using ``fprintf(stderr, "...%s...", message)`` and, in + the :term:`cool` :term:`variety`, terminates the program by + calling ``abort``. You can change this behaviour with + :c:func:`mps_lib_assert_fail_install`. For a discussion of + the default behaviour, see :ref:`topic-error-assertion-handling`. +.. c:function:: extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler) + + This function customises the behaviour of the default assertion handler + in the ANSI Library module. It is not otherwise required by the MPS + and you need not implement it if you are providing an alternative plinth. + + If you're using the ANSI Library module, you can use this function + to change the behaviour of the MPS when an assertion fails. For + example, you could terminate the program in the :term:`hot` + :term:`variety` too. (The MPS test programs do exactly that.) + + ``handler`` is the assertion handler to install. + + Returns the previously installed handler. + +.. c:type:: typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *) + + The type of assertion handlers passed to and returned by + :c:func:`mps_lib_assert_fail_install`. .. c:type:: mps_lib_FILE diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 296ddb9fa30..805f50af3bf 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -188,16 +188,6 @@ than the client program, but it is not unknown, so if you have made every effort to track down the cause (see :ref:`guide-debug`) without luck, :ref:`get in touch `. -If you are running your MPS-enabled program from Emacs via the -``compile`` command, you will probably want to recognize MPS -assertions automatically, by adding the following to your ``.emacs``: - -.. code-block:: scheme - - (add-to-list 'compilation-error-regexp-alist - '("MPS ASSERTION FAILURE: .*\n\\(.*\\)\n\\([0-9]+\\)" 1 2)) - - .. index:: single: assertion; common causes @@ -274,6 +264,30 @@ this documentation. condition? +.. index:: + single: assertion + single: error handling; assertion; assertion handling + +.. _topic-error-assertion-handling: + +Assertion Handling +------------------ + +When the MPS detects an assertion failure, it calls the :term:`plinth` +function :c:func:`mps_lib_assert_fail`. If you have not replaced the +plinth, this will print the assertion message and terminate the program +in the :term:`cool` :term:`variety`, but *not* in the :term:`hot` or +:term:`rash` varieties. You can change this behaviour by providing your +own plinth, or using :c:func:`mps_lib_assert_fail_install`. + +In many applications, users don't want their program terminated when the +MPS detects an error, no matter how severe. A lot of MPS assertions +indicate that the program is going to crash very soon, but there still +may be a chance for a user to get some useful results or save their +work. This is why the default assertion handler only terminates in the +:term:`cool` :term:`variety`. + + .. index:: single: error handling; varieties single: variety @@ -296,8 +310,11 @@ default. The cool variety is intended for development and testing. - All functions check the consistency of their data structures and - may assert, including functions on the :term:`critical path`. + All functions check the consistency of their data structures and may + assert, including functions on the :term:`critical path`. + Furthermore, in the default ANSI Library the default assertion + handler will terminate the program. See + :c:func:`mps_lib_assert_fail_install`. All events are sent to the :term:`telemetry stream`, including events on the :term:`critical path`. @@ -312,7 +329,9 @@ default. The hot variety is intended for production and deployment. Some functions check the consistency of their data structures and - may assert, namely those not on the :term:`critical path`. + may assert, namely those not on the :term:`critical path`. However, + in the default ANSI Library, the default assertion handler will not + terminate the program. See :c:func:`mps_lib_assert_fail_install`. Some events are sent to the telemetry stream, namely those not on the :term:`critical path`. diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index ce6beebf423..fc50e847a0e 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -236,7 +236,7 @@ Library module .. c:function:: void mps_lib_assert_fail(const char *message) - Report an assertion failure and abort. + Report an assertion failure. ``message`` is a NUL-terminated string describing the assertion failure. @@ -244,9 +244,31 @@ Library module .. note:: In the ANSI Library module, ``mpsliban.c``, this reports the - failure using ``fprintf(stderr, "...%s...", message)`` and - terminates the program by calling ``abort``. + failure using ``fprintf(stderr, "...%s...", message)`` and, in + the :term:`cool` :term:`variety`, terminates the program by + calling ``abort``. You can change this behaviour with + :c:func:`mps_lib_assert_fail_install`. For a discussion of + the default behaviour, see :ref:`topic-error-assertion-handling`. +.. c:function:: extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler) + + This function customises the behaviour of the default assertion handler + in the ANSI Library module. It is not otherwise required by the MPS + and you need not implement it if you are providing an alternative plinth. + + If you're using the ANSI Library module, you can use this function + to change the behaviour of the MPS when an assertion fails. For + example, you could terminate the program in the :term:`hot` + :term:`variety` too. (The MPS test programs do exactly that.) + + ``handler`` is the assertion handler to install. + + Returns the previously installed handler. + +.. c:type:: typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *) + + The type of assertion handlers passed to and returned by + :c:func:`mps_lib_assert_fail_install`. .. c:type:: mps_lib_FILE