Deadlock detection

The following example shows how the mutex objects to detect and avoid deadlocks.

#include <stdio.h>
#include "OS_API.h"


HANDLE Mutex1Handle;
HANDLE Mutex2Handle;


void WaitForMutex(int TaskID, int MutexID)
{
  HANDLE MutexHandle;

  /* Get the mutex handle by mutex ID */
  MutexHandle = (MutexID == 1) ? Mutex1Handle : Mutex2Handle;

  /* Wait for mutex and print completion status */
  printf("Task%i is waiting for Mutex%i.\n", TaskID, MutexID);

  if(osWaitForObject(MutexHandle, AR_TIME_INFINITE))
    printf("Task%i acquires the Mutex%i.\n", TaskID, MutexID);

  else
    switch(osGetLastError())
    {
      /* Deadlock has been detected and wait function fails */
      case ERR_WAIT_DEADLOCK:
        printf("Task%i fails to acquire Mutex%i. Deadlock occurs.\n",
          TaskID, MutexID);
        break;

      /* Task acquires abandoned mutex */
      case ERR_WAIT_ABANDONED:
        printf("Task%i acquires abandoned Mutex%i.\n", TaskID, MutexID);
        break;

      /* This situation should never occurs in this test */
      default:
        printf("Task%i fails to acquire Mutex%i. Unknown reason.\n",
          TaskID, MutexID);
    }
}


ERROR Task1(PVOID Arg)
{
  /* Mark parameter as unused */
  AR_UNUSED_PARAM(Arg);

  /* Wait for Mutex1 */
  WaitForMutex(1, 1);

  /* Sleep for one second */
  printf("Task1 sleeps for one second...\n");
  osSleep(1000);

  /* Wait for Mutex2 */
  WaitForMutex(1, 2);

  /* Exit tasks */
  printf("Task1 ends.\n");
  return ERR_NO_ERROR;
}


ERROR Task2(PVOID Arg)
{
  /* Mark parameter as unused */
  AR_UNUSED_PARAM(Arg);

  /* Wait for Mutex1 */
  WaitForMutex(2, 2);

  /* Sleep for one second */
  printf("Task2 sleeps for one second...\n");
  osSleep(1000);

  /* Wait for Mutex2 */
  WaitForMutex(2, 1);

  /* Exit tasks */
  printf("Task2 ends.\n");
  return ERR_NO_ERROR;
}


int main(void)
{
  /* Initialization */
  arInit();
  stInit();
  osInit();

  /* Create objects */
  Mutex1Handle = osCreateMutex(NULL, FALSE);
  Mutex2Handle = osCreateMutex(NULL, FALSE);
  osCreateTask(Task1, NULL, 0, 0, FALSE);
  osCreateTask(Task2, NULL, 0, 1, FALSE);

  /* Start the operating system */
  osStart();

  /* Deinitialization */
  osDeinit();
  arDeinit();
  return 0;
}

The result on the console should look as follows:

Task1 is waiting for Mutex1.
Task1 acquires the Mutex1.
Task1 sleeps for one second...
Task2 is waiting for Mutex2.
Task2 acquires the Mutex2.
Task2 sleeps for one second...
Task1 is waiting for Mutex2.
Task2 is waiting for Mutex1.
Task2 fails to acquire Mutex1. Deadlock occurs.
Task2 ends.
Task1 acquires abandoned Mutex2.
Task1 ends.
SpaceShadow documentation