Mercurial
comparison seobeo/os/s_linux_edge.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | a8976a008a9d |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 1 #include <sys/epoll.h> | 1 #include <sys/epoll.h> |
| 2 #include <netinet/tcp.h> | |
| 2 #include "seobeo/seobeo.h" | 3 #include "seobeo/seobeo.h" |
| 3 | 4 |
| 5 // TCP keep-alive settings | |
| 6 #define KEEP_ALIVE_IDLE_SEC 30 // Start probes after 30s idle | |
| 7 #define KEEP_ALIVE_INTERVAL 5 // Probe every 5 seconds | |
| 8 #define KEEP_ALIVE_COUNT 3 // Close after 3 failed probes | |
| 9 | |
| 10 // Configure TCP keep-alive on socket (kernel handles timeout) | |
| 11 static void configure_keep_alive(int socket) | |
| 12 { | |
| 13 int enable = 1; | |
| 14 setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); | |
| 15 | |
| 16 int idle = KEEP_ALIVE_IDLE_SEC; | |
| 17 setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)); | |
| 18 | |
| 19 int interval = KEEP_ALIVE_INTERVAL; | |
| 20 setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); | |
| 21 | |
| 22 int count = KEEP_ALIVE_COUNT; | |
| 23 setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count)); | |
| 24 } | |
| 4 | 25 |
| 5 void *Seobeo_Web_Edge_Worker(void *vargs) | 26 void *Seobeo_Web_Edge_Worker(void *vargs) |
| 6 { | 27 { |
| 7 WorkerArgs *args = vargs; | 28 WorkerArgs *args = vargs; |
| 8 const int max_events = 64; | 29 const int max_events = 64; |
| 9 struct epoll_event events[max_events]; | 30 struct epoll_event events[max_events]; |
| 10 | 31 |
| 11 // Each thread creates its own epoll to avoid race conditions | |
| 12 int epfd = epoll_create1(0); | 32 int epfd = epoll_create1(0); |
| 13 if (epfd < 0) { | 33 if (epfd < 0) |
| 34 { | |
| 14 perror("epoll_create1"); | 35 perror("epoll_create1"); |
| 15 return NULL; | 36 return NULL; |
| 16 } | 37 } |
| 17 | 38 |
| 18 // Add server socket to this thread's epoll | |
| 19 struct epoll_event ev = { | 39 struct epoll_event ev = { |
| 20 .events = EPOLLIN | EPOLLET, | 40 .events = EPOLLIN | EPOLLET, |
| 21 .data.ptr = args->srv | 41 .data.ptr = args->srv |
| 22 }; | 42 }; |
| 23 if (epoll_ctl(epfd, EPOLL_CTL_ADD, args->srv->socket, &ev) < 0) { | 43 if (epoll_ctl(epfd, EPOLL_CTL_ADD, args->srv->socket, &ev) < 0) |
| 44 { | |
| 24 perror("epoll_ctl ADD server"); | 45 perror("epoll_ctl ADD server"); |
| 25 close(epfd); | 46 close(epfd); |
| 26 return NULL; | 47 return NULL; |
| 27 } | 48 } |
| 28 | 49 |
| 29 while (1) { | 50 while (1) |
| 30 int n = epoll_wait(epfd, events, max_events, -1); | 51 { |
| 31 if (n < 0) { | 52 int n = epoll_wait(epfd, events, max_events, -1); // Block indefinitely, kernel handles timeouts |
| 32 if (errno == EINTR) continue; | 53 if (n < 0) |
| 54 { | |
| 55 if (errno == EINTR) | |
| 56 continue; | |
| 33 perror("epoll_wait"); | 57 perror("epoll_wait"); |
| 34 continue; | 58 continue; |
| 35 } | 59 } |
| 36 | 60 |
| 37 for (int i = 0; i < n; i++) { | 61 for (int i = 0; i < n; i++) |
| 38 Seobeo_Handle *phandle = events[i].data.ptr; | 62 { |
| 63 Seobeo_Handle *p_handle = events[i].data.ptr; | |
| 39 | 64 |
| 40 if (phandle == args->srv) { | 65 // Server socket - accept new connections |
| 41 // Accept all pending connections (edge-triggered mode) | 66 if (p_handle == args->srv) |
| 42 while (1) { | 67 { |
| 68 while (1) | |
| 69 { | |
| 43 Seobeo_Handle *p_cli_handle = Seobeo_Stream_Handle_Server_Accept(args->srv); | 70 Seobeo_Handle *p_cli_handle = Seobeo_Stream_Handle_Server_Accept(args->srv); |
| 44 if (!p_cli_handle) break; | 71 if (!p_cli_handle) break; |
| 72 | |
| 73 // Let kernel handle keep-alive timeout | |
| 74 configure_keep_alive(p_cli_handle->socket); | |
| 45 | 75 |
| 46 struct epoll_event client_ev = { | 76 struct epoll_event client_ev = { |
| 47 .events = EPOLLIN | EPOLLET, | 77 .events = EPOLLIN | EPOLLET, |
| 48 .data.ptr = p_cli_handle | 78 .data.ptr = p_cli_handle |
| 49 }; | 79 }; |
| 80 | |
| 50 if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_cli_handle->socket, &client_ev) < 0) | 81 if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_cli_handle->socket, &client_ev) < 0) |
| 51 { | 82 { |
| 52 perror("epoll_ctl ADD client"); | 83 perror("epoll_ctl ADD client"); |
| 53 Seobeo_Handle_Destroy(p_cli_handle); | 84 Seobeo_Handle_Destroy(p_cli_handle); |
| 54 } | 85 } |
| 55 } | 86 } |
| 56 } else { | 87 } |
| 57 // Remove from epoll first | 88 // Client socket - handle request |
| 58 epoll_ctl(epfd, EPOLL_CTL_DEL, phandle->socket, NULL); | 89 else |
| 90 { | |
| 91 Seobeo_Handle *p_client_handle = p_handle; | |
| 59 | 92 |
| 60 // Handle request (this function destroys the handle internally) | 93 // Connection error or hangup - clean up |
| 61 Seobeo_Web_HandleClientRequest(phandle, args->cache); | 94 if (events[i].events & (EPOLLERR | EPOLLHUP)) |
| 95 { | |
| 96 epoll_ctl(epfd, EPOLL_CTL_DEL, p_client_handle->socket, NULL); | |
| 97 Seobeo_Handle_Destroy(p_client_handle); | |
| 98 continue; | |
| 99 } | |
| 100 | |
| 101 // Handle requests (loop for pipelined requests) | |
| 102 boolean keep_alive = TRUE; | |
| 103 while (keep_alive) | |
| 104 { | |
| 105 keep_alive = Seobeo_Web_ClientHandle_Request(p_client_handle, args->cache, TRUE); | |
| 106 | |
| 107 // No more data in buffer, wait for next epoll event | |
| 108 if (keep_alive && p_client_handle->read_buffer_len == 0) | |
| 109 break; | |
| 110 } | |
| 111 | |
| 112 // Client wants to close | |
| 113 if (!keep_alive) | |
| 114 { | |
| 115 epoll_ctl(epfd, EPOLL_CTL_DEL, p_client_handle->socket, NULL); | |
| 116 Seobeo_Handle_Destroy(p_client_handle); | |
| 117 } | |
| 118 // Connection stays open, kernel will timeout if idle | |
| 62 } | 119 } |
| 63 } | 120 } |
| 64 } | 121 } |
| 65 | 122 |
| 66 close(epfd); | 123 close(epfd); |