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