nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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, see <http://www.gnu.org/licenses/>. |
||
21 | */ |
||
22 | |||
23 | /* |
||
24 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
||
25 | * file for a list of people on the GLib Team. See the ChangeLog |
||
26 | * files for a list of changes. These files are distributed with |
||
27 | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
||
28 | */ |
||
29 | |||
30 | /* |
||
31 | * Bugs that are related to the code in this file: |
||
32 | * |
||
33 | * Bug 137968 - Sometimes a GIOFunc on Win32 is called with zero condition |
||
34 | * http://bugzilla.gnome.org/show_bug.cgi?id=137968 |
||
35 | * |
||
36 | * Bug 324234 - Using g_io_add_watch_full() to wait for connect() to return on a non-blocking socket returns prematurely |
||
37 | * http://bugzilla.gnome.org/show_bug.cgi?id=324234 |
||
38 | * |
||
39 | * Bug 331214 - g_io_channel async socket io stalls |
||
40 | * http://bugzilla.gnome.org/show_bug.cgi?id=331214 |
||
41 | * |
||
42 | * Bug 338943 - Multiple watches on the same socket |
||
43 | * http://bugzilla.gnome.org/show_bug.cgi?id=338943 |
||
44 | * |
||
45 | * Bug 357674 - 2 serious bugs in giowin32.c making glib iochannels useless |
||
46 | * http://bugzilla.gnome.org/show_bug.cgi?id=357674 |
||
47 | * |
||
48 | * Bug 425156 - GIOChannel deadlocks on a win32 socket |
||
49 | * http://bugzilla.gnome.org/show_bug.cgi?id=425156 |
||
50 | * |
||
51 | * Bug 468910 - giofunc condition=0 |
||
52 | * http://bugzilla.gnome.org/show_bug.cgi?id=468910 |
||
53 | * |
||
54 | * Bug 500246 - Bug fixes for giowin32 |
||
55 | * http://bugzilla.gnome.org/show_bug.cgi?id=500246 |
||
56 | * |
||
57 | * Bug 548278 - Async GETs connections are always terminated unexpectedly on windows |
||
58 | * http://bugzilla.gnome.org/show_bug.cgi?id=548278 |
||
59 | * |
||
60 | * Bug 548536 - giowin32 problem when adding and removing watches |
||
61 | * http://bugzilla.gnome.org/show_bug.cgi?id=548536 |
||
62 | * |
||
63 | * When fixing bugs related to the code in this file, either the above |
||
64 | * bugs or others, make sure that the test programs attached to the |
||
65 | * above bugs continue to work. |
||
66 | */ |
||
67 | |||
68 | #include "config.h" |
||
69 | |||
70 | #include "glib.h" |
||
71 | |||
72 | #include <stdlib.h> |
||
73 | #include <winsock2.h> |
||
74 | #include <windows.h> |
||
75 | #include <conio.h> |
||
76 | #include <fcntl.h> |
||
77 | #include <io.h> |
||
78 | #include <process.h> |
||
79 | #include <errno.h> |
||
80 | #include <sys/stat.h> |
||
81 | |||
82 | #include "gstdio.h" |
||
83 | #include "glibintl.h" |
||
84 | |||
85 | |||
86 | typedef struct _GIOWin32Channel GIOWin32Channel; |
||
87 | typedef struct _GIOWin32Watch GIOWin32Watch; |
||
88 | |||
89 | #define BUFFER_SIZE 4096 |
||
90 | |||
91 | typedef enum { |
||
92 | G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */ |
||
93 | |||
94 | G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from |
||
95 | * _open() or _pipe(), except for |
||
96 | * console IO. Separate thread to read |
||
97 | * or write. |
||
98 | */ |
||
99 | |||
100 | G_IO_WIN32_CONSOLE, /* Console IO (usually stdin, stdout, stderr) */ |
||
101 | |||
102 | G_IO_WIN32_SOCKET /* Sockets. No separate thread. */ |
||
103 | } GIOWin32ChannelType; |
||
104 | |||
105 | struct _GIOWin32Channel { |
||
106 | GIOChannel channel; |
||
107 | gint fd; /* Either a Unix-like file handle as provided |
||
108 | * by the Microsoft C runtime, or a SOCKET |
||
109 | * as provided by WinSock. |
||
110 | */ |
||
111 | GIOWin32ChannelType type; |
||
112 | |||
113 | gboolean debug; |
||
114 | |||
115 | /* Field used by G_IO_WIN32_WINDOWS_MESSAGES channels */ |
||
116 | HWND hwnd; /* Handle of window, or NULL */ |
||
117 | |||
118 | /* Fields used by G_IO_WIN32_FILE_DESC channels. */ |
||
119 | CRITICAL_SECTION mutex; |
||
120 | |||
121 | int direction; /* 0 means we read from it, |
||
122 | * 1 means we write to it. |
||
123 | */ |
||
124 | |||
125 | gboolean running; /* Is reader or writer thread |
||
126 | * running. FALSE if EOF has been |
||
127 | * reached by the reader thread. |
||
128 | */ |
||
129 | |||
130 | gboolean needs_close; /* If the channel has been closed while |
||
131 | * the reader thread was still running. |
||
132 | */ |
||
133 | |||
134 | guint thread_id; /* If non-NULL the channel has or has |
||
135 | * had a reader or writer thread. |
||
136 | */ |
||
137 | HANDLE data_avail_event; |
||
138 | |||
139 | gushort revents; |
||
140 | |||
141 | /* Data is kept in a circular buffer. To be able to distinguish between |
||
142 | * empty and full buffers, we cannot fill it completely, but have to |
||
143 | * leave a one character gap. |
||
144 | * |
||
145 | * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE). |
||
146 | * |
||
147 | * Empty: wrp == rdp |
||
148 | * Full: (wrp + 1) % BUFFER_SIZE == rdp |
||
149 | * Partial: otherwise |
||
150 | */ |
||
151 | guchar *buffer; /* (Circular) buffer */ |
||
152 | gint wrp, rdp; /* Buffer indices for writing and reading */ |
||
153 | HANDLE space_avail_event; |
||
154 | |||
155 | /* Fields used by G_IO_WIN32_SOCKET channels */ |
||
156 | int event_mask; |
||
157 | int last_events; |
||
158 | HANDLE event; |
||
159 | gboolean write_would_have_blocked; |
||
160 | gboolean ever_writable; |
||
161 | }; |
||
162 | |||
163 | struct _GIOWin32Watch { |
||
164 | GSource source; |
||
165 | GPollFD pollfd; |
||
166 | GIOChannel *channel; |
||
167 | GIOCondition condition; |
||
168 | }; |
||
169 | |||
170 | static void |
||
171 | g_win32_print_access_mode (int flags) |
||
172 | { |
||
173 | g_print ("%s%s%s%s%s%s%s%s%s%s", |
||
174 | ((flags & 0x3) == _O_RDWR ? "O_RDWR" : |
||
175 | ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" : |
||
176 | ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))), |
||
177 | (flags & _O_APPEND ? "|O_APPEND" : ""), |
||
178 | (flags & _O_RANDOM ? "|O_RANDOM" : ""), |
||
179 | (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""), |
||
180 | (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""), |
||
181 | (flags & _O_CREAT ? "|O_CREAT" : ""), |
||
182 | (flags & _O_TRUNC ? "|O_TRUNC" : ""), |
||
183 | (flags & _O_EXCL ? "|O_EXCL" : ""), |
||
184 | (flags & _O_TEXT ? "|O_TEXT" : ""), |
||
185 | (flags & _O_BINARY ? "|O_BINARY" : "")); |
||
186 | } |
||
187 | |||
188 | static void |
||
189 | g_win32_print_gioflags (GIOFlags flags) |
||
190 | { |
||
191 | char *bar = ""; |
||
192 | |||
193 | if (flags & G_IO_FLAG_APPEND) |
||
194 | bar = "|", g_print ("APPEND"); |
||
195 | if (flags & G_IO_FLAG_NONBLOCK) |
||
196 | g_print ("%sNONBLOCK", bar), bar = "|"; |
||
197 | if (flags & G_IO_FLAG_IS_READABLE) |
||
198 | g_print ("%sREADABLE", bar), bar = "|"; |
||
199 | if (flags & G_IO_FLAG_IS_WRITABLE) |
||
200 | g_print ("%sWRITABLE", bar), bar = "|"; |
||
201 | if (flags & G_IO_FLAG_IS_SEEKABLE) |
||
202 | g_print ("%sSEEKABLE", bar), bar = "|"; |
||
203 | } |
||
204 | |||
205 | static const char * |
||
206 | event_mask_to_string (int mask) |
||
207 | { |
||
208 | char buf[100]; |
||
209 | int checked_bits = 0; |
||
210 | char *bufp = buf; |
||
211 | |||
212 | if (mask == 0) |
||
213 | return ""; |
||
214 | |||
215 | #define BIT(n) checked_bits |= FD_##n; if (mask & FD_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : "")) |
||
216 | |||
217 | BIT (READ); |
||
218 | BIT (WRITE); |
||
219 | BIT (OOB); |
||
220 | BIT (ACCEPT); |
||
221 | BIT (CONNECT); |
||
222 | BIT (CLOSE); |
||
223 | BIT (QOS); |
||
224 | BIT (GROUP_QOS); |
||
225 | BIT (ROUTING_INTERFACE_CHANGE); |
||
226 | BIT (ADDRESS_LIST_CHANGE); |
||
227 | |||
228 | #undef BIT |
||
229 | |||
230 | if ((mask & ~checked_bits) != 0) |
||
231 | bufp += sprintf (bufp, "|%#x", mask & ~checked_bits); |
||
232 | |||
233 | return g_quark_to_string (g_quark_from_string (buf)); |
||
234 | } |
||
235 | |||
236 | static const char * |
||
237 | condition_to_string (GIOCondition condition) |
||
238 | { |
||
239 | char buf[100]; |
||
240 | int checked_bits = 0; |
||
241 | char *bufp = buf; |
||
242 | |||
243 | if (condition == 0) |
||
244 | return ""; |
||
245 | |||
246 | #define BIT(n) checked_bits |= G_IO_##n; if (condition & G_IO_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : "")) |
||
247 | |||
248 | BIT (IN); |
||
249 | BIT (OUT); |
||
250 | BIT (PRI); |
||
251 | BIT (ERR); |
||
252 | BIT (HUP); |
||
253 | BIT (NVAL); |
||
254 | |||
255 | #undef BIT |
||
256 | |||
257 | if ((condition & ~checked_bits) != 0) |
||
258 | bufp += sprintf (bufp, "|%#x", condition & ~checked_bits); |
||
259 | |||
260 | return g_quark_to_string (g_quark_from_string (buf)); |
||
261 | } |
||
262 | |||
263 | static gboolean |
||
264 | g_io_win32_get_debug_flag (void) |
||
265 | { |
||
266 | return (getenv ("G_IO_WIN32_DEBUG") != NULL); |
||
267 | } |
||
268 | |||
269 | static void |
||
270 | g_io_channel_win32_init (GIOWin32Channel *channel) |
||
271 | { |
||
272 | channel->debug = g_io_win32_get_debug_flag (); |
||
273 | |||
274 | InitializeCriticalSection (&channel->mutex); |
||
275 | channel->running = FALSE; |
||
276 | channel->needs_close = FALSE; |
||
277 | channel->thread_id = 0; |
||
278 | channel->data_avail_event = NULL; |
||
279 | channel->revents = 0; |
||
280 | channel->buffer = NULL; |
||
281 | channel->space_avail_event = NULL; |
||
282 | |||
283 | channel->event_mask = 0; |
||
284 | channel->last_events = 0; |
||
285 | channel->event = NULL; |
||
286 | channel->write_would_have_blocked = FALSE; |
||
287 | channel->ever_writable = FALSE; |
||
288 | } |
||
289 | |||
290 | static void |
||
291 | create_events (GIOWin32Channel *channel) |
||
292 | { |
||
293 | SECURITY_ATTRIBUTES sec_attrs; |
||
294 | |||
295 | sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES); |
||
296 | sec_attrs.lpSecurityDescriptor = NULL; |
||
297 | sec_attrs.bInheritHandle = FALSE; |
||
298 | |||
299 | /* The data available event is manual reset, the space available event |
||
300 | * is automatic reset. |
||
301 | */ |
||
302 | if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL)) |
||
303 | || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))) |
||
304 | { |
||
305 | gchar *emsg = g_win32_error_message (GetLastError ()); |
||
306 | |||
307 | g_error ("Error creating event: %s", emsg); |
||
308 | g_free (emsg); |
||
309 | } |
||
310 | } |
||
311 | |||
312 | static unsigned __stdcall |
||
313 | read_thread (void *parameter) |
||
314 | { |
||
315 | GIOWin32Channel *channel = parameter; |
||
316 | guchar *buffer; |
||
317 | gint nbytes; |
||
318 | |||
319 | g_io_channel_ref ((GIOChannel *)channel); |
||
320 | |||
321 | if (channel->debug) |
||
322 | g_print ("read_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n", |
||
323 | channel->thread_id, |
||
324 | channel->fd, |
||
325 | channel->data_avail_event, |
||
326 | channel->space_avail_event); |
||
327 | |||
328 | channel->direction = 0; |
||
329 | channel->buffer = g_malloc (BUFFER_SIZE); |
||
330 | channel->rdp = channel->wrp = 0; |
||
331 | channel->running = TRUE; |
||
332 | |||
333 | SetEvent (channel->space_avail_event); |
||
334 | |||
335 | EnterCriticalSection (&channel->mutex); |
||
336 | while (channel->running) |
||
337 | { |
||
338 | if (channel->debug) |
||
339 | g_print ("read_thread %#x: rdp=%d, wrp=%d\n", |
||
340 | channel->thread_id, channel->rdp, channel->wrp); |
||
341 | if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) |
||
342 | { |
||
343 | /* Buffer is full */ |
||
344 | if (channel->debug) |
||
345 | g_print ("read_thread %#x: resetting space_avail\n", |
||
346 | channel->thread_id); |
||
347 | ResetEvent (channel->space_avail_event); |
||
348 | if (channel->debug) |
||
349 | g_print ("read_thread %#x: waiting for space\n", |
||
350 | channel->thread_id); |
||
351 | LeaveCriticalSection (&channel->mutex); |
||
352 | WaitForSingleObject (channel->space_avail_event, INFINITE); |
||
353 | EnterCriticalSection (&channel->mutex); |
||
354 | if (channel->debug) |
||
355 | g_print ("read_thread %#x: rdp=%d, wrp=%d\n", |
||
356 | channel->thread_id, channel->rdp, channel->wrp); |
||
357 | } |
||
358 | |||
359 | buffer = channel->buffer + channel->wrp; |
||
360 | |||
361 | /* Always leave at least one byte unused gap to be able to |
||
362 | * distinguish between the full and empty condition... |
||
363 | */ |
||
364 | nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE, |
||
365 | BUFFER_SIZE - channel->wrp); |
||
366 | |||
367 | if (channel->debug) |
||
368 | g_print ("read_thread %#x: calling read() for %d bytes\n", |
||
369 | channel->thread_id, nbytes); |
||
370 | |||
371 | LeaveCriticalSection (&channel->mutex); |
||
372 | |||
373 | nbytes = read (channel->fd, buffer, nbytes); |
||
374 | |||
375 | EnterCriticalSection (&channel->mutex); |
||
376 | |||
377 | channel->revents = G_IO_IN; |
||
378 | if (nbytes == 0) |
||
379 | channel->revents |= G_IO_HUP; |
||
380 | else if (nbytes < 0) |
||
381 | channel->revents |= G_IO_ERR; |
||
382 | |||
383 | if (channel->debug) |
||
384 | g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n", |
||
385 | channel->thread_id, nbytes, channel->rdp, channel->wrp); |
||
386 | |||
387 | if (nbytes <= 0) |
||
388 | break; |
||
389 | |||
390 | channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE; |
||
391 | if (channel->debug) |
||
392 | g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n", |
||
393 | channel->thread_id, channel->rdp, channel->wrp); |
||
394 | SetEvent (channel->data_avail_event); |
||
395 | } |
||
396 | |||
397 | channel->running = FALSE; |
||
398 | if (channel->needs_close) |
||
399 | { |
||
400 | if (channel->debug) |
||
401 | g_print ("read_thread %#x: channel fd %d needs closing\n", |
||
402 | channel->thread_id, channel->fd); |
||
403 | close (channel->fd); |
||
404 | channel->fd = -1; |
||
405 | } |
||
406 | |||
407 | if (channel->debug) |
||
408 | g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n", |
||
409 | channel->thread_id, channel->rdp, channel->wrp); |
||
410 | SetEvent (channel->data_avail_event); |
||
411 | LeaveCriticalSection (&channel->mutex); |
||
412 | |||
413 | g_io_channel_unref ((GIOChannel *)channel); |
||
414 | |||
415 | /* No need to call _endthreadex(), the actual thread starter routine |
||
416 | * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls |
||
417 | * _endthreadex() for us. |
||
418 | */ |
||
419 | |||
420 | return 0; |
||
421 | } |
||
422 | |||
423 | static unsigned __stdcall |
||
424 | write_thread (void *parameter) |
||
425 | { |
||
426 | GIOWin32Channel *channel = parameter; |
||
427 | guchar *buffer; |
||
428 | gint nbytes; |
||
429 | |||
430 | g_io_channel_ref ((GIOChannel *)channel); |
||
431 | |||
432 | if (channel->debug) |
||
433 | g_print ("write_thread %#x: start fd=%d, data_avail=%p space_avail=%p\n", |
||
434 | channel->thread_id, |
||
435 | channel->fd, |
||
436 | channel->data_avail_event, |
||
437 | channel->space_avail_event); |
||
438 | |||
439 | channel->direction = 1; |
||
440 | channel->buffer = g_malloc (BUFFER_SIZE); |
||
441 | channel->rdp = channel->wrp = 0; |
||
442 | channel->running = TRUE; |
||
443 | |||
444 | SetEvent (channel->space_avail_event); |
||
445 | |||
446 | /* We use the same event objects as for a reader thread, but with |
||
447 | * reversed meaning. So, space_avail is used if data is available |
||
448 | * for writing, and data_avail is used if space is available in the |
||
449 | * write buffer. |
||
450 | */ |
||
451 | |||
452 | EnterCriticalSection (&channel->mutex); |
||
453 | while (channel->running || channel->rdp != channel->wrp) |
||
454 | { |
||
455 | if (channel->debug) |
||
456 | g_print ("write_thread %#x: rdp=%d, wrp=%d\n", |
||
457 | channel->thread_id, channel->rdp, channel->wrp); |
||
458 | if (channel->wrp == channel->rdp) |
||
459 | { |
||
460 | /* Buffer is empty. */ |
||
461 | if (channel->debug) |
||
462 | g_print ("write_thread %#x: resetting space_avail\n", |
||
463 | channel->thread_id); |
||
464 | ResetEvent (channel->space_avail_event); |
||
465 | if (channel->debug) |
||
466 | g_print ("write_thread %#x: waiting for data\n", |
||
467 | channel->thread_id); |
||
468 | channel->revents = G_IO_OUT; |
||
469 | SetEvent (channel->data_avail_event); |
||
470 | LeaveCriticalSection (&channel->mutex); |
||
471 | WaitForSingleObject (channel->space_avail_event, INFINITE); |
||
472 | |||
473 | EnterCriticalSection (&channel->mutex); |
||
474 | if (channel->rdp == channel->wrp) |
||
475 | break; |
||
476 | |||
477 | if (channel->debug) |
||
478 | g_print ("write_thread %#x: rdp=%d, wrp=%d\n", |
||
479 | channel->thread_id, channel->rdp, channel->wrp); |
||
480 | } |
||
481 | |||
482 | buffer = channel->buffer + channel->rdp; |
||
483 | if (channel->rdp < channel->wrp) |
||
484 | nbytes = channel->wrp - channel->rdp; |
||
485 | else |
||
486 | nbytes = BUFFER_SIZE - channel->rdp; |
||
487 | |||
488 | if (channel->debug) |
||
489 | g_print ("write_thread %#x: calling write() for %d bytes\n", |
||
490 | channel->thread_id, nbytes); |
||
491 | |||
492 | LeaveCriticalSection (&channel->mutex); |
||
493 | nbytes = write (channel->fd, buffer, nbytes); |
||
494 | EnterCriticalSection (&channel->mutex); |
||
495 | |||
496 | if (channel->debug) |
||
497 | g_print ("write_thread %#x: write(%i) returned %d, rdp=%d, wrp=%d\n", |
||
498 | channel->thread_id, channel->fd, nbytes, channel->rdp, channel->wrp); |
||
499 | |||
500 | channel->revents = 0; |
||
501 | if (nbytes > 0) |
||
502 | channel->revents |= G_IO_OUT; |
||
503 | else if (nbytes <= 0) |
||
504 | channel->revents |= G_IO_ERR; |
||
505 | |||
506 | channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE; |
||
507 | |||
508 | if (nbytes <= 0) |
||
509 | break; |
||
510 | |||
511 | if (channel->debug) |
||
512 | g_print ("write_thread: setting data_avail for thread %#x\n", |
||
513 | channel->thread_id); |
||
514 | SetEvent (channel->data_avail_event); |
||
515 | } |
||
516 | |||
517 | channel->running = FALSE; |
||
518 | if (channel->needs_close) |
||
519 | { |
||
520 | if (channel->debug) |
||
521 | g_print ("write_thread %#x: channel fd %d needs closing\n", |
||
522 | channel->thread_id, channel->fd); |
||
523 | close (channel->fd); |
||
524 | channel->fd = -1; |
||
525 | } |
||
526 | |||
527 | LeaveCriticalSection (&channel->mutex); |
||
528 | |||
529 | g_io_channel_unref ((GIOChannel *)channel); |
||
530 | |||
531 | return 0; |
||
532 | } |
||
533 | |||
534 | static void |
||
535 | create_thread (GIOWin32Channel *channel, |
||
536 | GIOCondition condition, |
||
537 | unsigned (__stdcall *thread) (void *parameter)) |
||
538 | { |
||
539 | HANDLE thread_handle; |
||
540 | |||
541 | thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0, |
||
542 | &channel->thread_id); |
||
543 | if (thread_handle == 0) |
||
544 | g_warning ("Error creating thread: %s.", |
||
545 | g_strerror (errno)); |
||
546 | else if (!CloseHandle (thread_handle)) |
||
547 | { |
||
548 | gchar *emsg = g_win32_error_message (GetLastError ()); |
||
549 | |||
550 | g_warning ("Error closing thread handle: %s.", emsg); |
||
551 | g_free (emsg); |
||
552 | } |
||
553 | |||
554 | WaitForSingleObject (channel->space_avail_event, INFINITE); |
||
555 | } |
||
556 | |||
557 | static GIOStatus |
||
558 | buffer_read (GIOWin32Channel *channel, |
||
559 | gchar *dest, |
||
560 | gsize count, |
||
561 | gsize *bytes_read, |
||
562 | GError **err) |
||
563 | { |
||
564 | guint nbytes; |
||
565 | guint left = count; |
||
566 | |||
567 | EnterCriticalSection (&channel->mutex); |
||
568 | if (channel->debug) |
||
569 | g_print ("reading from thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n", |
||
570 | channel->thread_id, count, channel->rdp, channel->wrp); |
||
571 | |||
572 | if (channel->wrp == channel->rdp) |
||
573 | { |
||
574 | LeaveCriticalSection (&channel->mutex); |
||
575 | if (channel->debug) |
||
576 | g_print ("waiting for data from thread %#x\n", channel->thread_id); |
||
577 | WaitForSingleObject (channel->data_avail_event, INFINITE); |
||
578 | if (channel->debug) |
||
579 | g_print ("done waiting for data from thread %#x\n", channel->thread_id); |
||
580 | EnterCriticalSection (&channel->mutex); |
||
581 | if (channel->wrp == channel->rdp && !channel->running) |
||
582 | { |
||
583 | if (channel->debug) |
||
584 | g_print ("wrp==rdp, !running\n"); |
||
585 | LeaveCriticalSection (&channel->mutex); |
||
586 | *bytes_read = 0; |
||
587 | return G_IO_STATUS_EOF; |
||
588 | } |
||
589 | } |
||
590 | |||
591 | if (channel->rdp < channel->wrp) |
||
592 | nbytes = channel->wrp - channel->rdp; |
||
593 | else |
||
594 | nbytes = BUFFER_SIZE - channel->rdp; |
||
595 | LeaveCriticalSection (&channel->mutex); |
||
596 | nbytes = MIN (left, nbytes); |
||
597 | if (channel->debug) |
||
598 | g_print ("moving %d bytes from thread %#x\n", |
||
599 | nbytes, channel->thread_id); |
||
600 | memcpy (dest, channel->buffer + channel->rdp, nbytes); |
||
601 | dest += nbytes; |
||
602 | left -= nbytes; |
||
603 | EnterCriticalSection (&channel->mutex); |
||
604 | channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE; |
||
605 | if (channel->debug) |
||
606 | g_print ("setting space_avail for thread %#x\n", channel->thread_id); |
||
607 | SetEvent (channel->space_avail_event); |
||
608 | if (channel->debug) |
||
609 | g_print ("for thread %#x: rdp=%d, wrp=%d\n", |
||
610 | channel->thread_id, channel->rdp, channel->wrp); |
||
611 | if (channel->running && channel->wrp == channel->rdp) |
||
612 | { |
||
613 | if (channel->debug) |
||
614 | g_print ("resetting data_avail of thread %#x\n", |
||
615 | channel->thread_id); |
||
616 | ResetEvent (channel->data_avail_event); |
||
617 | }; |
||
618 | LeaveCriticalSection (&channel->mutex); |
||
619 | |||
620 | /* We have no way to indicate any errors form the actual |
||
621 | * read() or recv() call in the reader thread. Should we have? |
||
622 | */ |
||
623 | *bytes_read = count - left; |
||
624 | return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; |
||
625 | } |
||
626 | |||
627 | |||
628 | static GIOStatus |
||
629 | buffer_write (GIOWin32Channel *channel, |
||
630 | const gchar *dest, |
||
631 | gsize count, |
||
632 | gsize *bytes_written, |
||
633 | GError **err) |
||
634 | { |
||
635 | guint nbytes; |
||
636 | guint left = count; |
||
637 | |||
638 | EnterCriticalSection (&channel->mutex); |
||
639 | if (channel->debug) |
||
640 | g_print ("buffer_write: writing to thread %#x %" G_GSIZE_FORMAT " bytes, rdp=%d, wrp=%d\n", |
||
641 | channel->thread_id, count, channel->rdp, channel->wrp); |
||
642 | |||
643 | if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) |
||
644 | { |
||
645 | /* Buffer is full */ |
||
646 | if (channel->debug) |
||
647 | g_print ("buffer_write: tid %#x: resetting data_avail\n", |
||
648 | channel->thread_id); |
||
649 | ResetEvent (channel->data_avail_event); |
||
650 | if (channel->debug) |
||
651 | g_print ("buffer_write: tid %#x: waiting for space\n", |
||
652 | channel->thread_id); |
||
653 | LeaveCriticalSection (&channel->mutex); |
||
654 | WaitForSingleObject (channel->data_avail_event, INFINITE); |
||
655 | EnterCriticalSection (&channel->mutex); |
||
656 | if (channel->debug) |
||
657 | g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d\n", |
||
658 | channel->thread_id, channel->rdp, channel->wrp); |
||
659 | } |
||
660 | |||
661 | nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE, |
||
662 | BUFFER_SIZE - channel->wrp); |
||
663 | |||
664 | LeaveCriticalSection (&channel->mutex); |
||
665 | nbytes = MIN (left, nbytes); |
||
666 | if (channel->debug) |
||
667 | g_print ("buffer_write: tid %#x: writing %d bytes\n", |
||
668 | channel->thread_id, nbytes); |
||
669 | memcpy (channel->buffer + channel->wrp, dest, nbytes); |
||
670 | dest += nbytes; |
||
671 | left -= nbytes; |
||
672 | EnterCriticalSection (&channel->mutex); |
||
673 | |||
674 | channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE; |
||
675 | if (channel->debug) |
||
676 | g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d, setting space_avail\n", |
||
677 | channel->thread_id, channel->rdp, channel->wrp); |
||
678 | SetEvent (channel->space_avail_event); |
||
679 | |||
680 | if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp) |
||
681 | { |
||
682 | /* Buffer is full */ |
||
683 | if (channel->debug) |
||
684 | g_print ("buffer_write: tid %#x: resetting data_avail\n", |
||
685 | channel->thread_id); |
||
686 | ResetEvent (channel->data_avail_event); |
||
687 | } |
||
688 | |||
689 | LeaveCriticalSection (&channel->mutex); |
||
690 | |||
691 | /* We have no way to indicate any errors form the actual |
||
692 | * write() call in the writer thread. Should we have? |
||
693 | */ |
||
694 | *bytes_written = count - left; |
||
695 | return (*bytes_written > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; |
||
696 | } |
||
697 | |||
698 | |||
699 | static gboolean |
||
700 | g_io_win32_prepare (GSource *source, |
||
701 | gint *timeout) |
||
702 | { |
||
703 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
704 | GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); |
||
705 | GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; |
||
706 | int event_mask; |
||
707 | |||
708 | *timeout = -1; |
||
709 | |||
710 | if (channel->debug) |
||
711 | g_print ("g_io_win32_prepare: source=%p channel=%p", source, channel); |
||
712 | |||
713 | switch (channel->type) |
||
714 | { |
||
715 | case G_IO_WIN32_WINDOWS_MESSAGES: |
||
716 | if (channel->debug) |
||
717 | g_print (" MSG"); |
||
718 | break; |
||
719 | |||
720 | case G_IO_WIN32_CONSOLE: |
||
721 | if (channel->debug) |
||
722 | g_print (" CON"); |
||
723 | break; |
||
724 | |||
725 | case G_IO_WIN32_FILE_DESC: |
||
726 | if (channel->debug) |
||
727 | g_print (" FD thread=%#x buffer_condition:{%s}" |
||
728 | "\n watch->pollfd.events:{%s} watch->pollfd.revents:{%s} channel->revents:{%s}", |
||
729 | channel->thread_id, condition_to_string (buffer_condition), |
||
730 | condition_to_string (watch->pollfd.events), |
||
731 | condition_to_string (watch->pollfd.revents), |
||
732 | condition_to_string (channel->revents)); |
||
733 | |||
734 | EnterCriticalSection (&channel->mutex); |
||
735 | if (channel->running) |
||
736 | { |
||
737 | if (channel->direction == 0 && channel->wrp == channel->rdp) |
||
738 | { |
||
739 | if (channel->debug) |
||
740 | g_print ("\n setting revents=0"); |
||
741 | channel->revents = 0; |
||
742 | } |
||
743 | } |
||
744 | else |
||
745 | { |
||
746 | if (channel->direction == 1 |
||
747 | && (channel->wrp + 1) % BUFFER_SIZE == channel->rdp) |
||
748 | { |
||
749 | if (channel->debug) |
||
750 | g_print ("\n setting revents=0"); |
||
751 | channel->revents = 0; |
||
752 | } |
||
753 | } |
||
754 | LeaveCriticalSection (&channel->mutex); |
||
755 | break; |
||
756 | |||
757 | case G_IO_WIN32_SOCKET: |
||
758 | if (channel->debug) |
||
759 | g_print (" SOCK"); |
||
760 | event_mask = 0; |
||
761 | if (watch->condition & G_IO_IN) |
||
762 | event_mask |= (FD_READ | FD_ACCEPT); |
||
763 | if (watch->condition & G_IO_OUT) |
||
764 | event_mask |= (FD_WRITE | FD_CONNECT); |
||
765 | event_mask |= FD_CLOSE; |
||
766 | |||
767 | if (channel->event_mask != event_mask) |
||
768 | { |
||
769 | if (channel->debug) |
||
770 | g_print ("\n WSAEventSelect(%d,%p,{%s})", |
||
771 | channel->fd, (HANDLE) watch->pollfd.fd, |
||
772 | event_mask_to_string (event_mask)); |
||
773 | if (WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, |
||
774 | event_mask) == SOCKET_ERROR) |
||
775 | if (channel->debug) |
||
776 | { |
||
777 | gchar *emsg = g_win32_error_message (WSAGetLastError ()); |
||
778 | |||
779 | g_print (" failed: %s", emsg); |
||
780 | g_free (emsg); |
||
781 | } |
||
782 | channel->event_mask = event_mask; |
||
783 | |||
784 | if (channel->debug) |
||
785 | g_print ("\n setting last_events=0"); |
||
786 | channel->last_events = 0; |
||
787 | |||
788 | if ((event_mask & FD_WRITE) && |
||
789 | channel->ever_writable && |
||
790 | !channel->write_would_have_blocked) |
||
791 | { |
||
792 | if (channel->debug) |
||
793 | g_print (" WSASetEvent(%p)", (WSAEVENT) watch->pollfd.fd); |
||
794 | WSASetEvent ((WSAEVENT) watch->pollfd.fd); |
||
795 | } |
||
796 | } |
||
797 | break; |
||
798 | |||
799 | default: |
||
800 | g_assert_not_reached (); |
||
801 | abort (); |
||
802 | } |
||
803 | if (channel->debug) |
||
804 | g_print ("\n"); |
||
805 | |||
806 | return ((watch->condition & buffer_condition) == watch->condition); |
||
807 | } |
||
808 | |||
809 | static gboolean |
||
810 | g_io_win32_check (GSource *source) |
||
811 | { |
||
812 | MSG msg; |
||
813 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
814 | GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; |
||
815 | GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); |
||
816 | WSANETWORKEVENTS events; |
||
817 | |||
818 | if (channel->debug) |
||
819 | g_print ("g_io_win32_check: source=%p channel=%p", source, channel); |
||
820 | |||
821 | switch (channel->type) |
||
822 | { |
||
823 | case G_IO_WIN32_WINDOWS_MESSAGES: |
||
824 | if (channel->debug) |
||
825 | g_print (" MSG\n"); |
||
826 | return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE)); |
||
827 | |||
828 | case G_IO_WIN32_FILE_DESC: |
||
829 | if (channel->debug) |
||
830 | g_print (" FD thread=%#x buffer_condition=%s\n" |
||
831 | " watch->pollfd.events={%s} watch->pollfd.revents={%s} channel->revents={%s}\n", |
||
832 | channel->thread_id, condition_to_string (buffer_condition), |
||
833 | condition_to_string (watch->pollfd.events), |
||
834 | condition_to_string (watch->pollfd.revents), |
||
835 | condition_to_string (channel->revents)); |
||
836 | |||
837 | watch->pollfd.revents = (watch->pollfd.events & channel->revents); |
||
838 | |||
839 | return ((watch->pollfd.revents | buffer_condition) & watch->condition); |
||
840 | |||
841 | case G_IO_WIN32_CONSOLE: |
||
842 | if (channel->debug) |
||
843 | g_print (" CON\n"); |
||
844 | if (watch->channel->is_writeable) |
||
845 | return TRUE; |
||
846 | else if (watch->channel->is_readable) |
||
847 | { |
||
848 | INPUT_RECORD buffer; |
||
849 | DWORD n; |
||
850 | if (PeekConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n) && |
||
851 | n == 1) |
||
852 | { |
||
853 | /* _kbhit() does quite complex processing to find out |
||
854 | * whether at least one of the key events pending corresponds |
||
855 | * to a "real" character that can be read. |
||
856 | */ |
||
857 | if (_kbhit ()) |
||
858 | return TRUE; |
||
859 | |||
860 | /* Discard all other kinds of events */ |
||
861 | ReadConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n); |
||
862 | } |
||
863 | } |
||
864 | return FALSE; |
||
865 | |||
866 | case G_IO_WIN32_SOCKET: |
||
867 | if (channel->debug) |
||
868 | g_print (" SOCK"); |
||
869 | if (channel->last_events & FD_WRITE) |
||
870 | { |
||
871 | if (channel->debug) |
||
872 | g_print (" sock=%d event=%p last_events has FD_WRITE", |
||
873 | channel->fd, (HANDLE) watch->pollfd.fd); |
||
874 | } |
||
875 | else |
||
876 | { |
||
877 | WSAEnumNetworkEvents (channel->fd, 0, &events); |
||
878 | |||
879 | if (channel->debug) |
||
880 | g_print ("\n revents={%s} condition={%s}" |
||
881 | "\n WSAEnumNetworkEvents(%d,0) sets events={%s}", |
||
882 | condition_to_string (watch->pollfd.revents), |
||
883 | condition_to_string (watch->condition), |
||
884 | channel->fd, |
||
885 | event_mask_to_string (events.lNetworkEvents)); |
||
886 | |||
887 | if (watch->pollfd.revents != 0 && |
||
888 | events.lNetworkEvents == 0 && |
||
889 | !(channel->event_mask & FD_WRITE)) |
||
890 | { |
||
891 | channel->event_mask = 0; |
||
892 | if (channel->debug) |
||
893 | g_print ("\n WSAEventSelect(%d,%p,{})", |
||
894 | channel->fd, (HANDLE) watch->pollfd.fd); |
||
895 | WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, 0); |
||
896 | if (channel->debug) |
||
897 | g_print (" ResetEvent(%p)", |
||
898 | (HANDLE) watch->pollfd.fd); |
||
899 | ResetEvent ((HANDLE) watch->pollfd.fd); |
||
900 | } |
||
901 | else if (events.lNetworkEvents & FD_WRITE) |
||
902 | channel->ever_writable = TRUE; |
||
903 | channel->last_events = events.lNetworkEvents; |
||
904 | } |
||
905 | |||
906 | watch->pollfd.revents = 0; |
||
907 | if (channel->last_events & (FD_READ | FD_ACCEPT)) |
||
908 | watch->pollfd.revents |= G_IO_IN; |
||
909 | |||
910 | if (channel->last_events & FD_WRITE) |
||
911 | watch->pollfd.revents |= G_IO_OUT; |
||
912 | else |
||
913 | { |
||
914 | /* We have called WSAEnumNetworkEvents() above but it didn't |
||
915 | * set FD_WRITE. |
||
916 | */ |
||
917 | if (events.lNetworkEvents & FD_CONNECT) |
||
918 | { |
||
919 | if (events.iErrorCode[FD_CONNECT_BIT] == 0) |
||
920 | watch->pollfd.revents |= G_IO_OUT; |
||
921 | else |
||
922 | watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR); |
||
923 | } |
||
924 | if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE))) |
||
925 | watch->pollfd.revents |= G_IO_HUP; |
||
926 | } |
||
927 | |||
928 | /* Regardless of WSAEnumNetworkEvents() result, if watching for |
||
929 | * writability, and if we have ever got a FD_WRITE event, and |
||
930 | * unless last write would have blocked, set G_IO_OUT. But never |
||
931 | * set both G_IO_OUT and G_IO_HUP. |
||
932 | */ |
||
933 | if (!(watch->pollfd.revents & G_IO_HUP) && |
||
934 | channel->ever_writable && |
||
935 | !channel->write_would_have_blocked && |
||
936 | (channel->event_mask & FD_WRITE)) |
||
937 | watch->pollfd.revents |= G_IO_OUT; |
||
938 | |||
939 | if (channel->debug) |
||
940 | g_print ("\n revents={%s} retval={%s}\n", |
||
941 | condition_to_string (watch->pollfd.revents), |
||
942 | condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition)); |
||
943 | |||
944 | return ((watch->pollfd.revents | buffer_condition) & watch->condition); |
||
945 | |||
946 | default: |
||
947 | g_assert_not_reached (); |
||
948 | abort (); |
||
949 | } |
||
950 | } |
||
951 | |||
952 | static gboolean |
||
953 | g_io_win32_dispatch (GSource *source, |
||
954 | GSourceFunc callback, |
||
955 | gpointer user_data) |
||
956 | { |
||
957 | GIOFunc func = (GIOFunc)callback; |
||
958 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
959 | GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; |
||
960 | GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); |
||
961 | |||
962 | if (!func) |
||
963 | { |
||
964 | g_warning ("IO Watch dispatched without callback\n" |
||
965 | "You must call g_source_connect()."); |
||
966 | return FALSE; |
||
967 | } |
||
968 | |||
969 | if (channel->debug) |
||
970 | g_print ("g_io_win32_dispatch: pollfd.revents=%s condition=%s result=%s\n", |
||
971 | condition_to_string (watch->pollfd.revents), |
||
972 | condition_to_string (watch->condition), |
||
973 | condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition)); |
||
974 | |||
975 | return (*func) (watch->channel, |
||
976 | (watch->pollfd.revents | buffer_condition) & watch->condition, |
||
977 | user_data); |
||
978 | } |
||
979 | |||
980 | static void |
||
981 | g_io_win32_finalize (GSource *source) |
||
982 | { |
||
983 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
984 | GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; |
||
985 | |||
986 | if (channel->debug) |
||
987 | g_print ("g_io_win32_finalize: source=%p channel=%p", source, channel); |
||
988 | |||
989 | switch (channel->type) |
||
990 | { |
||
991 | case G_IO_WIN32_WINDOWS_MESSAGES: |
||
992 | if (channel->debug) |
||
993 | g_print (" MSG"); |
||
994 | break; |
||
995 | |||
996 | case G_IO_WIN32_CONSOLE: |
||
997 | if (channel->debug) |
||
998 | g_print (" CON"); |
||
999 | break; |
||
1000 | |||
1001 | case G_IO_WIN32_FILE_DESC: |
||
1002 | if (channel->debug) |
||
1003 | g_print (" FD thread=%#x", channel->thread_id); |
||
1004 | break; |
||
1005 | |||
1006 | case G_IO_WIN32_SOCKET: |
||
1007 | if (channel->debug) |
||
1008 | g_print (" SOCK sock=%d", channel->fd); |
||
1009 | break; |
||
1010 | |||
1011 | default: |
||
1012 | g_assert_not_reached (); |
||
1013 | abort (); |
||
1014 | } |
||
1015 | if (channel->debug) |
||
1016 | g_print ("\n"); |
||
1017 | g_io_channel_unref (watch->channel); |
||
1018 | } |
||
1019 | |||
1020 | GSourceFuncs g_io_watch_funcs = { |
||
1021 | g_io_win32_prepare, |
||
1022 | g_io_win32_check, |
||
1023 | g_io_win32_dispatch, |
||
1024 | g_io_win32_finalize |
||
1025 | }; |
||
1026 | |||
1027 | static GIOStatus |
||
1028 | g_io_win32_msg_read (GIOChannel *channel, |
||
1029 | gchar *buf, |
||
1030 | gsize count, |
||
1031 | gsize *bytes_read, |
||
1032 | GError **err) |
||
1033 | { |
||
1034 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1035 | MSG msg; /* In case of alignment problems */ |
||
1036 | |||
1037 | *bytes_read = 0; |
||
1038 | |||
1039 | if (count < sizeof (MSG)) |
||
1040 | { |
||
1041 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, |
||
1042 | "Incorrect message size"); /* Informative enough error message? */ |
||
1043 | return G_IO_STATUS_ERROR; |
||
1044 | } |
||
1045 | |||
1046 | if (win32_channel->debug) |
||
1047 | g_print ("g_io_win32_msg_read: channel=%p hwnd=%p\n", |
||
1048 | channel, win32_channel->hwnd); |
||
1049 | if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE)) |
||
1050 | return G_IO_STATUS_AGAIN; |
||
1051 | |||
1052 | memmove (buf, &msg, sizeof (MSG)); |
||
1053 | *bytes_read = sizeof (MSG); |
||
1054 | |||
1055 | return G_IO_STATUS_NORMAL; |
||
1056 | } |
||
1057 | |||
1058 | static GIOStatus |
||
1059 | g_io_win32_msg_write (GIOChannel *channel, |
||
1060 | const gchar *buf, |
||
1061 | gsize count, |
||
1062 | gsize *bytes_written, |
||
1063 | GError **err) |
||
1064 | { |
||
1065 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1066 | MSG msg; |
||
1067 | |||
1068 | *bytes_written = 0; |
||
1069 | |||
1070 | if (count != sizeof (MSG)) |
||
1071 | { |
||
1072 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL, |
||
1073 | "Incorrect message size"); /* Informative enough error message? */ |
||
1074 | return G_IO_STATUS_ERROR; |
||
1075 | } |
||
1076 | |||
1077 | /* In case of alignment problems */ |
||
1078 | memmove (&msg, buf, sizeof (MSG)); |
||
1079 | if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam)) |
||
1080 | { |
||
1081 | gchar *emsg = g_win32_error_message (GetLastError ()); |
||
1082 | |||
1083 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg); |
||
1084 | g_free (emsg); |
||
1085 | |||
1086 | return G_IO_STATUS_ERROR; |
||
1087 | } |
||
1088 | |||
1089 | *bytes_written = sizeof (MSG); |
||
1090 | |||
1091 | return G_IO_STATUS_NORMAL; |
||
1092 | } |
||
1093 | |||
1094 | static GIOStatus |
||
1095 | g_io_win32_msg_close (GIOChannel *channel, |
||
1096 | GError **err) |
||
1097 | { |
||
1098 | /* Nothing to be done. Or should we set hwnd to some invalid value? */ |
||
1099 | |||
1100 | return G_IO_STATUS_NORMAL; |
||
1101 | } |
||
1102 | |||
1103 | static void |
||
1104 | g_io_win32_free (GIOChannel *channel) |
||
1105 | { |
||
1106 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1107 | |||
1108 | if (win32_channel->debug) |
||
1109 | g_print ("g_io_win32_free channel=%p fd=%d\n", channel, win32_channel->fd); |
||
1110 | |||
1111 | DeleteCriticalSection (&win32_channel->mutex); |
||
1112 | |||
1113 | if (win32_channel->data_avail_event) |
||
1114 | if (!CloseHandle (win32_channel->data_avail_event)) |
||
1115 | if (win32_channel->debug) |
||
1116 | { |
||
1117 | gchar *emsg = g_win32_error_message (GetLastError ()); |
||
1118 | |||
1119 | g_print (" CloseHandle(%p) failed: %s\n", |
||
1120 | win32_channel->data_avail_event, emsg); |
||
1121 | g_free (emsg); |
||
1122 | } |
||
1123 | |||
1124 | g_free (win32_channel->buffer); |
||
1125 | |||
1126 | if (win32_channel->space_avail_event) |
||
1127 | if (!CloseHandle (win32_channel->space_avail_event)) |
||
1128 | if (win32_channel->debug) |
||
1129 | { |
||
1130 | gchar *emsg = g_win32_error_message (GetLastError ()); |
||
1131 | |||
1132 | g_print (" CloseHandle(%p) failed: %s\n", |
||
1133 | win32_channel->space_avail_event, emsg); |
||
1134 | g_free (emsg); |
||
1135 | } |
||
1136 | |||
1137 | if (win32_channel->type == G_IO_WIN32_SOCKET && |
||
1138 | win32_channel->fd != -1) |
||
1139 | if (WSAEventSelect (win32_channel->fd, NULL, 0) == SOCKET_ERROR) |
||
1140 | if (win32_channel->debug) |
||
1141 | { |
||
1142 | gchar *emsg = g_win32_error_message (WSAGetLastError ()); |
||
1143 | |||
1144 | g_print (" WSAEventSelect(%d,NULL,{}) failed: %s\n", |
||
1145 | win32_channel->fd, emsg); |
||
1146 | g_free (emsg); |
||
1147 | } |
||
1148 | |||
1149 | if (win32_channel->event) |
||
1150 | if (!WSACloseEvent (win32_channel->event)) |
||
1151 | if (win32_channel->debug) |
||
1152 | { |
||
1153 | gchar *emsg = g_win32_error_message (WSAGetLastError ()); |
||
1154 | |||
1155 | g_print (" WSACloseEvent(%p) failed: %s\n", |
||
1156 | win32_channel->event, emsg); |
||
1157 | g_free (emsg); |
||
1158 | } |
||
1159 | |||
1160 | g_free (win32_channel); |
||
1161 | } |
||
1162 | |||
1163 | static GSource * |
||
1164 | g_io_win32_msg_create_watch (GIOChannel *channel, |
||
1165 | GIOCondition condition) |
||
1166 | { |
||
1167 | GIOWin32Watch *watch; |
||
1168 | GSource *source; |
||
1169 | |||
1170 | source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); |
||
1171 | g_source_set_name (source, "GIOChannel (Win32)"); |
||
1172 | watch = (GIOWin32Watch *)source; |
||
1173 | |||
1174 | watch->channel = channel; |
||
1175 | g_io_channel_ref (channel); |
||
1176 | |||
1177 | watch->condition = condition; |
||
1178 | |||
1179 | watch->pollfd.fd = (gintptr) G_WIN32_MSG_HANDLE; |
||
1180 | watch->pollfd.events = condition; |
||
1181 | |||
1182 | g_source_add_poll (source, &watch->pollfd); |
||
1183 | |||
1184 | return source; |
||
1185 | } |
||
1186 | |||
1187 | static GIOStatus |
||
1188 | g_io_win32_fd_and_console_read (GIOChannel *channel, |
||
1189 | gchar *buf, |
||
1190 | gsize count, |
||
1191 | gsize *bytes_read, |
||
1192 | GError **err) |
||
1193 | { |
||
1194 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1195 | gint result; |
||
1196 | |||
1197 | if (win32_channel->debug) |
||
1198 | g_print ("g_io_win32_fd_read: fd=%d count=%" G_GSIZE_FORMAT "\n", |
||
1199 | win32_channel->fd, count); |
||
1200 | |||
1201 | if (win32_channel->thread_id) |
||
1202 | { |
||
1203 | return buffer_read (win32_channel, buf, count, bytes_read, err); |
||
1204 | } |
||
1205 | |||
1206 | result = read (win32_channel->fd, buf, count); |
||
1207 | |||
1208 | if (win32_channel->debug) |
||
1209 | g_print ("g_io_win32_fd_read: read() => %d\n", result); |
||
1210 | |||
1211 | if (result < 0) |
||
1212 | { |
||
1213 | *bytes_read = 0; |
||
1214 | |||
1215 | switch (errno) |
||
1216 | { |
||
1217 | #ifdef EAGAIN |
||
1218 | case EAGAIN: |
||
1219 | return G_IO_STATUS_AGAIN; |
||
1220 | #endif |
||
1221 | default: |
||
1222 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1223 | g_io_channel_error_from_errno (errno), |
||
1224 | g_strerror (errno)); |
||
1225 | return G_IO_STATUS_ERROR; |
||
1226 | } |
||
1227 | } |
||
1228 | |||
1229 | *bytes_read = result; |
||
1230 | |||
1231 | return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; |
||
1232 | } |
||
1233 | |||
1234 | static GIOStatus |
||
1235 | g_io_win32_fd_and_console_write (GIOChannel *channel, |
||
1236 | const gchar *buf, |
||
1237 | gsize count, |
||
1238 | gsize *bytes_written, |
||
1239 | GError **err) |
||
1240 | { |
||
1241 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1242 | gint result; |
||
1243 | |||
1244 | if (win32_channel->thread_id) |
||
1245 | { |
||
1246 | return buffer_write (win32_channel, buf, count, bytes_written, err); |
||
1247 | } |
||
1248 | |||
1249 | result = write (win32_channel->fd, buf, count); |
||
1250 | if (win32_channel->debug) |
||
1251 | g_print ("g_io_win32_fd_write: fd=%d count=%" G_GSIZE_FORMAT " => %d\n", |
||
1252 | win32_channel->fd, count, result); |
||
1253 | |||
1254 | if (result < 0) |
||
1255 | { |
||
1256 | *bytes_written = 0; |
||
1257 | |||
1258 | switch (errno) |
||
1259 | { |
||
1260 | #ifdef EAGAIN |
||
1261 | case EAGAIN: |
||
1262 | return G_IO_STATUS_AGAIN; |
||
1263 | #endif |
||
1264 | default: |
||
1265 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1266 | g_io_channel_error_from_errno (errno), |
||
1267 | g_strerror (errno)); |
||
1268 | return G_IO_STATUS_ERROR; |
||
1269 | } |
||
1270 | } |
||
1271 | |||
1272 | *bytes_written = result; |
||
1273 | |||
1274 | return G_IO_STATUS_NORMAL; |
||
1275 | } |
||
1276 | |||
1277 | static GIOStatus |
||
1278 | g_io_win32_fd_seek (GIOChannel *channel, |
||
1279 | gint64 offset, |
||
1280 | GSeekType type, |
||
1281 | GError **err) |
||
1282 | { |
||
1283 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1284 | int whence; |
||
1285 | off_t tmp_offset; |
||
1286 | off_t result; |
||
1287 | |||
1288 | switch (type) |
||
1289 | { |
||
1290 | case G_SEEK_SET: |
||
1291 | whence = SEEK_SET; |
||
1292 | break; |
||
1293 | case G_SEEK_CUR: |
||
1294 | whence = SEEK_CUR; |
||
1295 | break; |
||
1296 | case G_SEEK_END: |
||
1297 | whence = SEEK_END; |
||
1298 | break; |
||
1299 | default: |
||
1300 | whence = -1; /* Keep the compiler quiet */ |
||
1301 | g_assert_not_reached (); |
||
1302 | abort (); |
||
1303 | } |
||
1304 | |||
1305 | tmp_offset = offset; |
||
1306 | if (tmp_offset != offset) |
||
1307 | { |
||
1308 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1309 | g_io_channel_error_from_errno (EINVAL), |
||
1310 | g_strerror (EINVAL)); |
||
1311 | return G_IO_STATUS_ERROR; |
||
1312 | } |
||
1313 | |||
1314 | result = lseek (win32_channel->fd, tmp_offset, whence); |
||
1315 | |||
1316 | if (result < 0) |
||
1317 | { |
||
1318 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1319 | g_io_channel_error_from_errno (errno), |
||
1320 | g_strerror (errno)); |
||
1321 | return G_IO_STATUS_ERROR; |
||
1322 | } |
||
1323 | |||
1324 | return G_IO_STATUS_NORMAL; |
||
1325 | } |
||
1326 | |||
1327 | static GIOStatus |
||
1328 | g_io_win32_fd_close (GIOChannel *channel, |
||
1329 | GError **err) |
||
1330 | { |
||
1331 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1332 | |||
1333 | if (win32_channel->debug) |
||
1334 | g_print ("g_io_win32_fd_close: thread=%#x: fd=%d\n", |
||
1335 | win32_channel->thread_id, |
||
1336 | win32_channel->fd); |
||
1337 | EnterCriticalSection (&win32_channel->mutex); |
||
1338 | if (win32_channel->running) |
||
1339 | { |
||
1340 | if (win32_channel->debug) |
||
1341 | g_print ("thread %#x: running, marking fd %d for later close\n", |
||
1342 | win32_channel->thread_id, win32_channel->fd); |
||
1343 | win32_channel->running = FALSE; |
||
1344 | win32_channel->needs_close = TRUE; |
||
1345 | if (win32_channel->direction == 0) |
||
1346 | SetEvent (win32_channel->data_avail_event); |
||
1347 | else |
||
1348 | SetEvent (win32_channel->space_avail_event); |
||
1349 | } |
||
1350 | else |
||
1351 | { |
||
1352 | if (win32_channel->debug) |
||
1353 | g_print ("closing fd %d\n", win32_channel->fd); |
||
1354 | close (win32_channel->fd); |
||
1355 | if (win32_channel->debug) |
||
1356 | g_print ("closed fd %d, setting to -1\n", |
||
1357 | win32_channel->fd); |
||
1358 | win32_channel->fd = -1; |
||
1359 | } |
||
1360 | LeaveCriticalSection (&win32_channel->mutex); |
||
1361 | |||
1362 | /* FIXME error detection? */ |
||
1363 | |||
1364 | return G_IO_STATUS_NORMAL; |
||
1365 | } |
||
1366 | |||
1367 | static GSource * |
||
1368 | g_io_win32_fd_create_watch (GIOChannel *channel, |
||
1369 | GIOCondition condition) |
||
1370 | { |
||
1371 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1372 | GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); |
||
1373 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
1374 | |||
1375 | watch->channel = channel; |
||
1376 | g_io_channel_ref (channel); |
||
1377 | |||
1378 | watch->condition = condition; |
||
1379 | |||
1380 | if (win32_channel->data_avail_event == NULL) |
||
1381 | create_events (win32_channel); |
||
1382 | |||
1383 | watch->pollfd.fd = (gintptr) win32_channel->data_avail_event; |
||
1384 | watch->pollfd.events = condition; |
||
1385 | |||
1386 | if (win32_channel->debug) |
||
1387 | g_print ("g_io_win32_fd_create_watch: channel=%p fd=%d condition={%s} event=%p\n", |
||
1388 | channel, win32_channel->fd, |
||
1389 | condition_to_string (condition), (HANDLE) watch->pollfd.fd); |
||
1390 | |||
1391 | EnterCriticalSection (&win32_channel->mutex); |
||
1392 | if (win32_channel->thread_id == 0) |
||
1393 | { |
||
1394 | if (condition & G_IO_IN) |
||
1395 | create_thread (win32_channel, condition, read_thread); |
||
1396 | else if (condition & G_IO_OUT) |
||
1397 | create_thread (win32_channel, condition, write_thread); |
||
1398 | } |
||
1399 | |||
1400 | g_source_add_poll (source, &watch->pollfd); |
||
1401 | LeaveCriticalSection (&win32_channel->mutex); |
||
1402 | |||
1403 | return source; |
||
1404 | } |
||
1405 | |||
1406 | static GIOStatus |
||
1407 | g_io_win32_console_close (GIOChannel *channel, |
||
1408 | GError **err) |
||
1409 | { |
||
1410 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1411 | |||
1412 | if (close (win32_channel->fd) < 0) |
||
1413 | { |
||
1414 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1415 | g_io_channel_error_from_errno (errno), |
||
1416 | g_strerror (errno)); |
||
1417 | return G_IO_STATUS_ERROR; |
||
1418 | } |
||
1419 | |||
1420 | return G_IO_STATUS_NORMAL; |
||
1421 | } |
||
1422 | |||
1423 | static GSource * |
||
1424 | g_io_win32_console_create_watch (GIOChannel *channel, |
||
1425 | GIOCondition condition) |
||
1426 | { |
||
1427 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1428 | GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); |
||
1429 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
1430 | |||
1431 | watch->channel = channel; |
||
1432 | g_io_channel_ref (channel); |
||
1433 | |||
1434 | watch->condition = condition; |
||
1435 | |||
1436 | watch->pollfd.fd = _get_osfhandle (win32_channel->fd); |
||
1437 | watch->pollfd.events = condition; |
||
1438 | |||
1439 | g_source_add_poll (source, &watch->pollfd); |
||
1440 | |||
1441 | return source; |
||
1442 | } |
||
1443 | |||
1444 | static GIOStatus |
||
1445 | g_io_win32_sock_read (GIOChannel *channel, |
||
1446 | gchar *buf, |
||
1447 | gsize count, |
||
1448 | gsize *bytes_read, |
||
1449 | GError **err) |
||
1450 | { |
||
1451 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1452 | gint result; |
||
1453 | GIOChannelError error; |
||
1454 | int winsock_error; |
||
1455 | |||
1456 | if (win32_channel->debug) |
||
1457 | g_print ("g_io_win32_sock_read: channel=%p sock=%d count=%" G_GSIZE_FORMAT, |
||
1458 | channel, win32_channel->fd, count); |
||
1459 | |||
1460 | result = recv (win32_channel->fd, buf, count, 0); |
||
1461 | if (result == SOCKET_ERROR) |
||
1462 | winsock_error = WSAGetLastError (); |
||
1463 | |||
1464 | if (win32_channel->debug) |
||
1465 | g_print (" recv=%d", result); |
||
1466 | |||
1467 | if (result == SOCKET_ERROR) |
||
1468 | { |
||
1469 | gchar *emsg = g_win32_error_message (winsock_error); |
||
1470 | |||
1471 | if (win32_channel->debug) |
||
1472 | g_print (" %s\n", emsg); |
||
1473 | |||
1474 | *bytes_read = 0; |
||
1475 | |||
1476 | switch (winsock_error) |
||
1477 | { |
||
1478 | case WSAEINVAL: |
||
1479 | error = G_IO_CHANNEL_ERROR_INVAL; |
||
1480 | break; |
||
1481 | case WSAEWOULDBLOCK: |
||
1482 | g_free (emsg); |
||
1483 | return G_IO_STATUS_AGAIN; |
||
1484 | default: |
||
1485 | error = G_IO_CHANNEL_ERROR_FAILED; |
||
1486 | break; |
||
1487 | } |
||
1488 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg); |
||
1489 | g_free (emsg); |
||
1490 | |||
1491 | return G_IO_STATUS_ERROR; |
||
1492 | } |
||
1493 | else |
||
1494 | { |
||
1495 | if (win32_channel->debug) |
||
1496 | g_print ("\n"); |
||
1497 | *bytes_read = result; |
||
1498 | if (result == 0) |
||
1499 | return G_IO_STATUS_EOF; |
||
1500 | else |
||
1501 | return G_IO_STATUS_NORMAL; |
||
1502 | } |
||
1503 | } |
||
1504 | |||
1505 | static GIOStatus |
||
1506 | g_io_win32_sock_write (GIOChannel *channel, |
||
1507 | const gchar *buf, |
||
1508 | gsize count, |
||
1509 | gsize *bytes_written, |
||
1510 | GError **err) |
||
1511 | { |
||
1512 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1513 | gint result; |
||
1514 | GIOChannelError error; |
||
1515 | int winsock_error; |
||
1516 | |||
1517 | if (win32_channel->debug) |
||
1518 | g_print ("g_io_win32_sock_write: channel=%p sock=%d count=%" G_GSIZE_FORMAT, |
||
1519 | channel, win32_channel->fd, count); |
||
1520 | |||
1521 | result = send (win32_channel->fd, buf, count, 0); |
||
1522 | if (result == SOCKET_ERROR) |
||
1523 | winsock_error = WSAGetLastError (); |
||
1524 | |||
1525 | if (win32_channel->debug) |
||
1526 | g_print (" send=%d", result); |
||
1527 | |||
1528 | if (result == SOCKET_ERROR) |
||
1529 | { |
||
1530 | gchar *emsg = g_win32_error_message (winsock_error); |
||
1531 | |||
1532 | if (win32_channel->debug) |
||
1533 | g_print (" %s\n", emsg); |
||
1534 | |||
1535 | *bytes_written = 0; |
||
1536 | |||
1537 | switch (winsock_error) |
||
1538 | { |
||
1539 | case WSAEINVAL: |
||
1540 | error = G_IO_CHANNEL_ERROR_INVAL; |
||
1541 | break; |
||
1542 | case WSAEWOULDBLOCK: |
||
1543 | win32_channel->write_would_have_blocked = TRUE; |
||
1544 | win32_channel->last_events = 0; |
||
1545 | g_free (emsg); |
||
1546 | return G_IO_STATUS_AGAIN; |
||
1547 | default: |
||
1548 | error = G_IO_CHANNEL_ERROR_FAILED; |
||
1549 | break; |
||
1550 | } |
||
1551 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, error, emsg); |
||
1552 | g_free (emsg); |
||
1553 | |||
1554 | return G_IO_STATUS_ERROR; |
||
1555 | } |
||
1556 | else |
||
1557 | { |
||
1558 | if (win32_channel->debug) |
||
1559 | g_print ("\n"); |
||
1560 | *bytes_written = result; |
||
1561 | win32_channel->write_would_have_blocked = FALSE; |
||
1562 | |||
1563 | return G_IO_STATUS_NORMAL; |
||
1564 | } |
||
1565 | } |
||
1566 | |||
1567 | static GIOStatus |
||
1568 | g_io_win32_sock_close (GIOChannel *channel, |
||
1569 | GError **err) |
||
1570 | { |
||
1571 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1572 | |||
1573 | if (win32_channel->fd != -1) |
||
1574 | { |
||
1575 | if (win32_channel->debug) |
||
1576 | g_print ("g_io_win32_sock_close: channel=%p sock=%d\n", |
||
1577 | channel, win32_channel->fd); |
||
1578 | |||
1579 | closesocket (win32_channel->fd); |
||
1580 | win32_channel->fd = -1; |
||
1581 | } |
||
1582 | |||
1583 | /* FIXME error detection? */ |
||
1584 | |||
1585 | return G_IO_STATUS_NORMAL; |
||
1586 | } |
||
1587 | |||
1588 | static GSource * |
||
1589 | g_io_win32_sock_create_watch (GIOChannel *channel, |
||
1590 | GIOCondition condition) |
||
1591 | { |
||
1592 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1593 | GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); |
||
1594 | GIOWin32Watch *watch = (GIOWin32Watch *)source; |
||
1595 | |||
1596 | watch->channel = channel; |
||
1597 | g_io_channel_ref (channel); |
||
1598 | |||
1599 | watch->condition = condition; |
||
1600 | |||
1601 | if (win32_channel->event == 0) |
||
1602 | win32_channel->event = WSACreateEvent (); |
||
1603 | |||
1604 | watch->pollfd.fd = (gintptr) win32_channel->event; |
||
1605 | watch->pollfd.events = condition; |
||
1606 | |||
1607 | if (win32_channel->debug) |
||
1608 | g_print ("g_io_win32_sock_create_watch: channel=%p sock=%d event=%p condition={%s}\n", |
||
1609 | channel, win32_channel->fd, (HANDLE) watch->pollfd.fd, |
||
1610 | condition_to_string (watch->condition)); |
||
1611 | |||
1612 | g_source_add_poll (source, &watch->pollfd); |
||
1613 | |||
1614 | return source; |
||
1615 | } |
||
1616 | |||
1617 | GIOChannel * |
||
1618 | g_io_channel_new_file (const gchar *filename, |
||
1619 | const gchar *mode, |
||
1620 | GError **error) |
||
1621 | { |
||
1622 | int fid, flags, pmode; |
||
1623 | GIOChannel *channel; |
||
1624 | |||
1625 | enum { /* Cheesy hack */ |
||
1626 | MODE_R = 1 << 0, |
||
1627 | MODE_W = 1 << 1, |
||
1628 | MODE_A = 1 << 2, |
||
1629 | MODE_PLUS = 1 << 3, |
||
1630 | }; |
||
1631 | int mode_num; |
||
1632 | |||
1633 | g_return_val_if_fail (filename != NULL, NULL); |
||
1634 | g_return_val_if_fail (mode != NULL, NULL); |
||
1635 | g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL); |
||
1636 | |||
1637 | switch (mode[0]) |
||
1638 | { |
||
1639 | case 'r': |
||
1640 | mode_num = MODE_R; |
||
1641 | break; |
||
1642 | case 'w': |
||
1643 | mode_num = MODE_W; |
||
1644 | break; |
||
1645 | case 'a': |
||
1646 | mode_num = MODE_A; |
||
1647 | break; |
||
1648 | default: |
||
1649 | g_warning ("Invalid GIOFileMode %s.", mode); |
||
1650 | return NULL; |
||
1651 | } |
||
1652 | |||
1653 | switch (mode[1]) |
||
1654 | { |
||
1655 | case '\0': |
||
1656 | break; |
||
1657 | case '+': |
||
1658 | if (mode[2] == '\0') |
||
1659 | { |
||
1660 | mode_num |= MODE_PLUS; |
||
1661 | break; |
||
1662 | } |
||
1663 | /* Fall through */ |
||
1664 | default: |
||
1665 | g_warning ("Invalid GIOFileMode %s.", mode); |
||
1666 | return NULL; |
||
1667 | } |
||
1668 | |||
1669 | switch (mode_num) |
||
1670 | { |
||
1671 | case MODE_R: |
||
1672 | flags = O_RDONLY; |
||
1673 | pmode = _S_IREAD; |
||
1674 | break; |
||
1675 | case MODE_W: |
||
1676 | flags = O_WRONLY | O_TRUNC | O_CREAT; |
||
1677 | pmode = _S_IWRITE; |
||
1678 | break; |
||
1679 | case MODE_A: |
||
1680 | flags = O_WRONLY | O_APPEND | O_CREAT; |
||
1681 | pmode = _S_IWRITE; |
||
1682 | break; |
||
1683 | case MODE_R | MODE_PLUS: |
||
1684 | flags = O_RDWR; |
||
1685 | pmode = _S_IREAD | _S_IWRITE; |
||
1686 | break; |
||
1687 | case MODE_W | MODE_PLUS: |
||
1688 | flags = O_RDWR | O_TRUNC | O_CREAT; |
||
1689 | pmode = _S_IREAD | _S_IWRITE; |
||
1690 | break; |
||
1691 | case MODE_A | MODE_PLUS: |
||
1692 | flags = O_RDWR | O_APPEND | O_CREAT; |
||
1693 | pmode = _S_IREAD | _S_IWRITE; |
||
1694 | break; |
||
1695 | default: |
||
1696 | g_assert_not_reached (); |
||
1697 | abort (); |
||
1698 | } |
||
1699 | |||
1700 | /* always open 'untranslated' */ |
||
1701 | fid = g_open (filename, flags | _O_BINARY, pmode); |
||
1702 | |||
1703 | if (g_io_win32_get_debug_flag ()) |
||
1704 | { |
||
1705 | g_print ("g_io_channel_win32_new_file: open(\"%s\",", filename); |
||
1706 | g_win32_print_access_mode (flags|_O_BINARY); |
||
1707 | g_print (",%#o)=%d\n", pmode, fid); |
||
1708 | } |
||
1709 | |||
1710 | if (fid < 0) |
||
1711 | { |
||
1712 | g_set_error_literal (error, G_FILE_ERROR, |
||
1713 | g_file_error_from_errno (errno), |
||
1714 | g_strerror (errno)); |
||
1715 | return (GIOChannel *)NULL; |
||
1716 | } |
||
1717 | |||
1718 | channel = g_io_channel_win32_new_fd (fid); |
||
1719 | |||
1720 | /* XXX: move this to g_io_channel_win32_new_fd () */ |
||
1721 | channel->close_on_unref = TRUE; |
||
1722 | channel->is_seekable = TRUE; |
||
1723 | |||
1724 | /* g_io_channel_win32_new_fd sets is_readable and is_writeable to |
||
1725 | * correspond to actual readability/writeability. Set to FALSE those |
||
1726 | * that mode doesn't allow |
||
1727 | */ |
||
1728 | switch (mode_num) |
||
1729 | { |
||
1730 | case MODE_R: |
||
1731 | channel->is_writeable = FALSE; |
||
1732 | break; |
||
1733 | case MODE_W: |
||
1734 | case MODE_A: |
||
1735 | channel->is_readable = FALSE; |
||
1736 | break; |
||
1737 | case MODE_R | MODE_PLUS: |
||
1738 | case MODE_W | MODE_PLUS: |
||
1739 | case MODE_A | MODE_PLUS: |
||
1740 | break; |
||
1741 | default: |
||
1742 | g_assert_not_reached (); |
||
1743 | abort (); |
||
1744 | } |
||
1745 | |||
1746 | return channel; |
||
1747 | } |
||
1748 | |||
1749 | #if !defined (_WIN64) |
||
1750 | |||
1751 | #undef g_io_channel_new_file |
||
1752 | |||
1753 | /* Binary compatibility version. Not for newly compiled code. */ |
||
1754 | |||
1755 | GIOChannel * |
||
1756 | g_io_channel_new_file (const gchar *filename, |
||
1757 | const gchar *mode, |
||
1758 | GError **error) |
||
1759 | { |
||
1760 | gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error); |
||
1761 | GIOChannel *retval; |
||
1762 | |||
1763 | if (utf8_filename == NULL) |
||
1764 | return NULL; |
||
1765 | |||
1766 | retval = g_io_channel_new_file_utf8 (utf8_filename, mode, error); |
||
1767 | |||
1768 | g_free (utf8_filename); |
||
1769 | |||
1770 | return retval; |
||
1771 | } |
||
1772 | |||
1773 | #endif |
||
1774 | |||
1775 | static GIOStatus |
||
1776 | g_io_win32_unimpl_set_flags (GIOChannel *channel, |
||
1777 | GIOFlags flags, |
||
1778 | GError **err) |
||
1779 | { |
||
1780 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1781 | |||
1782 | if (win32_channel->debug) |
||
1783 | { |
||
1784 | g_print ("g_io_win32_unimpl_set_flags: "); |
||
1785 | g_win32_print_gioflags (flags); |
||
1786 | g_print ("\n"); |
||
1787 | } |
||
1788 | |||
1789 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1790 | G_IO_CHANNEL_ERROR_FAILED, |
||
1791 | "Not implemented on Win32"); |
||
1792 | |||
1793 | return G_IO_STATUS_ERROR; |
||
1794 | } |
||
1795 | |||
1796 | static GIOFlags |
||
1797 | g_io_win32_fd_get_flags_internal (GIOChannel *channel, |
||
1798 | struct _stati64 *st) |
||
1799 | { |
||
1800 | GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; |
||
1801 | gchar c; |
||
1802 | DWORD count; |
||
1803 | |||
1804 | if (st->st_mode & _S_IFIFO) |
||
1805 | { |
||
1806 | channel->is_readable = |
||
1807 | (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE; |
||
1808 | channel->is_writeable = |
||
1809 | (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); |
||
1810 | channel->is_seekable = FALSE; |
||
1811 | } |
||
1812 | else |
||
1813 | { |
||
1814 | channel->is_readable = |
||
1815 | (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); |
||
1816 | channel->is_writeable = |
||
1817 | (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0); |
||
1818 | channel->is_seekable = TRUE; |
||
1819 | } |
||
1820 | |||
1821 | /* XXX: G_IO_FLAG_APPEND */ |
||
1822 | /* XXX: G_IO_FLAG_NONBLOCK */ |
||
1823 | |||
1824 | return 0; |
||
1825 | } |
||
1826 | |||
1827 | static GIOFlags |
||
1828 | g_io_win32_fd_get_flags (GIOChannel *channel) |
||
1829 | { |
||
1830 | struct _stati64 st; |
||
1831 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1832 | |||
1833 | g_return_val_if_fail (win32_channel != NULL, 0); |
||
1834 | g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0); |
||
1835 | |||
1836 | if (0 == _fstati64 (win32_channel->fd, &st)) |
||
1837 | return g_io_win32_fd_get_flags_internal (channel, &st); |
||
1838 | else |
||
1839 | return 0; |
||
1840 | } |
||
1841 | |||
1842 | static GIOFlags |
||
1843 | g_io_win32_console_get_flags_internal (GIOChannel *channel) |
||
1844 | { |
||
1845 | GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; |
||
1846 | HANDLE handle = (HANDLE) _get_osfhandle (win32_channel->fd); |
||
1847 | gchar c; |
||
1848 | DWORD count; |
||
1849 | INPUT_RECORD record; |
||
1850 | |||
1851 | channel->is_readable = PeekConsoleInput (handle, &record, 1, &count); |
||
1852 | channel->is_writeable = WriteFile (handle, &c, 0, &count, NULL); |
||
1853 | channel->is_seekable = FALSE; |
||
1854 | |||
1855 | return 0; |
||
1856 | } |
||
1857 | |||
1858 | static GIOFlags |
||
1859 | g_io_win32_console_get_flags (GIOChannel *channel) |
||
1860 | { |
||
1861 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1862 | |||
1863 | g_return_val_if_fail (win32_channel != NULL, 0); |
||
1864 | g_return_val_if_fail (win32_channel->type == G_IO_WIN32_CONSOLE, 0); |
||
1865 | |||
1866 | return g_io_win32_console_get_flags_internal (channel); |
||
1867 | } |
||
1868 | |||
1869 | static GIOFlags |
||
1870 | g_io_win32_msg_get_flags (GIOChannel *channel) |
||
1871 | { |
||
1872 | return 0; |
||
1873 | } |
||
1874 | |||
1875 | static GIOStatus |
||
1876 | g_io_win32_sock_set_flags (GIOChannel *channel, |
||
1877 | GIOFlags flags, |
||
1878 | GError **err) |
||
1879 | { |
||
1880 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
1881 | u_long arg; |
||
1882 | |||
1883 | if (win32_channel->debug) |
||
1884 | { |
||
1885 | g_print ("g_io_win32_sock_set_flags: "); |
||
1886 | g_win32_print_gioflags (flags); |
||
1887 | g_print ("\n"); |
||
1888 | } |
||
1889 | |||
1890 | if (flags & G_IO_FLAG_NONBLOCK) |
||
1891 | { |
||
1892 | arg = 1; |
||
1893 | if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR) |
||
1894 | { |
||
1895 | gchar *emsg = g_win32_error_message (WSAGetLastError ()); |
||
1896 | |||
1897 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1898 | G_IO_CHANNEL_ERROR_FAILED, |
||
1899 | emsg); |
||
1900 | g_free (emsg); |
||
1901 | |||
1902 | return G_IO_STATUS_ERROR; |
||
1903 | } |
||
1904 | } |
||
1905 | else |
||
1906 | { |
||
1907 | arg = 0; |
||
1908 | if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR) |
||
1909 | { |
||
1910 | gchar *emsg = g_win32_error_message (WSAGetLastError ()); |
||
1911 | |||
1912 | g_set_error_literal (err, G_IO_CHANNEL_ERROR, |
||
1913 | G_IO_CHANNEL_ERROR_FAILED, |
||
1914 | emsg); |
||
1915 | g_free (emsg); |
||
1916 | |||
1917 | return G_IO_STATUS_ERROR; |
||
1918 | } |
||
1919 | } |
||
1920 | |||
1921 | return G_IO_STATUS_NORMAL; |
||
1922 | } |
||
1923 | |||
1924 | static GIOFlags |
||
1925 | g_io_win32_sock_get_flags (GIOChannel *channel) |
||
1926 | { |
||
1927 | /* Could we do something here? */ |
||
1928 | return 0; |
||
1929 | } |
||
1930 | |||
1931 | static GIOFuncs win32_channel_msg_funcs = { |
||
1932 | g_io_win32_msg_read, |
||
1933 | g_io_win32_msg_write, |
||
1934 | NULL, |
||
1935 | g_io_win32_msg_close, |
||
1936 | g_io_win32_msg_create_watch, |
||
1937 | g_io_win32_free, |
||
1938 | g_io_win32_unimpl_set_flags, |
||
1939 | g_io_win32_msg_get_flags, |
||
1940 | }; |
||
1941 | |||
1942 | static GIOFuncs win32_channel_fd_funcs = { |
||
1943 | g_io_win32_fd_and_console_read, |
||
1944 | g_io_win32_fd_and_console_write, |
||
1945 | g_io_win32_fd_seek, |
||
1946 | g_io_win32_fd_close, |
||
1947 | g_io_win32_fd_create_watch, |
||
1948 | g_io_win32_free, |
||
1949 | g_io_win32_unimpl_set_flags, |
||
1950 | g_io_win32_fd_get_flags, |
||
1951 | }; |
||
1952 | |||
1953 | static GIOFuncs win32_channel_console_funcs = { |
||
1954 | g_io_win32_fd_and_console_read, |
||
1955 | g_io_win32_fd_and_console_write, |
||
1956 | NULL, |
||
1957 | g_io_win32_console_close, |
||
1958 | g_io_win32_console_create_watch, |
||
1959 | g_io_win32_free, |
||
1960 | g_io_win32_unimpl_set_flags, |
||
1961 | g_io_win32_console_get_flags, |
||
1962 | }; |
||
1963 | |||
1964 | static GIOFuncs win32_channel_sock_funcs = { |
||
1965 | g_io_win32_sock_read, |
||
1966 | g_io_win32_sock_write, |
||
1967 | NULL, |
||
1968 | g_io_win32_sock_close, |
||
1969 | g_io_win32_sock_create_watch, |
||
1970 | g_io_win32_free, |
||
1971 | g_io_win32_sock_set_flags, |
||
1972 | g_io_win32_sock_get_flags, |
||
1973 | }; |
||
1974 | |||
1975 | /** |
||
1976 | * g_io_channel_win32_new_messages: |
||
1977 | * @hwnd: a window handle. |
||
1978 | * |
||
1979 | * Creates a new #GIOChannel given a window handle on Windows. |
||
1980 | * |
||
1981 | * This function creates a #GIOChannel that can be used to poll for |
||
1982 | * Windows messages for the window in question. |
||
1983 | * |
||
1984 | * Returns: a new #GIOChannel. |
||
1985 | **/ |
||
1986 | GIOChannel * |
||
1987 | #if GLIB_SIZEOF_VOID_P == 8 |
||
1988 | g_io_channel_win32_new_messages (gsize hwnd) |
||
1989 | #else |
||
1990 | g_io_channel_win32_new_messages (guint hwnd) |
||
1991 | #endif |
||
1992 | { |
||
1993 | GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1); |
||
1994 | GIOChannel *channel = (GIOChannel *)win32_channel; |
||
1995 | |||
1996 | g_io_channel_init (channel); |
||
1997 | g_io_channel_win32_init (win32_channel); |
||
1998 | if (win32_channel->debug) |
||
1999 | g_print ("g_io_channel_win32_new_messages: channel=%p hwnd=%p\n", |
||
2000 | channel, (HWND) hwnd); |
||
2001 | channel->funcs = &win32_channel_msg_funcs; |
||
2002 | win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES; |
||
2003 | win32_channel->hwnd = (HWND) hwnd; |
||
2004 | |||
2005 | /* XXX: check this. */ |
||
2006 | channel->is_readable = IsWindow (win32_channel->hwnd); |
||
2007 | channel->is_writeable = IsWindow (win32_channel->hwnd); |
||
2008 | |||
2009 | channel->is_seekable = FALSE; |
||
2010 | |||
2011 | return channel; |
||
2012 | } |
||
2013 | |||
2014 | static GIOChannel * |
||
2015 | g_io_channel_win32_new_fd_internal (gint fd, |
||
2016 | struct _stati64 *st) |
||
2017 | { |
||
2018 | GIOWin32Channel *win32_channel; |
||
2019 | GIOChannel *channel; |
||
2020 | |||
2021 | win32_channel = g_new (GIOWin32Channel, 1); |
||
2022 | channel = (GIOChannel *)win32_channel; |
||
2023 | |||
2024 | g_io_channel_init (channel); |
||
2025 | g_io_channel_win32_init (win32_channel); |
||
2026 | |||
2027 | win32_channel->fd = fd; |
||
2028 | |||
2029 | if (win32_channel->debug) |
||
2030 | g_print ("g_io_channel_win32_new_fd: channel=%p fd=%u\n", |
||
2031 | channel, fd); |
||
2032 | |||
2033 | if (st->st_mode & _S_IFCHR) /* console */ |
||
2034 | { |
||
2035 | channel->funcs = &win32_channel_console_funcs; |
||
2036 | win32_channel->type = G_IO_WIN32_CONSOLE; |
||
2037 | g_io_win32_console_get_flags_internal (channel); |
||
2038 | } |
||
2039 | else |
||
2040 | { |
||
2041 | channel->funcs = &win32_channel_fd_funcs; |
||
2042 | win32_channel->type = G_IO_WIN32_FILE_DESC; |
||
2043 | g_io_win32_fd_get_flags_internal (channel, st); |
||
2044 | } |
||
2045 | |||
2046 | return channel; |
||
2047 | } |
||
2048 | |||
2049 | /** |
||
2050 | * g_io_channel_win32_new_fd: |
||
2051 | * @fd: a C library file descriptor. |
||
2052 | * |
||
2053 | * Creates a new #GIOChannel given a file descriptor on Windows. This |
||
2054 | * works for file descriptors from the C runtime. |
||
2055 | * |
||
2056 | * This function works for file descriptors as returned by the open(), |
||
2057 | * creat(), pipe() and fileno() calls in the Microsoft C runtime. In |
||
2058 | * order to meaningfully use this function your code should use the |
||
2059 | * same C runtime as GLib uses, which is msvcrt.dll. Note that in |
||
2060 | * current Microsoft compilers it is near impossible to convince it to |
||
2061 | * build code that would use msvcrt.dll. The last Microsoft compiler |
||
2062 | * version that supported using msvcrt.dll as the C runtime was version |
||
2063 | * 6. The GNU compiler and toolchain for Windows, also known as Mingw, |
||
2064 | * fully supports msvcrt.dll. |
||
2065 | * |
||
2066 | * If you have created a #GIOChannel for a file descriptor and started |
||
2067 | * watching (polling) it, you shouldn't call read() on the file |
||
2068 | * descriptor. This is because adding polling for a file descriptor is |
||
2069 | * implemented in GLib on Windows by starting a thread that sits |
||
2070 | * blocked in a read() from the file descriptor most of the time. All |
||
2071 | * reads from the file descriptor should be done by this internal GLib |
||
2072 | * thread. Your code should call only g_io_channel_read(). |
||
2073 | * |
||
2074 | * This function is available only in GLib on Windows. |
||
2075 | * |
||
2076 | * Returns: a new #GIOChannel. |
||
2077 | **/ |
||
2078 | GIOChannel * |
||
2079 | g_io_channel_win32_new_fd (gint fd) |
||
2080 | { |
||
2081 | struct _stati64 st; |
||
2082 | |||
2083 | if (_fstati64 (fd, &st) == -1) |
||
2084 | { |
||
2085 | g_warning ("g_io_channel_win32_new_fd: %d isn't an open file descriptor in the C library GLib uses.", fd); |
||
2086 | return NULL; |
||
2087 | } |
||
2088 | |||
2089 | return g_io_channel_win32_new_fd_internal (fd, &st); |
||
2090 | } |
||
2091 | |||
2092 | gint |
||
2093 | g_io_channel_win32_get_fd (GIOChannel *channel) |
||
2094 | { |
||
2095 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
2096 | |||
2097 | return win32_channel->fd; |
||
2098 | } |
||
2099 | |||
2100 | /** |
||
2101 | * g_io_channel_win32_new_socket: |
||
2102 | * @socket: a Winsock socket |
||
2103 | * |
||
2104 | * Creates a new #GIOChannel given a socket on Windows. |
||
2105 | * |
||
2106 | * This function works for sockets created by Winsock. It's available |
||
2107 | * only in GLib on Windows. |
||
2108 | * |
||
2109 | * Polling a #GSource created to watch a channel for a socket puts the |
||
2110 | * socket in non-blocking mode. This is a side-effect of the |
||
2111 | * implementation and unavoidable. |
||
2112 | * |
||
2113 | * Returns: a new #GIOChannel |
||
2114 | **/ |
||
2115 | GIOChannel * |
||
2116 | g_io_channel_win32_new_socket (int socket) |
||
2117 | { |
||
2118 | GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1); |
||
2119 | GIOChannel *channel = (GIOChannel *)win32_channel; |
||
2120 | |||
2121 | g_io_channel_init (channel); |
||
2122 | g_io_channel_win32_init (win32_channel); |
||
2123 | if (win32_channel->debug) |
||
2124 | g_print ("g_io_channel_win32_new_socket: channel=%p sock=%d\n", |
||
2125 | channel, socket); |
||
2126 | channel->funcs = &win32_channel_sock_funcs; |
||
2127 | win32_channel->type = G_IO_WIN32_SOCKET; |
||
2128 | win32_channel->fd = socket; |
||
2129 | |||
2130 | channel->is_readable = TRUE; |
||
2131 | channel->is_writeable = TRUE; |
||
2132 | channel->is_seekable = FALSE; |
||
2133 | |||
2134 | return channel; |
||
2135 | } |
||
2136 | |||
2137 | GIOChannel * |
||
2138 | g_io_channel_unix_new (gint fd) |
||
2139 | { |
||
2140 | gboolean is_fd, is_socket; |
||
2141 | struct _stati64 st; |
||
2142 | int optval, optlen; |
||
2143 | |||
2144 | is_fd = (_fstati64 (fd, &st) == 0); |
||
2145 | |||
2146 | optlen = sizeof (optval); |
||
2147 | is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR); |
||
2148 | |||
2149 | if (is_fd && is_socket) |
||
2150 | g_warning ("g_io_channel_unix_new: %d is both a file descriptor and a socket. File descriptor interpretation assumed. To avoid ambiguity, call either g_io_channel_win32_new_fd() or g_io_channel_win32_new_socket() instead.", fd); |
||
2151 | |||
2152 | if (is_fd) |
||
2153 | return g_io_channel_win32_new_fd_internal (fd, &st); |
||
2154 | |||
2155 | if (is_socket) |
||
2156 | return g_io_channel_win32_new_socket(fd); |
||
2157 | |||
2158 | g_warning ("g_io_channel_unix_new: %d is neither a file descriptor or a socket.", fd); |
||
2159 | |||
2160 | return NULL; |
||
2161 | } |
||
2162 | |||
2163 | gint |
||
2164 | g_io_channel_unix_get_fd (GIOChannel *channel) |
||
2165 | { |
||
2166 | return g_io_channel_win32_get_fd (channel); |
||
2167 | } |
||
2168 | |||
2169 | void |
||
2170 | g_io_channel_win32_set_debug (GIOChannel *channel, |
||
2171 | gboolean flag) |
||
2172 | { |
||
2173 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
2174 | |||
2175 | win32_channel->debug = flag; |
||
2176 | } |
||
2177 | |||
2178 | gint |
||
2179 | g_io_channel_win32_poll (GPollFD *fds, |
||
2180 | gint n_fds, |
||
2181 | gint timeout) |
||
2182 | { |
||
2183 | g_return_val_if_fail (n_fds >= 0, 0); |
||
2184 | |||
2185 | return g_poll (fds, n_fds, timeout); |
||
2186 | } |
||
2187 | |||
2188 | void |
||
2189 | g_io_channel_win32_make_pollfd (GIOChannel *channel, |
||
2190 | GIOCondition condition, |
||
2191 | GPollFD *fd) |
||
2192 | { |
||
2193 | GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; |
||
2194 | |||
2195 | switch (win32_channel->type) |
||
2196 | { |
||
2197 | case G_IO_WIN32_FILE_DESC: |
||
2198 | if (win32_channel->data_avail_event == NULL) |
||
2199 | create_events (win32_channel); |
||
2200 | |||
2201 | fd->fd = (gintptr) win32_channel->data_avail_event; |
||
2202 | |||
2203 | if (win32_channel->thread_id == 0) |
||
2204 | { |
||
2205 | /* Is it meaningful for a file descriptor to be polled for |
||
2206 | * both IN and OUT? For what kind of file descriptor would |
||
2207 | * that be? Doesn't seem to make sense, in practise the file |
||
2208 | * descriptors handled here are always read or write ends of |
||
2209 | * pipes surely, and thus unidirectional. |
||
2210 | */ |
||
2211 | if (condition & G_IO_IN) |
||
2212 | create_thread (win32_channel, condition, read_thread); |
||
2213 | else if (condition & G_IO_OUT) |
||
2214 | create_thread (win32_channel, condition, write_thread); |
||
2215 | } |
||
2216 | break; |
||
2217 | |||
2218 | case G_IO_WIN32_CONSOLE: |
||
2219 | fd->fd = _get_osfhandle (win32_channel->fd); |
||
2220 | break; |
||
2221 | |||
2222 | case G_IO_WIN32_SOCKET: |
||
2223 | fd->fd = (gintptr) WSACreateEvent (); |
||
2224 | break; |
||
2225 | |||
2226 | case G_IO_WIN32_WINDOWS_MESSAGES: |
||
2227 | fd->fd = G_WIN32_MSG_HANDLE; |
||
2228 | break; |
||
2229 | |||
2230 | default: |
||
2231 | g_assert_not_reached (); |
||
2232 | abort (); |
||
2233 | } |
||
2234 | |||
2235 | fd->events = condition; |
||
2236 | } |
||
2237 | |||
2238 | #ifndef _WIN64 |
||
2239 | |||
2240 | /* Binary compatibility */ |
||
2241 | GIOChannel * |
||
2242 | g_io_channel_win32_new_stream_socket (int socket) |
||
2243 | { |
||
2244 | return g_io_channel_win32_new_socket (socket); |
||
2245 | } |
||
2246 | |||
2247 | #endif |