2005-09-12 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / wait.c
index daf009b..16a9f23 100644 (file)
@@ -1,22 +1,23 @@
 /* wait.c 
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
  
    This file is part of GPGME.
  
    GPGME is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+   
    GPGME is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-   You should have received a copy of the GNU General Public License
-   along with GPGME; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Lesser General Public License for more details.
+   
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #if HAVE_CONFIG_H
 #include <config.h>
@@ -32,8 +33,9 @@
 #include "ops.h"
 #include "wait.h"
 #include "sema.h"
-#include "io.h"
+#include "priv-io.h"
 #include "engine.h"
+#include "debug.h"
 
 \f
 void
@@ -52,10 +54,10 @@ _gpgme_fd_table_deinit (fd_table_t fdt)
 
 
 /* XXX We should keep a marker and roll over for speed.  */
-static GpgmeError
+static gpgme_error_t
 fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
 {
-  int i, j;
+  unsigned int i, j;
   struct io_select_fd_s *new_fds;
 
   for (i = 0; i < fdt->size; i++)
@@ -69,7 +71,7 @@ fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
       new_fds = realloc (fdt->fds, (fdt->size + FDT_ALLOCSIZE)
                         * sizeof (*new_fds));
       if (!new_fds)
-       return mk_error (Out_Of_Core);
+       return gpg_error_from_errno (errno);
       
       fdt->fds = new_fds;
       fdt->size += FDT_ALLOCSIZE;
@@ -92,12 +94,12 @@ fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
    FNC_DATA as its first argument) for the direction DIR.  DATA should
    be the context for which the fd is added.  R_TAG will hold the tag
    that can be used to remove the fd.  */
-GpgmeError
-_gpgme_add_io_cb (void *data, int fd, int dir, GpgmeIOCb fnc, void *fnc_data,
-                 void **r_tag)
+gpgme_error_t
+_gpgme_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc,
+                 void *fnc_data, void **r_tag)
 {
-  GpgmeError err;
-  GpgmeCtx ctx = (GpgmeCtx) data;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx = (gpgme_ctx_t) data;
   fd_table_t fdt;
   struct wait_item_s *item;
   struct tag *tag;
@@ -110,15 +112,16 @@ _gpgme_add_io_cb (void *data, int fd, int dir, GpgmeIOCb fnc, void *fnc_data,
 
   tag = malloc (sizeof *tag);
   if (!tag)
-    return mk_error (Out_Of_Core);
+    return gpg_error_from_errno (errno);
   tag->ctx = ctx;
 
   /* Allocate a structure to hold information about the handler.  */
   item = calloc (1, sizeof *item);
   if (!item)
     {
+      int saved_errno = errno;
       free (tag);
-      return mk_error (Out_Of_Core);
+      return gpg_error_from_errno (saved_errno);
     }
   item->ctx = ctx;
   item->dir = dir;
@@ -142,7 +145,7 @@ void
 _gpgme_remove_io_cb (void *data)
 {
   struct tag *tag = data;
-  GpgmeCtx ctx;
+  gpgme_ctx_t ctx;
   fd_table_t fdt;
   int idx;
 
@@ -164,3 +167,38 @@ _gpgme_remove_io_cb (void *data)
   fdt->fds[idx].for_write = 0;
   fdt->fds[idx].opaque = NULL;
 }
+
+\f
+/* This is slightly embarrassing.  The problem is that running an I/O
+   callback _may_ influence the status of other file descriptors.  Our
+   own event loops could compensate for that, but the external event
+   loops cannot.  FIXME: We may still want to optimize this a bit when
+   we are called from our own event loops.  So if CHECKED is 1, the
+   check is skipped.  */
+gpgme_error_t
+_gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked)
+{
+  struct wait_item_s *item;
+  item = (struct wait_item_s *) an_fds->opaque;
+  assert (item);
+
+  if (!checked)
+    {
+      int nr;
+      struct io_select_fd_s fds;
+
+      fds = *an_fds;
+      fds.signaled = 0;
+      /* Just give it a quick poll.  */
+      nr = _gpgme_io_select (&fds, 1, 1);
+      assert (nr <= 1);
+      if (nr < 0)
+       return errno;
+      else if (nr == 0)
+       /* The status changed in the meantime, there is nothing left
+          to do.  */
+       return 0;
+    }
+
+  return item->handler (item->handler_value, an_fds->fd);
+}