// File: /workspace/github_c_makefile_star2_O2/motet-a[P]libforks/libforks.c
// Function: serv_main
__attribute__((noreturn))
static void serv_main(serv_Client *first_client) {
  serv_DEBUG("starting fork server (pid %d)\n", (int)getpid());
  serv_DEBUG("the main client's pid is %d\n", (int)first_client->pid);

  if (signal(SIGPIPE, SIG_IGN)) {
    serv_print_errno(NULL);
    serv_panic();
  }

  if (pipe(serv_exit_pipe) == -1) {
    serv_print_errno("pipe");
    serv_panic();
  }

  // Ignore SIGTERM.
  // Some container environments send SIGTERM to all processes
  // when terminating. It is up to the main process to stop the
  // fork server and its children properly.
  struct sigaction sa;
  sa.sa_handler = SIG_IGN;
  sa.sa_flags = 0;
  sigemptyset(&sa.sa_mask);
  if (sigaction(SIGTERM, &sa, NULL) == -1) {
      serv_print_errno(NULL);
      serv_panic();
  }

  // Stay notified of child exits through a SIGCHLD handler and `serv_exit_pipe`
  sa.sa_handler = serv_sigchld_handler;
  sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
  sigemptyset(&sa.sa_mask);
  if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    serv_print_errno("sigaction");
    serv_panic();
  }

  size_t client_count = 1;

  while (true) {
    nfds_t fd_count = 1;

    struct pollfd poll_fds[1 + serv_MAX_CLIENTS];

    poll_fds[0].fd = serv_exit_pipe[READ_END];
    poll_fds[0].events = POLLIN | POLLPRI;
    poll_fds[0].revents = 0;

    for (serv_Client *c = first_client; c; c = c->next) {
      if (c->socket == -1) {
        continue; // “zombie” disconnected client
      }

      assert(fd_count <= (sizeof(poll_fds) / sizeof(struct pollfd)));
      struct pollfd *pollfd = poll_fds + fd_count;
      pollfd->fd = c->socket;
      pollfd->events = POLLIN | POLLPRI;
      pollfd->revents = 0;
      fd_count++;
    }

    serv_DEBUG("polling…\n");
    if (poll(poll_fds, fd_count, -1) == -1) {
      if (errno == EINTR) {
        serv_DEBUG("poll(2) has been interrupted by a signal\n");
        // poll failed because a signal has been received.
        // Just restart it.
        // (SA_RESTART does not work with poll(2))
        continue;
      }

      serv_print_errno("poll");
      serv_panic();
    }

    if (poll_fds[0].revents) {
      // A SIGCHLD signal has been received.

      assert(
        (poll_fds[0].revents & POLLIN) ||
        (poll_fds[0].revents & POLLPRI)
      );

      libforks_ExitEvent event;
      if (read_exact(serv_exit_pipe[READ_END], &event, sizeof event) == -1) {
        serv_print_errno("read_exact");
        serv_panic();
      }

      serv_DEBUG("main loop knows that %d has exited\n", (int)event.pid);

      serv_Client *client = serv_remove_client(&first_client, event.pid);
      assert(client);
      client_count--;

      if (client->exit_fd != -1) {
        serv_DEBUG("informing parent that %d has exited\n", (int)event.pid);
        if (write_exact(client->exit_fd, &event, sizeof event) == -1) {
          if (errno == EPIPE) {
            // Ignore the error because that’s pretty much normal and
            // expected, it happens if the client has closed the pipe
            // or exited.
            // (SIGPIPE is already ignored)
          } else {
            serv_print_errno("exit pipe write");
            serv_panic();
          }
        }
      }

      if (serv_connected_clients(first_client) == 0) {
        serv_DEBUG("no more connected clients, goodbye!\n");
        exit(0);
      }

      if (client->socket != -1) {
        close(client->socket);
      }
      if (client->exit_fd != -1) {
        close(client->exit_fd);
      }
      free(client);
    }

    for (size_t i = 1; i < fd_count; i++) {
      struct pollfd *pollfd = poll_fds + i;
      if (!pollfd->revents) {
        continue;
      }

      serv_Client *sender = serv_find_client_by_socket(
        first_client,
        pollfd->fd
      );
      if (!sender) {
        // the client has just exited and has been removed by the
        // libforks_ExitEvent handler
        continue;
      }

      if ((pollfd->revents & POLLERR) || (pollfd->revents & POLLNVAL)) {
        serv_print_error("socket read error (with client %d)",
            (int)sender->pid);
        serv_panic();
      }

      if (pollfd->revents & POLLHUP) {
        serv_DEBUG("client %d closed its socket\n", (int)sender->pid);
        // The sender may or may not have exited. We can’t forget it right
        // now because we may need its `exit_fd` to notify its parent
        // when it will actually exits, so we mark it as a “zombie” by
        // setting its `socket` to -1 and wait for a SIGCHLD signal.
        assert(sender->socket != -1);
        close(sender->socket);
        sender->socket = -1;
        if (serv_connected_clients(first_client) == 0) {
          serv_DEBUG("no more connected clients, goodbye!\n");
          exit(0);
        }
        continue;
      }

      assert(
        (pollfd->revents & POLLIN) ||
        (pollfd->revents & POLLPRI)
      );

      assert(sender->socket == pollfd->fd);
      ClientMessage req = serv_recv(pollfd->fd);
      serv_handle_request(&req, &first_client, &client_count, sender);
    }
  }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1b8, %rsp            # imm = 0x1B8
movq %rdi, 0x10(%rsp)
pushq $0xd
popq %rdi
pushq $0x1
popq %r13
movq %r13, %rsi
callq 0x1100
testq %rax, %rax
jne 0x2088
leaq 0x47d4(%rip), %rdi      # 0x6114
callq 0x10e0
cmpl $-0x1, %eax
je 0x206b
leaq 0x128(%rsp), %rbx
movq $0x1, -0x8(%rbx)
andl $0x0, 0x80(%rbx)
movq %rbx, %rdi
callq 0x1120
pushq $0xf
popq %rdi
leaq 0x120(%rsp), %rsi
xorl %edx, %edx
callq 0x1070
cmpl $-0x1, %eax
je 0x2088
leaq 0xacc(%rip), %rax       # 0x245b
leaq 0x120(%rsp), %r14
movq %rax, (%r14)
movl $0x10000001, 0x88(%r14) # imm = 0x10000001
movq %rbx, %rdi
callq 0x1120
pushq $0x11
popq %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x1070
cmpl $-0x1, %eax
je 0x208f
pushq $0x1
popq %r15
movq %r13, 0x18(%rsp)
movl 0x4742(%rip), %eax      # 0x6114
movl %eax, 0x70(%rsp)
movl $0x3, 0x74(%rsp)
leaq 0x10(%rsp), %rax
movq %r13, %rbx
movq (%rax), %rax
testq %rax, %rax
je 0x1a15
movl 0x8(%rax), %ecx
cmpl $-0x1, %ecx
je 0x1a0f
cmpq $0x16, %rbx
jae 0x1e9b
movl %ecx, 0x70(%rsp,%rbx,8)
movl $0x3, 0x74(%rsp,%rbx,8)
incq %rbx
addq $0x10, %rax
jmp 0x19e6
leaq 0x70(%rsp), %rdi
movq %rbx, %rsi
pushq $-0x1
popq %rdx
callq 0x1180
cmpl $-0x1, %eax
je 0x1b01
movzwl 0x76(%rsp), %eax
testw %ax, %ax
je 0x1b14
testb $0x3, %al
je 0x1f73
movl 0x46ca(%rip), %edi      # 0x6114
leaq 0x40(%rsp), %rsi
pushq $0x8
popq %rdx
callq 0x15e1
cmpl $-0x1, %eax
je 0x1f6a
movl 0x40(%rsp), %ecx
leaq 0x10(%rsp), %r15
movq %r15, %rax
movq (%r15), %r15
testq %r15, %r15
je 0x1eba
cmpl %ecx, (%r15)
je 0x1a8a
movq (%rax), %rax
addq $0x10, %rax
addq $0x10, %r15
jmp 0x1a6c
movq 0x10(%r15), %rcx
movq %rcx, (%rax)
movl 0xc(%r15), %edi
cmpl $-0x1, %edi
je 0x1aba
leaq 0x40(%rsp), %rsi
pushq $0x8
popq %rdx
callq 0x1770
cmpl $-0x1, %eax
jne 0x1aba
callq 0x1050
cmpl $0x20, (%rax)
jne 0x202f
movq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0x252f
testl %eax, %eax
je 0x2081
movl 0x8(%r15), %edi
cmpl $-0x1, %edi
je 0x1add
callq 0x187b
movl 0xc(%r15), %edi
cmpl $-0x1, %edi
je 0x1aeb
callq 0x187b
decq 0x18(%rsp)
movq %r15, %rdi
callq 0x1030
pushq $0x1
popq %r15
jmp 0x1e89
callq 0x1050
cmpl $0x4, (%rax)
je 0x19cc
jmp 0x1f92
movq 0x10(%rsp), %r14
jmp 0x1e89
movzwl 0x76(%rsp,%r13,8), %eax
testl %eax, %eax
je 0x1e86
movl 0x70(%rsp,%r13,8), %edi
movq %r14, %rbp
testl %edi, %edi
js 0x1ed9
testq %rbp, %rbp
je 0x1e86
cmpl %edi, 0x8(%rbp)
je 0x1b50
movq 0x10(%rbp), %rbp
jmp 0x1b3c
testb $0x28, %al
jne 0x1f01
testb $0x10, %al
jne 0x1bc5
testb $0x3, %al
je 0x1f17
leaq 0x40(%rsp), %rsi
pushq $0x18
popq %rdx
callq 0x15e1
cmpl $-0x1, %eax
je 0x1f36
movl 0x50(%rsp), %eax
cmpq $0x4, %rax
ja 0x1f57
leaq 0x1579(%rip), %rcx      # 0x3108
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
cmpq $0x14, 0x18(%rsp)
jne 0x1c4c
movl 0x8(%rbp), %edi
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
leaq -0x4(%rax), %rsi
movl %r15d, %edx
callq 0x262e
pushq $0x14
popq %rax
movq %rax, 0x18(%rsp)
jmp 0x1e86
callq 0x187b
orl $-0x1, 0x8(%rbp)
movq %r14, %rdi
callq 0x252f
testl %eax, %eax
jne 0x1e86
jmp 0x2081
movl 0x40(%rsp), %r15d
leaq 0x10(%rsp), %r12
movq (%r12), %r12
testq %r12, %r12
je 0x1c36
cmpq %rbp, %r12
je 0x1c1a
movl (%r12), %edi
movl %r15d, %esi
callq 0x1150
cmpl $-0x1, %eax
jne 0x1c1a
callq 0x1050
cmpl $0x3, (%rax)
jne 0x1ef8
addq $0x10, %r12
jmp 0x1bed
callq *0x40(%rsp)
movl 0x8(%rbp), %edi
xorl %esi, %esi
pushq $0x3
popq %rdx
callq 0x262e
jmp 0x1e86
movl 0x8(%rbp), %edi
xorl %esi, %esi
pushq $0x2
popq %rdx
callq 0x262e
pushq $0x1
popq %r15
jmp 0x1e86
callq 0x1090
movl %eax, %r12d
movl %r15d, %edi
movl %r15d, %esi
xorl %edx, %edx
leaq 0x58(%rsp), %rcx
callq 0x1140
cmpl $-0x1, %eax
je 0x1d6b
movl %r12d, 0x34(%rsp)
movl 0x58(%rsp), %eax
movl %eax, 0x8(%rsp)
movl 0x5c(%rsp), %eax
movl %eax, 0xc(%rsp)
orq $-0x1, 0x28(%rsp)
cmpb $0x1, 0x40(%rsp)
pushq $-0x1
popq %rax
movl %eax, %r12d
jne 0x1cbb
movl %r15d, %edi
movl %r15d, %esi
xorl %edx, %edx
leaq 0x28(%rsp), %rcx
callq 0x1140
cmpl $-0x1, %eax
je 0x1dc2
movl 0x28(%rsp), %eax
movl 0x2c(%rsp), %r12d
movl %eax, 0x4(%rsp)
callq 0x11f0
cmpl $-0x1, %eax
je 0x1d89
movl %eax, %r15d
testl %eax, %eax
je 0x1f9b
movl 0xc(%rsp), %edi
callq 0x187b
cmpl $-0x1, %r12d
je 0x1cef
movl %r12d, %edi
callq 0x187b
pushq $0x18
popq %rdi
callq 0x1160
testq %rax, %rax
je 0x2017
movq %rax, %r12
movl %r15d, (%rax)
movb $0x0, 0x4(%rax)
movl 0x8(%rsp), %eax
movl %eax, 0x8(%r12)
orl $-0x1, 0xc(%r12)
orq $-0x1, 0x20(%rsp)
movq %r14, 0x10(%r12)
cmpb $0x1, 0x41(%rsp)
jne 0x1d47
leaq 0x20(%rsp), %rdi
callq 0x10e0
cmpl $-0x1, %eax
je 0x206b
movl 0x24(%rsp), %eax
movl %eax, 0xc(%r12)
movq %r12, 0x10(%rsp)
movl 0x4(%rsp), %eax
cmpl $-0x1, %eax
je 0x1df5
movl %eax, 0x38(%rsp)
leaq 0x3c(%rsp), %rax
pushq $0x1
popq %r14
jmp 0x1dfd
callq 0x1050
movl (%rax), %esi
shlq $0x20, %rsi
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
orq %rax, %rsi
movl 0x8(%rbp), %edi
movl %r15d, %edx
jmp 0x1c2c
callq 0x1050
movl (%rax), %eax
shlq $0x20, %rax
movl $0xfffffffd, %ecx       # imm = 0xFFFFFFFD
leaq -0x2(%rcx), %rsi
orq %rax, %rsi
movl 0x8(%rbp), %edi
pushq $0x1
popq %r15
movl %r15d, %edx
callq 0x262e
movl 0x4(%rsp), %edi
callq 0x187b
movl %r12d, %edi
callq 0x187b
jmp 0x1de0
callq 0x1050
movl (%rax), %esi
shlq $0x20, %rsi
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
orq %rax, %rsi
movl 0x8(%rbp), %edi
movl %r15d, %edx
callq 0x262e
movl 0x8(%rsp), %edi
callq 0x187b
movq %r14, %r12
movl 0xc(%rsp), %edi
jmp 0x1e7e
leaq 0x38(%rsp), %rax
xorl %r14d, %r14d
movl 0x20(%rsp), %ecx
cmpl $-0x1, %ecx
je 0x1e0b
incq %r14
movl %ecx, (%rax)
movl 0x8(%rsp), %edi
leaq 0x3(%rsp), %rsi
pushq $0x1
popq %rdx
callq 0x15e1
cmpl $-0x1, %eax
je 0x1f6a
cmpb $0x72, 0x3(%rsp)
jne 0x1f6a
movl 0x8(%rbp), %edi
movl %r15d, %eax
movq %rax, 0x60(%rsp)
andl $0x0, 0x68(%rsp)
leaq 0x60(%rsp), %rsi
pushq $0xc
popq %rdx
leaq 0x38(%rsp), %rcx
movq %r14, %r8
callq 0x1613
cmpl $-0x1, %eax
je 0x2023
movl 0x20(%rsp), %edi
cmpl $-0x1, %edi
je 0x1e6c
callq 0x187b
incq 0x18(%rsp)
movl 0x4(%rsp), %edi
cmpl $-0x1, %edi
pushq $0x1
popq %r15
je 0x1e83
callq 0x187b
movq %r12, %r14
incq %r13
cmpq %rbx, %r13
jb 0x1b1e
pushq $0x1
popq %r13
jmp 0x19cc
leaq 0x1630(%rip), %rdi      # 0x34d2
leaq 0x12e6(%rip), %rsi      # 0x318f
leaq 0x1659(%rip), %rcx      # 0x3509
movl $0x35a, %edx            # imm = 0x35A
callq 0x10b0
leaq 0x16b8(%rip), %rdi      # 0x3579
leaq 0x12c7(%rip), %rsi      # 0x318f
leaq 0x163a(%rip), %rcx      # 0x3509
movl $0x381, %edx            # imm = 0x381
callq 0x10b0
leaq 0x17a7(%rip), %rdi      # 0x3687
leaq 0x12a8(%rip), %rsi      # 0x318f
leaq 0x17a5(%rip), %rcx      # 0x3693
movl $0x18f, %edx            # imm = 0x18F
callq 0x10b0
leaq 0x184f(%rip), %rdi      # 0x374e
jmp 0x1f3d
movl (%rbp), %esi
leaq 0x1685(%rip), %rdi      # 0x3590
xorl %eax, %eax
callq 0x239d
callq 0x2389
leaq 0x1695(%rip), %rdi      # 0x35b3
leaq 0x126a(%rip), %rsi      # 0x318f
leaq 0x15dd(%rip), %rcx      # 0x3509
movl $0x3ca, %edx            # imm = 0x3CA
callq 0x10b0
leaq 0x1792(%rip), %rdi      # 0x36cf
callq 0x1898
callq 0x2389
callq 0x25db
movq %r14, %rdi
movq %rbp, %rsi
callq 0x2548
leaq 0x1776(%rip), %rdi      # 0x36d4
xorl %eax, %eax
callq 0x239d
callq 0x2389
leaq 0x15fd(%rip), %rdi      # 0x356e
jmp 0x1f3d
leaq 0x15b2(%rip), %rdi      # 0x352c
leaq 0x120e(%rip), %rsi      # 0x318f
leaq 0x1581(%rip), %rcx      # 0x3509
movl $0x376, %edx            # imm = 0x376
callq 0x10b0
leaq 0x158e(%rip), %rdi      # 0x3527
jmp 0x1f3d
movl 0x8(%rsp), %edi
callq 0x187b
movl 0x4(%rsp), %edi
cmpl $-0x1, %edi
je 0x1fdf
callq 0x187b
jmp 0x1fdf
movq 0x10(%r14), %rbx
movl 0xc(%r14), %edi
cmpl $-0x1, %edi
je 0x1fc6
callq 0x187b
movl 0x8(%r14), %edi
cmpl $-0x1, %edi
je 0x1fd4
callq 0x187b
movq %r14, %rdi
callq 0x1030
movq %rbx, %r14
testq %r14, %r14
jne 0x1fb4
movl 0x412a(%rip), %edi      # 0x6114
callq 0x187b
movl 0x4123(%rip), %edi      # 0x6118
callq 0x187b
pushq $0xf
popq %rdi
callq 0x25e3
pushq $0x11
popq %rdi
callq 0x25e3
pushq $0x8
popq %rdi
callq 0x1160
testq %rax, %rax
jne 0x203b
leaq 0x120a(%rip), %rdi      # 0x3228
jmp 0x1f3d
leaq 0x173d(%rip), %rdi      # 0x3767
jmp 0x1f3d
leaq 0x154a(%rip), %rdi      # 0x3580
jmp 0x1f3d
movq %rax, %rbx
movl 0x34(%rsp), %eax
movl %eax, (%rbx)
movl 0xc(%rsp), %edi
movl %edi, 0x4(%rbx)
leaq 0x15c3(%rip), %rsi      # 0x3615
pushq $0x1
popq %rdx
callq 0x1770
cmpl $-0x1, %eax
jne 0x2077
leaq 0x16f5(%rip), %rdi      # 0x375b
jmp 0x1f3d
leaq 0x1451(%rip), %rdi      # 0x34c3
jmp 0x1f3d
movq %rbx, %rdi
movl %r12d, %esi
callq *0x48(%rsp)
xorl %edi, %edi
callq 0x11c0
xorl %edi, %edi
jmp 0x1f3d
leaq 0x1432(%rip), %rdi      # 0x34c8
jmp 0x1f3d