📄 cron.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet 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, or (at your option) any later version. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file util/pthreads/cron.c * @author Christian Grothoff * @brief Module for periodic background (cron) jobs. * * The module only uses one thread, thus every cron-job must be * short-lived, should never block for an indefinite amount of * time. Specified deadlines are only a guide-line, the 10ms * timer-resolution is only an upper-bound on the possible precision, * in practice it will be worse (depending on the other cron-jobs). * * If you need to schedule a long-running or blocking cron-job, * run a function that will start another thread that will * then run the actual job. */#include "gnunet_util.h"#include "gnunet_util_cron.h"#include "platform.h"#define DEBUG_CRON GNUNET_NO#if DEBUG_CRON#define HAVE_PRINT_CRON_TAB 1#else#define HAVE_PRINT_CRON_TAB 0#endif/** * The initial size of the cron-job table */#define INIT_CRON_JOBS 16/** * how long do we sleep at most? In some systems, the * signal-interrupted sleep does not work nicely, so to ensure * progress, we should rather wake up periodically. (But we don't want * to burn too much CPU time doing busy waiting; every 2s strikes a * good balance) */#define MAXSLEEP 2000#define CHECK_ASSERTS 1/* change this value to artificially speed up all GNUnet cron timers by this factor. E.g. with 10, a cron-job scheduled after 1 minute in the code will occur after 6 seconds. This is useful for testing bugs that would otherwise occur only after a long time. For releases, this value should always be 1 */#define SPEED_UP 1/** number of cron units (ms) in a second */#define CRON_UNIT_TO_SECONDS (1000 / SPEED_UP)/** number of us [usec] in a cron-unit (1000) */#define MICROSEC_TO_CRON_UNIT (1000 * SPEED_UP)/** * @brief The Delta-list for the cron jobs. */typedef struct{ /** * The method to call at that point. */ GNUNET_CronJob method; /** * data ptr (argument to the method) */ void *data; /** * The start-time for this event (in milliseconds). */ GNUNET_CronTime delta; /** * for cron-jobs: when this should be repeated * automatically, 0 if this was a once-only job */ unsigned int deltaRepeat; /** * The index of the next entry in the delta list * after this one (-1 for none) */ int next;} UTIL_cron_DeltaListEntry;typedef struct GNUNET_CronManager{ /** * The lock for the delta-list. */ struct GNUNET_Mutex *deltaListLock_; /** * The delta-list of waiting tasks. */ UTIL_cron_DeltaListEntry *deltaList_; /** * The currently running job. */ GNUNET_CronJob runningJob_; void *runningData_; struct GNUNET_GE_Context *ectx; /** * The cron thread. */ struct GNUNET_ThreadHandle *cron_handle; struct GNUNET_Semaphore *cron_signal; struct GNUNET_Semaphore *cron_signal_up; struct GNUNET_Mutex *inBlockLock_; unsigned int runningRepeat_; /** * The current size of the DeltaList. */ unsigned int deltaListSize_; /** * The first empty slot in the delta-list. */ int firstFree_; /** * The first empty slot in the delta-list. */ int firstUsed_; /** * Set to yes if we are shutting down or shut down. */ int cron_shutdown; /** * Are we in block? */ int inBlock; struct GNUNET_Semaphore *sig;} CronManager;struct GNUNET_CronManager *GNUNET_cron_create (struct GNUNET_GE_Context *ectx){ struct GNUNET_CronManager *cron; unsigned int i; cron = GNUNET_malloc (sizeof (CronManager)); memset (cron, 0, sizeof (CronManager)); cron->deltaListSize_ = INIT_CRON_JOBS; cron->deltaList_ = GNUNET_malloc (sizeof (UTIL_cron_DeltaListEntry) * cron->deltaListSize_); for (i = 0; i < cron->deltaListSize_; i++) cron->deltaList_[i].next = i - 1; cron->firstFree_ = cron->deltaListSize_ - 1; cron->deltaListLock_ = GNUNET_mutex_create (GNUNET_YES); cron->inBlockLock_ = GNUNET_mutex_create (GNUNET_NO); cron->runningJob_ = NULL; cron->firstUsed_ = -1; cron->cron_signal_up = GNUNET_semaphore_create (0); cron->ectx = ectx; cron->cron_shutdown = GNUNET_YES; cron->sig = NULL; return cron;}static voidnoJob (void *unused){#if DEBUG_CRON GNUNET_GE_LOG (NULL, GNUNET_GE_STATUS | GNUNET_GE_DEVELOPER | GNUNET_GE_BULK, "In noJob.\n");#endif}voidGNUNET_cron_stop (struct GNUNET_CronManager *cron){ void *unused;#if DEBUG_CRON GNUNET_GE_LOG (cron->ectx, GNUNET_GE_STATUS | GNUNET_GE_DEVELOPER | GNUNET_GE_BULK, "Stopping cron\n");#endif cron->cron_shutdown = GNUNET_YES; GNUNET_cron_add_job (cron, &noJob, 0, 0, NULL); GNUNET_semaphore_down (cron->cron_signal, GNUNET_YES); GNUNET_semaphore_destroy (cron->cron_signal); cron->cron_signal = NULL; GNUNET_thread_join (cron->cron_handle, &unused);#if DEBUG_CRON GNUNET_GE_LOG (NULL, GNUNET_GE_STATUS | GNUNET_GE_DEVELOPER | GNUNET_GE_BULK, "Cron stopped\n");#endif}/** * GNUNET_CronJob to suspend the cron thread * until it is resumed. */static voidblock (void *cls){ struct GNUNET_CronManager *cron = cls; int ok = GNUNET_SYSERR; if (cron->sig != NULL) GNUNET_semaphore_up (cron->sig); while (ok == GNUNET_SYSERR) { GNUNET_semaphore_down (cron->cron_signal_up, GNUNET_YES); GNUNET_mutex_lock (cron->inBlockLock_); cron->inBlock--; if (cron->inBlock == 0) ok = GNUNET_OK; GNUNET_mutex_unlock (cron->inBlockLock_); }}voidGNUNET_cron_suspend_jobs (struct GNUNET_CronManager *cron, int checkSelf){ if ((GNUNET_YES == checkSelf) && (cron->cron_shutdown == GNUNET_NO) && (GNUNET_NO != GNUNET_thread_test_self (cron->cron_handle))) return; GNUNET_GE_ASSERT (NULL, GNUNET_NO == GNUNET_thread_test_self (cron->cron_handle)); GNUNET_mutex_lock (cron->inBlockLock_); cron->inBlock++; if (cron->inBlock == 1) { cron->sig = GNUNET_semaphore_create (0); GNUNET_cron_add_job (cron, &block, 0, 0, cron); GNUNET_semaphore_down (cron->sig, GNUNET_YES); GNUNET_semaphore_destroy (cron->sig); cron->sig = NULL; } GNUNET_mutex_unlock (cron->inBlockLock_);}intGNUNET_cron_test_running (struct GNUNET_CronManager *cron){ if ((GNUNET_NO == cron->cron_shutdown) || (cron->inBlock > 0)) return GNUNET_YES; else return GNUNET_NO;}voidGNUNET_cron_resume_jobs (struct GNUNET_CronManager *cron, int checkSelf){ if ((GNUNET_YES == checkSelf) && (cron->cron_shutdown == GNUNET_NO) && (GNUNET_NO != GNUNET_thread_test_self (cron->cron_handle))) return; GNUNET_GE_ASSERT (NULL, cron->inBlock > 0); GNUNET_semaphore_up (cron->cron_signal_up);}static voidabortSleep (struct GNUNET_CronManager *cron){ if (cron->cron_signal == NULL) return; /* cron_handle not valid */ GNUNET_thread_stop_sleep (cron->cron_handle);}#if HAVE_PRINT_CRON_TAB/** * Print the cron-tab. */voidprintCronTab (struct GNUNET_CronManager *cron){ int jobId; UTIL_cron_DeltaListEntry *tab; GNUNET_CronTime now; now = GNUNET_get_time (); GNUNET_mutex_lock (cron->deltaListLock_); jobId = cron->firstUsed_; while (jobId != -1) { tab = &cron->deltaList_[jobId]; GNUNET_GE_LOG (NULL, GNUNET_GE_STATUS | GNUNET_GE_DEVELOPER | GNUNET_GE_BULK, "%3u: delta %8lld CU --- method %p --- repeat %8u CU\n", jobId, tab->delta - now, (int) tab->method, tab->deltaRepeat); jobId = tab->next; } GNUNET_mutex_unlock (cron->deltaListLock_);}#endifvoidGNUNET_cron_advance_job (struct GNUNET_CronManager *cron, GNUNET_CronJob method, unsigned int deltaRepeat, void *data){ UTIL_cron_DeltaListEntry *job; UTIL_cron_DeltaListEntry *last; int jobId;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -