X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgiowin32.c;h=171fb6803bffb4a5f1000b1f39fbdfb731759e48;hb=d0083f7e2dd621c6b78496bdb6ecf5d580c5e110;hp=8632209dcfa78508959a1f5b1ae77a2be4d9a37f;hpb=e5ef75596ecbc63891853d4cb10aa17be9b8c0ab;p=platform%2Fupstream%2Fglib.git diff --git a/glib/giowin32.c b/glib/giowin32.c index 8632209..171fb68 100644 --- a/glib/giowin32.c +++ b/glib/giowin32.c @@ -17,9 +17,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* @@ -29,6 +27,44 @@ * GLib at ftp://ftp.gtk.org/pub/gtk/. */ +/* + * Bugs that are related to the code in this file: + * + * Bug 137968 - Sometimes a GIOFunc on Win32 is called with zero condition + * http://bugzilla.gnome.org/show_bug.cgi?id=137968 + * + * Bug 324234 - Using g_io_add_watch_full() to wait for connect() to return on a non-blocking socket returns prematurely + * http://bugzilla.gnome.org/show_bug.cgi?id=324234 + * + * Bug 331214 - g_io_channel async socket io stalls + * http://bugzilla.gnome.org/show_bug.cgi?id=331214 + * + * Bug 338943 - Multiple watches on the same socket + * http://bugzilla.gnome.org/show_bug.cgi?id=338943 + * + * Bug 357674 - 2 serious bugs in giowin32.c making glib iochannels useless + * http://bugzilla.gnome.org/show_bug.cgi?id=357674 + * + * Bug 425156 - GIOChannel deadlocks on a win32 socket + * http://bugzilla.gnome.org/show_bug.cgi?id=425156 + * + * Bug 468910 - giofunc condition=0 + * http://bugzilla.gnome.org/show_bug.cgi?id=468910 + * + * Bug 500246 - Bug fixes for giowin32 + * http://bugzilla.gnome.org/show_bug.cgi?id=500246 + * + * Bug 548278 - Async GETs connections are always terminated unexpectedly on windows + * http://bugzilla.gnome.org/show_bug.cgi?id=548278 + * + * Bug 548536 - giowin32 problem when adding and removing watches + * http://bugzilla.gnome.org/show_bug.cgi?id=548536 + * + * When fixing bugs related to the code in this file, either the above + * bugs or others, make sure that the test programs attached to the + * above bugs continue to work. + */ + #include "config.h" #include "glib.h" @@ -46,7 +82,6 @@ #include "gstdio.h" #include "glibintl.h" -#include "galias.h" typedef struct _GIOWin32Channel GIOWin32Channel; typedef struct _GIOWin32Watch GIOWin32Watch; @@ -55,12 +90,16 @@ typedef struct _GIOWin32Watch GIOWin32Watch; typedef enum { G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */ + G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from - * _open() or _pipe(), except for console IO. - * Have to create separate thread to read. + * _open() or _pipe(), except for + * console IO. Separate thread to read + * or write. */ + G_IO_WIN32_CONSOLE, /* Console IO (usually stdin, stdout, stderr) */ - G_IO_WIN32_SOCKET /* Sockets. No separate thread */ + + G_IO_WIN32_SOCKET /* Sockets. No separate thread. */ } GIOWin32ChannelType; struct _GIOWin32Channel { @@ -73,32 +112,34 @@ struct _GIOWin32Channel { gboolean debug; - /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */ - HWND hwnd; /* handle of window, or NULL */ + /* Field used by G_IO_WIN32_WINDOWS_MESSAGES channels */ + HWND hwnd; /* Handle of window, or NULL */ - /* Following fields are used by fd channels. */ + /* Fields used by G_IO_WIN32_FILE_DESC channels. */ CRITICAL_SECTION mutex; int direction; /* 0 means we read from it, * 1 means we write to it. */ - gboolean running; /* Is reader thread running. FALSE if - * EOF has been reached. + gboolean running; /* Is reader or writer thread + * running. FALSE if EOF has been + * reached by the reader thread. */ + 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.*/ + + guint thread_id; /* If non-NULL the channel has or has + * had a reader or writer thread. + */ 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 + * empty and full buffers, we cannot fill it completely, but have to * leave a one character gap. * * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE). @@ -111,16 +152,14 @@ struct _GIOWin32Channel { gint wrp, rdp; /* Buffer indices for writing and reading */ HANDLE space_avail_event; - /* Following fields used by socket channels */ + /* Fields used by G_IO_WIN32_SOCKET channels */ int event_mask; int last_events; - int event; + HANDLE event; gboolean write_would_have_blocked; + gboolean ever_writable; }; -#define LOCK(mutex) EnterCriticalSection (&mutex) -#define UNLOCK(mutex) LeaveCriticalSection (&mutex) - struct _GIOWin32Watch { GSource source; GPollFD pollfd; @@ -157,8 +196,8 @@ g_win32_print_gioflags (GIOFlags flags) 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_WRITABLE) + g_print ("%sWRITABLE", bar), bar = "|"; if (flags & G_IO_FLAG_IS_SEEKABLE) g_print ("%sSEEKABLE", bar), bar = "|"; } @@ -227,138 +266,25 @@ g_io_win32_get_debug_flag (void) return (getenv ("G_IO_WIN32_DEBUG") != NULL); } -static char * -winsock_error_message (int number) -{ - static char unk[100]; - - switch (number) { - case WSAEINTR: - return "Interrupted function call"; - case WSAEACCES: - return "Permission denied"; - case WSAEFAULT: - return "Bad address"; - case WSAEINVAL: - return "Invalid argument"; - case WSAEMFILE: - return "Too many open sockets"; - case WSAEWOULDBLOCK: - return "Resource temporarily unavailable"; - case WSAEINPROGRESS: - return "Operation now in progress"; - case WSAEALREADY: - return "Operation already in progress"; - case WSAENOTSOCK: - return "Socket operation on nonsocket"; - case WSAEDESTADDRREQ: - return "Destination address required"; - case WSAEMSGSIZE: - return "Message too long"; - case WSAEPROTOTYPE: - return "Protocol wrong type for socket"; - case WSAENOPROTOOPT: - return "Bad protocol option"; - case WSAEPROTONOSUPPORT: - return "Protocol not supported"; - case WSAESOCKTNOSUPPORT: - return "Socket type not supported"; - case WSAEOPNOTSUPP: - return "Operation not supported on transport endpoint"; - case WSAEPFNOSUPPORT: - return "Protocol family not supported"; - case WSAEAFNOSUPPORT: - return "Address family not supported by protocol family"; - case WSAEADDRINUSE: - return "Address already in use"; - case WSAEADDRNOTAVAIL: - return "Address not available"; - case WSAENETDOWN: - return "Network interface is not configured"; - case WSAENETUNREACH: - return "Network is unreachable"; - case WSAENETRESET: - return "Network dropped connection on reset"; - case WSAECONNABORTED: - return "Software caused connection abort"; - case WSAECONNRESET: - return "Connection reset by peer"; - case WSAENOBUFS: - return "No buffer space available"; - case WSAEISCONN: - return "Socket is already connected"; - case WSAENOTCONN: - return "Socket is not connected"; - case WSAESHUTDOWN: - return "Can't send after socket shutdown"; - case WSAETIMEDOUT: - return "Connection timed out"; - case WSAECONNREFUSED: - return "Connection refused"; - case WSAEHOSTDOWN: - return "Host is down"; - case WSAEHOSTUNREACH: - return "Host is unreachable"; - case WSAEPROCLIM: - return "Too many processes"; - case WSASYSNOTREADY: - return "Network subsystem is unavailable"; - case WSAVERNOTSUPPORTED: - return "Winsock.dll version out of range"; - case WSANOTINITIALISED: - return "Successful WSAStartup not yet performed"; - case WSAEDISCON: - return "Graceful shutdown in progress"; - case WSATYPE_NOT_FOUND: - return "Class type not found"; - case WSAHOST_NOT_FOUND: - return "Host not found"; - case WSATRY_AGAIN: - return "Nonauthoritative host not found"; - case WSANO_RECOVERY: - return "This is a nonrecoverable error"; - case WSANO_DATA: - return "Valid name, no data record of requested type"; - case WSA_INVALID_HANDLE: - return "Specified event object handle is invalid"; - case WSA_INVALID_PARAMETER: - return "One or more parameters are invalid"; - case WSA_IO_INCOMPLETE: - return "Overlapped I/O event object not in signaled state"; - case WSA_NOT_ENOUGH_MEMORY: - return "Insufficient memory available"; - case WSA_OPERATION_ABORTED: - return "Overlapped operation aborted"; - case WSAEINVALIDPROCTABLE: - return "Invalid procedure table from service provider"; - case WSAEINVALIDPROVIDER: - return "Invalid service provider version number"; - case WSAEPROVIDERFAILEDINIT: - return "Unable to initialize a service provider"; - case WSASYSCALLFAILURE: - return "System call failure"; - default: - sprintf (unk, "Unknown WinSock error %d", number); - return unk; - } -} - static void g_io_channel_win32_init (GIOWin32Channel *channel) { channel->debug = g_io_win32_get_debug_flag (); - channel->buffer = NULL; + + InitializeCriticalSection (&channel->mutex); channel->running = FALSE; channel->needs_close = FALSE; channel->thread_id = 0; channel->data_avail_event = NULL; channel->revents = 0; + channel->buffer = NULL; channel->space_avail_event = NULL; + channel->event_mask = 0; channel->last_events = 0; - channel->event = 0; + channel->event = NULL; channel->write_would_have_blocked = FALSE; - InitializeCriticalSection (&channel->mutex); + channel->ever_writable = FALSE; } static void @@ -377,6 +303,7 @@ create_events (GIOWin32Channel *channel) || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))) { gchar *emsg = g_win32_error_message (GetLastError ()); + g_error ("Error creating event: %s", emsg); g_free (emsg); } @@ -387,16 +314,16 @@ read_thread (void *parameter) { GIOWin32Channel *channel = parameter; guchar *buffer; - guint nbytes; + gint nbytes; g_io_channel_ref ((GIOChannel *)channel); if (channel->debug) - g_print ("read_thread %#x: start fd=%d, data_avail=%#x space_avail=%#x\n", + g_print ("read_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n", channel->thread_id, channel->fd, - (guint) channel->data_avail_event, - (guint) channel->space_avail_event); + channel->data_avail_event, + channel->space_avail_event); channel->direction = 0; channel->buffer = g_malloc (BUFFER_SIZE); @@ -405,7 +332,7 @@ read_thread (void *parameter) SetEvent (channel->space_avail_event); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); while (channel->running) { if (channel->debug) @@ -421,9 +348,9 @@ read_thread (void *parameter) if (channel->debug) g_print ("read_thread %#x: waiting for space\n", channel->thread_id); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); WaitForSingleObject (channel->space_avail_event, INFINITE); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->debug) g_print ("read_thread %#x: rdp=%d, wrp=%d\n", channel->thread_id, channel->rdp, channel->wrp); @@ -441,11 +368,11 @@ read_thread (void *parameter) g_print ("read_thread %#x: calling read() for %d bytes\n", channel->thread_id, nbytes); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); nbytes = read (channel->fd, buffer, nbytes); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); channel->revents = G_IO_IN; if (nbytes == 0) @@ -481,7 +408,7 @@ read_thread (void *parameter) 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); + LeaveCriticalSection (&channel->mutex); g_io_channel_unref ((GIOChannel *)channel); @@ -498,16 +425,16 @@ write_thread (void *parameter) { GIOWin32Channel *channel = parameter; guchar *buffer; - guint nbytes; + gint nbytes; g_io_channel_ref ((GIOChannel *)channel); if (channel->debug) - g_print ("write_thread %#x: start fd=%d, data_avail=%#x space_avail=%#x\n", + g_print ("write_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n", channel->thread_id, channel->fd, - (guint) channel->data_avail_event, - (guint) channel->space_avail_event); + channel->data_avail_event, + channel->space_avail_event); channel->direction = 1; channel->buffer = g_malloc (BUFFER_SIZE); @@ -522,7 +449,7 @@ write_thread (void *parameter) * write buffer. */ - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); while (channel->running || channel->rdp != channel->wrp) { if (channel->debug) @@ -540,10 +467,10 @@ write_thread (void *parameter) channel->thread_id); channel->revents = G_IO_OUT; SetEvent (channel->data_avail_event); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); WaitForSingleObject (channel->space_avail_event, INFINITE); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->rdp == channel->wrp) break; @@ -562,9 +489,9 @@ write_thread (void *parameter) g_print ("write_thread %#x: calling write() for %d bytes\n", channel->thread_id, nbytes); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); nbytes = write (channel->fd, buffer, nbytes); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->debug) g_print ("write_thread %#x: write(%i) returned %d, rdp=%d, wrp=%d\n", @@ -597,7 +524,7 @@ write_thread (void *parameter) channel->fd = -1; } - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); g_io_channel_unref ((GIOChannel *)channel); @@ -614,18 +541,22 @@ create_thread (GIOWin32Channel *channel, 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", + g_warning ("Error creating thread: %s.", g_strerror (errno)); else if (!CloseHandle (thread_handle)) - g_warning (G_STRLOC ": Error closing thread handle: %s\n", - g_win32_error_message (GetLastError ())); + { + gchar *emsg = g_win32_error_message (GetLastError ()); + + g_warning ("Error closing thread handle: %s.", emsg); + g_free (emsg); + } WaitForSingleObject (channel->space_avail_event, INFINITE); } static GIOStatus buffer_read (GIOWin32Channel *channel, - guchar *dest, + gchar *dest, gsize count, gsize *bytes_read, GError **err) @@ -633,25 +564,25 @@ buffer_read (GIOWin32Channel *channel, guint nbytes; guint left = count; - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->debug) - g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n", + g_print ("reading from thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n", channel->thread_id, count, channel->rdp, channel->wrp); if (channel->wrp == channel->rdp) { - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); if (channel->debug) g_print ("waiting for data from thread %#x\n", channel->thread_id); WaitForSingleObject (channel->data_avail_event, INFINITE); if (channel->debug) g_print ("done waiting for data from thread %#x\n", channel->thread_id); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->wrp == channel->rdp && !channel->running) { if (channel->debug) g_print ("wrp==rdp, !running\n"); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); *bytes_read = 0; return G_IO_STATUS_EOF; } @@ -661,7 +592,7 @@ buffer_read (GIOWin32Channel *channel, nbytes = channel->wrp - channel->rdp; else nbytes = BUFFER_SIZE - channel->rdp; - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); nbytes = MIN (left, nbytes); if (channel->debug) g_print ("moving %d bytes from thread %#x\n", @@ -669,7 +600,7 @@ buffer_read (GIOWin32Channel *channel, memcpy (dest, channel->buffer + channel->rdp, nbytes); dest += nbytes; left -= nbytes; - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE; if (channel->debug) g_print ("setting space_avail for thread %#x\n", channel->thread_id); @@ -684,7 +615,7 @@ buffer_read (GIOWin32Channel *channel, channel->thread_id); ResetEvent (channel->data_avail_event); }; - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); /* We have no way to indicate any errors form the actual * read() or recv() call in the reader thread. Should we have? @@ -696,7 +627,7 @@ buffer_read (GIOWin32Channel *channel, static GIOStatus buffer_write (GIOWin32Channel *channel, - const guchar *dest, + const gchar *dest, gsize count, gsize *bytes_written, GError **err) @@ -704,9 +635,9 @@ buffer_write (GIOWin32Channel *channel, guint nbytes; guint left = count; - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->debug) - g_print ("buffer_write: writing to thread %#x %d bytes, rdp=%d, wrp=%d\n", + g_print ("buffer_write: writing to thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n", channel->thread_id, count, channel->rdp, channel->wrp); if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) @@ -719,9 +650,9 @@ buffer_write (GIOWin32Channel *channel, if (channel->debug) g_print ("buffer_write: tid %#x: waiting for space\n", channel->thread_id); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); WaitForSingleObject (channel->data_avail_event, INFINITE); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->debug) g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d\n", channel->thread_id, channel->rdp, channel->wrp); @@ -730,7 +661,7 @@ buffer_write (GIOWin32Channel *channel, nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE, BUFFER_SIZE - channel->wrp); - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); nbytes = MIN (left, nbytes); if (channel->debug) g_print ("buffer_write: tid %#x: writing %d bytes\n", @@ -738,7 +669,7 @@ buffer_write (GIOWin32Channel *channel, memcpy (channel->buffer + channel->wrp, dest, nbytes); dest += nbytes; left -= nbytes; - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE; if (channel->debug) @@ -755,7 +686,7 @@ buffer_write (GIOWin32Channel *channel, ResetEvent (channel->data_avail_event); } - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); /* We have no way to indicate any errors form the actual * write() call in the writer thread. Should we have? @@ -776,29 +707,37 @@ g_io_win32_prepare (GSource *source, *timeout = -1; + if (channel->debug) + g_print ("g_io_win32_prepare: source=%p channel=%p", source, channel); + switch (channel->type) { case G_IO_WIN32_WINDOWS_MESSAGES: + if (channel->debug) + g_print (" MSG"); + break; + case G_IO_WIN32_CONSOLE: + if (channel->debug) + g_print (" CON"); break; case G_IO_WIN32_FILE_DESC: if (channel->debug) - g_print ("g_io_win32_prepare: for thread %#x buffer_condition:{%s}\n" - " watch->pollfd.events:{%s} watch->pollfd.revents:{%s} channel->revents:{%s}\n", + g_print (" FD thread=%#x buffer_condition:{%s}" + "\n watch->pollfd.events:{%s} watch->pollfd.revents:{%s} channel->revents:{%s}", channel->thread_id, condition_to_string (buffer_condition), condition_to_string (watch->pollfd.events), condition_to_string (watch->pollfd.revents), condition_to_string (channel->revents)); - LOCK (channel->mutex); + EnterCriticalSection (&channel->mutex); if (channel->running) { if (channel->direction == 0 && channel->wrp == channel->rdp) { if (channel->debug) - g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n", - channel->thread_id); + g_print ("\n setting revents=0"); channel->revents = 0; } } @@ -808,37 +747,52 @@ g_io_win32_prepare (GSource *source, && (channel->wrp + 1) % BUFFER_SIZE == channel->rdp) { if (channel->debug) - g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = %i\n", - channel->thread_id, 0); + g_print ("\n setting revents=0"); channel->revents = 0; } } - UNLOCK (channel->mutex); + LeaveCriticalSection (&channel->mutex); break; case G_IO_WIN32_SOCKET: + if (channel->debug) + g_print (" SOCK"); event_mask = 0; if (watch->condition & G_IO_IN) event_mask |= (FD_READ | FD_ACCEPT); if (watch->condition & G_IO_OUT) event_mask |= (FD_WRITE | FD_CONNECT); - if (watch->condition & G_IO_HUP) - event_mask |= FD_CLOSE; + event_mask |= FD_CLOSE; - if (channel->event_mask != event_mask /* || channel->event != watch->pollfd.fd*/) + if (channel->event_mask != event_mask) { if (channel->debug) - g_print ("g_io_win32_prepare: WSAEventSelect(%d, %#x, {%s}\n", - channel->fd, watch->pollfd.fd, + g_print ("\n WSAEventSelect(%d,%p,{%s})", + channel->fd, (HANDLE) watch->pollfd.fd, event_mask_to_string (event_mask)); if (WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, event_mask) == SOCKET_ERROR) - ; /* What? */ + if (channel->debug) + { + gchar *emsg = g_win32_error_message (WSAGetLastError ()); + + g_print (" failed: %s", emsg); + g_free (emsg); + } channel->event_mask = event_mask; -#if 0 - channel->event = watch->pollfd.fd; -#endif + + if (channel->debug) + g_print ("\n setting last_events=0"); channel->last_events = 0; + + if ((event_mask & FD_WRITE) && + channel->ever_writable && + !channel->write_would_have_blocked) + { + if (channel->debug) + g_print (" WSASetEvent(%p)", (WSAEVENT) watch->pollfd.fd); + WSASetEvent ((WSAEVENT) watch->pollfd.fd); + } } break; @@ -846,6 +800,9 @@ g_io_win32_prepare (GSource *source, g_assert_not_reached (); abort (); } + if (channel->debug) + g_print ("\n"); + return ((watch->condition & buffer_condition) == watch->condition); } @@ -858,14 +815,19 @@ g_io_win32_check (GSource *source) GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); WSANETWORKEVENTS events; + if (channel->debug) + g_print ("g_io_win32_check: source=%p channel=%p", source, channel); + switch (channel->type) { case G_IO_WIN32_WINDOWS_MESSAGES: + if (channel->debug) + g_print (" MSG\n"); return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE)); case G_IO_WIN32_FILE_DESC: if (channel->debug) - g_print ("g_io_win32_check: for thread %#x buffer_condition=%s\n" + g_print (" FD thread=%#x buffer_condition=%s\n" " watch->pollfd.events={%s} watch->pollfd.revents={%s} channel->revents={%s}\n", channel->thread_id, condition_to_string (buffer_condition), condition_to_string (watch->pollfd.events), @@ -877,6 +839,8 @@ g_io_win32_check (GSource *source) return ((watch->pollfd.revents | buffer_condition) & watch->condition); case G_IO_WIN32_CONSOLE: + if (channel->debug) + g_print (" CON\n"); if (watch->channel->is_writeable) return TRUE; else if (watch->channel->is_readable) @@ -900,21 +864,24 @@ g_io_win32_check (GSource *source) return FALSE; case G_IO_WIN32_SOCKET: + if (channel->debug) + g_print (" SOCK"); if (channel->last_events & FD_WRITE) { if (channel->debug) - g_print ("g_io_win32_check: sock=%d event=%#x last_events has FD_WRITE\n", - channel->fd, watch->pollfd.fd); + g_print (" sock=%d event=%p last_events has FD_WRITE", + channel->fd, (HANDLE) watch->pollfd.fd); } else { WSAEnumNetworkEvents (channel->fd, 0, &events); if (channel->debug) - g_print ("g_io_win32_check: WSAEnumNetworkEvents (%d, %#x) revents={%s} condition={%s} events={%s}\n", - channel->fd, watch->pollfd.fd, + g_print ("\n revents={%s} condition={%s}" + "\n WSAEnumNetworkEvents(%d,0) sets events={%s}", condition_to_string (watch->pollfd.revents), condition_to_string (watch->condition), + channel->fd, event_mask_to_string (events.lNetworkEvents)); if (watch->pollfd.revents != 0 && @@ -923,26 +890,56 @@ g_io_win32_check (GSource *source) { channel->event_mask = 0; if (channel->debug) - g_print ("g_io_win32_check: WSAEventSelect(%d, %#x, {})\n", - channel->fd, watch->pollfd.fd); + g_print ("\n WSAEventSelect(%d,%p,{})", + channel->fd, (HANDLE) watch->pollfd.fd); WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, 0); if (channel->debug) - g_print ("g_io_win32_check: ResetEvent(%#x)\n", - watch->pollfd.fd); + g_print (" ResetEvent(%p)", + (HANDLE) watch->pollfd.fd); ResetEvent ((HANDLE) watch->pollfd.fd); } + else if (events.lNetworkEvents & FD_WRITE) + channel->ever_writable = TRUE; channel->last_events = events.lNetworkEvents; } + watch->pollfd.revents = 0; if (channel->last_events & (FD_READ | FD_ACCEPT)) watch->pollfd.revents |= G_IO_IN; - if (channel->last_events & (FD_WRITE | FD_CONNECT)) + + if (channel->last_events & FD_WRITE) watch->pollfd.revents |= G_IO_OUT; - if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE))) - watch->pollfd.revents |= G_IO_HUP; + else + { + /* We have called WSAEnumNetworkEvents() above but it didn't + * set FD_WRITE. + */ + if (events.lNetworkEvents & FD_CONNECT) + { + if (events.iErrorCode[FD_CONNECT_BIT] == 0) + watch->pollfd.revents |= G_IO_OUT; + else + watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR); + } + if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE))) + watch->pollfd.revents |= G_IO_HUP; + } - if (!channel->write_would_have_blocked && (channel->event_mask & FD_WRITE)) - watch->pollfd.revents |= G_IO_OUT; /* This sucks but... */ + /* Regardless of WSAEnumNetworkEvents() result, if watching for + * writability, and if we have ever got a FD_WRITE event, and + * unless last write would have blocked, set G_IO_OUT. But never + * set both G_IO_OUT and G_IO_HUP. + */ + if (!(watch->pollfd.revents & G_IO_HUP) && + channel->ever_writable && + !channel->write_would_have_blocked && + (channel->event_mask & FD_WRITE)) + watch->pollfd.revents |= G_IO_OUT; + + if (channel->debug) + g_print ("\n revents={%s} retval={%s}\n", + condition_to_string (watch->pollfd.revents), + condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition)); return ((watch->pollfd.revents | buffer_condition) & watch->condition); @@ -964,7 +961,7 @@ g_io_win32_dispatch (GSource *source, if (!func) { - g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n" + g_warning ("IO Watch dispatched without callback\n" "You must call g_source_connect()."); return FALSE; } @@ -986,34 +983,37 @@ g_io_win32_finalize (GSource *source) GIOWin32Watch *watch = (GIOWin32Watch *)source; GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; + if (channel->debug) + g_print ("g_io_win32_finalize: source=%p channel=%p", source, channel); + switch (channel->type) { case G_IO_WIN32_WINDOWS_MESSAGES: + if (channel->debug) + g_print (" MSG"); + break; + case G_IO_WIN32_CONSOLE: + if (channel->debug) + g_print (" CON"); break; case G_IO_WIN32_FILE_DESC: - LOCK (channel->mutex); if (channel->debug) - g_print ("g_io_win32_finalize: channel with thread %#x\n", - channel->thread_id); - UNLOCK (channel->mutex); + g_print (" FD thread=%#x", channel->thread_id); break; case G_IO_WIN32_SOCKET: if (channel->debug) - g_print ("g_io_win32_finalize: channel is for sock=%d\n", channel->fd); -#if 0 - CloseHandle ((HANDLE) watch->pollfd.fd); - channel->event = 0; - channel->event_mask = 0; -#endif + g_print (" SOCK sock=%d", channel->fd); break; default: g_assert_not_reached (); abort (); } + if (channel->debug) + g_print ("\n"); g_io_channel_unref (watch->channel); } @@ -1036,14 +1036,14 @@ 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"); /* Informative enough error message? */ + g_set_error_literal (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", - (guint) win32_channel->hwnd); + g_print ("g_io_win32_msg_read: channel=%p hwnd=%p\n", + channel, win32_channel->hwnd); if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE)) return G_IO_STATUS_AGAIN; @@ -1065,8 +1065,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"); /* Informative enough error message? */ + g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, + "Incorrect message size"); /* Informative enough error message? */ return G_IO_STATUS_ERROR; } @@ -1075,8 +1075,10 @@ g_io_win32_msg_write (GIOChannel *channel, if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam)) { gchar *emsg = g_win32_error_message (GetLastError ()); - g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg); + + g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg); g_free (emsg); + return G_IO_STATUS_ERROR; } @@ -1100,17 +1102,57 @@ g_io_win32_free (GIOChannel *channel) GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; if (win32_channel->debug) - g_print ("g_io_win32_free channel fd=%d\n", win32_channel->fd); + g_print ("g_io_win32_free channel=%p fd=%d\n", channel, win32_channel->fd); - if (win32_channel->data_avail_event) - CloseHandle (win32_channel->data_avail_event); - if (win32_channel->space_avail_event) - CloseHandle (win32_channel->space_avail_event); - if (win32_channel->type == G_IO_WIN32_SOCKET) - WSAEventSelect (win32_channel->fd, NULL, 0); DeleteCriticalSection (&win32_channel->mutex); + if (win32_channel->data_avail_event) + if (!CloseHandle (win32_channel->data_avail_event)) + if (win32_channel->debug) + { + gchar *emsg = g_win32_error_message (GetLastError ()); + + g_print (" CloseHandle(%p) failed: %s\n", + win32_channel->data_avail_event, emsg); + g_free (emsg); + } + g_free (win32_channel->buffer); + + if (win32_channel->space_avail_event) + if (!CloseHandle (win32_channel->space_avail_event)) + if (win32_channel->debug) + { + gchar *emsg = g_win32_error_message (GetLastError ()); + + g_print (" CloseHandle(%p) failed: %s\n", + win32_channel->space_avail_event, emsg); + g_free (emsg); + } + + if (win32_channel->type == G_IO_WIN32_SOCKET && + win32_channel->fd != -1) + if (WSAEventSelect (win32_channel->fd, NULL, 0) == SOCKET_ERROR) + if (win32_channel->debug) + { + gchar *emsg = g_win32_error_message (WSAGetLastError ()); + + g_print (" WSAEventSelect(%d,NULL,{}) failed: %s\n", + win32_channel->fd, emsg); + g_free (emsg); + } + + if (win32_channel->event) + if (!WSACloseEvent (win32_channel->event)) + if (win32_channel->debug) + { + gchar *emsg = g_win32_error_message (WSAGetLastError ()); + + g_print (" WSACloseEvent(%p) failed: %s\n", + win32_channel->event, emsg); + g_free (emsg); + } + g_free (win32_channel); } @@ -1122,6 +1164,7 @@ g_io_win32_msg_create_watch (GIOChannel *channel, GSource *source; source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); + g_source_set_name (source, "GIOChannel (Win32)"); watch = (GIOWin32Watch *)source; watch->channel = channel; @@ -1129,7 +1172,7 @@ g_io_win32_msg_create_watch (GIOChannel *channel, watch->condition = condition; - watch->pollfd.fd = G_WIN32_MSG_HANDLE; + watch->pollfd.fd = (gintptr) G_WIN32_MSG_HANDLE; watch->pollfd.events = condition; g_source_add_poll (source, &watch->pollfd); @@ -1148,7 +1191,7 @@ g_io_win32_fd_and_console_read (GIOChannel *channel, gint result; if (win32_channel->debug) - g_print ("g_io_win32_fd_read: fd=%d count=%d\n", + g_print ("g_io_win32_fd_read: fd=%d count=%" G_GSIZE_FORMAT "\n", win32_channel->fd, count); if (win32_channel->thread_id) @@ -1172,9 +1215,9 @@ g_io_win32_fd_and_console_read (GIOChannel *channel, return G_IO_STATUS_AGAIN; #endif default: - g_set_error (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - g_strerror (errno)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (errno), + g_strerror (errno)); return G_IO_STATUS_ERROR; } } @@ -1201,7 +1244,7 @@ g_io_win32_fd_and_console_write (GIOChannel *channel, result = write (win32_channel->fd, buf, count); if (win32_channel->debug) - g_print ("g_io_win32_fd_write: fd=%d count=%d => %d\n", + g_print ("g_io_win32_fd_write: fd=%d count=%" G_GSIZE_FORMAT " => %d\n", win32_channel->fd, count, result); if (result < 0) @@ -1215,9 +1258,9 @@ g_io_win32_fd_and_console_write (GIOChannel *channel, return G_IO_STATUS_AGAIN; #endif default: - g_set_error (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - g_strerror (errno)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (errno), + g_strerror (errno)); return G_IO_STATUS_ERROR; } } @@ -1258,9 +1301,9 @@ g_io_win32_fd_seek (GIOChannel *channel, 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)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (EINVAL), + g_strerror (EINVAL)); return G_IO_STATUS_ERROR; } @@ -1268,9 +1311,9 @@ g_io_win32_fd_seek (GIOChannel *channel, if (result < 0) { - g_set_error (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - g_strerror (errno)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (errno), + g_strerror (errno)); return G_IO_STATUS_ERROR; } @@ -1284,10 +1327,10 @@ g_io_win32_fd_close (GIOChannel *channel, GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; if (win32_channel->debug) - g_print ("thread %#x: closing fd %d\n", + g_print ("g_io_win32_fd_close: thread=%#x: fd=%d\n", win32_channel->thread_id, win32_channel->fd); - LOCK (win32_channel->mutex); + EnterCriticalSection (&win32_channel->mutex); if (win32_channel->running) { if (win32_channel->debug) @@ -1310,7 +1353,7 @@ g_io_win32_fd_close (GIOChannel *channel, win32_channel->fd); win32_channel->fd = -1; } - UNLOCK (win32_channel->mutex); + LeaveCriticalSection (&win32_channel->mutex); /* FIXME error detection? */ @@ -1333,14 +1376,15 @@ g_io_win32_fd_create_watch (GIOChannel *channel, if (win32_channel->data_avail_event == NULL) create_events (win32_channel); - watch->pollfd.fd = (gint) win32_channel->data_avail_event; + watch->pollfd.fd = (gintptr) win32_channel->data_avail_event; watch->pollfd.events = condition; if (win32_channel->debug) - g_print ("g_io_win32_fd_create_watch: fd=%d condition={%s} handle=%#x\n", - win32_channel->fd, condition_to_string (condition), watch->pollfd.fd); + g_print ("g_io_win32_fd_create_watch: channel=%p fd=%d condition={%s} event=%p\n", + channel, win32_channel->fd, + condition_to_string (condition), (HANDLE) watch->pollfd.fd); - LOCK (win32_channel->mutex); + EnterCriticalSection (&win32_channel->mutex); if (win32_channel->thread_id == 0) { if (condition & G_IO_IN) @@ -1350,7 +1394,7 @@ g_io_win32_fd_create_watch (GIOChannel *channel, } g_source_add_poll (source, &watch->pollfd); - UNLOCK (win32_channel->mutex); + LeaveCriticalSection (&win32_channel->mutex); return source; } @@ -1363,9 +1407,9 @@ g_io_win32_console_close (GIOChannel *channel, if (close (win32_channel->fd) < 0) { - g_set_error (err, G_IO_CHANNEL_ERROR, - g_io_channel_error_from_errno (errno), - g_strerror (errno)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + g_io_channel_error_from_errno (errno), + g_strerror (errno)); return G_IO_STATUS_ERROR; } @@ -1385,7 +1429,7 @@ g_io_win32_console_create_watch (GIOChannel *channel, watch->condition = condition; - watch->pollfd.fd = (gint) _get_osfhandle (win32_channel->fd); + watch->pollfd.fd = _get_osfhandle (win32_channel->fd); watch->pollfd.events = condition; g_source_add_poll (source, &watch->pollfd); @@ -1406,20 +1450,23 @@ g_io_win32_sock_read (GIOChannel *channel, int winsock_error; if (win32_channel->debug) - g_print ("g_io_win32_sock_read: sockfd=%d count=%d\n", - win32_channel->fd, count); + g_print ("g_io_win32_sock_read: channel=%p sock=%d count=%" G_GSIZE_FORMAT, + channel, win32_channel->fd, count); result = recv (win32_channel->fd, buf, count, 0); if (result == SOCKET_ERROR) winsock_error = WSAGetLastError (); if (win32_channel->debug) - g_print ("g_io_win32_sock_read: recv=%d %s\n", - result, - (result == SOCKET_ERROR ? winsock_error_message (winsock_error) : "")); + g_print (" recv=%d", result); if (result == SOCKET_ERROR) { + gchar *emsg = g_win32_error_message (winsock_error); + + if (win32_channel->debug) + g_print (" %s\n", emsg); + *bytes_read = 0; switch (winsock_error) @@ -1428,17 +1475,21 @@ g_io_win32_sock_read (GIOChannel *channel, error = G_IO_CHANNEL_ERROR_INVAL; break; case WSAEWOULDBLOCK: + g_free (emsg); return G_IO_STATUS_AGAIN; default: error = G_IO_CHANNEL_ERROR_FAILED; break; } - g_set_error (err, G_IO_CHANNEL_ERROR, error, - winsock_error_message (winsock_error)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg); + g_free (emsg); + return G_IO_STATUS_ERROR; } else { + if (win32_channel->debug) + g_print ("\n"); *bytes_read = result; if (result == 0) return G_IO_STATUS_EOF; @@ -1460,20 +1511,23 @@ g_io_win32_sock_write (GIOChannel *channel, int winsock_error; if (win32_channel->debug) - g_print ("g_io_win32_sock_write: sockfd=%d count=%d\n", - win32_channel->fd, count); + g_print ("g_io_win32_sock_write: channel=%p sock=%d count=%" G_GSIZE_FORMAT, + channel, win32_channel->fd, count); result = send (win32_channel->fd, buf, count, 0); if (result == SOCKET_ERROR) winsock_error = WSAGetLastError (); if (win32_channel->debug) - g_print ("g_io_win32_sock_write: send=%d %s\n", - result, - (result == SOCKET_ERROR ? winsock_error_message (winsock_error) : "")); + g_print (" send=%d", result); if (result == SOCKET_ERROR) { + gchar *emsg = g_win32_error_message (winsock_error); + + if (win32_channel->debug) + g_print (" %s\n", emsg); + *bytes_written = 0; switch (winsock_error) @@ -1484,18 +1538,21 @@ g_io_win32_sock_write (GIOChannel *channel, case WSAEWOULDBLOCK: win32_channel->write_would_have_blocked = TRUE; win32_channel->last_events = 0; + g_free (emsg); return G_IO_STATUS_AGAIN; default: error = G_IO_CHANNEL_ERROR_FAILED; break; } - g_set_error (err, G_IO_CHANNEL_ERROR, error, - winsock_error_message (winsock_error)); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg); + g_free (emsg); return G_IO_STATUS_ERROR; } else { + if (win32_channel->debug) + g_print ("\n"); *bytes_written = result; win32_channel->write_would_have_blocked = FALSE; @@ -1512,8 +1569,8 @@ g_io_win32_sock_close (GIOChannel *channel, if (win32_channel->fd != -1) { if (win32_channel->debug) - g_print ("g_io_win32_sock_close: closing socket %d\n", - win32_channel->fd); + g_print ("g_io_win32_sock_close: channel=%p sock=%d\n", + channel, win32_channel->fd); closesocket (win32_channel->fd); win32_channel->fd = -1; @@ -1538,14 +1595,14 @@ g_io_win32_sock_create_watch (GIOChannel *channel, watch->condition = condition; if (win32_channel->event == 0) - win32_channel->event = (int) WSACreateEvent (); + win32_channel->event = WSACreateEvent (); - watch->pollfd.fd = win32_channel->event; + watch->pollfd.fd = (gintptr) win32_channel->event; watch->pollfd.events = condition; if (win32_channel->debug) - g_print ("g_io_win32_sock_create_watch: sock=%d handle=%#x condition={%s}\n", - win32_channel->fd, watch->pollfd.fd, + g_print ("g_io_win32_sock_create_watch: channel=%p sock=%d event=%p condition={%s}\n", + channel, win32_channel->fd, (HANDLE) watch->pollfd.fd, condition_to_string (watch->condition)); g_source_add_poll (source, &watch->pollfd); @@ -1566,7 +1623,8 @@ g_io_channel_new_file (const gchar *filename, MODE_W = 1 << 1, MODE_A = 1 << 2, MODE_PLUS = 1 << 3, - } mode_num; + }; + int mode_num; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (mode != NULL, NULL); @@ -1584,7 +1642,7 @@ g_io_channel_new_file (const gchar *filename, mode_num = MODE_A; break; default: - g_warning ("Invalid GIOFileMode %s.\n", mode); + g_warning ("Invalid GIOFileMode %s.", mode); return NULL; } @@ -1600,7 +1658,7 @@ g_io_channel_new_file (const gchar *filename, } /* Fall through */ default: - g_warning ("Invalid GIOFileMode %s.\n", mode); + g_warning ("Invalid GIOFileMode %s.", mode); return NULL; } @@ -1640,16 +1698,16 @@ g_io_channel_new_file (const gchar *filename, if (g_io_win32_get_debug_flag ()) { - g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename); + 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); } if (fid < 0) { - g_set_error (error, G_FILE_ERROR, - g_file_error_from_errno (errno), - g_strerror (errno)); + g_set_error_literal (error, G_FILE_ERROR, + g_file_error_from_errno (errno), + g_strerror (errno)); return (GIOChannel *)NULL; } @@ -1684,7 +1742,7 @@ g_io_channel_new_file (const gchar *filename, return channel; } -#ifdef G_OS_WIN32 +#if !defined (_WIN64) #undef g_io_channel_new_file @@ -1724,16 +1782,16 @@ g_io_win32_unimpl_set_flags (GIOChannel *channel, g_print ("\n"); } - g_set_error (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - "Not implemented on Win32"); + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + G_IO_CHANNEL_ERROR_FAILED, + "Not implemented on Win32"); return G_IO_STATUS_ERROR; } static GIOFlags -g_io_win32_fd_get_flags_internal (GIOChannel *channel, - struct stat *st) +g_io_win32_fd_get_flags_internal (GIOChannel *channel, + struct _stati64 *st) { GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; gchar c; @@ -1765,13 +1823,13 @@ g_io_win32_fd_get_flags_internal (GIOChannel *channel, static GIOFlags g_io_win32_fd_get_flags (GIOChannel *channel) { - struct stat st; + struct _stati64 st; GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; g_return_val_if_fail (win32_channel != NULL, 0); g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0); - if (0 == fstat (win32_channel->fd, &st)) + if (0 == _fstati64 (win32_channel->fd, &st)) return g_io_win32_fd_get_flags_internal (channel, &st); else return 0; @@ -1830,9 +1888,13 @@ g_io_win32_sock_set_flags (GIOChannel *channel, arg = 1; if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR) { - g_set_error (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - winsock_error_message (WSAGetLastError ())); + gchar *emsg = g_win32_error_message (WSAGetLastError ()); + + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + G_IO_CHANNEL_ERROR_FAILED, + emsg); + g_free (emsg); + return G_IO_STATUS_ERROR; } } @@ -1841,9 +1903,13 @@ g_io_win32_sock_set_flags (GIOChannel *channel, arg = 0; if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR) { - g_set_error (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - winsock_error_message (WSAGetLastError ())); + gchar *emsg = g_win32_error_message (WSAGetLastError ()); + + g_set_error_literal (err, G_IO_CHANNEL_ERROR, + G_IO_CHANNEL_ERROR_FAILED, + emsg); + g_free (emsg); + return G_IO_STATUS_ERROR; } } @@ -1902,8 +1968,23 @@ static GIOFuncs win32_channel_sock_funcs = { g_io_win32_sock_get_flags, }; +/** + * g_io_channel_win32_new_messages: + * @hwnd: a window handle. + * + * Creates a new #GIOChannel given a window handle on Windows. + * + * This function creates a #GIOChannel that can be used to poll for + * Windows messages for the window in question. + * + * Returns: a new #GIOChannel. + **/ GIOChannel * +#if GLIB_SIZEOF_VOID_P == 8 +g_io_channel_win32_new_messages (gsize hwnd) +#else g_io_channel_win32_new_messages (guint hwnd) +#endif { GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1); GIOChannel *channel = (GIOChannel *)win32_channel; @@ -1911,7 +1992,8 @@ g_io_channel_win32_new_messages (guint hwnd) 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=%#x\n", hwnd); + g_print ("g_io_channel_win32_new_messages: channel=%p hwnd=%p\n", + channel, (HWND) hwnd); channel->funcs = &win32_channel_msg_funcs; win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES; win32_channel->hwnd = (HWND) hwnd; @@ -1926,8 +2008,8 @@ g_io_channel_win32_new_messages (guint hwnd) } static GIOChannel * -g_io_channel_win32_new_fd_internal (gint fd, - struct stat *st) +g_io_channel_win32_new_fd_internal (gint fd, + struct _stati64 *st) { GIOWin32Channel *win32_channel; GIOChannel *channel; @@ -1941,7 +2023,9 @@ g_io_channel_win32_new_fd_internal (gint fd, win32_channel->fd = fd; if (win32_channel->debug) - g_print ("g_io_channel_win32_new_fd: %u\n", fd); + g_print ("g_io_channel_win32_new_fd: channel=%p fd=%u\n", + channel, fd); + if (st->st_mode & _S_IFCHR) /* console */ { channel->funcs = &win32_channel_console_funcs; @@ -1958,14 +2042,43 @@ g_io_channel_win32_new_fd_internal (gint fd, return channel; } +/** + * g_io_channel_win32_new_fd: + * @fd: a C library file descriptor. + * + * Creates a new #GIOChannel given a file descriptor on Windows. This + * works for file descriptors from the C runtime. + * + * This function works for file descriptors as returned by the open(), + * creat(), pipe() and fileno() calls in the Microsoft C runtime. In + * order to meaningfully use this function your code should use the + * same C runtime as GLib uses, which is msvcrt.dll. Note that in + * current Microsoft compilers it is near impossible to convince it to + * build code that would use msvcrt.dll. The last Microsoft compiler + * version that supported using msvcrt.dll as the C runtime was version + * 6. The GNU compiler and toolchain for Windows, also known as Mingw, + * fully supports msvcrt.dll. + * + * If you have created a #GIOChannel for a file descriptor and started + * watching (polling) it, you shouldn't call read() on the file + * descriptor. This is because adding polling for a file descriptor is + * implemented in GLib on Windows 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(). + * + * This function is available only in GLib on Windows. + * + * Returns: a new #GIOChannel. + **/ GIOChannel * g_io_channel_win32_new_fd (gint fd) { - struct stat st; + struct _stati64 st; - if (fstat (fd, &st) == -1) + if (_fstati64 (fd, &st) == -1) { - g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd); + g_warning ("g_io_channel_win32_new_fd: %d isn't an open file descriptor in the C library GLib uses.", fd); return NULL; } @@ -1980,6 +2093,21 @@ g_io_channel_win32_get_fd (GIOChannel *channel) return win32_channel->fd; } +/** + * g_io_channel_win32_new_socket: + * @socket: a Winsock socket + * + * Creates a new #GIOChannel given a socket on Windows. + * + * This function works for sockets created by Winsock. It's available + * only in GLib on Windows. + * + * Polling a #GSource created to watch a channel for a socket puts the + * socket in non-blocking mode. This is a side-effect of the + * implementation and unavoidable. + * + * Returns: a new #GIOChannel + **/ GIOChannel * g_io_channel_win32_new_socket (int socket) { @@ -1989,7 +2117,8 @@ g_io_channel_win32_new_socket (int socket) g_io_channel_init (channel); g_io_channel_win32_init (win32_channel); if (win32_channel->debug) - g_print ("g_io_channel_win32_new_socket: sockfd=%d\n", socket); + g_print ("g_io_channel_win32_new_socket: channel=%p sock=%d\n", + channel, socket); channel->funcs = &win32_channel_sock_funcs; win32_channel->type = G_IO_WIN32_SOCKET; win32_channel->fd = socket; @@ -2005,16 +2134,16 @@ GIOChannel * g_io_channel_unix_new (gint fd) { gboolean is_fd, is_socket; - struct stat st; + struct _stati64 st; int optval, optlen; - is_fd = (fstat (fd, &st) == 0); + is_fd = (_fstati64 (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); + g_warning ("g_io_channel_unix_new: %d is both a file descriptor and a socket. File descriptor interpretation assumed. To avoid ambiguity, call either g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket() instead.", fd); if (is_fd) return g_io_channel_win32_new_fd_internal (fd, &st); @@ -2022,7 +2151,7 @@ g_io_channel_unix_new (gint fd) 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); + g_warning ("g_io_channel_unix_new: %d is neither a file descriptor or a socket.", fd); return NULL; } @@ -2047,13 +2176,9 @@ g_io_channel_win32_poll (GPollFD *fds, gint n_fds, gint timeout) { - int result; - g_return_val_if_fail (n_fds >= 0, 0); - result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout); - - return result; + return g_poll (fds, n_fds, timeout); } void @@ -2069,10 +2194,16 @@ g_io_channel_win32_make_pollfd (GIOChannel *channel, if (win32_channel->data_avail_event == NULL) create_events (win32_channel); - fd->fd = (gint) win32_channel->data_avail_event; + fd->fd = (gintptr) win32_channel->data_avail_event; - if (win32_channel->thread_id == 0 && (condition & G_IO_IN)) + if (win32_channel->thread_id == 0) { + /* Is it meaningful for a file descriptor to be polled for + * both IN and OUT? For what kind of file descriptor would + * that be? Doesn't seem to make sense, in practise the file + * descriptors handled here are always read or write ends of + * pipes surely, and thus unidirectional. + */ if (condition & G_IO_IN) create_thread (win32_channel, condition, read_thread); else if (condition & G_IO_OUT) @@ -2081,11 +2212,11 @@ g_io_channel_win32_make_pollfd (GIOChannel *channel, break; case G_IO_WIN32_CONSOLE: - fd->fd = (gint) _get_osfhandle (win32_channel->fd); + fd->fd = _get_osfhandle (win32_channel->fd); break; case G_IO_WIN32_SOCKET: - fd->fd = (int) WSACreateEvent (); + fd->fd = (gintptr) WSACreateEvent (); break; case G_IO_WIN32_WINDOWS_MESSAGES: @@ -2100,6 +2231,8 @@ g_io_channel_win32_make_pollfd (GIOChannel *channel, fd->events = condition; } +#ifndef _WIN64 + /* Binary compatibility */ GIOChannel * g_io_channel_win32_new_stream_socket (int socket) @@ -2107,5 +2240,4 @@ g_io_channel_win32_new_stream_socket (int socket) return g_io_channel_win32_new_socket (socket); } -#define __G_IO_WIN32_C__ -#include "galiasdef.c" +#endif