📄 timers.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * timers.c - timers and set of timers, mainly for WTP. * * See timers.h for a description of the interface. */#include <signal.h>#include "gwlib/gwlib.h"#include "wap_events.h"#include "timers.h"/* * Active timers are stored in a TimerHeap. It is a partially ordered * array. Each element i is the child of element i/2 (rounded down), * and a child never elapses before its parent. The result is that * element 0, the top of the heap, is always the first timer to * elapse. The heap is kept in this partial order by all operations on * it. Maintaining a partial order is much cheaper than maintaining * a sorted list. * The array will be resized as needed. The size field is the number * of elements for which space is reserved, and the len field is the * number of elements actually used. The elements used will always be * at tab[0] through tab[len-1]. */struct TimerHeap{ Timer **tab; long len; long size;};typedef struct TimerHeap TimerHeap;struct Timerset{ /* * This field is set to true when the timer thread should shut down. */ volatile sig_atomic_t stopping; /* * The entire set is locked for any operation on it. This is * not as expensive as it sounds because usually each set is * used by one caller thread and one (internal) timer thread, * and the timer thread does not wake up very often. */ Mutex *mutex; /* * Active timers are stored here in a partially ordered structure. * See the definition of TimerHeap, above, for an explanation. */ TimerHeap *heap; /* * The thread that watches the top of the heap, and processes * timers that have elapsed. */ long thread;};typedef struct Timerset Timerset;struct Timer{ /* * An event is produced on the output list when the * timer elapses. The timer is not considered to have * elapsed completely until that pointer has also been * consumed from this list (by the caller, presumably). * That is why the timer code sometimes goes back and * removes a pointer from the output list. */ List *output; /* * The timer is set to elapse at this time, expressed in * Unix time format. This field is set to -1 if the timer * is not active (i.e. in the timer set's heap). */ long elapses; /* * A duplicate of this event will be put on the output list * when the timer elapses. It can be NULL if the timer has * not been started yet. */ WAPEvent *event; /* * This field is normally NULL, but after the timer elapses * it points to the event that was put on the output list. * It is set back to NULL if the event was taken back from * the list, or if it's confirmed that the event was consumed. */ WAPEvent *elapsed_event; /* * Index in the timer set's heap. This field is managed by * the heap operations, and is used to make them faster. * If this timer is not in the heap, this field is -1. */ long index;};/* * Currently we have one timerset (and thus one heap and one thread) * for all timers. This might change in the future in order to tune * performance. In that case, it will be necessary to add a "set" * field to the Timer structure. */static Timerset *timers;/* * Used by timer functions to assert that the timer module has been * intialized. */static int initialized = 0;/* * Internal functions */static void abort_elapsed(Timer *timer);static TimerHeap *heap_create(void);static void heap_destroy(TimerHeap *heap);static void heap_delete(TimerHeap *heap, long index);static int heap_adjust(TimerHeap *heap, long index);static void heap_insert(TimerHeap *heap, Timer *timer);static void heap_swap(TimerHeap *heap, long index1, long index2);static void lock(Timerset *set);static void unlock(Timerset *set);static void watch_timers(void *arg); /* The timer thread */static void elapse_timer(Timer *timer);void timers_init(void){ if (initialized == 0) { timers = gw_malloc(sizeof(*timers)); timers->mutex = mutex_create(); timers->heap = heap_create(); timers->stopping = 0; timers->thread = gwthread_create(watch_timers, timers); } initialized++;}void timers_shutdown(void){ if (initialized > 1) { initialized--; return; } /* Stop all timers. */ if (timers->heap->len > 0) warning(0, "Timers shutting down with %ld active timers.", timers->heap->len); while (timers->heap->len > 0) gwtimer_stop(timers->heap->tab[0]); /* Kill timer thread */ timers->stopping = 1; gwthread_wakeup(timers->thread); gwthread_join(timers->thread); initialized = 0; /* Free resources */ heap_destroy(timers->heap); mutex_destroy(timers->mutex); gw_free(timers);}Timer *gwtimer_create(List *outputlist){ Timer *t; gw_assert(initialized); t = gw_malloc(sizeof(*t)); t->elapses = -1; t->event = NULL; t->elapsed_event = NULL; t->index = -1; t->output = outputlist; list_add_producer(outputlist); return t;}void gwtimer_destroy(Timer *timer){ gw_assert(initialized); if (timer == NULL) return; gwtimer_stop(timer); list_remove_producer(timer->output); wap_event_destroy(timer->event); gw_free(timer);}void gwtimer_start(Timer *timer, int interval, WAPEvent *event){ int wakeup = 0; gw_assert(initialized); gw_assert(timer != NULL); gw_assert(event != NULL || timer->event != NULL); lock(timers); /* Convert to absolute time */ interval += time(NULL); if (timer->elapses > 0) { /* Resetting an existing timer. Move it to its new * position in the heap. */ if (interval < timer->elapses && timer->index == 0) wakeup = 1; timer->elapses = interval; gw_assert(timers->heap->tab[timer->index] == timer); wakeup |= heap_adjust(timers->heap, timer->index); } else { /* Setting a new timer, or resetting an elapsed one. * First deal with a possible elapse event that may * still be on the output list. */ abort_elapsed(timer); /* Then activate the timer. */ timer->elapses = interval; gw_assert(timer->index < 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -