Mercurial
comparison seobeo/os/s_linux_edge.c @ 62:ea9ef388ab97
[Seobeo] Fixed issues with epoll or kqeue in different threads. Initizlied the event looop inside of the thread itself.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Tue, 23 Dec 2025 11:48:11 -0800 |
| parents | 84672efec192 |
| children | ecb6ee6a22c3 |
comparison
equal
deleted
inserted
replaced
| 61:9df5587cf23b | 62:ea9ef388ab97 |
|---|---|
| 1 #include <sys/epoll.h> | 1 #include <sys/epoll.h> |
| 2 #include "seobeo/seobeo.h" | 2 #include "seobeo/seobeo.h" |
| 3 | 3 |
| 4 | 4 |
| 5 void *Seobeo_Web_Edge_Worker(void *vargs) { | 5 void *Seobeo_Web_Edge_Worker(void *vargs) |
| 6 { | |
| 6 WorkerArgs *args = vargs; | 7 WorkerArgs *args = vargs; |
| 7 const int max_events = 64; | 8 const int max_events = 64; |
| 8 struct epoll_event events[max_events]; | 9 struct epoll_event events[max_events]; |
| 9 | 10 |
| 11 // Each thread creates its own epoll to avoid race conditions | |
| 12 int epfd = epoll_create1(0); | |
| 13 if (epfd < 0) { | |
| 14 perror("epoll_create1"); | |
| 15 return NULL; | |
| 16 } | |
| 17 | |
| 18 // Add server socket to this thread's epoll | |
| 19 struct epoll_event ev = { | |
| 20 .events = EPOLLIN | EPOLLET, | |
| 21 .data.ptr = args->srv | |
| 22 }; | |
| 23 if (epoll_ctl(epfd, EPOLL_CTL_ADD, args->srv->socket, &ev) < 0) { | |
| 24 perror("epoll_ctl ADD server"); | |
| 25 close(epfd); | |
| 26 return NULL; | |
| 27 } | |
| 28 | |
| 10 while (1) { | 29 while (1) { |
| 11 int n = epoll_wait(args->evfd, events, max_events, -1); | 30 int n = epoll_wait(epfd, events, max_events, -1); |
| 12 if (n < 0) { | 31 if (n < 0) { |
| 32 if (errno == EINTR) continue; | |
| 13 perror("epoll_wait"); | 33 perror("epoll_wait"); |
| 14 continue; | 34 continue; |
| 15 } | 35 } |
| 16 | 36 |
| 17 for (int i = 0; i < n; i++) { | 37 for (int i = 0; i < n; i++) { |
| 18 Seobeo_PHandle phandle = events[i].data.ptr; | 38 Seobeo_PHandle phandle = events[i].data.ptr; |
| 19 | 39 |
| 20 if (phandle == args->srv) { | 40 if (phandle == args->srv) { |
| 41 // Accept all pending connections (edge-triggered mode) | |
| 21 while (1) { | 42 while (1) { |
| 22 Seobeo_PHandle p_cli_handle = Seobeo_Stream_Handle_Server_Accept(args->srv); | 43 Seobeo_PHandle p_cli_handle = Seobeo_Stream_Handle_Server_Accept(args->srv); |
| 23 if (!p_cli_handle) break; | 44 if (!p_cli_handle) break; |
| 24 | 45 |
| 25 struct epoll_event client_ev = { | 46 struct epoll_event client_ev = { |
| 26 .events = EPOLLIN | EPOLLET, | 47 .events = EPOLLIN | EPOLLET, |
| 27 .data.ptr = p_cli_handle | 48 .data.ptr = p_cli_handle |
| 28 }; | 49 }; |
| 29 if (epoll_ctl(args->evfd, EPOLL_CTL_ADD, p_cli_handle->socket, &client_ev) < 0) | 50 if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_cli_handle->socket, &client_ev) < 0) |
| 30 { | 51 { |
| 31 perror("epoll_ctl ADD client"); | 52 perror("epoll_ctl ADD client"); |
| 32 Seobeo_Handle_Destroy(p_cli_handle); | 53 Seobeo_Handle_Destroy(p_cli_handle); |
| 33 } | 54 } |
| 34 } | 55 } |
| 35 } else { | 56 } else { |
| 57 // Remove from epoll first | |
| 58 epoll_ctl(epfd, EPOLL_CTL_DEL, phandle->socket, NULL); | |
| 59 | |
| 60 // Handle request (this function destroys the handle internally) | |
| 36 Seobeo_Web_HandleClientRequest(phandle, args->cache); | 61 Seobeo_Web_HandleClientRequest(phandle, args->cache); |
| 37 epoll_ctl(args->evfd, EPOLL_CTL_DEL, phandle->socket, NULL); | |
| 38 Seobeo_Handle_Destroy(phandle); | |
| 39 } | 62 } |
| 40 } | 63 } |
| 41 } | 64 } |
| 42 | 65 |
| 66 close(epfd); | |
| 43 return NULL; | 67 return NULL; |
| 44 } | 68 } |
| 45 | 69 |
| 46 void Seobeo_Web_Edge( | 70 void Seobeo_Web_Edge( |
| 47 Seobeo_PHandle p_server_handle, | 71 Seobeo_PHandle p_server_handle, |
| 48 int thread_count, | 72 int thread_count, |
| 49 Dowa_PHashMap p_html_cache) { | 73 Dowa_PHashMap p_html_cache) |
| 50 | 74 { |
| 51 int epfd = epoll_create1(0); | |
| 52 if (epfd < 0) { | |
| 53 perror("epoll_create1"); | |
| 54 return; | |
| 55 } | |
| 56 | |
| 57 struct epoll_event ev = { | |
| 58 .events = EPOLLIN | EPOLLET, | |
| 59 .data.ptr = p_server_handle | |
| 60 }; | |
| 61 if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_server_handle->socket, &ev) < 0) { | |
| 62 perror("epoll_ctl ADD server"); | |
| 63 close(epfd); | |
| 64 return; | |
| 65 } | |
| 66 | |
| 67 pthread_attr_t attr; | 75 pthread_attr_t attr; |
| 68 pthread_attr_init(&attr); | 76 pthread_attr_init(&attr); |
| 69 pthread_attr_setstacksize(&attr, 5 * 1024 * 1024); // 5 MB | 77 pthread_attr_setstacksize(&attr, 5 * 1024 * 1024); // 5 MB |
| 70 | 78 |
| 79 pthread_t threads[thread_count]; | |
| 71 for (int i = 0; i < thread_count; i++) { | 80 for (int i = 0; i < thread_count; i++) { |
| 72 WorkerArgs *args = malloc(sizeof(WorkerArgs)); | 81 WorkerArgs *args = malloc(sizeof(WorkerArgs)); |
| 73 *args = (WorkerArgs){ p_server_handle, p_html_cache, epfd }; | 82 *args = (WorkerArgs){ p_server_handle, p_html_cache }; |
| 74 | 83 |
| 75 pthread_t tid; | 84 pthread_create(&threads[i], &attr, Seobeo_Web_Edge_Worker, args); |
| 76 pthread_create(&tid, &attr, Seobeo_Web_Edge_Worker, args); | |
| 77 pthread_detach(tid); | |
| 78 } | 85 } |
| 79 | 86 |
| 80 while (1) pause(); | 87 // Join threads instead of detaching for proper cleanup |
| 88 for (int i = 0; i < thread_count; i++) { | |
| 89 pthread_join(threads[i], NULL); | |
| 90 } | |
| 91 | |
| 92 pthread_attr_destroy(&attr); | |
| 81 } | 93 } |
| 82 | 94 |
| 83 | 95 |
| 84 void Seobeo_Web_Edge_2(Seobeo_PHandle p_handle_server, Dowa_PHashMap cache) { | 96 void Seobeo_Web_Edge_2(Seobeo_PHandle p_handle_server, Dowa_PHashMap cache) |
| 97 { | |
| 85 const int MAX_EVENTS = 1024; | 98 const int MAX_EVENTS = 1024; |
| 86 struct epoll_event events[MAX_EVENTS]; | 99 struct epoll_event events[MAX_EVENTS]; |
| 87 char keybuf[32]; | 100 char keybuf[32]; |
| 88 | 101 |
| 89 int epfd = epoll_create1(0); | 102 int epfd = epoll_create1(0); |
| 133 .data.fd = p_handle_client->socket | 146 .data.fd = p_handle_client->socket |
| 134 }; | 147 }; |
| 135 if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_handle_client->socket, &client_ev) < 0) | 148 if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_handle_client->socket, &client_ev) < 0) |
| 136 { | 149 { |
| 137 perror("epoll_ctl ADD client"); | 150 perror("epoll_ctl ADD client"); |
| 151 Seobeo_Handle_Destroy(p_handle_client); | |
| 138 continue; | 152 continue; |
| 139 } | 153 } |
| 140 | 154 |
| 141 snprintf(keybuf, sizeof(keybuf), "%d", p_handle_client->socket); | 155 snprintf(keybuf, sizeof(keybuf), "%d", p_handle_client->socket); |
| 142 if (p_handle_client) | 156 if (p_handle_client) |
| 153 // might happen if client closed between event and lookup | 167 // might happen if client closed between event and lookup |
| 154 epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); | 168 epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); |
| 155 continue; | 169 continue; |
| 156 } | 170 } |
| 157 | 171 |
| 172 // Remove from epoll | |
| 173 epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); | |
| 174 | |
| 175 // Handle request (this function destroys the handle internally) | |
| 158 Seobeo_Web_HandleClientRequest(p_handle_client, cache); | 176 Seobeo_Web_HandleClientRequest(p_handle_client, cache); |
| 177 | |
| 178 // Remove from hashmap (handle is already destroyed by HandleClientRequest) | |
| 179 Dowa_HashMap_Pop_Key(handles, keybuf); | |
| 159 } | 180 } |
| 160 } | 181 } |
| 161 | 182 |
| 162 close(epfd); | 183 close(epfd); |
| 184 Dowa_HashMap_Destroy(handles); | |
| 163 } | 185 } |
| 164 | 186 |