/** Initialize several kinds of mutexes and lock each mutex twice.
 *  Note: locking a regular mutex twice causes a deadlock.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "../../config.h"


static void lock_twice(pthread_mutex_t* const p)
{
  if (pthread_mutex_trylock(p) != 0)
    fprintf(stderr, "first lock call failed !\n");
  if (pthread_mutex_trylock(p) != 0)
    fprintf(stderr, "second lock call failed !\n");
  if (pthread_mutex_unlock(p) != 0)
    fprintf(stderr, "first unlock call failed !\n");
  if (pthread_mutex_unlock(p) != 0)
    fprintf(stderr, "second unlock call failed !\n");
}

int main(int argc, char** argv)
{
#if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
  {
    pthread_mutex_t m = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

    fprintf(stderr, "Recursive mutex (statically initialized).\n");
    lock_twice(&m);
    pthread_mutex_destroy(&m);
  }
#endif
#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
  {
    pthread_mutex_t m;
    pthread_mutexattr_t attr;

    fprintf(stderr, "\nRecursive mutex (initialized via mutex attributes).\n");
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
    pthread_mutex_init(&m, &attr);
    pthread_mutexattr_destroy(&attr);
    lock_twice(&m);
    pthread_mutex_destroy(&m);
  }
#endif
#if defined(HAVE_PTHREAD_MUTEX_ERRORCHECK_NP)
  {
    pthread_mutex_t m;
    pthread_mutexattr_t attr;

    fprintf(stderr, "\nError checking mutex.\n");
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
    pthread_mutex_init(&m, &attr);
    pthread_mutexattr_destroy(&attr);
    lock_twice(&m);
    pthread_mutex_destroy(&m);
  }
#endif

  {
    pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

    fprintf(stderr, "\nNon-recursive mutex.\n");
    lock_twice(&m);
  }

  fprintf(stderr, "\nDone.\n");

  return 0;
}