#include	<errno.h>
#include	<malloc.h>
#include	<pthread.h>
#include	<stdio.h>

// Dining philosophers problem using mutex locks

#define	FALSE	0
#define	TRUE	1

static int			howMany;
static pthread_mutex_t *	spoon;

static int
left( int x )
{
	return x;
}

static int
right( int x )
{
	return (x + 1) % howMany;
}

void *
philosopher( void * arg )
{
	int			id;
	int			gotit;
	int			i, limit = 4;

	pthread_detach( pthread_self() );
	id = (int) arg;
	printf( "BKR philosopher %d seated line %d\n", id, __LINE__ );
	for ( i = 0 ; i < limit ; i++ )
	{
		gotit = FALSE;
		do {
			pthread_mutex_lock( &spoon[ right(id) ] );
			switch ( pthread_mutex_trylock( &spoon[ left(id) ] ) )
			{
				case 0:
					gotit = TRUE;
					break;
				case EBUSY:
					pthread_mutex_unlock( &spoon[ right(id) ] );
					break;
				default:
					printf( "BKR:  What?\n" );
					break;
			}
		} while ( gotit == FALSE );
		printf( "Philosopher %d eats meal %d\n", id, i );
		pthread_mutex_unlock( &spoon[ left(id) ] );
		pthread_mutex_unlock( &spoon[ right(id) ] );
		sched_yield();
	}
	printf( "Philosopher %d leaves the room.\n", id );
	return 0;
}

int
main( int argc, char ** argv )
{
	pthread_t		tid;
	int			i;
	char *			func = "main";

	if ( argc < 2 )
	{
		printf( "Must specify number of philosophers on command line.\n" );
		return 1;
	}
	else if ( sscanf( argv[1], "%d", &howMany ) < 1 )
	{
		printf( "Must specify number of philosophers as an integer on command line.\n" );
		return 1;
	}
	else if ( (spoon = (pthread_mutex_t *)malloc( howMany*sizeof(pthread_mutex_t) )) == 0 )
	{
		printf( "malloc() failed.\n" );
		return 1;
	}
	else
	{
		printf( "Setting up %d spoons ...\n", howMany );
		for ( i = 0 ; i < howMany ; i++ )
		{
			if ( pthread_mutex_init( &spoon[i], 0 ) != 0 )
			{
				printf( "pthread_mutex_init() failed in %s()\n", func );
				return 1;
			}
		}
		for ( i = 0 ; i < howMany ; i++ )
		{
			if ( pthread_create( &tid, 0, philosopher, (void *)i ) != 0 )
			{
				printf( "pthread_create() failed in %s()\n", func );
				return 1;
			}
			printf( "BKR philosopher %d enters line %d\n", i, __LINE__ );
		}
		printf( "Everybody start eating ...\n" );
		pthread_exit( 0 );
	}
}
