#include <iostream>
#include <cstring>
#include <cstdint>
#include <unistd.h>
#include <ctime>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <boost/thread.hpp>
#define SHM_KEY  1234

using namespace std;

uint8_t random_uint8(unsigned int* seed) {
	return rand_r(seed)%256;
}

void delete_shared_memory_if_exists() {
	int shmId=shmget(SHM_KEY,1,0666);
	if (shmId == -1) {
		cout << "Error shmId failed "<< endl;
		_exit(1);
	}
	shmctl(shmId, IPC_RMID, NULL);
	cout <<"Memory deleted..!"<<endl;
}

void fill_random_range(uint8_t *a, size_t total_elements, unsigned int thread_id, unsigned int k) {
	size_t chunk = total_elements/k;
	size_t start = thread_id*chunk;
	size_t end;
	if (thread_id == k-1) {
		end = total_elements;
	} else {
		end = start+chunk;
	}
	unsigned int seed = time(NULL)^thread_id;
	for (size_t index = start;index<end; index++) {
		a[index] = random_uint8(&seed);
	}
}

void generate_a(uint8_t *a, size_t l, size_t n, unsigned int k) {
	size_t total_elements = l*n*n;
	boost::thread_group threads;
	for (unsigned int tid = 0;tid<k;tid++) {
		threads.create_thread(boost::bind(fill_random_range,a,total_elements,tid,k));
	}
	threads.join_all();
}

void create_and_generate_a(size_t n) {
	size_t total_elements = l*n*n;
	size_t total_bytes = l*n*n*sizeof(uint8_t);
	delete_shared_memory_if_exists();
	int shmId = shmget(SHM_KEY,total_bytes,IPC_CREAT|0666);
	if (shmId == -1) {
		cout <<"Create shared memory failed !" << endl;
		_exit(1);
	}
	void *base = shmat(shmId,NULL,0);
	uint8_t *a=(uint8_t *)base;
	unsigned int k = boost::thread::hardware_concurrency();
	generate_a(a, l, n, k);
	shmdt(base);
	_exit(0);
}

void delete_shared_memory() {
	int shmId = shmget(SHM_KEY,1,0666);
	if (shmId == -1) {
		cout <<"No shared memory chunk!" <<endl;
		_exit(1);
	}
	shmctl(shmId, IPC_RMID, NULL);
	cout << "Shared memory deleted !"<< endl;
	_exit(0);

int main(int argc, char **argv) {
	size_t l=0;
	size_t n=0;
	if (argc == 3) {
		size_t l = (size_t)atoi(argv[1]);
		size_t n=(size_t)atoi(argv[2]);
		if (n == 0 && l == 0) {
			delete_shared_memory();
		}
		create_and_generate(l,n);
	} else {
		cout << "Usage:./generator8 l N delete" << endl;
	}

	
	return 0;
}

