Changed the close notify implementaion to allow for more than 256 fds.

We should write a test case for it, though.
This commit is contained in:
Werner Koch 2010-02-17 21:40:02 +00:00
parent 2281024d4c
commit 01ad3b7562
2 changed files with 81 additions and 21 deletions

View File

@ -1,3 +1,10 @@
2010-02-17 Werner Koch <wk@g10code.com>
* posix-io.c (notify_table): Change implementation.
(notify_table_item_t, notify_table_size, notify_table_lock): New.
(_gpgme_io_close, _gpgme_io_set_close_notify): Adjust for new
implementation.
2010-02-16 Werner Koch <wk@g10code.com> 2010-02-16 Werner Koch <wk@g10code.com>
* gpgme-tool.c (spacep, has_option, skip_options): New. * gpgme-tool.c (spacep, has_option, skip_options): New.

View File

@ -1,6 +1,6 @@
/* posix-io.c - Posix I/O functions /* posix-io.c - Posix I/O functions
Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2004, 2005, 2007 g10 Code GmbH Copyright (C) 2001, 2002, 2004, 2005, 2007, 2010 g10 Code GmbH
This file is part of GPGME. This file is part of GPGME.
@ -15,9 +15,8 @@
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software License along with this program; if not, see <http://www.gnu.org/licenses/>.
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA */
02111-1307, USA. */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
@ -73,13 +72,22 @@ _gpgme_io_fd2str (char *buf, int buflen, int fd)
} }
static struct /* The table to hold notification handlers. We use a linear search
and extend the table as needed. */
struct notify_table_item_s
{ {
int fd; /* -1 indicates an unused entry. */
_gpgme_close_notify_handler_t handler; _gpgme_close_notify_handler_t handler;
void *value; void *value;
} notify_table[256]; };
typedef struct notify_table_item_s *notify_table_item_t;
static notify_table_item_t notify_table;
static size_t notify_table_size;
DEFINE_STATIC_LOCK (notify_table_lock);
int int
_gpgme_io_read (int fd, void *buffer, size_t count) _gpgme_io_read (int fd, void *buffer, size_t count)
{ {
@ -149,6 +157,9 @@ int
_gpgme_io_close (int fd) _gpgme_io_close (int fd)
{ {
int res; int res;
_gpgme_close_notify_handler_t handler = NULL;
void *handler_value;
int idx;
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd); TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
@ -159,17 +170,26 @@ _gpgme_io_close (int fd)
} }
/* First call the notify handler. */ /* First call the notify handler. */
if (fd >= 0 && fd < (int) DIM (notify_table)) LOCK (notify_table_lock);
for (idx=0; idx < notify_table_size; idx++)
{ {
if (notify_table[fd].handler) if (notify_table[idx].fd == fd)
{ {
TRACE_LOG2 ("invoking close handler %p/%p", handler = notify_table[idx].handler;
notify_table[fd].handler, notify_table[fd].value); handler_value = notify_table[idx].value;
notify_table[fd].handler (fd, notify_table[fd].value); notify_table[idx].handler = NULL;
notify_table[fd].handler = NULL; notify_table[idx].value = NULL;
notify_table[fd].value = NULL; notify_table[idx].fd = -1; /* Mark slot as free. */
break;
} }
} }
UNLOCK (notify_table_lock);
if (handler)
{
TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
handler (fd, handler_value);
}
/* Then do the close. */ /* Then do the close. */
res = close (fd); res = close (fd);
return TRACE_SYSRES (res); return TRACE_SYSRES (res);
@ -180,19 +200,52 @@ int
_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler, _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
void *value) void *value)
{ {
int res = 0;
int idx;
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
"close_handler=%p/%p", handler, value); "close_handler=%p/%p", handler, value);
assert (fd != -1); assert (fd != -1);
if (fd < 0 || fd >= (int) DIM (notify_table)) LOCK (notify_table_lock);
for (idx=0; idx < notify_table_size; idx++)
if (notify_table[idx].fd == -1)
break;
if (idx == notify_table_size)
{ {
errno = EINVAL; /* We need to increase the size of the table. The approach we
return TRACE_SYSRES (-1); take is straightforward to minimize the risk of bugs. */
notify_table_item_t newtbl;
size_t newsize = notify_table_size + 64;
newtbl = calloc (newsize, sizeof *newtbl);
if (!newtbl)
{
res = -1;
goto leave;
}
for (idx=0; idx < notify_table_size; idx++)
newtbl[idx] = notify_table[idx];
for (; idx < newsize; idx++)
{
newtbl[idx].fd = -1;
newtbl[idx].handler = NULL;
newtbl[idx].value = NULL;
}
free (notify_table);
notify_table = newtbl;
idx = notify_table_size;
notify_table_size = newsize;
} }
notify_table[fd].handler = handler; notify_table[idx].fd = fd;
notify_table[fd].value = value; notify_table[idx].handler = handler;
return TRACE_SYSRES (0); notify_table[idx].value = value;
leave:
UNLOCK (notify_table_lock);
return TRACE_SYSRES (res);
} }