user: Converte this assembly snippet into its equivalent C code:

```asm
<test_cgcore_no_internal_process_constraint_on_threads>:
  endbr64
  push   %r15
  lea    D1(%rip),%rdx
  lea    D79(%rip),%rsi
  push   %r14
  push   %r13
  push   %r12
  push   %rbp
  mov    %rdi,%rbp
  push   %rbx
  sub    $0x8,%rsp
  call   <cg_read_strstr@plt>
  test   %rax,%rax
  jne    L116
  lea    D35(%rip),%r15
  lea    D12(%rip),%r14
  mov    %rbp,%rdi
  mov    %r15,%rdx
  mov    %r14,%rsi
  call   <cg_write@plt>
  test   %rax,%rax
  jne    L116
  lea    D6(%rip),%rsi
  mov    %rbp,%rdi
  call   <cg_name@plt>
  lea    D83(%rip),%rsi
  mov    %rbp,%rdi
  mov    %rax,%r12
  call   <cg_name@plt>
  mov    %rax,%r13
  test   %r12,%r12
  je     L63
  test   %rax,%rax
  je     L63
  mov    %r12,%rdi
  call   <cg_create@plt>
  test   %rax,%rax
  je     L85
L48:
  mov    $0x1,%r14d
L120:
  mov    %rbp,%rdi
  call   <cg_enter_current@plt>
  mov    %rbp,%rdi
  call   <cg_enter_current@plt>
L5:
  mov    %r13,%rdi
  call   <cg_destroy@plt>
L117:
  test   %r12,%r12
  je     L138
  mov    %r12,%rdi
  call   <cg_destroy@plt>
  jmp    L138
  cs nopw 0x0(%rax,%rax,1)
L116:
  mov    %rbp,%rdi
  xor    %r13d,%r13d
  xor    %r12d,%r12d
  mov    $0x4,%r14d
  call   <cg_enter_current@plt>
  mov    %rbp,%rdi
  call   <cg_enter_current@plt>
L138:
  mov    %r13,%rdi
  call   <free@plt>
  mov    %r12,%rdi
  call   <free@plt>
  add    $0x8,%rsp
  mov    %r14d,%eax
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  pop    %r15
  ret
  xchg   %ax,%ax
L63:
  mov    %rbp,%rdi
  mov    $0x1,%r14d
  call   <cg_enter_current@plt>
  mov    %rbp,%rdi
  call   <cg_enter_current@plt>
  test   %r13,%r13
  jne    L5
  jmp    L117
  nopl   (%rax)
L85:
  mov    %r13,%rdi
  call   <cg_create@plt>
  test   %rax,%rax
  jne    L48
  lea    D55(%rip),%rbx
  lea    D27(%rip),%rdx
  mov    %r12,%rdi
  mov    %rbx,%rsi
  call   <cg_write@plt>
  test   %rax,%rax
  jne    L48
  lea    D27(%rip),%rdx
  mov    %rbx,%rsi
  mov    %r13,%rdi
  call   <cg_write@plt>
  test   %rax,%rax
  jne    L48
  mov    %r15,%rdx
  mov    %r14,%rsi
  mov    %r12,%rdi
  call   <cg_write@plt>
  test   %rax,%rax
  jne    L48
  mov    %r12,%rdi
  xor    %r14d,%r14d
  call   <cg_enter_current@plt>
  test   %rax,%rax
  setne  %r14b
  jmp    L120
```

tool_calls: name: unpack_data
arguments: tag: D1
data_type: string
name: unpack_data
arguments: tag: D79
data_type: string
name: unpack_data
arguments: tag: D35
data_type: string
name: unpack_data
arguments: tag: D12
data_type: string
name: unpack_data
arguments: tag: D6
data_type: string
name: unpack_data
arguments: tag: D83
data_type: string
name: unpack_data
arguments: tag: D55
data_type: string
name: unpack_data
arguments: tag: D27
data_type: string

tool: D1: cpu

tool: D79: cgroup.controllers

tool: D35: +cpu

tool: D12: cgroup.subtree_control

tool: D6: cg_test_parent

tool: D83: cg_test_parent/cg_test_child

tool: D55: cgroup.type

tool: D27: threaded

assistant: ```c
int test_cgcore_no_internal_process_constraint_on_threads(const char *root) {
  int ret = 1;
  char *parent = NULL, *child = NULL;
  if (cg_read_strstr(root, "cgroup.controllers", "cpu") || cg_write(root, "cgroup.subtree_control", "+cpu")) {
    ret = 4;
    goto cleanup;
  }
  parent = cg_name(root, "cg_test_parent");
  child = cg_name(root, "cg_test_parent/cg_test_child");
  if (!parent || !child)
    goto cleanup;
  if (cg_create(parent))
    goto cleanup;
  if (cg_create(child))
    goto cleanup;
  if (cg_write(parent, "cgroup.type", "threaded"))
    goto cleanup;
  if (cg_write(child, "cgroup.type", "threaded"))
    goto cleanup;
  if (cg_write(parent, "cgroup.subtree_control", "+cpu"))
    goto cleanup;
  if (cg_enter_current(parent))
    goto cleanup;
  ret = 0;
cleanup:
  cg_enter_current(root);
  cg_enter_current(root);
  if (child)
    cg_destroy(child);
  if (parent)
    cg_destroy(parent);
  free(child);
  free(parent);
  return ret;
}
```