Ejemplo n.º 1
0
static void clear_pool(struct pool_rec *p) {

  /* Sanity check. */
  if (p == NULL) {
    return;
  }

  pr_alarms_block();

  /* Run through any cleanups. */
  run_cleanups(p->cleanups);
  p->cleanups = NULL;

  /* Destroy subpools. */
  while (p->sub_pools) {
    destroy_pool(p->sub_pools);
  }

  p->sub_pools = NULL;

  free_blocks(p->first->h.next, p->tag);
  p->first->h.next = NULL;

  p->last = p->first;
  p->first->h.first_avail = p->free_first_avail;

  pr_alarms_unblock();
}
Ejemplo n.º 2
0
void destroy_pool(pool *p) {
  if (p == NULL) {
    return;
  }

  pr_alarms_block();

  if (p->parent) {
    if (p->parent->sub_pools == p) {
      p->parent->sub_pools = p->sub_next;
    }

    if (p->sub_prev) {
      p->sub_prev->sub_next = p->sub_next;
    }

    if (p->sub_next) {
      p->sub_next->sub_prev = p->sub_prev;
    }
  }

  clear_pool(p);
  free_blocks(p->first, p->tag);

  pr_alarms_unblock();

#ifdef PR_DEVEL_NO_POOL_FREELIST
  /* If configured explicitly to do so, call free(3) on the freelist after
   * a pool is destroyed.  This can be useful for tracking down use-after-free
   * and other memory issues using libraries such as dmalloc.
   */
  pool_release_free_block_list();
#endif /* PR_EVEL_NO_POOL_FREELIST */
}
Ejemplo n.º 3
0
struct pool *make_sub_pool(struct pool *p) {
  union block_hdr *blok;
  pool *new_pool;

  pr_alarms_block();

  blok = new_block(0, FALSE);

  new_pool = (pool *) blok->h.first_avail;
  blok->h.first_avail += POOL_HDR_BYTES;

  memset(new_pool, 0, sizeof(struct pool));
  new_pool->free_first_avail = blok->h.first_avail;
  new_pool->first = new_pool->last = blok;

  if (p) {
    new_pool->parent = p;
    new_pool->sub_next = p->sub_pools;

    if (new_pool->sub_next)
      new_pool->sub_next->sub_prev = new_pool;

    p->sub_pools = new_pool;
  }

  pr_alarms_unblock();

  return new_pool;
}
Ejemplo n.º 4
0
struct pool_rec *pr_pool_create_sz(struct pool_rec *p, size_t sz) {
  union block_hdr *blok;
  pool *new_pool;

  pr_alarms_block();

  blok = new_block(sz + POOL_HDR_BYTES, TRUE);

  new_pool = (pool *) blok->h.first_avail;
  blok->h.first_avail += POOL_HDR_BYTES;

  memset(new_pool, 0, sizeof(struct pool_rec));
  new_pool->free_first_avail = blok->h.first_avail;
  new_pool->first = new_pool->last = blok;

  if (p) {
    new_pool->parent = p;
    new_pool->sub_next = p->sub_pools;

    if (new_pool->sub_next)
      new_pool->sub_next->sub_prev = new_pool;

    p->sub_pools = new_pool;
  }

  pr_alarms_unblock();

  return new_pool;
}
Ejemplo n.º 5
0
/* Release the entire free block list */
static void pool_release_free_block_list(void) {
  union block_hdr *blok = NULL, *next = NULL;

  pr_alarms_block();

  for (blok = block_freelist; blok; blok = next) {
    next = blok->h.next;
    free(blok);
  }
  block_freelist = NULL;

  pr_alarms_unblock();
}
Ejemplo n.º 6
0
/* Release the entire free block list */
static void pool_release_free_block_list(void) {
  union block_hdr *blok,*next;

  pr_alarms_block();

  blok = block_freelist;
  if (blok) {
    for (next = blok->h.next; next; blok = next, next = blok->h.next)
      free(blok);
  }
  block_freelist = NULL;

  pr_alarms_unblock();
}
Ejemplo n.º 7
0
int pr_timer_reset(int timerno, module *mod) {
  struct timer *t = NULL;

  if (!timers) {
    errno = EPERM;
    return -1;
  }

  if (_indispatch) {
    errno = EINTR;
    return -1;
  }

  pr_alarms_block();

  if (!recycled)
    recycled = xaset_create(timer_pool, NULL);

  for (t = (struct timer *) timers->xas_list; t; t = t->next) {
    if (t->timerno == timerno &&
        (t->mod == mod || mod == ANY_MODULE)) {
      t->count = t->interval;
      xaset_remove(timers, (xasetmember_t *) t);
      xaset_insert(recycled, (xasetmember_t *) t);
      nalarms++;

      /* The handle_alarm() function also readjusts the timers lists
       * as part of its processing, so it needs to be called when a timer
       * is reset.
       */
      handle_alarm();
      break;
    }
  }

  pr_alarms_unblock();

  if (t != NULL) {
    pr_trace_msg("timer", 7, "reset timer ID %d ('%s', for module '%s')",
      t->timerno, t->desc, t->mod ? t->mod->name : "[none]");
    return t->timerno;
  }

  return 0;
}
Ejemplo n.º 8
0
END_TEST

START_TEST (timer_sleep_test) {
  int res;

  res = pr_timer_sleep(0);
  fail_unless(res == -1, "Failed to handle sleep len of zero");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  pr_alarms_block();
  res = pr_timer_sleep(1);
  fail_unless(res == -1, "Failed to handle blocked alarms when sleeping");
  fail_unless(errno == EPERM, "Failed to set errno to EPERM");

  pr_alarms_unblock();

  res = pr_timer_sleep(1);
  fail_unless(res == 0, "Failed to sleep: %s", strerror(errno));
}
Ejemplo n.º 9
0
static void *alloc_pool(struct pool_rec *p, size_t reqsz, int exact) {
  /* Round up requested size to an even number of aligned units */
  size_t nclicks = 1 + ((reqsz - 1) / CLICK_SZ);
  size_t sz = nclicks * CLICK_SZ;

  /* For performance, see if space is available in the most recently
   * allocated block.
   */

  union block_hdr *blok = p->last;
  char *first_avail = blok->h.first_avail;
  char *new_first_avail;

  if (reqsz == 0) {
    /* Don't try to allocate memory of zero length.
     *
     * This should NOT happen normally; if it does, by returning NULL we
     * almost guarantee a null pointer dereference.
     */
    errno = EINVAL;
    return NULL;
  }

  new_first_avail = first_avail + sz;

  if (new_first_avail <= (char *) blok->h.endp) {
    blok->h.first_avail = new_first_avail;
    return (void *) first_avail;
  }

  /* Need a new one that's big enough */
  pr_alarms_block();

  blok = new_block(sz, exact);
  p->last->h.next = blok;
  p->last = blok;

  first_avail = blok->h.first_avail;
  blok->h.first_avail = sz + (char *) blok->h.first_avail;

  pr_alarms_unblock();
  return (void *) first_avail;
}
Ejemplo n.º 10
0
void destroy_pool(pool *p) {
  if (p == NULL)
    return;

  pr_alarms_block();

  if (p->parent) {
    if (p->parent->sub_pools == p)
      p->parent->sub_pools = p->sub_next;

    if (p->sub_prev)
      p->sub_prev->sub_next = p->sub_next;

    if (p->sub_next)
      p->sub_next->sub_prev = p->sub_prev;
  }
  clear_pool(p);
  free_blocks(p->first, p->tag);

  pr_alarms_unblock();
}
Ejemplo n.º 11
0
static void *alloc_pool(struct pool_rec *p, size_t reqsz, int exact) {

  /* Round up requested size to an even number of aligned units */
  size_t nclicks = 1 + ((reqsz - 1) / CLICK_SZ);
  size_t sz = nclicks * CLICK_SZ;

  /* For performance, see if space is available in the most recently
   * allocated block.
   */

  union block_hdr *blok = p->last;
  char *first_avail = blok->h.first_avail;
  char *new_first_avail;

  if (reqsz == 0) {
    /* Don't try to allocate memory of zero length. */
    return NULL;
  }

  new_first_avail = first_avail + sz;

  if (new_first_avail <= blok->h.endp) {
    blok->h.first_avail = new_first_avail;
    return (void *) first_avail;
  }

  /* Need a new one that's big enough */
  pr_alarms_block();

  blok = new_block(sz, exact);
  p->last->h.next = blok;
  p->last = blok;

  first_avail = blok->h.first_avail;
  blok->h.first_avail += sz;

  pr_alarms_unblock();
  return (void *) first_avail;
}
Ejemplo n.º 12
0
/* This function does the work of iterating through the list of registered
 * timers, checking to see if their callbacks should be invoked and whether
 * they should be removed from the registration list. Its return value is
 * the amount of time remaining on the first timer in the list.
 */
static int process_timers(int elapsed) {
  struct timer *t = NULL, *next = NULL;

  if (!recycled)
    recycled = xaset_create(timer_pool, NULL);

  if (!elapsed &&
      !recycled->xas_list) {

    if (!timers)
      return 0;

    return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0);
  }

  /* Critical code, no interruptions please */
  if (_indispatch)
    return 0;

  pr_alarms_block();
  _indispatch++;

  if (elapsed) {
    for (t = (struct timer *) timers->xas_list; t; t = next) {
      /* If this timer has already been handled, skip */
      next = t->next;

      if (t->remove) {
        /* Move the timer onto the free_timers chain, for later reuse. */
        xaset_remove(timers, (xasetmember_t *) t);
        xaset_insert(free_timers, (xasetmember_t *) t);

      } else if ((t->count -= elapsed) <= 0) {
        /* This timer's interval has elapsed, so trigger its callback. */

        pr_trace_msg("timer", 4,
          "%ld %s for timer ID %d ('%s', for module '%s') elapsed, invoking "
          "callback (%p)", t->interval,
          t->interval != 1 ? "seconds" : "second", t->timerno,
          t->desc ? t->desc : "<unknown>",
          t->mod ? t->mod->name : "<none>", t->callback);

        if (t->callback(t->interval, t->timerno, t->interval - t->count,
            t->mod) == 0) {

          /* A return value of zero means this timer is done, and can be
           * removed.
           */
          xaset_remove(timers, (xasetmember_t *) t);
          xaset_insert(free_timers, (xasetmember_t *) t);

        } else {
          /* A non-zero return value from a timer callback signals that
           * the timer should be reused/restarted.
           */
          pr_trace_msg("timer", 6, "restarting timer ID %d ('%s'), as per "
            "callback", t->timerno, t->desc ? t->desc : "<unknown>");

          xaset_remove(timers, (xasetmember_t *) t);
          t->count = t->interval;
          xaset_insert(recycled, (xasetmember_t *) t);
        }
      }
    }
  }

  /* Put the recycled timers back into the main timer list. */
  while ((t = (struct timer *) recycled->xas_list) != NULL) {
    xaset_remove(recycled, (xasetmember_t *) t);
    xaset_insert_sort(timers, (xasetmember_t *) t, TRUE);
  }

  _indispatch--;
  pr_alarms_unblock();

  /* If no active timers remain in the list, there is no reason to set the
   * SIGALRM handle.
   */
  return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0);
}
Ejemplo n.º 13
0
int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb,
    const char *desc) {
  struct timer *t = NULL;

  if (seconds <= 0 ||
      cb == NULL ||
      desc == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (!timers)
    timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp);

  /* Check to see that, if specified, the timerno is not already in use. */
  if (timerno >= 0) {
    for (t = (struct timer *) timers->xas_list; t; t = t->next) {
      if (t->timerno == timerno) {
        errno = EPERM;
        return -1;
      }
    }
  }

  if (!free_timers)
    free_timers = xaset_create(timer_pool, NULL);

  /* Try to use an old timer first */
  pr_alarms_block();
  t = (struct timer *) free_timers->xas_list;
  if (t != NULL) {
    xaset_remove(free_timers, (xasetmember_t *) t);

  } else {

    if (timer_pool == NULL) {
      timer_pool = make_sub_pool(permanent_pool);
      pr_pool_tag(timer_pool, "Timer Pool");
    }

    /* Must allocate a new one */
    t = palloc(timer_pool, sizeof(struct timer));
  }

  if (timerno < 0) {
    /* Dynamic timer */
    if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) {
      dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO;
    }

    timerno = dynamic_timerno++;
  }

  t->timerno = timerno;
  t->count = t->interval = seconds;
  t->callback = cb;
  t->mod = mod;
  t->remove = 0;
  t->desc = desc;

  /* If called while _indispatch, add to the recycled list to prevent
   * list corruption
   */

  if (_indispatch) {
    if (!recycled)
      recycled = xaset_create(timer_pool, NULL);
    xaset_insert(recycled, (xasetmember_t *) t);

  } else {
    xaset_insert_sort(timers, (xasetmember_t *) t, TRUE);
    nalarms++;
    set_sig_alarm();

    /* The handle_alarm() function also readjusts the timers lists
     * as part of its processing, so it needs to be called when a timer
     * is added.
     */
    handle_alarm();
  }

  pr_alarms_unblock();

  pr_trace_msg("timer", 7, "added timer ID %d ('%s', for module '%s'), "
    "triggering in %ld %s", t->timerno, t->desc,
    t->mod ? t->mod->name : "[none]", t->interval,
    t->interval != 1 ? "seconds" : "second");
  return timerno;
}
Ejemplo n.º 14
0
int pr_timer_remove(int timerno, module *mod) {
  struct timer *t = NULL, *tnext = NULL;
  int nremoved = 0;

  /* If there are no timers currently registered, do nothing. */
  if (!timers)
    return 0;

  pr_alarms_block();

  for (t = (struct timer *) timers->xas_list; t; t = tnext) {
    tnext = t->next;

    if ((timerno < 0 || t->timerno == timerno) &&
        (mod == ANY_MODULE || t->mod == mod)) {
      nremoved++;

      if (_indispatch) {
        t->remove++;

      } else {
        xaset_remove(timers, (xasetmember_t *) t);
        xaset_insert(free_timers, (xasetmember_t *) t);
	nalarms++;

        /* The handle_alarm() function also readjusts the timers lists
         * as part of its processing, so it needs to be called when a timer
         * is removed.
         */
        handle_alarm();
      }

      pr_trace_msg("timer", 7, "removed timer ID %d ('%s', for module '%s')",
        t->timerno, t->desc, t->mod ? t->mod->name : "[none]");
    }

    /* If we are removing a specific timer, break out of the loop now.
     * Otherwise, keep removing any matching timers.
     */
    if (nremoved > 0 &&
        timerno >= 0) {
      break;
    }
  }

  pr_alarms_unblock();

  if (nremoved == 0) {
    errno = ENOENT;
    return -1;
  }

  /* If we removed a specific timer because of the given timerno, return
   * that timerno value.
   */
  if (timerno >= 0) {
    return timerno;
  }

  return nremoved;
}