// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x468, %rsp            # imm = 0x468
leaq 0x2c3b(%rip), %rdi      # 0x5056
callq 0x2210
leaq 0x2c37(%rip), %rdi      # 0x505e
callq 0x2210
leaq -0x48(%rbp), %rax
movq $0x0, (%rax)
leaq -0x40(%rbp), %rcx
movq %rax, (%rcx)
leaq -0x90(%rbp), %rbx
andl $0x0, (%rbx)
movq $0x64, 0x8(%rbx)
andq $0x0, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
andq $0x0, 0x20(%rbx)
leaq 0x2b9f(%rip), %rsi      # 0x5004
leaq -0x490(%rbp), %r15
pushq $0x4
popq %r14
movq %r15, %rdi
movl %r14d, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %eax, %eax
callq 0x2070
leaq 0x2ba2(%rip), %rdi      # 0x502b
movq %r15, %rsi
xorl %eax, %eax
callq 0x2040
callq 0x2050
movq %rax, -0x50(%rbp)
leaq -0x68(%rbp), %r15
movq %r15, 0x8(%r15)
movq %r15, (%r15)
andq $0x0, 0x10(%r15)
leaq -0x38(%rbp), %r13
leaq -0x30(%rbp), %r12
subl $0x1, %r14d
jb 0x251a
andq $0x0, -0x38(%rbp)
pushq $0x20
popq %rdi
callq 0x21b0
leaq 0x57fa(%rip), %rcx      # 0x7cc8
movq %rcx, (%rax)
movq %rbx, 0x8(%rax)
leaq -0x40(%rbp), %rcx
movq %rcx, 0x10(%rax)
leaq -0x48(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq %rax, -0x30(%rbp)
movq %r13, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2160
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x2505
movq (%rdi), %rax
callq *0x8(%rax)
movq %r15, %rdi
movq %r13, %rsi
callq 0x29e6
movq %r13, %rdi
callq 0x29f6
jmp 0x24b4
pushq $0x4
popq %r14
leaq -0x38(%rbp), %r15
leaq -0x30(%rbp), %r12
leaq -0x68(%rbp), %r13
subl $0x1, %r14d
jb 0x2590
andq $0x0, -0x38(%rbp)
pushq $0x20
popq %rdi
callq 0x21b0
leaq 0x57c4(%rip), %rcx      # 0x7d08
movq %rcx, (%rax)
movq %rbx, 0x8(%rax)
leaq -0x40(%rbp), %rcx
movq %rcx, 0x10(%rax)
leaq -0x48(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq %rax, -0x30(%rbp)
movq %r15, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2160
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x257b
movq (%rdi), %rax
callq *0x8(%rax)
movq %r13, %rdi
movq %r15, %rsi
callq 0x29e6
movq %r15, %rdi
callq 0x29f6
jmp 0x252a
pushq $0x4
popq %r15
leaq -0x38(%rbp), %r12
leaq -0x30(%rbp), %r13
leaq -0x68(%rbp), %r14
subl $0x1, %r15d
jb 0x2606
andq $0x0, -0x38(%rbp)
pushq $0x20
popq %rdi
callq 0x21b0
leaq 0x578e(%rip), %rcx      # 0x7d48
movq %rcx, (%rax)
movq %rbx, 0x8(%rax)
leaq -0x40(%rbp), %rcx
movq %rcx, 0x10(%rax)
leaq -0x48(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq %rax, -0x30(%rbp)
movq %r12, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x2160
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x25f1
movq (%rdi), %rax
callq *0x8(%rax)
movq %r14, %rdi
movq %r12, %rsi
callq 0x29e6
movq %r12, %rdi
callq 0x29f6
jmp 0x25a0
leaq 0x2a94(%rip), %rdi      # 0x50a1
callq 0x2210
movq %r14, %rbx
movq (%rbx), %rbx
cmpq %r14, %rbx
je 0x2628
leaq 0x10(%rbx), %rdi
callq 0x2250
jmp 0x2615
callq 0x2050
movq %rax, %rbx
movq 0x59a1(%rip), %rdi      # 0x7fd8
leaq 0x29f0(%rip), %rsi      # 0x502e
callq 0x21a0
movq %rax, %rdi
subq -0x50(%rbp), %rbx
movl $0xf4240, %ecx          # imm = 0xF4240
movq %rbx, %rax
cqto
idivq %rcx
movq %rax, %rsi
callq 0x2190
leaq 0x29d8(%rip), %rsi      # 0x503e
movq %rax, %rdi
callq 0x21a0
leaq -0x68(%rbp), %rbx
movq %rbx, %rdi
callq 0x2a06
movq %rbx, %rdi
callq 0x2a28
xorl %eax, %eax
addq $0x468, %rsp            # imm = 0x468
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x26a8
jmp 0x26a8
jmp 0x26a8
jmp 0x26a8
jmp 0x26ad
jmp 0x26c1
jmp 0x26a8
jmp 0x26ad
jmp 0x26c1
movq %rax, %rbx
jmp 0x26cd
movq %rax, %rbx
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x26cd
movq (%rdi), %rax
callq *0x8(%rax)
jmp 0x26cd
movq %rax, %rbx
leaq -0x38(%rbp), %rdi
callq 0x29f6
leaq -0x68(%rbp), %rdi
callq 0x2a28
movq %rbx, %rdi
callq 0x2260