// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x130, %rsp            # imm = 0x130
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movl (%rax), %edi
callq 0x402ec0
cmpl $0x0, 0x10d137(%rip)    # 0x510110
je 0x4031c7
xorl %edi, %edi
movl $0x80, %esi
leaq -0x90(%rbp), %rdx
callq 0x46e050
cmpl $0x0, %eax
je 0x40300d
leaq 0xd701f(%rip), %rdi     # 0x4da01d
callq 0x41b6b0
movl $0x1, %edi
callq 0x41a3f0
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x98(%rbp)
movl $0x0, -0x94(%rbp)
cmpl $0x400, -0x94(%rbp)     # imm = 0x400
jge 0x4030e3
movslq -0x94(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x403094
movq -0xa0(%rbp), %rax
shrq $0x6, %rax
movq -0x90(%rbp,%rax,8), %rax
movq -0xa0(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %edx
shlq %cl, %rdx
movq %rdx, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x124(%rbp)
jmp 0x40309e
xorl %eax, %eax
movl %eax, -0x124(%rbp)
jmp 0x40309e
movl -0x124(%rbp), %eax
movl %eax, -0xa4(%rbp)
cmpl $0x0, -0xa4(%rbp)
jne 0x4030b5
jmp 0x4030cf
cmpl $0x0, -0x98(%rbp)
jne 0x4030c0
jmp 0x4030e3
movl -0x98(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x98(%rbp)
movl -0x94(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x94(%rbp)
jmp 0x403023
cmpl $0x400, -0x94(%rbp)     # imm = 0x400
jne 0x403111
movq $0x510708, %rax         # imm = 0x510708
movq (%rax), %rdi
leaq 0xd6f2f(%rip), %rsi     # 0x4da02f
movb $0x0, %al
callq 0x41b3c0
movl $0x1, %edi
callq 0x41a3f0
jmp 0x403113
leaq -0x90(%rbp), %rdi
xorl %esi, %esi
movl $0x80, %edx
callq 0x4010a8
movslq -0x94(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
shrq $0x3, %rax
cmpq $0x80, %rax
jae 0x40317e
movq -0xb0(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
movq -0xb0(%rbp), %rcx
shrq $0x6, %rcx
orq -0x90(%rbp,%rcx,8), %rax
movq %rax, -0x90(%rbp,%rcx,8)
movq %rax, -0x130(%rbp)
jmp 0x403189
xorl %eax, %eax
movq %rax, -0x130(%rbp)
jmp 0x403189
movq -0x130(%rbp), %rax
movq %rax, -0xb8(%rbp)
xorl %edi, %edi
movl $0x80, %esi
leaq -0x90(%rbp), %rdx
callq 0x46e0c0
cmpl $0x0, %eax
je 0x4031c5
leaq 0xd6ea2(%rip), %rdi     # 0x4da058
callq 0x41b6b0
movl $0x1, %edi
callq 0x41a3f0
jmp 0x4031c7
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movl 0x2c(%rax), %eax
movl %eax, -0xbc(%rbp)
movl $0x0, -0xc0(%rbp)
movl -0xc0(%rbp), %eax
cmpl -0xbc(%rbp), %eax
jae 0x403296
movq -0x10(%rbp), %rax
testb $0x1, 0x90(%rax)
je 0x40324a
movq -0x10(%rbp), %rax
movq 0x68(%rax), %rdi
movl -0xbc(%rbp), %eax
movq -0x10(%rbp), %rcx
imull (%rcx), %eax
addl -0xc0(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
movl -0xbc(%rbp), %eax
movl %eax, %edx
movq -0x10(%rbp), %rax
imulq 0x70(%rax), %rdx
callq 0x40f620
movq %rax, %rdx
movq -0x10(%rbp), %rax
movl -0xc0(%rbp), %ecx
movq %rdx, 0x8(%rax,%rcx,8)
jmp 0x403280
movq -0x10(%rbp), %rax
movq 0x68(%rax), %rdi
movl -0xbc(%rbp), %eax
movq -0x10(%rbp), %rcx
imull (%rcx), %eax
addl -0xc0(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x40f2e0
movq %rax, %rdx
movq -0x10(%rbp), %rax
movl -0xc0(%rbp), %ecx
movq %rdx, 0x8(%rax,%rcx,8)
jmp 0x403282
movl -0xc0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc0(%rbp)
jmp 0x4031e2
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movq 0x10(%rax), %rdi
leaq 0xd6cab(%rip), %rsi     # 0x4d9f54
callq 0x4010b8
cmpl $0x0, %eax
jne 0x40333f
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x41aba0
movq %rax, -0xc8(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0xd0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xe0(%rbp)
movq -0xe0(%rbp), %rdx
addq -0xc8(%rbp), %rdx
movq -0xd0(%rbp), %rax
movq -0xc8(%rbp), %rcx
movq %rdx, (%rax,%rcx)
movq -0xe0(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rax
cmpq -0xd8(%rbp), %rax
jne 0x4032ee
jmp 0x40333f
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movq 0x10(%rax), %rdi
leaq 0xd6c46(%rip), %rsi     # 0x4d9f98
callq 0x4010b8
cmpl $0x0, %eax
jne 0x4033f9
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x41aba0
movq %rax, -0xe8(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xf0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x100(%rbp)
movq -0x100(%rbp), %rdx
movq -0xf0(%rbp), %rax
movq -0xe8(%rbp), %rcx
movq %rdx, (%rax,%rcx)
movq -0xf0(%rbp), %rcx
addq -0xe8(%rbp), %rcx
movq -0xf0(%rbp), %rax
movq %rcx, (%rax)
movq -0x100(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
cmpq -0xf8(%rbp), %rax
jne 0x403397
jmp 0x4033f9
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movq 0x10(%rax), %rdi
leaq 0xd6826(%rip), %rsi     # 0x4d9c32
callq 0x4010b8
cmpl $0x0, %eax
jne 0x403442
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x108(%rbp)
movq -0x108(%rbp), %rdi
movl $0xc8, %esi
callq 0x4108a0
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x94(%rax)
movq -0x10(%rbp), %rax
cmpq $0x0, 0x88(%rax)
je 0x4034e4
movq -0x10(%rbp), %rax
movq 0x88(%rax), %rax
shrq $0x3, %rax
movq %rax, -0x110(%rbp)
movq -0x10(%rbp), %rax
movq 0x80(%rax), %rax
movq %rax, -0x118(%rbp)
movq $0x0, -0x120(%rbp)
cmpq $0x0, -0x110(%rbp)
je 0x4034cf
movq -0x118(%rbp), %rax
movq (%rax), %rax
addq -0x120(%rbp), %rax
movq %rax, -0x120(%rbp)
movq -0x118(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x118(%rbp)
movq -0x110(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x110(%rbp)
jmp 0x403487
movq -0x120(%rbp), %rdx
movq -0x10(%rbp), %rax
movslq 0x60(%rax), %rcx
addq %rdx, %rcx
movl %ecx, 0x60(%rax)
leaq 0x10eec5(%rip), %rdi    # 0x5123b0
callq 0x436e60
cmpq $0x1, 0x10eeb0(%rip)    # 0x5123a8
jne 0x403535
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movq 0x10(%rax), %rdi
leaq 0xd6725(%rip), %rsi     # 0x4d9c32
callq 0x4010b8
cmpl $0x0, %eax
jne 0x403533
movq -0x10(%rbp), %rax
movq 0x68(%rax), %rax
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x68(%rax), %rax
movq 0x8(%rax), %rsi
callq 0x410450
jmp 0x403535
movq 0x10ee6c(%rip), %rax    # 0x5123a8
addq $-0x1, %rax
movq %rax, 0x10ee61(%rip)    # 0x5123a8
cmpq $0x0, 0x10ee59(%rip)    # 0x5123a8
je 0x403566
leaq 0x10ee80(%rip), %rdi    # 0x5123d8
leaq 0x10ee51(%rip), %rsi    # 0x5123b0
callq 0x4334c0
jmp 0x403572
leaq 0x10ee6b(%rip), %rdi    # 0x5123d8
callq 0x432e70
leaq 0x10ee37(%rip), %rdi    # 0x5123b0
callq 0x437d40
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movq (%rax), %rax
movq -0x8(%rbp), %rdi
callq *%rax
xorl %eax, %eax
addq $0x130, %rsp            # imm = 0x130
popq %rbp
retq
nopw (%rax,%rax)