Changeset 1895c29


Ignore:
Timestamp:
Dec 17, 2008, 5:13:20 PM (15 years ago)
Author:
Nelson Elhage <nelhage@mit.edu>
Branches:
master, debian, release-1.10, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
Children:
cf0cc64
Parents:
f36cd97
git-author:
Nelson Elhage <nelhage@mit.edu> (12/17/08 16:58:41)
git-committer:
Nelson Elhage <nelhage@mit.edu> (12/17/08 17:13:20)
Message:
Fix owl_select_remove_dispatch bugs.

Fix two bugs in owl_select_remove_dispatch:

(1) Removing a dispatch from that dispatch's callback was bad, because
    it mutated the dispatch list while it was being traversed. Fix
    that by noting if we're in the middle of a dispatch, and deferring
    cleanup until later.
(2) Calling owl_free on dispatches in select.c is a strange API, since
    it doesn't allocate them in the first place. Since we now have
    destructors, make freeing the dispatch their job.
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • owl.h

    rf36cd97 r1895c29  
    527527typedef struct _owl_dispatch {
    528528  int fd;                                 /* FD to watch for dispatch. */
     529  int needs_gc;
    529530  void (*cfunc)(struct _owl_dispatch*);   /* C function to dispatch to. */
    530531  void (*destroy)(struct _owl_dispatch*); /* Destructor */
  • perlconfig.c

    rf36cd97 r1895c29  
    447447{
    448448  SvREFCNT_dec(d->data);
     449  owl_free(d);
    449450}
    450451
  • select.c

    rf36cd97 r1895c29  
    22
    33static const char fileIdent[] = "$Id: select.c 894 2008-01-17 07:13:44Z asedeno $";
     4
     5static int dispatch_active = 0;
    46
    57int _owl_select_timer_cmp(owl_timer *t1, owl_timer *t2) {
     
    9698}
    9799
     100void owl_select_remove_dispatch_at(int elt) /* noproto */
     101{
     102  owl_list *dl;
     103  owl_dispatch *d;
     104
     105  dl = owl_global_get_dispatchlist(&g);
     106  d = (owl_dispatch*)owl_list_get_element(dl, elt);
     107  owl_list_remove_element(dl, elt);
     108  if (d->destroy) {
     109    d->destroy(d);
     110  }
     111}
     112
    98113/* Adds a new owl_dispatch to the list, replacing existing ones if needed. */
    99114void owl_select_add_dispatch(owl_dispatch *d)
     
    101116  int elt;
    102117  owl_list *dl;
     118
     119  d->needs_gc = 0;
    103120
    104121  elt = owl_select_find_dispatch(d->fd);
     
    111128       replace the old dispatch. */
    112129    if (d_old != d) {
    113       owl_list_replace_element(dl, elt, d);
    114       owl_free(d_old);
    115     }
    116   }
    117   else {
    118     owl_list_append_element(dl, d);
    119   }
     130      owl_select_remove_dispatch_at(elt);
     131    }
     132  }
     133  owl_list_append_element(dl, d);
    120134}
    121135
     
    125139  int elt;
    126140  owl_list *dl;
     141  owl_dispatch *d;
    127142
    128143  elt = owl_select_find_dispatch(fd);
    129   dl = owl_global_get_dispatchlist(&g);
    130  
    131   if (elt != -1) {
    132     owl_dispatch *d;
     144  if(elt == -1) {
     145    return;
     146  } else if(dispatch_active) {
     147    /* Defer the removal until dispatch is done walking the list */
     148    dl = owl_global_get_dispatchlist(&g);
    133149    d = (owl_dispatch*)owl_list_get_element(dl, elt);
    134     owl_list_remove_element(dl, elt);
    135     if (d->destroy) {
    136       d->destroy(d);
    137     }
    138     owl_free(d);
     150    d->needs_gc = 1;
     151  } else {
     152    owl_select_remove_dispatch_at(elt);
    139153  }
    140154}
     
    176190    d = (owl_dispatch*)owl_list_get_element(owl_global_get_dispatchlist(&g), elt);
    177191    if (d->cfunc == owl_perlconfig_dispatch) {
    178       owl_select_remove_dispatch(fd);
     192      owl_select_remove_dispatch_at(elt);
    179193      return 0;
    180194    }
     
    203217}
    204218
     219void owl_select_gc()
     220{
     221  int i;
     222  owl_list *dl;
     223
     224  dl = owl_global_get_dispatchlist(&g);
     225  /*
     226   * Count down so we aren't set off by removing items from the list
     227   * during the iteration.
     228   */
     229  for(i = owl_list_get_size(dl) - 1; i >= 0; i--) {
     230    owl_dispatch *d = owl_list_get_element(dl, i);
     231    if(d->needs_gc) {
     232      owl_select_remove_dispatch_at(i);
     233    }
     234  }
     235}
     236
    205237void owl_select_dispatch(fd_set *fds, int max_fd)
    206238{
     
    211243  dl = owl_global_get_dispatchlist(&g);
    212244  len = owl_select_dispatch_count();
     245
     246  dispatch_active = 1;
     247
    213248  for(i = 0; i < len; i++) {
    214249    d = (owl_dispatch*)owl_list_get_element(dl, i);
    215250    /* While d shouldn't normally be null, the list may be altered by
    216251     * functions we dispatch to. */
    217     if (d != NULL && FD_ISSET(d->fd, fds)) {
     252    if (d != NULL && !d->needs_gc && FD_ISSET(d->fd, fds)) {
    218253      if (d->cfunc != NULL) {
    219254        d->cfunc(d);
     
    221256    }
    222257  }
     258
     259  dispatch_active = 0;
     260  owl_select_gc();
    223261}
    224262
Note: See TracChangeset for help on using the changeset viewer.