A design of abort handling module

The handling of abort of a operation is essential for a software. An abort represents:

  • An error condition
    • Internal errors
    • Subsystem errors
  • A user requested abort

The requirements of abort handling are:

  • Quickness: The ability to respond to an abort
  • Reliability: The measure of abort getting accepted at any phase of software execution
  • Robust: The resource cleanup and rendering system in an usable, stable state (no panic, exception or error)

Assume that there are two threads/ processes. One thread performs the job and another accepts request from the user. Abort can be requested from the job thread or job thread itself get aborted (error or another subsystem/layer error).

There are at least two approaches for abort handling that I have found in my experience:

  1. Using a check at multiple points in the execution path
  2. if (true == is_aborted) {
    goto exit_fun1;
    }
    
  3. Treating abort as an event and creating an event-handler
abort_me()
{
  enqueue(abort_event);
}
abort_handler(event e)
{
  case USER_ABORT:
    ....
    break;
  case INTERNAL_ABORT:
    ....
    break;
  default:
}

The first approach results litter in the code. Also, we need a variable acting as a flag to figure out occurrance of abort event. The use of flag needs a lock to get atomic value of abort flag. It make your code messy in a long run and things become difficult to manage and understand. A sample code could look as follows:

a()
{
  is_aborted();
  b();
  is_aborted();
  c();
  is_aborted();
}
b()
{
  is_aborted();
}

The latter approach is based on event handling. It needs more work. But it is cleaner and more intuitive. One possible implementation is by representing the software as a state machine. In a state machine, all events are managed by at least one queue. The state handler handles an abort event by switching to a state (named as “abort”/”error”). The handling of cleanup and appropriate action finds place in this handler.

state_machine()
{
   e = dequeue_event();

   switch(cur_state) {
        state_A:
            A_handler();
            break;
        state_B:
            B_handler();
            break;
        state_Abort:
            Abort_handler();
            break;
        default:
            assert(0);
   }
}

This model is discrete, predictable and manageable. We do not require a lock and flag checks. Thus we have better control and visibility of where an abort happened and where it was handled.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s