// File: /workspace/github_c_makefile_star2_O1/google[P]multichase/multiload.c
// Function: thread_start
static void *thread_start(void *data) {
  per_thread_t *args = data;

  // ensure every thread has a different RNG
  rng_init(args->x.thread_num);

  if (set_thread_affinity) {
    // find out which cpus we can run on and move us to an appropriate cpu
    cpu_set_t cpus;
    if (sched_getaffinity(0, sizeof(cpus), &cpus)) {
      perror("sched_getaffinity");
      exit(1);
    }
    int my_cpu;
    unsigned num = args->x.thread_num;
    for (my_cpu = 0; my_cpu < CPU_SETSIZE; ++my_cpu) {
      if (!CPU_ISSET(my_cpu, &cpus)) continue;
      if (num == 0) break;
      --num;
    }
    if (my_cpu == CPU_SETSIZE) {
      fprintf(stderr, "error: more threads than cpus available\n");
      exit(1);
    }
    CPU_ZERO(&cpus);
    CPU_SET(my_cpu, &cpus);
    if (sched_setaffinity(0, sizeof(cpus), &cpus)) {
      perror("sched_setaffinity");
      exit(1);
    }
  }
  if (args->x.run_test_type == RUN_CHASE) {
    // generate chases -- using a different mixer index for every
    // thread and for every parallel chase within a thread
    unsigned parallelism = args->x.chase->parallelism;
    for (unsigned par = 0; par < parallelism; ++par) {
      if (args->x.use_longer_chase) {
        args->x.cycle[par] = generate_chase_long(
            args->x.genchase_args, parallelism * args->x.thread_num + par,
            parallelism);
      } else {
        args->x.cycle[par] = generate_chase(
            args->x.genchase_args, parallelism * args->x.thread_num + par);
      }
    }
    // handle critword2 chases
    if (strcmp(args->x.chase->name, "critword2") == 0) {
      size_t offset = strtoul(args->x.extra_args, 0, 0);
      char *p = args->x.cycle[0];
      char *q = p;
      do {
        char *next = *(char **)p;
        *(void **)(p + offset) = next + offset;
        p = next;
      } while (p != q);
    }
    // handle critword chases
    if (strcmp(args->x.chase->name, "critword") == 0) {
      size_t offset = strtoul(args->x.extra_args, 0, 0);
      char *p = args->x.cycle[0];
      char *q = p;
      do {
        char *next = *(char **)p;
        *(void **)(p + offset) = next;
        *(void **)p = p + offset;
        p = next;
      } while (p != q);
    }
    // now flush our caches
    if (args->x.cache_flush_size) {
      size_t nr_elts = args->x.cache_flush_size / sizeof(size_t);
      size_t *p = args->x.flush_arena;
      size_t sum = 0;
      while (nr_elts) {
        sum += *p;
        ++p;
        --nr_elts;
      }
      args->x.dummy += sum;
    }
  } else {
    if (verbosity > 2)
      printf("thread_start(%d) memload generate buffers\n", args->x.thread_num);
    // generate buffers
    args->x.load_arena = (char *)alloc_arena_mmap(
                             page_size, use_thp,
                             args->x.load_total_memory + args->x.load_offset,
                             -1) + args->x.load_offset;
    memset(args->x.load_arena, 1,
           args->x.load_total_memory);  // ensure pages are mapped
  }

  if (verbosity > 2)
    printf("thread_start(%d) wait and/or wake up everyone\n",
           args->x.thread_num);
  // wait and/or wake up everyone if we're all ready
  pthread_mutex_lock(&wait_mutex);
  --nr_to_startup;
  if (nr_to_startup) {
    pthread_cond_wait(&wait_cond, &wait_mutex);
  } else {
    pthread_cond_broadcast(&wait_cond);
  }
  pthread_mutex_unlock(&wait_mutex);

  if (args->x.run_test_type == RUN_CHASE) {
    if (verbosity > 2) printf("thread_start: C(%d)\n", args->x.thread_num);
    args->x.chase->fn(data);
  } else {
    if (verbosity > 2) printf("thread_start: M(%d)\n", args->x.thread_num);
    args->x.memload->fn(data);
  }
  return NULL;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x88, %rsp
movq %rdi, %rbx
movl (%rdi), %ebp
movl $0x1, %edi
movl $0x20, %esi
callq 0x438ff0
movq %rax, %r14
movq $-0x60, %rax
movq %r14, %fs:(%rax)
movl $0x1, %edi
movl $0x30, %esi
callq 0x438ff0
movq $-0x58, %rcx
movq %rax, %fs:(%rcx)
testq %rax, %rax
je 0x403b89
movl $0x20, %edx
movl %ebp, %edi
movq %r14, %rsi
movq %rax, %rcx
callq 0x414c70
testl %eax, %eax
jne 0x403ba8
cmpb $0x0, 0x10bb1f(%rip)    # 0x50f3d0
jne 0x40396a
movq %rsp, %rdx
movl $0x80, %esi
xorl %edi, %edi
callq 0x4688d0
testl %eax, %eax
jne 0x403bad
movl (%rbx), %edx
movb $0x1, %al
xorl %ecx, %ecx
movq %rcx, %rsi
shrq $0x6, %rsi
movq (%rsp,%rsi,8), %rsi
btq %rcx, %rsi
jae 0x4038eb
testl %edx, %edx
je 0x40390a
decl %edx
cmpq $0x3ff, %rcx            # imm = 0x3FF
leaq 0x1(%rcx), %rsi
setb %al
movq %rsi, %rcx
cmpq $0x400, %rsi            # imm = 0x400
jne 0x4038d4
movl $0x400, %ecx            # imm = 0x400
cmpl $0x400, %ecx            # imm = 0x400
je 0x403bb2
xorps %xmm0, %xmm0
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movaps %xmm0, 0x50(%rsp)
movaps %xmm0, 0x40(%rsp)
movaps %xmm0, 0x30(%rsp)
movaps %xmm0, 0x20(%rsp)
movaps %xmm0, 0x10(%rsp)
movaps %xmm0, (%rsp)
testb $0x1, %al
je 0x403953
movl $0x1, %eax
shlq %cl, %rax
shrl $0x6, %ecx
orq %rax, (%rsp,%rcx,8)
movq %rsp, %rdx
movl $0x80, %esi
xorl %edi, %edi
callq 0x468940
testl %eax, %eax
jne 0x403bb7
cmpl $0x0, 0x9c(%rbx)
je 0x4039d9
cmpl $0x3, 0x10b9c6(%rip)    # 0x50f340
jl 0x40398c
movl (%rbx), %esi
leaq 0xd1d43(%rip), %rdi     # 0x4d56c8
xorl %eax, %eax
callq 0x4158b0
movq 0x10b99d(%rip), %rdi    # 0x50f330
movzbl 0x10b9aa(%rip), %esi    # 0x50f344
movq 0xb8(%rbx), %rdx
addq 0xb0(%rbx), %rdx
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
callq 0x409a57
addq 0xb8(%rbx), %rax
movq %rax, 0xa8(%rbx)
movq 0xb0(%rbx), %rdx
movq %rax, %rdi
movl $0x1, %esi
callq 0x4010b0
jmp 0x403adb
movq 0x80(%rbx), %rax
movl 0x2c(%rax), %r14d
testq %r14, %r14
je 0x403a22
xorl %r15d, %r15d
movl (%rbx), %esi
imull %r14d, %esi
addl %r15d, %esi
cmpb $0x1, 0x98(%rbx)
jne 0x403a0c
movq 0x70(%rbx), %rdi
movq %r14, %rdx
callq 0x4095ab
jmp 0x403a15
movq 0x70(%rbx), %rdi
callq 0x409380
movq %rax, 0x10(%rbx,%r15,8)
incq %r15
cmpq %r15, %r14
jne 0x4039ec
movq 0x80(%rbx), %rax
movq 0x10(%rax), %rdi
leaq 0xd19b0(%rip), %rsi     # 0x4d53e4
callq 0x4010c0
testl %eax, %eax
jne 0x403a64
movq 0x60(%rbx), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x414fd0
movq 0x10(%rbx), %rcx
movq %rcx, %rdx
movq (%rdx), %rsi
leaq (%rsi,%rax), %rdi
movq %rdi, (%rdx,%rax)
movq %rsi, %rdx
cmpq %rcx, %rsi
jne 0x403a51
movq 0x80(%rbx), %rax
movq 0x10(%rax), %rdi
leaq 0xd19b2(%rip), %rsi     # 0x4d5428
callq 0x4010c0
testl %eax, %eax
jne 0x403aa9
movq 0x60(%rbx), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x414fd0
movq 0x10(%rbx), %rcx
movq %rcx, %rdx
movq (%rdx), %rsi
leaq (%rdx,%rax), %rdi
movq %rsi, (%rdx,%rax)
movq %rdi, (%rdx)
movq %rsi, %rdx
cmpq %rcx, %rsi
jne 0x403a93
movq 0x90(%rbx), %rax
testq %rax, %rax
je 0x403adb
xorl %ecx, %ecx
cmpq $0x8, %rax
jb 0x403ad8
movq 0x88(%rbx), %rdx
shrq $0x3, %rax
xorl %esi, %esi
xorl %ecx, %ecx
addq (%rdx,%rsi,8), %rcx
incq %rsi
cmpq %rsi, %rax
jne 0x403acc
addl %ecx, 0x68(%rbx)
cmpl $0x3, 0x10b85e(%rip)    # 0x50f340
jl 0x403af4
movl (%rbx), %esi
leaq 0xd1c06(%rip), %rdi     # 0x4d56f3
xorl %eax, %eax
callq 0x4158b0
leaq 0x10b8e5(%rip), %rdi    # 0x50f3e0
callq 0x4316d0
decq 0x10b8d1(%rip)          # 0x50f3d8
je 0x403b1e
leaq 0x10b8f8(%rip), %rdi    # 0x50f408
leaq 0x10b8c9(%rip), %rsi    # 0x50f3e0
callq 0x42dd30
jmp 0x403b2a
leaq 0x10b8e3(%rip), %rdi    # 0x50f408
callq 0x42d6e0
leaq 0x10b8af(%rip), %rdi    # 0x50f3e0
callq 0x4325b0
movl 0x9c(%rbx), %ebp
cmpl $0x3, 0x10b7fd(%rip)    # 0x50f340
jl 0x403b62
testl %ebp, %ebp
leaq 0xd1bd4(%rip), %rax     # 0x4d5722
leaq 0xd1be2(%rip), %rdi     # 0x4d5737
cmoveq %rax, %rdi
movl (%rbx), %esi
xorl %eax, %eax
callq 0x4158b0
xorl %eax, %eax
testl %ebp, %ebp
setne %al
shll $0x5, %eax
movq 0x80(%rbx,%rax), %rax
movq %rbx, %rdi
callq *(%rax)
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
leaq 0xd1aa8(%rip), %rdi     # 0x4d5638
leaq 0xd1aac(%rip), %rsi     # 0x4d5643
leaq 0xd1ab5(%rip), %rcx     # 0x4d5653
movl $0x5d, %edx
callq 0x40e180
callq 0x401155
callq 0x40116a
callq 0x401194
callq 0x40117f