diff options
Diffstat (limited to 'libglusterfs/src/timer.c')
-rw-r--r-- | libglusterfs/src/timer.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/libglusterfs/src/timer.c b/libglusterfs/src/timer.c new file mode 100644 index 00000000000..a6dbaaa838f --- /dev/null +++ b/libglusterfs/src/timer.c @@ -0,0 +1,220 @@ +/* + Copyright (c) 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS 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 3 of the License, + or (at your option) any later version. + + GlusterFS 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, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "timer.h" +#include "logging.h" +#include "common-utils.h" + +#define TS(tv) ((((unsigned long long) tv.tv_sec) * 1000000) + (tv.tv_usec)) + +gf_timer_t * +gf_timer_call_after (glusterfs_ctx_t *ctx, + struct timeval delta, + gf_timer_cbk_t cbk, + void *data) +{ + gf_timer_registry_t *reg = NULL; + gf_timer_t *event = NULL; + gf_timer_t *trav = NULL; + unsigned long long at = 0L; + + if (ctx == NULL) + { + gf_log ("timer", GF_LOG_ERROR, "invalid argument"); + return NULL; + } + + reg = gf_timer_registry_init (ctx); + + if (!reg) { + gf_log ("timer", GF_LOG_ERROR, "!reg"); + return NULL; + } + + event = CALLOC (1, sizeof (*event)); + if (!event) { + gf_log ("timer", GF_LOG_CRITICAL, "Not enough memory"); + return NULL; + } + gettimeofday (&event->at, NULL); + event->at.tv_usec = ((event->at.tv_usec + delta.tv_usec) % 1000000); + event->at.tv_sec += ((event->at.tv_usec + delta.tv_usec) / 1000000); + event->at.tv_sec += delta.tv_sec; + at = TS (event->at); + event->cbk = cbk; + event->data = data; + pthread_mutex_lock (®->lock); + { + trav = reg->active.prev; + while (trav != ®->active) { + if (TS (trav->at) < at) + break; + trav = trav->prev; + } + event->prev = trav; + event->next = event->prev->next; + event->prev->next = event; + event->next->prev = event; + } + pthread_mutex_unlock (®->lock); + return event; +} + +int32_t +gf_timer_call_stale (gf_timer_registry_t *reg, + gf_timer_t *event) +{ + if (reg == NULL || event == NULL) + { + gf_log ("timer", GF_LOG_ERROR, "invalid argument"); + return 0; + } + + event->next->prev = event->prev; + event->prev->next = event->next; + event->next = ®->stale; + event->prev = event->next->prev; + event->next->prev = event; + event->prev->next = event; + + return 0; +} + +int32_t +gf_timer_call_cancel (glusterfs_ctx_t *ctx, + gf_timer_t *event) +{ + gf_timer_registry_t *reg = NULL; + + if (ctx == NULL || event == NULL) + { + gf_log ("timer", GF_LOG_ERROR, "invalid argument"); + return 0; + } + + reg = gf_timer_registry_init (ctx); + if (!reg) { + gf_log ("timer", GF_LOG_ERROR, "!reg"); + return 0; + } + + pthread_mutex_lock (®->lock); + { + event->next->prev = event->prev; + event->prev->next = event->next; + } + pthread_mutex_unlock (®->lock); + + FREE (event); + return 0; +} + +void * +gf_timer_proc (void *ctx) +{ + gf_timer_registry_t *reg = NULL; + + if (ctx == NULL) + { + gf_log ("timer", GF_LOG_ERROR, "invalid argument"); + return NULL; + } + + reg = gf_timer_registry_init (ctx); + if (!reg) { + gf_log ("timer", GF_LOG_ERROR, "!reg"); + return NULL; + } + + while (!reg->fin) { + unsigned long long now; + struct timeval now_tv; + gf_timer_t *event = NULL; + + gettimeofday (&now_tv, NULL); + now = TS (now_tv); + while (1) { + unsigned long long at; + char need_cbk = 0; + + pthread_mutex_lock (®->lock); + { + event = reg->active.next; + at = TS (event->at); + if (event != ®->active && now >= at) { + need_cbk = 1; + gf_timer_call_stale (reg, event); + } + } + pthread_mutex_unlock (®->lock); + if (need_cbk) + event->cbk (event->data); + + else + break; + } + usleep (1000000); + } + + pthread_mutex_lock (®->lock); + { + while (reg->active.next != ®->active) { + gf_timer_call_cancel (ctx, reg->active.next); + } + + while (reg->stale.next != ®->stale) { + gf_timer_call_cancel (ctx, reg->stale.next); + } + } + pthread_mutex_unlock (®->lock); + pthread_mutex_destroy (®->lock); + FREE (((glusterfs_ctx_t *)ctx)->timer); + + return NULL; +} + +gf_timer_registry_t * +gf_timer_registry_init (glusterfs_ctx_t *ctx) +{ + if (ctx == NULL) + { + gf_log ("timer", GF_LOG_ERROR, "invalid argument"); + return NULL; + } + + if (!ctx->timer) { + gf_timer_registry_t *reg = NULL; + + ctx->timer = reg = CALLOC (1, sizeof (*reg)); + ERR_ABORT (reg); + pthread_mutex_init (®->lock, NULL); + reg->active.next = ®->active; + reg->active.prev = ®->active; + reg->stale.next = ®->stale; + reg->stale.prev = ®->stale; + + pthread_create (®->th, NULL, gf_timer_proc, ctx); + } + return ctx->timer; +} |