Blame src/w32-estream.c

Packit fc043f
/* w32-estream.c - es_poll support on W32.
Packit fc043f
 * Copyright (C) 2000 Werner Koch (dd9jn)
Packit fc043f
 * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2010, 2016 g10 Code GmbH
Packit fc043f
 *
Packit fc043f
 * This file is part of libgpg-error.
Packit fc043f
 *
Packit fc043f
 * libgpg-error is free software; you can redistribute it and/or
Packit fc043f
 * modify it under the terms of the GNU Lesser General Public License
Packit fc043f
 * as published by the Free Software Foundation; either version 2.1 of
Packit fc043f
 * the License, or (at your option) any later version.
Packit fc043f
 *
Packit fc043f
 * libgpg-error is distributed in the hope that it will be useful, but
Packit fc043f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit fc043f
 * Lesser General Public License for more details.
Packit fc043f
 *
Packit fc043f
 * You should have received a copy of the GNU Lesser General Public
Packit fc043f
 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * This file is based on GPGME's w32-io.c started in 2001.
Packit fc043f
 */
Packit fc043f
Packit fc043f
#ifdef HAVE_CONFIG_H
Packit fc043f
#include <config.h>
Packit fc043f
#endif
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <string.h>
Packit fc043f
#include <assert.h>
Packit fc043f
#include <errno.h>
Packit fc043f
#include <fcntl.h>
Packit fc043f
#ifdef HAVE_SYS_TIME_H
Packit fc043f
# include <sys/time.h>
Packit fc043f
#endif
Packit fc043f
#ifdef HAVE_SYS_TYPES_H
Packit fc043f
# include <sys/types.h>
Packit fc043f
#endif
Packit fc043f
#include <io.h>
Packit fc043f
#include <windows.h>
Packit fc043f
Packit fc043f
/* Enable tracing.  The value is the module name to be printed.  */
Packit fc043f
/*#define ENABLE_TRACING "estream" */
Packit fc043f
Packit fc043f
#include "gpgrt-int.h"
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * In order to support es_poll on Windows, we create a proxy shim that
Packit fc043f
 * we use as the estream I/O functions.  This shim creates reader and
Packit fc043f
 * writer threads that use the original I/O functions.
Packit fc043f
 */
Packit fc043f
Packit fc043f
Packit fc043f
/* Calculate array dimension.  */
Packit fc043f
#ifndef DIM
Packit fc043f
#define DIM(array) (sizeof (array) / sizeof (*array))
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#define READBUF_SIZE 4096
Packit fc043f
#define WRITEBUF_SIZE 4096
Packit fc043f
Packit fc043f
Packit fc043f
typedef struct estream_cookie_w32_pollable *estream_cookie_w32_pollable_t;
Packit fc043f
Packit fc043f
struct reader_context_s
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie;
Packit fc043f
  HANDLE thread_hd;
Packit fc043f
Packit fc043f
  CRITICAL_SECTION mutex;
Packit fc043f
Packit fc043f
  int stop_me;
Packit fc043f
  int eof;
Packit fc043f
  int eof_shortcut;
Packit fc043f
  int error;
Packit fc043f
  int error_code;
Packit fc043f
Packit fc043f
  /* This is manually reset.  */
Packit fc043f
  HANDLE have_data_ev;
Packit fc043f
  /* This is automatically reset.  */
Packit fc043f
  HANDLE have_space_ev;
Packit fc043f
  /* This is manually reset but actually only triggered once.  */
Packit fc043f
  HANDLE close_ev;
Packit fc043f
Packit fc043f
  size_t readpos, writepos;
Packit fc043f
  char buffer[READBUF_SIZE];
Packit fc043f
};
Packit fc043f
Packit fc043f
struct writer_context_s
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie;
Packit fc043f
  HANDLE thread_hd;
Packit fc043f
Packit fc043f
  CRITICAL_SECTION mutex;
Packit fc043f
Packit fc043f
  int stop_me;
Packit fc043f
  int error;
Packit fc043f
  int error_code;
Packit fc043f
Packit fc043f
  /* This is manually reset.  */
Packit fc043f
  HANDLE have_data;
Packit fc043f
  HANDLE is_empty;
Packit fc043f
  HANDLE close_ev;
Packit fc043f
  size_t nbytes;
Packit fc043f
  char buffer[WRITEBUF_SIZE];
Packit fc043f
};
Packit fc043f
Packit fc043f
/* Cookie for pollable objects.  */
Packit fc043f
struct estream_cookie_w32_pollable
Packit fc043f
{
Packit fc043f
  unsigned int modeflags;
Packit fc043f
Packit fc043f
  struct cookie_io_functions_s next_functions;
Packit fc043f
  void *next_cookie;
Packit fc043f
Packit fc043f
  struct reader_context_s *reader;
Packit fc043f
  struct writer_context_s *writer;
Packit fc043f
};
Packit fc043f
Packit fc043f
Packit fc043f
static HANDLE
Packit fc043f
set_synchronize (HANDLE hd)
Packit fc043f
{
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
  return hd;
Packit fc043f
#else
Packit fc043f
  HANDLE new_hd;
Packit fc043f
Packit fc043f
  /* For NT we have to set the sync flag.  It seems that the only way
Packit fc043f
     to do it is by duplicating the handle.  Tsss...  */
Packit fc043f
  if (!DuplicateHandle (GetCurrentProcess (), hd,
Packit fc043f
			GetCurrentProcess (), &new_hd,
Packit fc043f
			EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
Packit fc043f
    {
Packit fc043f
      trace_errno (1, ("DuplicateHandle failed: ec=%d", (int)GetLastError ()));
Packit fc043f
      /* FIXME: Should translate the error code.  */
Packit fc043f
      _gpg_err_set_errno (EIO);
Packit fc043f
      return INVALID_HANDLE_VALUE;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  CloseHandle (hd);
Packit fc043f
  return new_hd;
Packit fc043f
#endif
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static DWORD CALLBACK
Packit fc043f
reader (void *arg)
Packit fc043f
{
Packit fc043f
  struct reader_context_s *ctx = arg;
Packit fc043f
  int nbytes;
Packit fc043f
  ssize_t nread;
Packit fc043f
Packit fc043f
  trace (("%p: reader starting", ctx));
Packit fc043f
Packit fc043f
  for (;;)
Packit fc043f
    {
Packit fc043f
      EnterCriticalSection (&ctx->mutex);
Packit fc043f
      /* Leave a 1 byte gap so that we can see whether it is empty or
Packit fc043f
	 full.  */
Packit fc043f
      while ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
Packit fc043f
	{
Packit fc043f
	  /* Wait for space.  */
Packit fc043f
	  if (!ResetEvent (ctx->have_space_ev))
Packit fc043f
	    trace (("%p: ResetEvent failed: ec=%d", ctx, (int)GetLastError()));
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
          trace (("%p: waiting for space", ctx));
Packit fc043f
	  WaitForSingleObject (ctx->have_space_ev, INFINITE);
Packit fc043f
	  trace (("%p: got space", ctx));
Packit fc043f
          EnterCriticalSection (&ctx->mutex);
Packit fc043f
        }
Packit fc043f
      assert (((ctx->writepos + 1) % READBUF_SIZE != ctx->readpos));
Packit fc043f
      if (ctx->stop_me)
Packit fc043f
	{
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  break;
Packit fc043f
        }
Packit fc043f
      nbytes = (ctx->readpos + READBUF_SIZE
Packit fc043f
		- ctx->writepos - 1) % READBUF_SIZE;
Packit fc043f
      assert (nbytes);
Packit fc043f
      if (nbytes > READBUF_SIZE - ctx->writepos)
Packit fc043f
	nbytes = READBUF_SIZE - ctx->writepos;
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
      trace (("%p: reading up to %d bytes", ctx, nbytes));
Packit fc043f
Packit fc043f
      nread = ctx->pcookie->next_functions.public.func_read
Packit fc043f
        (ctx->pcookie->next_cookie, ctx->buffer + ctx->writepos, nbytes);
Packit fc043f
      trace (("%p: got %d bytes", ctx, nread));
Packit fc043f
      if (nread < 0)
Packit fc043f
        {
Packit fc043f
          ctx->error_code = (int) errno;
Packit fc043f
          /* NOTE (W32CE): Do not ignore ERROR_BUSY!  Check at
Packit fc043f
             least stop_me if that happens.  */
Packit fc043f
          if (ctx->error_code == ERROR_BROKEN_PIPE)
Packit fc043f
            {
Packit fc043f
              ctx->eof = 1;
Packit fc043f
              trace (("%p: got EOF (broken pipe)", ctx));
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              ctx->error = 1;
Packit fc043f
              trace (("%p: read error: ec=%d", ctx, ctx->error_code));
Packit fc043f
            }
Packit fc043f
          break;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      EnterCriticalSection (&ctx->mutex);
Packit fc043f
      if (ctx->stop_me)
Packit fc043f
	{
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  break;
Packit fc043f
        }
Packit fc043f
      if (!nread)
Packit fc043f
	{
Packit fc043f
	  ctx->eof = 1;
Packit fc043f
	  trace (("%p: got eof", ctx));
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  break;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
Packit fc043f
      if (!SetEvent (ctx->have_data_ev))
Packit fc043f
	trace (("%p: SetEvent (%p) failed: ec=%d",
Packit fc043f
                ctx, ctx->have_data_ev, (int)GetLastError ()));
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
    }
Packit fc043f
  /* Indicate that we have an error or EOF.  */
Packit fc043f
  if (!SetEvent (ctx->have_data_ev))
Packit fc043f
    trace (("%p: SetEvent (%p) failed: ec=%d",
Packit fc043f
            ctx, ctx->have_data_ev, (int)GetLastError ()));
Packit fc043f
Packit fc043f
  trace (("%p: waiting for close", ctx));
Packit fc043f
  WaitForSingleObject (ctx->close_ev, INFINITE);
Packit fc043f
Packit fc043f
  CloseHandle (ctx->close_ev);
Packit fc043f
  CloseHandle (ctx->have_data_ev);
Packit fc043f
  CloseHandle (ctx->have_space_ev);
Packit fc043f
  CloseHandle (ctx->thread_hd);
Packit fc043f
  DeleteCriticalSection (&ctx->mutex);
Packit fc043f
  free (ctx);  /* Standard free!  See comment in create_reader. */
Packit fc043f
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static struct reader_context_s *
Packit fc043f
create_reader (estream_cookie_w32_pollable_t pcookie)
Packit fc043f
{
Packit fc043f
  struct reader_context_s *ctx;
Packit fc043f
  SECURITY_ATTRIBUTES sec_attr;
Packit fc043f
  DWORD tid;
Packit fc043f
Packit fc043f
  memset (&sec_attr, 0, sizeof sec_attr);
Packit fc043f
  sec_attr.nLength = sizeof sec_attr;
Packit fc043f
  sec_attr.bInheritHandle = FALSE;
Packit fc043f
Packit fc043f
  /* The CTX must be allocated in standard system memory so that we
Packit fc043f
   * won't use any custom allocation handler which may use our lock
Packit fc043f
   * primitives for its implementation.  The problem here is that the
Packit fc043f
   * syscall clamp mechanism (e.g. nPth) would be called recursively:
Packit fc043f
   * 1. For example by the caller of _gpgrt_w32_poll and 2. by
Packit fc043f
   * gpgrt_lock_lock on behalf of the the custom allocation and free
Packit fc043f
   * functions.  */
Packit fc043f
  ctx = calloc (1, sizeof *ctx);
Packit fc043f
  if (!ctx)
Packit fc043f
    {
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  ctx->pcookie = pcookie;
Packit fc043f
Packit fc043f
  ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
Packit fc043f
  if (ctx->have_data_ev)
Packit fc043f
    ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
Packit fc043f
  if (ctx->have_space_ev)
Packit fc043f
    ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
Packit fc043f
  if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->close_ev)
Packit fc043f
    {
Packit fc043f
      trace (("%p: CreateEvent failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
      if (ctx->have_data_ev)
Packit fc043f
	CloseHandle (ctx->have_data_ev);
Packit fc043f
      if (ctx->have_space_ev)
Packit fc043f
	CloseHandle (ctx->have_space_ev);
Packit fc043f
      if (ctx->close_ev)
Packit fc043f
	CloseHandle (ctx->close_ev);
Packit fc043f
      _gpgrt_free (ctx);
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
Packit fc043f
  InitializeCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
  ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, reader, ctx,
Packit fc043f
				 STACK_SIZE_PARAM_IS_A_RESERVATION, &tid;;
Packit fc043f
#else
Packit fc043f
  ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid;;
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  if (!ctx->thread_hd)
Packit fc043f
    {
Packit fc043f
      trace (("%p: CreateThread failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
      DeleteCriticalSection (&ctx->mutex);
Packit fc043f
      if (ctx->have_data_ev)
Packit fc043f
	CloseHandle (ctx->have_data_ev);
Packit fc043f
      if (ctx->have_space_ev)
Packit fc043f
	CloseHandle (ctx->have_space_ev);
Packit fc043f
      if (ctx->close_ev)
Packit fc043f
	CloseHandle (ctx->close_ev);
Packit fc043f
      _gpgrt_free (ctx);
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
#if 0
Packit fc043f
      /* We set the priority of the thread higher because we know that
Packit fc043f
         it only runs for a short time.  This greatly helps to
Packit fc043f
         increase the performance of the I/O.  */
Packit fc043f
      SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
Packit fc043f
#endif
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return ctx;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Prepare destruction of the reader thread for CTX.  Returns 0 if a
Packit fc043f
   call to this function is sufficient and destroy_reader_finish shall
Packit fc043f
   not be called.  */
Packit fc043f
static void
Packit fc043f
destroy_reader (struct reader_context_s *ctx)
Packit fc043f
{
Packit fc043f
  EnterCriticalSection (&ctx->mutex);
Packit fc043f
  ctx->stop_me = 1;
Packit fc043f
  if (ctx->have_space_ev)
Packit fc043f
    SetEvent (ctx->have_space_ev);
Packit fc043f
  LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
  /* Scenario: We never create a full pipe, but already started
Packit fc043f
     reading.  Then we need to unblock the reader in the pipe driver
Packit fc043f
     to make our reader thread notice that we want it to go away.  */
Packit fc043f
Packit fc043f
  if (ctx->file_hd != INVALID_HANDLE_VALUE)
Packit fc043f
    {
Packit fc043f
      if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
Packit fc043f
			NULL, 0, NULL, 0, NULL, NULL))
Packit fc043f
	{
Packit fc043f
	  trace (("%p: unblock control call failed: ec=%d",
Packit fc043f
                  ctx, (int)GetLastError ()));
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  /* XXX is it feasible to unblock the thread?  */
Packit fc043f
Packit fc043f
  /* After setting this event CTX is void. */
Packit fc043f
  SetEvent (ctx->close_ev);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Read function for pollable objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_w32_pollable_read (void *cookie, void *buffer, size_t count)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie = cookie;
Packit fc043f
  gpgrt_ssize_t nread;
Packit fc043f
  struct reader_context_s *ctx;
Packit fc043f
Packit fc043f
  trace (("%p: enter buffer=%p count=%u", cookie, buffer, count));
Packit fc043f
Packit fc043f
  /* FIXME: implement pending check if COUNT==0 */
Packit fc043f
Packit fc043f
  ctx = pcookie->reader;
Packit fc043f
  if (ctx == NULL)
Packit fc043f
    {
Packit fc043f
      pcookie->reader = ctx = create_reader (pcookie);
Packit fc043f
      if (!ctx)
Packit fc043f
        {
Packit fc043f
          _gpg_err_set_errno (EBADF);
Packit fc043f
          nread = -1;
Packit fc043f
          goto leave;
Packit fc043f
        }
Packit fc043f
      trace (("%p: new reader %p", cookie, pcookie->reader));
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (ctx->eof_shortcut)
Packit fc043f
    {
Packit fc043f
      nread = 0;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  EnterCriticalSection (&ctx->mutex);
Packit fc043f
  trace (("%p: readpos: %d, writepos %d", cookie, ctx->readpos, ctx->writepos));
Packit fc043f
  if (ctx->readpos == ctx->writepos && !ctx->error)
Packit fc043f
    {
Packit fc043f
      /* No data available.  */
Packit fc043f
      int eof = ctx->eof;
Packit fc043f
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
      if (pcookie->modeflags & O_NONBLOCK && ! eof)
Packit fc043f
        {
Packit fc043f
          _gpg_err_set_errno (EAGAIN);
Packit fc043f
          nread = -1;
Packit fc043f
          goto leave;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      trace (("%p: waiting for data", cookie));
Packit fc043f
      WaitForSingleObject (ctx->have_data_ev, INFINITE);
Packit fc043f
      trace (("%p: data available", cookie));
Packit fc043f
      EnterCriticalSection (&ctx->mutex);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (ctx->readpos == ctx->writepos || ctx->error)
Packit fc043f
    {
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
      ctx->eof_shortcut = 1;
Packit fc043f
      if (ctx->eof)
Packit fc043f
	return 0;
Packit fc043f
      if (!ctx->error)
Packit fc043f
	{
Packit fc043f
	  trace (("%p: EOF but ctx->eof flag not set", cookie));
Packit fc043f
          nread = 0;
Packit fc043f
          goto leave;
Packit fc043f
	}
Packit fc043f
      _gpg_err_set_errno (ctx->error_code);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  nread = ctx->readpos < ctx->writepos
Packit fc043f
    ? ctx->writepos - ctx->readpos
Packit fc043f
    : READBUF_SIZE - ctx->readpos;
Packit fc043f
  if (nread > count)
Packit fc043f
    nread = count;
Packit fc043f
  memcpy (buffer, ctx->buffer + ctx->readpos, nread);
Packit fc043f
  ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
Packit fc043f
  if (ctx->readpos == ctx->writepos && !ctx->eof)
Packit fc043f
    {
Packit fc043f
      if (!ResetEvent (ctx->have_data_ev))
Packit fc043f
	{
Packit fc043f
	  trace (("%p: ResetEvent failed: ec=%d",
Packit fc043f
                  cookie, (int)GetLastError ()));
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  /* FIXME: Should translate the error code.  */
Packit fc043f
	  _gpg_err_set_errno (EIO);
Packit fc043f
	  nread = -1;
Packit fc043f
          goto leave;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
  if (!SetEvent (ctx->have_space_ev))
Packit fc043f
    {
Packit fc043f
      trace (("%p: SetEvent (%p) failed: ec=%d",
Packit fc043f
              cookie, ctx->have_space_ev, (int)GetLastError ()));
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
      /* FIXME: Should translate the error code.  */
Packit fc043f
      _gpg_err_set_errno (EIO);
Packit fc043f
      nread = -1;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
  LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
 leave:
Packit fc043f
  trace_errno (nread==-1,("%p: leave nread=%d", cookie, (int)nread));
Packit fc043f
  return nread;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* The writer does use a simple buffering strategy so that we are
Packit fc043f
   informed about write errors as soon as possible (i. e. with the the
Packit fc043f
   next call to the write function.  */
Packit fc043f
static DWORD CALLBACK
Packit fc043f
writer (void *arg)
Packit fc043f
{
Packit fc043f
  struct writer_context_s *ctx = arg;
Packit fc043f
  ssize_t nwritten;
Packit fc043f
Packit fc043f
  trace (("%p: writer starting", ctx));
Packit fc043f
Packit fc043f
  for (;;)
Packit fc043f
    {
Packit fc043f
      EnterCriticalSection (&ctx->mutex);
Packit fc043f
      if (ctx->stop_me && !ctx->nbytes)
Packit fc043f
	{
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  break;
Packit fc043f
        }
Packit fc043f
      if (!ctx->nbytes)
Packit fc043f
	{
Packit fc043f
	  if (!SetEvent (ctx->is_empty))
Packit fc043f
	    trace (("%p: SetEvent failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
	  if (!ResetEvent (ctx->have_data))
Packit fc043f
	    trace (("%p: ResetEvent failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  trace (("%p: idle", ctx));
Packit fc043f
	  WaitForSingleObject (ctx->have_data, INFINITE);
Packit fc043f
	  trace (("%p: got data to write", ctx));
Packit fc043f
          EnterCriticalSection (&ctx->mutex);
Packit fc043f
        }
Packit fc043f
      if (ctx->stop_me && !ctx->nbytes)
Packit fc043f
	{
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  break;
Packit fc043f
        }
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
      trace (("%p: writing up to %d bytes", ctx, ctx->nbytes));
Packit fc043f
Packit fc043f
      nwritten = ctx->pcookie->next_functions.public.func_write
Packit fc043f
        (ctx->pcookie->next_cookie, ctx->buffer, ctx->nbytes);
Packit fc043f
      trace (("%p: wrote %d bytes", ctx, nwritten));
Packit fc043f
      if (nwritten < 1)
Packit fc043f
        {
Packit fc043f
          /* XXX */
Packit fc043f
          if (errno == ERROR_BUSY)
Packit fc043f
            {
Packit fc043f
              /* Probably stop_me is set now.  */
Packit fc043f
              trace (("%p: pipe busy (unblocked?)", ctx));
Packit fc043f
              continue;
Packit fc043f
            }
Packit fc043f
Packit fc043f
          ctx->error_code = errno;
Packit fc043f
          ctx->error = 1;
Packit fc043f
          trace (("%p: write error: ec=%d", ctx, ctx->error_code));
Packit fc043f
          break;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      EnterCriticalSection (&ctx->mutex);
Packit fc043f
      ctx->nbytes -= nwritten;
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
    }
Packit fc043f
  /* Indicate that we have an error.  */
Packit fc043f
  if (!SetEvent (ctx->is_empty))
Packit fc043f
    trace (("%p: SetEvent failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
Packit fc043f
  trace (("%p: waiting for close", ctx));
Packit fc043f
  WaitForSingleObject (ctx->close_ev, INFINITE);
Packit fc043f
Packit fc043f
  if (ctx->nbytes)
Packit fc043f
    trace (("%p: still %d bytes in buffer at close time", ctx, ctx->nbytes));
Packit fc043f
Packit fc043f
  CloseHandle (ctx->close_ev);
Packit fc043f
  CloseHandle (ctx->have_data);
Packit fc043f
  CloseHandle (ctx->is_empty);
Packit fc043f
  CloseHandle (ctx->thread_hd);
Packit fc043f
  DeleteCriticalSection (&ctx->mutex);
Packit fc043f
  trace (("%p: writer is destroyed", ctx));
Packit fc043f
  free (ctx); /* Standard free!  See comment in create_writer. */
Packit fc043f
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static struct writer_context_s *
Packit fc043f
create_writer (estream_cookie_w32_pollable_t pcookie)
Packit fc043f
{
Packit fc043f
  struct writer_context_s *ctx;
Packit fc043f
  SECURITY_ATTRIBUTES sec_attr;
Packit fc043f
  DWORD tid;
Packit fc043f
Packit fc043f
  memset (&sec_attr, 0, sizeof sec_attr);
Packit fc043f
  sec_attr.nLength = sizeof sec_attr;
Packit fc043f
  sec_attr.bInheritHandle = FALSE;
Packit fc043f
Packit fc043f
  /* See comment at create_reader.  */
Packit fc043f
  ctx = calloc (1, sizeof *ctx);
Packit fc043f
  if (!ctx)
Packit fc043f
    {
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  ctx->pcookie = pcookie;
Packit fc043f
Packit fc043f
  ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
Packit fc043f
  if (ctx->have_data)
Packit fc043f
    ctx->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
Packit fc043f
  if (ctx->is_empty)
Packit fc043f
    ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
Packit fc043f
  if (!ctx->have_data || !ctx->is_empty || !ctx->close_ev)
Packit fc043f
    {
Packit fc043f
      trace (("%p: CreateEvent failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
      if (ctx->have_data)
Packit fc043f
	CloseHandle (ctx->have_data);
Packit fc043f
      if (ctx->is_empty)
Packit fc043f
	CloseHandle (ctx->is_empty);
Packit fc043f
      if (ctx->close_ev)
Packit fc043f
	CloseHandle (ctx->close_ev);
Packit fc043f
      _gpgrt_free (ctx);
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  ctx->is_empty = set_synchronize (ctx->is_empty);
Packit fc043f
  InitializeCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
  ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, writer, ctx,
Packit fc043f
				 STACK_SIZE_PARAM_IS_A_RESERVATION, &tid;;
Packit fc043f
#else
Packit fc043f
  ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  if (!ctx->thread_hd)
Packit fc043f
    {
Packit fc043f
      trace (("%p: CreateThread failed: ec=%d", ctx, (int)GetLastError ()));
Packit fc043f
      DeleteCriticalSection (&ctx->mutex);
Packit fc043f
      if (ctx->have_data)
Packit fc043f
	CloseHandle (ctx->have_data);
Packit fc043f
      if (ctx->is_empty)
Packit fc043f
	CloseHandle (ctx->is_empty);
Packit fc043f
      if (ctx->close_ev)
Packit fc043f
	CloseHandle (ctx->close_ev);
Packit fc043f
      _gpgrt_free (ctx);
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
#if 0
Packit fc043f
      /* We set the priority of the thread higher because we know
Packit fc043f
	 that it only runs for a short time.  This greatly helps to
Packit fc043f
	 increase the performance of the I/O.  */
Packit fc043f
      SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
Packit fc043f
#endif
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return ctx;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
destroy_writer (struct writer_context_s *ctx)
Packit fc043f
{
Packit fc043f
  trace (("%p: enter pollable_destroy_writer", ctx));
Packit fc043f
  EnterCriticalSection (&ctx->mutex);
Packit fc043f
  trace (("%p: setting stopme", ctx));
Packit fc043f
  ctx->stop_me = 1;
Packit fc043f
  if (ctx->have_data)
Packit fc043f
    SetEvent (ctx->have_data);
Packit fc043f
  LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
  trace (("%p: waiting for empty", ctx));
Packit fc043f
Packit fc043f
  /* Give the writer a chance to flush the buffer.  */
Packit fc043f
  WaitForSingleObject (ctx->is_empty, INFINITE);
Packit fc043f
Packit fc043f
#ifdef HAVE_W32CE_SYSTEM
Packit fc043f
  /* Scenario: We never create a full pipe, but already started
Packit fc043f
     writing more than the pipe buffer.  Then we need to unblock the
Packit fc043f
     writer in the pipe driver to make our writer thread notice that
Packit fc043f
     we want it to go away.  */
Packit fc043f
Packit fc043f
  if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
Packit fc043f
			NULL, 0, NULL, 0, NULL, NULL))
Packit fc043f
    {
Packit fc043f
      trace (("%p: unblock control call failed: ec=%d",
Packit fc043f
              ctx, (int)GetLastError ()));
Packit fc043f
    }
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  /* After setting this event CTX is void.  */
Packit fc043f
  trace (("%p: set close_ev", ctx));
Packit fc043f
  SetEvent (ctx->close_ev);
Packit fc043f
  trace (("%p: leave pollable_destroy_writer", ctx));
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Write function for pollable objects.
Packit fc043f
 */
Packit fc043f
static gpgrt_ssize_t
Packit fc043f
func_w32_pollable_write (void *cookie, const void *buffer, size_t count)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie = cookie;
Packit fc043f
  struct writer_context_s *ctx = pcookie->writer;
Packit fc043f
  int nwritten;
Packit fc043f
Packit fc043f
  trace (("%p: enter buffer: %p count: %d", cookie, buffer, count));
Packit fc043f
  if (count == 0)
Packit fc043f
    {
Packit fc043f
      nwritten = 0;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (ctx == NULL)
Packit fc043f
    {
Packit fc043f
      pcookie->writer = ctx = create_writer (pcookie);
Packit fc043f
      if (!ctx)
Packit fc043f
        {
Packit fc043f
          nwritten = -1;
Packit fc043f
          goto leave;
Packit fc043f
        }
Packit fc043f
      trace (("%p: new writer %p", cookie, pcookie->writer));
Packit fc043f
    }
Packit fc043f
Packit fc043f
  EnterCriticalSection (&ctx->mutex);
Packit fc043f
  trace (("%p: buffer: %p, count: %d, nbytes: %d",
Packit fc043f
          cookie, buffer, count, ctx->nbytes));
Packit fc043f
  if (!ctx->error && ctx->nbytes)
Packit fc043f
    {
Packit fc043f
      /* Bytes are pending for send.  */
Packit fc043f
Packit fc043f
      /* Reset the is_empty event.  Better safe than sorry.  */
Packit fc043f
      if (!ResetEvent (ctx->is_empty))
Packit fc043f
	{
Packit fc043f
          trace (("%p: ResetEvent failed: ec=%d",
Packit fc043f
                  cookie, (int)GetLastError ()));
Packit fc043f
          LeaveCriticalSection (&ctx->mutex);
Packit fc043f
	  /* FIXME: Should translate the error code.  */
Packit fc043f
	  _gpg_err_set_errno (EIO);
Packit fc043f
	  nwritten = -1;
Packit fc043f
          goto leave;
Packit fc043f
	}
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
      if (pcookie->modeflags & O_NONBLOCK)
Packit fc043f
        {
Packit fc043f
          trace (("%p: would block", cookie));
Packit fc043f
          _gpg_err_set_errno (EAGAIN);
Packit fc043f
          nwritten = -1;
Packit fc043f
          goto leave;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      trace (("%p: waiting for empty buffer", cookie));
Packit fc043f
      WaitForSingleObject (ctx->is_empty, INFINITE);
Packit fc043f
      trace (("%p: buffer is empty", cookie));
Packit fc043f
      EnterCriticalSection (&ctx->mutex);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (ctx->error)
Packit fc043f
    {
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
      if (ctx->error_code == ERROR_NO_DATA)
Packit fc043f
        _gpg_err_set_errno (EPIPE);
Packit fc043f
      else
Packit fc043f
        _gpg_err_set_errno (EIO);
Packit fc043f
      nwritten = -1;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* If no error occurred, the number of bytes in the buffer must be
Packit fc043f
     zero.  */
Packit fc043f
  assert (!ctx->nbytes);
Packit fc043f
Packit fc043f
  if (count > WRITEBUF_SIZE)
Packit fc043f
    count = WRITEBUF_SIZE;
Packit fc043f
  memcpy (ctx->buffer, buffer, count);
Packit fc043f
  ctx->nbytes = count;
Packit fc043f
Packit fc043f
  /* We have to reset the is_empty event early, because it is also
Packit fc043f
     used by the select() implementation to probe the channel.  */
Packit fc043f
  if (!ResetEvent (ctx->is_empty))
Packit fc043f
    {
Packit fc043f
      trace (("%p: ResetEvent failed: ec=%d", cookie, (int)GetLastError ()));
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
      /* FIXME: Should translate the error code.  */
Packit fc043f
      _gpg_err_set_errno (EIO);
Packit fc043f
      nwritten = -1;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
  if (!SetEvent (ctx->have_data))
Packit fc043f
    {
Packit fc043f
      trace (("%p: SetEvent failed: ec=%d", cookie, (int)GetLastError ()));
Packit fc043f
      LeaveCriticalSection (&ctx->mutex);
Packit fc043f
      /* FIXME: Should translate the error code.  */
Packit fc043f
      _gpg_err_set_errno (EIO);
Packit fc043f
      nwritten = -1;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
  LeaveCriticalSection (&ctx->mutex);
Packit fc043f
Packit fc043f
  nwritten = count;
Packit fc043f
Packit fc043f
 leave:
Packit fc043f
  trace_errno (nwritten==-1,("%p: leave nwritten=%d", cookie, nwritten));
Packit fc043f
  return nwritten;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* This is the core of _gpgrt_poll.  The caller needs to make sure that
Packit fc043f
 * the syscall clamp has been engaged.  */
Packit fc043f
int
Packit fc043f
_gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout)
Packit fc043f
{
Packit fc043f
  HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
Packit fc043f
  int waitidx[MAXIMUM_WAIT_OBJECTS];
Packit fc043f
#ifdef ENABLE_TRACING
Packit fc043f
  char waitinfo[MAXIMUM_WAIT_OBJECTS];
Packit fc043f
#endif
Packit fc043f
  unsigned int code;
Packit fc043f
  int nwait;
Packit fc043f
  int i;
Packit fc043f
  int any;
Packit fc043f
  int count;
Packit fc043f
Packit fc043f
#if 0
Packit fc043f
 restart:
Packit fc043f
#endif
Packit fc043f
Packit fc043f
  any = 0;
Packit fc043f
  nwait = 0;
Packit fc043f
  count = 0;
Packit fc043f
  for (i = 0; i < nfds; i++)
Packit fc043f
    {
Packit fc043f
      struct estream_cookie_w32_pollable *pcookie;
Packit fc043f
Packit fc043f
      if (fds[i].ignore)
Packit fc043f
	continue;
Packit fc043f
Packit fc043f
      if (fds[i].stream->intern->kind != BACKEND_W32_POLLABLE)
Packit fc043f
        {
Packit fc043f
          /* This stream does not support polling.  */
Packit fc043f
          fds[i].got_err = 1;
Packit fc043f
          continue;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      pcookie = fds[i].stream->intern->cookie;
Packit fc043f
Packit fc043f
      if (fds[i].want_read || fds[i].want_write)
Packit fc043f
	{
Packit fc043f
          /* XXX: What if one wants read and write, is that supported?  */
Packit fc043f
	  if (fds[i].want_read)
Packit fc043f
	    {
Packit fc043f
	      struct reader_context_s *ctx = pcookie->reader;
Packit fc043f
              if (ctx == NULL)
Packit fc043f
                {
Packit fc043f
                  pcookie->reader = ctx = create_reader (pcookie);
Packit fc043f
                  if (!ctx)
Packit fc043f
                    {
Packit fc043f
                      /* FIXME:  Is the error code appropriate?  */
Packit fc043f
                      _gpg_err_set_errno (EBADF);
Packit fc043f
                      return -1;
Packit fc043f
                    }
Packit fc043f
                  trace (("%p: new reader %p", pcookie, pcookie->reader));
Packit fc043f
                }
Packit fc043f
              trace (("%p: using reader %p", pcookie, pcookie->reader));
Packit fc043f
Packit fc043f
              if (nwait >= DIM (waitbuf))
Packit fc043f
                {
Packit fc043f
                  trace (("oops: too many objects for WFMO"));
Packit fc043f
                  /* FIXME: Should translate the error code.  */
Packit fc043f
                  _gpg_err_set_errno (EIO);
Packit fc043f
                  return -1;
Packit fc043f
                }
Packit fc043f
              waitidx[nwait] = i;
Packit fc043f
#ifdef ENABLE_TRACING
Packit fc043f
              waitinfo[nwait] = 'r';
Packit fc043f
#endif /*ENABLE_TRACING*/
Packit fc043f
              waitbuf[nwait++] = ctx->have_data_ev;
Packit fc043f
	      any = 1;
Packit fc043f
            }
Packit fc043f
	  else if (fds[i].want_write)
Packit fc043f
	    {
Packit fc043f
	      struct writer_context_s *ctx = pcookie->writer;
Packit fc043f
              if (ctx == NULL)
Packit fc043f
                {
Packit fc043f
                  pcookie->writer = ctx = create_writer (pcookie);
Packit fc043f
                  if (!ctx)
Packit fc043f
                    {
Packit fc043f
                      trace (("oops: create writer failed"));
Packit fc043f
                      /* FIXME:  Is the error code appropriate?  */
Packit fc043f
                      _gpg_err_set_errno (EBADF);
Packit fc043f
                      return -1;
Packit fc043f
                    }
Packit fc043f
                  trace (("%p: new writer %p", pcookie, pcookie->writer));
Packit fc043f
                }
Packit fc043f
              trace (("%p: using writer %p", pcookie, pcookie->writer));
Packit fc043f
Packit fc043f
              if (nwait >= DIM (waitbuf))
Packit fc043f
                {
Packit fc043f
                  trace (("oops: Too many objects for WFMO"));
Packit fc043f
                  /* FIXME: Should translate the error code.  */
Packit fc043f
                  _gpg_err_set_errno (EIO);
Packit fc043f
                  return -1;
Packit fc043f
                }
Packit fc043f
              waitidx[nwait] = i;
Packit fc043f
#ifdef ENABLE_TRACING
Packit fc043f
              waitinfo[nwait] = 'w';
Packit fc043f
#endif /*ENABLE_TRACING*/
Packit fc043f
              waitbuf[nwait++] = ctx->is_empty;
Packit fc043f
	      any = 1;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
#ifdef ENABLE_TRACING
Packit fc043f
  trace_start (("poll on [ "));
Packit fc043f
  for (i = 0; i < nwait; i++)
Packit fc043f
    trace_append (("%d/%c ", waitidx[i], waitinfo[i]));
Packit fc043f
  trace_finish (("]"));
Packit fc043f
#endif /*ENABLE_TRACING*/
Packit fc043f
  if (!any)
Packit fc043f
    return 0;
Packit fc043f
Packit fc043f
  code = WaitForMultipleObjects (nwait, waitbuf, 0,
Packit fc043f
                                 timeout == -1 ? INFINITE : timeout);
Packit fc043f
  if (code < WAIT_OBJECT_0 + nwait)
Packit fc043f
    {
Packit fc043f
      /* This WFMO is a really silly function: It does return either
Packit fc043f
	 the index of the signaled object or if 2 objects have been
Packit fc043f
	 signalled at the same time, the index of the object with the
Packit fc043f
	 lowest object is returned - so and how do we find out how
Packit fc043f
	 many objects have been signaled???.  The only solution I can
Packit fc043f
	 imagine is to test each object starting with the returned
Packit fc043f
	 index individually - how dull.  */
Packit fc043f
      any = 0;
Packit fc043f
      for (i = code - WAIT_OBJECT_0; i < nwait; i++)
Packit fc043f
	{
Packit fc043f
	  if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
Packit fc043f
	    {
Packit fc043f
	      assert (waitidx[i] >=0 && waitidx[i] < nfds);
Packit fc043f
              /* XXX: What if one wants read and write, is that
Packit fc043f
                 supported?  */
Packit fc043f
              if (fds[waitidx[i]].want_read)
Packit fc043f
                fds[waitidx[i]].got_read = 1;
Packit fc043f
              else if (fds[waitidx[i]].want_write)
Packit fc043f
                fds[waitidx[i]].got_write = 1;
Packit fc043f
	      any = 1;
Packit fc043f
	      count++;
Packit fc043f
	    }
Packit fc043f
	}
Packit fc043f
      if (!any)
Packit fc043f
	{
Packit fc043f
	  trace (("no signaled objects found after WFMO"));
Packit fc043f
	  count = -1;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
  else if (code == WAIT_TIMEOUT)
Packit fc043f
    trace (("WFMO timed out"));
Packit fc043f
  else if (code == WAIT_FAILED)
Packit fc043f
    {
Packit fc043f
      trace (("WFMO failed: ec=%d", (int)GetLastError ()));
Packit fc043f
#if 0
Packit fc043f
      if (GetLastError () == ERROR_INVALID_HANDLE)
Packit fc043f
	{
Packit fc043f
	  int k;
Packit fc043f
	  int j = handle_to_fd (waitbuf[i]);
Packit fc043f
Packit fc043f
	  trace (("WFMO invalid handle %d removed", j));
Packit fc043f
	  for (k = 0 ; k < nfds; k++)
Packit fc043f
	    {
Packit fc043f
	      if (fds[k].fd == j)
Packit fc043f
		{
Packit fc043f
		  fds[k].want_read = fds[k].want_write = 0;
Packit fc043f
		  goto restart;
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
	  trace ((" oops, or not???"));
Packit fc043f
        }
Packit fc043f
#endif
Packit fc043f
      count = -1;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      trace (("WFMO returned %u", code));
Packit fc043f
      count = -1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (count > 0)
Packit fc043f
    {
Packit fc043f
      trace_start (("poll OK [ "));
Packit fc043f
      for (i = 0; i < nfds; i++)
Packit fc043f
	{
Packit fc043f
	  if (fds[i].ignore)
Packit fc043f
	    continue;
Packit fc043f
	  if (fds[i].got_read || fds[i].got_write)
Packit fc043f
	    trace_append (("%c%d ", fds[i].want_read ? 'r' : 'w', i));
Packit fc043f
        }
Packit fc043f
      trace_finish (("]"));
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (count < 0)
Packit fc043f
    {
Packit fc043f
      /* FIXME: Should determine a proper error code.  */
Packit fc043f
      _gpg_err_set_errno (EIO);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return count;
Packit fc043f
}
Packit fc043f
Packit fc043f

Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Implementation of pollable I/O on Windows.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Constructor for pollable objects.
Packit fc043f
 */
Packit fc043f
int
Packit fc043f
_gpgrt_w32_pollable_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie,
Packit fc043f
                            unsigned int modeflags,
Packit fc043f
                            struct cookie_io_functions_s next_functions,
Packit fc043f
                            void *next_cookie)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie;
Packit fc043f
  int err;
Packit fc043f
Packit fc043f
  pcookie = _gpgrt_malloc (sizeof *pcookie);
Packit fc043f
  if (!pcookie)
Packit fc043f
    err = -1;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      pcookie->modeflags = modeflags;
Packit fc043f
      pcookie->next_functions = next_functions;
Packit fc043f
      pcookie->next_cookie = next_cookie;
Packit fc043f
      pcookie->reader = NULL;
Packit fc043f
      pcookie->writer = NULL;
Packit fc043f
      *cookie = pcookie;
Packit fc043f
      err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  trace_errno (err,("cookie=%p", *cookie));
Packit fc043f
  return err;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Seek function for pollable objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_w32_pollable_seek (void *cookie, gpgrt_off_t *offset, int whence)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie = cookie;
Packit fc043f
  (void) pcookie;
Packit fc043f
  (void) offset;
Packit fc043f
  (void) whence;
Packit fc043f
  /* XXX */
Packit fc043f
  _gpg_err_set_errno (EOPNOTSUPP);
Packit fc043f
  return -1;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The IOCTL function for pollable objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_w32_pollable_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie = cookie;
Packit fc043f
  cookie_ioctl_function_t func_ioctl = pcookie->next_functions.func_ioctl;
Packit fc043f
Packit fc043f
  if (cmd == COOKIE_IOCTL_NONBLOCK)
Packit fc043f
    {
Packit fc043f
      if (ptr)
Packit fc043f
        pcookie->modeflags |= O_NONBLOCK;
Packit fc043f
      else
Packit fc043f
        pcookie->modeflags &= ~O_NONBLOCK;
Packit fc043f
      return 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (func_ioctl)
Packit fc043f
    return func_ioctl (pcookie->next_cookie, cmd, ptr, len);
Packit fc043f
Packit fc043f
  _gpg_err_set_errno (EOPNOTSUPP);
Packit fc043f
  return -1;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * The destroy function for pollable objects.
Packit fc043f
 */
Packit fc043f
static int
Packit fc043f
func_w32_pollable_destroy (void *cookie)
Packit fc043f
{
Packit fc043f
  estream_cookie_w32_pollable_t pcookie = cookie;
Packit fc043f
Packit fc043f
  if (cookie)
Packit fc043f
    {
Packit fc043f
      if (pcookie->reader)
Packit fc043f
        destroy_reader (pcookie->reader);
Packit fc043f
      if (pcookie->writer)
Packit fc043f
        destroy_writer (pcookie->writer);
Packit fc043f
      pcookie->next_functions.public.func_close (pcookie->next_cookie);
Packit fc043f
      _gpgrt_free (pcookie);
Packit fc043f
    }
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
/*
Packit fc043f
 * Access object for the pollable functions.
Packit fc043f
 */
Packit fc043f
struct cookie_io_functions_s _gpgrt_functions_w32_pollable =
Packit fc043f
  {
Packit fc043f
    {
Packit fc043f
      func_w32_pollable_read,
Packit fc043f
      func_w32_pollable_write,
Packit fc043f
      func_w32_pollable_seek,
Packit fc043f
      func_w32_pollable_destroy,
Packit fc043f
    },
Packit fc043f
    func_w32_pollable_ioctl,
Packit fc043f
  };