f2123727f8dfb36e1ce3fdd46f61fffa4eec51a0
[platform/upstream/glib.git] / glib / giowin32.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * giowin32.c: IO Channels for Win32.
5  * Copyright 1998 Owen Taylor and Tor Lillqvist
6  * Copyright 1999-2000 Tor Lillqvist and Craig Setera
7  * Copyright 2001-2003 Andrew Lanoix
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /*
26  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GLib Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GLib at ftp://ftp.gtk.org/pub/gtk/.
30  */
31
32 /* Define this to get (very) verbose logging of all channels */
33 /* #define G_IO_WIN32_DEBUG */
34
35 #include "config.h"
36
37 #include "glib.h"
38
39 #include <stdlib.h>
40 #include <windows.h>
41 #include <winsock.h>          /* Not everybody has winsock2 */
42 #include <fcntl.h>
43 #include <io.h>
44 #include <process.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47
48 #include "glibintl.h"
49
50 typedef struct _GIOWin32Channel GIOWin32Channel;
51 typedef struct _GIOWin32Watch GIOWin32Watch;
52
53 #define BUFFER_SIZE 4096
54
55 typedef enum {
56   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
57   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
58                                  * _open() or _pipe(). Read with read().
59                                  * Have to create separate thread to read.
60                                  */
61   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
62                                  * in select() most of the time.
63                                  */
64 } GIOWin32ChannelType;
65
66 struct _GIOWin32Channel {
67   GIOChannel channel;
68   gint fd;                      /* Either a Unix-like file handle as provided
69                                  * by the Microsoft C runtime, or a SOCKET
70                                  * as provided by WinSock.
71                                  */
72   GIOWin32ChannelType type;
73   
74   gboolean debug;
75
76   CRITICAL_SECTION mutex;
77
78   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
79   HWND hwnd;                    /* handle of window, or NULL */
80   
81   /* Following fields are used by both fd and socket channels. */
82   gboolean running;             /* Is reader thread running. FALSE if
83                                  * EOF has been reached.
84                                  */
85   gboolean needs_close;         /* If the channel has been closed while
86                                  * the reader thread was still running.
87                                  */
88   guint thread_id;              /* If non-NULL has a reader thread, or has
89                                  * had.*/
90   HANDLE data_avail_event;
91
92   gushort revents;
93
94   /* Following fields used by fd channels for input */
95   
96   /* Data is kept in a circular buffer. To be able to distinguish between
97    * empty and full buffer, we cannot fill it completely, but have to
98    * leave a one character gap.
99    *
100    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
101    *
102    * Empty:    wrp == rdp
103    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
104    * Partial:  otherwise
105    */
106   guchar *buffer;               /* (Circular) buffer */
107   gint wrp, rdp;                /* Buffer indices for writing and reading */
108   HANDLE space_avail_event;
109
110   /* Following fields used by socket channels */
111   GSList *watches;
112   HANDLE data_avail_noticed_event;
113   gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */
114   gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */
115 };
116
117 #define LOCK(mutex) EnterCriticalSection (&mutex)
118 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
119
120 struct _GIOWin32Watch {
121   GSource       source;
122   GPollFD       pollfd;
123   GIOChannel   *channel;
124   GIOCondition  condition;
125 };
126
127 static void
128 g_win32_print_access_mode (int flags)
129 {
130   g_print ("%s%s%s%s%s%s%s%s%s%s",
131            ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
132             ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
133              ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
134            (flags & _O_APPEND ? "|O_APPEND" : ""),
135            (flags & _O_RANDOM ? "|O_RANDOM" : ""),
136            (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
137            (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
138            (flags & _O_CREAT ? "|O_CREAT" : ""),
139            (flags & _O_TRUNC ? "|O_TRUNC" : ""),
140            (flags & _O_EXCL ? "|O_EXCL" : ""),
141            (flags & _O_TEXT ? "|O_TEXT" : ""),
142            (flags & _O_BINARY ? "|O_BINARY" : ""));
143 }
144
145 static void
146 g_win32_print_gioflags (GIOFlags flags)
147 {
148   char *bar = "";
149
150   if (flags & G_IO_FLAG_APPEND)
151     bar = "|", g_print ("APPEND");
152   if (flags & G_IO_FLAG_NONBLOCK)
153     g_print ("%sNONBLOCK", bar), bar = "|";
154   if (flags & G_IO_FLAG_IS_READABLE)
155     g_print ("%sREADABLE", bar), bar = "|";
156   if (flags & G_IO_FLAG_IS_WRITEABLE)
157     g_print ("%sWRITEABLE", bar), bar = "|";
158   if (flags & G_IO_FLAG_IS_WRITEABLE)
159     g_print ("%sWRITEABLE", bar), bar = "|";
160   if (flags & G_IO_FLAG_IS_SEEKABLE)
161     g_print ("%sSEEKABLE", bar), bar = "|";
162 }
163
164 static gboolean
165 g_io_win32_get_debug_flag (void)
166 {
167 #ifdef G_IO_WIN32_DEBUG
168   return TRUE;
169 #else
170   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
171     return TRUE;
172   else
173     return FALSE;
174 #endif
175 }  
176
177 static void
178 g_io_channel_win32_init (GIOWin32Channel *channel)
179 {
180   channel->debug = g_io_win32_get_debug_flag ();
181   channel->buffer = NULL;
182   channel->running = FALSE;
183   channel->needs_close = FALSE;
184   channel->thread_id = 0;
185   channel->data_avail_event = NULL;
186   channel->revents = 0;
187   channel->space_avail_event = NULL;
188   channel->data_avail_noticed_event = NULL;
189   channel->watches = NULL;
190   InitializeCriticalSection (&channel->mutex);
191 }
192
193 static void
194 create_events (GIOWin32Channel *channel)
195 {
196   SECURITY_ATTRIBUTES sec_attrs;
197   
198   sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
199   sec_attrs.lpSecurityDescriptor = NULL;
200   sec_attrs.bInheritHandle = FALSE;
201
202   /* The data available event is manual reset, the space available event
203    * is automatic reset.
204    */
205   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
206       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
207       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
208     {
209       gchar *emsg = g_win32_error_message (GetLastError ());
210       g_error ("Error creating event: %s", emsg);
211       g_free (emsg);
212     }
213 }
214
215 static unsigned __stdcall
216 read_thread (void *parameter)
217 {
218   GIOWin32Channel *channel = parameter;
219   guchar *buffer;
220   guint nbytes;
221
222   g_io_channel_ref ((GIOChannel *)channel);
223
224   if (channel->debug)
225     g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
226              channel->thread_id,
227              channel->fd,
228              (guint) channel->data_avail_event,
229              (guint) channel->space_avail_event);
230   
231   channel->buffer = g_malloc (BUFFER_SIZE);
232   channel->rdp = channel->wrp = 0;
233   channel->running = TRUE;
234
235   SetEvent (channel->space_avail_event);
236   
237   while (channel->running)
238     {
239       LOCK (channel->mutex);
240       if (channel->debug)
241         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
242                  channel->thread_id, channel->rdp, channel->wrp);
243       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
244         {
245           /* Buffer is full */
246           if (channel->debug)
247             g_print ("read_thread %#x: resetting space_avail\n",
248                      channel->thread_id);
249           ResetEvent (channel->space_avail_event);
250           if (channel->debug)
251             g_print ("read_thread %#x: waiting for space\n",
252                      channel->thread_id);
253           UNLOCK (channel->mutex);
254           WaitForSingleObject (channel->space_avail_event, INFINITE);
255           LOCK (channel->mutex);
256           if (channel->debug)
257             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
258                      channel->thread_id, channel->rdp, channel->wrp);
259         }
260       
261       buffer = channel->buffer + channel->wrp;
262       
263       /* Always leave at least one byte unused gap to be able to
264        * distinguish between the full and empty condition...
265        */
266       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
267                     BUFFER_SIZE - channel->wrp);
268
269       if (channel->debug)
270         g_print ("read_thread %#x: calling read() for %d bytes\n",
271                  channel->thread_id, nbytes);
272
273       UNLOCK (channel->mutex);
274
275       nbytes = read (channel->fd, buffer, nbytes);
276       
277       LOCK (channel->mutex);
278
279       channel->revents = G_IO_IN;
280       if (nbytes == 0)
281         channel->revents |= G_IO_HUP;
282       else if (nbytes < 0)
283         channel->revents |= G_IO_ERR;
284
285       if (channel->debug)
286         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
287                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
288
289       if (nbytes <= 0)
290         break;
291
292       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
293       if (channel->debug)
294         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
295                  channel->thread_id, channel->rdp, channel->wrp);
296       SetEvent (channel->data_avail_event);
297       UNLOCK (channel->mutex);
298     }
299   
300   channel->running = FALSE;
301   if (channel->needs_close)
302     {
303       if (channel->debug)
304         g_print ("read_thread %#x: channel fd %d needs closing\n",
305                  channel->thread_id, channel->fd);
306       close (channel->fd);
307       channel->fd = -1;
308     }
309
310   if (channel->debug)
311     g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
312              channel->thread_id, channel->rdp, channel->wrp);
313   SetEvent (channel->data_avail_event);
314   UNLOCK (channel->mutex);
315   
316   g_io_channel_unref ((GIOChannel *)channel);
317   
318   /* No need to call _endthreadex(), the actual thread starter routine
319    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
320    * _endthreadex() for us.
321    */
322
323   return 0;
324 }
325
326 static void
327 create_thread (GIOWin32Channel     *channel,
328                GIOCondition         condition,
329                unsigned (__stdcall *thread) (void *parameter))
330 {
331   HANDLE thread_handle;
332
333   thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
334                                            &channel->thread_id);
335   if (thread_handle == 0)
336     g_warning (G_STRLOC ": Error creating reader thread: %s",
337                g_strerror (errno));
338   else if (!CloseHandle (thread_handle))
339     g_warning (G_STRLOC ": Error closing thread handle: %s\n",
340                g_win32_error_message (GetLastError ()));
341
342   WaitForSingleObject (channel->space_avail_event, INFINITE);
343 }
344
345 static void
346 init_reset_sockets (GIOWin32Channel *channel)
347 {
348   struct sockaddr_in local, local2, server;
349   int len;
350
351   channel->reset_send = (gint) socket (AF_INET, SOCK_DGRAM, 0);
352   if (channel->reset_send == INVALID_SOCKET)
353     {
354       g_warning (G_STRLOC ": Error creating reset_send socket: %s\n",
355                  g_win32_error_message (WSAGetLastError ()));
356     }
357
358   local.sin_family = AF_INET;
359   local.sin_port = 0;
360   local.sin_addr.s_addr = htonl (INADDR_ANY);
361
362   if (bind (channel->reset_send, (struct sockaddr *)&local, sizeof (local)) == SOCKET_ERROR)
363     {
364       g_warning (G_STRLOC ": Error binding to reset_send socket: %s\n",
365                  g_win32_error_message (WSAGetLastError ()));
366   }
367
368   local2.sin_family = AF_INET;
369   local2.sin_port = 0;
370   local2.sin_addr.s_addr = htonl (INADDR_ANY);
371
372   channel->reset_recv = (gint) socket (AF_INET, SOCK_DGRAM, 0);
373   if (channel->reset_recv == INVALID_SOCKET)
374     {
375       g_warning (G_STRLOC ": Error creating reset_recv socket: %s\n",
376                  g_win32_error_message (WSAGetLastError ()));
377   }
378
379   if (bind (channel->reset_recv, (struct sockaddr *)&local2, sizeof (local)) == SOCKET_ERROR)
380     {
381       g_warning (G_STRLOC ": Error binding to reset_recv socket: %s\n",
382                  g_win32_error_message (WSAGetLastError ()));
383     }
384   
385   len = sizeof (local2);
386   if (getsockname (channel->reset_recv, (struct sockaddr *)&local2, &len) == SOCKET_ERROR)
387     {
388       g_warning (G_STRLOC ": Error getsockname with reset_recv socket: %s\n",
389                  g_win32_error_message (WSAGetLastError ()));
390     }
391
392   memset (&server, 0, sizeof (server));
393   server.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
394   server.sin_family = AF_INET;
395   server.sin_port = local2.sin_port;
396
397   if (connect (channel->reset_send, (struct sockaddr  *)&server, sizeof (server)) == SOCKET_ERROR)
398     {
399       g_warning (G_STRLOC ": connect to reset_recv socket: %s\n",
400                  g_win32_error_message (WSAGetLastError ()));
401   }
402
403 }
404
405 static GIOStatus
406 buffer_read (GIOWin32Channel *channel,
407              guchar          *dest,
408              gsize            count,
409              gsize           *bytes_read,
410              GError         **err)
411 {
412   guint nbytes;
413   guint left = count;
414   
415   LOCK (channel->mutex);
416   if (channel->debug)
417     g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
418              channel->thread_id, count, channel->rdp, channel->wrp);
419   
420   if (channel->wrp == channel->rdp)
421     {
422       UNLOCK (channel->mutex);
423       if (channel->debug)
424         g_print ("waiting for data from thread %#x\n", channel->thread_id);
425       WaitForSingleObject (channel->data_avail_event, INFINITE);
426       if (channel->debug)
427         g_print ("done waiting for data from thread %#x\n", channel->thread_id);
428       LOCK (channel->mutex);
429       if (channel->wrp == channel->rdp && !channel->running)
430         {
431           if (channel->debug)
432             g_print ("wrp==rdp, !running\n");
433           UNLOCK (channel->mutex);
434           *bytes_read = 0;
435           return G_IO_STATUS_EOF;
436         }
437     }
438   
439   if (channel->rdp < channel->wrp)
440     nbytes = channel->wrp - channel->rdp;
441   else
442     nbytes = BUFFER_SIZE - channel->rdp;
443   UNLOCK (channel->mutex);
444   nbytes = MIN (left, nbytes);
445   if (channel->debug)
446     g_print ("moving %d bytes from thread %#x\n",
447              nbytes, channel->thread_id);
448   memcpy (dest, channel->buffer + channel->rdp, nbytes);
449   dest += nbytes;
450   left -= nbytes;
451   LOCK (channel->mutex);
452   channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
453   if (channel->debug)
454     g_print ("setting space_avail for thread %#x\n", channel->thread_id);
455   SetEvent (channel->space_avail_event);
456   if (channel->debug)
457     g_print ("for thread %#x: rdp=%d, wrp=%d\n",
458              channel->thread_id, channel->rdp, channel->wrp);
459   if (channel->running && channel->wrp == channel->rdp)
460     {
461       if (channel->debug)
462         g_print ("resetting data_avail of thread %#x\n",
463                  channel->thread_id);
464       ResetEvent (channel->data_avail_event);
465     };
466   UNLOCK (channel->mutex);
467   
468   /* We have no way to indicate any errors form the actual
469    * read() or recv() call in the reader thread. Should we have?
470    */
471   *bytes_read = count - left;
472   return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
473 }
474
475 static unsigned __stdcall
476 select_thread (void *parameter)
477 {
478   GIOWin32Channel *channel = parameter;
479   fd_set read_fds, write_fds, except_fds;
480   GSList *tmp;
481   int n;
482   char buffer[8];
483
484   g_io_channel_ref ((GIOChannel *)channel);
485
486   if (channel->debug)
487     g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n",
488              channel->thread_id,
489              channel->fd,
490              (guint) channel->data_avail_event,
491              (guint) channel->data_avail_noticed_event);
492   
493   channel->rdp = channel->wrp = 0;
494   channel->running = TRUE;
495
496   SetEvent (channel->space_avail_event);
497   
498   while (channel->running)
499     {
500       FD_ZERO (&read_fds);
501       FD_ZERO (&write_fds);
502       FD_ZERO (&except_fds);
503       FD_SET (channel->reset_recv, &read_fds);
504
505       LOCK (channel->mutex);
506       tmp = channel->watches;
507       while (tmp)
508         {
509           GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
510
511           if (watch->condition & (G_IO_IN | G_IO_HUP))
512             FD_SET (channel->fd, &read_fds);
513           if (watch->condition & G_IO_OUT)
514             FD_SET (channel->fd, &write_fds);
515           if (watch->condition & G_IO_ERR)
516             FD_SET (channel->fd, &except_fds);
517           
518           tmp = tmp->next;
519         }
520       UNLOCK (channel->mutex);
521
522       if (channel->debug)
523         g_print ("select_thread %#x: calling select() for%s%s%s\n",
524                  channel->thread_id,
525                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
526                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
527                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
528       
529       n = select (1, &read_fds, &write_fds, &except_fds, NULL);
530       
531       LOCK (channel->mutex);
532       if (channel->needs_close)
533         {
534           UNLOCK (channel->mutex);
535           break;
536         }
537       UNLOCK (channel->mutex);
538
539       if (n == SOCKET_ERROR)
540         {
541           if (channel->debug)
542             g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
543                      channel->thread_id);
544           break;
545         }
546
547     if (FD_ISSET (channel->reset_recv, &read_fds))
548     {
549       if (channel->debug)
550         g_print ("select_thread %#x: re-looping\n",
551             channel->thread_id);
552       recv (channel->reset_recv,  (char *)&buffer, (int) sizeof (buffer), 0);
553       continue;
554     }
555
556     if (channel->debug)
557       g_print ("select_thread %#x: got%s%s%s\n",
558                channel->thread_id,
559                (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
560                (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
561                (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
562     
563     if (FD_ISSET (channel->fd, &read_fds))
564       channel->revents |= G_IO_IN;
565     if (FD_ISSET (channel->fd, &write_fds))
566       channel->revents |= G_IO_OUT;
567     if (FD_ISSET (channel->fd, &except_fds))
568       channel->revents |= G_IO_ERR;
569
570     if (channel->debug)
571       g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n",
572                channel->thread_id);
573
574     LOCK (channel->mutex);
575     ResetEvent (channel->data_avail_noticed_event);
576     SetEvent (channel->data_avail_event);
577     if (channel->needs_close)
578       {
579         UNLOCK (channel->mutex);
580         break;
581       }
582     UNLOCK (channel->mutex);
583
584     if (channel->debug)
585       g_print ("select_thread %#x: waiting for data_avail_noticed\n",
586         channel->thread_id);
587
588     WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
589     if (channel->debug)
590       g_print ("select_thread %#x: got data_avail_noticed\n",
591                  channel->thread_id);
592     }
593
594   LOCK (channel->mutex);
595   channel->running = FALSE;
596   if (channel->debug)
597     g_print ("select_thread %#x: got error, setting data_avail\n",
598              channel->thread_id);
599   SetEvent (channel->data_avail_event);
600   g_io_channel_unref ((GIOChannel *)channel);
601   UNLOCK (channel->mutex);
602
603   /* No need to call _endthreadex(), the actual thread starter routine
604    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
605    * _endthreadex() for us.
606    */
607
608   return 0;
609 }
610
611 static gboolean
612 g_io_win32_prepare (GSource *source,
613                     gint    *timeout)
614 {
615   GIOWin32Watch *watch = (GIOWin32Watch *)source;
616   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
617   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
618   
619   *timeout = -1;
620   
621   if (channel->debug)
622     g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n"
623              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
624              channel->thread_id, buffer_condition,
625              watch->pollfd.events, watch->pollfd.revents, channel->revents);
626
627   if (channel->type == G_IO_WIN32_FILE_DESC)
628     {
629       LOCK (channel->mutex);
630       if (channel->running && channel->wrp == channel->rdp)
631         {
632           if (channel->debug)
633             g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
634                      channel->thread_id);
635           channel->revents = 0;
636         }
637       UNLOCK (channel->mutex);
638     }
639   else if (channel->type == G_IO_WIN32_SOCKET)
640     {
641       LOCK (channel->mutex);
642       channel->revents = 0;
643       if (channel->debug)
644         g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n",
645                  channel->thread_id);
646       SetEvent (channel->data_avail_noticed_event);
647       if (channel->debug)
648         g_print ("g_io_win32_prepare: thread %#x, there.\n",
649                  channel->thread_id);
650       UNLOCK (channel->mutex);
651     }
652
653   return ((watch->condition & buffer_condition) == watch->condition);
654 }
655
656 static gboolean
657 g_io_win32_check (GSource *source)
658 {
659   MSG msg;
660   GIOWin32Watch *watch = (GIOWin32Watch *)source;
661   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
662   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
663
664   if (channel->debug)
665     g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n"
666              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
667              channel->thread_id, buffer_condition,
668              watch->pollfd.events, watch->pollfd.revents, channel->revents);
669
670   if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
671     {
672       watch->pollfd.revents = (watch->pollfd.events & channel->revents);
673     }
674   else
675     {
676       return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
677     }
678   
679   if (channel->type == G_IO_WIN32_SOCKET)
680     {
681       LOCK (channel->mutex);
682       if (channel->debug)
683         g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
684                  channel->thread_id);
685       ResetEvent (channel->data_avail_event);
686       if (channel->debug)
687         g_print ("g_io_win32_check: thread %#x, there.\n",
688                  channel->thread_id);
689       UNLOCK (channel->mutex);
690     }
691
692   return ((watch->pollfd.revents | buffer_condition) & watch->condition);
693 }
694
695 static gboolean
696 g_io_win32_dispatch (GSource     *source,
697                      GSourceFunc  callback,
698                      gpointer     user_data)
699 {
700   GIOFunc func = (GIOFunc)callback;
701   GIOWin32Watch *watch = (GIOWin32Watch *)source;
702   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
703   
704   if (!func)
705     {
706       g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
707                  "You must call g_source_connect().");
708       return FALSE;
709     }
710   
711   return (*func) (watch->channel,
712                   (watch->pollfd.revents | buffer_condition) & watch->condition,
713                   user_data);
714 }
715
716 static void
717 g_io_win32_finalize (GSource *source)
718 {
719   GIOWin32Watch *watch = (GIOWin32Watch *)source;
720   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
721   char send_buffer[] = "f";
722   
723   LOCK (channel->mutex);
724   if (channel->debug)
725     g_print ("g_io_win32_finalize: channel with thread %#x\n",
726              channel->thread_id);
727
728   channel->watches = g_slist_remove (channel->watches, watch);
729
730   SetEvent (channel->data_avail_noticed_event);
731   if (channel->type == G_IO_WIN32_SOCKET)
732     send (channel->reset_send, send_buffer, sizeof (send_buffer), 0);
733
734   g_io_channel_unref (watch->channel);
735   UNLOCK (channel->mutex);
736 }
737
738 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
739 __declspec(dllexport)
740 #endif
741 GSourceFuncs g_io_watch_funcs = {
742   g_io_win32_prepare,
743   g_io_win32_check,
744   g_io_win32_dispatch,
745   g_io_win32_finalize
746 };
747
748 static GSource *
749 g_io_win32_create_watch (GIOChannel    *channel,
750                          GIOCondition   condition,
751                          unsigned (__stdcall *thread) (void *parameter))
752 {
753   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
754   GIOWin32Watch *watch;
755   GSource *source;
756   char send_buffer[] = "c";
757
758   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
759   watch = (GIOWin32Watch *)source;
760   
761   watch->channel = channel;
762   g_io_channel_ref (channel);
763   
764   watch->condition = condition;
765   
766   if (win32_channel->data_avail_event == NULL)
767     create_events (win32_channel);
768
769   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
770   watch->pollfd.events = condition;
771   
772   if (win32_channel->debug)
773     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
774              win32_channel->fd, condition, watch->pollfd.fd);
775
776   LOCK (win32_channel->mutex);
777   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
778
779   if (win32_channel->thread_id == 0)
780     create_thread (win32_channel, condition, thread);
781   else
782     send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
783
784   g_source_add_poll (source, &watch->pollfd);
785   UNLOCK (win32_channel->mutex);
786
787   return source;
788 }
789
790 static GIOStatus
791 g_io_win32_msg_read (GIOChannel *channel,
792                      gchar      *buf,
793                      gsize       count,
794                      gsize      *bytes_read,
795                      GError    **err)
796 {
797   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
798   MSG msg;               /* In case of alignment problems */
799   
800   if (count < sizeof (MSG))
801     {
802       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
803                    "Incorrect message size"); /* Informative enough error message? */
804       return G_IO_STATUS_ERROR;
805     }
806   
807   if (win32_channel->debug)
808     g_print ("g_io_win32_msg_read: for %#x\n",
809              (guint) win32_channel->hwnd);
810   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
811     return G_IO_STATUS_AGAIN;
812
813   memmove (buf, &msg, sizeof (MSG));
814   *bytes_read = sizeof (MSG);
815
816   return G_IO_STATUS_NORMAL;
817 }
818
819 static GIOStatus
820 g_io_win32_msg_write (GIOChannel  *channel,
821                       const gchar *buf,
822                       gsize        count,
823                       gsize       *bytes_written,
824                       GError     **err)
825 {
826   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
827   MSG msg;
828   
829   if (count != sizeof (MSG))
830     {
831       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
832                    "Incorrect message size"); /* Informative enough error message? */
833       return G_IO_STATUS_ERROR;
834     }
835   
836   /* In case of alignment problems */
837   memmove (&msg, buf, sizeof (MSG));
838   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
839     {
840       gchar *emsg = g_win32_error_message (GetLastError ());
841       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
842       g_free (emsg);
843       return G_IO_STATUS_ERROR;
844     }
845
846   *bytes_written = sizeof (MSG);
847
848   return G_IO_STATUS_NORMAL;
849 }
850
851 static GIOStatus
852 g_io_win32_msg_close (GIOChannel *channel,
853                       GError    **err)
854 {
855   /* Nothing to be done. Or should we set hwnd to some invalid value? */
856
857   return G_IO_STATUS_NORMAL;
858 }
859
860 static void
861 g_io_win32_free (GIOChannel *channel)
862 {
863   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
864   
865   if (win32_channel->debug)
866     g_print ("thread %#x: freeing channel, fd: %d\n",
867              win32_channel->thread_id,
868              win32_channel->fd);
869
870   if (win32_channel->reset_send)
871     closesocket (win32_channel->reset_send);
872   if (win32_channel->reset_recv)
873     closesocket (win32_channel->reset_recv);
874   if (win32_channel->data_avail_event)
875     CloseHandle (win32_channel->data_avail_event);
876   if (win32_channel->space_avail_event)
877     CloseHandle (win32_channel->space_avail_event);
878   if (win32_channel->data_avail_noticed_event)
879     CloseHandle (win32_channel->data_avail_noticed_event);
880   DeleteCriticalSection (&win32_channel->mutex);
881
882   g_free (win32_channel->buffer);
883   g_slist_free (win32_channel->watches);
884   g_free (win32_channel);
885 }
886
887 static GSource *
888 g_io_win32_msg_create_watch (GIOChannel    *channel,
889                              GIOCondition   condition)
890 {
891   GIOWin32Watch *watch;
892   GSource *source;
893
894   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
895   watch = (GIOWin32Watch *)source;
896   
897   watch->channel = channel;
898   g_io_channel_ref (channel);
899   
900   watch->condition = condition;
901   
902   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
903   watch->pollfd.events = condition;
904   
905   g_source_add_poll (source, &watch->pollfd);
906   
907   return source;
908 }
909
910 static GIOStatus
911 g_io_win32_fd_read (GIOChannel *channel,
912                     gchar      *buf,
913                     gsize       count,
914                     gsize      *bytes_read,
915                     GError    **err)
916 {
917   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
918   gint result;
919   
920   if (win32_channel->debug)
921     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
922              win32_channel->fd, count);
923   
924   if (win32_channel->thread_id)
925     {
926       return buffer_read (win32_channel, buf, count, bytes_read, err);
927     }
928
929   result = read (win32_channel->fd, buf, count);
930
931   if (win32_channel->debug)
932     g_print ("g_io_win32_fd_read: read() = %d\n", result);
933
934   if (result < 0)
935     {
936       *bytes_read = 0;
937
938       switch (errno)
939         {
940 #ifdef EAGAIN
941         case EAGAIN:
942           return G_IO_STATUS_AGAIN;
943 #endif
944         default:
945           g_set_error (err, G_IO_CHANNEL_ERROR,
946                        g_io_channel_error_from_errno (errno),
947                        g_strerror (errno));
948           return G_IO_STATUS_ERROR;
949         }
950     }
951
952   *bytes_read = result;
953
954   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
955 }
956
957 static GIOStatus
958 g_io_win32_fd_write (GIOChannel  *channel,
959                      const gchar *buf,
960                      gsize        count,
961                      gsize       *bytes_written,
962                      GError     **err)
963 {
964   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
965   gint result;
966   
967   result = write (win32_channel->fd, buf, count);
968   if (win32_channel->debug)
969     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
970              win32_channel->fd, count, result);
971
972   if (result < 0)
973     {
974       *bytes_written = 0;
975
976       switch (errno)
977         {
978 #ifdef EAGAIN
979         case EAGAIN:
980           return G_IO_STATUS_AGAIN;
981 #endif
982         default:
983           g_set_error (err, G_IO_CHANNEL_ERROR,
984                        g_io_channel_error_from_errno (errno),
985                        g_strerror (errno));
986           return G_IO_STATUS_ERROR;
987         }
988     }
989
990   *bytes_written = result;
991
992   return G_IO_STATUS_NORMAL;
993 }
994
995 static GIOStatus
996 g_io_win32_fd_seek (GIOChannel *channel,
997                     gint64      offset,
998                     GSeekType   type,
999                     GError    **err)
1000 {
1001   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1002   int whence;
1003   off_t tmp_offset;
1004   off_t result;
1005   
1006   switch (type)
1007     {
1008     case G_SEEK_SET:
1009       whence = SEEK_SET;
1010       break;
1011     case G_SEEK_CUR:
1012       whence = SEEK_CUR;
1013       break;
1014     case G_SEEK_END:
1015       whence = SEEK_END;
1016       break;
1017     default:
1018       whence = -1; /* Keep the compiler quiet */
1019       g_assert_not_reached ();
1020     }
1021
1022   tmp_offset = offset;
1023   if (tmp_offset != offset)
1024     {
1025       g_set_error (err, G_IO_CHANNEL_ERROR,
1026                    g_io_channel_error_from_errno (EINVAL),
1027                    g_strerror (EINVAL));
1028       return G_IO_STATUS_ERROR;
1029     }
1030   
1031   result = lseek (win32_channel->fd, tmp_offset, whence);
1032   
1033   if (result < 0)
1034     {
1035       g_set_error (err, G_IO_CHANNEL_ERROR,
1036                    g_io_channel_error_from_errno (errno),
1037                    g_strerror (errno));
1038       return G_IO_STATUS_ERROR;
1039     }
1040
1041   return G_IO_STATUS_NORMAL;
1042 }
1043
1044 static GIOStatus
1045 g_io_win32_fd_close (GIOChannel *channel,
1046                      GError    **err)
1047 {
1048   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1049   
1050   if (win32_channel->debug)
1051     g_print ("thread %#x: closing fd %d\n",
1052              win32_channel->thread_id,
1053              win32_channel->fd);
1054   LOCK (win32_channel->mutex);
1055   if (win32_channel->running)
1056     {
1057       if (win32_channel->debug)
1058         g_print ("thread %#x: running, marking fd %d for later close\n",
1059                  win32_channel->thread_id, win32_channel->fd);
1060       win32_channel->running = FALSE;
1061       win32_channel->needs_close = TRUE;
1062       SetEvent (win32_channel->data_avail_event);
1063     }
1064   else
1065     {
1066       if (win32_channel->debug)
1067         g_print ("closing fd %d\n", win32_channel->fd);
1068       close (win32_channel->fd);
1069       if (win32_channel->debug)
1070         g_print ("closed fd %d, setting to -1\n",
1071                  win32_channel->fd);
1072       win32_channel->fd = -1;
1073     }
1074   UNLOCK (win32_channel->mutex);
1075
1076   /* FIXME error detection? */
1077
1078   return G_IO_STATUS_NORMAL;
1079 }
1080
1081 static GSource *
1082 g_io_win32_fd_create_watch (GIOChannel    *channel,
1083                             GIOCondition   condition)
1084 {
1085   return g_io_win32_create_watch (channel, condition, read_thread);
1086 }
1087
1088 static GIOStatus
1089 g_io_win32_sock_read (GIOChannel *channel,
1090                       gchar      *buf,
1091                       gsize       count,
1092                       gsize      *bytes_read,
1093                       GError    **err)
1094 {
1095   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1096   gint result;
1097   GIOChannelError error = G_IO_STATUS_NORMAL;
1098   GIOStatus internal_status = G_IO_STATUS_NORMAL;
1099   char send_buffer[] = "sr";
1100
1101   if (win32_channel->debug)
1102     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1103              win32_channel->fd, count);
1104 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1105 repeat:
1106 #endif
1107   result = recv (win32_channel->fd, buf, count, 0);
1108
1109   if (win32_channel->debug)
1110     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1111   
1112   if (result == SOCKET_ERROR)
1113     {
1114       *bytes_read = 0;
1115
1116       switch (WSAGetLastError ())
1117         {
1118         case WSAEINVAL:
1119           error = G_IO_CHANNEL_ERROR_INVAL;
1120           break;
1121         case WSAEWOULDBLOCK:
1122           return G_IO_STATUS_AGAIN;
1123 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1124         case WSAEINTR:
1125           goto repeat;
1126 #endif
1127         default:
1128           error = G_IO_CHANNEL_ERROR_FAILED;
1129           break;
1130         }
1131       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error");
1132       internal_status = G_IO_STATUS_ERROR;
1133       /* FIXME get all errors, better error messages */
1134     }
1135   else
1136     {
1137       *bytes_read = result;
1138       if (result == 0)
1139         internal_status = G_IO_STATUS_EOF;
1140     }
1141
1142   if ((internal_status == G_IO_STATUS_EOF) || 
1143       (internal_status == G_IO_STATUS_ERROR))
1144     {
1145       LOCK (win32_channel->mutex);
1146       SetEvent (win32_channel->data_avail_noticed_event);
1147       win32_channel->needs_close = 1;
1148       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1149       UNLOCK (win32_channel->mutex);
1150     }
1151   return internal_status;
1152 }
1153
1154 static GIOStatus
1155 g_io_win32_sock_write (GIOChannel  *channel,
1156                        const gchar *buf,
1157                        gsize        count,
1158                        gsize       *bytes_written,
1159                        GError     **err)
1160 {
1161   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1162   gint result;
1163   GIOChannelError error = G_IO_STATUS_NORMAL;
1164   char send_buffer[] = "sw";
1165   
1166   if (win32_channel->debug)
1167     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1168              win32_channel->fd, count);
1169 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1170 repeat:
1171 #endif
1172   result = send (win32_channel->fd, buf, count, 0);
1173   
1174   if (win32_channel->debug)
1175     g_print ("g_io_win32_sock_write: send:%d\n", result);
1176   
1177   if (result == SOCKET_ERROR)
1178     {
1179       *bytes_written = 0;
1180
1181       switch (WSAGetLastError ())
1182         {
1183         case WSAEINVAL:
1184           error = G_IO_CHANNEL_ERROR_INVAL;
1185           break;
1186         case WSAEWOULDBLOCK:
1187           return G_IO_STATUS_AGAIN;
1188 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1189         case WSAEINTR:
1190           goto repeat;
1191 #endif
1192         default:
1193           error = G_IO_CHANNEL_ERROR_FAILED;
1194           break;
1195         }
1196       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error");
1197       LOCK (win32_channel->mutex);
1198       SetEvent (win32_channel->data_avail_noticed_event);
1199       win32_channel->needs_close = 1;
1200       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1201       UNLOCK (win32_channel->mutex);
1202       return G_IO_STATUS_ERROR;
1203       /* FIXME get all errors, better error messages */
1204     }
1205   else
1206     {
1207       *bytes_written = result;
1208
1209       return G_IO_STATUS_NORMAL;
1210     }
1211 }
1212
1213 static GIOStatus
1214 g_io_win32_sock_close (GIOChannel *channel,
1215                        GError    **err)
1216 {
1217   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1218
1219   LOCK (win32_channel->mutex);
1220   if (win32_channel->running)
1221     {
1222       if (win32_channel->debug)
1223         g_print ("thread %#x: running, marking for later close\n",
1224                  win32_channel->thread_id);
1225       win32_channel->running = FALSE;
1226       win32_channel->needs_close = TRUE;
1227       SetEvent(win32_channel->data_avail_noticed_event);
1228     }
1229   if (win32_channel->fd != -1)
1230     {
1231       if (win32_channel->debug)
1232         g_print ("thread %#x: closing socket %d\n",
1233                  win32_channel->thread_id,
1234                  win32_channel->fd);
1235       
1236       closesocket (win32_channel->fd);
1237       win32_channel->fd = -1;
1238     }
1239   UNLOCK (win32_channel->mutex);
1240
1241   /* FIXME error detection? */
1242
1243   return G_IO_STATUS_NORMAL;
1244 }
1245
1246 static GSource *
1247 g_io_win32_sock_create_watch (GIOChannel    *channel,
1248                               GIOCondition   condition)
1249 {
1250   return g_io_win32_create_watch (channel, condition, select_thread);
1251 }
1252
1253 GIOChannel *
1254 g_io_channel_new_file (const gchar  *filename,
1255                        const gchar  *mode,
1256                        GError      **error)
1257 {
1258   int fid, flags, pmode;
1259   GIOChannel *channel;
1260
1261   enum { /* Cheesy hack */
1262     MODE_R = 1 << 0,
1263     MODE_W = 1 << 1,
1264     MODE_A = 1 << 2,
1265     MODE_PLUS = 1 << 3,
1266   } mode_num;
1267
1268   g_return_val_if_fail (filename != NULL, NULL);
1269   g_return_val_if_fail (mode != NULL, NULL);
1270   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1271
1272   switch (mode[0])
1273     {
1274       case 'r':
1275         mode_num = MODE_R;
1276         break;
1277       case 'w':
1278         mode_num = MODE_W;
1279         break;
1280       case 'a':
1281         mode_num = MODE_A;
1282         break;
1283       default:
1284         g_warning ("Invalid GIOFileMode %s.\n", mode);
1285         return NULL;
1286     }
1287
1288   switch (mode[1])
1289     {
1290       case '\0':
1291         break;
1292       case '+':
1293         if (mode[2] == '\0')
1294           {
1295             mode_num |= MODE_PLUS;
1296             break;
1297           }
1298         /* Fall through */
1299       default:
1300         g_warning ("Invalid GIOFileMode %s.\n", mode);
1301         return NULL;
1302     }
1303
1304   switch (mode_num)
1305     {
1306       case MODE_R:
1307         flags = O_RDONLY;
1308         pmode = _S_IREAD;
1309         break;
1310       case MODE_W:
1311         flags = O_WRONLY | O_TRUNC | O_CREAT;
1312         pmode = _S_IWRITE;
1313         break;
1314       case MODE_A:
1315         flags = O_WRONLY | O_APPEND | O_CREAT;
1316         pmode = _S_IWRITE;
1317         break;
1318       case MODE_R | MODE_PLUS:
1319         flags = O_RDWR;
1320         pmode = _S_IREAD | _S_IWRITE;
1321         break;
1322       case MODE_W | MODE_PLUS:
1323         flags = O_RDWR | O_TRUNC | O_CREAT;
1324         pmode = _S_IREAD | _S_IWRITE;
1325         break;
1326       case MODE_A | MODE_PLUS:
1327         flags = O_RDWR | O_APPEND | O_CREAT;
1328         pmode = _S_IREAD | _S_IWRITE;
1329         break;
1330       default:
1331         g_assert_not_reached ();
1332         flags = 0;
1333         pmode = 0;
1334     }
1335
1336   /* always open 'untranslated' */
1337   fid = open (filename, flags | _O_BINARY, pmode);
1338
1339   if (g_io_win32_get_debug_flag ())
1340     {
1341       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1342       g_win32_print_access_mode (flags|_O_BINARY);
1343       g_print (",%#o)=%d\n", pmode, fid);
1344     }
1345
1346   if (fid < 0)
1347     {
1348       g_set_error (error, G_FILE_ERROR,
1349                    g_file_error_from_errno (errno),
1350                    g_strerror (errno));
1351       return (GIOChannel *)NULL;
1352     }
1353
1354   channel = g_io_channel_win32_new_fd (fid);
1355
1356   /* XXX: move this to g_io_channel_win32_new_fd () */
1357   channel->close_on_unref = TRUE;
1358   channel->is_seekable = TRUE;
1359
1360   /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1361    * correspond to actual readability/writeability. Set to FALSE those
1362    * that mode doesn't allow
1363    */
1364   switch (mode_num)
1365     {
1366       case MODE_R:
1367         channel->is_writeable = FALSE;
1368         break;
1369       case MODE_W:
1370       case MODE_A:
1371         channel->is_readable = FALSE;
1372         break;
1373       case MODE_R | MODE_PLUS:
1374       case MODE_W | MODE_PLUS:
1375       case MODE_A | MODE_PLUS:
1376         break;
1377       default:
1378         g_assert_not_reached ();
1379     }
1380
1381   return channel;
1382 }
1383
1384 static GIOStatus
1385 g_io_win32_set_flags (GIOChannel *channel,
1386                       GIOFlags    flags,
1387                       GError    **err)
1388 {
1389   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1390
1391   if (win32_channel->debug)
1392     {
1393       g_print ("g_io_win32_set_flags: ");
1394       g_win32_print_gioflags (flags);
1395       g_print ("\n");
1396     }
1397
1398   g_warning ("g_io_win32_set_flags () not implemented.\n");
1399
1400   return G_IO_STATUS_NORMAL;
1401 }
1402
1403 static GIOFlags
1404 g_io_win32_fd_get_flags_internal (GIOChannel  *channel,
1405                                   struct stat *st)
1406 {
1407   GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1408   gchar c;
1409   DWORD count;
1410
1411   if (st->st_mode & _S_IFIFO)
1412     {
1413       channel->is_readable =
1414         (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
1415       channel->is_writeable =
1416         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1417       channel->is_seekable  = FALSE;
1418     }
1419   else if (st->st_mode & _S_IFCHR)
1420     {
1421       /* XXX Seems there is no way to find out the readability of file
1422        * handles to device files (consoles, mostly) without doing a
1423        * blocking read. So punt, use st->st_mode.
1424        */
1425       channel->is_readable  = !!(st->st_mode & _S_IREAD);
1426
1427       channel->is_writeable =
1428         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1429
1430       /* XXX What about devices that actually *are* seekable? But
1431        * those would probably not be handled using the C runtime
1432        * anyway, but using Windows-specific code.
1433        */
1434       channel->is_seekable = FALSE;
1435     }
1436   else
1437     {
1438       channel->is_readable =
1439         (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1440       channel->is_writeable =
1441         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1442       channel->is_seekable = TRUE;
1443     }
1444
1445   /* XXX: G_IO_FLAG_APPEND */
1446   /* XXX: G_IO_FLAG_NONBLOCK */
1447
1448   return 0;
1449 }
1450
1451 static GIOFlags
1452 g_io_win32_fd_get_flags (GIOChannel *channel)
1453 {
1454   struct stat st;
1455   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1456
1457   g_return_val_if_fail (win32_channel != NULL, 0);
1458   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1459
1460   if (0 == fstat (win32_channel->fd, &st))
1461     return g_io_win32_fd_get_flags_internal (channel, &st);
1462   else
1463     return 0;
1464 }
1465
1466 static GIOFlags
1467 g_io_win32_msg_get_flags (GIOChannel *channel)
1468 {
1469   return 0;
1470 }
1471
1472 static GIOFlags
1473 g_io_win32_sock_get_flags (GIOChannel *channel)
1474 {
1475   /* XXX Could do something here. */
1476   return 0;
1477 }
1478
1479 static GIOFuncs win32_channel_msg_funcs = {
1480   g_io_win32_msg_read,
1481   g_io_win32_msg_write,
1482   NULL,
1483   g_io_win32_msg_close,
1484   g_io_win32_msg_create_watch,
1485   g_io_win32_free,
1486   g_io_win32_set_flags,
1487   g_io_win32_msg_get_flags,
1488 };
1489
1490 static GIOFuncs win32_channel_fd_funcs = {
1491   g_io_win32_fd_read,
1492   g_io_win32_fd_write,
1493   g_io_win32_fd_seek,
1494   g_io_win32_fd_close,
1495   g_io_win32_fd_create_watch,
1496   g_io_win32_free,
1497   g_io_win32_set_flags,
1498   g_io_win32_fd_get_flags,
1499 };
1500
1501 static GIOFuncs win32_channel_sock_funcs = {
1502   g_io_win32_sock_read,
1503   g_io_win32_sock_write,
1504   NULL,
1505   g_io_win32_sock_close,
1506   g_io_win32_sock_create_watch,
1507   g_io_win32_free,
1508   g_io_win32_set_flags,
1509   g_io_win32_sock_get_flags,
1510 };
1511
1512 GIOChannel *
1513 g_io_channel_win32_new_messages (guint hwnd)
1514 {
1515   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1516   GIOChannel *channel = (GIOChannel *)win32_channel;
1517
1518   g_io_channel_init (channel);
1519   g_io_channel_win32_init (win32_channel);
1520   if (win32_channel->debug)
1521     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1522   channel->funcs = &win32_channel_msg_funcs;
1523   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1524   win32_channel->hwnd = (HWND) hwnd;
1525
1526   /* XXX: check this. */
1527   channel->is_readable = IsWindow (win32_channel->hwnd);
1528   channel->is_writeable = IsWindow (win32_channel->hwnd);
1529
1530   channel->is_seekable = FALSE;
1531
1532   return channel;
1533 }
1534
1535 static GIOChannel *
1536 g_io_channel_win32_new_fd_internal (gint         fd,
1537                                     struct stat *st)
1538 {
1539   GIOWin32Channel *win32_channel;
1540   GIOChannel *channel;
1541
1542   win32_channel = g_new (GIOWin32Channel, 1);
1543   channel = (GIOChannel *)win32_channel;
1544
1545   g_io_channel_init (channel);
1546   g_io_channel_win32_init (win32_channel);
1547   if (win32_channel->debug)
1548     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1549   channel->funcs = &win32_channel_fd_funcs;
1550   win32_channel->type = G_IO_WIN32_FILE_DESC;
1551   win32_channel->fd = fd;
1552
1553   g_io_win32_fd_get_flags_internal (channel, st);
1554   
1555   return channel;
1556 }
1557
1558 GIOChannel *
1559 g_io_channel_win32_new_fd (gint fd)
1560 {
1561   struct stat st;
1562
1563   if (fstat (fd, &st) == -1)
1564     {
1565       g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
1566       return NULL;
1567     }
1568
1569   return g_io_channel_win32_new_fd_internal (fd, &st);
1570 }
1571
1572 gint
1573 g_io_channel_win32_get_fd (GIOChannel *channel)
1574 {
1575   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1576
1577   return win32_channel->fd;
1578 }
1579
1580 GIOChannel *
1581 g_io_channel_win32_new_socket (int socket)
1582 {
1583   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1584   GIOChannel *channel = (GIOChannel *)win32_channel;
1585
1586   g_io_channel_init (channel);
1587   g_io_channel_win32_init (win32_channel);
1588   init_reset_sockets (win32_channel);
1589   if (win32_channel->debug)
1590     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1591   channel->funcs = &win32_channel_sock_funcs;
1592   win32_channel->type = G_IO_WIN32_SOCKET;
1593   win32_channel->fd = socket;
1594
1595   /* XXX: check this */
1596   channel->is_readable = TRUE;
1597   channel->is_writeable = TRUE;
1598
1599   channel->is_seekable = FALSE;
1600
1601   return channel;
1602 }
1603
1604 GIOChannel *
1605 g_io_channel_unix_new (gint fd)
1606 {
1607   struct stat st;
1608
1609   if (fstat (fd, &st) == 0)
1610     return g_io_channel_win32_new_fd_internal (fd, &st);
1611   
1612   if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SOCKET_ERROR)
1613     return g_io_channel_win32_new_socket (fd);
1614
1615   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1616   return NULL;
1617 }
1618
1619 gint
1620 g_io_channel_unix_get_fd (GIOChannel *channel)
1621 {
1622   return g_io_channel_win32_get_fd (channel);
1623 }
1624
1625 void
1626 g_io_channel_win32_set_debug (GIOChannel *channel,
1627                               gboolean    flag)
1628 {
1629   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1630
1631   win32_channel->debug = flag;
1632 }
1633
1634 gint
1635 g_io_channel_win32_poll (GPollFD *fds,
1636                          gint     n_fds,
1637                          gint     timeout)
1638 {
1639   int result;
1640
1641   g_return_val_if_fail (n_fds >= 0, 0);
1642
1643   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1644
1645   return result;
1646 }
1647
1648 void
1649 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1650                                 GIOCondition  condition,
1651                                 GPollFD      *fd)
1652 {
1653   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1654
1655   if (win32_channel->data_avail_event == NULL)
1656     create_events (win32_channel);
1657   
1658   fd->fd = (gint) win32_channel->data_avail_event;
1659   fd->events = condition;
1660
1661   if (win32_channel->thread_id == 0)
1662     {
1663       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1664         create_thread (win32_channel, condition, read_thread);
1665       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1666         create_thread (win32_channel, condition, select_thread);
1667     }
1668 }
1669
1670 /* Binary compatibility */
1671 GIOChannel *
1672 g_io_channel_win32_new_stream_socket (int socket)
1673 {
1674   return g_io_channel_win32_new_socket (socket);
1675 }