Skip to content

Commit

Permalink
#415 Take two with polling.
Browse files Browse the repository at this point in the history
  • Loading branch information
eidekrist committed Oct 15, 2019
1 parent f9db2f7 commit 11c12e5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 19 deletions.
20 changes: 17 additions & 3 deletions include/cse.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ cse_slave_index cse_execution_add_slave(
int cse_execution_step(cse_execution* execution, size_t numSteps);

/**
* Advances an execution to a specific point in time.
* Advances an execution to a specific point in time (blocking).
*
* \param [in] execution
* The execution to be stepped.
Expand All @@ -287,9 +287,10 @@ int cse_execution_simulate_until(cse_execution* execution, cse_time_point target


/**
* Starts an execution.
* Starts an execution (non blocking).
*
* The execution will run until `cse_execution_stop()` is called.
* The execution will run until `cse_execution_stop()` is called. The status of the
* simulation can be polled with `cse_execution_get_simulation_status()`.
*
* \param [in] execution
* The execution to be started.
Expand All @@ -300,6 +301,19 @@ int cse_execution_simulate_until(cse_execution* execution, cse_time_point target
int cse_execution_start(cse_execution* execution);


/**
* Polls an execution for its simulation status.
*
* his method can be used to poll the status of the asynchronous simulation
* execution started by calling `cse_execution_start()`. Will return failure
* if an error occurred during the simulation execution.
*
* \returns
* 0 on success and -1 on error.
*/
int cse_execution_get_simulation_status(cse_execution* execution);


/**
* Stops an execution.
*
Expand Down
41 changes: 28 additions & 13 deletions src/c/cse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,12 @@ cse_errc cpp_to_c_error_code(std::error_code ec)
// These hold information about the last reported error.
// They should only be set through `set_last_error()` and
// `handle_current_exception()`.
static cse_errc g_lastErrorCode;
static std::string g_lastErrorMessage;
static std::mutex g_lock;
thread_local cse_errc g_lastErrorCode;
thread_local std::string g_lastErrorMessage;

// Sets the last error code and message directly.
void set_last_error(cse_errc ec, std::string message)
{
std::lock_guard<std::mutex> lock(g_lock);
g_lastErrorCode = ec;
g_lastErrorMessage = std::move(message);
}
Expand Down Expand Up @@ -135,13 +133,11 @@ void safe_strncpy(char* dest, const char* src, std::size_t count)

cse_errc cse_last_error_code()
{
std::lock_guard<std::mutex> lock(g_lock);
return g_lastErrorCode;
}

const char* cse_last_error_message()
{
std::lock_guard<std::mutex> lock(g_lock);
return g_lastErrorMessage.c_str();
}

Expand All @@ -151,6 +147,7 @@ struct cse_execution_s
std::unique_ptr<cse::execution> cpp_execution;
std::thread t;
boost::fibers::future<bool> simulate_result;
std::exception_ptr simulate_exception_ptr;
std::atomic<cse_execution_state> state;
int error_code;
};
Expand Down Expand Up @@ -500,13 +497,8 @@ int cse_execution_start(cse_execution* execution)
auto task = boost::fibers::packaged_task<bool()>([execution]() {
auto future = execution->cpp_execution->simulate_until(std::nullopt);
if (auto ep = future.get_exception_ptr()) {
try {
std::rethrow_exception(ep);
} catch (...) {
handle_current_exception();
execution->state = CSE_EXECUTION_ERROR;
return false;
}
execution->simulate_exception_ptr = ep;
return false;
}
return future.get();
});
Expand All @@ -521,13 +513,36 @@ int cse_execution_start(cse_execution* execution)
}
}

int cse_execution_get_simulation_status(cse_execution* execution)
{
if (execution->state != CSE_EXECUTION_RUNNING) {
return success;
}
const auto status = execution->simulate_result.wait_for(std::chrono::duration<int64_t>());
if (boost::fibers::future_status::ready == status) {
if (execution->simulate_exception_ptr) {
try {
std::rethrow_exception(execution->simulate_exception_ptr);
} catch (...) {
handle_current_exception();
execution->state = CSE_EXECUTION_ERROR;
return failure;
}
}
}
return success;
}

int cse_execution_stop(cse_execution* execution)
{
try {
execution->cpp_execution->stop_simulation();
if (execution->t.joinable()) {
execution->simulate_result.get();
execution->t.join();
if (execution->simulate_exception_ptr) {
std::rethrow_exception(execution->simulate_exception_ptr);
}
}
execution->state = CSE_EXECUTION_STOPPED;
return success;
Expand Down
25 changes: 22 additions & 3 deletions test/c/simulation_error_handling_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ int main()

Sleep(100);

rc = cse_execution_get_simulation_status(execution);
if (rc < 0) {
fprintf(stderr, "Expected call to cse_execution_get_simulation_status() to return success.");
goto Lfailure;
}

cse_value_reference ref = 0;
const bool val = true;
// Produces a model error in the subsequent step
Expand All @@ -76,6 +82,12 @@ int main()
// Need to wait a bit due to stepping (and failure) happening in another thread.
Sleep(400);

rc = cse_execution_get_simulation_status(execution);
if (rc >= 0) {
fprintf(stderr, "Expected call to cse_execution_get_simulation_status() to return failure.");
goto Lfailure;
}

cse_execution_status executionStatus;
rc = cse_execution_get_status(execution, &executionStatus);
if (rc < 0) { goto Lerror; }
Expand All @@ -98,9 +110,16 @@ int main()
}

// What do we expect should happen if calling further methods?
// Sleep(100);
// rc = cse_execution_stop(execution);
// if (rc = 0) { goto Lfailure; }
Sleep(100);
rc = cse_execution_stop(execution);
if (rc >= 0) { goto Lfailure; }

Sleep(100);

rc = cse_execution_start(execution);
if (rc < 0) { goto Lerror; }

Sleep(1000);

goto Lcleanup;

Expand Down

0 comments on commit 11c12e5

Please sign in to comment.