*
* giowin32.c: IO Channels for Win32.
* Copyright 1998 Owen Taylor and Tor Lillqvist
+ * Copyright 1999-2000 Tor Lillqvist and Craig Setera
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
- * Modified by the GLib Team and others 1997-1999. See the AUTHORS
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
- * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
+/* Define this to get (very) verbose logging of all channels */
+/* #define G_IO_WIN32_DEBUG */
-#include "config.h"
#include "glib.h"
+
+#include <stdlib.h>
#include <windows.h>
-#include <winsock.h> /* Not everybody has winsock2 */
+#include <winsock.h> /* Not everybody has winsock2 */
#include <fcntl.h>
#include <io.h>
+#include <process.h>
#include <errno.h>
-#include <sys/types.h>
-
-#include <stdio.h>
+#include <sys/stat.h>
typedef struct _GIOWin32Channel GIOWin32Channel;
typedef struct _GIOWin32Watch GIOWin32Watch;
-guint g_pipe_readable_msg;
+#define BUFFER_SIZE 4096
typedef enum {
- G_IO_WINDOWS_MESSAGES, /* Windows messages */
- G_IO_FILE_DESC, /* Unix-like file descriptors from _open*/
- G_IO_PIPE, /* pipe, with windows messages for signalling */
- G_IO_STREAM_SOCKET /* Stream sockets */
+ G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */
+ G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from
+ * _open() or _pipe(). Read with read().
+ * Have to create separate thread to read.
+ */
+ G_IO_WIN32_SOCKET /* Sockets. A separate thread is blocked
+ * in select() most of the time.
+ */
} GIOWin32ChannelType;
struct _GIOWin32Channel {
* as provided by WinSock.
*/
GIOWin32ChannelType type;
+
+ gboolean debug;
- /* This is used by G_IO_WINDOWS_MESSAGES channels */
- HWND hwnd; /* handle of window, or NULL */
+ CRITICAL_SECTION mutex;
- /* This is used by G_IO_PIPE channels */
- guint peer; /* thread id of reader */
- guint peer_fd; /* fd in the reader */
- guint offset; /* counter of accumulated bytes */
- guint need_wakeups; /* in output channels whether the
- * reader needs wakeups
+ /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
+ HWND hwnd; /* handle of window, or NULL */
+
+ /* Following fields are used by both fd and socket channels. */
+ gboolean running; /* Is reader thread running. FALSE if
+ * EOF has been reached.
+ */
+ gboolean needs_close; /* If the channel has been closed while
+ * the reader thread was still running.
*/
+ guint thread_id; /* If non-NULL has a reader thread, or has
+ * had.*/
+ HANDLE thread_handle;
+ HANDLE data_avail_event;
+
+ gushort revents;
+
+ /* Following fields used by fd channels for input */
+
+ /* Data is kept in a circular buffer. To be able to distinguish between
+ * empty and full buffer, we cannot fill it completely, but have to
+ * leave a one character gap.
+ *
+ * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
+ *
+ * Empty: wrp == rdp
+ * Full: (wrp + 1) % BUFFER_SIZE == rdp
+ * Partial: otherwise
+ */
+ guchar *buffer; /* (Circular) buffer */
+ gint wrp, rdp; /* Buffer indices for writing and reading */
+ HANDLE space_avail_event;
+
+ /* Following fields used by socket channels */
+ GSList *watches;
+ HANDLE data_avail_noticed_event;
};
+#define LOCK(mutex) EnterCriticalSection (&mutex)
+#define UNLOCK(mutex) LeaveCriticalSection (&mutex)
+
struct _GIOWin32Watch {
+ GSource source;
GPollFD pollfd;
GIOChannel *channel;
GIOCondition condition;
GIOFunc callback;
};
-static gboolean g_io_win32_msg_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout);
-static gboolean g_io_win32_msg_check (gpointer source_data,
- GTimeVal *current_time);
-static gboolean g_io_win32_msg_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data);
-
-static gboolean g_io_win32_fd_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout);
-static gboolean g_io_win32_fd_check (gpointer source_data,
- GTimeVal *current_time);
-static gboolean g_io_win32_fd_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data);
-
-static gboolean g_io_win32_pipe_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout);
-static gboolean g_io_win32_pipe_check (gpointer source_data,
- GTimeVal *current_time);
-static gboolean g_io_win32_pipe_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data);
-static void g_io_win32_pipe_destroy (gpointer source_data);
-
-static gboolean g_io_win32_sock_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout);
-static gboolean g_io_win32_sock_check (gpointer source_data,
- GTimeVal *current_time);
-static gboolean g_io_win32_sock_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data);
-
-static void g_io_win32_destroy (gpointer source_data);
-
-static GIOError g_io_win32_msg_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-
-static GIOError g_io_win32_msg_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static GIOError g_io_win32_msg_seek (GIOChannel *channel,
- gint offset,
- GSeekType type);
-static void g_io_win32_msg_close (GIOChannel *channel);
-static guint g_io_win32_msg_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify);
-
-static GIOError g_io_win32_fd_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static GIOError g_io_win32_fd_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static GIOError g_io_win32_fd_seek (GIOChannel *channel,
- gint offset,
- GSeekType type);
-static void g_io_win32_fd_close (GIOChannel *channel);
-
-static void g_io_win32_free (GIOChannel *channel);
-
-static guint g_io_win32_fd_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify);
-
-static GIOError g_io_win32_no_seek (GIOChannel *channel,
- gint offset,
- GSeekType type);
-
-static GIOError g_io_win32_pipe_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static GIOError g_io_win32_pipe_write (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static void g_io_win32_pipe_close (GIOChannel *channel);
-static guint g_io_win32_pipe_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify);
-static void g_io_win32_pipe_free (GIOChannel *channel);
-
-static GIOError g_io_win32_sock_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static GIOError g_io_win32_sock_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written);
-static void g_io_win32_sock_close (GIOChannel *channel);
-static guint g_io_win32_sock_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify);
-
-GSourceFuncs win32_watch_msg_funcs = {
- g_io_win32_msg_prepare,
- g_io_win32_msg_check,
- g_io_win32_msg_dispatch,
- g_io_win32_destroy
-};
+static void
+g_io_channel_win32_init (GIOWin32Channel *channel)
+{
+#ifdef G_IO_WIN32_DEBUG
+ channel->debug = TRUE;
+#else
+ if (getenv ("G_IO_WIN32_DEBUG") != NULL)
+ channel->debug = TRUE;
+ else
+ channel->debug = FALSE;
+#endif
+ channel->buffer = NULL;
+ channel->running = FALSE;
+ channel->needs_close = FALSE;
+ channel->thread_id = 0;
+ channel->data_avail_event = NULL;
+ channel->revents = 0;
+ channel->space_avail_event = NULL;
+ channel->data_avail_noticed_event = NULL;
+ channel->watches = NULL;
+ InitializeCriticalSection (&channel->mutex);
+}
-GSourceFuncs win32_watch_fd_funcs = {
- g_io_win32_fd_prepare,
- g_io_win32_fd_check,
- g_io_win32_fd_dispatch,
- g_io_win32_destroy
-};
+static void
+create_events (GIOWin32Channel *channel)
+{
+ SECURITY_ATTRIBUTES sec_attrs;
+
+ sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sec_attrs.lpSecurityDescriptor = NULL;
+ sec_attrs.bInheritHandle = FALSE;
+
+ /* The data available event is manual reset, the space available event
+ * is automatic reset.
+ */
+ if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
+ || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
+ || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
+ {
+ gchar *msg = g_win32_error_message (GetLastError ());
+ g_error ("Error creating event: %s", msg);
+ }
+}
-GSourceFuncs win32_watch_pipe_funcs = {
- g_io_win32_pipe_prepare,
- g_io_win32_pipe_check,
- g_io_win32_pipe_dispatch,
- g_io_win32_pipe_destroy
-};
+static unsigned __stdcall
+read_thread (void *parameter)
+{
+ GIOWin32Channel *channel = parameter;
+ GSList *tmp;
+ guchar *buffer;
+ guint nbytes;
+
+ g_io_channel_ref ((GIOChannel *)channel);
+
+ if (channel->debug)
+ g_print ("read_thread %#x: start fd:%d, data_avail:%#x, space_avail:%#x\n",
+ channel->thread_id,
+ channel->fd,
+ (guint) channel->data_avail_event,
+ (guint) channel->space_avail_event);
+
+ channel->buffer = g_malloc (BUFFER_SIZE);
+ channel->rdp = channel->wrp = 0;
+ channel->running = TRUE;
-GSourceFuncs win32_watch_sock_funcs = {
- g_io_win32_sock_prepare,
- g_io_win32_sock_check,
- g_io_win32_sock_dispatch,
- g_io_win32_destroy
-};
+ SetEvent (channel->space_avail_event);
+
+ while (channel->running)
+ {
+ LOCK (channel->mutex);
+ if (channel->debug)
+ g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
+ channel->thread_id, channel->rdp, channel->wrp);
+ if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
+ {
+ /* Buffer is full */
+ if (channel->debug)
+ g_print ("read_thread %#x: resetting space_avail\n",
+ channel->thread_id);
+ ResetEvent (channel->space_avail_event);
+ if (channel->debug)
+ g_print ("read_thread %#x: waiting for space\n",
+ channel->thread_id);
+ UNLOCK (channel->mutex);
+ WaitForSingleObject (channel->space_avail_event, INFINITE);
+ LOCK (channel->mutex);
+ if (channel->debug)
+ g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
+ channel->thread_id, channel->rdp, channel->wrp);
+ }
+
+ buffer = channel->buffer + channel->wrp;
+
+ /* Always leave at least one byte unused gap to be able to
+ * distinguish between the full and empty condition...
+ */
+ nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
+ BUFFER_SIZE - channel->wrp);
-GIOFuncs win32_channel_msg_funcs = {
- g_io_win32_msg_read,
- g_io_win32_msg_write,
- g_io_win32_no_seek,
- g_io_win32_msg_close,
- g_io_win32_msg_add_watch,
- g_io_win32_free
-};
+ if (channel->debug)
+ g_print ("read_thread %#x: calling read() for %d bytes\n",
+ channel->thread_id, nbytes);
-GIOFuncs win32_channel_fd_funcs = {
- g_io_win32_fd_read,
- g_io_win32_fd_write,
- g_io_win32_fd_seek,
- g_io_win32_fd_close,
- g_io_win32_fd_add_watch,
- g_io_win32_free
-};
+ UNLOCK (channel->mutex);
-GIOFuncs win32_channel_pipe_funcs = {
- g_io_win32_pipe_read,
- g_io_win32_pipe_write,
- g_io_win32_no_seek,
- g_io_win32_pipe_close,
- g_io_win32_pipe_add_watch,
- g_io_win32_pipe_free
-};
+ nbytes = read (channel->fd, buffer, nbytes);
+
+ LOCK (channel->mutex);
-GIOFuncs win32_channel_sock_funcs = {
- g_io_win32_sock_read,
- g_io_win32_sock_write,
- g_io_win32_no_seek,
- g_io_win32_sock_close,
- g_io_win32_sock_add_watch,
- g_io_win32_free
-};
+ channel->revents = G_IO_IN;
+ if (nbytes == 0)
+ channel->revents |= G_IO_HUP;
+ else if (nbytes < 0)
+ channel->revents |= G_IO_ERR;
-#define N_WATCHED_PIPES 4
+ if (channel->debug)
+ g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
+ channel->thread_id, nbytes, channel->rdp, channel->wrp);
-static struct {
- gint fd;
- GIOWin32Watch *watch;
- GIOWin32Channel *channel;
- gpointer user_data;
-} watched_pipes[N_WATCHED_PIPES];
+ if (nbytes <= 0)
+ break;
-static gint n_watched_pipes = 0;
+ channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
+ if (channel->debug)
+ g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
+ channel->thread_id, channel->rdp, channel->wrp);
+ SetEvent (channel->data_avail_event);
+ UNLOCK (channel->mutex);
+ }
+
+ channel->running = FALSE;
+ if (channel->needs_close)
+ {
+ if (channel->debug)
+ g_print ("read_thread %#x: channel fd %d needs closing\n",
+ channel->thread_id, channel->fd);
+ close (channel->fd);
+ channel->fd = -1;
+ }
-static gboolean
-g_io_win32_msg_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout)
-{
- GIOWin32Watch *data = source_data;
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) data->channel;
- MSG msg;
+ if (channel->debug)
+ g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
+ channel->thread_id, channel->rdp, channel->wrp);
+ SetEvent (channel->data_avail_event);
+ UNLOCK (channel->mutex);
+
+ g_io_channel_unref((GIOChannel *)channel);
+
+ /* No need to call _endthreadex(), the actual thread starter routine
+ * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
+ * _endthreadex() for us.
+ */
- *timeout = -1;
+ CloseHandle (channel->thread_handle);
- return PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_NOREMOVE) == TRUE;
+ return 0;
}
-static gboolean
-g_io_win32_msg_check (gpointer source_data,
- GTimeVal *current_time)
+static void
+create_thread (GIOWin32Channel *channel,
+ GIOCondition condition,
+ unsigned (__stdcall *thread) (void *parameter))
{
- GIOWin32Watch *data = source_data;
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) data->channel;
- MSG msg;
-
- return PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_NOREMOVE) == TRUE;
+ channel->thread_handle =
+ (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
+ &channel->thread_id);
+ if (channel->thread_handle == 0)
+ g_warning (G_STRLOC ": Error creating reader thread: %s",
+ strerror (errno));
+ WaitForSingleObject (channel->space_avail_event, INFINITE);
}
-static gboolean
-g_io_win32_msg_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data)
-
+static int
+buffer_read (GIOWin32Channel *channel,
+ guchar *dest,
+ guint count,
+ GIOError *error)
{
- GIOWin32Watch *data = source_data;
-
- return (*data->callback)(data->channel,
- data->pollfd.revents & data->condition,
- user_data);
+ guint nbytes;
+ guint left = count;
+
+ LOCK (channel->mutex);
+ if (channel->debug)
+ g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
+ channel->thread_id, count, channel->rdp, channel->wrp);
+
+ if (channel->wrp == channel->rdp)
+ {
+ UNLOCK (channel->mutex);
+ if (channel->debug)
+ g_print ("waiting for data from thread %#x\n", channel->thread_id);
+ WaitForSingleObject (channel->data_avail_event, INFINITE);
+ if (channel->debug)
+ g_print ("done waiting for data from thread %#x\n", channel->thread_id);
+ LOCK (channel->mutex);
+ if (channel->wrp == channel->rdp && !channel->running)
+ {
+ UNLOCK (channel->mutex);
+ return 0;
+ }
+ }
+
+ if (channel->rdp < channel->wrp)
+ nbytes = channel->wrp - channel->rdp;
+ else
+ nbytes = BUFFER_SIZE - channel->rdp;
+ UNLOCK (channel->mutex);
+ nbytes = MIN (left, nbytes);
+ if (channel->debug)
+ g_print ("moving %d bytes from thread %#x\n",
+ nbytes, channel->thread_id);
+ memcpy (dest, channel->buffer + channel->rdp, nbytes);
+ dest += nbytes;
+ left -= nbytes;
+ LOCK (channel->mutex);
+ channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
+ if (channel->debug)
+ g_print ("setting space_avail for thread %#x\n", channel->thread_id);
+ SetEvent (channel->space_avail_event);
+ if (channel->debug)
+ g_print ("for thread %#x: rdp=%d, wrp=%d\n",
+ channel->thread_id, channel->rdp, channel->wrp);
+ if (channel->running && channel->wrp == channel->rdp)
+ {
+ if (channel->debug)
+ g_print ("resetting data_avail of thread %#x\n",
+ channel->thread_id);
+ ResetEvent (channel->data_avail_event);
+ };
+ UNLOCK (channel->mutex);
+
+ /* We have no way to indicate any errors form the actual
+ * read() or recv() call in the reader thread. Should we have?
+ */
+ *error = G_IO_ERROR_NONE;
+ return count - left;
}
-static void
-g_io_win32_destroy (gpointer source_data)
+static unsigned __stdcall
+select_thread (void *parameter)
{
- GIOWin32Watch *data = source_data;
+ GIOWin32Channel *channel = parameter;
+ fd_set read_fds, write_fds, except_fds;
+ GSList *tmp;
+ int n;
+
+ g_io_channel_ref ((GIOChannel *)channel);
+
+ if (channel->debug)
+ g_print ("select_thread %#x: start fd:%d,\n\tdata_avail:%#x, data_avail_noticed:%#x\n",
+ channel->thread_id,
+ channel->fd,
+ (guint) channel->data_avail_event,
+ (guint) channel->data_avail_noticed_event);
+
+ channel->rdp = channel->wrp = 0;
+ channel->running = TRUE;
+
+ SetEvent (channel->space_avail_event);
+
+ while (channel->running)
+ {
+ FD_ZERO (&read_fds);
+ FD_ZERO (&write_fds);
+ FD_ZERO (&except_fds);
+
+ tmp = channel->watches;
+ while (tmp)
+ {
+ GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
+
+ if (watch->condition & (G_IO_IN | G_IO_HUP))
+ FD_SET (channel->fd, &read_fds);
+ if (watch->condition & G_IO_OUT)
+ FD_SET (channel->fd, &write_fds);
+ if (watch->condition & G_IO_ERR)
+ FD_SET (channel->fd, &except_fds);
+
+ tmp = tmp->next;
+ }
+ if (channel->debug)
+ g_print ("select_thread %#x: calling select() for%s%s%s\n",
+ channel->thread_id,
+ (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
+ (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
+ (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
+
+ n = select (1, &read_fds, &write_fds, &except_fds, NULL);
+
+ if (n == SOCKET_ERROR)
+ {
+ if (channel->debug)
+ g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
+ channel->thread_id);
+ break;
+ }
+
+ if (channel->debug)
+ g_print ("select_thread %#x: got%s%s%s\n",
+ channel->thread_id,
+ (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
+ (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
+ (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
+
+ if (FD_ISSET (channel->fd, &read_fds))
+ channel->revents |= G_IO_IN;
+ if (FD_ISSET (channel->fd, &write_fds))
+ channel->revents |= G_IO_OUT;
+ if (FD_ISSET (channel->fd, &except_fds))
+ channel->revents |= G_IO_ERR;
+
+ if (channel->debug)
+ g_print ("select_thread %#x: resetting data_avail_noticed,\n"
+ "\tsetting data_avail\n",
+ channel->thread_id);
+ ResetEvent (channel->data_avail_noticed_event);
+ SetEvent (channel->data_avail_event);
+
+ if (channel->debug)
+ g_print ("select_thread %#x: waiting for data_avail_noticed\n",
+ channel->thread_id);
+
+ WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
+ if (channel->debug)
+ g_print ("select_thread %#x: got data_avail_noticed\n",
+ channel->thread_id);
+ }
+
+ channel->running = FALSE;
+ LOCK (channel->mutex);
+ if (channel->needs_close)
+ {
+ if (channel->debug)
+ g_print ("select_thread %#x: channel fd %d needs closing\n",
+ channel->thread_id, channel->fd);
+ closesocket (channel->fd);
+ channel->fd = -1;
+ }
+
+ if (channel->debug)
+ g_print ("select_thread %#x: got error, setting data_avail\n",
+ channel->thread_id);
+ SetEvent (channel->data_avail_event);
+ UNLOCK (channel->mutex);
+
+ g_io_channel_unref((GIOChannel *)channel);
+
+ /* No need to call _endthreadex(), the actual thread starter routine
+ * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
+ * _endthreadex() for us.
+ */
- g_main_remove_poll (&data->pollfd);
- g_io_channel_unref (data->channel);
- g_free (data);
+ CloseHandle (channel->thread_handle);
+
+ return 0;
}
static gboolean
-g_io_win32_fd_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout)
+g_io_win32_prepare (GSource *source,
+ gint *timeout)
{
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+
*timeout = -1;
+
+ if (channel->type == G_IO_WIN32_FILE_DESC)
+ {
+ LOCK (channel->mutex);
+ if (channel->running && channel->wrp == channel->rdp)
+ channel->revents = 0;
+ UNLOCK (channel->mutex);
+ }
+ else if (channel->type == G_IO_WIN32_SOCKET)
+ {
+ channel->revents = 0;
+
+ if (channel->debug)
+ g_print ("g_io_win32_prepare: thread %#x, setting data_avail_noticed\n",
+ channel->thread_id);
+ SetEvent (channel->data_avail_noticed_event);
+ if (channel->debug)
+ g_print ("g_io_win32_prepare: thread %#x, there.\n",
+ channel->thread_id);
+ }
return FALSE;
}
-static gboolean
-g_io_win32_fd_check (gpointer source_data,
- GTimeVal *current_time)
+static gboolean
+g_io_win32_check (GSource *source)
{
- GIOWin32Watch *data = source_data;
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+
+ if (channel->debug)
+ g_print ("g_io_win32_check: for thread %#x:\n"
+ "\twatch->pollfd.events:%#x, watch->pollfd.revents:%#x, channel->revents:%#x\n",
+ channel->thread_id,
+ watch->pollfd.events, watch->pollfd.revents, channel->revents);
- return (data->pollfd.revents & data->condition);
+ if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
+ watch->pollfd.revents = (watch->pollfd.events & channel->revents);
+
+ if (channel->type == G_IO_WIN32_SOCKET)
+ {
+ if (channel->debug)
+ g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
+ channel->thread_id);
+ ResetEvent (channel->data_avail_event);
+ if (channel->debug)
+ g_print ("g_io_win32_check: thread %#x, there.\n",
+ channel->thread_id);
+ }
+
+ return (watch->pollfd.revents & watch->condition);
}
static gboolean
-g_io_win32_fd_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data)
+g_io_win32_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GIOFunc func = (GIOFunc)callback;
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+
+ if (!func)
+ {
+ g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
+ "You must call g_source_connect().");
+ return FALSE;
+ }
+
+ return (*func) (watch->channel,
+ watch->pollfd.revents & watch->condition,
+ user_data);
+}
+static void
+g_io_win32_destroy (GSource *source)
{
- GIOWin32Watch *data = source_data;
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+
+ if (channel->debug)
+ g_print ("g_io_win32_destroy: channel with thread %#x\n",
+ channel->thread_id);
- return (*data->callback)(data->channel,
- data->pollfd.revents & data->condition,
- user_data);
+ channel->watches = g_slist_remove (channel->watches, watch);
+
+ g_io_channel_unref (watch->channel);
}
-static GIOError
-g_io_win32_msg_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_read)
+static GSourceFuncs win32_watch_funcs = {
+ g_io_win32_prepare,
+ g_io_win32_check,
+ g_io_win32_dispatch,
+ g_io_win32_destroy
+};
+
+static GSource *
+g_io_win32_create_watch (GIOChannel *channel,
+ GIOCondition condition,
+ unsigned (__stdcall *thread) (void *parameter))
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- MSG msg; /* In case of alignment problems */
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
+ GIOWin32Watch *watch;
+ GSource *source;
+
+ source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
+ watch = (GIOWin32Watch *)source;
+
+ watch->channel = channel;
+ g_io_channel_ref (channel);
+
+ watch->condition = condition;
+
+ if (win32_channel->data_avail_event == NULL)
+ create_events (win32_channel);
+
+ watch->pollfd.fd = (gint) win32_channel->data_avail_event;
+ watch->pollfd.events = condition;
+
+ if (win32_channel->debug)
+ g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
+ win32_channel->fd, condition, watch->pollfd.fd);
+
+ win32_channel->watches = g_slist_append (win32_channel->watches, watch);
+
+ if (win32_channel->thread_id == 0)
+ create_thread (win32_channel, condition, thread);
+ g_source_add_poll (source, &watch->pollfd);
+
+ return source;
+}
+
+static GIOError
+g_io_win32_msg_read (GIOChannel *channel,
+ gchar *buf,
+ guint count,
+ guint *bytes_read)
+{
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
+ MSG msg; /* In case of alignment problems */
+
if (count < sizeof (MSG))
return G_IO_ERROR_INVAL;
+ if (win32_channel->debug)
+ g_print ("g_io_win32_msg_read: for %#x\n",
+ win32_channel->hwnd);
if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
return G_IO_ERROR_AGAIN;
-
+
memmove (buf, &msg, sizeof (MSG));
*bytes_read = sizeof (MSG);
return G_IO_ERROR_NONE;
}
-
-static GIOError
-g_io_win32_msg_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written)
+
+static GIOError
+g_io_win32_msg_write (GIOChannel *channel,
+ gchar *buf,
+ guint count,
+ guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
MSG msg;
- gint result;
-
+
if (count != sizeof (MSG))
return G_IO_ERROR_INVAL;
-
+
/* In case of alignment problems */
memmove (&msg, buf, sizeof (MSG));
if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
return G_IO_ERROR_UNKNOWN;
-
+
*bytes_written = sizeof (MSG);
- return G_IO_ERROR_NONE;
+ return G_IO_ERROR_NONE;
}
-static GIOError
+static GIOError
g_io_win32_no_seek (GIOChannel *channel,
- gint offset,
- GSeekType type)
+ gint offset,
+ GSeekType type)
{
- g_warning ("g_io_win32_no_seek: unseekable IO channel type");
return G_IO_ERROR_UNKNOWN;
}
-
-static void
+static void
g_io_win32_msg_close (GIOChannel *channel)
{
/* Nothing to be done. Or should we set hwnd to some invalid value? */
}
-static void
+static void
g_io_win32_free (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
-
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
+
+ if (win32_channel->debug)
+ g_print ("thread %#x: freeing channel, fd: %d\n",
+ win32_channel->thread_id,
+ win32_channel->fd);
+
+ if (win32_channel->data_avail_event)
+ CloseHandle (win32_channel->data_avail_event);
+ if (win32_channel->space_avail_event)
+ CloseHandle (win32_channel->space_avail_event);
+ if (win32_channel->data_avail_noticed_event)
+ CloseHandle (win32_channel->data_avail_noticed_event);
+ DeleteCriticalSection (&win32_channel->mutex);
+
+ g_free (win32_channel->buffer);
+ g_slist_free (win32_channel->watches);
g_free (win32_channel);
}
-static guint
-g_io_win32_msg_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify)
+static GSource *
+g_io_win32_msg_create_watch (GIOChannel *channel,
+ GIOCondition condition)
{
- GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Watch *watch;
+ GSource *source;
+
+ source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
+ watch = (GIOWin32Watch *)source;
watch->channel = channel;
g_io_channel_ref (channel);
-
- watch->callback = func;
+
watch->condition = condition;
-
+
watch->pollfd.fd = G_WIN32_MSG_HANDLE;
watch->pollfd.events = condition;
-
- g_main_add_poll (&watch->pollfd, priority);
-
- return g_source_add (priority, TRUE, &win32_watch_msg_funcs,
- watch, user_data, notify);
-}
-
-static gboolean
-g_io_win32_pipe_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout)
-{
- *timeout = -1;
-
- return FALSE;
-}
-
-static gboolean
-g_io_win32_pipe_check (gpointer source_data,
- GTimeVal *current_time)
-{
- GIOWin32Watch *data = source_data;
- return FALSE;
-}
-
-static gboolean
-g_io_win32_pipe_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data)
-
-{
- GIOWin32Watch *data = source_data;
-
- return (*data->callback)(data->channel,
- data->pollfd.revents & data->condition,
- user_data);
-}
-
-static void
-g_io_win32_pipe_destroy (gpointer source_data)
-{
- GIOWin32Watch *data = source_data;
-
- g_io_channel_unref (data->channel);
- g_free (data);
-}
-
-static gboolean
-g_io_win32_sock_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout)
-{
- *timeout = -1;
-
- return FALSE;
-}
-
-static gboolean
-g_io_win32_sock_check (gpointer source_data,
- GTimeVal *current_time)
-{
- GIOWin32Watch *data = source_data;
-
- return (data->pollfd.revents & data->condition);
-}
-
-static gboolean
-g_io_win32_sock_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data)
-
-{
- GIOWin32Watch *data = source_data;
-
- return (*data->callback)(data->channel,
- data->pollfd.revents & data->condition,
- user_data);
+
+ g_source_add_poll (source, &watch->pollfd);
+
+ return source;
}
static GIOError
-g_io_win32_fd_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_read)
+g_io_win32_fd_read (GIOChannel *channel,
+ gchar *buf,
+ guint count,
+ guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
+ GIOError error;
+
+ if (win32_channel->debug)
+ g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
+ win32_channel->fd, count);
+
+ if (win32_channel->thread_id)
+ {
+ result = buffer_read (win32_channel, buf, count, &error);
+ if (result < 0)
+ {
+ *bytes_read = 0;
+ return error;
+ }
+ else
+ {
+ *bytes_read = result;
+ return G_IO_ERROR_NONE;
+ }
+ }
result = read (win32_channel->fd, buf, count);
+
if (result < 0)
{
*bytes_read = 0;
- switch (errno)
- {
- case EINVAL:
- return G_IO_ERROR_INVAL;
- case EAGAIN:
- return G_IO_ERROR_AGAIN;
- default:
- return G_IO_ERROR_UNKNOWN;
- }
+ if (errno == EINVAL)
+ return G_IO_ERROR_INVAL;
+ else
+ return G_IO_ERROR_UNKNOWN;
}
else
{
return G_IO_ERROR_NONE;
}
}
-
-static GIOError
-g_io_win32_fd_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written)
+
+static GIOError
+g_io_win32_fd_write (GIOChannel *channel,
+ gchar *buf,
+ guint count,
+ guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
-
+
result = write (win32_channel->fd, buf, count);
-
+ if (win32_channel->debug)
+ g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
+ win32_channel->fd, count, result);
+
if (result < 0)
{
*bytes_written = 0;
}
}
-static GIOError
+static GIOError
g_io_win32_fd_seek (GIOChannel *channel,
- gint offset,
- GSeekType type)
+ gint offset,
+ GSeekType type)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
int whence;
off_t result;
-
+
switch (type)
{
case G_SEEK_SET:
whence = SEEK_END;
break;
default:
- g_warning ("g_io_win32_fd_seek: unknown seek type");
+ g_warning (G_STRLOC ": Unknown seek type %d", (int) type);
return G_IO_ERROR_UNKNOWN;
}
return G_IO_ERROR_NONE;
}
-static void
+static void
g_io_win32_fd_close (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
-
- close (win32_channel->fd);
- return;
-}
-
-static guint
-g_io_win32_fd_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify)
-{
- GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- watch->channel = channel;
- g_io_channel_ref (channel);
-
- watch->callback = func;
- watch->condition = condition;
-
- /* This probably does not work, except for CONIN$. */
- watch->pollfd.fd = _get_osfhandle (win32_channel->fd);
- watch->pollfd.events = condition;
-
- g_main_add_poll (&watch->pollfd, priority);
-
- return g_source_add (priority, TRUE, &win32_watch_fd_funcs,
- watch, user_data, notify);
-}
-
-static GIOError
-g_io_win32_pipe_read (GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_read)
-{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- HANDLE handle;
- DWORD avail;
- gint result;
-
- handle = (HANDLE) _get_osfhandle (win32_channel->fd);
- if (!PeekNamedPipe (handle, NULL, 0, NULL, &avail, NULL))
- {
- return G_IO_ERROR_UNKNOWN;
- }
-
- count = MIN (count, avail);
-
- count = MAX (count, 1); /* Must read at least one byte, or
- * caller will think it's EOF.
- */
- /* g_print ("g_io_win32_pipe_read: %d %d\n", win32_channel->fd, count); */
- if (count == 0)
- result = 0;
- else
- result = read (win32_channel->fd, buf, count);
- if (result < 0)
- {
- *bytes_read = 0;
- switch (errno)
- {
- case EINVAL:
- return G_IO_ERROR_INVAL;
- case EAGAIN:
- return G_IO_ERROR_AGAIN;
- default:
- return G_IO_ERROR_UNKNOWN;
- }
- }
- else
- {
- *bytes_read = result;
- win32_channel->offset += result;
- /* g_print ("=%d (%d)\n", result, win32_channel->offset); */
- return G_IO_ERROR_NONE;
- }
-}
-
-static GIOError
-g_io_win32_pipe_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written)
-{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- LONG prevcnt;
- gint result;
-
- /* g_print ("g_io_win32_pipe_write: %d %d\n", win32_channel->fd, count); */
- result = write (win32_channel->fd, buf, count);
- if (result < 0)
- {
- *bytes_written = 0;
- switch (errno)
- {
- case EINVAL:
- return G_IO_ERROR_INVAL;
- case EAGAIN:
- return G_IO_ERROR_AGAIN;
- default:
- return G_IO_ERROR_UNKNOWN;
- }
- }
- else
+ if (win32_channel->debug)
+ g_print ("thread %#x: closing fd %d\n",
+ win32_channel->thread_id,
+ win32_channel->fd);
+ LOCK (win32_channel->mutex);
+ if (win32_channel->running)
{
- if (g_pipe_readable_msg == 0)
- g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable");
-
- win32_channel->offset += result;
- /* g_print ("=%d (%d)\n", result, win32_channel->offset); */
- if (win32_channel->need_wakeups)
- {
- PostThreadMessage (win32_channel->peer,
- g_pipe_readable_msg,
- win32_channel->peer_fd,
- win32_channel->offset);
- }
- *bytes_written = result;
- return G_IO_ERROR_NONE;
+ if (win32_channel->debug)
+ g_print ("thread %#x: running, marking fd %d for later close\n",
+ win32_channel->thread_id, win32_channel->fd);
+ win32_channel->running = FALSE;
+ win32_channel->needs_close = TRUE;
+ SetEvent (win32_channel->data_avail_event);
}
-}
-
-static void
-g_io_win32_pipe_close (GIOChannel *channel)
-{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
-
- /* g_print ("g_io_win32_pipe_close: %#x %d\n", channel, win32_channel->fd); */
-
- close (win32_channel->fd);
- return;
-}
-
-static guint
-g_io_win32_pipe_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify)
-{
- GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- gint i;
-
- /* g_print ("g_io_win32_pipe_add_watch: %d\n", win32_channel->fd); */
-
- watch->channel = channel;
- g_io_channel_ref (channel);
-
- watch->callback = func;
- watch->condition = condition;
-
- watch->pollfd.fd = win32_channel->fd;
- watch->pollfd.events = condition;
-
- for (i = 0; i < n_watched_pipes; i++)
- if (watched_pipes[i].fd == -1)
- break;
- if (i == N_WATCHED_PIPES)
- g_error ("Too many watched pipes");
else
{
- watched_pipes[i].fd = win32_channel->fd;
- watched_pipes[i].watch = watch;
- watched_pipes[i].channel = win32_channel;
- watched_pipes[i].user_data = user_data;
- n_watched_pipes = MAX (i + 1, n_watched_pipes);
+ if (win32_channel->debug)
+ g_print ("closing fd %d\n", win32_channel->fd);
+ close (win32_channel->fd);
+ if (win32_channel->debug)
+ g_print ("closed fd %d, setting to -1\n",
+ win32_channel->fd);
+ win32_channel->fd = -1;
}
- return g_source_add (priority, FALSE, &win32_watch_pipe_funcs, watch, user_data, notify);
+ UNLOCK (win32_channel->mutex);
}
-static void
-g_io_win32_pipe_free (GIOChannel *channel)
+static GSource *
+g_io_win32_fd_create_watch (GIOChannel *channel,
+ GIOCondition condition)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- gint i;
-
- /* g_print ("g_io_win32_pipe_free: %#x %#x\n", channel, channel->channel_data); */
-
- for (i = 0; i < n_watched_pipes; i++)
- if (watched_pipes[i].fd == win32_channel->fd)
- {
- watched_pipes[i].fd = -1;
- break;
- }
- g_io_win32_free (channel);
+ return g_io_win32_create_watch (channel, condition, read_thread);
}
-static GIOError
-g_io_win32_sock_read (GIOChannel *channel,
- gchar *buf,
+static GIOError
+g_io_win32_sock_read (GIOChannel *channel,
+ gchar *buf,
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
+ GIOError error;
+ if (win32_channel->debug)
+ g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
+ win32_channel->fd, count);
+
result = recv (win32_channel->fd, buf, count, 0);
+
+ if (win32_channel->debug)
+ g_print ("g_io_win32_sock_read: recv:%d\n", result);
+
if (result == SOCKET_ERROR)
{
*bytes_read = 0;
return G_IO_ERROR_NONE;
}
}
-
-static GIOError
-g_io_win32_sock_write(GIOChannel *channel,
- gchar *buf,
- guint count,
- guint *bytes_written)
+
+static GIOError
+g_io_win32_sock_write (GIOChannel *channel,
+ gchar *buf,
+ guint count,
+ guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
-
+
+ if (win32_channel->debug)
+ g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
+ win32_channel->fd, count);
+
result = send (win32_channel->fd, buf, count, 0);
-
+
+ if (win32_channel->debug)
+ g_print ("g_io_win32_sock_write: send:%d\n", result);
+
if (result == SOCKET_ERROR)
{
*bytes_written = 0;
}
}
-static void
+static void
g_io_win32_sock_close (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
+ if (win32_channel->debug)
+ g_print ("thread %#x: closing socket %d\n",
+ win32_channel->thread_id,
+ win32_channel->fd);
closesocket (win32_channel->fd);
- return;
+ win32_channel->fd = -1;
}
-static guint
-g_io_win32_sock_add_watch (GIOChannel *channel,
- gint priority,
- GIOCondition condition,
- GIOFunc func,
- gpointer user_data,
- GDestroyNotify notify)
+static GSource *
+g_io_win32_sock_create_watch (GIOChannel *channel,
+ GIOCondition condition)
{
- GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
-
- watch->channel = channel;
- g_io_channel_ref (channel);
-
- watch->callback = func;
- watch->condition = condition;
+ return g_io_win32_create_watch (channel, condition, select_thread);
+}
- watch->pollfd.fd = win32_channel->fd;
- watch->pollfd.events = condition;
+static GIOFuncs win32_channel_msg_funcs = {
+ g_io_win32_msg_read,
+ g_io_win32_msg_write,
+ g_io_win32_no_seek,
+ g_io_win32_msg_close,
+ g_io_win32_msg_create_watch,
+ g_io_win32_free
+};
- g_main_add_poll (&watch->pollfd, priority);
+static GIOFuncs win32_channel_fd_funcs = {
+ g_io_win32_fd_read,
+ g_io_win32_fd_write,
+ g_io_win32_fd_seek,
+ g_io_win32_fd_close,
+ g_io_win32_fd_create_watch,
+ g_io_win32_free
+};
- return g_source_add (priority, TRUE, &win32_watch_sock_funcs, watch, user_data, notify);
-}
+static GIOFuncs win32_channel_sock_funcs = {
+ g_io_win32_sock_read,
+ g_io_win32_sock_write,
+ g_io_win32_no_seek,
+ g_io_win32_sock_close,
+ g_io_win32_sock_create_watch,
+ g_io_win32_free
+};
GIOChannel *
g_io_channel_win32_new_messages (guint hwnd)
{
GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- GIOChannel *channel = (GIOChannel *) win32_channel;
+ GIOChannel *channel = (GIOChannel *)win32_channel;
g_io_channel_init (channel);
+ g_io_channel_win32_init (win32_channel);
+ if (win32_channel->debug)
+ g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
channel->funcs = &win32_channel_msg_funcs;
- win32_channel->fd = -1;
- win32_channel->type = G_IO_WINDOWS_MESSAGES;
+ win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
win32_channel->hwnd = (HWND) hwnd;
return channel;
}
GIOChannel *
-g_io_channel_unix_new (gint fd)
+g_io_channel_win32_new_fd (gint fd)
{
- GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- GIOChannel *channel = (GIOChannel *) win32_channel;
+ GIOWin32Channel *win32_channel;
+ GIOChannel *channel;
+ struct stat st;
+
+ if (fstat (fd, &st) == -1)
+ {
+ g_warning (G_STRLOC ": %d isn't a (emulated) file descriptor", fd);
+ return NULL;
+ }
+
+ win32_channel = g_new (GIOWin32Channel, 1);
+ channel = (GIOChannel *)win32_channel;
g_io_channel_init (channel);
+ g_io_channel_win32_init (win32_channel);
+ if (win32_channel->debug)
+ g_print ("g_io_channel_win32_new_fd: fd = %d\n", fd);
channel->funcs = &win32_channel_fd_funcs;
+ win32_channel->type = G_IO_WIN32_FILE_DESC;
win32_channel->fd = fd;
- win32_channel->type = G_IO_FILE_DESC;
return channel;
}
gint
-g_io_channel_unix_get_fd (GIOChannel *channel)
+g_io_channel_win32_get_fd (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
return win32_channel->fd;
}
GIOChannel *
-g_io_channel_win32_new_pipe_with_wakeups (int fd,
- guint peer,
- int peer_fd)
+g_io_channel_win32_new_socket (int socket)
{
GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- GIOChannel *channel = (GIOChannel *) win32_channel;
-
- /* g_print ("g_io_channel_win32_new_pipe_with_wakeups %d %#x %d\n", fd, peer, peer_fd); */
+ GIOChannel *channel = (GIOChannel *)win32_channel;
g_io_channel_init (channel);
- channel->funcs = &win32_channel_pipe_funcs;
- win32_channel->fd = fd;
- win32_channel->type = G_IO_PIPE;
- win32_channel->peer = peer;
- win32_channel->peer_fd = peer_fd;
- win32_channel->offset = 0;
- win32_channel->need_wakeups = TRUE;
+ g_io_channel_win32_init (win32_channel);
+ if (win32_channel->debug)
+ g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
+ channel->funcs = &win32_channel_sock_funcs;
+ win32_channel->type = G_IO_WIN32_SOCKET;
+ win32_channel->fd = socket;
return channel;
}
GIOChannel *
-g_io_channel_win32_new_pipe (int fd)
+g_io_channel_unix_new (gint fd)
{
- GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- GIOChannel *channel = (GIOChannel *) win32_channel;
+ struct stat st;
- g_io_channel_init (channel);
- channel->funcs = &win32_channel_pipe_funcs;
- win32_channel->fd = fd;
- win32_channel->type = G_IO_PIPE;
- win32_channel->offset = 0;
- win32_channel->need_wakeups = FALSE;
+ if (fstat (fd, &st) == 0)
+ return g_io_channel_win32_new_fd (fd);
+
+ if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
+ return g_io_channel_win32_new_socket(fd);
- return channel;
+ g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
+ return NULL;
}
-GIOChannel *
-g_io_channel_win32_new_stream_socket (int socket)
+gint
+g_io_channel_unix_get_fd (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- GIOChannel *channel = (GIOChannel *) win32_channel;
+ return g_io_channel_win32_get_fd (channel);
+}
- g_io_channel_init (channel);
- channel->funcs = &win32_channel_sock_funcs;
- win32_channel->fd = socket;
- win32_channel->type = G_IO_STREAM_SOCKET;
+void
+g_io_channel_win32_set_debug (GIOChannel *channel,
+ gboolean flag)
+{
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- return channel;
+ win32_channel->debug = flag;
}
gint
-g_io_channel_win32_get_fd (GIOChannel *channel)
+g_io_channel_win32_poll (GPollFD *fds,
+ gint n_fds,
+ gint timeout)
{
- return g_io_channel_unix_get_fd (channel);
+ int result;
+
+ g_return_val_if_fail (n_fds >= 0, 0);
+
+ result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
+
+ return result;
}
void
-g_io_channel_win32_pipe_request_wakeups (GIOChannel *channel,
- guint peer,
- int peer_fd)
+g_io_channel_win32_make_pollfd (GIOChannel *channel,
+ GIOCondition condition,
+ GPollFD *fd)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- win32_channel->peer = peer;
- win32_channel->peer_fd = peer_fd;
- win32_channel->need_wakeups = TRUE;
+ if (win32_channel->data_avail_event == NULL)
+ create_events (win32_channel);
+
+ fd->fd = (gint) win32_channel->data_avail_event;
+ fd->events = condition;
+
+ if (win32_channel->thread_id == 0)
+ if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
+ create_thread (win32_channel, condition, read_thread);
+ else if (win32_channel->type == G_IO_WIN32_SOCKET)
+ create_thread (win32_channel, condition, select_thread);
}
-void
-g_io_channel_win32_pipe_readable (gint fd,
- guint offset)
+/* Binary compatibility */
+GIOChannel *
+g_io_channel_win32_new_stream_socket (int socket)
{
- gint i;
-
- for (i = 0; i < n_watched_pipes; i++)
- if (watched_pipes[i].fd == fd)
- {
- if (watched_pipes[i].channel->offset < offset)
- (*watched_pipes[i].watch->callback) (watched_pipes[i].watch->channel,
- G_IO_IN,
- watched_pipes[i].user_data);
- break;
- }
+ return g_io_channel_win32_new_socket (socket);
}