From cb056def0ea479f297fd8b7067328c0ef05c95d5 Mon Sep 17 00:00:00 2001 From: j-hui Date: Tue, 31 Aug 2021 18:07:07 -0400 Subject: [PATCH 1/6] Clean up + accommodate ssm-edsl trace-based testing - Remove ssm-debug.h - Fix prio queue bug in ssm_unschedule - Introduce SSM_THROW for crashing - Change ssm_event_t to a struct wrapping ssm_sv_t, rather than a typedef, for consistency with other types. --- examples/hello2.c | 2 +- include/ssm.h | 56 +++++++++++++++++++++++++++++++++------------ src/ssm-event.c | 8 +++---- src/ssm-scheduler.c | 24 +++++++++++-------- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/examples/hello2.c b/examples/hello2.c index 83680304..ffe027fe 100644 --- a/examples/hello2.c +++ b/examples/hello2.c @@ -86,7 +86,7 @@ void step_print(ssm_act_t *sact) case 1: if (ssm_event_on((ssm_sv_t *) act->stdout)) putchar(act->stdout->value); - if (ssm_event_on(act->done)) { + if (ssm_event_on(&act->done->sv)) { ssm_desensitize(&act->trigger1); ssm_desensitize(&act->trigger2); ssm_leave((ssm_act_t *) act, sizeof(print_act_t)); diff --git a/include/ssm.h b/include/ssm.h index bc00077d..9e3d9e40 100644 --- a/include/ssm.h +++ b/include/ssm.h @@ -68,14 +68,47 @@ See [the detailed documentation](@ref all) #define SSM_ACT_FREE(ptr, size) free(ptr) #endif -#ifndef SSM_RESOURCES_EXHAUSTED -/** Invoked when limited resources are exhausted, e.g., unable to - * allocate memory, no more queue space. Not expected to return +/** Invoked when a process must terminate, e.g., when memory or queue space is + * exhausted. Not expected to return. * - * Argument passed is a string indicating where the failure occurred. + * Argument passed is an ssm_error_t indicating why the failure occurred. + * Default behavior is to exit with reason as the exit code, but can be + * overridden by defining ssm_throw. */ -#define SSM_RESOURCES_EXHAUSTED(string) exit(1) -#endif +#define SSM_THROW(reason) \ + ssm_throw ? \ + ssm_throw(reason, __FILE__, __LINE__, __func__) : \ + exit(reason) + +/** Underlying crash handler; can be overriden. */ +void ssm_throw(int reason, const char *file, int line, const char *func) + __attribute__((weak)); + +/** Error codes, indicating reason for failure. + * + * Platforms may extend the list of errors using SSM_PLATFORM_ERROR like this: + * + * enum { + * SSM_CUSTOM_ERROR1 = SSM_PLATFORM_ERROR, + * // etc. + * }; + */ +enum ssm_error_t { + /** Reserved for unforeseen, non-user-facing errors. */ + SSM_INTERNAL_ERROR = 1, + /** Tried to insert into full activation record queue. */ + SSM_EXHAUSTED_ACT_QUEUE, + /** Tried to insert into full event queue. */ + SSM_EXHAUSTED_EVENT_QUEUE, + /** Could not allocate more memory. */ + SSM_EXHAUSTED_MEMORY, + /** Tried to exceed available recursion depth. */ + SSM_EXHAUSTED_PRIORITY, + /** Invalid time, e.g., scheduled delayed assignment at an earlier time. */ + SSM_INVALID_TIME, + /** Start of platform-specific error code range. */ + SSM_PLATFORM_ERROR +}; #ifndef SSM_SECOND /** Ticks in a second @@ -266,7 +299,7 @@ static inline ssm_act_t *ssm_enter(size_t bytes, /**< size of the activation rec assert(parent); ++parent->children; ssm_act_t *act = (ssm_act_t *)SSM_ACT_MALLOC(bytes); - if (!act) SSM_RESOURCES_EXHAUSTED("ssm_enter"); + if (!act) SSM_THROW(SSM_EXHAUSTED_MEMORY); *act = (ssm_act_t){ .step = step, .caller = parent, @@ -404,8 +437,8 @@ extern ssm_act_t ssm_top_parent; ((type *)((char *)(member_type(type, member) *){ptr} - \ offsetof(type, member))) -typedef ssm_sv_t ssm_event_t; -#define ssm_later_event(var, then) ssm_schedule((var), (then)) +typedef struct { ssm_sv_t sv; } ssm_event_t; +#define ssm_later_event(var, then) ssm_schedule(&(var)->sv, (then)) extern void ssm_assign_event(ssm_event_t *var, ssm_priority_t prio); extern void ssm_initialize_event(ssm_event_t *); @@ -482,9 +515,4 @@ SSM_DECLARE_SV_SCALAR(u64) /** @} */ - -// FIXME! -#include "ssm-debug.h" - #endif - diff --git a/src/ssm-event.c b/src/ssm-event.c index f9681efc..fa52d345 100644 --- a/src/ssm-event.c +++ b/src/ssm-event.c @@ -3,15 +3,15 @@ void ssm_assign_event(ssm_event_t *v, ssm_priority_t prio) { assert(v); - v->last_updated = ssm_now(); - ssm_trigger(v, prio); + v->sv.last_updated = ssm_now(); + ssm_trigger(&v->sv, prio); } -static void ssm_update_event(ssm_event_t *v) +static void ssm_update_event(ssm_sv_t *v) { } void ssm_initialize_event(ssm_event_t *v) { - ssm_initialize(v, ssm_update_event); + ssm_initialize(&v->sv, ssm_update_event); } diff --git a/src/ssm-scheduler.c b/src/ssm-scheduler.c index e5f57736..9ae6c160 100644 --- a/src/ssm-scheduler.c +++ b/src/ssm-scheduler.c @@ -169,7 +169,7 @@ void ssm_activate(ssm_act_t *act) q_idx_t hole = ++act_queue_len; if (act_queue_len > SSM_ACT_QUEUE_SIZE) - SSM_RESOURCES_EXHAUSTED("ssm_activate"); + SSM_THROW(SSM_EXHAUSTED_ACT_QUEUE); act_queue_percolate_up(hole, act); } @@ -263,18 +263,19 @@ SSM_STATIC_INLINE void event_queue_percolate_down(q_idx_t hole, void ssm_schedule(ssm_sv_t *var, ssm_time_t later) { - assert(var); // A real variable - assert(later > now); // Must be in the future + assert(var); // A real variable + if (later <= now) // "later" must be in the future + SSM_THROW(SSM_INVALID_TIME); if (var->later_time == SSM_NEVER) { // Variable does not have a pending event: add it to the queue q_idx_t hole = ++event_queue_len; if (event_queue_len > SSM_EVENT_QUEUE_SIZE) - SSM_RESOURCES_EXHAUSTED("ssm_schedule"); + SSM_THROW(SSM_EXHAUSTED_EVENT_QUEUE); var->later_time = later; event_queue_percolate_up(hole, var); - + } else { // Variable has a pending event: reposition the event in the queue // as appropriate @@ -296,11 +297,14 @@ void ssm_unschedule(ssm_sv_t *var) q_idx_t hole = find_queued_event(var); var->later_time = SSM_NEVER; ssm_sv_t *moved_var = event_queue[event_queue_len--]; - if (hole == SSM_QUEUE_HEAD || - event_queue[hole >> 1]->later_time < moved_var->later_time) - event_queue_percolate_down(hole, moved_var); - else - event_queue_percolate_up(hole, moved_var); + if (hole < SSM_QUEUE_HEAD + event_queue_len) { + // Percolate if removal led to hole in the queue. + if (hole == SSM_QUEUE_HEAD || + event_queue[hole >> 1]->later_time < moved_var->later_time) + event_queue_percolate_down(hole, moved_var); + else + event_queue_percolate_up(hole, moved_var); + } } } From f8b151fcb2b8eb77a806c26762bcc8f4f5940c5b Mon Sep 17 00:00:00 2001 From: j-hui Date: Tue, 31 Aug 2021 18:36:04 -0400 Subject: [PATCH 2/6] Delete ssm-debug.h (previously forgot to) --- include/ssm-debug.h | 83 --------------------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 include/ssm-debug.h diff --git a/include/ssm-debug.h b/include/ssm-debug.h deleted file mode 100644 index 584eea32..00000000 --- a/include/ssm-debug.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _SSM_DEBUG_H -#define _SSM_DEBUG_H - -/** - * Platform-agnostic debug interface for SSM. - * - * TODO: lots of tidying up to get rid of ugly CPP ifdefs etc. - */ - -// FIXME! -#undef DEBUG - -#ifdef DEBUG -#include /* TODO: should only be included for debug */ - -/* FIXME: This is kind of an ugly hack. */ -struct debug_buffer { - char buf[32]; -}; - -/** SV debug information. */ -struct debug_sv { - const char *var_name; - const char *type_name; - struct debug_buffer (*value_repr)(struct ssm_sv *); -}; - -/** Debug information for activation records. */ -struct debug_act { - const char *act_name; -}; - -#define DEBUG_ACT_SET_ACT_NAME(actd, name) ((actd).act_name = (name)) -#define DEBUG_SV_SET_VAR_NAME(svd, name) ((svd).var_name = (name)) -#define DEBUG_SV_SET_TYPE_NAME(svd, name) ((svd).type_name = (name)) -#define DEBUG_SV_SET_VALUE_REPR(svd, vr) ((svd).value_repr = (vr)) - -#define DEBUG_ACT_GET_ACT_NAME(actd) (actd).act_name -#define DEBUG_SV_GET_VAR_NAME(svd) (svd).var_name -#define DEBUG_SV_GET_TYPE_NAME(svd) (svd).type_name -#define DEBUG_SV_GET_VALUE_REPR(svd, sv) (svd).value_repr(sv).buf - -#else - -#define DEBUG_ACT_SET_ACT_NAME(actd, name) \ - do { \ - } while (0) -#define DEBUG_SV_SET_VAR_NAME(svd, name) \ - do { \ - } while (0) -#define DEBUG_SV_SET_TYPE_NAME(svd, name) \ - do { \ - } while (0) -#define DEBUG_SV_SET_VALUE_REPR(svd, vr) \ - do { \ - } while (0) - -#define DEBUG_ACT_GET_ACT_NAME(actd) "(no DEBUG; act name unavailable)" -#define DEBUG_SV_GET_VAR_NAME(svd) "(no DEBUG; var name unavailable)" -#define DEBUG_SV_GET_TYPE_NAME(svd) "(no DEBUG; type name unavailable)" -#define DEBUG_SV_GET_VALUE_REPR(svd, sv) "(no DEBUG; value unavailable)" - -#endif /* ifdef DEBUG */ - -#ifndef DEBUG_TRACE -#define DEBUG_TRACE(...) \ - do { \ - } while (0) -#endif - -#ifndef DEBUG_PRINT -#define DEBUG_PRINT(...) \ - do { \ - } while (0) -#endif - -#ifndef DEBUG_ASSERT -#define DEBUG_ASSERT(assertion, ...) \ - do { \ - } while (0) -#endif - -#endif /* ifndef _SSM_DEBUG_H */ From 52e66bb143f1fb12bfcaea7719b09ff0987ee384 Mon Sep 17 00:00:00 2001 From: j-hui Date: Thu, 2 Sep 2021 16:37:31 -0400 Subject: [PATCH 3/6] Default to hanging instead of exit() upon crash This is the most platform-independent way of crashing, since it doesn't rely on any external exit() function. --- include/ssm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ssm.h b/include/ssm.h index 9e3d9e40..5d63572d 100644 --- a/include/ssm.h +++ b/include/ssm.h @@ -78,7 +78,7 @@ See [the detailed documentation](@ref all) #define SSM_THROW(reason) \ ssm_throw ? \ ssm_throw(reason, __FILE__, __LINE__, __func__) : \ - exit(reason) + for(;;) /** Underlying crash handler; can be overriden. */ void ssm_throw(int reason, const char *file, int line, const char *func) From 6baa2ca16d62448581374aaf5beb9106854de9f3 Mon Sep 17 00:00:00 2001 From: j-hui Date: Thu, 2 Sep 2021 16:48:05 -0400 Subject: [PATCH 4/6] Add documentation for weak ssm_throw --- include/ssm.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/ssm.h b/include/ssm.h index 5d63572d..c91ff53b 100644 --- a/include/ssm.h +++ b/include/ssm.h @@ -68,6 +68,15 @@ See [the detailed documentation](@ref all) #define SSM_ACT_FREE(ptr, size) free(ptr) #endif +/** Underlying exception handler; can be overridden by each platform + * + * ssm_throw is declared as a weak symbol, meaning it will be left a null + * pointer if the linker does not find a definition for this symbol in any + * object file. + */ +void ssm_throw(int reason, const char *file, int line, const char *func) + __attribute__((weak)); + /** Invoked when a process must terminate, e.g., when memory or queue space is * exhausted. Not expected to return. * @@ -80,10 +89,6 @@ See [the detailed documentation](@ref all) ssm_throw(reason, __FILE__, __LINE__, __func__) : \ for(;;) -/** Underlying crash handler; can be overriden. */ -void ssm_throw(int reason, const char *file, int line, const char *func) - __attribute__((weak)); - /** Error codes, indicating reason for failure. * * Platforms may extend the list of errors using SSM_PLATFORM_ERROR like this: From e90446104f7d9665cac3be93a6d81d2e26b789b7 Mon Sep 17 00:00:00 2001 From: j-hui Date: Thu, 2 Sep 2021 16:50:59 -0400 Subject: [PATCH 5/6] Add documentation for ssm_unschedule --- src/ssm-scheduler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ssm-scheduler.c b/src/ssm-scheduler.c index 9ae6c160..35fb3b53 100644 --- a/src/ssm-scheduler.c +++ b/src/ssm-scheduler.c @@ -297,14 +297,14 @@ void ssm_unschedule(ssm_sv_t *var) q_idx_t hole = find_queued_event(var); var->later_time = SSM_NEVER; ssm_sv_t *moved_var = event_queue[event_queue_len--]; - if (hole < SSM_QUEUE_HEAD + event_queue_len) { - // Percolate if removal led to hole in the queue. + if (hole < SSM_QUEUE_HEAD + event_queue_len) + // Percolate only if removal led to a hole in the queue; no need to do + // this if we happened to remove the last element of the queue. if (hole == SSM_QUEUE_HEAD || event_queue[hole >> 1]->later_time < moved_var->later_time) event_queue_percolate_down(hole, moved_var); else event_queue_percolate_up(hole, moved_var); - } } } From 80c234cbc8c6dfed82f3a1ace26e8534f1b0464a Mon Sep 17 00:00:00 2001 From: j-hui Date: Thu, 2 Sep 2021 16:59:25 -0400 Subject: [PATCH 6/6] Fix SSM_THOW macro definition --- include/ssm.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/ssm.h b/include/ssm.h index c91ff53b..5e59531a 100644 --- a/include/ssm.h +++ b/include/ssm.h @@ -85,9 +85,12 @@ void ssm_throw(int reason, const char *file, int line, const char *func) * overridden by defining ssm_throw. */ #define SSM_THROW(reason) \ - ssm_throw ? \ - ssm_throw(reason, __FILE__, __LINE__, __func__) : \ - for(;;) + do \ + if (ssm_throw) \ + ssm_throw(reason, __FILE__, __LINE__, __func__); \ + else \ + for(;;); \ + while (0) /** Error codes, indicating reason for failure. *