Blame src/wait.c

Packit d7e8d0
/* wait.c
Packit d7e8d0
   Copyright (C) 2000 Werner Koch (dd9jn)
Packit d7e8d0
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
Packit d7e8d0
Packit d7e8d0
   This file is part of GPGME.
Packit d7e8d0
Packit d7e8d0
   GPGME is free software; you can redistribute it and/or modify it
Packit d7e8d0
   under the terms of the GNU Lesser General Public License as
Packit d7e8d0
   published by the Free Software Foundation; either version 2.1 of
Packit d7e8d0
   the License, or (at your option) any later version.
Packit d7e8d0
Packit d7e8d0
   GPGME is distributed in the hope that it will be useful, but
Packit d7e8d0
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d7e8d0
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit d7e8d0
   Lesser General Public License for more details.
Packit d7e8d0
Packit d7e8d0
   You should have received a copy of the GNU Lesser General Public
Packit d7e8d0
   License along with this program; if not, write to the Free Software
Packit d7e8d0
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit d7e8d0
   02111-1307, USA.  */
Packit d7e8d0
Packit d7e8d0
#if HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#include <string.h>
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
#ifdef HAVE_SYS_TYPES_H
Packit d7e8d0
# include <sys/types.h>
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
#include "util.h"
Packit d7e8d0
#include "context.h"
Packit d7e8d0
#include "ops.h"
Packit d7e8d0
#include "wait.h"
Packit d7e8d0
#include "sema.h"
Packit d7e8d0
#include "priv-io.h"
Packit d7e8d0
#include "engine.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
void
Packit d7e8d0
_gpgme_fd_table_init (fd_table_t fdt)
Packit d7e8d0
{
Packit d7e8d0
  fdt->fds = NULL;
Packit d7e8d0
  fdt->size = 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
_gpgme_fd_table_deinit (fd_table_t fdt)
Packit d7e8d0
{
Packit d7e8d0
  if (fdt->fds)
Packit d7e8d0
    free (fdt->fds);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* XXX We should keep a marker and roll over for speed.  */
Packit d7e8d0
static gpgme_error_t
Packit d7e8d0
fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
Packit d7e8d0
{
Packit d7e8d0
  unsigned int i, j;
Packit d7e8d0
  struct io_select_fd_s *new_fds;
Packit d7e8d0
Packit d7e8d0
  for (i = 0; i < fdt->size; i++)
Packit d7e8d0
    {
Packit d7e8d0
      if (fdt->fds[i].fd == -1)
Packit d7e8d0
	break;
Packit d7e8d0
    }
Packit d7e8d0
  if (i == fdt->size)
Packit d7e8d0
    {
Packit d7e8d0
#define FDT_ALLOCSIZE 10
Packit d7e8d0
      new_fds = realloc (fdt->fds, (fdt->size + FDT_ALLOCSIZE)
Packit d7e8d0
			 * sizeof (*new_fds));
Packit d7e8d0
      if (!new_fds)
Packit d7e8d0
	return gpg_error_from_syserror ();
Packit d7e8d0
Packit d7e8d0
      fdt->fds = new_fds;
Packit d7e8d0
      fdt->size += FDT_ALLOCSIZE;
Packit d7e8d0
      for (j = 0; j < FDT_ALLOCSIZE; j++)
Packit d7e8d0
	fdt->fds[i + j].fd = -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  fdt->fds[i].fd = fd;
Packit d7e8d0
  fdt->fds[i].for_read = (dir == 1);
Packit d7e8d0
  fdt->fds[i].for_write = (dir == 0);
Packit d7e8d0
  fdt->fds[i].signaled = 0;
Packit d7e8d0
  fdt->fds[i].opaque = opaque;
Packit d7e8d0
  *idx = i;
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Register the file descriptor FD with the handler FNC (which gets
Packit d7e8d0
   FNC_DATA as its first argument) for the direction DIR.  DATA should
Packit d7e8d0
   be the context for which the fd is added.  R_TAG will hold the tag
Packit d7e8d0
   that can be used to remove the fd.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc,
Packit d7e8d0
		  void *fnc_data, void **r_tag)
Packit d7e8d0
{
Packit d7e8d0
  gpgme_error_t err;
Packit d7e8d0
  gpgme_ctx_t ctx = (gpgme_ctx_t) data;
Packit d7e8d0
  fd_table_t fdt;
Packit d7e8d0
  struct wait_item_s *item;
Packit d7e8d0
  struct tag *tag;
Packit d7e8d0
Packit d7e8d0
  assert (fnc);
Packit d7e8d0
  assert (ctx);
Packit d7e8d0
Packit d7e8d0
  fdt = &ctx->fdt;
Packit d7e8d0
  assert (fdt);
Packit d7e8d0
Packit d7e8d0
  tag = malloc (sizeof *tag);
Packit d7e8d0
  if (!tag)
Packit d7e8d0
    return gpg_error_from_syserror ();
Packit d7e8d0
  tag->ctx = ctx;
Packit d7e8d0
Packit d7e8d0
  /* Allocate a structure to hold information about the handler.  */
Packit d7e8d0
  item = calloc (1, sizeof *item);
Packit d7e8d0
  if (!item)
Packit d7e8d0
    {
Packit d7e8d0
      free (tag);
Packit d7e8d0
      return gpg_error_from_syserror ();
Packit d7e8d0
    }
Packit d7e8d0
  item->ctx = ctx;
Packit d7e8d0
  item->dir = dir;
Packit d7e8d0
  item->handler = fnc;
Packit d7e8d0
  item->handler_value = fnc_data;
Packit d7e8d0
Packit d7e8d0
  err = fd_table_put (fdt, fd, dir, item, &tag->idx);
Packit d7e8d0
  if (err)
Packit d7e8d0
    {
Packit d7e8d0
      free (tag);
Packit d7e8d0
      free (item);
Packit d7e8d0
      return err;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  TRACE3 (DEBUG_CTX, "_gpgme_add_io_cb", ctx,
Packit d7e8d0
	  "fd %d, dir=%d -> tag=%p", fd, dir, tag);
Packit d7e8d0
Packit d7e8d0
  *r_tag = tag;
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
_gpgme_remove_io_cb (void *data)
Packit d7e8d0
{
Packit d7e8d0
  struct tag *tag = data;
Packit d7e8d0
  gpgme_ctx_t ctx;
Packit d7e8d0
  fd_table_t fdt;
Packit d7e8d0
  int idx;
Packit d7e8d0
Packit d7e8d0
  assert (tag);
Packit d7e8d0
  ctx = tag->ctx;
Packit d7e8d0
  assert (ctx);
Packit d7e8d0
  fdt = &ctx->fdt;
Packit d7e8d0
  assert (fdt);
Packit d7e8d0
  idx = tag->idx;
Packit d7e8d0
Packit d7e8d0
  TRACE2 (DEBUG_CTX, "_gpgme_remove_io_cb", data,
Packit d7e8d0
	  "setting fd 0x%x (item=%p) done", fdt->fds[idx].fd,
Packit d7e8d0
	  fdt->fds[idx].opaque);
Packit d7e8d0
Packit d7e8d0
  free (fdt->fds[idx].opaque);
Packit d7e8d0
  free (tag);
Packit d7e8d0
Packit d7e8d0
  /* Free the table entry.  */
Packit d7e8d0
  fdt->fds[idx].fd = -1;
Packit d7e8d0
  fdt->fds[idx].for_read = 0;
Packit d7e8d0
  fdt->fds[idx].for_write = 0;
Packit d7e8d0
  fdt->fds[idx].opaque = NULL;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* This is slightly embarrassing.  The problem is that running an I/O
Packit d7e8d0
   callback _may_ influence the status of other file descriptors.  Our
Packit d7e8d0
   own event loops could compensate for that, but the external event
Packit d7e8d0
   loops cannot.  FIXME: We may still want to optimize this a bit when
Packit d7e8d0
   we are called from our own event loops.  So if CHECKED is 1, the
Packit d7e8d0
   check is skipped.  */
Packit d7e8d0
gpgme_error_t
Packit d7e8d0
_gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked,
Packit d7e8d0
		  gpgme_error_t *op_err)
Packit d7e8d0
{
Packit d7e8d0
  struct wait_item_s *item;
Packit d7e8d0
  struct io_cb_data iocb_data;
Packit d7e8d0
  gpgme_error_t err;
Packit d7e8d0
Packit d7e8d0
  item = (struct wait_item_s *) an_fds->opaque;
Packit d7e8d0
  assert (item);
Packit d7e8d0
Packit d7e8d0
  if (!checked)
Packit d7e8d0
    {
Packit d7e8d0
      int nr;
Packit d7e8d0
      struct io_select_fd_s fds;
Packit d7e8d0
Packit d7e8d0
      TRACE0 (DEBUG_CTX, "_gpgme_run_io_cb", item, "need to check");
Packit d7e8d0
      fds = *an_fds;
Packit d7e8d0
      fds.signaled = 0;
Packit d7e8d0
      /* Just give it a quick poll.  */
Packit d7e8d0
      nr = _gpgme_io_select (&fds, 1, 1);
Packit d7e8d0
      assert (nr <= 1);
Packit d7e8d0
      if (nr < 0)
Packit d7e8d0
	return errno;
Packit d7e8d0
      else if (nr == 0)
Packit d7e8d0
	/* The status changed in the meantime, there is nothing left
Packit d7e8d0
	   to do.  */
Packit d7e8d0
	return 0;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  TRACE2 (DEBUG_CTX, "_gpgme_run_io_cb", item, "handler (%p, %d)",
Packit d7e8d0
          item->handler_value, an_fds->fd);
Packit d7e8d0
Packit d7e8d0
  iocb_data.handler_value = item->handler_value;
Packit d7e8d0
  iocb_data.op_err = 0;
Packit d7e8d0
  err = item->handler (&iocb_data, an_fds->fd);
Packit d7e8d0
Packit d7e8d0
  *op_err = iocb_data.op_err;
Packit d7e8d0
  return err;
Packit d7e8d0
}