View Issue Details

IDProjectCategoryView StatusLast Update
0003128GNUnetutil librarypublic2013-11-26 23:27
ReporterMatthias Wachs Assigned ToChristian Grothoff  
PrioritynormalSeverityfeatureReproducibilityhave not tried
Status closedResolutionwon't fix 
Summary0003128: scheduler patch
DescriptionThis is a patch that extends GNUnet's scheduler to be able to monitor
exceptions on file descriptors. The externally-facing API is slightly modified
and a few programs have been changed to use this new API. I don't think it
breaks anything - all the tests that passed on my machine without this patch
pass with it.

https://canndrew.org/misc/gnunet_scheduler_fd_exceptions.diff
TagsNo tags attached.
Attached Files
gnunet_scheduler_fd_exceptions.diff (40,969 bytes)   
diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c
index e494d24..b931137 100644
--- a/src/dns/dnsstub.c
+++ b/src/dns/dnsstub.c
@@ -239,6 +239,7 @@ get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
   rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
 					       REQUEST_TIMEOUT,
 					       rset,
+                           NULL,
 					       NULL,
 					       &read_response, rs);
   GNUNET_NETWORK_fdset_destroy (rset);
@@ -502,6 +503,7 @@ read_response (void *cls,
 					       GNUNET_TIME_absolute_get_remaining (rs->timeout),
 					       rset,
 					       NULL,
+                           NULL,
 					       &read_response, rs);
   GNUNET_NETWORK_fdset_destroy (rset);
 }
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c
index e464ffa..31bcd99 100644
--- a/src/gns/gnunet-gns-proxy.c
+++ b/src/gns/gnunet-gns-proxy.c
@@ -1269,6 +1269,7 @@ curl_download_prepare ()
   int max;
   struct GNUNET_NETWORK_FDSet *grs;
   struct GNUNET_NETWORK_FDSet *gws;
+  struct GNUNET_NETWORK_FDSet *ges;
   long to;
   struct GNUNET_TIME_Relative rtime;
 
@@ -1299,14 +1300,17 @@ curl_download_prepare ()
   {
     grs = GNUNET_NETWORK_fdset_create ();
     gws = GNUNET_NETWORK_fdset_create ();
+    ges = GNUNET_NETWORK_fdset_create ();
     GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
     GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
+    GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
     curl_download_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
 						      rtime,
-						      grs, gws,
+						      grs, gws, ges,
 						      &curl_task_download, curl_multi);
     GNUNET_NETWORK_fdset_destroy (gws);
     GNUNET_NETWORK_fdset_destroy (grs);
+    GNUNET_NETWORK_fdset_destroy (ges);
   }
   else
   {
@@ -1833,6 +1837,7 @@ schedule_httpd (struct MhdHttpList *hd)
   fd_set es;
   struct GNUNET_NETWORK_FDSet *wrs;
   struct GNUNET_NETWORK_FDSet *wws;
+  struct GNUNET_NETWORK_FDSet *wes;
   int max;
   int haveto;
   MHD_UNSIGNED_LONG_LONG timeout;
@@ -1856,13 +1861,16 @@ schedule_httpd (struct MhdHttpList *hd)
   {
     wrs = GNUNET_NETWORK_fdset_create ();
     wws = GNUNET_NETWORK_fdset_create ();
+    wes = GNUNET_NETWORK_fdset_create ();
     GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
     GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
+    GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
   }
   else
   {
     wrs = NULL;
     wws = NULL;
+    wes = NULL;
   }
   if (GNUNET_SCHEDULER_NO_TASK != hd->httpd_task)
     GNUNET_SCHEDULER_cancel (hd->httpd_task);
@@ -1879,13 +1887,15 @@ schedule_httpd (struct MhdHttpList *hd)
   {
     hd->httpd_task =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-				   tv, wrs, wws,
+				   tv, wrs, wws, wes,
 				   &do_httpd, hd);
   }
   if (NULL != wrs)
     GNUNET_NETWORK_fdset_destroy (wrs);
   if (NULL != wws)
     GNUNET_NETWORK_fdset_destroy (wws);
+  if (NULL != wes)
+    GNUNET_NETWORK_fdset_destroy (wes);
 }
 
 
diff --git a/src/gns/test_gns_proxy.c b/src/gns/test_gns_proxy.c
index eac9e44..89f5ce8 100644
--- a/src/gns/test_gns_proxy.c
+++ b/src/gns/test_gns_proxy.c
@@ -178,6 +178,7 @@ curl_main ()
   int max;
   struct GNUNET_NETWORK_FDSet nrs;
   struct GNUNET_NETWORK_FDSet nws;
+  struct GNUNET_NETWORK_FDSet nes;
   struct GNUNET_TIME_Relative delay;
   long timeout;
   int running;
@@ -234,10 +235,14 @@ curl_main ()
   GNUNET_NETWORK_fdset_copy_native (&nws,
 				    &ws,
 				    max + 1);
+  GNUNET_NETWORK_fdset_copy_native (&nes,
+                    &es,
+                    max + 1);
   curl_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
 					      delay,
 					      &nrs,
 					      &nws,
+                          &nes,
 					      &curl_task,
 					      NULL);
 }
@@ -325,6 +330,7 @@ mhd_main ()
 {
   struct GNUNET_NETWORK_FDSet nrs;
   struct GNUNET_NETWORK_FDSet nws;
+  struct GNUNET_NETWORK_FDSet nes;
   fd_set rs;
   fd_set ws;
   fd_set es;
@@ -350,10 +356,14 @@ mhd_main ()
   GNUNET_NETWORK_fdset_copy_native (&nws,
 				    &ws,
 				    max_fd + 1);
+  GNUNET_NETWORK_fdset_copy_native (&nes,
+				    &es,
+				    max_fd + 1);
   mhd_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
 					     delay,
 					     &nrs,
 					     &nws,
+                         &nes,
 					     &mhd_task,
 					     NULL);
 }
diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c
index 488443f..ae0782d 100644
--- a/src/hostlist/hostlist-client.c
+++ b/src/hostlist/hostlist-client.c
@@ -725,6 +725,7 @@ download_prepare ()
   int max;
   struct GNUNET_NETWORK_FDSet *grs;
   struct GNUNET_NETWORK_FDSet *gws;
+  struct GNUNET_NETWORK_FDSet *ges;
   long timeout;
   struct GNUNET_TIME_Relative rtime;
 
@@ -756,16 +757,19 @@ download_prepare ()
                                 (GNUNET_TIME_UNIT_MILLISECONDS, timeout));
   grs = GNUNET_NETWORK_fdset_create ();
   gws = GNUNET_NETWORK_fdset_create ();
+  ges = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
+  GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Scheduling task for hostlist download using cURL\n");
   ti_download =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   rtime, grs, gws,
+                                   rtime, grs, gws, ges,
                                    &task_download, multi);
   GNUNET_NETWORK_fdset_destroy (gws);
   GNUNET_NETWORK_fdset_destroy (grs);
+  GNUNET_NETWORK_fdset_destroy (ges);
 }
 
 
diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c
index 49d3a52..2c67ccd 100644
--- a/src/hostlist/hostlist-server.c
+++ b/src/hostlist/hostlist-server.c
@@ -512,7 +512,7 @@ prepare_daemon (struct MHD_Daemon *daemon_handle)
   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
   ret =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-				   tv, wrs, wws,
+				   tv, wrs, wws, wes,
                                    &run_daemon, daemon_handle);
   GNUNET_NETWORK_fdset_destroy (wrs);
   GNUNET_NETWORK_fdset_destroy (wws);
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h
index 83d9d26..754b314 100644
--- a/src/include/gnunet_scheduler_lib.h
+++ b/src/include/gnunet_scheduler_lib.h
@@ -85,7 +85,12 @@ enum GNUNET_SCHEDULER_Reason
   /**
    * The prerequisite task is done.
    */
-  GNUNET_SCHEDULER_REASON_PREREQ_DONE = 16
+  GNUNET_SCHEDULER_REASON_PREREQ_DONE = 16,
+
+  /**
+   * The socket has an exception
+   */
+  GNUNET_SCHEDULER_REASON_EXCEPTION = 32
 };
 
 
@@ -184,6 +189,12 @@ struct GNUNET_SCHEDULER_TaskContext
    */
   const struct GNUNET_NETWORK_FDSet *write_ready;
 
+  /**
+   * Set of file descriptors that have an exception;
+   * note that additional bits may be set
+   * that were not in the original request.
+   */
+  const struct GNUNET_NETWORK_FDSet *exceptional;
 };
 
 
@@ -465,6 +476,32 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
                                 struct GNUNET_NETWORK_Handle *wfd,
                                 GNUNET_SCHEDULER_Task task, void *task_cls);
 
+/**
+ * Schedule a new task to be run with a specified delay or when a
+ * specified file descriptor is ready for reading, writing, or has
+ * an exception. The delay can be used as a timeout on the sockets
+ * being ready.  The task will be scheduled for execution once
+ * either the delay has expired or the socket operation is ready.
+ *
+ * @param delay when should this operation time out? Use
+ *        #GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param priority priority of the task
+ * @param rfs read file-descriptor
+ * @param wfd write file-descriptor
+ * @param efd exception file-descriptor
+ * @param task main function of the task
+ * @param task_cls closure of @a task
+ * @return unique task identifier for the job
+ *         only valid until @a task is started!
+ */
+GNUNET_SCHEDULER_TaskIdentifier
+GNUNET_SCHEDULER_add_net_with_priority (
+    struct GNUNET_TIME_Relative delay,
+    enum GNUNET_SCHEDULER_Priority priority,
+    struct GNUNET_NETWORK_Handle *rfd,
+    struct GNUNET_NETWORK_Handle *wfd,
+    struct GNUNET_NETWORK_Handle *efd,
+    GNUNET_SCHEDULER_Task task, void *task_cls);
 
 /**
  * Schedule a new task to be run with a specified delay or when the
@@ -509,6 +546,32 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
 
 
 /**
+ * Schedule a new task to be run with a specified delay or when a
+ * specified file descriptor is ready.  The delay can be
+ * used as a timeout on the socket being ready.  The task will be
+ * scheduled for execution once either the delay has expired or the
+ * socket operation is ready.
+ *
+ * @param delay when should this operation time out? Use
+ *        #GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param rfd read file-descriptor
+ * @param wfd write file-descriptor
+ * @param efd exception file-descriptor
+ * @param task main function of the task
+ * @param task_cls closure of @a task
+ * @return unique task identifier for the job
+ *         only valid until @a task is started!
+ */
+GNUNET_SCHEDULER_TaskIdentifier
+GNUNET_SCHEDULER_add_file_with_priority (
+    struct GNUNET_TIME_Relative delay,
+    enum GNUNET_SCHEDULER_Priority priority,
+    const struct GNUNET_DISK_FileHandle *rfd,
+    const struct GNUNET_DISK_FileHandle *wfd,
+    const struct GNUNET_DISK_FileHandle *efd,
+    GNUNET_SCHEDULER_Task task, void *task_cls);
+
+/**
  * Schedule a new task to be run with a specified delay or when any of
  * the specified file descriptor sets is ready.  The delay can be used
  * as a timeout on the socket(s) being ready.  The task will be
@@ -540,6 +603,7 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
                              struct GNUNET_TIME_Relative delay,
                              const struct GNUNET_NETWORK_FDSet *rs,
                              const struct GNUNET_NETWORK_FDSet *ws,
+                             const struct GNUNET_NETWORK_FDSet *es,
                              GNUNET_SCHEDULER_Task task, void *task_cls);
 
 /**
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c
index 008e9ce..10fd674 100644
--- a/src/namestore/gnunet-namestore-fcfsd.c
+++ b/src/namestore/gnunet-namestore-fcfsd.c
@@ -808,7 +808,7 @@ run_httpd ()
   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
   httpd_task =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                   tv, wrs, wws,
+                                   tv, wrs, wws, wes,
                                    &do_httpd, NULL);
   GNUNET_NETWORK_fdset_destroy (wrs);
   GNUNET_NETWORK_fdset_destroy (wws);
diff --git a/src/pt/test_gns_vpn.c b/src/pt/test_gns_vpn.c
index e686ce8..7261fd6 100644
--- a/src/pt/test_gns_vpn.c
+++ b/src/pt/test_gns_vpn.c
@@ -175,6 +175,7 @@ curl_main ()
   int max;
   struct GNUNET_NETWORK_FDSet nrs;
   struct GNUNET_NETWORK_FDSet nws;
+  struct GNUNET_NETWORK_FDSet nes;
   struct GNUNET_TIME_Relative delay;
   long timeout;
   int running;
@@ -231,10 +232,14 @@ curl_main ()
   GNUNET_NETWORK_fdset_copy_native (&nws,
 				    &ws,
 				    max + 1);
+  GNUNET_NETWORK_fdset_copy_native (&nes,
+                    &es,
+                    max + 1);
   curl_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
 					      delay,
 					      &nrs,
 					      &nws,
+                          &nes,
 					      &curl_task,
 					      NULL);
 }
@@ -321,6 +326,7 @@ mhd_main ()
 {
   struct GNUNET_NETWORK_FDSet nrs;
   struct GNUNET_NETWORK_FDSet nws;
+  struct GNUNET_NETWORK_FDSet nes;
   fd_set rs;
   fd_set ws;
   fd_set es;
@@ -346,10 +352,14 @@ mhd_main ()
   GNUNET_NETWORK_fdset_copy_native (&nws,
 				    &ws,
 				    max_fd + 1);
+  GNUNET_NETWORK_fdset_copy_native (&nes,
+				    &es,
+				    max_fd + 1);
   mhd_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
 					     delay,
 					     &nrs,
 					     &nws,
+                         &nes,
 					     &mhd_task,
 					     NULL);
 }
diff --git a/src/pt/test_gnunet_vpn.c b/src/pt/test_gnunet_vpn.c
index 7e83fdc..2e0347a 100644
--- a/src/pt/test_gnunet_vpn.c
+++ b/src/pt/test_gnunet_vpn.c
@@ -187,6 +187,7 @@ curl_main ()
   int max;
   struct GNUNET_NETWORK_FDSet nrs;
   struct GNUNET_NETWORK_FDSet nws;
+  struct GNUNET_NETWORK_FDSet nes;
   struct GNUNET_TIME_Relative delay;
   long timeout;
   int running;
@@ -239,9 +240,10 @@ curl_main ()
                                        (unsigned int) timeout);
   GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max + 1);
   GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max + 1);
+  GNUNET_NETWORK_fdset_copy_native (&nes, &es, max + 1);
   curl_task_id =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay,
-                                   &nrs, &nws, &curl_task, NULL);
+                                   &nrs, &nws, &nes, &curl_task, NULL);
 }
 
 
@@ -322,6 +324,7 @@ mhd_main ()
 {
   struct GNUNET_NETWORK_FDSet nrs;
   struct GNUNET_NETWORK_FDSet nws;
+  struct GNUNET_NETWORK_FDSet nes;
   fd_set rs;
   fd_set ws;
   fd_set es;
@@ -343,9 +346,10 @@ mhd_main ()
     delay = GNUNET_TIME_UNIT_FOREVER_REL;
   GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max_fd + 1);
   GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max_fd + 1);
+  GNUNET_NETWORK_fdset_copy_native (&nes, &es, max_fd + 1);
   mhd_task_id =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay,
-                                   &nrs, &nws, &mhd_task, NULL);
+                                   &nrs, &nws, &nes, &mhd_task, NULL);
 }
 
 
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
index ba125aa..97cab7c 100644
--- a/src/transport/plugin_transport_http_client.c
+++ b/src/transport/plugin_transport_http_client.c
@@ -1047,6 +1047,7 @@ client_schedule (struct HTTP_Client_Plugin *plugin, int now)
   int max;
   struct GNUNET_NETWORK_FDSet *grs;
   struct GNUNET_NETWORK_FDSet *gws;
+  struct GNUNET_NETWORK_FDSet *ges;
   long to;
   CURLMcode mret;
   struct GNUNET_TIME_Relative timeout;
@@ -1089,11 +1090,14 @@ client_schedule (struct HTTP_Client_Plugin *plugin, int now)
   gws = GNUNET_NETWORK_fdset_create ();
+  ges = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
+  GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
 
   plugin->client_perform_task =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   timeout, grs, gws,
+                                   timeout, grs, gws, ges,
                                    &client_run, plugin);
+  GNUNET_NETWORK_fdset_destroy (ges);
   GNUNET_NETWORK_fdset_destroy (gws);
   GNUNET_NETWORK_fdset_destroy (grs);
   return GNUNET_OK;
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
index a1c321d..382ee9c 100644
--- a/src/transport/plugin_transport_http_server.c
+++ b/src/transport/plugin_transport_http_server.c
@@ -1798,7 +1798,7 @@ server_schedule (struct HTTP_Server_Plugin *plugin,
 #endif
     ret =
         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                     tv, wrs, wws,
+                                     tv, wrs, wws, wes,
                                      &server_v4_run, plugin);
   }
   if (daemon_handle == plugin->server_v6)
@@ -1814,7 +1814,7 @@ server_schedule (struct HTTP_Server_Plugin *plugin,
 #endif
     ret =
         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                     tv, wrs, wws,
+                                     tv, wrs, wws, wes,
                                      &server_v6_run, plugin);
   }
   GNUNET_NETWORK_fdset_destroy (wrs);
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
index 896dc66..8efd47c 100644
--- a/src/transport/plugin_transport_udp.c
+++ b/src/transport/plugin_transport_udp.c
@@ -514,6 +514,7 @@ schedule_select (struct Plugin *plugin)
 				   (0 == min_delay.rel_value_us) ? GNUNET_TIME_UNIT_FOREVER_REL : min_delay,
 				   plugin->rs_v4,
 				   (0 == min_delay.rel_value_us) ? plugin->ws_v4 : NULL,
+                   NULL,
 				   &udp_plugin_select, plugin);
   }
   if ((GNUNET_YES == plugin->enable_ipv6) && (NULL != plugin->sockv6))
@@ -530,6 +531,7 @@ schedule_select (struct Plugin *plugin)
 				   (0 == min_delay.rel_value_us) ? GNUNET_TIME_UNIT_FOREVER_REL : min_delay,
 				   plugin->rs_v6,
 				   (0 == min_delay.rel_value_us) ? plugin->ws_v6 : NULL,
+                   NULL,
 				   &udp_plugin_select_v6, plugin);
   }
 }
diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c
index e78445a..c58ec09 100644
--- a/src/transport/plugin_transport_unix.c
+++ b/src/transport/plugin_transport_unix.c
@@ -444,6 +444,7 @@ reschedule_select (struct Plugin * plugin)
                                    GNUNET_TIME_UNIT_FOREVER_REL,
                                    plugin->rs,
                                    plugin->ws,
+                                   NULL,
                                    &unix_plugin_select, plugin);
     plugin->with_ws = GNUNET_YES;
   }
@@ -454,6 +455,7 @@ reschedule_select (struct Plugin * plugin)
                                    GNUNET_TIME_UNIT_FOREVER_REL,
                                    plugin->rs,
                                    NULL,
+                                   NULL,
                                    &unix_plugin_select, plugin);
     plugin->with_ws = GNUNET_NO;
   }
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 36c3a44..b407161 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -106,6 +106,13 @@ struct Task
   struct GNUNET_NETWORK_FDSet *write_set;
 
   /**
+   * Set of file descriptors to watch for exceptions.
+   * Once ready, this is updated to reflect the set of file
+   * descriptors ready for operation.
+   */
+  struct GNUNET_NETWORK_FDSet *exception_set;
+
+  /**
    * Unique task identifier.
    */
   GNUNET_SCHEDULER_TaskIdentifier id;
@@ -146,6 +153,11 @@ struct Task
   int write_fd;
 
   /**
+   * Set if we only wait for exceptions on a single FD, otherwise -1.
+   */
+  int exception_fd;
+
+  /**
    * Should the existence of this task in the queue be counted as
    * reason to not shutdown the scheduler?
    */
@@ -284,7 +296,9 @@ check_priority (enum GNUNET_SCHEDULER_Priority p)
  * @param timeout next timeout (updated)
  */
 static void
-update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
+update_sets (struct GNUNET_NETWORK_FDSet *rs,
+             struct GNUNET_NETWORK_FDSet *ws,
+             struct GNUNET_NETWORK_FDSet *es,
              struct GNUNET_TIME_Relative *timeout)
 {
   struct Task *pos;
@@ -314,10 +328,14 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
       GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd);
     if (pos->write_fd != -1)
       GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd);
+    if (pos->exception_fd != -1)
+      GNUNET_NETWORK_fdset_set_native (es, pos->exception_fd);
     if (pos->read_set != NULL)
       GNUNET_NETWORK_fdset_add (rs, pos->read_set);
     if (pos->write_set != NULL)
       GNUNET_NETWORK_fdset_add (ws, pos->write_set);
+    if (pos->exception_set != NULL)
+      GNUNET_NETWORK_fdset_add (es, pos->exception_set);
     if (pos->reason != 0)
       *timeout = GNUNET_TIME_UNIT_ZERO;
     pos = pos->next;
@@ -359,12 +377,14 @@ set_overlaps (const struct GNUNET_NETWORK_FDSet *ready,
  * @param now the current time
  * @param rs set of FDs ready for reading
  * @param ws set of FDs ready for writing
+ * @param es set of FDs with exceptions
  * @return #GNUNET_YES if we can run it, #GNUNET_NO if not.
  */
 static int
 is_ready (struct Task *task, struct GNUNET_TIME_Absolute now,
           const struct GNUNET_NETWORK_FDSet *rs,
-          const struct GNUNET_NETWORK_FDSet *ws)
+          const struct GNUNET_NETWORK_FDSet *ws,
+          const struct GNUNET_NETWORK_FDSet *es)
 {
   enum GNUNET_SCHEDULER_Reason reason;
 
@@ -381,6 +401,11 @@ is_ready (struct Task *task, struct GNUNET_TIME_Absolute now,
         (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, task->write_fd)))
        || (set_overlaps (ws, task->write_set))))
     reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
+  if ((0 == (reason & GNUNET_SCHEDULER_REASON_EXCEPTION)) &&
+      (((task->exception_fd != -1) &&
+        (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (es, task->exception_fd))) ||
+       (set_overlaps (es, task->exception_set))))
+    reason |= GNUNET_SCHEDULER_REASON_EXCEPTION;
   if (reason == 0)
     return GNUNET_NO;           /* not ready */
   reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
@@ -413,10 +438,12 @@ queue_ready_task (struct Task *task)
  *
  * @param rs FDs ready for reading
  * @param ws FDs ready for writing
+ * @param es FDs with exceptions
  */
 static void
 check_ready (const struct GNUNET_NETWORK_FDSet *rs,
-             const struct GNUNET_NETWORK_FDSet *ws)
+             const struct GNUNET_NETWORK_FDSet *ws,
+             const struct GNUNET_NETWORK_FDSet *es)
 {
   struct Task *pos;
   struct Task *prev;
@@ -446,7 +473,7 @@ check_ready (const struct GNUNET_NETWORK_FDSet *rs,
 	 "Checking readiness of task: %llu / %p\n",
          pos->id, pos->callback_cls);
     next = pos->next;
-    if (GNUNET_YES == is_ready (pos, now, rs, ws))
+    if (GNUNET_YES == is_ready (pos, now, rs, ws, es))
     {
       if (prev == NULL)
         pending = next;
@@ -520,6 +547,8 @@ destroy_task (struct Task *t)
     GNUNET_NETWORK_fdset_destroy (t->read_set);
   if (NULL != t->write_set)
     GNUNET_NETWORK_fdset_destroy (t->write_set);
+  if (NULL != t->exception_set)
+    GNUNET_NETWORK_fdset_destroy (t->exception_set);
 #if EXECINFO
   GNUNET_free (t->backtrace_strings);
 #endif
@@ -536,9 +565,13 @@ destroy_task (struct Task *t)
  *
  * @param rs FDs ready for reading
  * @param ws FDs ready for writing
+ * @param es FDs with exceptions
  */
 static void
-run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
+run_ready (
+    struct GNUNET_NETWORK_FDSet *rs,
+    struct GNUNET_NETWORK_FDSet *ws,
+    struct GNUNET_NETWORK_FDSet *es)
 {
   enum GNUNET_SCHEDULER_Priority p;
   struct Task *pos;
@@ -575,10 +608,16 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
     }
 #endif
     tc.reason = pos->reason;
+
     tc.read_ready = (pos->read_set == NULL) ? rs : pos->read_set;
     if ((pos->read_fd != -1) &&
         (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY)))
       GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd);
+    if (((tc.reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) &&
+        (pos->read_fd != -1) &&
+        (!GNUNET_NETWORK_fdset_test_native (rs, pos->read_fd)))
+      GNUNET_abort ();          // added to ready in previous select loop!
+
     tc.write_ready = (pos->write_set == NULL) ? ws : pos->write_set;
     if ((pos->write_fd != -1) &&
         (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)))
@@ -587,6 +626,17 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
         (pos->write_fd != -1) &&
         (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd)))
       GNUNET_abort ();          // added to ready in previous select loop!
+
+    tc.exceptional = (pos->exception_set == NULL) ? es : pos->exception_set;
+    if ((pos->exception_fd != -1) &&
+        (0 != (pos->reason & GNUNET_SCHEDULER_REASON_EXCEPTION)))
+      GNUNET_NETWORK_fdset_set_native (es, pos->exception_fd);
+    if (((tc.reason & GNUNET_SCHEDULER_REASON_EXCEPTION) != 0) &&
+        (pos->exception_fd != -1) &&
+        (!GNUNET_NETWORK_fdset_test_native (es, pos->exception_fd)))
+      GNUNET_abort ();          // added to ready in previous select loop!
+
+
     LOG (GNUNET_ERROR_TYPE_DEBUG,
 	 "Running task: %llu / %p\n", pos->id,
          pos->callback_cls);
@@ -713,6 +763,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
 {
   struct GNUNET_NETWORK_FDSet *rs;
   struct GNUNET_NETWORK_FDSet *ws;
+  struct GNUNET_NETWORK_FDSet *es;
   struct GNUNET_TIME_Relative timeout;
   int ret;
   struct GNUNET_SIGNAL_Context *shc_int;
@@ -734,6 +785,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   GNUNET_assert (active_task == NULL);
   rs = GNUNET_NETWORK_fdset_create ();
   ws = GNUNET_NETWORK_fdset_create ();
+  es = GNUNET_NETWORK_fdset_create ();
   GNUNET_assert (shutdown_pipe_handle == NULL);
   shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
   GNUNET_assert (shutdown_pipe_handle != NULL);
@@ -767,8 +819,9 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   {
     GNUNET_NETWORK_fdset_zero (rs);
     GNUNET_NETWORK_fdset_zero (ws);
+    GNUNET_NETWORK_fdset_zero (es);
     timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-    update_sets (rs, ws, &timeout);
+    update_sets (rs, ws, es, &timeout);
     GNUNET_NETWORK_fdset_handle_set (rs, pr);
     if (ready_count > 0)
     {
@@ -776,9 +829,9 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
       timeout = GNUNET_TIME_UNIT_ZERO;
     }
     if (NULL == scheduler_select)
-      ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, timeout);
+      ret = GNUNET_NETWORK_socket_select (rs, ws, es, timeout);
     else
-      ret = scheduler_select (scheduler_select_cls, rs, ws, NULL, timeout);
+      ret = scheduler_select (scheduler_select_cls, rs, ws, es, timeout);
     if (ret == GNUNET_SYSERR)
     {
       if (errno == EINTR)
@@ -804,8 +857,8 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
       LOG (GNUNET_ERROR_TYPE_WARNING, _("Looks like we're busy waiting...\n"));
       short_wait (100);                /* mitigate */
     }
-    check_ready (rs, ws);
-    run_ready (rs, ws);
+    check_ready (rs, ws, es);
+    run_ready (rs, ws, es);
     if (GNUNET_NETWORK_fdset_handle_isset (rs, pr))
     {
       /* consume the signal */
@@ -838,6 +891,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   shutdown_pipe_handle = NULL;
   GNUNET_NETWORK_fdset_destroy (rs);
   GNUNET_NETWORK_fdset_destroy (ws);
+  GNUNET_NETWORK_fdset_destroy (es);
 }
 
 
@@ -1014,6 +1068,7 @@ GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, voi
 #endif
   t->read_fd = -1;
   t->write_fd = -1;
+  t->exception_fd = -1;
   t->callback = task;
   t->callback_cls = task_cls;
   t->id = ++last_id;
@@ -1062,7 +1117,7 @@ GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
                                     GNUNET_SCHEDULER_Task task, void *task_cls)
 {
   return GNUNET_SCHEDULER_add_select (prio,
-                                      GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
+                                      GNUNET_TIME_UNIT_ZERO, NULL, NULL, NULL, task,
                                       task_cls);
 }
 
@@ -1105,6 +1160,7 @@ GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
 #endif
   t->read_fd = -1;
   t->write_fd = -1;
+  t->exception_fd = -1;
   t->id = ++last_id;
 #if PROFILE_DELAYS
   t->start_time = GNUNET_TIME_absolute_get ();
@@ -1222,7 +1278,7 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
 
   ret =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
+                                   GNUNET_TIME_UNIT_ZERO, NULL, NULL, NULL, task,
                                    task_cls);
   GNUNET_assert (pending->id == ret);
   pending->lifeness = lifeness;
@@ -1259,10 +1315,11 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
  */
 #ifndef MINGW
 static GNUNET_SCHEDULER_TaskIdentifier
-add_without_sets (struct GNUNET_TIME_Relative delay,
-		  enum GNUNET_SCHEDULER_Priority priority,
-		  int rfd, int wfd,
-                  GNUNET_SCHEDULER_Task task, void *task_cls)
+add_without_sets (
+    struct GNUNET_TIME_Relative delay,
+    enum GNUNET_SCHEDULER_Priority priority,
+    int rfd, int wfd, int efd,
+    GNUNET_SCHEDULER_Task task, void *task_cls)
 {
   struct Task *t;
 
@@ -1287,7 +1344,7 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
 
     if ((flags == -1) && (errno == EBADF))
     {
-      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", rfd);
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d! (rfd)\n", rfd);
 #if EXECINFO
       int i;
 
@@ -1303,7 +1360,23 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
 
     if (flags == -1 && errno == EBADF)
     {
-      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", wfd);
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d! (wfd)\n", wfd);
+#if EXECINFO
+      int i;
+
+      for (i = 0; i < t->num_backtrace_strings; i++)
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]);
+#endif
+      GNUNET_assert (0);
+    }
+  }
+  if (-1 != efd)
+  {
+    int flags = fcntl (efd, F_GETFD);
+
+    if (flags == -1 && errno == EBADF)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d (efd)!\n", efd);
 #if EXECINFO
       int i;
 
@@ -1315,8 +1388,9 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
   }
 #endif
   t->read_fd = rfd;
-  GNUNET_assert (wfd >= -1);
+  //GNUNET_assert (wfd >= -1); why is this here?
   t->write_fd = wfd;
+  t->exception_fd = efd;
   t->id = ++last_id;
 #if PROFILE_DELAYS
   t->start_time = GNUNET_TIME_absolute_get ();
@@ -1391,25 +1465,12 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
 					     struct GNUNET_NETWORK_Handle *rfd,
 					     GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if MINGW
-  struct GNUNET_NETWORK_FDSet *rs;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
-
   GNUNET_assert (rfd != NULL);
-  rs = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_set (rs, rfd);
-  ret =
-    GNUNET_SCHEDULER_add_select (priority,
-				 delay, rs, NULL,
-				 task, task_cls);
-  GNUNET_NETWORK_fdset_destroy (rs);
-  return ret;
-#else
-  return add_without_sets (delay,
-			   priority,
-			   GNUNET_NETWORK_get_fd (rfd), -1, task,
-                           task_cls);
-#endif
+  return GNUNET_SCHEDULER_add_net_with_priority (
+      delay,
+      priority,
+      rfd, NULL, NULL,
+      task, task_cls);
 }
 
 
@@ -1435,25 +1496,84 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
                                 struct GNUNET_NETWORK_Handle *wfd,
                                 GNUNET_SCHEDULER_Task task, void *task_cls)
 {
+  GNUNET_assert (wfd != NULL);
+  return GNUNET_SCHEDULER_add_net_with_priority (
+      delay,
+      GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+      NULL, wfd, NULL,
+      task, task_cls);
+}
+
+/**
+ * Schedule a new task to be run with a specified delay or when a
+ * specified file descriptor is ready for reading, writing, or has
+ * an exception. The delay can be used as a timeout on the sockets
+ * being ready.  The task will be scheduled for execution once
+ * either the delay has expired or the socket operation is ready.
+ *
+ * @param delay when should this operation time out? Use
+ *        #GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param priority priority of the task
+ * @param rfs read file-descriptor
+ * @param wfd write file-descriptor
+ * @param efd exception file-descriptor
+ * @param task main function of the task
+ * @param task_cls closure of @a task
+ * @return unique task identifier for the job
+ *         only valid until @a task is started!
+ */
+GNUNET_SCHEDULER_TaskIdentifier
+GNUNET_SCHEDULER_add_net_with_priority (
+    struct GNUNET_TIME_Relative delay,
+    enum GNUNET_SCHEDULER_Priority priority,
+    struct GNUNET_NETWORK_Handle *rfd,
+    struct GNUNET_NETWORK_Handle *wfd,
+    struct GNUNET_NETWORK_Handle *efd,
+    GNUNET_SCHEDULER_Task task, void *task_cls)
+{
 #if MINGW
-  struct GNUNET_NETWORK_FDSet *ws;
   GNUNET_SCHEDULER_TaskIdentifier ret;
 
-  GNUNET_assert (wfd != NULL);
-  ws = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_set (ws, wfd);
-  ret =
-    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-				 delay, NULL, ws,
-                                   task, task_cls);
+  struct GNUNET_NETWORK_FDSet *rs = NULL;
+  struct GNUNET_NETWORK_FDSet *ws = NULL;
+  struct GNUNET_NETWORK_FDSet *es = NULL;
+
+  if (rfd)
+  {
+    rs = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_set (rs, rfd);
+  };
+  if (wfd)
+  {
+    ws = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_set (ws, wfd);
+  };
+  if (efd)
+  {
+    es = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_set (es, efd);
+  };
+  ret = GNUNET_SCHEDULER_add_select (
+      priority,
+      delay,
+      rs,
+      ws,
+      es,
+      task,
+      task_cls);
+  GNUNET_NETWORK_fdset_destroy (rs);
   GNUNET_NETWORK_fdset_destroy (ws);
+  GNUNET_NETWORK_fdset_destroy (es);
   return ret;
 #else
-  GNUNET_assert (GNUNET_NETWORK_get_fd (wfd) >= 0);
-  return add_without_sets (delay,
-			   GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-			   -1, GNUNET_NETWORK_get_fd (wfd), task,
-                           task_cls);
+  return add_without_sets (
+      delay,
+      priority,
+      rfd ? GNUNET_NETWORK_get_fd (rfd) : -1,
+      wfd ? GNUNET_NETWORK_get_fd (wfd) : -1,
+      efd ? GNUNET_NETWORK_get_fd (efd) : -1,
+      task,
+      task_cls);
 #endif
 }
 
@@ -1478,28 +1598,14 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
                                 const struct GNUNET_DISK_FileHandle *rfd,
                                 GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if MINGW
-  struct GNUNET_NETWORK_FDSet *rs;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
-
-  GNUNET_assert (rfd != NULL);
-  rs = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_handle_set (rs, rfd);
-  ret =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   delay, rs, NULL,
-                                   task, task_cls);
-  GNUNET_NETWORK_fdset_destroy (rs);
-  return ret;
-#else
-  int fd;
-
-  GNUNET_DISK_internal_file_handle_ (rfd, &fd, sizeof (int));
-  return add_without_sets (delay,
-			   GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-			   fd, -1, task, task_cls);
-
-#endif
+  return GNUNET_SCHEDULER_add_file_with_priority (
+      delay,
+      GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+      rfd,
+      NULL,
+      NULL,
+      task,
+      task_cls);
 }
 
 
@@ -1523,31 +1629,100 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
                                  const struct GNUNET_DISK_FileHandle *wfd,
                                  GNUNET_SCHEDULER_Task task, void *task_cls)
 {
+  return GNUNET_SCHEDULER_add_file_with_priority (
+      delay,
+      GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+      NULL,
+      wfd,
+      NULL,
+      task,
+      task_cls);
+}
+
+/**
+ * Schedule a new task to be run with a specified delay or when a
+ * specified file descriptor is ready.  The delay can be
+ * used as a timeout on the socket being ready.  The task will be
+ * scheduled for execution once either the delay has expired or the
+ * socket operation is ready.
+ *
+ * @param delay when should this operation time out? Use
+ *        #GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param rfd read file-descriptor
+ * @param wfd write file-descriptor
+ * @param efd exception file-descriptor
+ * @param task main function of the task
+ * @param task_cls closure of @a task
+ * @return unique task identifier for the job
+ *         only valid until @a task is started!
+ */
+GNUNET_SCHEDULER_TaskIdentifier
+GNUNET_SCHEDULER_add_file_with_priority (
+    struct GNUNET_TIME_Relative delay,
+    enum GNUNET_SCHEDULER_Priority priority,
+    const struct GNUNET_DISK_FileHandle *rfd,
+    const struct GNUNET_DISK_FileHandle *wfd,
+    const struct GNUNET_DISK_FileHandle *efd,
+    GNUNET_SCHEDULER_Task task, void *task_cls)
+{
 #if MINGW
-  struct GNUNET_NETWORK_FDSet *ws;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
+  GNUNET_SCHEDULER_TaskIdentifier task;
+
+  struct GNUNET_NETWORK_FDSet *rs = NULL;
+  struct GNUNET_NETWORK_FDSet *ws = NULL;
+  struct GNUNET_NETWORK_FDSet *es = NULL;
+  
+  GNUNET_assert (rfd || wfd || efd);
+  if (rfd)
+  {
+    rs = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_handle (rs, rfd);
+  }
+  if (wfd)
+  {
+    ws = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_handle (ws, wfd);
+  }
+  if (efd)
+  {
+    es = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_handle (es, efd);
+  }
 
-  GNUNET_assert (wfd != NULL);
-  ws = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_handle_set (ws, wfd);
-  ret =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                                   delay, NULL, ws,
-                                   task, task_cls);
+  ret = GNUNET_SCHEDULER_add_select (
+      priority,
+      delay,
+      rs,
+      ws,
+      es,
+      task,
+      task_cls);
+  GNUNET_NETWORK_fdset_destroy (rs);
   GNUNET_NETWORK_fdset_destroy (ws);
+  GNUNET_NETWORK_fdset_destroy (es);
   return ret;
 #else
-  int fd;
-
-  GNUNET_DISK_internal_file_handle_ (wfd, &fd, sizeof (int));
-  GNUNET_assert (fd >= 0);
-  return add_without_sets (delay,
-			   GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-			   -1, fd, task, task_cls);
-
+  int r = -1;
+  int w = -1;
+  int e = -1;
+
+  if (rfd)
+    GNUNET_DISK_internal_file_handle_ (rfd, &r, sizeof (int));
+  if (wfd)
+    GNUNET_DISK_internal_file_handle_ (wfd, &w, sizeof (int));
+  if (efd)
+    GNUNET_DISK_internal_file_handle_ (efd, &e, sizeof (int));
+
+  return add_without_sets (
+      delay,
+      priority,
+      r,
+      w,
+      e,
+      task,
+      task_cls);
 #endif
-}
-
+};
 
 
 /**
@@ -1564,6 +1739,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
  * && (delay-ready
  *     || any-rs-ready
  *     || any-ws-ready
+ *     || any-es-ready
  *     || (shutdown-active && run-on-shutdown) )
  * </code>
  *
@@ -1572,6 +1748,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
  *        which means that the task will only be run after we receive SIGTERM
  * @param rs set of file descriptors we want to read (can be NULL)
  * @param ws set of file descriptors we want to write (can be NULL)
+ * @param es set of file descriptors we want to monitor for exceptions (can be NULL)
  * @param task main function of the task
  * @param task_cls closure of task
  * @return unique task identifier for the job
@@ -1582,6 +1759,7 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
                              struct GNUNET_TIME_Relative delay,
                              const struct GNUNET_NETWORK_FDSet *rs,
                              const struct GNUNET_NETWORK_FDSet *ws,
+                             const struct GNUNET_NETWORK_FDSet *es,
                              GNUNET_SCHEDULER_Task task, void *task_cls)
 {
   struct Task *t;
@@ -1602,6 +1780,7 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
 #endif
   t->read_fd = -1;
   t->write_fd = -1;
+  t->exception_fd = -1;
   if (rs != NULL)
   {
     t->read_set = GNUNET_NETWORK_fdset_create ();
@@ -1612,6 +1791,11 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
     t->write_set = GNUNET_NETWORK_fdset_create ();
     GNUNET_NETWORK_fdset_copy (t->write_set, ws);
   }
+  if (es != NULL)
+  {
+    t->exception_set = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_copy (t->exception_set, es);
+  }
   t->id = ++last_id;
 #if PROFILE_DELAYS
   t->start_time = GNUNET_TIME_absolute_get ();
diff --git a/src/util/server.c b/src/util/server.c
index 7c38292..c6ffe73 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -729,7 +729,7 @@ GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
     GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
   server->listen_task =
     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-				 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
+				 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, NULL,
 				 &process_listen_socket, server);
   GNUNET_NETWORK_fdset_destroy (r);
 }

Activities

Christian Grothoff

2013-11-25 22:47

manager   ~0007683

I don't see how this is useful, except for making things slower and more complicated. Are you sure you understand when the 'except' set is used?

Issue History

Date Modified Username Field Change
2013-11-25 08:17 Matthias Wachs New Issue
2013-11-25 08:17 Matthias Wachs File Added: gnunet_scheduler_fd_exceptions.diff
2013-11-25 22:47 Christian Grothoff Note Added: 0007683
2013-11-25 22:47 Christian Grothoff Assigned To => Christian Grothoff
2013-11-25 22:47 Christian Grothoff Status new => feedback
2013-11-26 23:27 Christian Grothoff Status feedback => closed
2013-11-26 23:27 Christian Grothoff Resolution open => won't fix