From e095fd904836fc673b201944afa34fcbd58ad4f6 Mon Sep 17 00:00:00 2001 From: Teodoro Freund Date: Thu, 24 Aug 2023 09:45:45 +0100 Subject: [PATCH 1/2] Added test --- CMakeLists.txt | 1 + test/src/sphinx.c | 107 +++++++++++++++++++++++++++++++++++++++++++ test/test.h | 2 +- test/test_mpe_main.c | 3 +- 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 test/src/sphinx.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 87e714a..098c4d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ set(test_mpe_main_sources test/src/nqueens.c test/src/rehandle.c test/src/triples.c + test/src/sphinx.c test/test_mpe_main.c) if (NOT MP_USE_C) diff --git a/test/src/sphinx.c b/test/src/sphinx.c new file mode 100644 index 0000000..333bec5 --- /dev/null +++ b/test/src/sphinx.c @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------------- + Copyright (c) 2021, Microsoft Research, Daan Leijen + This is free software; you can redistribute it and/or modify it + under the terms of the MIT License. A copy of the license can be + found in the "LICENSE" file at the root of this distribution. + + The sphinx effect will only allow performers to continue execution + when they provide the correct answer to their riddle +-----------------------------------------------------------------------------*/ +#include "test.h" +#include + + +/*----------------------------------------------------------------- + Define operations +-----------------------------------------------------------------*/ +MPE_DEFINE_EFFECT1(sphinx, answer) +MPE_DEFINE_VOIDOP1(sphinx, answer, mpe_string_t) + +/*----------------------------------------------------------------- + Example programs +-----------------------------------------------------------------*/ + +void* brian(void* arg){ + UNUSED(arg); + // Arrive at Thebes + sphinx_answer("Scooters"); + // Die + mpt_assert(false, "Brian should have been eaten by the sphinx"); + return mpe_voidp_int(1); +} + + +void* oedipus(void* arg){ + UNUSED(arg); + // Arrive at Thebes + sphinx_answer("Person"); + // Free Thebes + return mpe_voidp_int(1); +} + +/*----------------------------------------------------------------- + Sphinx handler +-----------------------------------------------------------------*/ + +static void* _sphinx_answer(mpe_resume_t* r, void* local, void* arg){ + if (strcmp(mpe_mpe_string_t_voidp(arg), "Person") == 0) { + return mpe_resume_tail(r, local, NULL); + } else { + // I couldn't find a way to release it, this one is not intended for MPE_RESUMPTION_INPLACE + // mpe_resume_release(r); + return mpe_voidp_int(0); + } +} + +static const mpe_handlerdef_t sphinx_hdef = { MPE_EFFECT(sphinx), NULL, { + { MPE_OP_TAIL, MPE_OPTAG(sphinx, answer), &_sphinx_answer }, + { MPE_OP_NULL, mpe_op_null, NULL} +}}; + +static void* sphinx_handle(mpe_actionfun_t action) { + return mpe_handle(&sphinx_hdef, NULL, action, NULL); +} + +static const mpe_handlerdef_t sphinx_noop_hdef = { MPE_EFFECT(sphinx), NULL, { + { MPE_OP_TAIL_NOOP, MPE_OPTAG(sphinx, answer), &_sphinx_answer }, + { MPE_OP_NULL, mpe_op_null, NULL} +}}; + +static void* sphinx_noop_handle(mpe_actionfun_t action) { + return mpe_handle(&sphinx_noop_hdef, NULL, action, NULL); +} + +/*----------------------------------------------------------------- + testing +-----------------------------------------------------------------*/ + +static void oedipus_tail() { + int res = mpe_int_voidp(sphinx_handle(&oedipus)); + mpt_printf("state: %d\n", res); + mpt_assert(res == 1, "Oedipus should pass"); +} + +static void oedipus_tail_noop() { + int res = mpe_int_voidp(sphinx_noop_handle(&oedipus)); + mpt_printf("state: %d\n", res); + mpt_assert(res == 1, "Oedipus should pass"); +} + +static void brian_tail() { + int res = mpe_int_voidp(sphinx_handle(&brian)); + mpt_printf("state: %d\n", res); + mpt_assert(res == 0, "Brian shouldn't pass"); +} + +static void brian_tail_noop() { + int res = mpe_int_voidp(sphinx_noop_handle(&brian)); + mpt_printf("state: %d\n", res); + mpt_assert(res == 0, "Brian shouldn't pass"); +} + +void sphinx_run(void) { + oedipus_tail(); + oedipus_tail_noop(); + brian_tail(); + brian_tail_noop(); +} \ No newline at end of file diff --git a/test/test.h b/test/test.h index 093e88e..72be6c5 100644 --- a/test/test.h +++ b/test/test.h @@ -37,7 +37,7 @@ void triples_run(void); void amb_run(void); void amb_state_run(void); void rehandle_run(void); - +void sphinx_run(void); #ifdef __cplusplus void throw_run(void); diff --git a/test/test_mpe_main.c b/test/test_mpe_main.c index 6229783..1389322 100644 --- a/test/test_mpe_main.c +++ b/test/test_mpe_main.c @@ -47,7 +47,8 @@ static void test_c(void) { countern_run(); mstate_run(); rehandle_run(); - + sphinx_run(); + // multi-shot tests amb_run(); amb_state_run(); From 7e8dfdd4aff55b2fe8a3f4496c2b2ebb3a34883e Mon Sep 17 00:00:00 2001 From: Teodoro Freund Date: Thu, 24 Aug 2023 09:58:52 +0100 Subject: [PATCH 2/2] Possible fix --- src/mpeff/mpeff.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/mpeff/mpeff.c b/src/mpeff/mpeff.c index 9cdae2e..55fc455 100644 --- a/src/mpeff/mpeff.c +++ b/src/mpeff/mpeff.c @@ -132,6 +132,7 @@ struct mpe_resume_s { void** plocal; // kind == MPE_RESUMPTION_INPLACE mp_resume_t* resume; // kind == MPE_RESUMPTION_SCOPED_ONCE || MPE_RESUMPTION_ONCE || MPE_RESUME_MULTI } mp; + bool resumed; }; @@ -302,6 +303,10 @@ static void* mpe_perform_yield_to_abort(mpe_frame_handle_t* h, const mpe_operati return mp_yield(h->prompt, &mpe_perform_op_clause_abort, &env); } +// Id function for resuming +static void* id(mp_resume_t* mpr, void* arg) { + return arg; +} // Tail resumptive under an "under" frame static void* mpe_perform_under(mpe_frame_handle_t* h, const mpe_operation_t* op, void* arg) { @@ -309,11 +314,16 @@ static void* mpe_perform_under(mpe_frame_handle_t* h, const mpe_operation_t* op, f.frame.effect = MPE_EFFECT(mpe_frame_under); f.under = h->frame.effect; void* result = NULL; + mpe_resume_t resume = { MPE_RESUMPTION_INPLACE, { &h->local }, false }; {mpe_with_frame(&f.frame) { - mpe_resume_t resume = { MPE_RESUMPTION_INPLACE, { &h->local } }; result = (op->opfun)(&resume, h->local, arg); }} - return result; + + if (resume.resumed) { + return result; + } else { + return mp_yield(h->prompt, &id, result); + } } // ------------------------------------------------------------------------------ @@ -325,8 +335,13 @@ static void* mpe_perform_at(mpe_frame_handle_t* h, const mpe_operation_t* op, vo mpe_assert_internal(opkind == op->opkind); if (mpe_likely(opkind == MPE_OP_TAIL_NOOP)) { // tail resumptive, calls no operations, execute in place - mpe_resume_t resume = { MPE_RESUMPTION_INPLACE, { &h->local } }; - return (op->opfun)(&resume, h->local, arg); + mpe_resume_t resume = { MPE_RESUMPTION_INPLACE, { &h->local }, false }; + void* result = (op->opfun)(&resume, h->local, arg); + if (resume.resumed) { + return result; + } else { + return mp_yield(h->prompt, &id, result); + } } else if (mpe_likely(opkind == MPE_OP_TAIL)) { // tail resumptive; execute in place under an "under" frame @@ -497,16 +512,19 @@ static void mpe_resume_unwind(mpe_resume_t* r) { // Last use of a resumption void* mpe_resume_final(mpe_resume_t* resume, void* local, void* arg) { + resume->resumed = true; return mpe_resume_internal(true, resume, local, arg, false); } // Regular resume void* mpe_resume(mpe_resume_t* resume, void* local, void* arg) { + resume->resumed = true; return mpe_resume_internal(false, resume, local, arg, false); } // Last resume in tail-position void* mpe_resume_tail(mpe_resume_t* resume, void* local, void* arg) { + resume->resumed = true; if (mpe_likely(resume->kind == MPE_RESUMPTION_INPLACE)) { *resume->mp.plocal = local; return arg;