// File: /workspace/github_cpp_makefile_star2_O1/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 %r13d, %r13d
leaq -0x48(%rbp), %rax
movq %r13, (%rax)
leaq -0x40(%rbp), %rcx
movq %rax, (%rcx)
leaq -0x90(%rbp), %rbx
movl $0x0, (%rbx)
movq $0x64, 0x8(%rbx)
movq %r13, 0x10(%rbx)
movb $0x0, 0x18(%rbx)
movq %r13, 0x20(%rbx)
leaq 0x2abf(%rip), %rsi      # 0x5004
leaq -0x490(%rbp), %r14
movl $0x4, %r15d
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 %r13, 0x10(%r14)
leaq -0x38(%rbp), %r12
movq $0x0, -0x30(%rbp)
movl $0x20, %edi
callq 0x21c0
leaq 0x571c(%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)
leaq -0x30(%rbp), %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2170
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x25e4
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x18, %edi
callq 0x21c0
movq %r13, 0x10(%rax)
movq -0x30(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq %r13, -0x30(%rbp)
movq %rax, %rdi
movq %r14, %rsi
callq 0x2070
incq -0x50(%rbp)
cmpq %r13, -0x30(%rbp)
jne 0x2862
decl %r15d
jne 0x2593
movl $0x4, %r13d
xorl %r14d, %r14d
leaq -0x38(%rbp), %r15
leaq -0x60(%rbp), %r12
movq $0x0, -0x30(%rbp)
movl $0x20, %edi
callq 0x21c0
leaq 0x56be(%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)
leaq -0x30(%rbp), %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x2170
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x2682
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x18, %edi
callq 0x21c0
movq %r14, 0x10(%rax)
movq -0x30(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq %r14, -0x30(%rbp)
movq %rax, %rdi
movq %r12, %rsi
callq 0x2070
incq -0x50(%rbp)
cmpq %r14, -0x30(%rbp)
jne 0x2862
decl %r13d
jne 0x2631
movl $0x4, %r13d
xorl %r15d, %r15d
leaq -0x38(%rbp), %r12
leaq -0x60(%rbp), %r14
movq $0x0, -0x30(%rbp)
movl $0x20, %edi
callq 0x21c0
leaq 0x5660(%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)
leaq -0x30(%rbp), %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2170
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x2720
movq (%rdi), %rax
callq *0x8(%rax)
movl $0x18, %edi
callq 0x21c0
movq %r15, 0x10(%rax)
movq -0x30(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq %r15, -0x30(%rbp)
movq %rax, %rdi
movq %r14, %rsi
callq 0x2070
incq -0x50(%rbp)
cmpq %r15, -0x30(%rbp)
jne 0x2862
decl %r13d
jne 0x26cf
leaq 0x2968(%rip), %rdi      # 0x50cb
callq 0x2230
movq %r14, %rbx
movq (%rbx), %rbx
cmpq %r14, %rbx
je 0x277e
leaq 0x10(%rbx), %rdi
callq 0x2270
jmp 0x276b
callq 0x2060
movq %rax, %r14
movq 0x584b(%rip), %rdi      # 0x7fd8
leaq 0x289a(%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 0x5811(%rip), %rdi      # 0x7fd8
callq 0x21a0
leaq 0x286b(%rip), %rsi      # 0x503e
movl $0xf, %edx
movq %rax, %rdi
callq 0x21d0
leaq -0x60(%rbp), %rbx
movq %rbx, %rdi
callq 0x2c1a
movq %rbx, 0x8(%rbx)
movq %rbx, (%rbx)
movq $0x0, 0x10(%rbx)
movq %rbx, %rdi
callq 0x2c1a
xorl %eax, %eax
addq $0x468, %rsp            # imm = 0x468
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x284e
jmp 0x284e
jmp 0x284e
jmp 0x284e
jmp 0x282b
jmp 0x2847
jmp 0x284e
jmp 0x282b
jmp 0x2847
jmp 0x284e
movq %rax, %rbx
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x283d
movq (%rdi), %rax
callq *0x8(%rax)
movq $0x0, -0x38(%rbp)
jmp 0x2851
cmpq $0x0, -0x30(%rbp)
jne 0x2862
movq %rax, %rbx
leaq -0x60(%rbp), %rdi
callq 0x2c1a
movq %rbx, %rdi
callq 0x2280
callq 0x2090
nop