// File: shutow[P]shared_mutex/test1.cpp
// Function: test1()
int test1()
{
	char output[1024];

	printf("test 1:\n");
	printf("using gx::shared_mutex in multiple readers / multiple writers mode\n");

	volatile long long value = 0;
	volatile long long * ptr_value = &value;

	gx::shared_mutex m(gx::shared_mutex::yield); // yield is the default and seemingly the best mode

	auto thread1 = [&]
	{
		for (uint32_t i = 0; i < LOOPS; i++)
		{
			gx::shared_lock l(m);
			l.upgrade_to_exclusive();
			ptr_value = nullptr;
			rand_wait();
			ptr_value = &value;
			*ptr_value = my_rand();
			l.downgrade_to_shared();
			volatile long long intvalue = 0;
			for (uint32_t i = 0; i < 1000; i++)
			{
				intvalue += *ptr_value * my_rand();
			}
			l.upgrade_to_exclusive();
			*ptr_value = intvalue;
		}
	};

	auto thread2 = [&]
	{
		for (uint32_t i = 0; i < LOOPS; i++)
		{
			gx::exclusive_lock l(m);
			ptr_value = nullptr;
			rand_wait();
			ptr_value = &value;
			*ptr_value = my_rand();
			l.downgrade_to_shared();
			volatile long long intvalue = 0;
			for (uint32_t i = 0; i < 1000; i++)
			{
				intvalue += *ptr_value * my_rand();
			}
			l.upgrade_to_exclusive();
			*ptr_value = intvalue;
		}
	};

	auto thread3 = [&]
	{
		for (uint32_t i = 0; i < LOOPS; i++)
		{
			gx::shareable_lock l(m, gx::lock_mode::shared); // or gx::shareable_lock_template<gx::shared_lock_t> l(m);
			volatile long long intvalue = 0;
			for (uint32_t i = 0; i < 1000; i++)
			{
				intvalue += *ptr_value * my_rand();
			}
			l.upgrade_to_exclusive();
			ptr_value = nullptr;
			rand_wait();
			ptr_value = &value;
			*ptr_value = intvalue;
		}
	};

	sprintf(output, "starting %i x 3 threads with %i loops\n", THREADS, LOOPS);
	printf("%s", output);

	auto timeMark1 = std::chrono::high_resolution_clock::now();

	std::list<std::thread> insert_threads;
	for (auto i = 0; i < THREADS; ++i) insert_threads.emplace_back(std::thread(thread1));
	for (auto i = 0; i < THREADS; ++i) insert_threads.emplace_back(std::thread(thread2));
	for (auto i = 0; i < THREADS; ++i) insert_threads.emplace_back(std::thread(thread3));

	printf("wait for threads to end\n");
	for (auto& t : insert_threads) t.join();

	auto timeMark2 = std::chrono::high_resolution_clock::now();
	std::cout << "execution took " << std::chrono::duration_cast<std::chrono::milliseconds>(timeMark2 - timeMark1).count() << " milliseconds\n\n";

	insert_threads.clear();

	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x570, %rsp            # imm = 0x570
leaq 0x9c6a(%rip), %rdi      # 0xc0cc
xorl %eax, %eax
movl %eax, -0x53c(%rbp)
movb %al, -0x519(%rbp)
callq 0x2040
movb -0x519(%rbp), %al
leaq 0x9c53(%rip), %rdi      # 0xc0d5
callq 0x2040
movl -0x53c(%rbp), %esi
movq $0x0, -0x408(%rbp)
leaq -0x408(%rbp), %rax
movq %rax, -0x530(%rbp)
movq %rax, -0x410(%rbp)
leaq -0x438(%rbp), %rdi
movq %rdi, -0x538(%rbp)
movl $0x64, %edx
callq 0x3630
movq -0x538(%rbp), %rsi
movq -0x530(%rbp), %rcx
movb -0x519(%rbp), %al
movq %rsi, -0x450(%rbp)
leaq -0x410(%rbp), %rdx
movq %rdx, -0x448(%rbp)
movq %rcx, -0x440(%rbp)
movq %rsi, -0x468(%rbp)
movq %rdx, -0x460(%rbp)
movq %rcx, -0x458(%rbp)
movq %rsi, -0x480(%rbp)
movq %rdx, -0x478(%rbp)
movq %rcx, -0x470(%rbp)
leaq 0x9bf3(%rip), %rsi      # 0xc119
leaq -0x400(%rbp), %rdi
movq %rdi, -0x528(%rbp)
movl $0x4, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
callq 0x2070
movq -0x528(%rbp), %rsi
movb -0x519(%rbp), %al
leaq 0x9be9(%rip), %rdi      # 0xc140
callq 0x2040
jmp 0x255e
callq 0x2050
movq %rax, -0x498(%rbp)
leaq -0x4b0(%rbp), %rdi
callq 0x3690
movl $0x0, -0x4b4(%rbp)
cmpl $0x4, -0x4b4(%rbp)
jge 0x2625
leaq -0x4c0(%rbp), %rdi
leaq -0x450(%rbp), %rsi
callq 0x28c0
jmp 0x25a2
leaq -0x4b0(%rbp), %rdi
leaq -0x4c0(%rbp), %rsi
callq 0x36b0
jmp 0x25b7
leaq -0x4c0(%rbp), %rdi
callq 0x36f0
movl -0x4b4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4b4(%rbp)
jmp 0x2580
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x488(%rbp)
movl %eax, -0x48c(%rbp)
jmp 0x28a3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x488(%rbp)
movl %eax, -0x48c(%rbp)
jmp 0x2897
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x488(%rbp)
movl %eax, -0x48c(%rbp)
leaq -0x4c0(%rbp), %rdi
callq 0x36f0
jmp 0x2897
movl $0x0, -0x4c4(%rbp)
cmpl $0x4, -0x4c4(%rbp)
jge 0x26a2
leaq -0x4d0(%rbp), %rdi
leaq -0x468(%rbp), %rsi
callq 0x2970
jmp 0x264d
leaq -0x4b0(%rbp), %rdi
leaq -0x4d0(%rbp), %rsi
callq 0x36b0
jmp 0x2662
leaq -0x4d0(%rbp), %rdi
callq 0x36f0
movl -0x4c4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c4(%rbp)
jmp 0x262f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x488(%rbp)
movl %eax, -0x48c(%rbp)
leaq -0x4d0(%rbp), %rdi
callq 0x36f0
jmp 0x2897
movl $0x0, -0x4d4(%rbp)
cmpl $0x4, -0x4d4(%rbp)
jge 0x271f
leaq -0x4e0(%rbp), %rdi
leaq -0x480(%rbp), %rsi
callq 0x2a20
jmp 0x26ca
leaq -0x4b0(%rbp), %rdi
leaq -0x4e0(%rbp), %rsi
callq 0x36b0
jmp 0x26df
leaq -0x4e0(%rbp), %rdi
callq 0x36f0
movl -0x4d4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4d4(%rbp)
jmp 0x26ac
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x488(%rbp)
movl %eax, -0x48c(%rbp)
leaq -0x4e0(%rbp), %rdi
callq 0x36f0
jmp 0x2897
leaq 0x9a1d(%rip), %rdi      # 0xc143
xorl %eax, %eax
callq 0x2040
jmp 0x272f
leaq -0x4b0(%rbp), %rax
movq %rax, -0x4e8(%rbp)
movq -0x4e8(%rbp), %rdi
callq 0x3720
movq %rax, -0x4f0(%rbp)
movq -0x4e8(%rbp), %rdi
callq 0x3750
movq %rax, -0x4f8(%rbp)
leaq -0x4f0(%rbp), %rdi
leaq -0x4f8(%rbp), %rsi
callq 0x3780
testb $0x1, %al
jne 0x277c
jmp 0x27ad
leaq -0x4f0(%rbp), %rdi
callq 0x37b0
movq %rax, -0x500(%rbp)
movq -0x500(%rbp), %rdi
callq 0x2250
jmp 0x279d
jmp 0x279f
leaq -0x4f0(%rbp), %rdi
callq 0x37d0
jmp 0x2763
callq 0x2050
movq %rax, -0x508(%rbp)
movq 0x11818(%rip), %rdi     # 0x13fd8
leaq 0x9995(%rip), %rsi      # 0xc15c
callq 0x2180
movq %rax, -0x548(%rbp)
jmp 0x27d5
leaq -0x508(%rbp), %rdi
leaq -0x498(%rbp), %rsi
callq 0x3820
movq %rax, -0x550(%rbp)
jmp 0x27f1
movq -0x550(%rbp), %rax
movq %rax, -0x518(%rbp)
leaq -0x518(%rbp), %rdi
callq 0x37f0
movq %rax, -0x558(%rbp)
jmp 0x2814
movq -0x558(%rbp), %rax
movq %rax, -0x510(%rbp)
leaq -0x510(%rbp), %rdi
callq 0x3870
movq %rax, -0x560(%rbp)
jmp 0x2837
movq -0x560(%rbp), %rsi
movq -0x548(%rbp), %rdi
callq 0x2290
movq %rax, -0x568(%rbp)
jmp 0x2853
movq -0x568(%rbp), %rdi
leaq 0x990b(%rip), %rsi      # 0xc16c
callq 0x2180
jmp 0x2868
leaq -0x4b0(%rbp), %rdi
callq 0x3890
leaq -0x4b0(%rbp), %rdi
callq 0x38c0
leaq -0x438(%rbp), %rdi
callq 0x38e0
xorl %eax, %eax
addq $0x570, %rsp            # imm = 0x570
popq %rbp
retq
leaq -0x4b0(%rbp), %rdi
callq 0x38c0
leaq -0x438(%rbp), %rdi
callq 0x38e0
movq -0x488(%rbp), %rdi
callq 0x2260
nopl (%rax,%rax)