Re-implemented timer code to fix memory leaks and use generic linked list
This commit is contained in:
parent
f23333a597
commit
e9d31bb053
@ -1,3 +1,15 @@
|
|||||||
|
2007-09-23 Ted Bullock <tbullock@canada.com>
|
||||||
|
|
||||||
|
* httperf.c: Add a check to return value of timer_schedule
|
||||||
|
* timer.c: Fix a crash associated with rescheduling a timer
|
||||||
|
* lib/list.c: NEW Generic linked list data structure implementation
|
||||||
|
* lib/list.h: NEW Generic linked list data structure API
|
||||||
|
|
||||||
|
2007-09-18 Ted Bullock <tbullock@canada.com>
|
||||||
|
|
||||||
|
* timer.c: Remove the last of the old timer logic code and replace it
|
||||||
|
with simpler functionality
|
||||||
|
|
||||||
2007-09-11 Ted Bullock <tbullock@canada.com>
|
2007-09-11 Ted Bullock <tbullock@canada.com>
|
||||||
|
|
||||||
* timer.c and timer.h: Use new heap and queue data
|
* timer.c and timer.h: Use new heap and queue data
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
* New in version 1.0:
|
* New in version 0.9.1:
|
||||||
** timer memory leak fix (Ted Bullock)
|
** timer re-write to reduce memory and fix memory leaks (Ted Bullock)
|
||||||
|
** Generic data structures and implementations (heap, queue, linked list)
|
||||||
|
** New options (see man-page for details):
|
||||||
|
--period=vT1,D1,T2,D2...Tn,Dn
|
||||||
|
|
||||||
* New in version 0.9:
|
* New in version 0.9.0:
|
||||||
** Re-Factored build system now builds on the following platforms
|
** Re-Factored build system now builds on the following platforms
|
||||||
HP-UX 11i (64-bit PA-RISC and IA-64)
|
HP-UX 11i (64-bit PA-RISC and IA-64)
|
||||||
Red Hat Enterprise Linux AS (AMD64 and IA-64)
|
Red Hat Enterprise Linux AS (AMD64 and IA-64)
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
# Process this file with autoconf to produce a configure script.
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
AC_INIT(httperf, 0.9.99, httperf@linux.hpl.hp.com)
|
AC_INIT(httperf, 0.9.1, httperf@linux.hpl.hp.com)
|
||||||
AC_CONFIG_SRCDIR([src/httperf.c])
|
AC_CONFIG_SRCDIR([src/httperf.c])
|
||||||
AC_CONFIG_HEADER([config.h])
|
AC_CONFIG_HEADER([config.h])
|
||||||
|
|
||||||
AC_CANONICAL_TARGET
|
AC_CANONICAL_TARGET
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE(httperf, 0.9.99)
|
AM_INIT_AUTOMAKE(httperf, 0.9.1)
|
||||||
|
|
||||||
# Checks for programs.
|
# Checks for programs.
|
||||||
AC_GNU_SOURCE
|
AC_GNU_SOURCE
|
||||||
@ -19,7 +19,7 @@ AC_PROG_INSTALL
|
|||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
|
|
||||||
# Checks for libraries.
|
# Checks for libraries.
|
||||||
AC_CHECK_LIB(event, event_init, , AC_MSG_ERROR([libevent is required to build httperf]) )
|
# AC_CHECK_LIB(event, event_init, , AC_MSG_ERROR([libevent is required to build httperf]) )
|
||||||
AC_CHECK_LIB(m, sqrt)
|
AC_CHECK_LIB(m, sqrt)
|
||||||
AC_CHECK_LIB(crypto, main)
|
AC_CHECK_LIB(crypto, main)
|
||||||
AC_CHECK_LIB(ssl, SSL_version, , AC_MSG_WARN([SSL Disabled]) )
|
AC_CHECK_LIB(ssl, SSL_version, , AC_MSG_WARN([SSL Disabled]) )
|
||||||
|
@ -206,7 +206,8 @@ perf_sample (struct Timer *t, Any_Type regarg)
|
|||||||
|
|
||||||
/* prepare for next sample interval: */
|
/* prepare for next sample interval: */
|
||||||
perf_sample_start = timer_now ();
|
perf_sample_start = timer_now ();
|
||||||
timer_schedule (perf_sample, regarg, RATE_INTERVAL);
|
if( timer_schedule (perf_sample, regarg, RATE_INTERVAL) == NULL)
|
||||||
|
panic("%s(%d): Received NULL from timer_schedule\n", __func__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -4,4 +4,4 @@ AM_LDFLAGS =
|
|||||||
|
|
||||||
noinst_LIBRARIES = libutil.a
|
noinst_LIBRARIES = libutil.a
|
||||||
libutil_a_SOURCES = getopt.c getopt.h getopt1.c ssl_writev.c generic_types.h \
|
libutil_a_SOURCES = getopt.c getopt.h getopt1.c ssl_writev.c generic_types.h \
|
||||||
queue.c queue.h heap.c heap.h
|
queue.c queue.h heap.c heap.h list.c list.h
|
||||||
|
153
httperf/src/lib/list.c
Normal file
153
httperf/src/lib/list.c
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
|
||||||
|
*
|
||||||
|
* This file is part of httperf, a web server performance measurment tool.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission
|
||||||
|
* to link the code of this work with the OpenSSL project's "OpenSSL" library
|
||||||
|
* (or with modified versions of it that use the same license as the "OpenSSL"
|
||||||
|
* library), and distribute linked combinations including the two. You must
|
||||||
|
* obey the GNU General Public License in all respects for all of the code
|
||||||
|
* used other than "OpenSSL". If you modify this file, you may extend this
|
||||||
|
* exception to your version of the file, but you are not obligated to do so.
|
||||||
|
* If you do not wish to do so, delete this exception statement from your
|
||||||
|
* 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., 51
|
||||||
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <generic_types.h>
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
Any_Type data;
|
||||||
|
struct Node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct List {
|
||||||
|
struct Node *dummy_head;
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
is_list_empty(struct List *l)
|
||||||
|
{
|
||||||
|
|
||||||
|
return l->dummy_head->next == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct List *
|
||||||
|
list_create()
|
||||||
|
{
|
||||||
|
struct List *l;
|
||||||
|
|
||||||
|
if ((l = malloc(sizeof(struct List))) == NULL)
|
||||||
|
goto create_error;
|
||||||
|
|
||||||
|
if ((l->dummy_head = malloc(sizeof(struct Node))) == NULL)
|
||||||
|
goto create_error;
|
||||||
|
|
||||||
|
l->dummy_head->next = NULL;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
|
||||||
|
create_error:
|
||||||
|
if (l != NULL)
|
||||||
|
free(l);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
list_free(struct List *l)
|
||||||
|
{
|
||||||
|
free(l->dummy_head);
|
||||||
|
l->dummy_head = NULL;
|
||||||
|
free(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
list_push(struct List *l, Any_Type data)
|
||||||
|
{
|
||||||
|
struct Node *n;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Implement caching so that we don't have to call
|
||||||
|
* malloc every time we push a new node onto the list
|
||||||
|
*/
|
||||||
|
if ((n = malloc(sizeof(struct Node))) == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->data = data;
|
||||||
|
n->next = l->dummy_head->next;
|
||||||
|
l->dummy_head->next = n;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Any_Type
|
||||||
|
list_top(struct List * l)
|
||||||
|
{
|
||||||
|
return l->dummy_head->next->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Any_Type
|
||||||
|
list_pop(struct List * l)
|
||||||
|
{
|
||||||
|
Any_Type data;
|
||||||
|
struct Node *n;
|
||||||
|
|
||||||
|
n = l->dummy_head->next;
|
||||||
|
data = l->dummy_head->next->data;
|
||||||
|
l->dummy_head->next = l->dummy_head->next->next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: As per above, implement caching here so that this memory
|
||||||
|
* does not have to be freed
|
||||||
|
*/
|
||||||
|
free(n);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
list_remove_if_true(struct List *l, int (*action) (Any_Type))
|
||||||
|
{
|
||||||
|
struct Node *n = l->dummy_head;
|
||||||
|
|
||||||
|
while (n->next != NULL) {
|
||||||
|
if ((*action) (n->next->data)) {
|
||||||
|
struct Node *oldnext = n->next;
|
||||||
|
n->next = n->next->next;
|
||||||
|
free(oldnext);
|
||||||
|
} else
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
list_for_each(struct List *l, int (*action) (Any_Type))
|
||||||
|
{
|
||||||
|
struct Node *n = l->dummy_head->next;
|
||||||
|
|
||||||
|
while (n != NULL) {
|
||||||
|
(*action) (n->data);
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
}
|
47
httperf/src/lib/list.h
Normal file
47
httperf/src/lib/list.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
|
||||||
|
*
|
||||||
|
* This file is part of httperf, a web server performance measurment tool.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission
|
||||||
|
* to link the code of this work with the OpenSSL project's "OpenSSL" library
|
||||||
|
* (or with modified versions of it that use the same license as the "OpenSSL"
|
||||||
|
* library), and distribute linked combinations including the two. You must
|
||||||
|
* obey the GNU General Public License in all respects for all of the code
|
||||||
|
* used other than "OpenSSL". If you modify this file, you may extend this
|
||||||
|
* exception to your version of the file, but you are not obligated to do so.
|
||||||
|
* If you do not wish to do so, delete this exception statement from your
|
||||||
|
* 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., 51
|
||||||
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef list_h
|
||||||
|
#define list_h
|
||||||
|
|
||||||
|
typedef int (*list_action) (Any_Type);
|
||||||
|
struct List;
|
||||||
|
|
||||||
|
struct List *list_create();
|
||||||
|
void list_free(struct List *);
|
||||||
|
void list_push(struct List *, Any_Type);
|
||||||
|
int is_list_empty(struct List *);
|
||||||
|
Any_Type list_top(struct List *);
|
||||||
|
Any_Type list_pop(struct List *);
|
||||||
|
void list_remove_if_true(struct List *, list_action);
|
||||||
|
void list_for_each(struct List *, list_action);
|
||||||
|
|
||||||
|
#endif /* list_h */
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2000-2007 Hewlett-Packard Company
|
|
||||||
* Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
|
* Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
|
||||||
|
* Copyright (C) 2000-2007 Hewlett-Packard Company
|
||||||
*
|
*
|
||||||
* This file is part of httperf, a web server performance measurment tool.
|
* This file is part of httperf, a web server performance measurment tool.
|
||||||
*
|
*
|
||||||
@ -38,20 +38,18 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <generic_types.h>
|
#include <generic_types.h>
|
||||||
#include <heap.h>
|
#include <list.h>
|
||||||
#include <queue.h>
|
|
||||||
#include <httperf.h>
|
#include <httperf.h>
|
||||||
|
|
||||||
#define HEAP_SIZE 4096
|
#define NUM_TIMERS 0
|
||||||
#define WHEEL_SIZE 4096
|
|
||||||
|
|
||||||
#define TIMER_INTERVAL (1.0/1000) /* timer granularity in seconds */
|
|
||||||
|
|
||||||
static Time now;
|
static Time now;
|
||||||
static Time next_tick;
|
static Time next_tick;
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
u_long delta;
|
Time time_started;
|
||||||
|
Time timeout_delay;
|
||||||
|
bool has_expired;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Callback function called when timer expires (timeout)
|
* Callback function called when timer expires (timeout)
|
||||||
@ -65,26 +63,17 @@ struct Timer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIFO Queue of inactive timers
|
* inactive timers
|
||||||
*/
|
*/
|
||||||
static struct Queue *passive_timers = NULL;
|
static struct List *passive_timers = NULL;
|
||||||
/*
|
/*
|
||||||
* Min heap of active timers
|
* active timers
|
||||||
*/
|
*/
|
||||||
static struct Heap *active_timers = NULL;
|
static struct List *active_timers = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Executed once a timer has expired, enqueues the timer back into
|
* active timeoutless timers
|
||||||
* the passive_timers queue for later use
|
|
||||||
*/
|
*/
|
||||||
static void
|
static struct List *persistent_timers = NULL;
|
||||||
done(struct Timer *t)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Double cast. Irritating but does the trick
|
|
||||||
*/
|
|
||||||
enqueue((Any_Type) (void *) t, passive_timers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the time and calls the syscall gettimeofday. This is an expensive
|
* Returns the time and calls the syscall gettimeofday. This is an expensive
|
||||||
@ -112,21 +101,6 @@ timer_now(void)
|
|||||||
return timer_now_forced();
|
return timer_now_forced();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Comparison callback function used by the heap data structure to correctly
|
|
||||||
* insert the timer in the proper order (min order as in this case).
|
|
||||||
*/
|
|
||||||
_Bool
|
|
||||||
comparator(Any_Type a, Any_Type b)
|
|
||||||
{
|
|
||||||
struct Timer *timer_a, *timer_b;
|
|
||||||
|
|
||||||
timer_a = (struct Timer *) a.vp;
|
|
||||||
timer_b = (struct Timer *) b.vp;
|
|
||||||
|
|
||||||
return timer_a->delta < timer_b->delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes a large timer pool cache
|
* Initializes a large timer pool cache
|
||||||
* This is a very expensive function. Call before beginning measurements.
|
* This is a very expensive function. Call before beginning measurements.
|
||||||
@ -135,22 +109,26 @@ comparator(Any_Type a, Any_Type b)
|
|||||||
_Bool
|
_Bool
|
||||||
timer_init(void)
|
timer_init(void)
|
||||||
{
|
{
|
||||||
passive_timers = create_queue(WHEEL_SIZE);
|
passive_timers = list_create();
|
||||||
if (passive_timers == NULL)
|
if (passive_timers == NULL)
|
||||||
goto init_failure;
|
goto init_failure;
|
||||||
|
|
||||||
active_timers = create_heap(HEAP_SIZE, &comparator);
|
active_timers = list_create();
|
||||||
if (active_timers == NULL)
|
if (active_timers == NULL)
|
||||||
goto init_failure;
|
goto init_failure;
|
||||||
|
|
||||||
while (!is_queue_full(passive_timers)) {
|
persistent_timers = list_create();
|
||||||
|
if (persistent_timers == NULL)
|
||||||
|
goto init_failure;
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_TIMERS; i++) {
|
||||||
Any_Type a;
|
Any_Type a;
|
||||||
a.vp = malloc(sizeof(struct Timer));
|
a.vp = malloc(sizeof(struct Timer));
|
||||||
|
|
||||||
if (a.vp == NULL)
|
if (a.vp == NULL)
|
||||||
goto init_failure;
|
goto init_failure;
|
||||||
|
|
||||||
enqueue(a, passive_timers);
|
list_push(passive_timers, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
now = timer_now_forced();
|
now = timer_now_forced();
|
||||||
@ -162,63 +140,78 @@ timer_init(void)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Frees all allocated timers, and timer queues
|
* Frees all allocated timers, and timer queues
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
timer_free_all(void)
|
timer_free_all(void)
|
||||||
{
|
{
|
||||||
while (!is_queue_empty(passive_timers)) {
|
int count = 0;
|
||||||
Any_Type a = get_front_and_dequeue(passive_timers);
|
|
||||||
free(a.vp);
|
|
||||||
}
|
|
||||||
free_queue(passive_timers);
|
|
||||||
|
|
||||||
while (!is_heap_empty(active_timers)) {
|
while (!is_list_empty(passive_timers)) {
|
||||||
Any_Type a = remove_min(active_timers);
|
Any_Type a = list_pop(passive_timers);
|
||||||
|
fprintf(stderr,
|
||||||
|
"passive_timers Freeing counter at address %p\n",
|
||||||
|
a.vp);
|
||||||
free(a.vp);
|
free(a.vp);
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
free_heap(active_timers);
|
list_free(passive_timers);
|
||||||
|
passive_timers = NULL;
|
||||||
|
|
||||||
|
while (!is_list_empty(active_timers)) {
|
||||||
|
Any_Type a = list_pop(active_timers);
|
||||||
|
fprintf(stderr,
|
||||||
|
"active_timers Freeing counter at address %p\n", a.vp);
|
||||||
|
free(a.vp);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
list_free(active_timers);
|
||||||
|
active_timers = NULL;
|
||||||
|
|
||||||
|
while (!is_list_empty(persistent_timers)) {
|
||||||
|
Any_Type a = list_pop(persistent_timers);
|
||||||
|
fprintf(stderr,
|
||||||
|
"persistent_timers Freeing counter at address %p\n",
|
||||||
|
a.vp);
|
||||||
|
free(a.vp);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
list_free(persistent_timers);
|
||||||
|
persistent_timers = NULL;
|
||||||
|
|
||||||
|
if (DBG > 2)
|
||||||
|
fprintf(stderr, "Freed a total of %d counters\n", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int
|
||||||
* Checks for timers which have had their timeout value pass and executes their
|
timer_has_expired(Any_Type a)
|
||||||
* callback function. The timer is then removed from the active timer list
|
|
||||||
* and then enqueued back into the passive timer queue
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
expire_complete_timers(Any_Type a)
|
|
||||||
{
|
{
|
||||||
struct Timer *t = (struct Timer *) a.vp;
|
struct Timer *t = a.vp;
|
||||||
|
|
||||||
if (t->delta == 0) {
|
/*
|
||||||
(*t->timeout_callback) (t, t->timer_subject);
|
* Only expire currently processing timers
|
||||||
|
*/
|
||||||
Any_Type verify = remove_min(active_timers);
|
if (t->has_expired == false) {
|
||||||
|
if (t->time_started + t->timeout_delay < timer_now()) {
|
||||||
if (verify.vp != t)
|
t->has_expired = true;
|
||||||
fprintf(stderr,
|
(*t->timeout_callback) (t, t->timer_subject);
|
||||||
"Active timer heap is out of min order!\n\t%s.%s(%d): %s\n",
|
return 1;
|
||||||
__FILE__, __func__, __LINE__, strerror(errno));
|
}
|
||||||
|
} else
|
||||||
/*
|
return 0;
|
||||||
* Double cast. Irritating but does the trick
|
|
||||||
*/
|
|
||||||
enqueue((Any_Type) (void *) t, passive_timers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int
|
||||||
* To be used to decrement a single timer delta value with the heap_for_each
|
timer_deactivate(Any_Type a)
|
||||||
* function via a function pointer
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
decrement_timers(Any_Type a)
|
|
||||||
{
|
{
|
||||||
struct Timer *t = (struct Timer *) a.vp;
|
struct Timer *t = a.vp;
|
||||||
|
|
||||||
if (t != 0)
|
if (t->has_expired == true)
|
||||||
t->delta--;
|
list_push(passive_timers, a);
|
||||||
|
|
||||||
|
return t->has_expired;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -230,20 +223,8 @@ void
|
|||||||
timer_tick(void)
|
timer_tick(void)
|
||||||
{
|
{
|
||||||
now = timer_now_forced();
|
now = timer_now_forced();
|
||||||
|
list_for_each(active_timers, &timer_has_expired);
|
||||||
while (timer_now() >= next_tick) {
|
list_remove_if_true(active_timers, &timer_deactivate);
|
||||||
/*
|
|
||||||
* Check for timers that have timed out and expire them
|
|
||||||
*/
|
|
||||||
heap_for_each(active_timers, &expire_complete_timers);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decrement remaining timers
|
|
||||||
*/
|
|
||||||
heap_for_each(active_timers, &decrement_timers);
|
|
||||||
|
|
||||||
next_tick += TIMER_INTERVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Timer *
|
struct Timer *
|
||||||
@ -251,37 +232,24 @@ timer_schedule(void (*timeout) (struct Timer * t, Any_Type arg),
|
|||||||
Any_Type subject, Time delay)
|
Any_Type subject, Time delay)
|
||||||
{
|
{
|
||||||
struct Timer *t;
|
struct Timer *t;
|
||||||
u_long ticks;
|
|
||||||
u_long delta;
|
|
||||||
Time behind;
|
|
||||||
|
|
||||||
if (!is_queue_empty(passive_timers)) {
|
if (!is_list_empty(passive_timers)) {
|
||||||
Any_Type a = get_front_and_dequeue(passive_timers);
|
Any_Type a = list_pop(passive_timers);
|
||||||
t = (struct Timer *) a.vp;
|
t = (struct Timer *) a.vp;
|
||||||
} else
|
} else if ((t = malloc(sizeof(struct Timer))) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset(t, 0, sizeof(struct Timer));
|
memset(t, 0, sizeof(struct Timer));
|
||||||
t->timeout_callback = timeout;
|
t->timeout_callback = timeout;
|
||||||
|
t->has_expired = false;
|
||||||
t->timer_subject = subject;
|
t->timer_subject = subject;
|
||||||
|
t->time_started = timer_now();
|
||||||
|
t->timeout_delay = delay;
|
||||||
|
|
||||||
behind = (timer_now() - next_tick);
|
if (delay > 0)
|
||||||
if (behind > 0.0)
|
list_push(active_timers, (Any_Type) (void *) t);
|
||||||
delay += behind;
|
else
|
||||||
|
list_push(persistent_timers, (Any_Type) (void *) t);
|
||||||
if (delay < 0.0)
|
|
||||||
ticks = 1;
|
|
||||||
else {
|
|
||||||
ticks =
|
|
||||||
(delay + TIMER_INTERVAL / 2.0) * (1.0 / TIMER_INTERVAL);
|
|
||||||
if (!ticks)
|
|
||||||
ticks = 1; /* minimum delay is a tick */
|
|
||||||
}
|
|
||||||
|
|
||||||
delta = ticks / WHEEL_SIZE;
|
|
||||||
t->delta = delta;
|
|
||||||
|
|
||||||
insert((Any_Type) (void *) t, active_timers);
|
|
||||||
|
|
||||||
if (DBG > 2)
|
if (DBG > 2)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@ -302,5 +270,5 @@ timer_cancel(struct Timer *t)
|
|||||||
* being processed (whose timeout has expired).
|
* being processed (whose timeout has expired).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
done(t);
|
t->has_expired = true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user