1 /* w32-io.c - W32 API I/O functions.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
5 This file is part of GPGME.
7 GPGME is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
12 GPGME is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
33 #include <sys/types.h>
42 /* We assume that a HANDLE can be represented by an int which should
43 be true for all i386 systems (HANDLE is defined as void *) and
44 these are the only systems for which Windows is available. Further
45 we assume that -1 denotes an invalid handle. */
47 #define fd_to_handle(a) ((HANDLE)(a))
48 #define handle_to_fd(a) ((int)(a))
49 #define pid_to_handle(a) ((HANDLE)(a))
50 #define handle_to_pid(a) ((int)(a))
52 #define READBUF_SIZE 4096
53 #define WRITEBUF_SIZE 4096
54 #define PIPEBUF_SIZE 4096
55 #define MAX_READERS 20
56 #define MAX_WRITERS 20
61 void (*handler)(int,void*);
64 DEFINE_STATIC_LOCK (notify_table_lock);
67 struct reader_context_s {
78 HANDLE have_data_ev; /* manually reset */
79 HANDLE have_space_ev; /* auto reset */
81 size_t readpos, writepos;
82 char buffer[READBUF_SIZE];
89 struct reader_context_s *context;
90 } reader_table[MAX_READERS];
91 static int reader_table_size= MAX_READERS;
92 DEFINE_STATIC_LOCK (reader_table_lock);
95 struct writer_context_s {
104 HANDLE have_data; /* manually reset */
108 char buffer[WRITEBUF_SIZE];
115 struct writer_context_s *context;
116 } writer_table[MAX_WRITERS];
117 static int writer_table_size= MAX_WRITERS;
118 DEFINE_STATIC_LOCK (writer_table_lock);
123 get_desired_thread_priority (void)
127 if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
129 value = THREAD_PRIORITY_HIGHEST;
130 DEBUG1 ("** Using standard IOThreadPriority of %d\n", value);
133 DEBUG1 ("** Configured IOThreadPriority is %d\n", value);
140 set_synchronize (HANDLE h)
144 /* For NT we have to set the sync flag. It seems that the only
145 * way to do it is by duplicating the handle. Tsss.. */
146 if (!DuplicateHandle( GetCurrentProcess(), h,
147 GetCurrentProcess(), &tmp,
148 EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, 0 ) ) {
149 DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError());
160 static DWORD CALLBACK
163 struct reader_context_s *c = arg;
167 DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd );
170 /* leave a 1 byte gap so that we can see whether it is empty or full*/
171 if ((c->writepos + 1) % READBUF_SIZE == c->readpos) {
173 if (!ResetEvent (c->have_space_ev) )
174 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
176 DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd );
177 WaitForSingleObject (c->have_space_ev, INFINITE);
178 DEBUG1 ("reader thread %p: got space", c->thread_hd );
185 nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE;
186 if ( nbytes > READBUF_SIZE - c->writepos )
187 nbytes = READBUF_SIZE - c->writepos;
190 DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes );
191 if ( !ReadFile ( c->file_hd,
192 c->buffer+c->writepos, nbytes, &nread, NULL) ) {
193 c->error_code = (int)GetLastError ();
194 if (c->error_code == ERROR_BROKEN_PIPE ) {
196 DEBUG1 ("reader thread %p: got eof (broken pipe)",
201 DEBUG2 ("reader thread %p: read error: ec=%d",
202 c->thread_hd, c->error_code );
208 DEBUG1 ("reader thread %p: got eof", c->thread_hd );
211 DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread );
218 c->writepos = (c->writepos + nread) % READBUF_SIZE;
219 if ( !SetEvent (c->have_data_ev) )
220 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
223 /* indicate that we have an error or eof */
224 if ( !SetEvent (c->have_data_ev) )
225 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
226 DEBUG1 ("reader thread %p ended", c->thread_hd );
227 SetEvent (c->stopped);
233 static struct reader_context_s *
234 create_reader (HANDLE fd)
236 struct reader_context_s *c;
237 SECURITY_ATTRIBUTES sec_attr;
240 DEBUG1 ("creating new read thread for file handle %p", fd );
241 memset (&sec_attr, 0, sizeof sec_attr );
242 sec_attr.nLength = sizeof sec_attr;
243 sec_attr.bInheritHandle = FALSE;
245 c = calloc (1, sizeof *c );
250 c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
251 c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
252 c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
253 if (!c->have_data_ev || !c->have_space_ev || !c->stopped ) {
254 DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
256 CloseHandle (c->have_data_ev);
257 if (c->have_space_ev)
258 CloseHandle (c->have_space_ev);
260 CloseHandle (c->stopped);
265 c->have_data_ev = set_synchronize (c->have_data_ev);
266 INIT_LOCK (c->mutex);
268 c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid );
270 DEBUG1 ("** failed to create reader thread: ec=%d\n",
271 (int)GetLastError ());
272 DESTROY_LOCK (c->mutex);
274 CloseHandle (c->have_data_ev);
275 if (c->have_space_ev)
276 CloseHandle (c->have_space_ev);
278 CloseHandle (c->stopped);
283 /* We set the priority of the thread higher because we know that
284 it only runs for a short time. This greatly helps to increase
285 the performance of the I/O. */
286 SetThreadPriority (c->thread_hd, get_desired_thread_priority ());
293 destroy_reader (struct reader_context_s *c)
297 if (c->have_space_ev)
298 SetEvent (c->have_space_ev);
301 DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
302 WaitForSingleObject (c->stopped, INFINITE);
303 DEBUG1 ("thread %p has terminated", c->thread_hd );
306 CloseHandle (c->stopped);
308 CloseHandle (c->have_data_ev);
309 if (c->have_space_ev)
310 CloseHandle (c->have_space_ev);
311 CloseHandle (c->thread_hd);
312 DESTROY_LOCK (c->mutex);
318 * Find a reader context or create a new one
319 * Note that the reader context will last until a io_close.
321 static struct reader_context_s *
322 find_reader (int fd, int start_it)
326 for (i=0; i < reader_table_size ; i++ ) {
327 if ( reader_table[i].used && reader_table[i].fd == fd )
328 return reader_table[i].context;
333 LOCK (reader_table_lock);
334 for (i=0; i < reader_table_size; i++ ) {
335 if (!reader_table[i].used) {
336 reader_table[i].fd = fd;
337 reader_table[i].context = create_reader (fd_to_handle (fd));
338 reader_table[i].used = 1;
339 UNLOCK (reader_table_lock);
340 return reader_table[i].context;
343 UNLOCK (reader_table_lock);
353 LOCK (reader_table_lock);
354 for (i=0; i < reader_table_size; i++ ) {
355 if (reader_table[i].used && reader_table[i].fd == fd ) {
356 destroy_reader (reader_table[i].context);
357 reader_table[i].context = NULL;
358 reader_table[i].used = 0;
362 UNLOCK (reader_table_lock);
368 _gpgme_io_read ( int fd, void *buffer, size_t count )
371 struct reader_context_s *c = find_reader (fd,1);
373 DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count );
375 DEBUG0 ( "no reader thread\n");
378 if (c->eof_shortcut) {
379 DEBUG1 ("fd %d: EOF (again)", fd );
384 if (c->readpos == c->writepos && !c->error) { /*no data avail*/
386 DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd);
387 WaitForSingleObject (c->have_data_ev, INFINITE);
388 DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd);
392 if (c->readpos == c->writepos || c->error) {
396 DEBUG1 ("fd %d: EOF", fd );
400 DEBUG1 ("fd %d: EOF but eof flag not set", fd );
403 DEBUG1 ("fd %d: read error", fd );
407 nread = c->readpos < c->writepos? c->writepos - c->readpos
408 : READBUF_SIZE - c->readpos;
411 memcpy (buffer, c->buffer+c->readpos, nread);
412 c->readpos = (c->readpos + nread) % READBUF_SIZE;
413 if (c->readpos == c->writepos && !c->eof) {
414 if ( !ResetEvent (c->have_data_ev) )
415 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
417 if (!SetEvent (c->have_space_ev))
418 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
421 DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
423 _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
428 * The writer does use a simple buffering strategy so that we are
429 * informed about write errors as soon as possible (i.e. with the the
430 * next call to the write function
432 static DWORD CALLBACK
435 struct writer_context_s *c = arg;
438 DEBUG2 ("writer thread %p for file %p started", c->thread_hd, c->file_hd );
446 if (!SetEvent (c->is_empty))
447 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
448 if (!ResetEvent (c->have_data) )
449 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
451 DEBUG1 ("writer thread %p: idle ...", c->thread_hd );
452 WaitForSingleObject (c->have_data, INFINITE);
453 DEBUG1 ("writer thread %p: got data to send", c->thread_hd );
462 DEBUG2 ("writer thread %p: writing %d bytes",
463 c->thread_hd, c->nbytes );
464 if ( c->nbytes && !WriteFile ( c->file_hd, c->buffer, c->nbytes,
466 c->error_code = (int)GetLastError ();
468 DEBUG2 ("writer thread %p: write error: ec=%d",
469 c->thread_hd, c->error_code );
472 DEBUG2 ("writer thread %p: wrote %d bytes",
473 c->thread_hd, (int)nwritten );
476 c->nbytes -= nwritten;
479 /* indicate that we have an error */
480 if ( !SetEvent (c->is_empty) )
481 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
482 DEBUG1 ("writer thread %p ended", c->thread_hd );
483 SetEvent (c->stopped);
489 static struct writer_context_s *
490 create_writer (HANDLE fd)
492 struct writer_context_s *c;
493 SECURITY_ATTRIBUTES sec_attr;
496 DEBUG1 ("creating new write thread for file handle %p", fd );
497 memset (&sec_attr, 0, sizeof sec_attr );
498 sec_attr.nLength = sizeof sec_attr;
499 sec_attr.bInheritHandle = FALSE;
501 c = calloc (1, sizeof *c );
506 c->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
507 c->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
508 c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
509 if (!c->have_data || !c->is_empty || !c->stopped ) {
510 DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
512 CloseHandle (c->have_data);
514 CloseHandle (c->is_empty);
516 CloseHandle (c->stopped);
521 c->is_empty = set_synchronize (c->is_empty);
522 INIT_LOCK (c->mutex);
524 c->thread_hd = CreateThread (&sec_attr, 0, writer, c, 0, &tid );
526 DEBUG1 ("** failed to create writer thread: ec=%d\n",
527 (int)GetLastError ());
528 DESTROY_LOCK (c->mutex);
530 CloseHandle (c->have_data);
532 CloseHandle (c->is_empty);
534 CloseHandle (c->stopped);
539 /* We set the priority of the thread higher because we know that
540 it only runs for a short time. This greatly helps to increase
541 the performance of the I/O. */
542 SetThreadPriority (c->thread_hd, get_desired_thread_priority ());
549 destroy_writer (struct writer_context_s *c)
554 SetEvent (c->have_data);
557 DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
558 WaitForSingleObject (c->stopped, INFINITE);
559 DEBUG1 ("thread %p has terminated", c->thread_hd );
562 CloseHandle (c->stopped);
564 CloseHandle (c->have_data);
566 CloseHandle (c->is_empty);
567 CloseHandle (c->thread_hd);
568 DESTROY_LOCK (c->mutex);
574 * Find a writer context or create a new one
575 * Note that the writer context will last until a io_close.
577 static struct writer_context_s *
578 find_writer (int fd, int start_it)
582 for (i=0; i < writer_table_size ; i++ ) {
583 if ( writer_table[i].used && writer_table[i].fd == fd )
584 return writer_table[i].context;
589 LOCK (writer_table_lock);
590 for (i=0; i < writer_table_size; i++ ) {
591 if (!writer_table[i].used) {
592 writer_table[i].fd = fd;
593 writer_table[i].context = create_writer (fd_to_handle (fd));
594 writer_table[i].used = 1;
595 UNLOCK (writer_table_lock);
596 return writer_table[i].context;
599 UNLOCK (writer_table_lock);
609 LOCK (writer_table_lock);
610 for (i=0; i < writer_table_size; i++ ) {
611 if (writer_table[i].used && writer_table[i].fd == fd ) {
612 destroy_writer (writer_table[i].context);
613 writer_table[i].context = NULL;
614 writer_table[i].used = 0;
618 UNLOCK (writer_table_lock);
625 _gpgme_io_write ( int fd, const void *buffer, size_t count )
627 struct writer_context_s *c = find_writer (fd,1);
629 DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count );
630 _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
632 DEBUG0 ( "no writer thread\n");
637 if ( c->nbytes ) { /* bytes are pending for send */
638 /* Reset the is_empty event. Better safe than sorry. */
639 if (!ResetEvent (c->is_empty))
640 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
642 DEBUG2 ("fd %d: waiting for empty buffer in thread %p",
644 WaitForSingleObject (c->is_empty, INFINITE);
645 DEBUG2 ("fd %d: thread %p buffer is empty", fd, c->thread_hd);
651 DEBUG1 ("fd %d: write error", fd );
655 /* If no error occured, the number of bytes in the buffer must be
659 if (count > WRITEBUF_SIZE)
660 count = WRITEBUF_SIZE;
661 memcpy (c->buffer, buffer, count);
664 /* We have to reset the is_empty event early, because it is also
665 used by the select() implementation to probe the channel. */
666 if (!ResetEvent (c->is_empty))
667 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
668 if (!SetEvent (c->have_data))
669 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
672 DEBUG2 ("fd %d: copied %d bytes\n",
679 _gpgme_io_pipe ( int filedes[2], int inherit_idx )
682 SECURITY_ATTRIBUTES sec_attr;
684 memset (&sec_attr, 0, sizeof sec_attr );
685 sec_attr.nLength = sizeof sec_attr;
686 sec_attr.bInheritHandle = FALSE;
688 if (!CreatePipe ( &r, &w, &sec_attr, PIPEBUF_SIZE))
690 /* Make one end inheritable. */
691 if ( inherit_idx == 0 ) {
693 if (!DuplicateHandle( GetCurrentProcess(), r,
694 GetCurrentProcess(), &h, 0,
695 TRUE, DUPLICATE_SAME_ACCESS ) ) {
696 DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
704 else if ( inherit_idx == 1 ) {
706 if (!DuplicateHandle( GetCurrentProcess(), w,
707 GetCurrentProcess(), &h, 0,
708 TRUE, DUPLICATE_SAME_ACCESS ) ) {
709 DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
718 filedes[0] = handle_to_fd (r);
719 filedes[1] = handle_to_fd (w);
720 DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
721 filedes[0], filedes[1], inherit_idx );
726 _gpgme_io_close ( int fd )
729 void (*handler)(int, void*) = NULL;
735 DEBUG1 ("** closing handle for fd %d\n", fd);
738 LOCK (notify_table_lock);
739 for ( i=0; i < DIM (notify_table); i++ ) {
740 if (notify_table[i].inuse && notify_table[i].fd == fd) {
741 handler = notify_table[i].handler;
742 value = notify_table[i].value;
743 notify_table[i].handler = NULL;
744 notify_table[i].value = NULL;
745 notify_table[i].inuse = 0;
749 UNLOCK (notify_table_lock);
753 if ( !CloseHandle (fd_to_handle (fd)) ) {
754 DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
755 fd, (int)GetLastError ());
763 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
769 LOCK (notify_table_lock);
770 for (i=0; i < DIM (notify_table); i++ ) {
771 if ( notify_table[i].inuse && notify_table[i].fd == fd )
774 if ( i == DIM (notify_table) ) {
775 for (i=0; i < DIM (notify_table); i++ ) {
776 if ( !notify_table[i].inuse )
780 if ( i == DIM (notify_table) ) {
781 UNLOCK (notify_table_lock);
784 notify_table[i].fd = fd;
785 notify_table[i].handler = handler;
786 notify_table[i].value = value;
787 notify_table[i].inuse = 1;
788 UNLOCK (notify_table_lock);
789 DEBUG2 ("set notification for fd %d (idx=%d)", fd, i );
795 _gpgme_io_set_nonblocking ( int fd )
802 build_commandline (char **argv)
810 /* We have to quote some things because under Windows the program
811 parses the commandline and does some unquoting. We enclose the
812 whole argument in double-quotes, and escape literal double-quotes
813 as well as backslashes with a backslash. We end up with a
814 trailing space at the end of the line, but that is harmless. */
815 for (i = 0; argv[i]; i++)
818 /* The leading double-quote. */
822 /* An extra one for each literal that must be escaped. */
823 if (*p == '\\' || *p == '"')
828 /* The trailing double-quote and the delimiter. */
831 /* And a trailing zero. */
834 buf = p = malloc (n);
837 for (i = 0; argv[i]; i++)
839 char *argvp = argv[i];
844 if (*argvp == '\\' || *argvp == '"')
858 _gpgme_io_spawn ( const char *path, char **argv,
859 struct spawn_fd_item_s *fd_child_list,
860 struct spawn_fd_item_s *fd_parent_list )
862 SECURITY_ATTRIBUTES sec_attr;
863 PROCESS_INFORMATION pi = {
864 NULL, /* returns process handle */
865 0, /* returns primary thread handle */
870 char *envblock = NULL;
871 int cr_flags = CREATE_DEFAULT_ERROR_MODE
872 | GetPriorityClass (GetCurrentProcess ());
876 int duped_stderr = 0;
877 HANDLE hnul = INVALID_HANDLE_VALUE;
881 memset (&sec_attr, 0, sizeof sec_attr );
882 sec_attr.nLength = sizeof sec_attr;
883 sec_attr.bInheritHandle = FALSE;
885 arg_string = build_commandline ( argv );
889 memset (&si, 0, sizeof si);
891 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
892 si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
893 si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
894 si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
895 si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
897 for (i=0; fd_child_list[i].fd != -1; i++ ) {
898 if (fd_child_list[i].dup_to == 0 ) {
899 si.hStdInput = fd_to_handle (fd_child_list[i].fd);
900 DEBUG1 ("using %d for stdin", fd_child_list[i].fd );
903 else if (fd_child_list[i].dup_to == 1 ) {
904 si.hStdOutput = fd_to_handle (fd_child_list[i].fd);
905 DEBUG1 ("using %d for stdout", fd_child_list[i].fd );
907 else if (fd_child_list[i].dup_to == 2 ) {
908 si.hStdError = fd_to_handle (fd_child_list[i].fd);
909 DEBUG1 ("using %d for stderr", fd_child_list[i].fd );
914 if( !duped_stdin || !duped_stderr ) {
915 SECURITY_ATTRIBUTES sa;
917 memset (&sa, 0, sizeof sa );
918 sa.nLength = sizeof sa;
919 sa.bInheritHandle = TRUE;
920 hnul = CreateFile ( "nul",
921 GENERIC_READ|GENERIC_WRITE,
922 FILE_SHARE_READ|FILE_SHARE_WRITE,
925 FILE_ATTRIBUTE_NORMAL,
927 if ( hnul == INVALID_HANDLE_VALUE ) {
928 DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
932 /* Make sure that the process has a connected stdin */
933 if ( !duped_stdin ) {
935 DEBUG1 ("using %d for dummy stdin", (int)hnul );
937 /* We normally don't want all the normal output */
938 if ( !duped_stderr ) {
940 DEBUG1 ("using %d for dummy stderr", (int)hnul );
944 DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
945 cr_flags |= CREATE_SUSPENDED;
946 if ( !CreateProcessA (path,
948 &sec_attr, /* process security attributes */
949 &sec_attr, /* thread security attributes */
950 TRUE, /* inherit handles */
951 cr_flags, /* creation flags */
952 envblock, /* environment */
953 NULL, /* use current drive/directory */
954 &si, /* startup information */
955 &pi /* returns process information */
957 DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
962 /* Close the /dev/nul handle if used. */
963 if (hnul != INVALID_HANDLE_VALUE ) {
964 if ( !CloseHandle ( hnul ) )
965 DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
968 /* Close the other ends of the pipes. */
969 for (i = 0; fd_parent_list[i].fd != -1; i++)
970 _gpgme_io_close (fd_parent_list[i].fd);
972 DEBUG4 ("CreateProcess ready\n"
973 "- hProcess=%p hThread=%p\n"
974 "- dwProcessID=%d dwThreadId=%d\n",
975 pi.hProcess, pi.hThread,
976 (int) pi.dwProcessId, (int) pi.dwThreadId);
978 if ( ResumeThread ( pi.hThread ) < 0 ) {
979 DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
982 if ( !CloseHandle (pi.hThread) ) {
983 DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
984 (int)GetLastError ());
987 return handle_to_pid (pi.hProcess);
992 * Select on the list of fds.
993 * Returns: -1 = error
994 * 0 = timeout or nothing to select
995 * >0 = number of signaled fds
998 _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock )
1000 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1001 int waitidx[MAXIMUM_WAIT_OBJECTS];
1008 DEBUG_BEGIN (dbg_help, 3, "select on [ ");
1012 for ( i=0; i < nfds; i++ ) {
1013 if ( fds[i].fd == -1 )
1015 fds[i].signaled = 0;
1016 if ( fds[i].for_read || fds[i].for_write ) {
1017 if ( fds[i].frozen ) {
1018 DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd );
1020 else if ( fds[i].for_read ) {
1021 struct reader_context_s *c = find_reader (fds[i].fd,1);
1024 DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd);
1027 if ( nwait >= DIM (waitbuf) ) {
1028 DEBUG_END (dbg_help, "oops ]");
1029 DEBUG0 ("Too many objects for WFMO!" );
1033 waitbuf[nwait++] = c->have_data_ev;
1035 DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd );
1038 else if ( fds[i].for_write ) {
1039 struct writer_context_s *c = find_writer (fds[i].fd,1);
1042 DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd);
1045 if ( nwait >= DIM (waitbuf) ) {
1046 DEBUG_END (dbg_help, "oops ]");
1047 DEBUG0 ("Too many objects for WFMO!" );
1051 waitbuf[nwait++] = c->is_empty;
1053 DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd );
1058 DEBUG_END (dbg_help, "]");
1062 code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000);
1063 if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
1064 /* This WFMO is a really silly function: It does return either
1065 * the index of the signaled object or if 2 objects have been
1066 * signalled at the same time, the index of the object with the
1067 * lowest object is returned - so and how do we find out
1068 * how many objects have been signaled???.
1069 * The only solution I can imagine is to test each object starting
1070 * with the returned index individually - how dull.
1073 for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) {
1074 if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) {
1075 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1076 fds[waitidx[i]].signaled = 1;
1082 DEBUG0 ("Oops: No signaled objects found after WFMO");
1086 else if ( code == WAIT_TIMEOUT ) {
1087 DEBUG0 ("WFMO timed out\n" );
1089 else if (code == WAIT_FAILED ) {
1090 int le = (int)GetLastError ();
1091 if ( le == ERROR_INVALID_HANDLE ) {
1092 int k, j = handle_to_fd (waitbuf[i]);
1094 DEBUG1 ("WFMO invalid handle %d removed\n", j);
1095 for (k=0 ; k < nfds; k++ ) {
1096 if ( fds[k].fd == j ) {
1097 fds[k].for_read = fds[k].for_write = 0;
1101 DEBUG0 (" oops, or not???\n");
1103 DEBUG1 ("WFMO failed: %d\n", le );
1107 DEBUG1 ("WFMO returned %d\n", code );
1112 DEBUG_BEGIN (dbg_help, 3, " signaled [ ");
1113 for ( i=0; i < nfds; i++ ) {
1114 if ( fds[i].fd == -1 )
1116 if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
1117 DEBUG_ADD2 (dbg_help, "%c%d ",
1118 fds[i].for_read? 'r':'w',fds[i].fd );
1121 DEBUG_END (dbg_help, "]");
1128 _gpgme_io_subsystem_init (void)
1134 /* Write the printable version of FD to the buffer BUF of length
1135 BUFLEN. The printable version is the representation on the command
1136 line that the child process expects. */
1138 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1140 return snprintf (buf, buflen, "%d", fd);
1144 /* The following interface is only useful for GPGME Glib. */
1146 /* Look up the giochannel for file descriptor FD. */
1148 gpgme_get_giochannel (int fd)