Explorar o código

BReactor: report error events for file descriptors. BSocket: add a new event for catching these errors, but keep existing behaviour by first reporting
errors through other handlers.

ambrop7 %!s(int64=15) %!d(string=hai) anos
pai
achega
82d03fdea5
Modificáronse 4 ficheiros con 70 adicións e 66 borrados
  1. 8 11
      system/BReactor.c
  2. 10 8
      system/BReactor.h
  3. 44 41
      system/BSocket.c
  4. 8 6
      system/BSocket.h

+ 8 - 11
system/BReactor.c

@@ -227,21 +227,18 @@ static void dispatch_io (BReactor *bsys)
         
         // calculate events to report
         int events = 0;
-        if (bfd->waitEvents&BREACTOR_READ) {
-            if ((event->events&EPOLLIN) || (event->events&EPOLLERR) || (event->events&EPOLLHUP)) {
-                events |= BREACTOR_READ;
-            }
+        if ((bfd->waitEvents&BREACTOR_READ) && (event->events&EPOLLIN)) {
+            events |= BREACTOR_READ;
         }
-        if (bfd->waitEvents&BREACTOR_WRITE) {
-            if ((event->events&EPOLLOUT) || (event->events&EPOLLERR) || (event->events&EPOLLHUP)) {
-                events |= BREACTOR_WRITE;
-            }
+        if ((bfd->waitEvents&BREACTOR_WRITE) && (event->events&EPOLLOUT)) {
+            events |= BREACTOR_WRITE;
+        }
+        if ((event->events&EPOLLERR) || (event->events&EPOLLHUP)) {
+            events |= BREACTOR_ERROR;
         }
         
-        // BUG: if an error occurs on the socket and neither BREACTOR_READ nor BREACTOR_WRITE were requested,
-        // we get the event from epoll as ready, but don't have anybody to tell about it, resulting in an
-        // infinite loop
         if (!events) {
+            BLog(BLOG_ERROR, "no events detected?");
             continue;
         }
         

+ 10 - 8
system/BReactor.h

@@ -132,18 +132,21 @@ void BHandle_Init (BHandle *bh, HANDLE handle, BHandle_handler handler, void *us
 
 struct BFileDescriptor_t;
 
-#define BREACTOR_READ 1
-#define BREACTOR_WRITE 2
+#define BREACTOR_READ (1 << 0)
+#define BREACTOR_WRITE (1 << 1)
+#define BREACTOR_ERROR (1 << 2)
 
 /**
- * Handler function invoked by the reactor when one or more monitored events
- * are detected.
+ * Handler function invoked by the reactor when one or more events are detected.
+ * The events argument will contain a subset of the monitored events (BREACTOR_READ, BREACTOR_WRITE),
+ * plus possibly the error event (BREACTOR_ERROR).
  * The file descriptor object is in active state, being called from within
  * the associated reactor.
  *
  * @param user value passed to {@link BFileDescriptor_Init}
- * @param events bitmask of detected events (BREACTOR_READ, BREACTOR_WRITE).
- *               Will be nonzero, and a subset of current monitored events.
+ * @param events bitmask composed of a subset of monitored events (BREACTOR_READ, BREACTOR_WRITE),
+ *               and possibly the error event (BREACTOR_ERROR).
+ *               Will be nonzero.
  */
 typedef void (*BFileDescriptor_handler) (void *user, int events);
 
@@ -252,8 +255,7 @@ int BReactor_Exec (BReactor *bsys);
  *
  * @param bsys the object
  * @param code value {@link BReactor_Exec} should return. If this is
- *             called more than once from an event loop, the last code
- *             will be returned.
+ *             called more than once, it will return the last code.
  */
 void BReactor_Quit (BReactor *bsys, int code);
 

+ 44 - 41
system/BSocket.c

@@ -45,7 +45,7 @@
 #define HANDLER_WRITE 1
 #define HANDLER_ACCEPT 2
 #define HANDLER_CONNECT 3
-#define NUM_EVENTS 4
+#define HANDLER_ERROR 4
 
 static int get_event_index (int event)
 {
@@ -58,6 +58,8 @@ static int get_event_index (int event)
             return HANDLER_ACCEPT;
         case BSOCKET_CONNECT:
             return HANDLER_CONNECT;
+        case BSOCKET_ERROR:
+            return HANDLER_ERROR;
         default:
             ASSERT(0)
             return 42;
@@ -68,15 +70,15 @@ static int handler_events[] = {
     [HANDLER_READ] = BSOCKET_READ,
     [HANDLER_WRITE] = BSOCKET_WRITE,
     [HANDLER_ACCEPT] = BSOCKET_ACCEPT,
-    [HANDLER_CONNECT] = BSOCKET_CONNECT
+    [HANDLER_CONNECT] = BSOCKET_CONNECT,
+    [HANDLER_ERROR] = BSOCKET_ERROR
 };
 
 static void init_handlers (BSocket *bs)
 {
     bs->global_handler = NULL;
     
-    int i;
-    for (i = 0; i < 4; i++) {
+    for (int i = 0; i < BSOCKET_NUM_EVENTS; i++) {
         bs->handlers[i] = NULL;
     }
 }
@@ -229,7 +231,7 @@ static void dispatch_event (BSocket *bs)
 {
     ASSERT(!bs->global_handler)
     ASSERT(bs->current_event_index >= 0)
-    ASSERT(bs->current_event_index < NUM_EVENTS)
+    ASSERT(bs->current_event_index < BSOCKET_NUM_EVENTS)
     ASSERT(((bs->ready_events)&~(bs->waitEvents)) == 0)
     
     do {
@@ -242,7 +244,7 @@ static void dispatch_event (BSocket *bs)
         bs->current_event_index++;
         bs->ready_events &= ~ev_mask;
         
-        ASSERT(!(bs->ready_events) || bs->current_event_index < NUM_EVENTS)
+        ASSERT(!(bs->ready_events) || bs->current_event_index < BSOCKET_NUM_EVENTS)
         
         if (ev_dispatch) {
             // if there are more events to dispatch, schedule job
@@ -254,7 +256,7 @@ static void dispatch_event (BSocket *bs)
             bs->handlers[ev_index](bs->handlers_user[ev_index], ev_mask);
             return;
         }
-    } while (bs->current_event_index < NUM_EVENTS);
+    } while (bs->current_event_index < BSOCKET_NUM_EVENTS);
     
     ASSERT(!bs->ready_events)
 }
@@ -263,7 +265,7 @@ static void job_handler (BSocket *bs)
 {
     ASSERT(!bs->global_handler) // BSocket_RemoveGlobalEventHandler unsets the job
     ASSERT(bs->current_event_index >= 0)
-    ASSERT(bs->current_event_index < NUM_EVENTS)
+    ASSERT(bs->current_event_index < BSOCKET_NUM_EVENTS)
     ASSERT(((bs->ready_events)&~(bs->waitEvents)) == 0) // BSocket_DisableEvent clears events from ready_events
     DebugObject_Access(&bs->d_obj);
     
@@ -325,39 +327,35 @@ static void handle_handler (BSocket *bs)
     
     int returned_events = 0;
     
-    if (bs->waitEvents&BSOCKET_READ) {
-        if ((events.lNetworkEvents&FD_READ) || (events.lNetworkEvents&FD_CLOSE)) {
-            returned_events |= BSOCKET_READ;
-        }
+    if ((bs->waitEvents&BSOCKET_READ) && ((events.lNetworkEvents&FD_READ) || (events.lNetworkEvents&FD_CLOSE))) {
+        returned_events |= BSOCKET_READ;
     }
     
-    if (bs->waitEvents&BSOCKET_WRITE) {
-        if ((events.lNetworkEvents&FD_WRITE) || (events.lNetworkEvents&FD_CLOSE)) {
-            returned_events |= BSOCKET_WRITE;
-        }
+    if ((bs->waitEvents&BSOCKET_WRITE) && ((events.lNetworkEvents&FD_WRITE) || (events.lNetworkEvents&FD_CLOSE))) {
+        returned_events |= BSOCKET_WRITE;
     }
     
-    if (bs->waitEvents&BSOCKET_ACCEPT) {
-        if (events.lNetworkEvents&FD_ACCEPT) {
-            returned_events |= BSOCKET_ACCEPT;
-        }
+    if ((bs->waitEvents&BSOCKET_ACCEPT) && (events.lNetworkEvents&FD_ACCEPT)) {
+        returned_events |= BSOCKET_ACCEPT;
     }
     
-    if (bs->waitEvents&BSOCKET_CONNECT) {
-        if (events.lNetworkEvents&FD_CONNECT) {
-            returned_events |= BSOCKET_CONNECT;
-            
-            // read connection attempt result
-            ASSERT(bs->connecting_status == 1)
-            bs->connecting_status = 2;
-            if (events.iErrorCode[FD_CONNECT_BIT] == 0) {
-                bs->connecting_result = BSOCKET_ERROR_NONE;
-            } else {
-                bs->connecting_result = translate_error(events.iErrorCode[FD_CONNECT_BIT]);
-            }
+    if ((bs->waitEvents&BSOCKET_CONNECT) && (events.lNetworkEvents&FD_CONNECT)) {
+        returned_events |= BSOCKET_CONNECT;
+        
+        // read connection attempt result
+        ASSERT(bs->connecting_status == 1)
+        bs->connecting_status = 2;
+        if (events.iErrorCode[FD_CONNECT_BIT] == 0) {
+            bs->connecting_result = BSOCKET_ERROR_NONE;
+        } else {
+            bs->connecting_result = translate_error(events.iErrorCode[FD_CONNECT_BIT]);
         }
     }
     
+    if ((bs->waitEvents&BSOCKET_ERROR) && (events.lNetworkEvents&FD_CLOSE)) {
+        returned_events |= BSOCKET_ERROR;
+    }
+    
     dispatch_events(bs, returned_events);
     return;
 }
@@ -367,7 +365,7 @@ static void handle_handler (BSocket *bs)
 static int get_reactor_fd_events (int sock_events)
 {
     int res = 0;
-
+    
     if ((sock_events&BSOCKET_READ) || (sock_events&BSOCKET_ACCEPT)) {
         res |= BREACTOR_READ;
     }
@@ -384,19 +382,19 @@ static void file_descriptor_handler (BSocket *bs, int events)
     
     int returned_events = 0;
     
-    if ((bs->waitEvents&BSOCKET_READ) && (events&BREACTOR_READ)) {
+    if ((bs->waitEvents&BSOCKET_READ) && ((events&BREACTOR_READ) || (events&BREACTOR_ERROR))) {
         returned_events |= BSOCKET_READ;
     }
     
-    if ((bs->waitEvents&BSOCKET_WRITE) && (events&BREACTOR_WRITE)) {
+    if ((bs->waitEvents&BSOCKET_WRITE) && ((events&BREACTOR_WRITE) || (events&BREACTOR_ERROR))) {
         returned_events |= BSOCKET_WRITE;
     }
     
-    if ((bs->waitEvents&BSOCKET_ACCEPT) && (events&BREACTOR_READ)) {
+    if ((bs->waitEvents&BSOCKET_ACCEPT) && ((events&BREACTOR_READ) || (events&BREACTOR_ERROR))) {
         returned_events |= BSOCKET_ACCEPT;
     }
     
-    if ((bs->waitEvents&BSOCKET_CONNECT) && (events&BREACTOR_WRITE)) {
+    if ((bs->waitEvents&BSOCKET_CONNECT) && ((events&BREACTOR_WRITE) || (events&BREACTOR_ERROR))) {
         returned_events |= BSOCKET_CONNECT;
         
         // read connection attempt result
@@ -413,6 +411,10 @@ static void file_descriptor_handler (BSocket *bs, int events)
         }
     }
     
+    if ((bs->waitEvents&BSOCKET_ERROR) && (events&BREACTOR_ERROR)) {
+        returned_events |= BSOCKET_ERROR;
+    }
+    
     dispatch_events(bs, returned_events);
     return;
 }
@@ -670,10 +672,9 @@ void BSocket_AddGlobalEventHandler (BSocket *bs, BSocket_handler handler, void *
     
     ASSERT(handler)
     ASSERT(!bs->global_handler)
-    ASSERT(!bs->handlers[0])
-    ASSERT(!bs->handlers[1])
-    ASSERT(!bs->handlers[2])
-    ASSERT(!bs->handlers[3])
+    for (int i = 0; i < BSOCKET_NUM_EVENTS; i++) {
+        ASSERT(!bs->handlers[i])
+    }
     
     bs->global_handler = handler;
     bs->global_handler_user = user;
@@ -761,6 +762,8 @@ void BSocket_EnableEvent (BSocket *bs, uint8_t event)
             ASSERT(!(bs->waitEvents&BSOCKET_WRITE))
             ASSERT(!(bs->waitEvents&BSOCKET_ACCEPT))
             break;
+        case BSOCKET_ERROR:
+            break;
         default:
             ASSERT(0)
             break;

+ 8 - 6
system/BSocket.h

@@ -58,10 +58,12 @@
 #define BSOCKET_TYPE_DGRAM 2
 
 // socket events
-#define BSOCKET_READ 1
-#define BSOCKET_WRITE 2
-#define BSOCKET_ACCEPT 4
-#define BSOCKET_CONNECT 8
+#define BSOCKET_READ (1 << 0)
+#define BSOCKET_WRITE (1 << 1)
+#define BSOCKET_ACCEPT (1 << 2)
+#define BSOCKET_CONNECT (1 << 3)
+#define BSOCKET_ERROR (1 << 4)
+#define BSOCKET_NUM_EVENTS 5
 
 // default backlog if backlog is <0
 #define BSOCKET_DEFAULT_BACKLOG 128
@@ -107,8 +109,8 @@ typedef struct BSocket_t {
     int error;
     BSocket_handler global_handler;
     void *global_handler_user;
-    BSocket_handler handlers[4];
-    void *handlers_user[4];
+    BSocket_handler handlers[BSOCKET_NUM_EVENTS];
+    void *handlers_user[BSOCKET_NUM_EVENTS];
     uint8_t waitEvents;
     int connecting_status; // 0 not connecting, 1 connecting, 2 finished
     int connecting_result;