+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
+2001-01-25 Tor Lillqvist <tml@iki.fi>
+
+ * giowin32.c: Socket support rewritten. It was utterly broken, and
+ untested in fact. We still do use a thread for each socket being
+ watched, but instead of blocking in recv() (which of course was
+ plain stupid for sockets being liste()ed on), we block in
+ select(). The read method for sockets calls recv(). It is now
+ possible for the application to call accept(), recv() or send() in
+ the callback, just like on Unix. Tested with code kindly provided
+ by Andrew Lanoix.
+
+ Rename g_io_channel_win32_new_stream_socket() to
+ g_io_channel_win32_new_socket() as it isn't restricted to stream
+ sockets.
+
+ * gmain.c (g_poll): Related changes in the Win32 version of
+ g_poll(). When polling for messages, always do a PeekMessage()
+ first. We used to miss messages if several were posted between
+ calls to g_poll().
+
+ * giochannel.h: Improve Win32-related comments.
+
+ * gutf8.c: (Win32) Include <stdio.h> for sprintf.
+
+ * tests/gio-test.c: (Win32) Add tests for polling for Windows
+ messages.
+
+ * tests/makefile.mingw.in: Remove superfluous compilation command
+ line.
+
2001-01-23 <alexl@redhat.com>
* gmain.c (g_source_callback_unref): Free the callback
/* On Unix, IO channels created with this function for any file
* descriptor or socket.
*
- * On Win32, use this only for files opened with the MSVCRT (the
- * Microsoft run-time C library) _open() or _pipe, including file
- * descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr).
+ * On Win32, this can be used either for files opened with the MSVCRT
+ * (the Microsoft run-time C library) _open() or _pipe, including file
+ * descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr),
+ * or for Winsock SOCKETs. If the parameter is a legal file
+ * descriptor, it is assumed to be such, otherwise it should be a
+ * SOCKET. This relies on SOCKETs and file descriptors not
+ * overlapping. If you want to be certain, call either
+ * g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket()
+ * instead as appropriate.
*
* The term file descriptor as used in the context of Win32 refers to
* the emulated Unix-like file descriptors MSVCRT provides. The native
* corresponding concept is file HANDLE. There isn't as of yet a way to
- * get GIOChannels for file HANDLEs.
+ * get GIOChannels for Win32 file HANDLEs.
*/
GIOChannel* g_io_channel_unix_new (int fd);
gint g_io_channel_unix_get_fd (GIOChannel *channel);
/* Use this to get a GPollFD from a GIOChannel, so that you can call
* g_io_channel_win32_poll(). After calling this you should only use
* g_io_channel_read() to read from the GIOChannel, i.e. never read()
- * or recv() from the underlying file descriptor or SOCKET.
+ * from the underlying file descriptor. For SOCKETs, it is possible to call
+ * recv().
*/
void g_io_channel_win32_make_pollfd (GIOChannel *channel,
GIOCondition condition,
/* This can be used to wait a until at least one of the channels is readable.
* On Unix you would do a select() on the file descriptors of the channels.
- * This should probably be available for all platforms?
*/
gint g_io_channel_win32_poll (GPollFD *fds,
gint n_fds,
GPollFD *fd,
guint hwnd);
-/* An IO channel for Windows messages for window handle hwnd. */
+/* Create an IO channel for Windows messages for window handle hwnd. */
GIOChannel *g_io_channel_win32_new_messages (guint hwnd);
-/* An IO channel for C runtime (emulated Unix-like) file
- * descriptors. Identical to g_io_channel_unix_new above.
- * After calling g_io_add_watch() on a IO channel returned
- * by this function, you shouldn't call read() on the file
- * descriptor.
+/* Create an IO channel for C runtime (emulated Unix-like) file
+ * descriptors. After calling g_io_add_watch() on a IO channel
+ * returned by this function, you shouldn't call read() on the file
+ * descriptor. This is because adding polling for a file descriptor is
+ * implemented on Win32 by starting a thread that sits blocked in a
+ * read() from the file descriptor most of the time. All reads from
+ * the file descriptor should be done by this internal GLib
+ * thread. Your code should call only g_io_channel_read().
*/
GIOChannel* g_io_channel_win32_new_fd (int fd);
/* Get the C runtime file descriptor of a channel. */
gint g_io_channel_win32_get_fd (GIOChannel *channel);
-/* An IO channel for a SOCK_STREAM winsock socket. The parameter
- * should be a SOCKET. After calling g_io_add_watch() on a IO channel
- * returned by this function, you shouldn't call recv() on the SOCKET.
+/* Create an IO channel for a winsock socket. The parameter should be
+ * a SOCKET. Contrary to IO channels for file descriptors (on *Win32),
+ * you can use normal recv() or recvfrom() on sockets even if GLib
+ * is polling them.
*/
-GIOChannel *g_io_channel_win32_new_stream_socket (int socket);
+GIOChannel *g_io_channel_win32_new_socket (int socket);
#endif
#define BUFFER_SIZE 4096
typedef enum {
- G_IO_WINDOWS_MESSAGES, /* Windows messages */
- G_IO_FILE_DESC, /* Unix-like file descriptors from
+ 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_STREAM_SOCKET /* Stream sockets. Similar as fds, but
- * read with recv().
+ G_IO_WIN32_SOCKET /* Sockets. A separate thread is blocked
+ * in select() most of the time.
*/
} GIOWin32ChannelType;
gboolean debug;
- /* This is used by G_IO_WINDOWS_MESSAGES channels */
+ CRITICAL_SECTION mutex;
+
+ /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
HWND hwnd; /* handle of window, or NULL */
- /* Following fields used by fd and socket channels for input */
+ /* 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
*/
guchar *buffer; /* (Circular) buffer */
gint wrp, rdp; /* Buffer indices for writing and reading */
- 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;
HANDLE space_avail_event;
- CRITICAL_SECTION mutex;
-
- /* Function that actually reads from fd */
- int (*reader) (int fd, guchar *buf, int len);
+
+ /* Following fields used by socket channels */
+ GSList *watches;
+ HANDLE data_avail_noticed_event;
};
#define LOCK(mutex) EnterCriticalSection (&mutex)
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);
}
* 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->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);
}
static unsigned __stdcall
-reader_thread (void *parameter)
+read_thread (void *parameter)
{
GIOWin32Channel *channel = parameter;
+ GSList *tmp;
guchar *buffer;
guint nbytes;
- g_io_channel_ref ((GIOChannel *) channel);
+ g_io_channel_ref ((GIOChannel *)channel);
if (channel->debug)
- g_print ("thread %#x: starting. pid:%#x, fd:%d, data_avail:%#x, space_avail:%#x\n",
+ g_print ("read_thread %#x: start fd:%d, data_avail:%#x, space_avail:%#x\n",
channel->thread_id,
- (guint) GetCurrentProcessId (),
channel->fd,
(guint) channel->data_avail_event,
(guint) channel->space_avail_event);
{
LOCK (channel->mutex);
if (channel->debug)
- g_print ("thread %#x: rdp=%d, wrp=%d\n",
+ 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 ("thread %#x: resetting space_available\n",
+ g_print ("read_thread %#x: resetting space_avail\n",
channel->thread_id);
ResetEvent (channel->space_avail_event);
if (channel->debug)
- g_print ("thread %#x: waiting for space\n", channel->thread_id);
+ 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 ("thread %#x: rdp=%d, wrp=%d\n",
+ g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
channel->thread_id, channel->rdp, channel->wrp);
}
BUFFER_SIZE - channel->wrp);
if (channel->debug)
- g_print ("thread %#x: calling reader for %d bytes\n",
+ g_print ("read_thread %#x: calling read() for %d bytes\n",
channel->thread_id, nbytes);
UNLOCK (channel->mutex);
- nbytes = (*channel->reader) (channel->fd, buffer, nbytes);
+ nbytes = read (channel->fd, buffer, nbytes);
LOCK (channel->mutex);
+ channel->revents = G_IO_IN;
+ if (nbytes == 0)
+ channel->revents |= G_IO_HUP;
+ else if (nbytes < 0)
+ channel->revents |= G_IO_ERR;
+
if (channel->debug)
- g_print ("thread %#x: got %d bytes, rdp=%d, wrp=%d\n",
+ g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
channel->thread_id, nbytes, channel->rdp, channel->wrp);
if (nbytes <= 0)
channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
if (channel->debug)
- g_print ("thread %#x: rdp=%d, wrp=%d, setting data available\n",
+ 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->debug)
- g_print ("thread %#x: got EOF, rdp=%d, wrp=%d, setting data available\n",
- channel->thread_id, channel->rdp, channel->wrp);
-
if (channel->needs_close)
{
if (channel->debug)
- g_print ("thread %#x: channel fd %d needs closing\n",
+ g_print ("read_thread %#x: channel fd %d needs closing\n",
channel->thread_id, channel->fd);
- if (channel->type == G_IO_FILE_DESC)
- close (channel->fd);
- else if (channel->type == G_IO_STREAM_SOCKET)
- closesocket (channel->fd);
+ close (channel->fd);
channel->fd = -1;
}
+ 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);
+ 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
}
static void
-create_reader_thread (GIOWin32Channel *channel,
- gpointer reader)
+create_thread (GIOWin32Channel *channel,
+ GIOCondition condition,
+ unsigned (__stdcall *thread) (void *parameter))
{
- channel->reader = reader;
-
if ((channel->thread_handle =
- (HANDLE) _beginthreadex (NULL, 0, reader_thread, channel, 0,
+ (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
&channel->thread_id)) == 0)
g_warning ("Error creating reader thread: %s", strerror (errno));
WaitForSingleObject (channel->space_avail_event, INFINITE);
g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
channel->thread_id, count, channel->rdp, channel->wrp);
- if (channel->rdp == channel->wrp)
+ if (channel->wrp == channel->rdp)
{
UNLOCK (channel->mutex);
if (channel->debug)
if (channel->debug)
g_print ("done waiting for data from thread %#x\n", channel->thread_id);
LOCK (channel->mutex);
- if (channel->rdp == channel->wrp && !channel->running)
+ if (channel->wrp == channel->rdp && !channel->running)
{
UNLOCK (channel->mutex);
return 0;
LOCK (channel->mutex);
channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
if (channel->debug)
- g_print ("setting space available for thread %#x\n", channel->thread_id);
+ 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->rdp == channel->wrp)
+ if (channel->running && channel->wrp == channel->rdp)
{
if (channel->debug)
- g_print ("resetting data_available of thread %#x\n",
+ g_print ("resetting data_avail of thread %#x\n",
channel->thread_id);
ResetEvent (channel->data_avail_event);
};
return count - left;
}
+static unsigned __stdcall
+select_thread (void *parameter)
+{
+ 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.
+ */
+
+ CloseHandle (channel->thread_handle);
+
+ return 0;
+}
+
static gboolean
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;
}
g_io_win32_check (GSource *source)
{
GIOWin32Watch *watch = (GIOWin32Watch *)source;
- GIOWin32Channel *channel = (GIOWin32Channel *) watch->channel;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
- /* If the thread has died, we have encountered EOF. If the buffer
- * also is emtpty set the HUP bit.
- */
- if (!channel->running && channel->rdp == channel->wrp)
+ 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);
+
+ 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: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n",
- channel->thread_id, channel->rdp, channel->wrp);
- watch->pollfd.revents |= G_IO_HUP;
- return TRUE;
+ 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);
g_io_win32_destroy (GSource *source)
{
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);
+
+ channel->watches = g_slist_remove (channel->watches, watch);
+
g_io_channel_unref (watch->channel);
}
static GSource *
g_io_win32_create_watch (GIOChannel *channel,
GIOCondition condition,
- int (*reader) (int, guchar *, int))
+ unsigned (__stdcall *thread) (void *parameter))
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
GIOWin32Watch *watch;
GSource *source;
watch->pollfd.events = condition;
if (win32_channel->debug)
- g_print ("g_io_win32_create_watch: fd:%d handle:%#x\n",
- win32_channel->fd, watch->pollfd.fd);
+ 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_reader_thread (win32_channel, reader);
+ create_thread (win32_channel, condition, thread);
g_source_add_poll (source, &watch->pollfd);
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ 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;
guint count,
guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
MSG msg;
if (count != sizeof (MSG))
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->buffer)
- {
- CloseHandle (win32_channel->data_avail_event);
- CloseHandle (win32_channel->space_avail_event);
- DeleteCriticalSection (&win32_channel->mutex);
- }
+ 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);
}
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
GIOError error;
guint count,
guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
result = write (win32_channel->fd, buf, count);
gint offset,
GSeekType type)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
int whence;
off_t result;
static void
g_io_win32_fd_close (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
if (win32_channel->debug)
g_print ("thread %#x: closing fd %d\n",
UNLOCK (win32_channel->mutex);
}
-static int
-fd_reader (int fd,
- guchar *buf,
- int len)
-{
- return read (fd, buf, len);
-}
-
static GSource *
g_io_win32_fd_create_watch (GIOChannel *channel,
GIOCondition condition)
{
- return g_io_win32_create_watch (channel, condition, fd_reader);
+ return g_io_win32_create_watch (channel, condition, read_thread);
}
static GIOError
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
GIOError error;
-
- 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;
- }
- }
+ 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 (result < 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_UNKNOWN;
+ switch (WSAGetLastError ())
+ {
+ case WSAEINVAL:
+ return G_IO_ERROR_INVAL;
+ case WSAEWOULDBLOCK:
+ case WSAEINTR:
+ return G_IO_ERROR_AGAIN;
+ default:
+ return G_IO_ERROR_UNKNOWN;
+ }
}
else
{
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
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->fd = -1;
}
-static int
-sock_reader (int fd,
- guchar *buf,
- int len)
-{
- return recv (fd, buf, len, 0);
-}
-
static GSource *
g_io_win32_sock_create_watch (GIOChannel *channel,
GIOCondition condition)
{
- return g_io_win32_create_watch (channel, condition, sock_reader);
+ return g_io_win32_create_watch (channel, condition, select_thread);
}
static GIOFuncs win32_channel_msg_funcs = {
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->type = G_IO_WINDOWS_MESSAGES;
+ win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
win32_channel->hwnd = (HWND) hwnd;
return channel;
}
win32_channel = g_new (GIOWin32Channel, 1);
- channel = (GIOChannel *) win32_channel;
+ 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_FILE_DESC;
+ win32_channel->type = G_IO_WIN32_FILE_DESC;
win32_channel->fd = fd;
return channel;
gint
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_stream_socket (int socket)
+g_io_channel_win32_new_socket (int socket)
{
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_stream_socket: socket = %d\n", socket);
+ g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
channel->funcs = &win32_channel_sock_funcs;
- win32_channel->type = G_IO_STREAM_SOCKET;
+ win32_channel->type = G_IO_WIN32_SOCKET;
win32_channel->fd = socket;
return channel;
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_stream_socket(fd);
+ return g_io_channel_win32_new_socket(fd);
- g_warning ("%d isn't a file descriptor or a socket", fd);
+ g_warning ("%d is neither a file descriptor or a socket", fd);
return NULL;
}
g_io_channel_win32_set_debug (GIOChannel *channel,
gboolean flag)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
win32_channel->debug = flag;
}
GIOCondition condition,
GPollFD *fd)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
if (win32_channel->data_avail_event == NULL)
create_events (win32_channel);
fd->events = condition;
if (win32_channel->thread_id == 0)
- if (win32_channel->type == G_IO_FILE_DESC)
- create_reader_thread (win32_channel, fd_reader);
- else if (win32_channel->type == G_IO_STREAM_SOCKET)
- create_reader_thread (win32_channel, sock_reader);
+ 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);
+}
+
+/* Binary compatibility */
+GIOChannel *
+g_io_channel_win32_new_stream_socket (int socket)
+{
+ return g_io_channel_win32_new_socket (socket);
}
g_io_channel_win32_make_pollfd
g_io_channel_win32_new_fd
g_io_channel_win32_new_messages
+ g_io_channel_win32_new_socket
g_io_channel_win32_new_stream_socket
g_io_channel_win32_poll
g_io_channel_win32_set_debug
/* On Unix, IO channels created with this function for any file
* descriptor or socket.
*
- * On Win32, use this only for files opened with the MSVCRT (the
- * Microsoft run-time C library) _open() or _pipe, including file
- * descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr).
+ * On Win32, this can be used either for files opened with the MSVCRT
+ * (the Microsoft run-time C library) _open() or _pipe, including file
+ * descriptors 0, 1 and 2 (corresponding to stdin, stdout and stderr),
+ * or for Winsock SOCKETs. If the parameter is a legal file
+ * descriptor, it is assumed to be such, otherwise it should be a
+ * SOCKET. This relies on SOCKETs and file descriptors not
+ * overlapping. If you want to be certain, call either
+ * g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket()
+ * instead as appropriate.
*
* The term file descriptor as used in the context of Win32 refers to
* the emulated Unix-like file descriptors MSVCRT provides. The native
* corresponding concept is file HANDLE. There isn't as of yet a way to
- * get GIOChannels for file HANDLEs.
+ * get GIOChannels for Win32 file HANDLEs.
*/
GIOChannel* g_io_channel_unix_new (int fd);
gint g_io_channel_unix_get_fd (GIOChannel *channel);
/* Use this to get a GPollFD from a GIOChannel, so that you can call
* g_io_channel_win32_poll(). After calling this you should only use
* g_io_channel_read() to read from the GIOChannel, i.e. never read()
- * or recv() from the underlying file descriptor or SOCKET.
+ * from the underlying file descriptor. For SOCKETs, it is possible to call
+ * recv().
*/
void g_io_channel_win32_make_pollfd (GIOChannel *channel,
GIOCondition condition,
/* This can be used to wait a until at least one of the channels is readable.
* On Unix you would do a select() on the file descriptors of the channels.
- * This should probably be available for all platforms?
*/
gint g_io_channel_win32_poll (GPollFD *fds,
gint n_fds,
GPollFD *fd,
guint hwnd);
-/* An IO channel for Windows messages for window handle hwnd. */
+/* Create an IO channel for Windows messages for window handle hwnd. */
GIOChannel *g_io_channel_win32_new_messages (guint hwnd);
-/* An IO channel for C runtime (emulated Unix-like) file
- * descriptors. Identical to g_io_channel_unix_new above.
- * After calling g_io_add_watch() on a IO channel returned
- * by this function, you shouldn't call read() on the file
- * descriptor.
+/* Create an IO channel for C runtime (emulated Unix-like) file
+ * descriptors. After calling g_io_add_watch() on a IO channel
+ * returned by this function, you shouldn't call read() on the file
+ * descriptor. This is because adding polling for a file descriptor is
+ * implemented on Win32 by starting a thread that sits blocked in a
+ * read() from the file descriptor most of the time. All reads from
+ * the file descriptor should be done by this internal GLib
+ * thread. Your code should call only g_io_channel_read().
*/
GIOChannel* g_io_channel_win32_new_fd (int fd);
/* Get the C runtime file descriptor of a channel. */
gint g_io_channel_win32_get_fd (GIOChannel *channel);
-/* An IO channel for a SOCK_STREAM winsock socket. The parameter
- * should be a SOCKET. After calling g_io_add_watch() on a IO channel
- * returned by this function, you shouldn't call recv() on the SOCKET.
+/* Create an IO channel for a winsock socket. The parameter should be
+ * a SOCKET. Contrary to IO channels for file descriptors (on *Win32),
+ * you can use normal recv() or recvfrom() on sockets even if GLib
+ * is polling them.
*/
-GIOChannel *g_io_channel_win32_new_stream_socket (int socket);
+GIOChannel *g_io_channel_win32_new_socket (int socket);
#endif
#define BUFFER_SIZE 4096
typedef enum {
- G_IO_WINDOWS_MESSAGES, /* Windows messages */
- G_IO_FILE_DESC, /* Unix-like file descriptors from
+ 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_STREAM_SOCKET /* Stream sockets. Similar as fds, but
- * read with recv().
+ G_IO_WIN32_SOCKET /* Sockets. A separate thread is blocked
+ * in select() most of the time.
*/
} GIOWin32ChannelType;
gboolean debug;
- /* This is used by G_IO_WINDOWS_MESSAGES channels */
+ CRITICAL_SECTION mutex;
+
+ /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
HWND hwnd; /* handle of window, or NULL */
- /* Following fields used by fd and socket channels for input */
+ /* 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
*/
guchar *buffer; /* (Circular) buffer */
gint wrp, rdp; /* Buffer indices for writing and reading */
- 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;
HANDLE space_avail_event;
- CRITICAL_SECTION mutex;
-
- /* Function that actually reads from fd */
- int (*reader) (int fd, guchar *buf, int len);
+
+ /* Following fields used by socket channels */
+ GSList *watches;
+ HANDLE data_avail_noticed_event;
};
#define LOCK(mutex) EnterCriticalSection (&mutex)
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);
}
* 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->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);
}
static unsigned __stdcall
-reader_thread (void *parameter)
+read_thread (void *parameter)
{
GIOWin32Channel *channel = parameter;
+ GSList *tmp;
guchar *buffer;
guint nbytes;
- g_io_channel_ref ((GIOChannel *) channel);
+ g_io_channel_ref ((GIOChannel *)channel);
if (channel->debug)
- g_print ("thread %#x: starting. pid:%#x, fd:%d, data_avail:%#x, space_avail:%#x\n",
+ g_print ("read_thread %#x: start fd:%d, data_avail:%#x, space_avail:%#x\n",
channel->thread_id,
- (guint) GetCurrentProcessId (),
channel->fd,
(guint) channel->data_avail_event,
(guint) channel->space_avail_event);
{
LOCK (channel->mutex);
if (channel->debug)
- g_print ("thread %#x: rdp=%d, wrp=%d\n",
+ 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 ("thread %#x: resetting space_available\n",
+ g_print ("read_thread %#x: resetting space_avail\n",
channel->thread_id);
ResetEvent (channel->space_avail_event);
if (channel->debug)
- g_print ("thread %#x: waiting for space\n", channel->thread_id);
+ 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 ("thread %#x: rdp=%d, wrp=%d\n",
+ g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
channel->thread_id, channel->rdp, channel->wrp);
}
BUFFER_SIZE - channel->wrp);
if (channel->debug)
- g_print ("thread %#x: calling reader for %d bytes\n",
+ g_print ("read_thread %#x: calling read() for %d bytes\n",
channel->thread_id, nbytes);
UNLOCK (channel->mutex);
- nbytes = (*channel->reader) (channel->fd, buffer, nbytes);
+ nbytes = read (channel->fd, buffer, nbytes);
LOCK (channel->mutex);
+ channel->revents = G_IO_IN;
+ if (nbytes == 0)
+ channel->revents |= G_IO_HUP;
+ else if (nbytes < 0)
+ channel->revents |= G_IO_ERR;
+
if (channel->debug)
- g_print ("thread %#x: got %d bytes, rdp=%d, wrp=%d\n",
+ g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
channel->thread_id, nbytes, channel->rdp, channel->wrp);
if (nbytes <= 0)
channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
if (channel->debug)
- g_print ("thread %#x: rdp=%d, wrp=%d, setting data available\n",
+ 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->debug)
- g_print ("thread %#x: got EOF, rdp=%d, wrp=%d, setting data available\n",
- channel->thread_id, channel->rdp, channel->wrp);
-
if (channel->needs_close)
{
if (channel->debug)
- g_print ("thread %#x: channel fd %d needs closing\n",
+ g_print ("read_thread %#x: channel fd %d needs closing\n",
channel->thread_id, channel->fd);
- if (channel->type == G_IO_FILE_DESC)
- close (channel->fd);
- else if (channel->type == G_IO_STREAM_SOCKET)
- closesocket (channel->fd);
+ close (channel->fd);
channel->fd = -1;
}
+ 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);
+ 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
}
static void
-create_reader_thread (GIOWin32Channel *channel,
- gpointer reader)
+create_thread (GIOWin32Channel *channel,
+ GIOCondition condition,
+ unsigned (__stdcall *thread) (void *parameter))
{
- channel->reader = reader;
-
if ((channel->thread_handle =
- (HANDLE) _beginthreadex (NULL, 0, reader_thread, channel, 0,
+ (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
&channel->thread_id)) == 0)
g_warning ("Error creating reader thread: %s", strerror (errno));
WaitForSingleObject (channel->space_avail_event, INFINITE);
g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
channel->thread_id, count, channel->rdp, channel->wrp);
- if (channel->rdp == channel->wrp)
+ if (channel->wrp == channel->rdp)
{
UNLOCK (channel->mutex);
if (channel->debug)
if (channel->debug)
g_print ("done waiting for data from thread %#x\n", channel->thread_id);
LOCK (channel->mutex);
- if (channel->rdp == channel->wrp && !channel->running)
+ if (channel->wrp == channel->rdp && !channel->running)
{
UNLOCK (channel->mutex);
return 0;
LOCK (channel->mutex);
channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
if (channel->debug)
- g_print ("setting space available for thread %#x\n", channel->thread_id);
+ 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->rdp == channel->wrp)
+ if (channel->running && channel->wrp == channel->rdp)
{
if (channel->debug)
- g_print ("resetting data_available of thread %#x\n",
+ g_print ("resetting data_avail of thread %#x\n",
channel->thread_id);
ResetEvent (channel->data_avail_event);
};
return count - left;
}
+static unsigned __stdcall
+select_thread (void *parameter)
+{
+ 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.
+ */
+
+ CloseHandle (channel->thread_handle);
+
+ return 0;
+}
+
static gboolean
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;
}
g_io_win32_check (GSource *source)
{
GIOWin32Watch *watch = (GIOWin32Watch *)source;
- GIOWin32Channel *channel = (GIOWin32Channel *) watch->channel;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
- /* If the thread has died, we have encountered EOF. If the buffer
- * also is emtpty set the HUP bit.
- */
- if (!channel->running && channel->rdp == channel->wrp)
+ 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);
+
+ 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: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n",
- channel->thread_id, channel->rdp, channel->wrp);
- watch->pollfd.revents |= G_IO_HUP;
- return TRUE;
+ 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);
g_io_win32_destroy (GSource *source)
{
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);
+
+ channel->watches = g_slist_remove (channel->watches, watch);
+
g_io_channel_unref (watch->channel);
}
static GSource *
g_io_win32_create_watch (GIOChannel *channel,
GIOCondition condition,
- int (*reader) (int, guchar *, int))
+ unsigned (__stdcall *thread) (void *parameter))
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
GIOWin32Watch *watch;
GSource *source;
watch->pollfd.events = condition;
if (win32_channel->debug)
- g_print ("g_io_win32_create_watch: fd:%d handle:%#x\n",
- win32_channel->fd, watch->pollfd.fd);
+ 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_reader_thread (win32_channel, reader);
+ create_thread (win32_channel, condition, thread);
g_source_add_poll (source, &watch->pollfd);
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ 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;
guint count,
guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
MSG msg;
if (count != sizeof (MSG))
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->buffer)
- {
- CloseHandle (win32_channel->data_avail_event);
- CloseHandle (win32_channel->space_avail_event);
- DeleteCriticalSection (&win32_channel->mutex);
- }
+ 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);
}
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
GIOError error;
guint count,
guint *bytes_written)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
result = write (win32_channel->fd, buf, count);
gint offset,
GSeekType type)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
int whence;
off_t result;
static void
g_io_win32_fd_close (GIOChannel *channel)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
if (win32_channel->debug)
g_print ("thread %#x: closing fd %d\n",
UNLOCK (win32_channel->mutex);
}
-static int
-fd_reader (int fd,
- guchar *buf,
- int len)
-{
- return read (fd, buf, len);
-}
-
static GSource *
g_io_win32_fd_create_watch (GIOChannel *channel,
GIOCondition condition)
{
- return g_io_win32_create_watch (channel, condition, fd_reader);
+ return g_io_win32_create_watch (channel, condition, read_thread);
}
static GIOError
guint count,
guint *bytes_read)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
GIOError error;
-
- 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;
- }
- }
+ 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 (result < 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_UNKNOWN;
+ switch (WSAGetLastError ())
+ {
+ case WSAEINVAL:
+ return G_IO_ERROR_INVAL;
+ case WSAEWOULDBLOCK:
+ case WSAEINTR:
+ return G_IO_ERROR_AGAIN;
+ default:
+ return G_IO_ERROR_UNKNOWN;
+ }
}
else
{
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
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->fd = -1;
}
-static int
-sock_reader (int fd,
- guchar *buf,
- int len)
-{
- return recv (fd, buf, len, 0);
-}
-
static GSource *
g_io_win32_sock_create_watch (GIOChannel *channel,
GIOCondition condition)
{
- return g_io_win32_create_watch (channel, condition, sock_reader);
+ return g_io_win32_create_watch (channel, condition, select_thread);
}
static GIOFuncs win32_channel_msg_funcs = {
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->type = G_IO_WINDOWS_MESSAGES;
+ win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
win32_channel->hwnd = (HWND) hwnd;
return channel;
}
win32_channel = g_new (GIOWin32Channel, 1);
- channel = (GIOChannel *) win32_channel;
+ 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_FILE_DESC;
+ win32_channel->type = G_IO_WIN32_FILE_DESC;
win32_channel->fd = fd;
return channel;
gint
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_stream_socket (int socket)
+g_io_channel_win32_new_socket (int socket)
{
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_stream_socket: socket = %d\n", socket);
+ g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
channel->funcs = &win32_channel_sock_funcs;
- win32_channel->type = G_IO_STREAM_SOCKET;
+ win32_channel->type = G_IO_WIN32_SOCKET;
win32_channel->fd = socket;
return channel;
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_stream_socket(fd);
+ return g_io_channel_win32_new_socket(fd);
- g_warning ("%d isn't a file descriptor or a socket", fd);
+ g_warning ("%d is neither a file descriptor or a socket", fd);
return NULL;
}
g_io_channel_win32_set_debug (GIOChannel *channel,
gboolean flag)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
win32_channel->debug = flag;
}
GIOCondition condition,
GPollFD *fd)
{
- GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
if (win32_channel->data_avail_event == NULL)
create_events (win32_channel);
fd->events = condition;
if (win32_channel->thread_id == 0)
- if (win32_channel->type == G_IO_FILE_DESC)
- create_reader_thread (win32_channel, fd_reader);
- else if (win32_channel->type == G_IO_STREAM_SOCKET)
- create_reader_thread (win32_channel, sock_reader);
+ 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);
+}
+
+/* Binary compatibility */
+GIOChannel *
+g_io_channel_win32_new_stream_socket (int socket)
+{
+ return g_io_channel_win32_new_socket (socket);
}
g_io_channel_win32_make_pollfd
g_io_channel_win32_new_fd
g_io_channel_win32_new_messages
+ g_io_channel_win32_new_socket
g_io_channel_win32_new_stream_socket
g_io_channel_win32_poll
g_io_channel_win32_set_debug
if (poll_msgs)
{
- /* Waiting for messages, and maybe events */
- if (nhandles == 0)
- {
- if (timeout == INFINITE)
- {
- /* Waiting just for messages, infinite timeout
- * -> Use PeekMessage, then WaitMessage
- */
+ /* Waiting for messages, and maybe events
+ * -> First PeekMessage
+ */
#ifdef G_MAIN_POLL_DEBUG
- g_print ("PeekMessage, then WaitMessage\n");
+ g_print ("PeekMessage\n");
#endif
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
- ready = WAIT_OBJECT_0;
- else if (!WaitMessage ())
- g_warning ("g_poll: WaitMessage failed");
- ready = WAIT_OBJECT_0;
- }
- else if (timeout == 0)
+ if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
+ ready = WAIT_OBJECT_0 + nhandles;
+ else
+ {
+ if (nhandles == 0)
{
- /* Waiting just for messages, zero timeout
- * -> Use PeekMessage
- */
+ /* Waiting just for messages */
+ if (timeout == INFINITE)
+ {
+ /* Infinite timeout
+ * -> WaitMessage
+ */
#ifdef G_MAIN_POLL_DEBUG
- g_print ("PeekMessage\n");
+ g_print ("WaitMessage\n");
#endif
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
- ready = WAIT_OBJECT_0;
+ if (!WaitMessage ())
+ g_warning ("g_poll: WaitMessage failed");
+ ready = WAIT_OBJECT_0 + nhandles;
+ }
+ else if (timeout == 0)
+ {
+ /* Waiting just for messages, zero timeout.
+ * If we got here, there was no message
+ */
+ ready = WAIT_TIMEOUT;
+ }
else
- ready = WAIT_TIMEOUT;
- }
- else
- {
- /* Waiting just for messages, some timeout
- * -> First try PeekMessage, then set a timer, wait for message,
- * kill timer, use PeekMessage
- */
+ {
+ /* Waiting just for messages, some timeout
+ * -> Set a timer, wait for message,
+ * kill timer, use PeekMessage
+ */
+ if ((timer = SetTimer (NULL, 0, timeout, NULL)) == 0)
+ g_warning ("g_poll: SetTimer failed");
+ else
+ {
#ifdef G_MAIN_POLL_DEBUG
- g_print ("PeekMessage\n");
+ g_print ("WaitMessage\n");
#endif
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
- ready = WAIT_OBJECT_0;
- else if ((timer = SetTimer (NULL, 0, timeout, NULL)) == 0)
- g_warning ("g_poll: SetTimer failed");
- else
- {
+ WaitMessage ();
+ KillTimer (NULL, timer);
#ifdef G_MAIN_POLL_DEBUG
- g_print ("WaitMessage\n");
+ g_print ("PeekMessage\n");
#endif
- WaitMessage ();
- KillTimer (NULL, timer);
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)
- && msg.message != WM_TIMER)
- ready = WAIT_OBJECT_0;
- else
- ready = WAIT_TIMEOUT;
+ if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)
+ && msg.message != WM_TIMER)
+ ready = WAIT_OBJECT_0;
+ else
+ ready = WAIT_TIMEOUT;
+ }
}
}
- }
- else
- {
- /* Wait for either message or event
- * -> Use MsgWaitForMultipleObjects
- */
+ else
+ {
+ /* Wait for either message or event
+ * -> Use MsgWaitForMultipleObjects
+ */
#ifdef G_MAIN_POLL_DEBUG
- g_print ("MsgWaitForMultipleObjects(%d, %d)\n", nhandles, timeout);
+ g_print ("MsgWaitForMultipleObjects(%d, %d)\n", nhandles, timeout);
#endif
- ready = MsgWaitForMultipleObjects (nhandles, handles, FALSE,
- timeout, QS_ALLINPUT);
+ ready = MsgWaitForMultipleObjects (nhandles, handles, FALSE,
+ timeout, QS_ALLINPUT);
- if (ready == WAIT_FAILED)
- g_warning ("g_poll: MsgWaitForMultipleObjects failed");
+ if (ready == WAIT_FAILED)
+ g_warning ("g_poll: MsgWaitForMultipleObjects failed");
+ }
}
}
else if (nhandles == 0)
g_warning ("g_poll: WaitForMultipleObjects failed");
}
+#ifdef G_MAIN_POLL_DEBUG
+ g_print ("wait returns %d%s\n",
+ ready,
+ (ready == WAIT_FAILED ? " (WAIT_FAILED)" :
+ (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" :
+ (poll_msgs && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : ""))));
+#endif
for (f = fds; f < &fds[nfds]; ++f)
f->revents = 0;
f->revents |= G_IO_IN;
}
}
+#if TEST_WITHOUT_THIS
else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
for (f = fds; f < &fds[nfds]; ++f)
{
#endif
}
}
+#endif
- if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
- return ready - WAIT_OBJECT_0 + 1;
- else
- return 0;
+ return 1;
}
#else /* !G_OS_WIN32 */
#include "glib.h"
#ifdef G_OS_WIN32
+#include <stdio.h>
+#define STRICT
#include <windows.h>
#endif
if (poll_msgs)
{
- /* Waiting for messages, and maybe events */
- if (nhandles == 0)
- {
- if (timeout == INFINITE)
- {
- /* Waiting just for messages, infinite timeout
- * -> Use PeekMessage, then WaitMessage
- */
+ /* Waiting for messages, and maybe events
+ * -> First PeekMessage
+ */
#ifdef G_MAIN_POLL_DEBUG
- g_print ("PeekMessage, then WaitMessage\n");
+ g_print ("PeekMessage\n");
#endif
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
- ready = WAIT_OBJECT_0;
- else if (!WaitMessage ())
- g_warning ("g_poll: WaitMessage failed");
- ready = WAIT_OBJECT_0;
- }
- else if (timeout == 0)
+ if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
+ ready = WAIT_OBJECT_0 + nhandles;
+ else
+ {
+ if (nhandles == 0)
{
- /* Waiting just for messages, zero timeout
- * -> Use PeekMessage
- */
+ /* Waiting just for messages */
+ if (timeout == INFINITE)
+ {
+ /* Infinite timeout
+ * -> WaitMessage
+ */
#ifdef G_MAIN_POLL_DEBUG
- g_print ("PeekMessage\n");
+ g_print ("WaitMessage\n");
#endif
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
- ready = WAIT_OBJECT_0;
+ if (!WaitMessage ())
+ g_warning ("g_poll: WaitMessage failed");
+ ready = WAIT_OBJECT_0 + nhandles;
+ }
+ else if (timeout == 0)
+ {
+ /* Waiting just for messages, zero timeout.
+ * If we got here, there was no message
+ */
+ ready = WAIT_TIMEOUT;
+ }
else
- ready = WAIT_TIMEOUT;
- }
- else
- {
- /* Waiting just for messages, some timeout
- * -> First try PeekMessage, then set a timer, wait for message,
- * kill timer, use PeekMessage
- */
+ {
+ /* Waiting just for messages, some timeout
+ * -> Set a timer, wait for message,
+ * kill timer, use PeekMessage
+ */
+ if ((timer = SetTimer (NULL, 0, timeout, NULL)) == 0)
+ g_warning ("g_poll: SetTimer failed");
+ else
+ {
#ifdef G_MAIN_POLL_DEBUG
- g_print ("PeekMessage\n");
+ g_print ("WaitMessage\n");
#endif
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
- ready = WAIT_OBJECT_0;
- else if ((timer = SetTimer (NULL, 0, timeout, NULL)) == 0)
- g_warning ("g_poll: SetTimer failed");
- else
- {
+ WaitMessage ();
+ KillTimer (NULL, timer);
#ifdef G_MAIN_POLL_DEBUG
- g_print ("WaitMessage\n");
+ g_print ("PeekMessage\n");
#endif
- WaitMessage ();
- KillTimer (NULL, timer);
- if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)
- && msg.message != WM_TIMER)
- ready = WAIT_OBJECT_0;
- else
- ready = WAIT_TIMEOUT;
+ if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)
+ && msg.message != WM_TIMER)
+ ready = WAIT_OBJECT_0;
+ else
+ ready = WAIT_TIMEOUT;
+ }
}
}
- }
- else
- {
- /* Wait for either message or event
- * -> Use MsgWaitForMultipleObjects
- */
+ else
+ {
+ /* Wait for either message or event
+ * -> Use MsgWaitForMultipleObjects
+ */
#ifdef G_MAIN_POLL_DEBUG
- g_print ("MsgWaitForMultipleObjects(%d, %d)\n", nhandles, timeout);
+ g_print ("MsgWaitForMultipleObjects(%d, %d)\n", nhandles, timeout);
#endif
- ready = MsgWaitForMultipleObjects (nhandles, handles, FALSE,
- timeout, QS_ALLINPUT);
+ ready = MsgWaitForMultipleObjects (nhandles, handles, FALSE,
+ timeout, QS_ALLINPUT);
- if (ready == WAIT_FAILED)
- g_warning ("g_poll: MsgWaitForMultipleObjects failed");
+ if (ready == WAIT_FAILED)
+ g_warning ("g_poll: MsgWaitForMultipleObjects failed");
+ }
}
}
else if (nhandles == 0)
g_warning ("g_poll: WaitForMultipleObjects failed");
}
+#ifdef G_MAIN_POLL_DEBUG
+ g_print ("wait returns %d%s\n",
+ ready,
+ (ready == WAIT_FAILED ? " (WAIT_FAILED)" :
+ (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" :
+ (poll_msgs && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : ""))));
+#endif
for (f = fds; f < &fds[nfds]; ++f)
f->revents = 0;
f->revents |= G_IO_IN;
}
}
+#if TEST_WITHOUT_THIS
else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
for (f = fds; f < &fds[nfds]; ++f)
{
#endif
}
}
+#endif
- if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
- return ready - WAIT_OBJECT_0 + 1;
- else
- return 0;
+ return 1;
}
#else /* !G_OS_WIN32 */
#include "glib.h"
#ifdef G_OS_WIN32
+#include <stdio.h>
+#define STRICT
#include <windows.h>
#endif
#include <io.h>
#include <fcntl.h>
#include <process.h>
+ #define STRICT
+ #include <windows.h>
#else
#ifdef HAVE_UNISTD_H
#include <unistd.h>
return retval;
}
+#ifdef G_OS_WIN32
+
+static gboolean
+recv_windows_message (GIOChannel *channel,
+ GIOCondition cond,
+ gpointer data)
+{
+ GIOError error;
+ MSG msg;
+ guint nb;
+
+ while (1)
+ {
+ error = g_io_channel_read (channel, &msg, sizeof (MSG), &nb);
+
+ if (error != G_IO_ERROR_NONE)
+ {
+ g_print ("gio-test: ...reading Windows message: G_IO_ERROR_%s\n",
+ (error == G_IO_ERROR_AGAIN ? "AGAIN" :
+ (error == G_IO_ERROR_INVAL ? "INVAL" :
+ (error == G_IO_ERROR_UNKNOWN ? "UNKNOWN" : "???"))));
+ if (error == G_IO_ERROR_AGAIN)
+ continue;
+ }
+ break;
+ }
+
+ g_print ("gio-test: ...Windows message for %#x: %d,%d,%d\n",
+ msg.hwnd, msg.message, msg.wParam, msg.lParam);
+
+ return TRUE;
+}
+
+LRESULT CALLBACK
+window_procedure (HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ g_print ("gio-test: window_procedure for %#x: %d,%d,%d\n",
+ hwnd, message, wparam, lparam);
+ return DefWindowProc (hwnd, message, wparam, lparam);
+}
+
+#endif
+
int
main (int argc,
char **argv)
GTimeVal start, end;
GPollFD pollfd;
int pollresult;
+ ATOM klass;
+ static WNDCLASS wcl;
+ HWND hwnd;
+ GIOChannel *windows_messages_channel;
#endif
nkiddies = (argc == 1 ? 1 : atoi(argv[1]));
seqtab = g_malloc (nkiddies * 2 * sizeof (int));
+#ifdef G_OS_WIN32
+ wcl.style = 0;
+ wcl.lpfnWndProc = window_procedure;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = GetModuleHandle (NULL);
+ wcl.hIcon = NULL;
+ wcl.hCursor = NULL;
+ wcl.hbrBackground = NULL;
+ wcl.lpszMenuName = NULL;
+ wcl.lpszClassName = "gio-test";
+
+ klass = RegisterClass (&wcl);
+
+ if (!klass)
+ {
+ g_print ("gio-test: RegisterClass failed\n");
+ exit (1);
+ }
+
+ hwnd = CreateWindow (klass, "gio-test", 0, 0, 0, 10, 10,
+ NULL, NULL, wcl.hInstance, NULL);
+ if (!hwnd)
+ {
+ g_print ("gio-test: CreateWindow failed\n");
+ exit (1);
+ }
+
+ windows_messages_channel = g_io_channel_win32_new_messages (hwnd);
+ g_io_add_watch (windows_messages_channel, G_IO_IN, recv_windows_message, 0);
+#endif
+
for (i = 0; i < nkiddies; i++)
{
int pipe_to_sub[2], pipe_from_sub[2];
pipe (pipe_from_sub) == -1)
perror ("pipe"), exit (1);
-
seqtab[i].fd = pipe_from_sub[0];
seqtab[i].seq = 0;
recv_message,
id);
- cmdline = g_strdup_printf ("%s %d %d &", argv[0],
- pipe_to_sub[0], pipe_from_sub[1]);
-
nrunning++;
#ifdef G_OS_WIN32
- {
- gchar *readfd = g_strdup_printf ("%d", pipe_to_sub[0]);
- gchar *writefd = g_strdup_printf ("%d", pipe_from_sub[1]);
- _spawnl (_P_NOWAIT, argv[0], argv[0], readfd, writefd, NULL);
- }
+ cmdline = g_strdup_printf ("%d:%d:%d",
+ pipe_to_sub[0],
+ pipe_from_sub[1],
+ hwnd);
+ _spawnl (_P_NOWAIT, argv[0], argv[0], "--child", cmdline, NULL);
#else
+ cmdline = g_strdup_printf ("%s --child %d:%d &", argv[0],
+ pipe_to_sub[0], pipe_from_sub[1]);
+
system (cmdline);
#endif
close (pipe_to_sub[0]);
/* Child */
int readfd, writefd;
+#ifdef G_OS_WIN32
+ HWND hwnd;
+#endif
int i, j;
char buf[BUFSIZE];
int buflen;
GTimeVal tv;
+ int n;
g_get_current_time (&tv);
- readfd = atoi (argv[1]);
- writefd = atoi (argv[2]);
+ sscanf (argv[2], "%d:%d%n", &readfd, &writefd, &n);
+
+#ifdef G_OS_WIN32
+ sscanf (argv[2] + n, ":%d", &hwnd);
+#endif
srand (tv.tv_sec ^ (tv.tv_usec / 1000) ^ readfd ^ (writefd << 4));
buflen = rand() % BUFSIZE;
for (j = 0; j < buflen; j++)
buf[j] = ' ' + ((buflen + j) % 95);
- g_print ("gio-test: child writing %d bytes to %d\n", buflen, writefd);
+ g_print ("gio-test: child writing %d+%d bytes to %d\n",
+ sizeof(i) + sizeof(buflen), buflen, writefd);
write (writefd, &i, sizeof (i));
write (writefd, &buflen, sizeof (buflen));
write (writefd, buf, buflen);
+
+#ifdef G_OS_WIN32
+ if (rand() % 100 < 5)
+ {
+ int msg = WM_USER + (rand() % 100);
+ WPARAM wparam = rand ();
+ LPARAM lparam = rand ();
+ g_print ("gio-test: child posting message %d,%d,%d to %#x\n",
+ msg, wparam, lparam, hwnd);
+ PostMessage (hwnd, msg, wparam, lparam);
+ }
+#endif
}
g_print ("gio-test: child exiting, closing %d\n", writefd);
close (writefd);
.SUFFIXES: .c .exe
.c.exe:
- $(CC) $(CFLAGS) -c $<
$(CC) $(CFLAGS) -o $@ $< -L .. -lglib-$(GLIB_VER) -L ../gthread -lgthread-$(GLIB_VER)
check: all