Implement the same PLT reduction technique used in GTK+:
[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 "galias.h"
38 #include "glib.h"
39
40 #include <stdlib.h>
41 #include <windows.h>
42 #include <winsock.h>          /* Not everybody has winsock2 */
43 #include <fcntl.h>
44 #include <io.h>
45 #include <process.h>
46 #include <errno.h>
47 #include <sys/stat.h>
48
49 #include "glibintl.h"
50
51 typedef struct _GIOWin32Channel GIOWin32Channel;
52 typedef struct _GIOWin32Watch GIOWin32Watch;
53
54 #define BUFFER_SIZE 4096
55
56 typedef enum {
57   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
58   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
59                                  * _open() or _pipe(). Read with read().
60                                  * Have to create separate thread to read.
61                                  */
62   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
63                                  * in select() most of the time.
64                                  */
65 } GIOWin32ChannelType;
66
67 struct _GIOWin32Channel {
68   GIOChannel channel;
69   gint fd;                      /* Either a Unix-like file handle as provided
70                                  * by the Microsoft C runtime, or a SOCKET
71                                  * as provided by WinSock.
72                                  */
73   GIOWin32ChannelType type;
74   
75   gboolean debug;
76
77   CRITICAL_SECTION mutex;
78
79   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
80   HWND hwnd;                    /* handle of window, or NULL */
81   
82   /* Following fields are used by both fd and socket channels. */
83   gboolean running;             /* Is reader thread running. FALSE if
84                                  * EOF has been reached.
85                                  */
86   gboolean needs_close;         /* If the channel has been closed while
87                                  * the reader thread was still running.
88                                  */
89   guint thread_id;              /* If non-NULL has a reader thread, or has
90                                  * had.*/
91   HANDLE data_avail_event;
92
93   gushort revents;
94
95   /* Following fields used by fd channels for input */
96   
97   /* Data is kept in a circular buffer. To be able to distinguish between
98    * empty and full buffer, we cannot fill it completely, but have to
99    * leave a one character gap.
100    *
101    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
102    *
103    * Empty:    wrp == rdp
104    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
105    * Partial:  otherwise
106    */
107   guchar *buffer;               /* (Circular) buffer */
108   gint wrp, rdp;                /* Buffer indices for writing and reading */
109   HANDLE space_avail_event;
110
111   /* Following fields used by socket channels */
112   GSList *watches;
113   HANDLE data_avail_noticed_event;
114   gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */
115   gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */
116 };
117
118 #define LOCK(mutex) EnterCriticalSection (&mutex)
119 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
120
121 struct _GIOWin32Watch {
122   GSource       source;
123   GPollFD       pollfd;
124   GIOChannel   *channel;
125   GIOCondition  condition;
126 };
127
128 static void
129 g_win32_print_access_mode (int flags)
130 {
131   g_print ("%s%s%s%s%s%s%s%s%s%s",
132            ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
133             ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
134              ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
135            (flags & _O_APPEND ? "|O_APPEND" : ""),
136            (flags & _O_RANDOM ? "|O_RANDOM" : ""),
137            (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
138            (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
139            (flags & _O_CREAT ? "|O_CREAT" : ""),
140            (flags & _O_TRUNC ? "|O_TRUNC" : ""),
141            (flags & _O_EXCL ? "|O_EXCL" : ""),
142            (flags & _O_TEXT ? "|O_TEXT" : ""),
143            (flags & _O_BINARY ? "|O_BINARY" : ""));
144 }
145
146 static void
147 g_win32_print_gioflags (GIOFlags flags)
148 {
149   char *bar = "";
150
151   if (flags & G_IO_FLAG_APPEND)
152     bar = "|", g_print ("APPEND");
153   if (flags & G_IO_FLAG_NONBLOCK)
154     g_print ("%sNONBLOCK", bar), bar = "|";
155   if (flags & G_IO_FLAG_IS_READABLE)
156     g_print ("%sREADABLE", bar), bar = "|";
157   if (flags & G_IO_FLAG_IS_WRITEABLE)
158     g_print ("%sWRITEABLE", bar), bar = "|";
159   if (flags & G_IO_FLAG_IS_SEEKABLE)
160     g_print ("%sSEEKABLE", bar), bar = "|";
161 }
162
163 static gboolean
164 g_io_win32_get_debug_flag (void)
165 {
166 #ifdef G_IO_WIN32_DEBUG
167   return TRUE;
168 #else
169   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
170     return TRUE;
171   else
172     return FALSE;
173 #endif
174 }  
175
176 static void
177 g_io_channel_win32_init (GIOWin32Channel *channel)
178 {
179   channel->debug = g_io_win32_get_debug_flag ();
180   channel->buffer = NULL;
181   channel->running = FALSE;
182   channel->needs_close = FALSE;
183   channel->thread_id = 0;
184   channel->data_avail_event = NULL;
185   channel->revents = 0;
186   channel->space_avail_event = NULL;
187   channel->reset_send = INVALID_SOCKET;
188   channel->reset_recv = INVALID_SOCKET;
189   channel->data_avail_noticed_event = NULL;
190   channel->watches = NULL;
191   InitializeCriticalSection (&channel->mutex);
192 }
193
194 static void
195 create_events (GIOWin32Channel *channel)
196 {
197   SECURITY_ATTRIBUTES sec_attrs;
198   
199   sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
200   sec_attrs.lpSecurityDescriptor = NULL;
201   sec_attrs.bInheritHandle = FALSE;
202
203   /* The data available event is manual reset, the space available event
204    * is automatic reset.
205    */
206   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
207       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
208       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
209     {
210       gchar *emsg = g_win32_error_message (GetLastError ());
211       g_error ("Error creating event: %s", emsg);
212       g_free (emsg);
213     }
214 }
215
216 static unsigned __stdcall
217 read_thread (void *parameter)
218 {
219   GIOWin32Channel *channel = parameter;
220   guchar *buffer;
221   guint nbytes;
222
223   g_io_channel_ref ((GIOChannel *)channel);
224
225   if (channel->debug)
226     g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
227              channel->thread_id,
228              channel->fd,
229              (guint) channel->data_avail_event,
230              (guint) channel->space_avail_event);
231   
232   channel->buffer = g_malloc (BUFFER_SIZE);
233   channel->rdp = channel->wrp = 0;
234   channel->running = TRUE;
235
236   SetEvent (channel->space_avail_event);
237   
238   LOCK (channel->mutex);
239   while (channel->running)
240     {
241       if (channel->debug)
242         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
243                  channel->thread_id, channel->rdp, channel->wrp);
244       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
245         {
246           /* Buffer is full */
247           if (channel->debug)
248             g_print ("read_thread %#x: resetting space_avail\n",
249                      channel->thread_id);
250           ResetEvent (channel->space_avail_event);
251           if (channel->debug)
252             g_print ("read_thread %#x: waiting for space\n",
253                      channel->thread_id);
254           UNLOCK (channel->mutex);
255           WaitForSingleObject (channel->space_avail_event, INFINITE);
256           LOCK (channel->mutex);
257           if (channel->debug)
258             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
259                      channel->thread_id, channel->rdp, channel->wrp);
260         }
261       
262       buffer = channel->buffer + channel->wrp;
263       
264       /* Always leave at least one byte unused gap to be able to
265        * distinguish between the full and empty condition...
266        */
267       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
268                     BUFFER_SIZE - channel->wrp);
269
270       if (channel->debug)
271         g_print ("read_thread %#x: calling read() for %d bytes\n",
272                  channel->thread_id, nbytes);
273
274       UNLOCK (channel->mutex);
275
276       nbytes = read (channel->fd, buffer, nbytes);
277       
278       LOCK (channel->mutex);
279
280       channel->revents = G_IO_IN;
281       if (nbytes == 0)
282         channel->revents |= G_IO_HUP;
283       else if (nbytes < 0)
284         channel->revents |= G_IO_ERR;
285
286       if (channel->debug)
287         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
288                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
289
290       if (nbytes <= 0)
291         break;
292
293       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
294       if (channel->debug)
295         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
296                  channel->thread_id, channel->rdp, channel->wrp);
297       SetEvent (channel->data_avail_event);
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_LOOPBACK);
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_LOOPBACK);
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   {
733     /* Tell select_thread() to exit */
734     channel->needs_close = 1;
735     /* Wake up select_thread() from its blocking select() */
736     send (channel->reset_send, send_buffer, sizeof (send_buffer), 0);
737   }
738
739   g_io_channel_unref (watch->channel);
740   UNLOCK (channel->mutex);
741 }
742
743 GSourceFuncs g_io_watch_funcs = {
744   g_io_win32_prepare,
745   g_io_win32_check,
746   g_io_win32_dispatch,
747   g_io_win32_finalize
748 };
749
750 static GSource *
751 g_io_win32_create_watch (GIOChannel    *channel,
752                          GIOCondition   condition,
753                          unsigned (__stdcall *thread) (void *parameter))
754 {
755   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
756   GIOWin32Watch *watch;
757   GSource *source;
758   char send_buffer[] = "c";
759
760   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
761   watch = (GIOWin32Watch *)source;
762   
763   watch->channel = channel;
764   g_io_channel_ref (channel);
765   
766   watch->condition = condition;
767   
768   if (win32_channel->data_avail_event == NULL)
769     create_events (win32_channel);
770
771   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
772   watch->pollfd.events = condition;
773   
774   if (win32_channel->debug)
775     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
776              win32_channel->fd, condition, watch->pollfd.fd);
777
778   LOCK (win32_channel->mutex);
779   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
780
781   if (win32_channel->thread_id == 0)
782     create_thread (win32_channel, condition, thread);
783   else
784     send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
785
786   g_source_add_poll (source, &watch->pollfd);
787   UNLOCK (win32_channel->mutex);
788
789   return source;
790 }
791
792 static GIOStatus
793 g_io_win32_msg_read (GIOChannel *channel,
794                      gchar      *buf,
795                      gsize       count,
796                      gsize      *bytes_read,
797                      GError    **err)
798 {
799   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
800   MSG msg;               /* In case of alignment problems */
801   
802   if (count < sizeof (MSG))
803     {
804       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
805                    "Incorrect message size"); /* Informative enough error message? */
806       return G_IO_STATUS_ERROR;
807     }
808   
809   if (win32_channel->debug)
810     g_print ("g_io_win32_msg_read: for %#x\n",
811              (guint) win32_channel->hwnd);
812   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
813     return G_IO_STATUS_AGAIN;
814
815   memmove (buf, &msg, sizeof (MSG));
816   *bytes_read = sizeof (MSG);
817
818   return G_IO_STATUS_NORMAL;
819 }
820
821 static GIOStatus
822 g_io_win32_msg_write (GIOChannel  *channel,
823                       const gchar *buf,
824                       gsize        count,
825                       gsize       *bytes_written,
826                       GError     **err)
827 {
828   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
829   MSG msg;
830   
831   if (count != sizeof (MSG))
832     {
833       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
834                    "Incorrect message size"); /* Informative enough error message? */
835       return G_IO_STATUS_ERROR;
836     }
837   
838   /* In case of alignment problems */
839   memmove (&msg, buf, sizeof (MSG));
840   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
841     {
842       gchar *emsg = g_win32_error_message (GetLastError ());
843       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
844       g_free (emsg);
845       return G_IO_STATUS_ERROR;
846     }
847
848   *bytes_written = sizeof (MSG);
849
850   return G_IO_STATUS_NORMAL;
851 }
852
853 static GIOStatus
854 g_io_win32_msg_close (GIOChannel *channel,
855                       GError    **err)
856 {
857   /* Nothing to be done. Or should we set hwnd to some invalid value? */
858
859   return G_IO_STATUS_NORMAL;
860 }
861
862 static void
863 g_io_win32_free (GIOChannel *channel)
864 {
865   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
866   
867   if (win32_channel->debug)
868     g_print ("thread %#x: freeing channel, fd: %d\n",
869              win32_channel->thread_id,
870              win32_channel->fd);
871
872   if (win32_channel->reset_send && win32_channel->reset_send != INVALID_SOCKET)
873     closesocket (win32_channel->reset_send);
874   if (win32_channel->reset_recv && win32_channel->reset_recv != INVALID_SOCKET)
875     closesocket (win32_channel->reset_recv);
876   if (win32_channel->data_avail_event)
877     CloseHandle (win32_channel->data_avail_event);
878   if (win32_channel->space_avail_event)
879     CloseHandle (win32_channel->space_avail_event);
880   if (win32_channel->data_avail_noticed_event)
881     CloseHandle (win32_channel->data_avail_noticed_event);
882   DeleteCriticalSection (&win32_channel->mutex);
883
884   g_free (win32_channel->buffer);
885   g_slist_free (win32_channel->watches);
886   g_free (win32_channel);
887 }
888
889 static GSource *
890 g_io_win32_msg_create_watch (GIOChannel    *channel,
891                              GIOCondition   condition)
892 {
893   GIOWin32Watch *watch;
894   GSource *source;
895
896   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
897   watch = (GIOWin32Watch *)source;
898   
899   watch->channel = channel;
900   g_io_channel_ref (channel);
901   
902   watch->condition = condition;
903   
904   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
905   watch->pollfd.events = condition;
906   
907   g_source_add_poll (source, &watch->pollfd);
908   
909   return source;
910 }
911
912 static GIOStatus
913 g_io_win32_fd_read (GIOChannel *channel,
914                     gchar      *buf,
915                     gsize       count,
916                     gsize      *bytes_read,
917                     GError    **err)
918 {
919   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
920   gint result;
921   
922   if (win32_channel->debug)
923     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
924              win32_channel->fd, count);
925   
926   if (win32_channel->thread_id)
927     {
928       return buffer_read (win32_channel, buf, count, bytes_read, err);
929     }
930
931   result = read (win32_channel->fd, buf, count);
932
933   if (win32_channel->debug)
934     g_print ("g_io_win32_fd_read: read() = %d\n", result);
935
936   if (result < 0)
937     {
938       *bytes_read = 0;
939
940       switch (errno)
941         {
942 #ifdef EAGAIN
943         case EAGAIN:
944           return G_IO_STATUS_AGAIN;
945 #endif
946         default:
947           g_set_error (err, G_IO_CHANNEL_ERROR,
948                        g_io_channel_error_from_errno (errno),
949                        g_strerror (errno));
950           return G_IO_STATUS_ERROR;
951         }
952     }
953
954   *bytes_read = result;
955
956   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
957 }
958
959 static GIOStatus
960 g_io_win32_fd_write (GIOChannel  *channel,
961                      const gchar *buf,
962                      gsize        count,
963                      gsize       *bytes_written,
964                      GError     **err)
965 {
966   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
967   gint result;
968   
969   result = write (win32_channel->fd, buf, count);
970   if (win32_channel->debug)
971     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
972              win32_channel->fd, count, result);
973
974   if (result < 0)
975     {
976       *bytes_written = 0;
977
978       switch (errno)
979         {
980 #ifdef EAGAIN
981         case EAGAIN:
982           return G_IO_STATUS_AGAIN;
983 #endif
984         default:
985           g_set_error (err, G_IO_CHANNEL_ERROR,
986                        g_io_channel_error_from_errno (errno),
987                        g_strerror (errno));
988           return G_IO_STATUS_ERROR;
989         }
990     }
991
992   *bytes_written = result;
993
994   return G_IO_STATUS_NORMAL;
995 }
996
997 static GIOStatus
998 g_io_win32_fd_seek (GIOChannel *channel,
999                     gint64      offset,
1000                     GSeekType   type,
1001                     GError    **err)
1002 {
1003   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1004   int whence;
1005   off_t tmp_offset;
1006   off_t result;
1007   
1008   switch (type)
1009     {
1010     case G_SEEK_SET:
1011       whence = SEEK_SET;
1012       break;
1013     case G_SEEK_CUR:
1014       whence = SEEK_CUR;
1015       break;
1016     case G_SEEK_END:
1017       whence = SEEK_END;
1018       break;
1019     default:
1020       whence = -1; /* Keep the compiler quiet */
1021       g_assert_not_reached ();
1022     }
1023
1024   tmp_offset = offset;
1025   if (tmp_offset != offset)
1026     {
1027       g_set_error (err, G_IO_CHANNEL_ERROR,
1028                    g_io_channel_error_from_errno (EINVAL),
1029                    g_strerror (EINVAL));
1030       return G_IO_STATUS_ERROR;
1031     }
1032   
1033   result = lseek (win32_channel->fd, tmp_offset, whence);
1034   
1035   if (result < 0)
1036     {
1037       g_set_error (err, G_IO_CHANNEL_ERROR,
1038                    g_io_channel_error_from_errno (errno),
1039                    g_strerror (errno));
1040       return G_IO_STATUS_ERROR;
1041     }
1042
1043   return G_IO_STATUS_NORMAL;
1044 }
1045
1046 static GIOStatus
1047 g_io_win32_fd_close (GIOChannel *channel,
1048                      GError    **err)
1049 {
1050   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1051   
1052   if (win32_channel->debug)
1053     g_print ("thread %#x: closing fd %d\n",
1054              win32_channel->thread_id,
1055              win32_channel->fd);
1056   LOCK (win32_channel->mutex);
1057   if (win32_channel->running)
1058     {
1059       if (win32_channel->debug)
1060         g_print ("thread %#x: running, marking fd %d for later close\n",
1061                  win32_channel->thread_id, win32_channel->fd);
1062       win32_channel->running = FALSE;
1063       win32_channel->needs_close = TRUE;
1064       SetEvent (win32_channel->data_avail_event);
1065     }
1066   else
1067     {
1068       if (win32_channel->debug)
1069         g_print ("closing fd %d\n", win32_channel->fd);
1070       close (win32_channel->fd);
1071       if (win32_channel->debug)
1072         g_print ("closed fd %d, setting to -1\n",
1073                  win32_channel->fd);
1074       win32_channel->fd = -1;
1075     }
1076   UNLOCK (win32_channel->mutex);
1077
1078   /* FIXME error detection? */
1079
1080   return G_IO_STATUS_NORMAL;
1081 }
1082
1083 static GSource *
1084 g_io_win32_fd_create_watch (GIOChannel    *channel,
1085                             GIOCondition   condition)
1086 {
1087   return g_io_win32_create_watch (channel, condition, read_thread);
1088 }
1089
1090 static GIOStatus
1091 g_io_win32_sock_read (GIOChannel *channel,
1092                       gchar      *buf,
1093                       gsize       count,
1094                       gsize      *bytes_read,
1095                       GError    **err)
1096 {
1097   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1098   gint result;
1099   GIOChannelError error = G_IO_STATUS_NORMAL;
1100   GIOStatus internal_status = G_IO_STATUS_NORMAL;
1101   char send_buffer[] = "sr";
1102
1103   if (win32_channel->debug)
1104     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1105              win32_channel->fd, count);
1106 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1107 repeat:
1108 #endif
1109   result = recv (win32_channel->fd, buf, count, 0);
1110
1111   if (win32_channel->debug)
1112     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1113   
1114   if (result == SOCKET_ERROR)
1115     {
1116       *bytes_read = 0;
1117
1118       switch (WSAGetLastError ())
1119         {
1120         case WSAEINVAL:
1121           error = G_IO_CHANNEL_ERROR_INVAL;
1122           break;
1123         case WSAEWOULDBLOCK:
1124           return G_IO_STATUS_AGAIN;
1125 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1126         case WSAEINTR:
1127           goto repeat;
1128 #endif
1129         default:
1130           error = G_IO_CHANNEL_ERROR_FAILED;
1131           break;
1132         }
1133       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error");
1134       internal_status = G_IO_STATUS_ERROR;
1135       /* FIXME get all errors, better error messages */
1136     }
1137   else
1138     {
1139       *bytes_read = result;
1140       if (result == 0)
1141         internal_status = G_IO_STATUS_EOF;
1142     }
1143
1144   if ((internal_status == G_IO_STATUS_EOF) || 
1145       (internal_status == G_IO_STATUS_ERROR))
1146     {
1147       LOCK (win32_channel->mutex);
1148       SetEvent (win32_channel->data_avail_noticed_event);
1149       win32_channel->needs_close = 1;
1150       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1151       UNLOCK (win32_channel->mutex);
1152     }
1153   return internal_status;
1154 }
1155
1156 static GIOStatus
1157 g_io_win32_sock_write (GIOChannel  *channel,
1158                        const gchar *buf,
1159                        gsize        count,
1160                        gsize       *bytes_written,
1161                        GError     **err)
1162 {
1163   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1164   gint result;
1165   GIOChannelError error = G_IO_STATUS_NORMAL;
1166   char send_buffer[] = "sw";
1167   
1168   if (win32_channel->debug)
1169     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1170              win32_channel->fd, count);
1171 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1172 repeat:
1173 #endif
1174   result = send (win32_channel->fd, buf, count, 0);
1175   
1176   if (win32_channel->debug)
1177     g_print ("g_io_win32_sock_write: send:%d\n", result);
1178   
1179   if (result == SOCKET_ERROR)
1180     {
1181       *bytes_written = 0;
1182
1183       switch (WSAGetLastError ())
1184         {
1185         case WSAEINVAL:
1186           error = G_IO_CHANNEL_ERROR_INVAL;
1187           break;
1188         case WSAEWOULDBLOCK:
1189           return G_IO_STATUS_AGAIN;
1190 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1191         case WSAEINTR:
1192           goto repeat;
1193 #endif
1194         default:
1195           error = G_IO_CHANNEL_ERROR_FAILED;
1196           break;
1197         }
1198       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error");
1199       LOCK (win32_channel->mutex);
1200       SetEvent (win32_channel->data_avail_noticed_event);
1201       win32_channel->needs_close = 1;
1202       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1203       UNLOCK (win32_channel->mutex);
1204       return G_IO_STATUS_ERROR;
1205       /* FIXME get all errors, better error messages */
1206     }
1207   else
1208     {
1209       *bytes_written = result;
1210
1211       return G_IO_STATUS_NORMAL;
1212     }
1213 }
1214
1215 static GIOStatus
1216 g_io_win32_sock_close (GIOChannel *channel,
1217                        GError    **err)
1218 {
1219   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1220
1221   LOCK (win32_channel->mutex);
1222   if (win32_channel->running)
1223     {
1224       if (win32_channel->debug)
1225         g_print ("thread %#x: running, marking for later close\n",
1226                  win32_channel->thread_id);
1227       win32_channel->running = FALSE;
1228       win32_channel->needs_close = TRUE;
1229       SetEvent(win32_channel->data_avail_noticed_event);
1230     }
1231   if (win32_channel->fd != -1)
1232     {
1233       if (win32_channel->debug)
1234         g_print ("thread %#x: closing socket %d\n",
1235                  win32_channel->thread_id,
1236                  win32_channel->fd);
1237       
1238       closesocket (win32_channel->fd);
1239       win32_channel->fd = -1;
1240     }
1241   UNLOCK (win32_channel->mutex);
1242
1243   /* FIXME error detection? */
1244
1245   return G_IO_STATUS_NORMAL;
1246 }
1247
1248 static GSource *
1249 g_io_win32_sock_create_watch (GIOChannel    *channel,
1250                               GIOCondition   condition)
1251 {
1252   return g_io_win32_create_watch (channel, condition, select_thread);
1253 }
1254
1255 GIOChannel *
1256 g_io_channel_new_file (const gchar  *filename,
1257                        const gchar  *mode,
1258                        GError      **error)
1259 {
1260   int fid, flags, pmode;
1261   GIOChannel *channel;
1262
1263   enum { /* Cheesy hack */
1264     MODE_R = 1 << 0,
1265     MODE_W = 1 << 1,
1266     MODE_A = 1 << 2,
1267     MODE_PLUS = 1 << 3,
1268   } mode_num;
1269
1270   g_return_val_if_fail (filename != NULL, NULL);
1271   g_return_val_if_fail (mode != NULL, NULL);
1272   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1273
1274   switch (mode[0])
1275     {
1276       case 'r':
1277         mode_num = MODE_R;
1278         break;
1279       case 'w':
1280         mode_num = MODE_W;
1281         break;
1282       case 'a':
1283         mode_num = MODE_A;
1284         break;
1285       default:
1286         g_warning ("Invalid GIOFileMode %s.\n", mode);
1287         return NULL;
1288     }
1289
1290   switch (mode[1])
1291     {
1292       case '\0':
1293         break;
1294       case '+':
1295         if (mode[2] == '\0')
1296           {
1297             mode_num |= MODE_PLUS;
1298             break;
1299           }
1300         /* Fall through */
1301       default:
1302         g_warning ("Invalid GIOFileMode %s.\n", mode);
1303         return NULL;
1304     }
1305
1306   switch (mode_num)
1307     {
1308       case MODE_R:
1309         flags = O_RDONLY;
1310         pmode = _S_IREAD;
1311         break;
1312       case MODE_W:
1313         flags = O_WRONLY | O_TRUNC | O_CREAT;
1314         pmode = _S_IWRITE;
1315         break;
1316       case MODE_A:
1317         flags = O_WRONLY | O_APPEND | O_CREAT;
1318         pmode = _S_IWRITE;
1319         break;
1320       case MODE_R | MODE_PLUS:
1321         flags = O_RDWR;
1322         pmode = _S_IREAD | _S_IWRITE;
1323         break;
1324       case MODE_W | MODE_PLUS:
1325         flags = O_RDWR | O_TRUNC | O_CREAT;
1326         pmode = _S_IREAD | _S_IWRITE;
1327         break;
1328       case MODE_A | MODE_PLUS:
1329         flags = O_RDWR | O_APPEND | O_CREAT;
1330         pmode = _S_IREAD | _S_IWRITE;
1331         break;
1332       default:
1333         g_assert_not_reached ();
1334         flags = 0;
1335         pmode = 0;
1336     }
1337
1338   /* always open 'untranslated' */
1339   fid = open (filename, flags | _O_BINARY, pmode);
1340
1341   if (g_io_win32_get_debug_flag ())
1342     {
1343       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1344       g_win32_print_access_mode (flags|_O_BINARY);
1345       g_print (",%#o)=%d\n", pmode, fid);
1346     }
1347
1348   if (fid < 0)
1349     {
1350       g_set_error (error, G_FILE_ERROR,
1351                    g_file_error_from_errno (errno),
1352                    g_strerror (errno));
1353       return (GIOChannel *)NULL;
1354     }
1355
1356   channel = g_io_channel_win32_new_fd (fid);
1357
1358   /* XXX: move this to g_io_channel_win32_new_fd () */
1359   channel->close_on_unref = TRUE;
1360   channel->is_seekable = TRUE;
1361
1362   /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1363    * correspond to actual readability/writeability. Set to FALSE those
1364    * that mode doesn't allow
1365    */
1366   switch (mode_num)
1367     {
1368       case MODE_R:
1369         channel->is_writeable = FALSE;
1370         break;
1371       case MODE_W:
1372       case MODE_A:
1373         channel->is_readable = FALSE;
1374         break;
1375       case MODE_R | MODE_PLUS:
1376       case MODE_W | MODE_PLUS:
1377       case MODE_A | MODE_PLUS:
1378         break;
1379       default:
1380         g_assert_not_reached ();
1381     }
1382
1383   return channel;
1384 }
1385
1386 static GIOStatus
1387 g_io_win32_set_flags (GIOChannel *channel,
1388                       GIOFlags    flags,
1389                       GError    **err)
1390 {
1391   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1392
1393   if (win32_channel->debug)
1394     {
1395       g_print ("g_io_win32_set_flags: ");
1396       g_win32_print_gioflags (flags);
1397       g_print ("\n");
1398     }
1399
1400   g_warning ("g_io_win32_set_flags () not implemented.\n");
1401
1402   return G_IO_STATUS_NORMAL;
1403 }
1404
1405 static GIOFlags
1406 g_io_win32_fd_get_flags_internal (GIOChannel  *channel,
1407                                   struct stat *st)
1408 {
1409   GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1410   gchar c;
1411   DWORD count;
1412
1413   if (st->st_mode & _S_IFIFO)
1414     {
1415       channel->is_readable =
1416         (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
1417       channel->is_writeable =
1418         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1419       channel->is_seekable  = FALSE;
1420     }
1421   else if (st->st_mode & _S_IFCHR)
1422     {
1423       /* XXX Seems there is no way to find out the readability of file
1424        * handles to device files (consoles, mostly) without doing a
1425        * blocking read. So punt, use st->st_mode.
1426        */
1427       channel->is_readable  = !!(st->st_mode & _S_IREAD);
1428
1429       channel->is_writeable =
1430         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1431
1432       /* XXX What about devices that actually *are* seekable? But
1433        * those would probably not be handled using the C runtime
1434        * anyway, but using Windows-specific code.
1435        */
1436       channel->is_seekable = FALSE;
1437     }
1438   else
1439     {
1440       channel->is_readable =
1441         (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1442       channel->is_writeable =
1443         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1444       channel->is_seekable = TRUE;
1445     }
1446
1447   /* XXX: G_IO_FLAG_APPEND */
1448   /* XXX: G_IO_FLAG_NONBLOCK */
1449
1450   return 0;
1451 }
1452
1453 static GIOFlags
1454 g_io_win32_fd_get_flags (GIOChannel *channel)
1455 {
1456   struct stat st;
1457   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1458
1459   g_return_val_if_fail (win32_channel != NULL, 0);
1460   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1461
1462   if (0 == fstat (win32_channel->fd, &st))
1463     return g_io_win32_fd_get_flags_internal (channel, &st);
1464   else
1465     return 0;
1466 }
1467
1468 static GIOFlags
1469 g_io_win32_msg_get_flags (GIOChannel *channel)
1470 {
1471   return 0;
1472 }
1473
1474 static GIOFlags
1475 g_io_win32_sock_get_flags (GIOChannel *channel)
1476 {
1477   /* XXX Could do something here. */
1478   return 0;
1479 }
1480
1481 static GIOFuncs win32_channel_msg_funcs = {
1482   g_io_win32_msg_read,
1483   g_io_win32_msg_write,
1484   NULL,
1485   g_io_win32_msg_close,
1486   g_io_win32_msg_create_watch,
1487   g_io_win32_free,
1488   g_io_win32_set_flags,
1489   g_io_win32_msg_get_flags,
1490 };
1491
1492 static GIOFuncs win32_channel_fd_funcs = {
1493   g_io_win32_fd_read,
1494   g_io_win32_fd_write,
1495   g_io_win32_fd_seek,
1496   g_io_win32_fd_close,
1497   g_io_win32_fd_create_watch,
1498   g_io_win32_free,
1499   g_io_win32_set_flags,
1500   g_io_win32_fd_get_flags,
1501 };
1502
1503 static GIOFuncs win32_channel_sock_funcs = {
1504   g_io_win32_sock_read,
1505   g_io_win32_sock_write,
1506   NULL,
1507   g_io_win32_sock_close,
1508   g_io_win32_sock_create_watch,
1509   g_io_win32_free,
1510   g_io_win32_set_flags,
1511   g_io_win32_sock_get_flags,
1512 };
1513
1514 GIOChannel *
1515 g_io_channel_win32_new_messages (guint hwnd)
1516 {
1517   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1518   GIOChannel *channel = (GIOChannel *)win32_channel;
1519
1520   g_io_channel_init (channel);
1521   g_io_channel_win32_init (win32_channel);
1522   if (win32_channel->debug)
1523     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1524   channel->funcs = &win32_channel_msg_funcs;
1525   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1526   win32_channel->hwnd = (HWND) hwnd;
1527
1528   /* XXX: check this. */
1529   channel->is_readable = IsWindow (win32_channel->hwnd);
1530   channel->is_writeable = IsWindow (win32_channel->hwnd);
1531
1532   channel->is_seekable = FALSE;
1533
1534   return channel;
1535 }
1536
1537 static GIOChannel *
1538 g_io_channel_win32_new_fd_internal (gint         fd,
1539                                     struct stat *st)
1540 {
1541   GIOWin32Channel *win32_channel;
1542   GIOChannel *channel;
1543
1544   win32_channel = g_new (GIOWin32Channel, 1);
1545   channel = (GIOChannel *)win32_channel;
1546
1547   g_io_channel_init (channel);
1548   g_io_channel_win32_init (win32_channel);
1549   if (win32_channel->debug)
1550     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1551   channel->funcs = &win32_channel_fd_funcs;
1552   win32_channel->type = G_IO_WIN32_FILE_DESC;
1553   win32_channel->fd = fd;
1554
1555   g_io_win32_fd_get_flags_internal (channel, st);
1556   
1557   return channel;
1558 }
1559
1560 GIOChannel *
1561 g_io_channel_win32_new_fd (gint fd)
1562 {
1563   struct stat st;
1564
1565   if (fstat (fd, &st) == -1)
1566     {
1567       g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
1568       return NULL;
1569     }
1570
1571   return g_io_channel_win32_new_fd_internal (fd, &st);
1572 }
1573
1574 gint
1575 g_io_channel_win32_get_fd (GIOChannel *channel)
1576 {
1577   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1578
1579   return win32_channel->fd;
1580 }
1581
1582 GIOChannel *
1583 g_io_channel_win32_new_socket (int socket)
1584 {
1585   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1586   GIOChannel *channel = (GIOChannel *)win32_channel;
1587
1588   g_io_channel_init (channel);
1589   g_io_channel_win32_init (win32_channel);
1590   init_reset_sockets (win32_channel);
1591   if (win32_channel->debug)
1592     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1593   channel->funcs = &win32_channel_sock_funcs;
1594   win32_channel->type = G_IO_WIN32_SOCKET;
1595   win32_channel->fd = socket;
1596
1597   /* XXX: check this */
1598   channel->is_readable = TRUE;
1599   channel->is_writeable = TRUE;
1600
1601   channel->is_seekable = FALSE;
1602
1603   return channel;
1604 }
1605
1606 GIOChannel *
1607 g_io_channel_unix_new (gint fd)
1608 {
1609   gboolean is_fd, is_socket;
1610   struct stat st;
1611   int optval, optlen;
1612
1613   is_fd = (fstat (fd, &st) == 0);
1614
1615   optlen = sizeof (optval);
1616   is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR);
1617
1618   if (is_fd && is_socket)
1619     g_warning (G_STRLOC ": %d is both a file descriptor and a socket, file descriptor interpretation assumed.", fd);
1620
1621   if (is_fd)
1622     return g_io_channel_win32_new_fd_internal (fd, &st);
1623
1624   if (is_socket)
1625     return g_io_channel_win32_new_socket(fd);
1626
1627   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1628
1629   return NULL;
1630 }
1631
1632 gint
1633 g_io_channel_unix_get_fd (GIOChannel *channel)
1634 {
1635   return g_io_channel_win32_get_fd (channel);
1636 }
1637
1638 void
1639 g_io_channel_win32_set_debug (GIOChannel *channel,
1640                               gboolean    flag)
1641 {
1642   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1643
1644   win32_channel->debug = flag;
1645 }
1646
1647 gint
1648 g_io_channel_win32_poll (GPollFD *fds,
1649                          gint     n_fds,
1650                          gint     timeout)
1651 {
1652   int result;
1653
1654   g_return_val_if_fail (n_fds >= 0, 0);
1655
1656   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1657
1658   return result;
1659 }
1660
1661 void
1662 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1663                                 GIOCondition  condition,
1664                                 GPollFD      *fd)
1665 {
1666   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1667
1668   if (win32_channel->data_avail_event == NULL)
1669     create_events (win32_channel);
1670   
1671   fd->fd = (gint) win32_channel->data_avail_event;
1672   fd->events = condition;
1673
1674   if (win32_channel->thread_id == 0)
1675     {
1676       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1677         create_thread (win32_channel, condition, read_thread);
1678       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1679         create_thread (win32_channel, condition, select_thread);
1680     }
1681 }
1682
1683 /* Binary compatibility */
1684 GIOChannel *
1685 g_io_channel_win32_new_stream_socket (int socket)
1686 {
1687   return g_io_channel_win32_new_socket (socket);
1688 }