#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 l, 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);
	cout << "Shared memory created sucess!" <<endl;
	_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) {
		l=(size_t)atoi(argv[1]);
		n=(size_t)atoi(argv[2]);
		if (n==0 && l==0) {
			delete_shared_memory();
		}
		create_and_generate_a(l,n);


	} else {
		cout << "Usage:./generator8 l N" << endl;
		_exit(1);
	}	

	return 0;
}
