/*
Race Condition Random Seeder Release 1.0
Science and technology promotion license applied.
(c) Zhikai Wang/ www.heteroclinic.net 2013
*/
/*
Introduction:
Race Condition Random Seeder Release 1.0 is a tool aiming to create random seeds for random generators. It ulilizes modern computer systems' high frequency CPU clock and multitasking in paralell features. By creating man-made race condition, we retrieve a volatile boolean value that threads race upon. The values retrieved thus form a bit-bundle representing a numerical value.
The C++ implementation has four parts:
Part 1 is a test to validate the bit ops functions.
Part 2 is a test to validate the threading ops functionality.
part 3 runs a statitistic or poll. In this part, we want to make sure the 'true' or 'false' are distributed randomly but statistically evenly.
It is suggested to design more complex functions to do such test/poll. When the system demonstrates stable behavior, it is time to retrieve the 'shared' values.
The program will be affected by concrete systems' thread slicing settings, system work load etc.
Like most engineering products, it needs a permitting condition. Thus we programmed this part for the users' evaluation.
So there are some values to be tuned with:
- unsigned int sleepinmiddle = 0;
- unsigned  int noofthreads = 3; // the more threads, the higher competition, thus the randomness
- unsigned int start_interval =1000 ;
- unsigned int start_interval2 =1000 ;
- const unsigned int racer_sleep_value = 0; 
It is suggested sleepinmiddle would be one more order bigger than racer_sleep_value. In Cygwin environment, we set both as 0.
Part 4 is an example of how to get unsigned long long random values.
Each part should be compiled and run independently.
This program due to its nature will not be of high performance. It is suggested to be used as a seeder program for other random generators, e.g. linear congruential random generator etc.
Due to the limititation of resources, this program is only tested in Cygwin settings.
*/
/*
How to run (Cygwin/Linux/UNIX) in Shell console:
wget www.heteroclinic.net/attached/RaceConditionRandomSeederR1d0.cpp
g++ -o RaceConditionRandomSeederR1d0.exe RaceConditionRandomSeederR1d0.cpp -lpthread
./RaceConditionRandomSeederR1d0.exe
*/
#ifndef __RACECONDITIONRANDOMSEEDER
#define __RACECONDITIONRANDOMSEEDER
#include <deque>
#include <pthread.h>
#include <iostream>
#include <string.h>
#include <bitset>
#include <limits>
#include <unistd.h> // for usleep
#endif

typedef std::numeric_limits< unsigned long long > ulllimit;


std::deque<pthread_t  *> racers;
std::deque<int > ret_racers;
volatile bool shared = false;
volatile bool halted = false;
void * racer( void *ptr );
const unsigned int racer_sleep_value = 0;
inline void SetAULLatBit ( unsigned long long  & input , unsigned int bitposlowestis0, bool bv) 
{
			unsigned long upper_pattern = 0L;
			unsigned long lower_pattern = 0L;
	memcpy(&lower_pattern, &input, sizeof lower_pattern);
	memcpy(&upper_pattern, (char *) &input + sizeof lower_pattern, sizeof upper_pattern);
	if (bitposlowestis0 >64)
		return ;
	else {
		if (bitposlowestis0 < 31) {
			if (bv)
				input |= 1 << bitposlowestis0;
			else
				//input |= 0 << bitposlowestis0;
				input &= ~(1 << bitposlowestis0);
			
				
		} else if (bitposlowestis0==31) { //there is a bug when bitposlowestis0== 32

			if (bv)
				input |= 1 << bitposlowestis0;
			else
				//input |= 0 << bitposlowestis0;
				input &= ~(1 << bitposlowestis0);
			memcpy( (char *) &input + sizeof lower_pattern,&upper_pattern, sizeof upper_pattern);				
		}
		else {



			if (bv)
				upper_pattern |= 1 << (bitposlowestis0-32);
			else
				//upper_pattern |= 0 << (bitposlowestis0-32);
				upper_pattern &= ~(1 << bitposlowestis0-32);
				
			memcpy( (char *) &input + sizeof lower_pattern,&upper_pattern, sizeof upper_pattern);				
		}
	}
};
void statTest (unsigned int size) {
	bool * barr = new bool [size];
	unsigned int i = 0;
	for (i = 0; i <size; i++){
		barr[i] = shared;
	}
	unsigned int fcount = 0;
	for (i = 0; i <size; i++){
		if (barr[i] == false ) {
			++fcount; 
		};
	}
	std::cout<<"STAT:"<<std::endl;
	std::cout<<size <<"\t"<<fcount<<"\t"<<size-fcount <<std::endl;
	
}
void printULLinBits (unsigned long long start_pattern) {
	//unsigned long long start_pattern = ULLONG_MAX;
	unsigned long upper_pattern = 0LL;
	unsigned long lower_pattern = 0LL;

	memcpy(&lower_pattern, &start_pattern, sizeof lower_pattern);
	memcpy(&upper_pattern, (char *) &start_pattern + sizeof lower_pattern, sizeof upper_pattern);
	
	std::bitset<32> bsup(upper_pattern);
	std::bitset<32> bslo(lower_pattern);
	std::cout<<bsup <<bslo <<std::endl; 
}

const unsigned long long getARandomULL (unsigned int sleepinmiddle = 0) {
unsigned long long input  =0;
		unsigned long upper_pattern = 0L;
			unsigned long lower_pattern = 0L;
	memcpy(&lower_pattern, &input, sizeof lower_pattern);
	memcpy(&upper_pattern, (char *) &input + sizeof lower_pattern, sizeof upper_pattern);

	unsigned int i = 0;
	for (i = 0; i<64; i++ ) {
		if (i < 32) {
			if (shared)
				input |= 1 << i;
			else
				//input |= 0 << bitposlowestis0;
				input &= ~(1 << i);
		} else {
					if (shared)
				upper_pattern |= 1 << (i-32);
			else
				upper_pattern &= ~(1 << i-32);
				
			memcpy( (char *) &input + sizeof lower_pattern,&upper_pattern, sizeof upper_pattern);		
		
		}
		usleep (sleepinmiddle);
	}

return input;;

}

int main () {

/* part 1 bit ops
const unsigned int ULLbitslength = 64;

	unsigned int j = 0;
	for (j = 0; j<64; j++ ) {
		unsigned long long v = 0LL;
		SetAULLatBit(v,j,true);
		//std::cout<<v<<std::endl;
		printULLinBits (v);
	}
	
	//ULLMAX 18446744073709551615
	std::cout.precision(ulllimit::digits10);
	for (j = 0; j<64; j++ ) {
		unsigned long long v = 18446744073709551615ULL;
		SetAULLatBit(v,j,false);
		//std::cout<<v<<std::endl;
		printULLinBits (v);
	}
 part 1 */
 
 
 
 

/* part 2 threading ops	
	unsigned  int noofthreads = 3;
	unsigned  int bitsofresults = 32;

	int i = 0;
	for (i = 0; i<noofthreads; i++) {
		pthread_t  * tmp_pt = new pthread_t();
		racers.push_back(tmp_pt);
		ret_racers.push_back(pthread_create( tmp_pt, NULL, racer, NULL));
	}
	halted = true;
	for (i = 0; i<noofthreads; i++) {
		 pthread_join( *racers.front(),NULL);
		 racers.pop_front();
	}
		for (std::deque<int >::const_iterator iter = ret_racers.begin();
		iter != ret_racers.end(); iter++)
		std::cout<<(*iter)<<std::endl;
 part 2 threading ops*/


/* part 3 run a statitistic
	unsigned  int noofthreads = 3;
	unsigned  int bitstorun = 32;
	unsigned int start_interval =1000 ;//us 
	unsigned int start_interval2 =1000 ;//us 
	

	int i = 0;
	for (i = 0; i<noofthreads; i++) {
		pthread_t  * tmp_pt = new pthread_t();
		racers.push_back(tmp_pt);
		usleep ( start_interval);
		ret_racers.push_back(pthread_create( tmp_pt, NULL, racer, NULL));
	}
	
	usleep ( start_interval);
	unsigned int runs = 22;
	unsigned int mul = 2;
	
	for (i= 0; i< runs; i++ ) {
	mul *= 2;
	statTest (mul);
	}
	
	halted = true;
	
	 
	
	
	
	for (i = 0; i<noofthreads; i++) {
		 pthread_join( *racers.front(),NULL);
		 racers.pop_front();
	}
		for (std::deque<int >::const_iterator iter = ret_racers.begin();
		iter != ret_racers.end(); iter++)
		std::cout<<(*iter)<<std::endl;
 part 3 run a statitistic*/

 /* part 4 get ULL random number */
	unsigned  int noofthreads = 3;
	unsigned  int bitstorun = 32;
	unsigned int start_interval =1000 ;//us 
	unsigned int start_interval2 =1000 ;//us 
	

	int i = 0;
	for (i = 0; i<noofthreads; i++) {
		pthread_t  * tmp_pt = new pthread_t();
		racers.push_back(tmp_pt);
		usleep ( start_interval);
		ret_racers.push_back(pthread_create( tmp_pt, NULL, racer, NULL));
	}
	
	usleep ( start_interval);
	unsigned int runs = 32;
	
	for (i= 0; i< runs; i++ ) {
		// you can tune the argument value of getARandomULL() and observer the bits pattern
		unsigned long long result = getARandomULL(10);
		//unsigned long long result = getARandomULL(0);
		std::cout <<result <<"\t\t"; 
		//printULLinBits (getARandomULL(10));
		printULLinBits (result);
	}
	
	halted = true;
	
	 
	
	
	
	for (i = 0; i<noofthreads; i++) {
		 pthread_join( *racers.front(),NULL);
		 racers.pop_front();
	}
		for (std::deque<int >::const_iterator iter = ret_racers.begin();
		iter != ret_racers.end(); iter++)
		std::cout<<(*iter)<<std::endl;
 /*part 4 ULL random number */

return 0;
}

void *racer( void *ptr )
{
     //char *message;
     //message = (char *) ptr;
     //printf("%s \n", message);
	 while (!halted) {
		shared=!shared;
		usleep(racer_sleep_value);
	 }
}
