summaryrefslogtreecommitdiff
path: root/lib/common/WaitForEvent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common/WaitForEvent.cpp')
-rw-r--r--lib/common/WaitForEvent.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/lib/common/WaitForEvent.cpp b/lib/common/WaitForEvent.cpp
new file mode 100644
index 00000000..5646bfbf
--- /dev/null
+++ b/lib/common/WaitForEvent.cpp
@@ -0,0 +1,197 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: WaitForEvent.cpp
+// Purpose: Generic waiting for events, using an efficient method (platform dependent)
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include "WaitForEvent.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::WaitForEvent()
+// Purpose: Constructor
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+#ifdef HAVE_KQUEUE
+WaitForEvent::WaitForEvent(int Timeout)
+ : mKQueue(::kqueue()),
+ mpTimeout(0)
+{
+ if(mKQueue == -1)
+ {
+ THROW_EXCEPTION(CommonException, CouldNotCreateKQueue)
+ }
+
+ // Set the choosen timeout
+ SetTimeout(Timeout);
+}
+#else
+WaitForEvent::WaitForEvent(int Timeout)
+ : mTimeout(Timeout),
+ mpPollInfo(0)
+{
+}
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::~WaitForEvent()
+// Purpose: Destructor
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+WaitForEvent::~WaitForEvent()
+{
+#ifdef HAVE_KQUEUE
+ ::close(mKQueue);
+ mKQueue = -1;
+#else
+ if(mpPollInfo != 0)
+ {
+ ::free(mpPollInfo);
+ mpPollInfo = 0;
+ }
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::SetTimeout
+// Purpose: Sets the timeout for future wait calls
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+void WaitForEvent::SetTimeout(int Timeout)
+{
+#ifdef HAVE_KQUEUE
+ // Generate timeout
+ if(Timeout != TimeoutInfinite)
+ {
+ mTimeout.tv_sec = Timeout / 1000;
+ mTimeout.tv_nsec = (Timeout % 1000) * 1000000;
+ }
+
+ // Infinite or not?
+ mpTimeout = (Timeout != TimeoutInfinite)?(&mTimeout):(NULL);
+#else
+ mTimeout = Timeout;
+#endif
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::Wait(int)
+// Purpose: Wait for an event to take place. Returns a pointer to the object
+// which has been signalled, or returns 0 for the timeout condition.
+// Timeout specified in milliseconds.
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+void *WaitForEvent::Wait()
+{
+#ifdef HAVE_KQUEUE
+ // Event return structure
+ struct kevent e;
+ ::memset(&e, 0, sizeof(e));
+
+ switch(::kevent(mKQueue, NULL, 0, &e, 1, mpTimeout))
+ {
+ case 0:
+ // Timeout
+ return 0;
+ break;
+
+ case 1:
+ // Event happened!
+ return e.udata;
+ break;
+
+ default:
+ // Interrupted system calls aren't an error, just equivalent to a timeout
+ if(errno != EINTR)
+ {
+ THROW_EXCEPTION(CommonException, KEventErrorWait)
+ }
+ return 0;
+ break;
+ }
+#else
+ // Use poll() instead.
+ // Need to build the structures?
+ if(mpPollInfo == 0)
+ {
+ // Yes...
+ mpPollInfo = (struct pollfd *)::malloc((sizeof(struct pollfd) * mItems.size()) + 4);
+ if(mpPollInfo == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ // Build...
+ for(unsigned int l = 0; l < mItems.size(); ++l)
+ {
+ mpPollInfo[l].fd = mItems[l].fd;
+ mpPollInfo[l].events = mItems[l].events;
+ mpPollInfo[l].revents = 0;
+ }
+ }
+
+ // Make sure everything is reset (don't really have to do this, but don't trust the OS)
+ for(unsigned int l = 0; l < mItems.size(); ++l)
+ {
+ mpPollInfo[l].revents = 0;
+ }
+
+ // Poll!
+ switch(::poll(mpPollInfo, mItems.size(), mTimeout))
+ {
+ case -1:
+ // Interrupted system calls aren't an error, just equivalent to a timeout
+ if(errno != EINTR)
+ {
+ THROW_EXCEPTION(CommonException, KEventErrorWait)
+ }
+ return 0;
+ break;
+ case 0: // timed out
+ return 0;
+ break;
+ default: // got some thing...
+ // control flows on...
+ break;
+ }
+
+ // Find the item which was ready
+ for(unsigned int s = 0; s < mItems.size(); ++s)
+ {
+ if(mpPollInfo[s].revents & POLLIN)
+ {
+ return mItems[s].item;
+ break;
+ }
+ }
+#endif
+
+ return 0;
+}
+