// File: /workspace/github_cpp_makefile_star2_O3/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 0x2b85(%rip), %rdi      # 0x5080
callq 0x2230
leaq 0x2b81(%rip), %rdi      # 0x5088
callq 0x2230
xorl %r15d, %r15d
leaq -0x48(%rbp), %rax
movq %r15, (%rax)
leaq -0x40(%rbp), %rcx
movq %rax, (%rcx)
leaq -0x90(%rbp), %rbx
movl $0x0, (%rbx)
movq $0x64, 0x8(%rbx)
movq %r15, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
movq %r15, 0x20(%rbx)
leaq 0x2abf(%rip), %rsi      # 0x5004
leaq -0x490(%rbp), %r14
movl $0x4, %r13d
movq %r14, %rdi
movl $0x4, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %eax, %eax
callq 0x2080
leaq 0x2abe(%rip), %rdi      # 0x502b
movq %r14, %rsi
xorl %eax, %eax
callq 0x2050
callq 0x2060
movq %rax, -0x68(%rbp)
leaq -0x60(%rbp), %r14
movq %r14, 0x8(%r14)
movq %r14, (%r14)
movq %r15, 0x10(%r14)
leaq -0x30(%rbp), %r15
leaq -0x38(%rbp), %r12
movq $0x0, -0x30(%rbp)
movl $0x20, %edi
callq 0x21c0
leaq 0x5718(%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, -0x38(%rbp)
movq %r15, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2170
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x25e7
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x18, %edi
callq 0x21c0
movq -0x30(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq $0x0, -0x30(%rbp)
movq %rax, %rdi
movq %r14, %rsi
callq 0x2070
incq -0x50(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x2860
decl %r13d
jne 0x2597
movl $0x4, %r13d
leaq -0x30(%rbp), %r14
leaq -0x38(%rbp), %r15
leaq -0x60(%rbp), %r12
movq $0x0, -0x30(%rbp)
movl $0x20, %edi
callq 0x21c0
leaq 0x56b9(%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, -0x38(%rbp)
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x2170
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x2686
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x18, %edi
callq 0x21c0
movq -0x30(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq $0x0, -0x30(%rbp)
movq %rax, %rdi
movq %r12, %rsi
callq 0x2070
incq -0x50(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x2860
decl %r13d
jne 0x2636
movl $0x4, %r13d
leaq -0x30(%rbp), %r15
leaq -0x38(%rbp), %r12
leaq -0x60(%rbp), %r14
movq $0x0, -0x30(%rbp)
movl $0x20, %edi
callq 0x21c0
leaq 0x565a(%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, -0x38(%rbp)
movq %r15, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2170
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x2725
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x18, %edi
callq 0x21c0
movq -0x30(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq $0x0, -0x30(%rbp)
movq %rax, %rdi
movq %r14, %rsi
callq 0x2070
incq -0x50(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x2860
decl %r13d
jne 0x26d5
leaq 0x2962(%rip), %rdi      # 0x50cb
callq 0x2230
movq %r14, %rbx
movq (%rbx), %rbx
cmpq %r14, %rbx
je 0x2784
leaq 0x10(%rbx), %rdi
callq 0x2270
jmp 0x2771
callq 0x2060
movq %rax, %r14
movq 0x5845(%rip), %rdi      # 0x7fd8
leaq 0x2894(%rip), %rsi      # 0x502e
movl $0xf, %edx
callq 0x21d0
subq -0x68(%rbp), %r14
movabsq $0x431bde82d7b634db, %rcx # imm = 0x431BDE82D7B634DB
movq %r14, %rax
imulq %rcx
movq %rdx, %rsi
shrq $0x3f, %rsi
sarq $0x12, %rdx
addq %rdx, %rsi
movq 0x580b(%rip), %rdi      # 0x7fd8
callq 0x21a0
leaq 0x2865(%rip), %rsi      # 0x503e
movl $0xf, %edx
movq %rax, %rdi
callq 0x21d0
leaq -0x60(%rbp), %rbx
movq %rbx, %rdi
callq 0x2ba2
movq %rbx, 0x8(%rbx)
movq %rbx, (%rbx)
movq $0x0, 0x10(%rbx)
movq %rbx, %rdi
callq 0x2ba2
xorl %eax, %eax
addq $0x468, %rsp            # imm = 0x468
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x284c
jmp 0x284c
jmp 0x284c
jmp 0x284c
jmp 0x2831
jmp 0x2845
jmp 0x284c
jmp 0x2831
jmp 0x2845
jmp 0x284c
movq %rax, %rbx
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x284f
movq (%rdi), %rax
callq *0x8(%rax)
jmp 0x284f
cmpq $0x0, -0x30(%rbp)
jne 0x2860
movq %rax, %rbx
leaq -0x60(%rbp), %rdi
callq 0x2ba2
movq %rbx, %rdi
callq 0x2280
callq 0x2090
nop