#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include "utils.h"

void lock_mu( pthread_mutex_t *mu )
{
   int st;

   printf_r("Child attempting to lock mutex\n");
   st = pthread_mutex_lock( mu );
   CHECK(st, "pthread_mutex_lock()");
   printf_r("... mutex locked\n");

   st = pthread_mutex_unlock( mu );
   CHECK(st, "pthread_mutex_unlock()");
   printf_r("... mutex unlocked\n");

   pthread_exit( (void *) SUCCESS );
}

void
init_mu( pthread_mutex_t *mu )
{
   int st;

   st = pthread_mutex_init( mu, NULL );
   CHECK( st, "pthread_mutex_init()");
}

void
destroy_mu( pthread_mutex_t *mu )
{
   int st;

   st = pthread_mutex_destroy( mu );
   CHECK(st, "pthread_mutex_destroy()");
}

static pthread_mutex_t mutex;
static pthread_t th;

int 
main( int argc, char *argv[] )
{
   int st, exit_status;
   pthread_attr_t th_attr;

   init_mu( &mutex );

   /*
    *  --  Set the child's thread attributes so that the main() thread
    *      can join it.
    */
   (void) pthread_attr_init( &th_attr );
   (void) pthread_attr_setdetachstate( &th_attr, PTHREAD_CREATE_JOINABLE );

   /*
    *  --  Now, lock the mutex, and create the child thread.  The child
    *      will attempt to lock the same mutex, and block until
    *      the mutex is released.
    */
   st = pthread_mutex_lock( &mutex );
   CHECK(st, "pthread_mutex_lock()");
   printf_r("Main has locked the mutex\n");

   /*
    *  --  This is the second thread that should block when it attempts to
    *      lock mu.
    */
   st = pthread_create( &th, &th_attr, (thread_proc_t)lock_mu, &mutex );
   CHECK(st, "pthread_create()");

   /*
    *  --  Unlock the mutex
    */
   st = pthread_mutex_unlock( &mutex );
   CHECK(st, "pthread_mutex_unlock()");
   printf_r("Main has unlocked the mutex\n");

   st = pthread_join( th, (void **) &exit_status );
   CHECK(st, "pthread_join()");

   if( exit_status != SUCCESS )
       printf_r("Failed to join\n");

   destroy_mu( &mutex );
   return( EXIT_SUCCESS );
}
