/* Expected output:
Th 1: started
Th 1: Set max of A to 7
Th 1: Set max of B to 5
Th 1: Set max of C to 3
Th 2: started
Th 2: Set max of A to 5
Th 2: Set max of B to 2
Th 2: Set max of C to 2
Th 3: started
Th 3: Set max of A to 5
Th 3: Set max of B to 3
Th 3: Set max of C to 2
Th 3: Acquire 3 copies of A
Th 3: Got 3 copies of A
Th 2: Acquire 3 copies of A
Th 2: Got 3 copies of A
Th 3: Acquire 3 copies of B
Th 3: Got 3 copies of B
Th 1: Acquire 4 copies of A
Th 2: done
Th 1: Got 4 copies of A
Th 3: done
Th 1: done
*/

#include "safe_resource.h"
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>

#define NUM_RESOURCE 3
int res[NUM_RESOURCE];
#define NUM_THREAD 3

void tdie(char *msg, int thread_nr) {
	printf("Thread %d: %s--%s\n", thread_nr, msg, strerror(errno));
	safe_res_release_all();
	pthread_exit(0);
}

struct thread_data {
	int thread_nr;
	char *thread_ops;
};

void *thread_func(void *arg) {
	struct thread_data *data = (struct thread_data *)arg;
	printf("Th %d: started\n", data->thread_nr);
	char *curr = data->thread_ops;
	while (*curr) {
		int res_id, num_res, sleep_time;
		switch (curr[0]) {
		case 'A':
			res_id = curr[1]-'A';
			num_res = curr[2] - '0';
			printf("Th %d: Acquire %d copies of %c\n",
			       data->thread_nr, num_res, curr[1]);
			if (safe_res_acquire(res[res_id], num_res) == -1)
				tdie("safe_res_acquire", data->thread_nr);
			printf("Th %d: Got %d copies of %c\n",
			       data->thread_nr, num_res, curr[1]);
			break;
		case 'S':
			res_id = curr[1]-'A';
			num_res = curr[2] - '0';
			printf("Th %d: Set max of %c to %d\n",
			       data->thread_nr, curr[1], num_res);
			if (safe_res_set_max(res[res_id], num_res) == -1)
				tdie("safe_res_set_max", data->thread_nr);
			break;
		case 's':
			sleep_time = (curr[1]-'0')*10+(curr[2]-'0');
			sleep(sleep_time);
			break;
		default:
			errno = EINVAL;
			tdie("Unknown command", data->thread_nr);
		}
		curr += 4;
	}
	printf("Th %d: done\n", data->thread_nr);
	safe_res_release_all();
	return 0;
}

int main() {
	int i;
	struct thread_data data[NUM_THREAD] = {
		{ 1, "SA7-SB5-SC3-s05-AA4-s05-"},
		{ 2, "SA5-SB2-SC2-s02-AA3-s05-" },
		{ 3, "SA5-SB3-SC2-s01-AA3-s03-AB3-s04-"},
	};
	res[0] = safe_res_create(10);
	res[1] = safe_res_create(5);
	res[2] = safe_res_create(7);
	pthread_t threads[NUM_THREAD];
	for (i = 0; i < NUM_THREAD; ++i)
		pthread_create(threads+i, 0, thread_func, (void *)(data+i));
	for (i = 0; i < NUM_THREAD; ++i)
		pthread_join(threads[i], 0);
	return 0;
}

/* Local Variables: */
/* mode: C */
/* c-basic-offset: 8 */
/* compile-command: "gcc -Wall -g test_pthread.c safe_resource.o -lpthread -lstdc++" */
/* End: */

