Skip to content

Commit

Permalink
Ensure ASIO thread cannot be stopped prematurely (ponylang#2612)
Browse files Browse the repository at this point in the history
Prior to this commit, it was possible for the ASIO thread to
be stopped in anticipation of runtime termination when runtime
termination didn't actually occur. This would leave the runtime
in an invalid state where a new ASIO thread would need to be
restarted.

This commit changes the behavior to ensure that the ASIO thread
is only stopped when the runtime is about to be terminated to
ensure the runtime cannot be in an invalid state where the ASIO
thread isn't running.
  • Loading branch information
dipinhora committed Jun 5, 2018
1 parent f2fddfd commit 2dab944
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 17 deletions.
8 changes: 7 additions & 1 deletion src/libponyrt/asio/asio.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ bool ponyint_asio_start()

bool ponyint_asio_stop()
{
if(atomic_load_explicit(&running_base.noisy_count, memory_order_relaxed) > 0)
if(!ponyint_asio_stoppable())
return false;

if(running_base.backend != NULL)
Expand All @@ -74,6 +74,12 @@ bool ponyint_asio_stop()
return true;
}

bool ponyint_asio_stoppable()
{
// can only stop if we have no noisy actors
return atomic_load_explicit(&running_base.noisy_count, memory_order_relaxed) == 0;
}

uint64_t ponyint_asio_noisy_add()
{
return atomic_fetch_add_explicit(&running_base.noisy_count, 1, memory_order_relaxed);
Expand Down
7 changes: 7 additions & 0 deletions src/libponyrt/asio/asio.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ uint32_t ponyint_asio_get_cpu();
*/
bool ponyint_asio_stop();

/** Checks if it is safe to stop the asynchronous event mechanism.
*
* Stopping an event mechanism is only possible if there are no pending "noisy"
* subscriptions.
*/
bool ponyint_asio_stoppable();

/** Add a noisy event subscription.
*/
uint64_t ponyint_asio_noisy_add();
Expand Down
23 changes: 8 additions & 15 deletions src/libponyrt/sched/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,6 @@ static void handle_sched_block(scheduler_t* sched)
// handle SCHED_UNBLOCK message
static void handle_sched_unblock(scheduler_t* sched)
{
// if the ASIO thread has already been stopped
if (sched->asio_stopped)
{
// restart the ASIO thread
ponyint_asio_init(asio_cpu);
sched->asio_stopped = !ponyint_asio_start();
}

// make sure asio hasn't already been stopped or else runtime is in
// an invalid state without the ASIO thread running
pony_assert(!sched->asio_stopped);

// Cancel all acks and increment the ack token, so that any pending
// acks in the queue will be dropped when they are received.
sched->block_count--;
Expand Down Expand Up @@ -328,21 +316,26 @@ static bool quiescent(scheduler_t* sched, uint64_t tsc, uint64_t tsc2)

if(sched->ack_count >= current_active_scheduler_count)
{
if(sched->asio_stopped)
if(sched->asio_stoppable && ponyint_asio_stop())
{
// successfully stopped ASIO thread
// tell all scheduler threads to terminate
send_msg_all(sched->index, SCHED_TERMINATE, 0);

wake_suspended_threads(sched->index);

sched->ack_token++;
sched->ack_count = 0;
} else if(ponyint_asio_stop()) {
sched->asio_stopped = true;
} else if(ponyint_asio_stoppable()) {
sched->asio_stoppable = true;
sched->ack_token++;
sched->ack_count = 0;

// Run another CNF/ACK cycle.
send_msg_all_active(sched->index, SCHED_CNF, sched->ack_token);
} else {
// ASIO is not stoppable
sched->asio_stoppable = false;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/libponyrt/sched/scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct scheduler_t
uint32_t cpu;
uint32_t node;
bool terminate;
bool asio_stopped;
bool asio_stoppable;
bool asio_noisy;
pony_signal_event_t sleep_object;

Expand Down

0 comments on commit 2dab944

Please sign in to comment.