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 000000000..a6dbaaa83 --- /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; +}  | 
