X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgiowin32.c;h=290cc9350b668902b1bd64c86ca5619f45e3afed;hb=9b4080611ac14c5579ca7491c512f07a0a9b8347;hp=00e16408606b5739473a59a02ecb73cdb43bc502;hpb=07741c07d814bfd86998dfed1a5da347bb9335bd;p=platform%2Fupstream%2Fglib.git diff --git a/glib/giowin32.c b/glib/giowin32.c index 00e1640..290cc93 100644 --- a/glib/giowin32.c +++ b/glib/giowin32.c @@ -4,7 +4,7 @@ * giowin32.c: IO Channels for Win32. * Copyright 1998 Owen Taylor and Tor Lillqvist * Copyright 1999-2000 Tor Lillqvist and Craig Setera - * Copyright 2001 Andrew Lanoix + * Copyright 2001-2003 Andrew Lanoix * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,6 +32,8 @@ /* Define this to get (very) verbose logging of all channels */ /* #define G_IO_WIN32_DEBUG */ +#include "config.h" + #include "glib.h" #include @@ -85,7 +87,6 @@ struct _GIOWin32Channel { */ guint thread_id; /* If non-NULL has a reader thread, or has * had.*/ - HANDLE thread_handle; HANDLE data_avail_event; gushort revents; @@ -109,6 +110,8 @@ struct _GIOWin32Channel { /* Following fields used by socket channels */ GSList *watches; HANDLE data_avail_noticed_event; + gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */ + gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */ }; #define LOCK(mutex) EnterCriticalSection (&mutex) @@ -119,20 +122,62 @@ struct _GIOWin32Watch { GPollFD pollfd; GIOChannel *channel; GIOCondition condition; - GIOFunc callback; }; static void -g_io_channel_win32_init (GIOWin32Channel *channel) +g_win32_print_access_mode (int flags) +{ + g_print ("%s%s%s%s%s%s%s%s%s%s", + ((flags & 0x3) == _O_RDWR ? "O_RDWR" : + ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" : + ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))), + (flags & _O_APPEND ? "|O_APPEND" : ""), + (flags & _O_RANDOM ? "|O_RANDOM" : ""), + (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""), + (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""), + (flags & _O_CREAT ? "|O_CREAT" : ""), + (flags & _O_TRUNC ? "|O_TRUNC" : ""), + (flags & _O_EXCL ? "|O_EXCL" : ""), + (flags & _O_TEXT ? "|O_TEXT" : ""), + (flags & _O_BINARY ? "|O_BINARY" : "")); +} + +static void +g_win32_print_gioflags (GIOFlags flags) +{ + char *bar = ""; + + if (flags & G_IO_FLAG_APPEND) + bar = "|", g_print ("APPEND"); + if (flags & G_IO_FLAG_NONBLOCK) + g_print ("%sNONBLOCK", bar), bar = "|"; + if (flags & G_IO_FLAG_IS_READABLE) + g_print ("%sREADABLE", bar), bar = "|"; + if (flags & G_IO_FLAG_IS_WRITEABLE) + g_print ("%sWRITEABLE", bar), bar = "|"; + if (flags & G_IO_FLAG_IS_WRITEABLE) + g_print ("%sWRITEABLE", bar), bar = "|"; + if (flags & G_IO_FLAG_IS_SEEKABLE) + g_print ("%sSEEKABLE", bar), bar = "|"; +} + +static gboolean +g_io_win32_get_debug_flag (void) { #ifdef G_IO_WIN32_DEBUG - channel->debug = TRUE; + return TRUE; #else if (getenv ("G_IO_WIN32_DEBUG") != NULL) - channel->debug = TRUE; + return TRUE; else - channel->debug = FALSE; + return FALSE; #endif +} + +static void +g_io_channel_win32_init (GIOWin32Channel *channel) +{ + channel->debug = g_io_win32_get_debug_flag (); channel->buffer = NULL; channel->running = FALSE; channel->needs_close = FALSE; @@ -150,7 +195,7 @@ create_events (GIOWin32Channel *channel) { SECURITY_ATTRIBUTES sec_attrs; - sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES); + sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES); sec_attrs.lpSecurityDescriptor = NULL; sec_attrs.bInheritHandle = FALSE; @@ -161,8 +206,9 @@ create_events (GIOWin32Channel *channel) || !(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); + gchar *emsg = g_win32_error_message (GetLastError ()); + g_error ("Error creating event: %s", emsg); + g_free (emsg); } } @@ -176,7 +222,7 @@ read_thread (void *parameter) g_io_channel_ref ((GIOChannel *)channel); if (channel->debug) - g_print ("read_thread %#x: start 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, channel->fd, (guint) channel->data_avail_event, @@ -188,9 +234,9 @@ read_thread (void *parameter) SetEvent (channel->space_avail_event); + LOCK (channel->mutex); 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); @@ -248,7 +294,6 @@ read_thread (void *parameter) 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; @@ -267,15 +312,13 @@ read_thread (void *parameter) 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 * _endthreadex() for us. */ - CloseHandle (channel->thread_handle); - return 0; } @@ -284,15 +327,80 @@ create_thread (GIOWin32Channel *channel, GIOCondition condition, unsigned (__stdcall *thread) (void *parameter)) { - channel->thread_handle = - (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0, - &channel->thread_id); - if (channel->thread_handle == 0) + HANDLE thread_handle; + + thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0, + &channel->thread_id); + if (thread_handle == 0) g_warning (G_STRLOC ": Error creating reader thread: %s", - strerror (errno)); + g_strerror (errno)); + else if (!CloseHandle (thread_handle)) + g_warning (G_STRLOC ": Error closing thread handle: %s\n", + g_win32_error_message (GetLastError ())); + WaitForSingleObject (channel->space_avail_event, INFINITE); } +static void +init_reset_sockets (GIOWin32Channel *channel) +{ + struct sockaddr_in local, local2, server; + int len; + + channel->reset_send = (gint) socket (AF_INET, SOCK_DGRAM, 0); + if (channel->reset_send == INVALID_SOCKET) + { + g_warning (G_STRLOC ": Error creating reset_send socket: %s\n", + g_win32_error_message (WSAGetLastError ())); + } + + local.sin_family = AF_INET; + local.sin_port = 0; + local.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + if (bind (channel->reset_send, (struct sockaddr *)&local, sizeof (local)) == SOCKET_ERROR) + { + g_warning (G_STRLOC ": Error binding to reset_send socket: %s\n", + g_win32_error_message (WSAGetLastError ())); + } + + local2.sin_family = AF_INET; + local2.sin_port = 0; + local2.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + channel->reset_recv = (gint) socket (AF_INET, SOCK_DGRAM, 0); + if (channel->reset_recv == INVALID_SOCKET) + { + g_warning (G_STRLOC ": Error creating reset_recv socket: %s\n", + g_win32_error_message (WSAGetLastError ())); + } + + if (bind (channel->reset_recv, (struct sockaddr *)&local2, sizeof (local)) == SOCKET_ERROR) + { + g_warning (G_STRLOC ": Error binding to reset_recv socket: %s\n", + g_win32_error_message (WSAGetLastError ())); + } + + len = sizeof (local2); + if (getsockname (channel->reset_recv, (struct sockaddr *)&local2, &len) == SOCKET_ERROR) + { + g_warning (G_STRLOC ": Error getsockname with reset_recv socket: %s\n", + g_win32_error_message (WSAGetLastError ())); + } + + memset (&server, 0, sizeof (server)); + server.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + server.sin_family = AF_INET; + server.sin_port = local2.sin_port; + + if (connect (channel->reset_send, (struct sockaddr *)&server, sizeof (server)) == SOCKET_ERROR) + { + g_warning (G_STRLOC ": connect to reset_recv socket: %s\n", + g_win32_error_message (WSAGetLastError ())); + } + +} + static GIOStatus buffer_read (GIOWin32Channel *channel, guchar *dest, @@ -319,9 +427,11 @@ buffer_read (GIOWin32Channel *channel, LOCK (channel->mutex); if (channel->wrp == channel->rdp && !channel->running) { + if (channel->debug) + g_print ("wrp==rdp, !running\n"); UNLOCK (channel->mutex); *bytes_read = 0; - return G_IO_STATUS_NORMAL; /* as before, normal case ? */ + return G_IO_STATUS_EOF; } } @@ -368,11 +478,12 @@ select_thread (void *parameter) fd_set read_fds, write_fds, except_fds; GSList *tmp; int n; + char buffer[8]; 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", + g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n", channel->thread_id, channel->fd, (guint) channel->data_avail_event, @@ -388,7 +499,9 @@ select_thread (void *parameter) FD_ZERO (&read_fds); FD_ZERO (&write_fds); FD_ZERO (&except_fds); + FD_SET (channel->reset_recv, &read_fds); + LOCK (channel->mutex); tmp = channel->watches; while (tmp) { @@ -403,15 +516,25 @@ select_thread (void *parameter) tmp = tmp->next; } + UNLOCK (channel->mutex); + 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); + LOCK (channel->mutex); + if (channel->needs_close) + { + UNLOCK (channel->mutex); + break; + } + UNLOCK (channel->mutex); + if (n == SOCKET_ERROR) { if (channel->debug) @@ -420,68 +543,67 @@ select_thread (void *parameter) break; } + if (FD_ISSET (channel->reset_recv, &read_fds)) + { 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); + g_print ("select_thread %#x: re-looping\n", + channel->thread_id); + recv (channel->reset_recv, (char *)&buffer, (int) sizeof (buffer), 0); + continue; + } - LOCK (channel->mutex); - if (channel->needs_close) - { - UNLOCK (channel->mutex); - break; - } - UNLOCK (channel->mutex); + 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, setting data_avail\n", + channel->thread_id); + + LOCK (channel->mutex); + ResetEvent (channel->data_avail_noticed_event); + SetEvent (channel->data_avail_event); + if (channel->needs_close) + { + UNLOCK (channel->mutex); + break; + } + UNLOCK (channel->mutex); - if (channel->debug) - g_print ("select_thread %#x: waiting for data_avail_noticed\n", - channel->thread_id); + 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", + 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->fd != -1) - { - /* DO NOT close the fd here */ - channel->fd = -1; - } + LOCK (channel->mutex); + channel->running = FALSE; if (channel->debug) g_print ("select_thread %#x: got error, setting data_avail\n", channel->thread_id); SetEvent (channel->data_avail_event); + g_io_channel_unref ((GIOChannel *)channel); 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; } @@ -490,63 +612,72 @@ g_io_win32_prepare (GSource *source, gint *timeout) { GIOWin32Watch *watch = (GIOWin32Watch *)source; + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; *timeout = -1; + if (channel->debug) + g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n" + " watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n", + channel->thread_id, buffer_condition, + watch->pollfd.events, watch->pollfd.revents, channel->revents); + if (channel->type == G_IO_WIN32_FILE_DESC) { LOCK (channel->mutex); if (channel->running && channel->wrp == channel->rdp) - channel->revents = 0; + { + if (channel->debug) + g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n", + channel->thread_id); + channel->revents = 0; + } UNLOCK (channel->mutex); } else if (channel->type == G_IO_WIN32_SOCKET) { + LOCK (channel->mutex); channel->revents = 0; - if (channel->debug) - g_print ("g_io_win32_prepare: thread %#x, setting data_avail_noticed\n", + g_print ("g_io_win32_prepare: for 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); + UNLOCK (channel->mutex); } - return FALSE; - /* XXX: why should we want to do this ? */ - watch->condition = g_io_channel_get_buffer_condition (watch->channel); - - return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition; + return ((watch->condition & buffer_condition) == watch->condition); } static gboolean g_io_win32_check (GSource *source) { - MSG msg; + MSG msg; GIOWin32Watch *watch = (GIOWin32Watch *)source; GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; GIOCondition buffer_condition = g_io_channel_get_buffer_condition (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, + g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n" + " watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n", + channel->thread_id, buffer_condition, watch->pollfd.events, watch->pollfd.revents, channel->revents); if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES) - { - watch->pollfd.revents = (watch->pollfd.events & channel->revents); - } - else - { - return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE)); - } - + { + watch->pollfd.revents = (watch->pollfd.events & channel->revents); + } + else + { + return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE)); + } + if (channel->type == G_IO_WIN32_SOCKET) { + LOCK (channel->mutex); if (channel->debug) g_print ("g_io_win32_check: thread %#x, resetting data_avail\n", channel->thread_id); @@ -554,9 +685,10 @@ g_io_win32_check (GSource *source) if (channel->debug) g_print ("g_io_win32_check: thread %#x, there.\n", channel->thread_id); + UNLOCK (channel->mutex); } - return (watch->pollfd.revents & watch->condition); + return ((watch->pollfd.revents | buffer_condition) & watch->condition); } static gboolean @@ -566,6 +698,7 @@ g_io_win32_dispatch (GSource *source, { GIOFunc func = (GIOFunc)callback; GIOWin32Watch *watch = (GIOWin32Watch *)source; + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); if (!func) { @@ -575,7 +708,7 @@ g_io_win32_dispatch (GSource *source, } return (*func) (watch->channel, - watch->pollfd.revents & watch->condition, + (watch->pollfd.revents | buffer_condition) & watch->condition, user_data); } @@ -584,7 +717,9 @@ g_io_win32_finalize (GSource *source) { GIOWin32Watch *watch = (GIOWin32Watch *)source; GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; + char send_buffer[] = "f"; + LOCK (channel->mutex); if (channel->debug) g_print ("g_io_win32_finalize: channel with thread %#x\n", channel->thread_id); @@ -592,7 +727,11 @@ g_io_win32_finalize (GSource *source) channel->watches = g_slist_remove (channel->watches, watch); SetEvent (channel->data_avail_noticed_event); + if (channel->type == G_IO_WIN32_SOCKET) + send (channel->reset_send, send_buffer, sizeof (send_buffer), 0); + g_io_channel_unref (watch->channel); + UNLOCK (channel->mutex); } GSourceFuncs g_io_watch_funcs = { @@ -610,6 +749,7 @@ g_io_win32_create_watch (GIOChannel *channel, GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; GIOWin32Watch *watch; GSource *source; + char send_buffer[] = "c"; source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); watch = (GIOWin32Watch *)source; @@ -628,14 +768,18 @@ g_io_win32_create_watch (GIOChannel *channel, 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); - + + LOCK (win32_channel->mutex); win32_channel->watches = g_slist_append (win32_channel->watches, watch); if (win32_channel->thread_id == 0) create_thread (win32_channel, condition, thread); + else + send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0); g_source_add_poll (source, &watch->pollfd); - + UNLOCK (win32_channel->mutex); + return source; } @@ -651,21 +795,21 @@ g_io_win32_msg_read (GIOChannel *channel, if (count < sizeof (MSG)) { - g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, - _("Incorrect message size")); /* Correct error message? FIXME */ + g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, + "Incorrect message size"); /* Informative enough error message? */ return G_IO_STATUS_ERROR; } if (win32_channel->debug) g_print ("g_io_win32_msg_read: for %#x\n", - win32_channel->hwnd); + (guint) win32_channel->hwnd); if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE)) return G_IO_STATUS_AGAIN; memmove (buf, &msg, sizeof (MSG)); *bytes_read = sizeof (MSG); - return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; + return G_IO_STATUS_NORMAL; } static GIOStatus @@ -680,8 +824,8 @@ g_io_win32_msg_write (GIOChannel *channel, if (count != sizeof (MSG)) { - g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, - _("Incorrect message size")); /* Correct error message? FIXME */ + g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, + "Incorrect message size"); /* Informative enough error message? */ return G_IO_STATUS_ERROR; } @@ -689,8 +833,9 @@ g_io_win32_msg_write (GIOChannel *channel, memmove (&msg, buf, sizeof (MSG)); if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam)) { - g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, - _("Unknown error")); /* Correct error message? FIXME */ + gchar *emsg = g_win32_error_message (GetLastError ()); + g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg); + g_free (emsg); return G_IO_STATUS_ERROR; } @@ -700,17 +845,6 @@ g_io_win32_msg_write (GIOChannel *channel, } static GIOStatus -g_io_win32_no_seek (GIOChannel *channel, - glong offset, - GSeekType type, - GError **err) -{ - g_assert_not_reached (); - - return G_IO_STATUS_ERROR; -} - -static GIOStatus g_io_win32_msg_close (GIOChannel *channel, GError **err) { @@ -729,6 +863,10 @@ g_io_win32_free (GIOChannel *channel) win32_channel->thread_id, win32_channel->fd); + if (win32_channel->reset_send) + closesocket (win32_channel->reset_send); + if (win32_channel->reset_recv) + closesocket (win32_channel->reset_recv); if (win32_channel->data_avail_event) CloseHandle (win32_channel->data_avail_event); if (win32_channel->space_avail_event) @@ -786,27 +924,29 @@ g_io_win32_fd_read (GIOChannel *channel, result = read (win32_channel->fd, buf, count); + if (win32_channel->debug) + g_print ("g_io_win32_fd_read: read() = %d\n", result); + if (result < 0) { *bytes_read = 0; - switch(errno) + switch (errno) { #ifdef EAGAIN - case EAGAIN: - return G_IO_STATUS_AGAIN; + case EAGAIN: + return G_IO_STATUS_AGAIN; #endif - default: - g_set_error (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - strerror (errno)); - return G_IO_STATUS_ERROR; + default: + g_set_error (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (errno), + g_strerror (errno)); + return G_IO_STATUS_ERROR; } } *bytes_read = result; - return G_IO_STATUS_NORMAL; /* XXX: 0 byte read an error ?? */ return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; } @@ -829,17 +969,17 @@ g_io_win32_fd_write (GIOChannel *channel, { *bytes_written = 0; - switch(errno) + switch (errno) { #ifdef EAGAIN - case EAGAIN: - return G_IO_STATUS_AGAIN; + case EAGAIN: + return G_IO_STATUS_AGAIN; #endif - default: - g_set_error (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - strerror (errno)); - return G_IO_STATUS_ERROR; + default: + g_set_error (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (errno), + g_strerror (errno)); + return G_IO_STATUS_ERROR; } } @@ -850,12 +990,13 @@ g_io_win32_fd_write (GIOChannel *channel, static GIOStatus g_io_win32_fd_seek (GIOChannel *channel, - glong offset, + gint64 offset, GSeekType type, GError **err) { GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; int whence; + off_t tmp_offset; off_t result; switch (type) @@ -871,16 +1012,25 @@ g_io_win32_fd_seek (GIOChannel *channel, break; default: whence = -1; /* Keep the compiler quiet */ - g_assert_not_reached(); + g_assert_not_reached (); + } + + tmp_offset = offset; + if (tmp_offset != offset) + { + g_set_error (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (EINVAL), + g_strerror (EINVAL)); + return G_IO_STATUS_ERROR; } - result = lseek (win32_channel->fd, offset, whence); + result = lseek (win32_channel->fd, tmp_offset, whence); if (result < 0) { g_set_error (err, G_IO_CHANNEL_ERROR, g_io_channel_error_from_errno (errno), - strerror (errno)); + g_strerror (errno)); return G_IO_STATUS_ERROR; } @@ -940,12 +1090,16 @@ g_io_win32_sock_read (GIOChannel *channel, { GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; gint result; - GIOChannelError error; + GIOChannelError error = G_IO_STATUS_NORMAL; + GIOStatus internal_status = G_IO_STATUS_NORMAL; + char send_buffer[] = "sr"; if (win32_channel->debug) g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n", win32_channel->fd, count); -repeat: +#ifdef WE_NEED_TO_HANDLE_WSAEINTR +repeat: +#endif result = recv (win32_channel->fd, buf, count, 0); if (win32_channel->debug) @@ -970,17 +1124,27 @@ repeat: error = G_IO_CHANNEL_ERROR_FAILED; break; } - g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error")); - return G_IO_STATUS_ERROR; + g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error"); + internal_status = G_IO_STATUS_ERROR; /* FIXME get all errors, better error messages */ } else { *bytes_read = result; + if (result == 0) + internal_status = G_IO_STATUS_EOF; + } - return G_IO_STATUS_NORMAL; /* XXX: 0 byte read an error ?? */ - return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; + if ((internal_status == G_IO_STATUS_EOF) || + (internal_status == G_IO_STATUS_ERROR)) + { + LOCK (win32_channel->mutex); + SetEvent (win32_channel->data_avail_noticed_event); + win32_channel->needs_close = 1; + send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0); + UNLOCK (win32_channel->mutex); } + return internal_status; } static GIOStatus @@ -992,12 +1156,15 @@ g_io_win32_sock_write (GIOChannel *channel, { GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; gint result; - GIOChannelError error; + GIOChannelError error = G_IO_STATUS_NORMAL; + char send_buffer[] = "sw"; if (win32_channel->debug) g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n", win32_channel->fd, count); +#ifdef WE_NEED_TO_HANDLE_WSAEINTR repeat: +#endif result = send (win32_channel->fd, buf, count, 0); if (win32_channel->debug) @@ -1022,7 +1189,12 @@ repeat: error = G_IO_CHANNEL_ERROR_FAILED; break; } - g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error")); + g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error"); + LOCK (win32_channel->mutex); + SetEvent (win32_channel->data_avail_noticed_event); + win32_channel->needs_close = 1; + send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0); + UNLOCK (win32_channel->mutex); return G_IO_STATUS_ERROR; /* FIXME get all errors, better error messages */ } @@ -1040,27 +1212,27 @@ g_io_win32_sock_close (GIOChannel *channel, { GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - LOCK(win32_channel->mutex); + LOCK (win32_channel->mutex); if (win32_channel->running) - { - if (win32_channel->debug) + { + if (win32_channel->debug) g_print ("thread %#x: running, marking for later close\n", win32_channel->thread_id); - win32_channel->running = FALSE; - win32_channel->needs_close = TRUE; - SetEvent(win32_channel->data_avail_noticed_event); - } + win32_channel->running = FALSE; + win32_channel->needs_close = TRUE; + SetEvent(win32_channel->data_avail_noticed_event); + } if (win32_channel->fd != -1) - { - if (win32_channel->debug) - g_print ("thread %#x: closing socket %d\n", - win32_channel->thread_id, - win32_channel->fd); - - closesocket (win32_channel->fd); - win32_channel->fd = -1; - } - UNLOCK(win32_channel->mutex); + { + if (win32_channel->debug) + g_print ("thread %#x: closing socket %d\n", + win32_channel->thread_id, + win32_channel->fd); + + closesocket (win32_channel->fd); + win32_channel->fd = -1; + } + UNLOCK (win32_channel->mutex); /* FIXME error detection? */ @@ -1105,7 +1277,7 @@ g_io_channel_new_file (const gchar *filename, mode_num = MODE_A; break; default: - g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode); + g_warning ("Invalid GIOFileMode %s.\n", mode); return NULL; } @@ -1121,7 +1293,7 @@ g_io_channel_new_file (const gchar *filename, } /* Fall through */ default: - g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode); + g_warning ("Invalid GIOFileMode %s.\n", mode); return NULL; } @@ -1157,13 +1329,21 @@ g_io_channel_new_file (const gchar *filename, pmode = 0; } + /* always open 'untranslated' */ + fid = open (filename, flags | _O_BINARY, pmode); + + if (g_io_win32_get_debug_flag ()) + { + g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename); + g_win32_print_access_mode (flags|_O_BINARY); + g_print (",%#o)=%d\n", pmode, fid); + } - fid = open (filename, flags, pmode); if (fid < 0) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), - strerror (errno)); + g_strerror (errno)); return (GIOChannel *)NULL; } @@ -1173,94 +1353,134 @@ g_io_channel_new_file (const gchar *filename, channel->close_on_unref = TRUE; channel->is_seekable = TRUE; + /* g_io_channel_win32_new_fd sets is_readable and is_writeable to + * correspond to actual readability/writeability. Set to FALSE those + * that mode doesn't allow + */ switch (mode_num) { case MODE_R: - channel->is_readable = TRUE; channel->is_writeable = FALSE; break; case MODE_W: case MODE_A: channel->is_readable = FALSE; - channel->is_writeable = TRUE; break; case MODE_R | MODE_PLUS: case MODE_W | MODE_PLUS: case MODE_A | MODE_PLUS: - channel->is_readable = TRUE; - channel->is_writeable = TRUE; break; default: g_assert_not_reached (); } - if (((GIOWin32Channel *)channel)->debug) - g_print ("g_io_channel_win32_new_file: fd = %ud\n", fid); - return channel; } -GIOStatus -g_io_win32_set_flags (GIOChannel *channel, - GIOFlags flags, - GError **err) +static GIOStatus +g_io_win32_set_flags (GIOChannel *channel, + GIOFlags flags, + GError **err) { GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - g_set_error (err, - G_IO_CHANNEL_ERROR, - g_file_error_from_errno (EACCES), - _("Channel set flags unsupported")); - return G_IO_STATUS_ERROR; + if (win32_channel->debug) + { + g_print ("g_io_win32_set_flags: "); + g_win32_print_gioflags (flags); + g_print ("\n"); + } + + g_warning ("g_io_win32_set_flags () not implemented.\n"); + + return G_IO_STATUS_NORMAL; } -GIOFlags -g_io_win32_fd_get_flags (GIOChannel *channel) +static GIOFlags +g_io_win32_fd_get_flags_internal (GIOChannel *channel, + struct stat *st) { - GIOFlags flags = 0; - struct _stat st; - GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; + GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; + gchar c; + DWORD count; - g_return_val_if_fail (win32_channel != NULL, 0); - g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0); + if (st->st_mode & _S_IFIFO) + { + channel->is_readable = + (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE; + channel->is_writeable = + (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); + channel->is_seekable = FALSE; + } + else if (st->st_mode & _S_IFCHR) + { + /* XXX Seems there is no way to find out the readability of file + * handles to device files (consoles, mostly) without doing a + * blocking read. So punt, use st->st_mode. + */ + channel->is_readable = !!(st->st_mode & _S_IREAD); + + channel->is_writeable = + (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); - if (0 == _fstat (win32_channel->fd, &st)) + /* XXX What about devices that actually *are* seekable? But + * those would probably not be handled using the C runtime + * anyway, but using Windows-specific code. + */ + channel->is_seekable = FALSE; + } + else { - /* XXX: G_IO_FLAG_APPEND */ - /* XXX: G_IO_FLAG_NONBLOCK */ - if (st.st_mode & _S_IREAD) flags |= G_IO_FLAG_IS_READABLE; - if (st.st_mode & _S_IWRITE) flags |= G_IO_FLAG_IS_WRITEABLE; - /* XXX: */ - if (!(st.st_mode & _S_IFIFO)) flags |= G_IO_FLAG_IS_SEEKABLE; + channel->is_readable = + (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); + channel->is_writeable = + (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); + channel->is_seekable = TRUE; } - return flags; + /* XXX: G_IO_FLAG_APPEND */ + /* XXX: G_IO_FLAG_NONBLOCK */ + + return 0; } -/* - * Generic implementation, just translating createion flags - */ -GIOFlags -g_io_win32_get_flags (GIOChannel *channel) +static GIOFlags +g_io_win32_fd_get_flags (GIOChannel *channel) { - GIOFlags flags; + struct stat st; + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; - flags = (channel->is_readable ? G_IO_FLAG_IS_READABLE : 0) - | (channel->is_writeable ? G_IO_FLAG_IS_READABLE : 0) - | (channel->is_seekable ? G_IO_FLAG_IS_SEEKABLE : 0); + g_return_val_if_fail (win32_channel != NULL, 0); + g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0); - return flags; + if (0 == fstat (win32_channel->fd, &st)) + return g_io_win32_fd_get_flags_internal (channel, &st); + else + return 0; +} + +static GIOFlags +g_io_win32_msg_get_flags (GIOChannel *channel) +{ + return 0; +} + +static GIOFlags +g_io_win32_sock_get_flags (GIOChannel *channel) +{ + /* XXX Could do something here. */ + return 0; } static GIOFuncs win32_channel_msg_funcs = { g_io_win32_msg_read, g_io_win32_msg_write, - g_io_win32_no_seek, + NULL, g_io_win32_msg_close, g_io_win32_msg_create_watch, g_io_win32_free, g_io_win32_set_flags, - g_io_win32_get_flags, + g_io_win32_msg_get_flags, }; static GIOFuncs win32_channel_fd_funcs = { @@ -1277,12 +1497,12 @@ static GIOFuncs win32_channel_fd_funcs = { static GIOFuncs win32_channel_sock_funcs = { g_io_win32_sock_read, g_io_win32_sock_write, - g_io_win32_no_seek, + NULL, g_io_win32_sock_close, g_io_win32_sock_create_watch, g_io_win32_free, g_io_win32_set_flags, - g_io_win32_get_flags, + g_io_win32_sock_get_flags, }; GIOChannel * @@ -1308,18 +1528,12 @@ g_io_channel_win32_new_messages (guint hwnd) return channel; } -GIOChannel * -g_io_channel_win32_new_fd (gint fd) +static GIOChannel * +g_io_channel_win32_new_fd_internal (gint fd, + struct stat *st) { 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; @@ -1327,18 +1541,28 @@ g_io_channel_win32_new_fd (gint fd) 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); + g_print ("g_io_channel_win32_new_fd: %u\n", fd); channel->funcs = &win32_channel_fd_funcs; win32_channel->type = G_IO_WIN32_FILE_DESC; win32_channel->fd = fd; + g_io_win32_fd_get_flags_internal (channel, st); + + return channel; +} - channel->is_readable = !!(st.st_mode & _S_IREAD); - channel->is_writeable = !!(st.st_mode & _S_IWRITE); - /* XXX: pipes aren't seeakable, are they ? */ - channel->is_seekable = !(st.st_mode & _S_IFIFO); +GIOChannel * +g_io_channel_win32_new_fd (gint fd) +{ + struct stat st; - return channel; + if (fstat (fd, &st) == -1) + { + g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd); + return NULL; + } + + return g_io_channel_win32_new_fd_internal (fd, &st); } gint @@ -1357,6 +1581,7 @@ g_io_channel_win32_new_socket (int socket) g_io_channel_init (channel); g_io_channel_win32_init (win32_channel); + init_reset_sockets (win32_channel); if (win32_channel->debug) g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket); channel->funcs = &win32_channel_sock_funcs; @@ -1366,6 +1591,7 @@ g_io_channel_win32_new_socket (int socket) /* XXX: check this */ channel->is_readable = TRUE; channel->is_writeable = TRUE; + channel->is_seekable = FALSE; return channel; @@ -1374,15 +1600,26 @@ g_io_channel_win32_new_socket (int socket) GIOChannel * g_io_channel_unix_new (gint fd) { + gboolean is_fd, is_socket; struct stat st; + int optval, optlen; - if (fstat (fd, &st) == 0) - return g_io_channel_win32_new_fd (fd); - - if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR) + is_fd = (fstat (fd, &st) == 0); + + optlen = sizeof (optval); + is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR); + + if (is_fd && is_socket) + g_warning (G_STRLOC ": %d is both a file descriptor and a socket, file descriptor interpretation assumed.", fd); + + if (is_fd) + return g_io_channel_win32_new_fd_internal (fd, &st); + + if (is_socket) return g_io_channel_win32_new_socket(fd); g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd); + return NULL; } @@ -1429,10 +1666,12 @@ g_io_channel_win32_make_pollfd (GIOChannel *channel, 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); + { + 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 */