From b6cf32b80991efb982069b9f6c65e06b05a9d102 Mon Sep 17 00:00:00 2001
From: Robert Ricci <ricci@cs.utah.edu>
Date: Fri, 28 Feb 2003 00:52:19 +0000
Subject: [PATCH] Add a blocking poll, event_poll_blocking(), to the event
 library.

Note the following: (from the API file)
  IMPORTANT: elvin uses timeouts internally. So, this function does
  NOT guarantee that when it returns, either an event has been
  recieved or your timeout has passed. This should not be much of
  a problem, but you have been warned!

The above is not really fixable, without hacking elvin. And it may
not be entirely fixable even then. In particular, the first call to
event_poll_blocking() will always return at once, since there are
leftover timers from connecting to elvind.
---
 event/API              | 23 +++++++++++++++++++
 event/example/tbrecv.c | 10 ++++++++
 event/lib/event.c      | 52 +++++++++++++++++++++++++++++++++++++++---
 event/lib/event.h      |  1 +
 4 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/event/API b/event/API
index 7c9a0a7550..7ee4ada719 100644
--- a/event/API
+++ b/event/API
@@ -232,3 +232,26 @@
   the event notification, and DATA is the arbitrary pointer passed to
   event_subscribe.  Returns a pointer to an event
   subscription structure if the operation is successful, 0 otherwise.
+
+* event_poll: Poll for new events
+
+      #include <event.h>
+
+      int event_poll(event_handle_t handle);
+
+  Polls for new events. Calls callbacks for all pending events. Does
+  not block - simply processes events that are currently queued.
+
+* event_poll_blocking: Poll for new events
+
+      #include <event.h>
+
+      int event_poll_blocking(event_handle_t handle, unsigned int timeout);
+
+  Same as event_poll, but blocks waiting for an event. Times out
+  after the given amount of time, or doesn't time out if 0 is given.
+
+  IMPORTANT: elvin uses timeouts internally. So, this function does
+  NOT guarantee that when it returns, either an event has been
+  recieved or your timeout has passed. This should not be much of
+  a problem, but you have been warned!
diff --git a/event/example/tbrecv.c b/event/example/tbrecv.c
index 2192ed9d3c..992016b7ad 100644
--- a/event/example/tbrecv.c
+++ b/event/example/tbrecv.c
@@ -131,6 +131,16 @@ main(int argc, char **argv)
 	 */
 	event_main(handle);
 
+	/*
+	 * Or, we can use a blocking poll like so:
+	 */
+	
+	/*
+	while (1) {
+		event_poll_blocking(handle,0);
+	}
+	*/
+
 	/*
 	 * Unregister with the event system:
 	 */
diff --git a/event/lib/event.c b/event/lib/event.c
index 736a5971dd..601bac5c90 100644
--- a/event/lib/event.c
+++ b/event/lib/event.c
@@ -204,31 +204,77 @@ event_unregister(event_handle_t handle)
 
 
 /*
- *
+ * An internal function to handle the two different event_poll calls, without
+ * making the library user mess around with arguments they don't care about.
  */
 
 int
-event_poll(event_handle_t handle)
+internal_event_poll(event_handle_t handle, int blocking, unsigned int timeout)
 {
 	extern int depth;
 	int rv;
+	elvin_timeout_t elvin_timeout = NULL;
 
 	if (!handle->mainloop) {
 		ERROR("multithreaded programs cannot use event_poll\n");
 		return 0;
 	}
 
+	/*
+	 * If the user wants a timeout, set up an elvin timeout now. We just
+	 * use a NULL callback, so that it simply causes a timeout, and doesn't
+	 * actually do anything.
+	 */
+	if (timeout) {
+		elvin_timeout = elvin_sync_add_timeout(NULL, timeout, NULL,
+				NULL, handle->status);
+		if (!elvin_timeout) {
+			ERROR("Elvin elvin_sync_add_timeout failed\n");
+			elvin_error_fprintf(stderr, handle->status);
+			return elvin_error_get_code(handle->status);
+		}
+	}
+
 	depth++;
-	rv = elvin_sync_default_select_and_dispatch(0, handle->status);
+	rv = elvin_sync_default_select_and_dispatch(blocking, handle->status);
 	depth--;
 	if (rv == 0) {
 		ERROR("Elvin select_and_dispatch failed\n");
 		elvin_error_fprintf(stderr, handle->status);
 	}
 
+	/*
+	 * Try to remove the timeout - if it didn't go off, we don't want to
+	 * hit it later. We don't check the return value, since, if it did go
+	 * off (and we don't really have a good way of knowing that), it's not
+	 * there any more, so it looks like an error.
+	 */
+	if (timeout && elvin_timeout) {
+		elvin_error_t error;
+		elvin_sync_remove_timeout(elvin_timeout, error);
+	}
+
 	return elvin_error_get_code(handle->status);
 }
 
+/*
+ * A non-blocking poll of the event system
+ */
+
+int
+event_poll(event_handle_t handle)
+{
+	return internal_event_poll(handle,0,0);
+}
+
+/*
+ * A blocking poll of the event system, with an optional timeout
+ */
+
+int event_poll_blocking(event_handle_t handle, unsigned int timeout)
+{
+	return internal_event_poll(handle,1,timeout);
+}
 
 /*
  * Enter the main loop of the event system, waiting to receive event
diff --git a/event/lib/event.h b/event/lib/event.h
index 13679e8bfc..f83b5767c6 100644
--- a/event/lib/event.h
+++ b/event/lib/event.h
@@ -142,6 +142,7 @@ typedef void (*event_notify_callback_t)(event_handle_t handle,
 event_handle_t event_register(char *name, int threaded);
 int event_unregister(event_handle_t handle);
 int event_poll(event_handle_t handle);
+int event_poll_blocking(event_handle_t handle, unsigned int timeout);
 int event_main(event_handle_t handle);
 int event_notify(event_handle_t handle, event_notification_t notification);
 int event_schedule(event_handle_t handle, event_notification_t notification,
-- 
GitLab