// File: /workspace/github_c_makefile_star2_O3/stevenmherring[P]DNS/fine-trie.c
// Function: delete
struct trie_node *
      _delete (struct trie_node *node, const char *string,
        size_t strlen) {
          int keylen, cmp;
          int rc;
          // First things first, check if we are NULL

          if (node == NULL) return NULL;


          // lock the node here,
          rc = pthread_mutex_lock(&(node->lock));
          assert(rc == 0);


          assert(node->strlen < 64);

          // See if this key is a substring of the string passed in
          cmp = compare_keys (node->key, node->strlen, string, strlen, &keylen);
          if (cmp == 0) {
            // Yes, either quit, or recur on the children

            // If this key is longer than our search string, the key isn't here
            if (node->strlen > keylen)
            {
              // unlock node
              rc = pthread_mutex_unlock(&(node->lock));
              assert(rc == 0);

              return NULL;
            }
            else if (strlen > keylen)
            {
              // found wont be unlocked by this method
              struct trie_node *found =  _delete(node->children, string, strlen - keylen);

              if (found)
              {
                if(found->waiting > 0 && allow_squatting)
                {
                  pthread_cond_broadcast(&(found->c));
                  rc = pthread_mutex_unlock(&(found->lock));
                  assert(rc == 0);

                }
                else
                {
                  /* If the node doesn't have children, delete it.
                  * Otherwise, keep it around to find the kids */
                  if (found->children == NULL && found->ip4_address == 0)
                  {
                    // shouldnt need to lock found->next because as long as parent is locked,
                    // nothing bad should be able to happen to it (check what insert does)
                    assert(node->children == found);
                    node->children = found->next;
                    // unlock found
                    rc = pthread_mutex_unlock(&(found->lock));
                    assert(rc == 0);


                    free(found);

                  }
                  else
                  {
                    rc = pthread_mutex_unlock(&(found->lock));
                    assert(rc == 0);

                  }
                }

                // unlock found

                // TODO get root lock
                /* Delete the root node if we empty the tree */
                if (node == root && node->children == NULL && node->ip4_address == 0)
                {
                  if(node->waiting > 0 && allow_squatting)
                  {
                    pthread_cond_broadcast(&(node->c));
                    rc = pthread_mutex_unlock(&(node->lock));
                    assert(rc == 0);

                  }
                  else
                  {
                    root = node->next;

                    rc = pthread_mutex_unlock(&(node->lock));
                    assert(rc == 0);


                    free(node);
                  }
                }

                // dont unlock node, we are still doing operations on it
                return node; /* Recursively delete needless interior nodes */
              }
              else
              {
                rc = pthread_mutex_unlock(&(node->lock));
                assert(rc == 0);

                return NULL;
              }
            }
            else
            {
              assert (strlen == keylen);

              /* We found it! Clear the ip4 address and return. */
              if (node->ip4_address)
              {
                node->ip4_address = 0;

                //TODO lock root
                /* Delete the root node if we empty the tree */
                if (node == root && node->children == NULL && node->ip4_address == 0)
                {

                  root = node->next;


                  rc = pthread_mutex_unlock(&(node->lock));
                  assert(rc == 0);


                  // dont free if waiting > 0

                  free(node);
                  return (struct trie_node *) 0x100100; /* XXX: Don't use this pointer for anything except
                  * comparison with NULL, since the memory is freed.
                  * Return a "poison" pointer that will probably
                  * segfault if used.
                  */
                }

                // dont return node, still doing stuff
                return node;
              }
              else
              {
                /* Just an interior node with no value */
                rc = pthread_mutex_unlock(&(node->lock));
                assert(rc == 0);

                return NULL;
              }
            }
          }
          else if (cmp < 0) {
            // No, look right (the node's key is "less" than  the search key)

            // found should be locked
            struct trie_node *found = _delete(node->next, string, strlen);

            if (found)
            {
              if(found->waiting > 0 && allow_squatting)
              {
                pthread_cond_broadcast(&(found->c));
                rc = pthread_mutex_unlock(&(found->lock));
                assert(rc == 0);

              }
              else
              {
                /* If the node doesn't have children, delete it.
                * Otherwise, keep it around to find the kids */
                if (found->children == NULL && found->ip4_address == 0)
                {
                  assert(node->next == found);
                  node->next = found->next;
                  rc = pthread_mutex_unlock(&(found->lock));
                  assert(rc == 0);


                  free(found);
                }
                else
                {
                  rc = pthread_mutex_unlock(&(found->lock));
                  assert(rc == 0);

                }
              }

              return node; /* Recursively delete needless interior nodes */
            }

            rc = pthread_mutex_unlock(&(node->lock));
            assert(rc == 0);

            return NULL;
          }
          else
          {
            // Quit early
            rc = pthread_mutex_unlock(&(node->lock));
            assert(rc == 0);

            return NULL;
          }

        }

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
pushq %rax
testq %rdi, %rdi
je 0x28dd
movq %rdx, %r15
movq %rsi, %r12
movq %rdi, %rbx
leaq 0x58(%rdi), %r14
movq %r14, %rdi
callq 0x11d0
testl %eax, %eax
jne 0x2a13
movl 0x8(%rbx), %esi
cmpl $0x40, %esi
jae 0x2a32
leaq 0x18(%rbx), %rdi
leaq 0x4(%rsp), %r8
movq %r12, %rdx
movl %r15d, %ecx
callq 0x13f8
testl %eax, %eax
je 0x2691
js 0x26ce
movq %r14, %rdi
callq 0x1110
testl %eax, %eax
je 0x28dd
leaq 0x1a94(%rip), %rdi      # 0x410d
leaq 0x1984(%rip), %rsi      # 0x4004
leaq 0x1c57(%rip), %rcx      # 0x42de
movl $0x345, %edx            # imm = 0x345
callq 0x10b0
movslq 0x4(%rsp), %rax
cmpl %eax, 0x8(%rbx)
jbe 0x2744
movq %r14, %rdi
callq 0x1110
testl %eax, %eax
je 0x28dd
leaq 0x1a57(%rip), %rdi      # 0x410d
leaq 0x1947(%rip), %rsi      # 0x4004
leaq 0x1c1a(%rip), %rcx      # 0x42de
movl $0x298, %edx            # imm = 0x298
callq 0x10b0
movq (%rbx), %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x260e
testq %rax, %rax
je 0x2832
movq %rax, %r15
cmpl $0x0, 0xb0(%rax)
jle 0x2861
leaq 0x4a44(%rip), %rax      # 0x7140
cmpl $0x0, (%rax)
je 0x2861
leaq 0x80(%r15), %rdi
callq 0x1070
addq $0x58, %r15
movq %r15, %rdi
callq 0x1110
testl %eax, %eax
je 0x28df
leaq 0x19e1(%rip), %rdi      # 0x410d
leaq 0x18d1(%rip), %rsi      # 0x4004
leaq 0x1ba4(%rip), %rcx      # 0x42de
movl $0x320, %edx            # imm = 0x320
callq 0x10b0
subq %rax, %r15
jbe 0x27c2
movq 0x10(%rbx), %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x260e
testq %rax, %rax
je 0x28a2
movq %rax, %r15
cmpl $0x0, 0xb0(%rax)
leaq 0x49ce(%rip), %r12      # 0x7140
jle 0x28ee
cmpl $0x0, (%r12)
je 0x28ee
leaq 0x80(%r15), %rdi
callq 0x1070
addq $0x58, %r15
movq %r15, %rdi
callq 0x1110
testl %eax, %eax
je 0x2914
leaq 0x1963(%rip), %rdi      # 0x410d
leaq 0x1853(%rip), %rsi      # 0x4004
leaq 0x1b26(%rip), %rcx      # 0x42de
movl $0x2a7, %edx            # imm = 0x2A7
callq 0x10b0
jne 0x2a51
cmpl $0x0, 0xc(%rbx)
je 0x28cd
movl $0x0, 0xc(%rbx)
cmpq %rbx, 0x4930(%rip)      # 0x7110
jne 0x28df
cmpq $0x0, 0x10(%rbx)
jne 0x28df
movq (%rbx), %rax
movq %rax, 0x4915(%rip)      # 0x7110
movq %r14, %rdi
callq 0x1110
movq %rbx, %r15
movl $0x100100, %ebx         # imm = 0x100100
testl %eax, %eax
je 0x299c
leaq 0x18f3(%rip), %rdi      # 0x410d
leaq 0x17e3(%rip), %rsi      # 0x4004
leaq 0x1ab6(%rip), %rcx      # 0x42de
movl $0x2fa, %edx            # imm = 0x2FA
callq 0x10b0
movq %r14, %rdi
callq 0x1110
testl %eax, %eax
je 0x28dd
leaq 0x18c4(%rip), %rdi      # 0x410d
leaq 0x17b4(%rip), %rsi      # 0x4004
leaq 0x1a87(%rip), %rcx      # 0x42de
movl $0x33d, %edx            # imm = 0x33D
callq 0x10b0
cmpq $0x0, 0x10(%r15)
jne 0x2873
cmpl $0x0, 0xc(%r15)
je 0x2979
addq $0x58, %r15
movq %r15, %rdi
callq 0x1110
testl %eax, %eax
je 0x28df
leaq 0x1883(%rip), %rdi      # 0x410d
leaq 0x1773(%rip), %rsi      # 0x4004
leaq 0x1a46(%rip), %rcx      # 0x42de
movl $0x334, %edx            # imm = 0x334
callq 0x10b0
movq %r14, %rdi
callq 0x1110
testl %eax, %eax
je 0x28dd
leaq 0x1858(%rip), %rdi      # 0x410d
leaq 0x1748(%rip), %rsi      # 0x4004
leaq 0x1a1b(%rip), %rcx      # 0x42de
movl $0x2e3, %edx            # imm = 0x2E3
callq 0x10b0
movq %r14, %rdi
callq 0x1110
testl %eax, %eax
jne 0x2a70
xorl %ebx, %ebx
movq %rbx, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
cmpq $0x0, 0x10(%r15)
jne 0x2900
cmpl $0x0, 0xc(%r15)
je 0x29a9
addq $0x58, %r15
movq %r15, %rdi
callq 0x1110
testl %eax, %eax
jne 0x2a8f
cmpq %rbx, 0x47f5(%rip)      # 0x7110
jne 0x28df
cmpq $0x0, 0x10(%rbx)
jne 0x28df
cmpl $0x0, 0xc(%rbx)
jne 0x28df
cmpl $0x0, 0xb0(%rbx)
jle 0x29db
cmpl $0x0, (%r12)
je 0x29db
leaq 0x80(%rbx), %rdi
callq 0x1070
movq %r14, %rdi
callq 0x1110
testl %eax, %eax
je 0x28df
leaq 0x17ac(%rip), %rdi      # 0x410d
leaq 0x169c(%rip), %rsi      # 0x4004
leaq 0x196f(%rip), %rcx      # 0x42de
movl $0x2ce, %edx            # imm = 0x2CE
callq 0x10b0
cmpq %r15, (%rbx)
jne 0x2aae
movq (%r15), %rax
movq %rax, (%rbx)
movq %r15, %rdi
addq $0x58, %rdi
callq 0x1110
testl %eax, %eax
jne 0x2acd
movq %r15, %rdi
callq 0x1030
jmp 0x28df
cmpq %r15, 0x10(%rbx)
jne 0x2aec
movq (%r15), %rax
movq %rax, 0x10(%rbx)
movq %r15, %rdi
addq $0x58, %rdi
callq 0x1110
testl %eax, %eax
jne 0x2b0b
movq %r15, %rdi
callq 0x1030
jmp 0x2914
movq (%rbx), %rax
movq %rax, 0x472b(%rip)      # 0x7110
movq %r14, %rdi
callq 0x1110
movq %rbx, %r15
testl %eax, %eax
je 0x299c
leaq 0x1712(%rip), %rdi      # 0x410d
leaq 0x1602(%rip), %rsi      # 0x4004
leaq 0x18d5(%rip), %rcx      # 0x42de
movl $0x2d6, %edx            # imm = 0x2D6
callq 0x10b0
leaq 0x16f3(%rip), %rdi      # 0x410d
leaq 0x15e3(%rip), %rsi      # 0x4004
leaq 0x18b6(%rip), %rcx      # 0x42de
movl $0x289, %edx            # imm = 0x289
callq 0x10b0
leaq 0x16b8(%rip), %rdi      # 0x40f1
leaq 0x15c4(%rip), %rsi      # 0x4004
leaq 0x1897(%rip), %rcx      # 0x42de
movl $0x28c, %edx            # imm = 0x28C
callq 0x10b0
leaq 0x16bd(%rip), %rdi      # 0x4115
leaq 0x15a5(%rip), %rsi      # 0x4004
leaq 0x1878(%rip), %rcx      # 0x42de
movl $0x2ea, %edx            # imm = 0x2EA
callq 0x10b0
leaq 0x1696(%rip), %rdi      # 0x410d
leaq 0x1586(%rip), %rsi      # 0x4004
leaq 0x1859(%rip), %rcx      # 0x42de
movl $0x30e, %edx            # imm = 0x30E
callq 0x10b0
leaq 0x1677(%rip), %rdi      # 0x410d
leaq 0x1567(%rip), %rsi      # 0x4004
leaq 0x183a(%rip), %rcx      # 0x42de
movl $0x2bf, %edx            # imm = 0x2BF
callq 0x10b0
leaq 0x1885(%rip), %rdi      # 0x433a
leaq 0x1548(%rip), %rsi      # 0x4004
leaq 0x181b(%rip), %rcx      # 0x42de
movl $0x329, %edx            # imm = 0x329
callq 0x10b0
leaq 0x1639(%rip), %rdi      # 0x410d
leaq 0x1529(%rip), %rsi      # 0x4004
leaq 0x17fc(%rip), %rcx      # 0x42de
movl $0x32c, %edx            # imm = 0x32C
callq 0x10b0
leaq 0x182f(%rip), %rdi      # 0x4322
leaq 0x150a(%rip), %rsi      # 0x4004
leaq 0x17dd(%rip), %rcx      # 0x42de
movl $0x2b2, %edx            # imm = 0x2B2
callq 0x10b0
leaq 0x15fb(%rip), %rdi      # 0x410d
leaq 0x14eb(%rip), %rsi      # 0x4004
leaq 0x17be(%rip), %rcx      # 0x42de
movl $0x2b6, %edx            # imm = 0x2B6
callq 0x10b0