// File: /workspace/github_c_makefile_star2_O3/google[P]multichase/multichase.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);
    }
  }

  // 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 * args->x.nr_threads);
    } 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);
  }

  // handle branch chases
  if (!strcmp(args->x.chase->name, "branch")) {
    void *p = args->x.cycle[0];
    args->x.branch_chunk_size = convert_pointers_to_branches(p, 200);
#if defined(__aarch64__)
    __builtin___clear_cache(
        args->x.genchase_args->arena,
        args->x.genchase_args->arena + args->x.genchase_args->total_memory);
#endif
  }
  
  // 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;
  }

  // wait and/or wake up everyone if we're all ready
  pthread_mutex_lock(&wait_mutex);
  if (nr_to_startup == 1) {
    if (!strcmp(args->x.chase->name, "branch")) {
      // Change buffer to executable before letting the chases run.
      make_buffer_executable(args->x.genchase_args->arena,
                             args->x.genchase_args->total_memory);
    }
  }
  --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);

  args->x.chase->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 0x437310
movq %rax, %r14
movq $-0x60, %rax
movq %r14, %fs:(%rax)
movl $0x1, %edi
movl $0x30, %esi
callq 0x437310
movq $-0x58, %rcx
movq %rax, %fs:(%rcx)
testq %rax, %rax
je 0x4031e5
movl $0x20, %edx
movl %ebp, %edi
movq %r14, %rsi
movq %rax, %rcx
callq 0x4130a0
testl %eax, %eax
jne 0x403204
cmpb $0x0, 0x108422(%rip)    # 0x50b3a0
jne 0x40300f
movq %rsp, %rdx
movl $0x80, %esi
xorl %edi, %edi
callq 0x466bd0
testl %eax, %eax
jne 0x403209
movl (%rbx), %eax
xorl %ecx, %ecx
movq %rcx, %rdx
shrq $0x6, %rdx
movq (%rsp,%rdx,8), %rdx
btq %rcx, %rdx
jae 0x402fb6
testl %eax, %eax
je 0x402fc7
decl %eax
incq %rcx
cmpq $0x400, %rcx            # imm = 0x400
jne 0x402f9f
callq 0x401194
xorps %xmm0, %xmm0
movq %rsp, %rdx
movaps %xmm0, 0x70(%rdx)
movaps %xmm0, 0x60(%rdx)
movaps %xmm0, 0x50(%rdx)
movaps %xmm0, 0x40(%rdx)
movaps %xmm0, 0x30(%rdx)
movaps %xmm0, 0x20(%rdx)
movaps %xmm0, 0x10(%rdx)
movaps %xmm0, (%rdx)
movl $0x1, %eax
shlq %cl, %rax
shrl $0x6, %ecx
orq %rax, (%rsp,%rcx,8)
movl $0x80, %esi
xorl %edi, %edi
callq 0x466c40
testl %eax, %eax
jne 0x40320e
movq 0x78(%rbx), %rax
movl 0x2c(%rax), %r14d
testq %r14, %r14
je 0x40305a
xorl %r15d, %r15d
movq 0x68(%rbx), %rdi
movl (%rbx), %esi
imull %r14d, %esi
addl %r15d, %esi
cmpb $0x1, 0x90(%rbx)
jne 0x403044
movq 0x70(%rbx), %rdx
imulq %r14, %rdx
callq 0x408983
jmp 0x403049
callq 0x408758
movq %rax, 0x8(%rbx,%r15,8)
incq %r15
cmpq %r15, %r14
jne 0x40301f
movq 0x78(%rbx), %rax
movq 0x10(%rax), %r14
leaq 0xcfeb6(%rip), %rsi     # 0x4d2f1b
movq %r14, %rdi
callq 0x4010b8
testl %eax, %eax
jne 0x4030a0
movq 0x58(%rbx), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x413400
movq 0x8(%rbx), %rcx
movq %rcx, %rdx
movq (%rdx), %rsi
leaq (%rsi,%rax), %rdi
movq %rdi, (%rdx,%rax)
movq %rsi, %rdx
cmpq %rcx, %rsi
jne 0x403085
movq 0x78(%rbx), %rax
movq 0x10(%rax), %r14
leaq 0xcfeb8(%rip), %rsi     # 0x4d2f5f
movq %r14, %rdi
callq 0x4010b8
testl %eax, %eax
jne 0x4030e5
movq 0x58(%rbx), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x413400
movq 0x8(%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 0x4030c7
movq 0x78(%rbx), %rax
movq 0x10(%rax), %r14
leaq 0xcfb0d(%rip), %rsi     # 0x4d2bf9
movq %r14, %rdi
callq 0x4010b8
testl %eax, %eax
jne 0x40310c
movq 0x8(%rbx), %rdi
movl $0xc8, %esi
callq 0x409318
movl %eax, 0x94(%rbx)
movq 0x88(%rbx), %rax
testq %rax, %rax
je 0x40313e
xorl %ecx, %ecx
cmpq $0x8, %rax
jb 0x40313b
movq 0x80(%rbx), %rdx
shrq $0x3, %rax
xorl %esi, %esi
xorl %ecx, %ecx
addq (%rdx,%rsi,8), %rcx
incq %rsi
cmpq %rsi, %rax
jne 0x40312f
addl %ecx, 0x60(%rbx)
leaq 0x10826b(%rip), %rdi    # 0x50b3b0
callq 0x42f9f0
movq 0x108257(%rip), %rax    # 0x50b3a8
cmpq $0x1, %rax
jne 0x403193
movq 0x78(%rbx), %rax
movq 0x10(%rax), %rdi
leaq 0xcfa93(%rip), %rsi     # 0x4d2bf9
callq 0x4010b8
testl %eax, %eax
je 0x40317c
movq $0x0, 0x10822e(%rip) # 0x50b3a8
jmp 0x4031b4
movq 0x68(%rbx), %rax
movq (%rax), %rdi
movq 0x8(%rax), %rsi
callq 0x4091f4
movq 0x108215(%rip), %rax    # 0x50b3a8
decq %rax
movq %rax, 0x10820b(%rip)    # 0x50b3a8
je 0x4031b4
leaq 0x108232(%rip), %rdi    # 0x50b3d8
leaq 0x108203(%rip), %rsi    # 0x50b3b0
callq 0x42c050
jmp 0x4031c0
leaq 0x10821d(%rip), %rdi    # 0x50b3d8
callq 0x42ba00
leaq 0x1081e9(%rip), %rdi    # 0x50b3b0
callq 0x4308d0
movq 0x78(%rbx), %rax
movq %rbx, %rdi
callq *(%rax)
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
leaq 0xcfdb5(%rip), %rdi     # 0x4d2fa1
leaq 0xcfdb9(%rip), %rsi     # 0x4d2fac
leaq 0xcfdc2(%rip), %rcx     # 0x4d2fbc
movl $0x5d, %edx
callq 0x40c5b0
callq 0x401155
callq 0x40116a
callq 0x40117f