summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Jinghua <sunmoon1997@gmail.com>2009-10-31 20:33:48 +0800
committerLuo Jinghua <sunmoon1997@gmail.com>2009-10-31 20:33:48 +0800
commit897d49d92094eddb24702aaa4f8c3e1f760f7fc6 (patch)
tree5ba2fba9a566fd5a66ce8387c636f7100922e41a
parent74e3ae685ed561d328f89b3a33f53fc9df81d289 (diff)
milkway: fixed the win32 implementation
-rw-r--r--milkway/mw-poll-win32.c191
-rw-r--r--milkway/mw-poll.h4
2 files changed, 188 insertions, 7 deletions
diff --git a/milkway/mw-poll-win32.c b/milkway/mw-poll-win32.c
index 81d2ef2..ad88ba7 100644
--- a/milkway/mw-poll-win32.c
+++ b/milkway/mw-poll-win32.c
@@ -18,15 +18,18 @@
* Boston, MA 02111-1307, USA.
*/
#include "milkwayint.h"
-#include "mw-poll-sys-private.h"
+#include "mw-poll-win32-private.h"
#include <time.h>
#include <stdlib.h>
+#include <stdio.h>
#ifdef MW_OS_WINDOWS
#include <windows.h>
+#define WIN32_POLL_DEBUG (0)
+
static mw_poll_win32_t*
mw_poll_win32_init(mw_poll_win32_t *self)
{
@@ -42,24 +45,198 @@ mw_poll_win32_new(void)
mw_poll_win32_t *self = mw_object_alloc(MW_POLL_WIN32_TYPE);
if (!self)
return NULL;
- return (mw_poll_t*)mw_poll_win32_init(self, MW_POLL_WIN32_TYPE);
+ return (mw_poll_t*)mw_poll_win32_init(self);
+}
+
+static int
+poll_rest (mw_bool_t poll_msgs,
+ HANDLE *handles,
+ int nhandles,
+ mw_pollfd_t *fds,
+ mw_uint_t nfds,
+ int timeout)
+{
+ DWORD ready;
+ mw_pollfd_t *f;
+ int recursed_result;
+
+ if (poll_msgs) {
+ /* Wait for either messages or handles
+ * -> Use MsgWaitForMultipleObjectsEx
+ */
+ if (WIN32_POLL_DEBUG)
+ printf (" MsgWaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout);
+
+ ready = MsgWaitForMultipleObjectsEx (nhandles, handles, timeout,
+ QS_ALLINPUT, MWMO_ALERTABLE);
+
+ if (ready == WAIT_FAILED) {
+ fprintf (stderr, "MsgWaitForMultipleObjectsEx failed.\n");
+ }
+ } else if (nhandles == 0) {
+ /* No handles to wait for, just the timeout */
+ if (timeout == INFINITE) {
+ ready = WAIT_FAILED;
+ } else {
+ SleepEx (timeout, TRUE);
+ ready = WAIT_TIMEOUT;
+ }
+ } else {
+ /* Wait for just handles
+ * -> Use WaitForMultipleObjectsEx
+ */
+ if (WIN32_POLL_DEBUG)
+ printf (" WaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout);
+
+ ready = WaitForMultipleObjectsEx (nhandles, handles, FALSE, timeout, TRUE);
+ if (ready == WAIT_FAILED) {
+ fprintf (stderr, "WaitForMultipleObjectsEx failed.\n");
+ }
+ }
+
+ if (WIN32_POLL_DEBUG)
+ printf (" wait returns %ld%s\n",
+ ready,
+ (ready == WAIT_FAILED ? " (WAIT_FAILED)" :
+ (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" :
+ (poll_msgs && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : ""))));
+
+ if (ready == WAIT_FAILED) {
+ return -1;
+ } else if (ready == WAIT_TIMEOUT ||
+ ready == WAIT_IO_COMPLETION) {
+ return 0;
+ } else if (poll_msgs && ready == WAIT_OBJECT_0 + nhandles) {
+ for (f = fds; f < &fds[nfds]; ++f)
+ if (f->fd == MW_WIN32_MSG_HANDLE && f->events & MW_IO_IN)
+ f->revents |= MW_IO_IN;
+
+ /* If we have a timeout, or no handles to poll, be satisfied
+ * with just noticing we have messages waiting.
+ */
+ if (timeout != 0 || nhandles == 0)
+ return 1;
+
+ /* If no timeout and handles to poll, recurse to poll them,
+ * too.
+ */
+ recursed_result = poll_rest (FALSE, handles, nhandles, fds, nfds, 0);
+ return (recursed_result == -1) ? -1 : 1 + recursed_result;
+ } else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) {
+ for (f = fds; f < &fds[nfds]; ++f) {
+ if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) {
+ f->revents = f->events;
+ if (WIN32_POLL_DEBUG)
+ printf (" got event %p\n", (HANDLE) f->fd);
+ }
+ }
+
+ /* If no timeout and polling several handles, recurse to poll
+ * the rest of them.
+ */
+ if (timeout == 0 && nhandles > 1) {
+ /* Remove the handle that fired */
+ int i;
+ if (ready < nhandles - 1)
+ for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++)
+ handles[i-1] = handles[i];
+ nhandles--;
+ recursed_result = poll_rest (FALSE, handles, nhandles, fds, nfds, 0);
+ return (recursed_result == -1) ? -1 : 1 + recursed_result;
+ }
+ return 1;
+ }
+
+ return 0;
}
static int
mw_poll_win32_poll(mw_poll_t *super,
- mw_pollfd_t *fds;
- mw_uint_t nfds;
+ mw_pollfd_t *fds,
+ mw_uint_t nfds,
int timeout)
{
- mw_poll_win32_t *self = (mw_poll_win32_t*)super;
+ /* mw_poll_win32_t *self = (mw_poll_win32_t*)super; */
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ mw_bool_t poll_msgs = MW_FALSE;
+ mw_pollfd_t *f;
+ int nhandles = 0;
+ int retval;
+
+ if (WIN32_POLL_DEBUG)
+ printf ("MWPollWin32: waiting for");
+
+ for (f = fds; f < &fds[nfds]; ++f) {
+ if (f->fd == MW_WIN32_MSG_HANDLE && (f->events & MW_IO_IN)) {
+ if (WIN32_POLL_DEBUG && !poll_msgs)
+ printf (" MSG");
+ poll_msgs = MW_TRUE;
+ } else if (f->fd > 0) {
+ /* Don't add the same handle several times into the array, as
+ * docs say that is not allowed, even if it actually does seem
+ * to work.
+ */
+ int i;
+
+ for (i = 0; i < nhandles; i++)
+ if (handles[i] == (HANDLE) f->fd)
+ break;
+
+ if (i == nhandles) {
+ if (nhandles == MAXIMUM_WAIT_OBJECTS) {
+ fprintf (stderr, "Too many handles to wait for!\n");
+ break;
+ } else {
+ if (WIN32_POLL_DEBUG)
+ printf (" %p", (HANDLE) f->fd);
+ handles[nhandles++] = (HANDLE) f->fd;
+ }
+ }
+ }
+ }
+ if (WIN32_POLL_DEBUG)
+ printf ("\n");
+
+ for (f = fds; f < &fds[nfds]; ++f)
+ f->revents = 0;
+
+ if (timeout == -1)
+ timeout = INFINITE;
+
+ /* Polling for several things? */
+ if (nhandles > 1 || (nhandles > 0 && poll_msgs)) {
+ /* First check if one or several of them are immediately
+ * available
+ */
+ retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, 0);
+
+ /* If not, and we have a significant timeout, poll again with
+ * timeout then. Note that this will return indication for only
+ * one event, or only for messages. We ignore timeouts less than
+ * ten milliseconds as they are mostly pointless on Windows, the
+ * MsgWaitForMultipleObjectsEx() call will timeout right away
+ * anyway.
+ */
+ if (retval == 0 && (timeout == INFINITE || timeout >= 10))
+ retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout);
+ } else {
+ /* Just polling for one thing, so no need to check first if
+ * available immediately
+ */
+ retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout);
+ }
+
+ if (retval == -1)
+ for (f = fds; f < &fds[nfds]; ++f)
+ f->revents = 0;
- return 0;
+ return retval;
}
static void
mw_poll_win32_finalize(mw_object_t *super)
{
- MW_SUPER_FINALIZE(super, MW_POLL_WIN32_TYPE);
+ MW_SUPER_FINALIZE(super, MW_POLL_WIN32_TYPE)(super);
}
static void
diff --git a/milkway/mw-poll.h b/milkway/mw-poll.h
index 2365ed0..d38e345 100644
--- a/milkway/mw-poll.h
+++ b/milkway/mw-poll.h
@@ -56,6 +56,10 @@ typedef enum
MW_IO_NVAL = 1 << 5
} mw_poll_event_t;
+#ifdef MW_OS_WINDOWS
+#define MW_WIN32_MSG_HANDLE 20091031
+#endif
+
struct mw_pollfd {
mw_intptr_t fd;