Просмотр исходного кода

BReactor: add poll() backend. Use it on Linux when epoll is not available.

ambrop7 15 лет назад
Родитель
Сommit
5340a3a761
3 измененных файлов с 237 добавлено и 4 удалено
  1. 4 3
      CMakeLists.txt
  2. 213 0
      system/BReactor.c
  3. 20 1
      system/BReactor.h

+ 4 - 3
CMakeLists.txt

@@ -68,10 +68,11 @@ else ()
         add_definitions(-DBADVPN_USE_SIGNALFD)
         add_definitions(-DBADVPN_USE_SIGNALFD)
 
 
         check_include_files(sys/epoll.h HAVE_SYS_EPOLL_H)
         check_include_files(sys/epoll.h HAVE_SYS_EPOLL_H)
-        if (NOT HAVE_SYS_EPOLL_H)
-            message(FATAL_ERROR "epoll is required")
+        if (HAVE_SYS_EPOLL_H)
+            add_definitions(-DBADVPN_USE_EPOLL)
+        else ()
+            add_definitions(-DBADVPN_USE_POLL)
         endif ()
         endif ()
-        add_definitions(-DBADVPN_USE_EPOLL)
 
 
         check_include_files(linux/rfkill.h HAVE_LINUX_RFKILL_H)
         check_include_files(linux/rfkill.h HAVE_LINUX_RFKILL_H)
         if (HAVE_LINUX_RFKILL_H)
         if (HAVE_LINUX_RFKILL_H)

+ 213 - 0
system/BReactor.c

@@ -36,6 +36,7 @@
 
 
 #include <misc/debug.h>
 #include <misc/debug.h>
 #include <misc/offset.h>
 #include <misc/offset.h>
+#include <misc/balloc.h>
 #include <system/BLog.h>
 #include <system/BLog.h>
 
 
 #include <system/BReactor.h>
 #include <system/BReactor.h>
@@ -212,6 +213,21 @@ static void update_kevent_fd_events (BReactor *bsys, BFileDescriptor *bs, int ev
 
 
 #endif
 #endif
 
 
+#ifdef BADVPN_USE_POLL
+
+static void set_poll_fd_pointers (BReactor *bsys)
+{
+    for (int i = 0; i < bsys->poll_results_num; i++) {
+        BFileDescriptor *bfd = bsys->poll_results_bfds[i];
+        ASSERT(bfd)
+        ASSERT(bfd->active)
+        ASSERT(bfd->poll_returned_index == -1)
+        bfd->poll_returned_index = i;
+    }
+}
+
+#endif
+
 static void wait_for_events (BReactor *bsys)
 static void wait_for_events (BReactor *bsys)
 {
 {
     // must have processed all pending events
     // must have processed all pending events
@@ -226,6 +242,9 @@ static void wait_for_events (BReactor *bsys)
     #ifdef BADVPN_USE_KEVENT
     #ifdef BADVPN_USE_KEVENT
     ASSERT(bsys->kevent_results_pos == bsys->kevent_results_num)
     ASSERT(bsys->kevent_results_pos == bsys->kevent_results_num)
     #endif
     #endif
+    #ifdef BADVPN_USE_POLL
+    ASSERT(bsys->poll_results_pos == bsys->poll_results_num)
+    #endif
 
 
     // clean up epoll results
     // clean up epoll results
     #ifdef BADVPN_USE_EPOLL
     #ifdef BADVPN_USE_EPOLL
@@ -239,6 +258,12 @@ static void wait_for_events (BReactor *bsys)
     bsys->kevent_results_pos = 0;
     bsys->kevent_results_pos = 0;
     #endif
     #endif
     
     
+    // clean up poll results
+    #ifdef BADVPN_USE_POLL
+    bsys->poll_results_num = 0;
+    bsys->poll_results_pos = 0;
+    #endif
+    
     // timeout vars
     // timeout vars
     int have_timeout = 0;
     int have_timeout = 0;
     btime_t timeout_abs;
     btime_t timeout_abs;
@@ -382,6 +407,78 @@ static void wait_for_events (BReactor *bsys)
         
         
         #endif
         #endif
         
         
+        #ifdef BADVPN_USE_POLL
+        
+        if (have_timeout) {
+            if (timeout_rel_trunc > INT_MAX) {
+                timeout_rel_trunc = INT_MAX;
+            }
+        }
+        
+        ASSERT(bsys->poll_num_enabled_fds >= 0)
+        ASSERT(bsys->poll_num_enabled_fds <= BSYSTEM_MAX_POLL_FDS)
+        int num_fds = 0;
+        
+        LinkedList1Node *list_node = LinkedList1_GetFirst(&bsys->poll_enabled_fds_list);
+        while (list_node) {
+            BFileDescriptor *bfd = UPPER_OBJECT(list_node, BFileDescriptor, poll_enabled_fds_list_node);
+            ASSERT(bfd->active)
+            ASSERT(bfd->poll_returned_index == -1)
+            
+            // calculate poll events
+            int pevents = 0;
+            if ((bfd->waitEvents & BREACTOR_READ)) {
+                pevents |= POLLIN;
+            }
+            if ((bfd->waitEvents & BREACTOR_WRITE)) {
+                pevents |= POLLOUT;
+            }
+            
+            // write pollfd entry
+            struct pollfd *pfd = &bsys->poll_results_pollfds[num_fds];
+            pfd->fd = bfd->fd;
+            pfd->events = pevents;
+            pfd->revents = 0;
+            
+            // write BFileDescriptor reference entry
+            bsys->poll_results_bfds[num_fds] = bfd;
+            
+            // increment number of fds in array
+            num_fds++;
+            
+            list_node = LinkedList1Node_Next(list_node);
+        }
+        
+        BLog(BLOG_DEBUG, "Calling poll");
+        
+        int waitres = poll(bsys->poll_results_pollfds, num_fds, (have_timeout ? timeout_rel_trunc : -1));
+        if (waitres < 0) {
+            int error = errno;
+            if (error == EINTR) {
+                BLog(BLOG_DEBUG, "poll interrupted");
+                goto try_again;
+            }
+            perror("poll");
+            ASSERT_FORCE(0)
+        }
+        
+        ASSERT_FORCE(!(waitres == 0) || have_timeout)
+        
+        if (waitres != 0 || timeout_rel_trunc == timeout_rel) {
+            if (waitres != 0) {
+                BLog(BLOG_DEBUG, "poll returned %d file descriptors", waitres);
+                bsys->poll_results_num = num_fds;
+                bsys->poll_results_pos = 0;
+                set_poll_fd_pointers(bsys);
+            } else {
+                BLog(BLOG_DEBUG, "poll timed out");
+                move_first_timers(bsys);
+            }
+            break;
+        }
+        
+        #endif
+        
     try_again:
     try_again:
         if (have_timeout) {
         if (have_timeout) {
             // get current time
             // get current time
@@ -483,6 +580,30 @@ int BReactor_Init (BReactor *bsys)
     
     
     #endif
     #endif
     
     
+    #ifdef BADVPN_USE_POLL
+    
+    // init enabled fds list
+    LinkedList1_Init(&bsys->poll_enabled_fds_list);
+    
+    // set zero enabled fds
+    bsys->poll_num_enabled_fds = 0;
+    
+    // allocate results arrays
+    if (!(bsys->poll_results_pollfds = BAllocArray(BSYSTEM_MAX_POLL_FDS, sizeof(bsys->poll_results_pollfds[0])))) {
+        BLog(BLOG_ERROR, "BAllocArray failed");
+        goto fail0;
+    }
+    if (!(bsys->poll_results_bfds = BAllocArray(BSYSTEM_MAX_POLL_FDS, sizeof(bsys->poll_results_bfds[0])))) {
+        BLog(BLOG_ERROR, "BAllocArray failed");
+        goto fail1;
+    }
+    
+    // init results array
+    bsys->poll_results_num = 0;
+    bsys->poll_results_pos = 0;
+    
+    #endif
+    
     DebugObject_Init(&bsys->d_obj);
     DebugObject_Init(&bsys->d_obj);
     #ifndef BADVPN_USE_WINAPI
     #ifndef BADVPN_USE_WINAPI
     DebugCounter_Init(&bsys->d_fds_counter);
     DebugCounter_Init(&bsys->d_fds_counter);
@@ -493,6 +614,10 @@ int BReactor_Init (BReactor *bsys)
     
     
     return 1;
     return 1;
     
     
+    #ifdef BADVPN_USE_POLL
+fail1:
+    BFree(bsys->poll_results_pollfds);
+    #endif
 fail0:
 fail0:
     BPendingGroup_Free(&bsys->pending_jobs);
     BPendingGroup_Free(&bsys->pending_jobs);
     BLog(BLOG_ERROR, "Reactor failed to initialize");
     BLog(BLOG_ERROR, "Reactor failed to initialize");
@@ -515,6 +640,10 @@ void BReactor_Free (BReactor *bsys)
     #ifdef BADVPN_USE_KEVENT
     #ifdef BADVPN_USE_KEVENT
     DebugCounter_Free(&bsys->d_kevent_ctr);
     DebugCounter_Free(&bsys->d_kevent_ctr);
     #endif
     #endif
+    #ifdef BADVPN_USE_POLL
+    ASSERT(bsys->poll_num_enabled_fds == 0)
+    ASSERT(LinkedList1_IsEmpty(&bsys->poll_enabled_fds_list))
+    #endif
     
     
     BLog(BLOG_DEBUG, "Reactor freeing");
     BLog(BLOG_DEBUG, "Reactor freeing");
     
     
@@ -532,6 +661,14 @@ void BReactor_Free (BReactor *bsys)
     
     
     #endif
     #endif
     
     
+    #ifdef BADVPN_USE_POLL
+    
+    // free results arrays
+    BFree(bsys->poll_results_bfds);
+    BFree(bsys->poll_results_pollfds);
+    
+    #endif
+    
     // free jobs
     // free jobs
     BPendingGroup_Free(&bsys->pending_jobs);
     BPendingGroup_Free(&bsys->pending_jobs);
 }
 }
@@ -698,6 +835,49 @@ int BReactor_Exec (BReactor *bsys)
         
         
         #endif
         #endif
         
         
+        #ifdef BADVPN_USE_POLL
+        
+        if (bsys->poll_results_pos < bsys->poll_results_num) {
+            // grab event
+            struct pollfd *pfd = &bsys->poll_results_pollfds[bsys->poll_results_pos];
+            BFileDescriptor *bfd = bsys->poll_results_bfds[bsys->poll_results_pos];
+            bsys->poll_results_pos++;
+            
+            // skip removed entry
+            if (!bfd) {
+                continue;
+            }
+            
+            ASSERT(bfd->active)
+            ASSERT(bfd->poll_returned_index == bsys->poll_results_pos - 1)
+            
+            // remove result reference
+            bfd->poll_returned_index = -1;
+            
+            // calculate events to report
+            int events = 0;
+            if ((bfd->waitEvents & BREACTOR_READ) && (pfd->revents & POLLIN)) {
+                events |= BREACTOR_READ;
+            }
+            if ((bfd->waitEvents & BREACTOR_WRITE) && (pfd->revents & POLLOUT)) {
+                events |= BREACTOR_WRITE;
+            }
+            if ((pfd->revents & POLLERR) || (pfd->revents & POLLHUP)) {
+                events |= BREACTOR_ERROR;
+            }
+            
+            if (!events) {
+                continue;
+            }
+            
+            // call handler
+            BLog(BLOG_DEBUG, "Dispatching file descriptor");
+            bfd->handler(bfd->user, events);
+            continue;
+        }
+        
+        #endif
+        
         wait_for_events(bsys);
         wait_for_events(bsys);
     }
     }
 
 
@@ -887,6 +1067,22 @@ int BReactor_AddFileDescriptor (BReactor *bsys, BFileDescriptor *bs)
     
     
     #endif
     #endif
     
     
+    #ifdef BADVPN_USE_POLL
+    
+    if (bsys->poll_num_enabled_fds == BSYSTEM_MAX_POLL_FDS) {
+        BLog(BLOG_ERROR, "too many fds");
+        return 0;
+    }
+    
+    // append to enabled fds list
+    LinkedList1_Append(&bsys->poll_enabled_fds_list, &bs->poll_enabled_fds_list_node);
+    bsys->poll_num_enabled_fds++;
+    
+    // set not returned
+    bs->poll_returned_index = -1;
+    
+    #endif
+    
     bs->active = 1;
     bs->active = 1;
     bs->waitEvents = 0;
     bs->waitEvents = 0;
     
     
@@ -924,6 +1120,23 @@ void BReactor_RemoveFileDescriptor (BReactor *bsys, BFileDescriptor *bs)
     }
     }
     
     
     #endif
     #endif
+    
+    #ifdef BADVPN_USE_POLL
+    
+    // invalidate results entry
+    if (bs->poll_returned_index != -1) {
+        ASSERT(bs->poll_returned_index >= bsys->poll_results_pos)
+        ASSERT(bs->poll_returned_index < bsys->poll_results_num)
+        ASSERT(bsys->poll_results_bfds[bs->poll_returned_index] == bs)
+        
+        bsys->poll_results_bfds[bs->poll_returned_index] = NULL;
+    }
+    
+    // remove from enabled fds list
+    LinkedList1_Remove(&bsys->poll_enabled_fds_list, &bs->poll_enabled_fds_list_node);
+    bsys->poll_num_enabled_fds--;
+    
+    #endif
 }
 }
 
 
 void BReactor_SetFileDescriptorEvents (BReactor *bsys, BFileDescriptor *bs, int events)
 void BReactor_SetFileDescriptorEvents (BReactor *bsys, BFileDescriptor *bs, int events)

+ 20 - 1
system/BReactor.h

@@ -28,7 +28,7 @@
 #ifndef BADVPN_SYSTEM_BREACTOR_H
 #ifndef BADVPN_SYSTEM_BREACTOR_H
 #define BADVPN_SYSTEM_BREACTOR_H
 #define BADVPN_SYSTEM_BREACTOR_H
 
 
-#if (defined(BADVPN_USE_WINAPI) + defined(BADVPN_USE_EPOLL) + defined(BADVPN_USE_KEVENT)) != 1
+#if (defined(BADVPN_USE_WINAPI) + defined(BADVPN_USE_EPOLL) + defined(BADVPN_USE_KEVENT) + defined(BADVPN_USE_POLL)) != 1
 #error Unknown event backend or too many event backends
 #error Unknown event backend or too many event backends
 #endif
 #endif
 
 
@@ -46,6 +46,10 @@
 #include <sys/time.h>
 #include <sys/time.h>
 #endif
 #endif
 
 
+#ifdef BADVPN_USE_POLL
+#include <poll.h>
+#endif
+
 #include <stdint.h>
 #include <stdint.h>
 
 
 #include <misc/debug.h>
 #include <misc/debug.h>
@@ -180,6 +184,11 @@ typedef struct BFileDescriptor_t {
     int kevent_tag;
     int kevent_tag;
     int **kevent_returned_ptr;
     int **kevent_returned_ptr;
     #endif
     #endif
+    
+    #ifdef BADVPN_USE_POLL
+    LinkedList1Node poll_enabled_fds_list_node;
+    int poll_returned_index;
+    #endif
 } BFileDescriptor;
 } BFileDescriptor;
 
 
 /**
 /**
@@ -199,6 +208,7 @@ void BFileDescriptor_Init (BFileDescriptor *bs, int fd, BFileDescriptor_handler
 
 
 #define BSYSTEM_MAX_RESULTS 64
 #define BSYSTEM_MAX_RESULTS 64
 #define BSYSTEM_MAX_HANDLES 64
 #define BSYSTEM_MAX_HANDLES 64
+#define BSYSTEM_MAX_POLL_FDS 4096
 
 
 /**
 /**
  * Event loop that supports file desciptor (Linux) or HANDLE (Windows) events
  * Event loop that supports file desciptor (Linux) or HANDLE (Windows) events
@@ -237,6 +247,15 @@ typedef struct {
     int kevent_results_pos;
     int kevent_results_pos;
     #endif
     #endif
     
     
+    #ifdef BADVPN_USE_POLL
+    LinkedList1 poll_enabled_fds_list;
+    int poll_num_enabled_fds;
+    int poll_results_num;
+    int poll_results_pos;
+    struct pollfd *poll_results_pollfds;
+    BFileDescriptor **poll_results_bfds;
+    #endif
+    
     DebugObject d_obj;
     DebugObject d_obj;
     #ifndef BADVPN_USE_WINAPI
     #ifndef BADVPN_USE_WINAPI
     DebugCounter d_fds_counter;
     DebugCounter d_fds_counter;