diff options
| -rw-r--r-- | bus/expirelist.c | 302 | ||||
| -rw-r--r-- | bus/expirelist.h | 70 | 
2 files changed, 372 insertions, 0 deletions
diff --git a/bus/expirelist.c b/bus/expirelist.c new file mode 100644 index 00000000..f732ebd1 --- /dev/null +++ b/bus/expirelist.c @@ -0,0 +1,302 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* expirelist.c  List of items that expire + * + * Copyright (C) 2003  Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#include "expirelist.h" +#include "test.h" +#include <dbus/dbus-internals.h> +#include <dbus/dbus-mainloop.h> +#include <dbus/dbus-timeout.h> + +static dbus_bool_t expire_timeout_handler (void *data); + +static void +call_timeout_callback (DBusTimeout   *timeout, +                       void          *data) +{ +  /* can return FALSE on OOM but we just let it fire again later */ +  dbus_timeout_handle (timeout); +} + +BusExpireList* +bus_expire_list_new (DBusLoop      *loop, +                     int            expire_after, +                     BusExpireFunc  expire_func, +                     void          *data) +{ +  BusExpireList *list; + +  list = dbus_new0 (BusExpireList, 1); +  if (list == NULL) +    return NULL; + +  list->expire_func = expire_func; +  list->data = data; +  list->loop = loop; +  list->expire_after = expire_after; + +  list->timeout = _dbus_timeout_new (100, /* irrelevant */ +                                     expire_timeout_handler, +                                     list, NULL); +  if (list->timeout == NULL) +    goto failed; + +  _dbus_timeout_set_enabled (list->timeout, FALSE); + +  if (!_dbus_loop_add_timeout (list->loop, +                               list->timeout, +                               call_timeout_callback, NULL, NULL)) +    goto failed; + +  return list; + + failed: +  if (list->timeout) +    _dbus_timeout_unref (list->timeout); + +  dbus_free (list); + +  return NULL; +} + +void +bus_expire_list_free (BusExpireList *list) +{ +  _dbus_assert (list->n_items == 0); +  _dbus_assert (list->items == NULL); + +  _dbus_loop_remove_timeout (list->loop, list->timeout, +                             call_timeout_callback, NULL); + +  _dbus_timeout_unref (list->timeout); + +  dbus_free (list); +} + +void +bus_expire_timeout_set_interval (DBusTimeout *timeout, +                                 int          next_interval) +{ +  if (next_interval >= 0) +    { +      _dbus_timeout_set_interval (timeout, +                                  next_interval); +      _dbus_timeout_set_enabled (timeout, TRUE); + +      _dbus_verbose ("Enabled expire timeout with interval %d\n", +                     next_interval); +    } +  else if (dbus_timeout_get_enabled (timeout)) +    { +      _dbus_timeout_set_enabled (timeout, FALSE); + +      _dbus_verbose ("Disabled expire timeout\n"); +    } +  else +    _dbus_verbose ("No need to disable expire timeout\n"); +} + +static int +do_expiration_with_current_time (BusExpireList *list, +                                 long           tv_sec, +                                 long           tv_usec) +{ +  DBusList *link; +  int next_interval; + +  next_interval = -1; +   +  link = _dbus_list_get_first_link (&list->items); +  while (link != NULL) +    { +      DBusList *next = _dbus_list_get_next_link (&list->items, link); +      double elapsed; +      BusExpireItem *item; + +      item = link->data; + +      elapsed = ELAPSED_MILLISECONDS_SINCE (item->added_tv_sec, +                                            item->added_tv_usec, +                                            tv_sec, tv_usec); + +      if (elapsed >= (double) list->expire_after) +        { +          _dbus_verbose ("Expiring an item %p\n", item); +          (* list->expire_func) (list, item, list->data); +        } +      else +        { +          /* We can end the loop, since the connections are in oldest-first order */ +          next_interval = ((double)list->expire_after) - elapsed; +          _dbus_verbose ("Item %p expires in %d milliseconds\n", +                         item, next_interval); + +          break; +        } + +      link = next; +    } + +  return next_interval; +} + +static void +bus_expirelist_expire (BusExpireList *list) +{ +  int next_interval; + +  next_interval = -1; + +  if (list->items != NULL) +    { +      long tv_sec, tv_usec; + +      _dbus_get_current_time (&tv_sec, &tv_usec); + +      next_interval = do_expiration_with_current_time (list, tv_sec, tv_usec); +    } + +  bus_expire_timeout_set_interval (list->timeout, next_interval); +} + +static dbus_bool_t +expire_timeout_handler (void *data) +{ +  BusExpireList *list = data; + +  _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME); + +  /* note that this may remove the timeout */ +  bus_expirelist_expire (list); + +  return TRUE; +} + +#ifdef DBUS_BUILD_TESTS + +typedef struct +{ +  BusExpireItem item; +  int expire_count; +} TestExpireItem; + +static void +test_expire_func (BusExpireList *list, +                  BusExpireItem *item, +                  void          *data) +{ +  TestExpireItem *t; + +  t = (TestExpireItem*) item; + +  t->expire_count += 1; +} + +static void +time_add_milliseconds (long *tv_sec, +                       long *tv_usec, +                       int   milliseconds) +{ +  *tv_sec = *tv_sec + milliseconds / 1000; +  *tv_usec = *tv_usec + milliseconds * 1000; +  if (*tv_usec >= 1000000) +    { +      *tv_usec -= 1000000; +      *tv_sec += 1; +    } +} + +dbus_bool_t +bus_expire_list_test (const DBusString *test_data_dir) +{ +  DBusLoop *loop; +  BusExpireList *list; +  long tv_sec, tv_usec; +  long tv_sec_not_expired, tv_usec_not_expired; +  long tv_sec_expired, tv_usec_expired; +  long tv_sec_past, tv_usec_past; +  TestExpireItem *item; +  int next_interval; +   +  loop = _dbus_loop_new (); +  _dbus_assert (loop != NULL); + +#define EXPIRE_AFTER 100 +   +  list = bus_expire_list_new (loop, EXPIRE_AFTER, +                              test_expire_func, NULL); +  _dbus_assert (list != NULL); + +  _dbus_get_current_time (&tv_sec, &tv_usec); + +  tv_sec_not_expired = tv_sec; +  tv_usec_not_expired = tv_usec; +  time_add_milliseconds (&tv_sec_not_expired, +                         &tv_usec_not_expired, EXPIRE_AFTER - 1); + +  tv_sec_expired = tv_sec; +  tv_usec_expired = tv_usec; +  time_add_milliseconds (&tv_sec_expired, +                         &tv_usec_expired, EXPIRE_AFTER); +   + +  tv_sec_past = tv_sec - 1; +  tv_usec_past = tv_usec; + +  item = dbus_new0 (TestExpireItem, 1); + +  item->item.added_tv_sec = tv_sec; +  item->item.added_tv_usec = tv_usec; +  if (!_dbus_list_append (&list->items, item)) +    _dbus_assert_not_reached ("out of memory"); + +  next_interval = +    do_expiration_with_current_time (list, tv_sec_not_expired, +                                     tv_usec_not_expired); +  _dbus_assert (item->expire_count == 0); +  _dbus_verbose ("next_interval = %d\n", next_interval); +  _dbus_assert (next_interval == 1); +   +  next_interval = +    do_expiration_with_current_time (list, tv_sec_expired, +                                     tv_usec_expired); +  _dbus_assert (item->expire_count == 1); +  _dbus_verbose ("next_interval = %d\n", next_interval); +  _dbus_assert (next_interval == -1); + +  next_interval = +    do_expiration_with_current_time (list, tv_sec_past, +                                     tv_usec_past); +  _dbus_assert (item->expire_count == 1); +  _dbus_verbose ("next_interval = %d\n", next_interval); +  _dbus_assert (next_interval == 1000 + EXPIRE_AFTER); + +  _dbus_list_clear (&list->items); +  dbus_free (item); +   +  bus_expire_list_free (list); +  _dbus_loop_unref (loop); +   +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/bus/expirelist.h b/bus/expirelist.h new file mode 100644 index 00000000..2e7752fc --- /dev/null +++ b/bus/expirelist.h @@ -0,0 +1,70 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* expirelist.h  List of stuff that expires + * + * Copyright (C) 2003  Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#ifndef BUS_EXPIRE_LIST_H +#define BUS_EXPIRE_LIST_H + +#include <dbus/dbus.h> +#include <dbus/dbus-list.h> +#include <dbus/dbus-mainloop.h> + +typedef struct BusExpireList BusExpireList; +typedef struct BusExpireItem BusExpireItem; + +typedef void (* BusExpireFunc) (BusExpireList *list, +                                BusExpireItem *item, +                                void          *data); + +struct BusExpireList +{ +  DBusList      *items; /**< List of BusExpireItem */ +  int            n_items; +  DBusTimeout   *timeout; +  DBusLoop      *loop; +  BusExpireFunc  expire_func; +  void          *data; +  int            expire_after; /**< Expire after milliseconds (thousandths) */ +}; + +/* embed this in a child expire item struct */ +struct BusExpireItem +{ +  long added_tv_sec;  /**< Time we were added (seconds component) */ +  long added_tv_usec; /**< Time we were added (microsec component) */ +}; + +BusExpireList* bus_expire_list_new    (DBusLoop      *loop, +                                       int            expire_after, +                                       BusExpireFunc  expire_func, +                                       void          *data); +void           bus_expire_list_free   (BusExpireList *list); + +#define ELAPSED_MILLISECONDS_SINCE(orig_tv_sec, orig_tv_usec,   \ +                                   now_tv_sec, now_tv_usec)     \ + (((double) (now_tv_sec) - (double) (orig_tv_sec)) * 1000.0 +   \ + ((double) (now_tv_usec) - (double) (orig_tv_usec)) / 1000.0) + +void bus_expire_timeout_set_interval (DBusTimeout *timeout, +                                      int          next_interval); + +#endif /* BUS_EXPIRE_LIST_H */  | 
