]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
add support for timeouts to the event loop
authorRay Strode <rstrode@redhat.com>
Thu, 7 Jun 2007 18:51:27 +0000 (14:51 -0400)
committerRay Strode <rstrode@redhat.com>
Thu, 7 Jun 2007 18:51:27 +0000 (14:51 -0400)
src/libply/ply-event-loop.c
src/libply/ply-event-loop.h

index d8c85b1d1049071653982f0399c0e467792125c3..d805a9d4497e30cbf5b7b1ec7f1c70c0170ffc9b 100644 (file)
@@ -25,6 +25,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <math.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <stdbool.h>
 #define PLY_EVENT_LOOP_NUM_EVENT_HANDLERS 64
 #endif
 
+#ifndef PLY_EVENT_LOOP_NO_TIMED_WAKEUP
+#define PLY_EVENT_LOOP_NO_TIMED_WAKEUP 0.0
+#endif
+
 typedef struct
 {
   int fd;                                 
@@ -89,15 +94,24 @@ typedef struct
 {
   ply_event_loop_exit_handler_t  handler;
   void                          *user_data;
-} ply_event_loop_closure_t;
+} ply_event_loop_exit_closure_t;
+
+typedef struct
+{
+  double timeout;
+  ply_event_loop_timeout_handler_t  handler;
+  void                             *user_data;
+} ply_event_loop_timeout_watch_t;
 
 struct _ply_event_loop
 {
   int epoll_fd;                      
   int exit_code;                    
+  double wakeup_time;
 
   ply_list_t *sources;
-  ply_list_t *closures;
+  ply_list_t *exit_closures;
+  ply_list_t *timeout_watches;
 
   ply_signal_dispatcher_t *signal_dispatcher; 
 
@@ -448,6 +462,7 @@ ply_event_loop_new (void)
   loop = calloc (1, sizeof (ply_event_loop_t));
 
   loop->epoll_fd = epoll_create (PLY_EVENT_LOOP_NUM_EVENT_HANDLERS);
+  loop->wakeup_time = PLY_EVENT_LOOP_NO_TIMED_WAKEUP;
 
   assert (loop->epoll_fd >= 0);
 
@@ -455,7 +470,8 @@ ply_event_loop_new (void)
   loop->exit_code = 0;
 
   loop->sources = ply_list_new ();
-  loop->closures = ply_list_new ();
+  loop->exit_closures = ply_list_new ();
+  loop->timeout_watches = ply_list_new ();
 
   loop->signal_dispatcher = ply_signal_dispatcher_new ();
 
@@ -479,19 +495,19 @@ ply_event_loop_free_exit_closures (ply_event_loop_t *loop)
 {
   ply_list_node_t *node;
 
-  node = ply_list_get_first_node (loop->closures);
+  node = ply_list_get_first_node (loop->exit_closures);
   while (node != NULL)
     {
       ply_list_node_t *next_node;
-      ply_event_loop_closure_t *closure;
+      ply_event_loop_exit_closure_t *closure;
 
-      closure = (ply_event_loop_closure_t *) ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (loop->closures, node);
+      closure = (ply_event_loop_exit_closure_t *) ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (loop->exit_closures, node);
       free (closure);
 
       node = next_node;
     }
-  ply_list_free (loop->closures);
+  ply_list_free (loop->exit_closures);
 }
 
 static void
@@ -499,16 +515,16 @@ ply_event_loop_run_exit_closures (ply_event_loop_t *loop)
 {
   ply_list_node_t *node;
 
-  node = ply_list_get_first_node (loop->closures);
+  node = ply_list_get_first_node (loop->exit_closures);
   while (node != NULL)
     {
       ply_list_node_t *next_node;
-      ply_event_loop_closure_t *closure;
+      ply_event_loop_exit_closure_t *closure;
 
-      closure = (ply_event_loop_closure_t *) ply_list_node_get_data (node);
+      closure = (ply_event_loop_exit_closure_t *) ply_list_node_get_data (node);
 
       assert (closure->handler != NULL);
-      next_node = ply_list_get_next_node (loop->closures, node);
+      next_node = ply_list_get_next_node (loop->exit_closures, node);
 
       closure->handler (closure->user_data, loop->exit_code, loop);
 
@@ -523,10 +539,14 @@ ply_event_loop_free (ply_event_loop_t *loop)
     return;
 
   assert (ply_list_get_length (loop->sources) == 0);
+  assert (ply_list_get_length (loop->timeout_watches) == 0);
 
   ply_signal_dispatcher_free (loop->signal_dispatcher);
   ply_event_loop_free_exit_closures (loop);
 
+  ply_list_free (loop->sources);
+  ply_list_free (loop->timeout_watches);
+
   close (loop->epoll_fd);
   free (loop);
 }
@@ -608,6 +628,24 @@ ply_event_loop_remove_source (ply_event_loop_t   *loop,
   ply_event_loop_remove_source_node (loop, source_node);
 }
 
+void
+ply_event_loop_free_sources (ply_event_loop_t *loop)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (loop->sources);
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_event_source_t *source;
+
+      source = (ply_event_source_t *) ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (loop->sources, node);
+      ply_event_loop_remove_source_node (loop, node);
+      node = next_node;
+    }
+}
+
 static bool
 ply_event_loop_fd_status_is_valid (ply_event_loop_fd_status_t status)
 {
@@ -782,16 +820,41 @@ ply_event_loop_watch_for_exit (ply_event_loop_t              *loop,
                                ply_event_loop_exit_handler_t  exit_handler,
                                void                          *user_data)
 {
-  ply_event_loop_closure_t *closure;
+  ply_event_loop_exit_closure_t *closure;
 
   assert (loop != NULL);
   assert (exit_handler != NULL);
 
-  closure = calloc (1, sizeof (ply_event_loop_closure_t));
+  closure = calloc (1, sizeof (ply_event_loop_exit_closure_t));
   closure->handler = exit_handler;
   closure->user_data = user_data;
 
-  ply_list_append_data (loop->closures, closure);
+  ply_list_append_data (loop->exit_closures, closure);
+}
+
+void
+ply_event_loop_watch_for_timeout (ply_event_loop_t    *loop,
+                                  double               seconds,             
+                                  ply_event_loop_timeout_handler_t timeout_handler,
+                                  void                *user_data)
+{
+  ply_event_loop_timeout_watch_t *timeout_watch;
+
+  assert (loop != NULL);
+  assert (timeout_handler != NULL);
+  assert (seconds > 0.0);
+
+  timeout_watch = calloc (1, sizeof (ply_event_loop_timeout_watch_t));
+  timeout_watch->timeout = ply_get_timestamp () + seconds;
+  timeout_watch->handler = timeout_handler;
+  timeout_watch->user_data = user_data;
+
+  if (fabs (loop->wakeup_time - PLY_EVENT_LOOP_NO_TIMED_WAKEUP) <= 0)
+    loop->wakeup_time = timeout_watch->timeout;
+  else
+    loop->wakeup_time = MIN (loop->wakeup_time, timeout_watch->timeout);
+
+  ply_list_append_data (loop->timeout_watches, timeout_watch);
 }
 
 static ply_event_loop_fd_status_t 
@@ -920,6 +983,34 @@ ply_event_loop_free_watches_for_source (ply_event_loop_t   *loop,
     }
 }
 
+static void
+ply_event_loop_free_timeout_watches (ply_event_loop_t *loop)
+{
+  ply_list_node_t *node;
+  double now;
+
+  assert (loop != NULL);
+
+  now = ply_get_timestamp ();
+  node = ply_list_get_first_node (loop->timeout_watches);
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_event_loop_timeout_watch_t *watch;
+
+      watch = (ply_event_loop_timeout_watch_t *) ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (loop->timeout_watches, node);
+
+      free (watch);
+      ply_list_remove_node (loop->timeout_watches, node);
+
+      node = next_node;
+    }
+
+  assert (ply_list_get_length (loop->timeout_watches) == 0);
+  loop->wakeup_time = PLY_EVENT_LOOP_NO_TIMED_WAKEUP;
+}
+
 static void
 ply_event_loop_free_destinations_for_source (ply_event_loop_t   *loop,
                                              ply_event_source_t *source)
@@ -965,12 +1056,46 @@ ply_event_loop_disconnect_source (ply_event_loop_t           *loop,
   ply_event_source_free (source);
 }
 
+static void
+ply_event_loop_handle_timeouts (ply_event_loop_t *loop)
+{
+  ply_list_node_t *node;
+  double now;
+
+  assert (loop != NULL);
+
+  now = ply_get_timestamp ();
+  node = ply_list_get_first_node (loop->timeout_watches);
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_event_loop_timeout_watch_t *watch;
+
+      watch = (ply_event_loop_timeout_watch_t *) ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (loop->timeout_watches, node);
+
+      if (watch->timeout <= now)
+        {
+          assert (watch->handler != NULL);
+          watch->handler (watch->user_data, loop);
+          free (watch);
+          ply_list_remove_node (loop->timeout_watches, node);
+        }
+
+      node = next_node;
+    }
+
+  if (ply_list_get_length (loop->timeout_watches) == 0)
+    loop->wakeup_time = PLY_EVENT_LOOP_NO_TIMED_WAKEUP;
+}
+
 static void
 ply_event_loop_process_pending_events (ply_event_loop_t *loop)
 {
   int number_of_received_events, i;
   static struct epoll_event *events = NULL;
-  int saved_errno;
+
+  assert (loop != NULL);
 
   if (events == NULL)
     events = 
@@ -981,21 +1106,28 @@ ply_event_loop_process_pending_events (ply_event_loop_t *loop)
 
   do
    {
+     int timeout;
+
+     if (fabs (loop->wakeup_time - PLY_EVENT_LOOP_NO_TIMED_WAKEUP) <= 0)
+       timeout = -1;
+     else
+       timeout = (int) ((loop->wakeup_time - ply_get_timestamp ()) * 1000);
+
      number_of_received_events = epoll_wait (loop->epoll_fd, events,
-                                             sizeof (events), -1);
+                                             sizeof (events), timeout);
+
+     ply_event_loop_handle_timeouts (loop);
 
      if (number_of_received_events < 0)
        {
-         saved_errno = errno;
-
-         if (saved_errno != EINTR)
+         if (errno != EINTR)
            {
              ply_event_loop_exit (loop, 255);
              return;
            }
        }
     } 
-  while ((number_of_received_events < 0) && (saved_errno == EINTR));
+  while ((number_of_received_events < 0) && (errno == EINTR));
 
   for (i = 0; i < number_of_received_events; i++)
     {
@@ -1049,6 +1181,8 @@ ply_event_loop_run (ply_event_loop_t *loop)
     ply_event_loop_process_pending_events (loop);
 
   ply_event_loop_run_exit_closures (loop);
+  ply_event_loop_free_sources (loop);
+  ply_event_loop_free_timeout_watches (loop);
 
   loop->should_exit = false;
 
@@ -1096,6 +1230,12 @@ line_received_handler (void)
   printf ("%s", line);
 }
 
+static void
+on_timeout (ply_event_loop_t *loop)
+{
+  printf ("timeout elapsed\n");
+}
+
 int
 main (int    argc, 
       char **argv)
@@ -1117,6 +1257,9 @@ main (int    argc,
                             (ply_event_handler_t)
                             alrm_signal_handler, NULL);
 
+  ply_event_loop_watch_for_timeout (loop, 2.0, 
+                                    (ply_event_loop_timeout_handler_t)
+                                    on_timeout, loop);
   ply_event_loop_watch_fd (loop, 0, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
                           (ply_event_handler_t) line_received_handler,
                           (ply_event_handler_t) line_received_handler,
index 7a43d077663d08597038ab9d227eb2710f4efb46..46ce294a4bb94cc8f3fc49495b3df1ec12415fcd 100644 (file)
@@ -42,6 +42,8 @@ typedef void (* ply_event_handler_t) (void *user_data,
 typedef void (* ply_event_loop_exit_handler_t) (void *user_data,
                                                 int   exit_code,
                                                 ply_event_loop_t *loop);
+typedef void (* ply_event_loop_timeout_handler_t) (void             *user_data,
+                                                   ply_event_loop_t *loop);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_event_loop_t *ply_event_loop_new (void);
@@ -64,6 +66,10 @@ void ply_event_loop_stop_watching_signal (ply_event_loop_t *loop,
 void ply_event_loop_watch_for_exit (ply_event_loop_t              *loop,
                                     ply_event_loop_exit_handler_t  exit_handler,
                                     void                          *user_data);
+void ply_event_loop_watch_for_timeout (ply_event_loop_t    *loop,
+                                       double               seconds,             
+                                       ply_event_loop_timeout_handler_t timeout_handler,
+                                       void                 *user_data);
 
 int ply_event_loop_run (ply_event_loop_t *loop);
 void ply_event_loop_exit (ply_event_loop_t *loop,