diff seobeo/os/s_macos_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 c0f6c8c7829f
children ecb6ee6a22c3
line wrap: on
line diff
--- a/seobeo/os/s_macos_edge.c	Sat Dec 20 21:07:34 2025 -0500
+++ b/seobeo/os/s_macos_edge.c	Tue Dec 23 11:48:11 2025 -0800
@@ -6,41 +6,66 @@
 {
   WorkerArgs *args = vargs;
   struct kevent evlist[64];
+
+  // Each thread creates its own kqueue to avoid race conditions
+  int kq = kqueue();
+  if (kq < 0) {
+    perror("kqueue");
+    return NULL;
+  }
+
+  // Add server socket to this thread's kqueue
+  struct kevent kev = {
+    .ident  = args->srv->socket,
+    .filter = EVFILT_READ,
+    .flags  = EV_ADD,
+    .udata  = args->srv
+  };
+  kevent(kq, &kev, 1, NULL, 0, NULL);
+
   while (1)
   {
-    int ne = kevent(args->evfd, NULL, 0, evlist, 64, NULL);
-    if (ne < 0) continue;
+    int ne = kevent(kq, NULL, 0, evlist, 64, NULL);
+    if (ne < 0) {
+      if (errno == EINTR) continue;
+      perror("kevent");
+      continue;
+    }
 
     for (int i = 0; i < ne; i++)
     {
       Seobeo_PHandle h = evlist[i].udata;
       if (h == args->srv)
       {
-        Seobeo_PHandle cli =
-          Seobeo_Stream_Handle_Server_Accept(args->srv);
+        // Accept new connections in a loop (for edge-triggered behavior)
+        while (1) {
+          Seobeo_PHandle cli = Seobeo_Stream_Handle_Server_Accept(args->srv);
+          if (!cli) break;
 
-        if (!cli) continue;
-        struct kevent kev = {
-          .ident  = cli->socket,
+          struct kevent client_kev = {
+            .ident  = cli->socket,
+            .filter = EVFILT_READ,
+            .flags  = EV_ADD | EV_ONESHOT,
+            .udata  = cli
+          };
+          kevent(kq, &client_kev, 1, NULL, 0, NULL);
+        }
+      } else {
+        // Remove from kqueue first
+        struct kevent del_kev = {
+          .ident  = h->socket,
           .filter = EVFILT_READ,
-          .flags  = EV_ADD | EV_ONESHOT,
-          .udata  = cli
+          .flags  = EV_DELETE,
         };
-        kevent(args->evfd, &kev, 1, NULL, 0, NULL);
-      } else {
-        if (h != args->srv) {
-          struct kevent kev = {
-            .ident  = h->socket,
-            .filter = EVFILT_READ,
-            .flags  = EV_DELETE,
-          };
-          kevent(args->evfd, &kev, 1, NULL, 0, NULL); // Remove from kqueue first
-        
-          Seobeo_Web_HandleClientRequest(h, args->cache); // this frees 
-        }
+        kevent(kq, &del_kev, 1, NULL, 0, NULL);
+
+        // Handle request (this function destroys the handle internally)
+        Seobeo_Web_HandleClientRequest(h, args->cache);
       }
     }
   }
+
+  close(kq);
   return NULL;
 }
 
@@ -49,15 +74,6 @@
     int            thread_count,
     Dowa_PHashMap  p_html_cache)
 {
-  int kq = kqueue();
-  struct kevent kev = {
-    .ident  = p_server_handle->socket,
-    .filter = EVFILT_READ,
-    .flags  = EV_ADD,
-    .udata  = p_server_handle
-  };
-  kevent(kq, &kev, 1, NULL, 0, NULL);
-
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setstacksize(&attr, 5 * 1024 * 1024); // 5 MB
@@ -66,13 +82,15 @@
   for (int i = 0; i < thread_count; i++)
   {
     WorkerArgs *args = malloc(sizeof(WorkerArgs));
-    *args = (WorkerArgs){ p_server_handle, p_html_cache, kq };
+    *args = (WorkerArgs){ p_server_handle, p_html_cache };
 
-    pthread_create(&threads[i], NULL, Seobeo_Web_Edge_Worker, args);
+    pthread_create(&threads[i], &attr, Seobeo_Web_Edge_Worker, args);
   }
   for (int i = 0; i < thread_count; i++)
   {
     pthread_join(threads[i], NULL);
   }
+
+  pthread_attr_destroy(&attr);
   return;
 }