// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x1b0, %rsp            # imm = 0x1B0
movq %rdi, -0x8(%rbp)
movl $0xd, %edi
movl $0x1, %esi
callq 0x1110
cmpq $0x0, %rax
je 0x1d52
xorl %eax, %eax
movl %eax, %edi
callq 0x1c90
callq 0x2830
leaq 0x53c3(%rip), %rdi      # 0x711c
callq 0x10f0
cmpl $-0x1, %eax
jne 0x1d74
leaq 0x277d(%rip), %rdi      # 0x44e7
callq 0x1c90
callq 0x2830
movl $0x1, %eax
movq %rax, -0xa0(%rbp)
movl $0x0, -0x18(%rbp)
leaq -0xa0(%rbp), %rdi
addq $0x8, %rdi
callq 0x1130
movl $0xf, %edi
leaq -0xa0(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x1070
cmpl $-0x1, %eax
jne 0x1dbf
xorl %eax, %eax
movl %eax, %edi
callq 0x1c90
callq 0x2830
leaq 0xb5a(%rip), %rax       # 0x2920
movq %rax, -0xa0(%rbp)
movl $0x10000001, -0x18(%rbp) # imm = 0x10000001
leaq -0xa0(%rbp), %rdi
addq $0x8, %rdi
callq 0x1130
movl $0x11, %edi
leaq -0xa0(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x1070
cmpl $-0x1, %eax
jne 0x1e0f
leaq 0x26e7(%rip), %rdi      # 0x44ec
callq 0x1c90
callq 0x2830
movq $0x1, -0xa8(%rbp)
movq $0x1, -0xb0(%rbp)
movl 0x52f1(%rip), %eax      # 0x711c
movl %eax, -0x160(%rbp)
movw $0x3, -0x15c(%rbp)
movw $0x0, -0x15a(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x168(%rbp)
cmpq $0x0, -0x168(%rbp)
je 0x1f0b
movq -0x168(%rbp), %rax
cmpl $-0x1, 0x8(%rax)
jne 0x1e6e
jmp 0x1ef4
cmpq $0x15, -0xb0(%rbp)
ja 0x1e7a
jmp 0x1e99
leaq 0x2675(%rip), %rdi      # 0x44f6
leaq 0x232b(%rip), %rsi      # 0x41b3
movl $0x35a, %edx            # imm = 0x35A
leaq 0x2699(%rip), %rcx      # 0x452d
callq 0x10b0
leaq -0x160(%rbp), %rax
movq -0xb0(%rbp), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq %rax, -0x170(%rbp)
movq -0x168(%rbp), %rax
movl 0x8(%rax), %ecx
movq -0x170(%rbp), %rax
movl %ecx, (%rax)
movq -0x170(%rbp), %rax
movw $0x3, 0x4(%rax)
movq -0x170(%rbp), %rax
movw $0x0, 0x6(%rax)
movq -0xb0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb0(%rbp)
movq -0x168(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x168(%rbp)
jmp 0x1e4e
leaq -0x160(%rbp), %rdi
movq -0xb0(%rbp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x1190
cmpl $-0x1, %eax
jne 0x1f48
callq 0x1050
cmpl $0x4, (%rax)
jne 0x1f37
jmp 0x1e1a
leaq 0x260d(%rip), %rdi      # 0x454b
callq 0x1c90
callq 0x2830
cmpw $0x0, -0x15a(%rbp)
je 0x20bc
movswl -0x15a(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x1f74
movswl -0x15a(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
je 0x1f76
jmp 0x1f95
leaq 0x25d3(%rip), %rdi      # 0x4550
leaq 0x222f(%rip), %rsi      # 0x41b3
movl $0x376, %edx            # imm = 0x376
leaq 0x259d(%rip), %rcx      # 0x452d
callq 0x10b0
movl 0x5181(%rip), %edi      # 0x711c
leaq -0x178(%rbp), %rsi
movl $0x8, %edx
callq 0x1830
cmpl $-0x1, %eax
jne 0x1fc2
leaq 0x25da(%rip), %rdi      # 0x4592
callq 0x1c90
callq 0x2830
movl -0x178(%rbp), %esi
leaq -0x8(%rbp), %rdi
callq 0x2a10
movq %rax, -0x180(%rbp)
cmpq $0x0, -0x180(%rbp)
je 0x1fe4
jmp 0x2003
leaq 0x25b2(%rip), %rdi      # 0x459d
leaq 0x21c1(%rip), %rsi      # 0x41b3
movl $0x381, %edx            # imm = 0x381
leaq 0x252f(%rip), %rcx      # 0x452d
callq 0x10b0
movq -0xa8(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0xa8(%rbp)
movq -0x180(%rbp), %rax
cmpl $-0x1, 0xc(%rax)
je 0x2063
movq -0x180(%rbp), %rax
movl 0xc(%rax), %edi
leaq -0x178(%rbp), %rsi
movl $0x8, %edx
callq 0x1aa0
cmpl $-0x1, %eax
jne 0x2061
callq 0x1050
cmpl $0x20, (%rax)
jne 0x204e
jmp 0x205f
leaq 0x254f(%rip), %rdi      # 0x45a4
callq 0x1c90
callq 0x2830
jmp 0x2061
jmp 0x2063
movq -0x8(%rbp), %rdi
callq 0x2a90
cmpl $0x0, %eax
jne 0x2078
xorl %edi, %edi
callq 0x11d0
movq -0x180(%rbp), %rax
cmpl $-0x1, 0x8(%rax)
je 0x2094
movq -0x180(%rbp), %rax
movl 0x8(%rax), %edi
callq 0x1c50
movq -0x180(%rbp), %rax
cmpl $-0x1, 0xc(%rax)
je 0x20b0
movq -0x180(%rbp), %rax
movl 0xc(%rax), %edi
callq 0x1c50
movq -0x180(%rbp), %rdi
callq 0x1030
movq $0x1, -0x188(%rbp)
movq -0x188(%rbp), %rax
cmpq -0xb0(%rbp), %rax
jae 0x22b3
leaq -0x160(%rbp), %rax
movq -0x188(%rbp), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq %rax, -0x190(%rbp)
movq -0x190(%rbp), %rax
cmpw $0x0, 0x6(%rax)
jne 0x210a
jmp 0x229c
movq -0x8(%rbp), %rdi
movq -0x190(%rbp), %rax
movl (%rax), %esi
callq 0x2ad0
movq %rax, -0x198(%rbp)
cmpq $0x0, -0x198(%rbp)
jne 0x2132
jmp 0x229c
movq -0x190(%rbp), %rax
movswl 0x6(%rax), %eax
andl $0x8, %eax
cmpl $0x0, %eax
jne 0x2158
movq -0x190(%rbp), %rax
movswl 0x6(%rax), %eax
andl $0x20, %eax
cmpl $0x0, %eax
je 0x2174
movq -0x198(%rbp), %rax
movl (%rax), %esi
leaq 0x244c(%rip), %rdi      # 0x45b4
movb $0x0, %al
callq 0x2850
callq 0x2830
movq -0x190(%rbp), %rax
movswl 0x6(%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x21ec
movq -0x198(%rbp), %rax
cmpl $-0x1, 0x8(%rax)
je 0x2196
jmp 0x21b5
leaq 0x243a(%rip), %rdi      # 0x45d7
leaq 0x200f(%rip), %rsi      # 0x41b3
movl $0x3bd, %edx            # imm = 0x3BD
leaq 0x237d(%rip), %rcx      # 0x452d
callq 0x10b0
movq -0x198(%rbp), %rax
movl 0x8(%rax), %edi
callq 0x1c50
movq -0x198(%rbp), %rax
movl $0xffffffff, 0x8(%rax)  # imm = 0xFFFFFFFF
movq -0x8(%rbp), %rdi
callq 0x2a90
cmpl $0x0, %eax
jne 0x21e7
xorl %edi, %edi
callq 0x11d0
jmp 0x229c
movq -0x190(%rbp), %rax
movswl 0x6(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x2212
movq -0x190(%rbp), %rax
movswl 0x6(%rax), %eax
andl $0x2, %eax
cmpl $0x0, %eax
je 0x2214
jmp 0x2233
leaq 0x23d1(%rip), %rdi      # 0x45ec
leaq 0x1f91(%rip), %rsi      # 0x41b3
movl $0x3ca, %edx            # imm = 0x3CA
leaq 0x22ff(%rip), %rcx      # 0x452d
callq 0x10b0
movq -0x198(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x190(%rbp), %rcx
cmpl (%rcx), %eax
jne 0x224a
jmp 0x2269
leaq 0x23d5(%rip), %rdi      # 0x4626
leaq 0x1f5b(%rip), %rsi      # 0x41b3
movl $0x3cc, %edx            # imm = 0x3CC
leaq 0x22c9(%rip), %rcx      # 0x452d
callq 0x10b0
movq -0x190(%rbp), %rax
movl (%rax), %esi
leaq -0x1b0(%rbp), %rdi
callq 0x2b50
movq -0x198(%rbp), %rcx
leaq -0x1b0(%rbp), %rdi
leaq -0x8(%rbp), %rsi
leaq -0xa8(%rbp), %rdx
callq 0x2ba0
movq -0x188(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x188(%rbp)
jmp 0x20c7
jmp 0x1e1a
nopl (%rax,%rax)