/************************************************************************
The test module for the operating system interface

(c) 1995 Innobase Oy

Created 9/27/1995 Heikki Tuuri
*************************************************************************/


#include "../os0thread.h"
#include "../os0shm.h"
#include "../os0proc.h"
#include "../os0sync.h"
#include "../os0file.h"
#include "ut0ut.h"
#include "ut0mem.h"
#include "sync0sync.h"
#include "mem0mem.h"

#define _WIN32_WINNT	0x0400
#include "n:\program files\devstudio\vc\include\windows.h"
#include "n:\program files\devstudio\vc\include\winbase.h"

ulint	last_thr = 1;

byte	global_buf[4000000];

ulint*	cache_buf;

os_file_t	file;
os_file_t	file2;

os_event_t	gl_ready;

mutex_t		ios_mutex;
ulint		ios;
ulint		rnd	= 9837497;

/********************************************************************
Start function for threads in test1. */

ulint
thread(void* arg)
/*==============*/
{
	ulint	i;
	void*	arg2;
	ulint	count = 0;
	ulint	n;
	ulint	rnd_loc;
	byte	local_buf[2000];
	
	arg2 = arg;

	n = *((ulint*)arg);

/*	printf("Thread %lu started!\n", n); */
	
	for (i = 0; i < 8000; i++) {

		rnd_loc = rnd;
		rnd += 763482469;	
		
		ut_memcpy(global_buf + (rnd_loc % 1500000) + 8200, local_buf,
									2000);
		if (last_thr != n) {
			count++;
			last_thr = n;
		}

		if (i % 32 == 0) {
			os_thread_yield();
		}
	}

	printf("Thread %lu exits: %lu thread switches noticed\n", n, count);

	return(0);
}

/*********************************************************************
Test of the speed of wait for multiple events. */

void
testa1(void)
/*========*/
{
	ulint		i;
	os_event_t	arr[64];
	ulint		tm, oldtm;

	printf("-------------------------------------------------\n");
	printf("TEST A1. Speed of waits\n");
	
	for (i = 0; i < 64; i++) {
		arr[i] = os_event_create(NULL);
		ut_a(arr[i]);
	}

	os_event_set(arr[1]);
	
	oldtm = ut_clock();

	for (i = 0; i < 10000; i++) {
		os_event_wait_multiple(4, arr);
	}

	tm = ut_clock();

	printf("Wall clock time for %lu multiple waits %lu millisecs\n",
		i, tm - oldtm);

	oldtm = ut_clock();

	for (i = 0; i < 10000; i++) {
		os_event_wait(arr[1]);
	}

	tm = ut_clock();

	printf("Wall clock time for %lu single waits %lu millisecs\n",
		i, tm - oldtm);

	
	for (i = 0; i < 64; i++) {
		os_event_free(arr[i]);
	}
}
	
/*********************************************************************
Test for threads. */

void 
test1(void)
/*=======*/
{
	os_thread_t	thr[64];
	os_thread_id_t	id[64];
	ulint		n[64];
	ulint		tm, oldtm;
	ulint		i, j;
	
        printf("-------------------------------------------\n");
	printf("OS-TEST 1. Test of thread switching through yield\n");

	printf("Main thread %lu starts!\n", os_thread_get_curr_id());

    for (j = 0; j < 2; j++) {

	oldtm = ut_clock();

	for (i = 0; i < 64; i++) {
		n[i] = i;
	
		thr[i] = os_thread_create(thread, n + i, id + i);
/*		printf("Thread %lu created, id %lu \n", i, id[i]); */
	}

	for (i = 0; i < 64; i++) {
		os_thread_wait(thr[i]);
	}

	tm = ut_clock();
	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);

	oldtm = ut_clock();

	for (i = 0; i < 64; i++) {

		thr[5] = os_thread_create(thread, n + 5, id + 5);

/*		printf("Thread created, id %lu \n", id[5]); */

		os_thread_wait(thr[5]);
	}

	tm = ut_clock();
	printf("Wall clock time for single thread test %lu milliseconds\n",
								tm - oldtm);
    }
}

/*********************************************************************
Test for shared memory and process switching through yield. */

void 
test2(void)
/*=======*/
{
	os_shm_t	shm;
	ulint		tm, oldtm;
	ulint*		pr_no;
	ulint		count;
	ulint		i;
	bool		ret;
	os_process_t	proc;
	os_process_id_t	proc_id;
	
        printf("-------------------------------------------\n");
	printf("OS-TEST 2. Test of process switching through yield\n");

	shm = os_shm_create(1000, "TSOS_SHM");

	pr_no = os_shm_map(shm);

	*pr_no = 1;
	count = 0;

	ret = os_process_create("tsosaux.exe", NULL, &proc, &proc_id);

	printf("Last error: %lu\n", os_thread_get_last_error());

	ut_a(ret);

	printf("Process 1 starts test!\n");
	
	oldtm = ut_clock();

	for (i = 0; i < 500000; i++) {
		if (*pr_no != 1) {
			count++;
			*pr_no = 1;
		}

		os_thread_yield();
	}

	tm = ut_clock();

	printf("Process 1 finishes test: %lu process switches noticed\n",
		count);
	
	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);

	os_shm_unmap(shm);

	os_shm_free(shm);
}

#ifdef notdefined

/*********************************************************************
Test for asynchronous file io. */

void 
test3(void)
/*=======*/
{
	ulint	i;
	ulint	j;
	void*	mess;
	bool	ret;
	void*	buf;
	ulint	rnd;
	ulint	addr[64];
	ulint	serv[64];
	ulint	tm, oldtm;
	
        printf("-------------------------------------------\n");
	printf("OS-TEST 3. Test of asynchronous file io\n");

	/* Align the buffer for file io */

	buf = (void*)(((ulint)global_buf + 6300) & (~0xFFF)); 

	rnd = ut_time();

	rnd = rnd * 3416133;

	printf("rnd seed %lu\n", rnd % 4900);

	oldtm = ut_clock();
	
	for (i = 0; i < 32; i++) {
	
		ret = os_aio_read(file, buf, 8192 * (rnd % 4900), 0,
						8192, (void*)i);
		ut_a(ret);
		rnd += 1;
		ret = os_aio_wait(0, &mess);
		ut_a(ret);
	}

	tm = ut_clock();
	printf("Wall clock time for synchr. io %lu milliseconds\n",
			tm - oldtm);

	rnd = rnd * 3416133;

	printf("rnd seed %lu\n", rnd % 5000);

	oldtm = ut_clock();

    for (j = 0; j < 5; j++) {

	rnd = rnd + 3416133; 
	
	for (i = 0; i < 16; i++) {
		ret = os_aio_read(file, buf, 8192 * (rnd % 5000), 0, 8192,
					(void*)i);
		addr[i] = rnd % 5000;
		ut_a(ret);
		rnd += 1;
	}

	
	for (i = 0; i < 16; i++) {
		ret = os_aio_read(file, buf, 8192 * (rnd % 5000), 0, 8192,
					(void*)i);
		addr[i] = rnd % 5000;
		ut_a(ret);
		rnd += 1;
	}
	
	rnd = rnd + 3416133; 

	for (i = 0; i < 32; i++) {
		ret = os_aio_wait(0, &mess);
		ut_a(ret);
		ut_a((ulint)mess < 64);
		serv[(ulint)mess] = i;
	}
    }
	tm = ut_clock();
	printf("Wall clock time for aio %lu milliseconds\n", tm - oldtm);

	rnd = rnd * 3416133;

	printf("rnd seed %lu\n", rnd % 4900);

	oldtm = ut_clock();

for (j = 0; j < 5; j++) {
	
	rnd = rnd + 3416133;

	for (i = 0; i < 1; i++) {
		ret = os_aio_read(file, buf, 8192 * (rnd % 4900), 0,
						64 * 8192, (void*)i);
		ut_a(ret);
		rnd += 4;
		ret = os_aio_wait(0, &mess);
		ut_a(ret);
		ut_a((ulint)mess < 64);
	}
}
	tm = ut_clock();
	printf("Wall clock time for synchr. io %lu milliseconds\n",
			tm - oldtm);


/*
	for (i = 0; i < 63; i++) {
		printf("read %lu addr %lu served as %lu\n",
			i, addr[i], serv[i]);		
	}
*/	

	ut_a(ret);
}

/************************************************************************
Io-handler thread function. */

ulint
handler_thread(
/*===========*/
	void*	arg)
{
	ulint	segment;
	void*	mess;
	ulint	i;
	bool	ret;
	
	segment = *((ulint*)arg);

	printf("Thread %lu starts\n", segment);

	for (i = 0;; i++) {
		ret = os_aio_wait(segment, &mess);

		mutex_enter(&ios_mutex);
		ios++;
		mutex_exit(&ios_mutex);
		
		ut_a(ret);
/*		printf("Message for thread %lu %lu\n", segment,
						(ulint)mess); */
		if ((ulint)mess == 3333) {
			os_event_set(gl_ready);
		}
	}

	return(0);
}

/************************************************************************
Test of io-handler threads */

void 
test4(void)
/*=======*/
{
	ulint		i;
	ulint		j;
	bool		ret;
	void*		buf;
	ulint		rnd;
	ulint		tm, oldtm;
	os_thread_t	thr[5];
	os_thread_id_t	id[5];
	ulint		n[5];
	
        printf("-------------------------------------------\n");
	printf("OS-TEST 4. Test of asynchronous file io\n");

	/* Align the buffer for file io */

	buf = (void*)(((ulint)global_buf + 6300) & (~0xFFF)); 

	gl_ready = os_event_create(NULL);
	ios = 0;

	sync_init();
	mem_init();

	mutex_create(&ios_mutex);
	
	for (i = 0; i < 5; i++) {
		n[i] = i;

		thr[i] = os_thread_create(handler_thread, n + i, id + i);
	}

	rnd = 0;
	
	oldtm = ut_clock();

for (j = 0; j < 128; j++) {


	for (i = 0; i < 32; i++) {
		ret = os_aio_read(file, (byte*)buf + 8192 * (rnd % 100),
				8192 * (rnd % 4096), 0,
							8192, (void*)i);
		ut_a(ret);
		rnd += 1; 
	}

/*
	rnd += 67475941;

	for (i = 0; i < 1; i++) {
		ret = os_aio_read(file2, buf, 8192 * (rnd % 5000), 0,
						8192, (void*)i);
		ut_a(ret);
		rnd += 1;
	}
*/
}
	ret = os_aio_read(file, buf, 8192 * (rnd % 4096), 0, 8192,
							(void*)3333);
	ut_a(ret);

	ut_a(!os_aio_all_slots_free());
/*
	printf("Starting flush!\n");
	ret = os_file_flush(file);
	ut_a(ret);
	printf("Ending flush!\n");
*/
	tm = ut_clock();

	printf("All ios queued! N ios: %lu\n", ios);

	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);
	
	os_event_wait(gl_ready);

	tm = ut_clock();
	printf("N ios: %lu\n", ios);
	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);

	os_thread_sleep(2000000);

	printf("N ios: %lu\n", ios);

	ut_a(os_aio_all_slots_free());
}

/*************************************************************************
Initializes the asyncronous io system for tests. */

void
init_aio(void)
/*==========*/
{
	bool	ret;
	ulint	i;
	void*	buf;
	void*	mess;

	buf = (void*)(((ulint)global_buf + 6300) & (~0xFFF)); 

	os_aio_init(160, 5);
	file = os_file_create("j:\\tsfile2", OS_FILE_CREATE, OS_FILE_TABLESPACE,
				&ret);

	if (ret == FALSE) {
		ut_a(os_file_get_last_error() == OS_FILE_ALREADY_EXISTS);
	
		file = os_file_create("j:\\tsfile2", OS_FILE_OPEN,
			OS_FILE_TABLESPACE, &ret);

		ut_a(ret);
	} else {
	
		for (i = 0; i < 4100; i++) {
			ret = os_aio_write(file, buf, 8192 * i, 0, 8192, NULL);
			ut_a(ret);

			ret = os_aio_wait(0, &mess);

			ut_a(ret);
			ut_a(mess == NULL);
		}
	}

	file2 = os_file_create("F:\\tmp\\tsfile", OS_FILE_CREATE,
				OS_FILE_TABLESPACE,
				&ret);

	if (ret == FALSE) {
		ut_a(os_file_get_last_error() == OS_FILE_ALREADY_EXISTS);
	
		file2 = os_file_create("F:\\tmp\\tsfile", OS_FILE_OPEN,
			OS_FILE_TABLESPACE, &ret);

		ut_a(ret);
	} else {
	
		for (i = 0; i < 5000; i++) {
			ret = os_aio_write(file2, buf, 8192 * i, 0, 8192, NULL);
			ut_a(ret);

			ret = os_aio_wait(0, &mess);

			ut_a(ret);
			ut_a(mess == NULL);
		}
	}
}

/************************************************************************
Test of synchronous io */

void 
test5(void)
/*=======*/
{
	ulint		i, j, k;
	bool		ret;
	void*		buf;
	ulint		rnd = 0;
	ulint		tm = 0;
	ulint		oldtm = 0;
	os_file_t	files[1000];
	char		name[5];
	ulint		err;
	
        printf("-------------------------------------------\n");
	printf("OS-TEST 5. Test of creating and opening of many files\n");

	/* Align the buffer for file io */

	buf = (void*)(((ulint)global_buf + 6300) & (~0xFFF)); 

	name[2] = '.';
	name[3] = 'd';
	name[4] = '\0';

	oldtm = ut_clock();
	
	for (j = 0; j < 20; j++) {
	   for (i = 0; i < 20; i++) {
		name[0] = (char)(i + (ulint)'A');
		name[1] = (char)(j + (ulint)'A');
		files[j * 20 + i] = os_file_create(name, OS_FILE_CREATE,
			OS_FILE_NORMAL, &ret);
		if (!ret) {
			err = os_file_get_last_error();
		}
		ut_a(ret);
	  }
	}

	for (k = 0; k < i * j; k++) {
		ret = os_file_close(files[k]);
		ut_a(ret);
	}

	for (j = 0; j < 20; j++) {
	   for (i = 0; i < 20; i++) {
		name[0] = (char)(i + (ulint)'A');
		name[1] = (char)(j + (ulint)'A');
		ret = os_file_delete(name);
		ut_a(ret);
	  }
	}

	tm = ut_clock();
	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);
}

/************************************************************************
Test of synchronous io */

void 
test6(void)
/*=======*/
{
	ulint		i, j;
	bool		ret;
	void*		buf;
	ulint		rnd = 0;
	ulint		tm = 0;
	ulint		oldtm = 0;
	os_file_t	s_file;

        printf("-------------------------------------------\n");
	printf("OS-TEST 6. Test of synchronous io\n");

	buf = (void*)(((ulint)global_buf + 6300) & (~0xFFF)); 

	ret = os_file_close(file);
	ut_a(ret);

	ret = os_file_close(file2);
	ut_a(ret);
	
	s_file = os_file_create("tsfile", OS_FILE_OPEN,
					OS_FILE_NORMAL, &ret);
	if (!ret) {
		printf("Error no %lu\n", os_file_get_last_error());
	}
	
	ut_a(ret);

	rnd = ut_time() * 6346353;
	
	oldtm = ut_clock();

   for (j = 0; j < 100; j++) {

	rnd += 8072791;

	for (i = 0; i < 32; i++) {
		ret = os_file_read(s_file, buf, 8192 * (rnd % 5000), 0,
							8192);
		ut_a(ret);
		rnd += 1;
	}
   }

	tm = ut_clock();

	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);
}

/************************************************************************
Test of file size operations. */

void 
test7(void)
/*=======*/
{
	bool		ret;
	os_file_t	f;
	ulint		len;
	ulint		high;
	
        printf("-------------------------------------------\n");
	printf("OS-TEST 7. Test of setting and getting file size\n");

	
	f = os_file_create("sizefile", OS_FILE_CREATE, OS_FILE_TABLESPACE,
									&ret);
	ut_a(ret);

	ret = os_file_get_size(f, &len, &high);
	ut_a(ret);

	ut_a(len == 0);
	ut_a(high == 0);

	ret = os_file_set_size(f, 5000000, 0);
	ut_a(ret);

	ret = os_file_get_size(f, &len, &high);
	ut_a(ret);

	ut_a(len == 5000000);
	ut_a(high == 0);
	
	ret = os_file_set_size(f, 4000000, 0);
	ut_a(ret);

	ret = os_file_get_size(f, &len, &high);
	ut_a(ret);

	ut_a(len == 4000000);
	ut_a(high == 0);
	
	ret = os_file_close(f);
	ut_a(ret);

	ret = os_file_delete("sizefile");
	ut_a(ret);
}
#endif

/************************************************************************
Main test function. */

void 
main(void) 
/*======*/
{
	ulint			tm, oldtm;
	ulint			i;
	CRITICAL_SECTION	cs;
	ulint			sum;
	ulint			rnd;

	cache_buf = VirtualAlloc(NULL, 4 * 1024, MEM_COMMIT,
					PAGE_READWRITE /* | PAGE_NOCACHE */);
	oldtm = ut_clock();

	sum = 0;
	rnd = 0;
	
	for (i = 0; i < 1000000; i++) {
	
		sum += cache_buf[rnd * (16)];

		rnd += 1;

		if (rnd > 7) {
			rnd = 0;
		}
	}

	tm = ut_clock();

	printf("Wall clock time for cache test %lu milliseconds\n", tm - oldtm);

	InterlockedExchange(&i, 5);
	
	InitializeCriticalSection(&cs);

	oldtm = ut_clock();

	for (i = 0; i < 10000000; i++) {
	
		TryEnterCriticalSection(&cs);

		LeaveCriticalSection(&cs);
	}

	tm = ut_clock();
	printf("Wall clock time for test %lu milliseconds\n", tm - oldtm);

	testa1();

	test1();

/*	test2(); */

/*	init_aio(); */
/*
	test3();
*/
/*	test4();

	test5(); 

	test6();

	test7(); */
	
	printf("TESTS COMPLETED SUCCESSFULLY!\n");
}