From 3b99f7a97553a0a357d50abe507d4f0060c4ecea Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Wed, 20 Jan 2016 12:01:39 +0100 Subject: Rename dp_ptask to be_ptask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Sumit Bose Reviewed-by: Jakub Hrozek Reviewed-by: Lukáš Slebodník --- Makefile.am | 8 +- src/providers/ad/ad_machine_pw_renewal.c | 2 +- src/providers/be_ptask.c | 484 +++++++++++++++++++++++++++++++ src/providers/be_ptask.h | 131 +++++++++ src/providers/be_ptask_private.h | 48 +++ src/providers/data_provider_be.c | 2 +- src/providers/dp_ptask.c | 484 ------------------------------- src/providers/dp_ptask.h | 131 --------- src/providers/dp_ptask_private.h | 48 --- src/providers/dp_refresh.c | 2 +- src/providers/dp_refresh.h | 2 +- src/providers/ipa/ipa_sudo_refresh.c | 2 +- src/providers/ldap/sdap_sudo_refresh.c | 2 +- src/providers/ldap/sdap_sudo_shared.c | 2 +- src/providers/ldap/sdap_sudo_shared.h | 2 +- src/tests/cmocka/test_be_ptask.c | 4 +- 16 files changed, 677 insertions(+), 677 deletions(-) create mode 100644 src/providers/be_ptask.c create mode 100644 src/providers/be_ptask.h create mode 100644 src/providers/be_ptask_private.h delete mode 100644 src/providers/dp_ptask.c delete mode 100644 src/providers/dp_ptask.h delete mode 100644 src/providers/dp_ptask_private.h diff --git a/Makefile.am b/Makefile.am index ee8f698d6..74084bc64 100644 --- a/Makefile.am +++ b/Makefile.am @@ -616,8 +616,8 @@ dist_noinst_HEADERS = \ src/providers/data_provider_iface_generated.h \ src/providers/dp_backend.h \ src/providers/dp_dyndns.h \ - src/providers/dp_ptask_private.h \ - src/providers/dp_ptask.h \ + src/providers/be_ptask_private.h \ + src/providers/be_ptask.h \ src/providers/dp_refresh.h \ src/providers/fail_over.h \ src/providers/fail_over_srv.h \ @@ -1293,7 +1293,7 @@ sssd_be_SOURCES = \ src/providers/data_provider_opts.c \ src/providers/data_provider_callbacks.c \ src/providers/dp_dyndns.c \ - src/providers/dp_ptask.c \ + src/providers/be_ptask.c \ src/providers/dp_refresh.c \ src/monitor/monitor_iface_generated.c \ src/providers/data_provider_iface_generated.c \ @@ -2494,7 +2494,7 @@ test_sysdb_utils_LDADD = \ test_be_ptask_SOURCES = \ src/tests/cmocka/common_mock_be.c \ src/tests/cmocka/test_be_ptask.c \ - src/providers/dp_ptask.c \ + src/providers/be_ptask.c \ $(NULL) test_be_ptask_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c index 6b8fe9c8a..fd7666e35 100644 --- a/src/providers/ad/ad_machine_pw_renewal.c +++ b/src/providers/ad/ad_machine_pw_renewal.c @@ -23,7 +23,7 @@ #include "util/util.h" #include "util/strtonum.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" #include "providers/ad/ad_common.h" #ifndef RENEWAL_PROG_PATH diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c new file mode 100644 index 000000000..18e8681ea --- /dev/null +++ b/src/providers/be_ptask.c @@ -0,0 +1,484 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2013 Red Hat + + 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 3 of the License, or + (at your option) any later 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, see . +*/ + +#include +#include +#include +#include + +#include "util/util.h" +#include "providers/dp_backend.h" +#include "providers/be_ptask_private.h" +#include "providers/be_ptask.h" + +#define backoff_allowed(ptask) (ptask->max_backoff != 0) + +enum be_ptask_schedule { + BE_PTASK_SCHEDULE_FROM_NOW, + BE_PTASK_SCHEDULE_FROM_LAST +}; + +enum be_ptask_delay { + BE_PTASK_FIRST_DELAY, + BE_PTASK_ENABLED_DELAY, + BE_PTASK_PERIOD +}; + +static void be_ptask_schedule(struct be_ptask *task, + enum be_ptask_delay delay_type, + enum be_ptask_schedule from); + +static int be_ptask_destructor(void *pvt) +{ + struct be_ptask *task; + + task = talloc_get_type(pvt, struct be_ptask); + if (task == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "BUG: task is NULL\n"); + return 0; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Terminating periodic task [%s]\n", task->name); + + return 0; +} + +static void be_ptask_online_cb(void *pvt) +{ + struct be_ptask *task = NULL; + + task = talloc_get_type(pvt, struct be_ptask); + if (task == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "BUG: task is NULL\n"); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Back end is online\n"); + be_ptask_enable(task); +} + +static void be_ptask_offline_cb(void *pvt) +{ + struct be_ptask *task = NULL; + task = talloc_get_type(pvt, struct be_ptask); + + DEBUG(SSSDBG_TRACE_FUNC, "Back end is offline\n"); + be_ptask_disable(task); +} + +static void be_ptask_timeout(struct tevent_context *ev, + struct tevent_timer *tt, + struct timeval tv, + void *pvt) +{ + struct be_ptask *task = NULL; + task = talloc_get_type(pvt, struct be_ptask); + + DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: timed out\n", task->name); + + talloc_zfree(task->req); + be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); +} + +static void be_ptask_done(struct tevent_req *req); + +static void be_ptask_execute(struct tevent_context *ev, + struct tevent_timer *tt, + struct timeval tv, + void *pvt) +{ + struct be_ptask *task = NULL; + struct tevent_timer *timeout = NULL; + + task = talloc_get_type(pvt, struct be_ptask); + task->timer = NULL; /* timer is freed by tevent */ + + if (be_is_offline(task->be_ctx)) { + DEBUG(SSSDBG_TRACE_FUNC, "Back end is offline\n"); + switch (task->offline) { + case BE_PTASK_OFFLINE_SKIP: + be_ptask_schedule(task, BE_PTASK_PERIOD, + BE_PTASK_SCHEDULE_FROM_NOW); + return; + case BE_PTASK_OFFLINE_DISABLE: + /* This case is normally handled by offline callback but we + * should handle it here as well since we can get here in some + * special cases for example unit tests or tevent events order. */ + be_ptask_disable(task); + return; + case BE_PTASK_OFFLINE_EXECUTE: + /* continue */ + break; + } + } + + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: executing task, timeout %lu " + "seconds\n", task->name, task->timeout); + + task->last_execution = tv.tv_sec; + + task->req = task->send_fn(task, task->ev, task->be_ctx, task, task->pvt); + if (task->req == NULL) { + /* skip this iteration and try again later */ + DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed to execute task, " + "will try again later\n", task->name); + + be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); + return; + } + + tevent_req_set_callback(task->req, be_ptask_done, task); + + /* schedule timeout */ + if (task->timeout > 0) { + tv = tevent_timeval_current_ofs(task->timeout, 0); + timeout = tevent_add_timer(task->ev, task->req, tv, + be_ptask_timeout, task); + if (timeout == NULL) { + /* If we can't guarantee a timeout, + * we need to cancel the request. */ + talloc_zfree(task->req); + + DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed to set timeout, " + "the task will be rescheduled\n", task->name); + + be_ptask_schedule(task, BE_PTASK_PERIOD, + BE_PTASK_SCHEDULE_FROM_NOW); + } + } + + return; +} + +static void be_ptask_done(struct tevent_req *req) +{ + struct be_ptask *task = NULL; + errno_t ret; + + task = tevent_req_callback_data(req, struct be_ptask); + + ret = task->recv_fn(req); + talloc_zfree(req); + task->req = NULL; + switch (ret) { + case EOK: + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: finished successfully\n", + task->name); + + be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_LAST); + break; + default: + DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed with [%d]: %s\n", + task->name, ret, sss_strerror(ret)); + + be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); + break; + } +} + +static void be_ptask_schedule(struct be_ptask *task, + enum be_ptask_delay delay_type, + enum be_ptask_schedule from) +{ + struct timeval tv = { 0, }; + time_t delay = 0; + + if (!task->enabled) { + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabled\n", task->name); + return; + } + + switch (delay_type) { + case BE_PTASK_FIRST_DELAY: + delay = task->first_delay; + break; + case BE_PTASK_ENABLED_DELAY: + delay = task->enabled_delay; + break; + case BE_PTASK_PERIOD: + delay = task->period; + + if (backoff_allowed(task) && task->period * 2 <= task->max_backoff) { + /* double the period for the next execution */ + task->period *= 2; + } + break; + } + + /* add random offset */ + if (task->random_offset != 0) { + delay = delay + (rand_r(&task->ro_seed) % task->random_offset); + } + + switch (from) { + case BE_PTASK_SCHEDULE_FROM_NOW: + tv = tevent_timeval_current_ofs(delay, 0); + + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds " + "from now [%lu]\n", task->name, delay, tv.tv_sec); + break; + case BE_PTASK_SCHEDULE_FROM_LAST: + tv = tevent_timeval_set(task->last_execution + delay, 0); + + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds " + "from last execution time [%lu]\n", + task->name, delay, tv.tv_sec); + break; + } + + if (task->timer != NULL) { + DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: another timer is already " + "active?\n", task->name); + talloc_zfree(task->timer); + } + + task->timer = tevent_add_timer(task->ev, task, tv, be_ptask_execute, task); + if (task->timer == NULL) { + /* nothing we can do about it */ + DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Unable to schedule task [%s]\n", + task->name); + be_ptask_disable(task); + } + + task->next_execution = tv.tv_sec; +} + +errno_t be_ptask_create(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + time_t period, + time_t first_delay, + time_t enabled_delay, + time_t random_offset, + time_t timeout, + enum be_ptask_offline offline, + time_t max_backoff, + be_ptask_send_t send_fn, + be_ptask_recv_t recv_fn, + void *pvt, + const char *name, + struct be_ptask **_task) +{ + struct be_ptask *task = NULL; + errno_t ret; + + if (be_ctx == NULL || period == 0 || send_fn == NULL || recv_fn == NULL + || name == NULL) { + return EINVAL; + } + + task = talloc_zero(mem_ctx, struct be_ptask); + if (task == NULL) { + ret = ENOMEM; + goto done; + } + + task->ev = be_ctx->ev; + task->be_ctx = be_ctx; + task->period = period; + task->orig_period = period; + task->first_delay = first_delay; + task->enabled_delay = enabled_delay; + task->random_offset = random_offset; + task->ro_seed = time(NULL) * getpid(); + task->max_backoff = max_backoff; + task->timeout = timeout; + task->offline = offline; + task->send_fn = send_fn; + task->recv_fn = recv_fn; + task->pvt = pvt; + task->name = talloc_strdup(task, name); + if (task->name == NULL) { + ret = ENOMEM; + goto done; + } + + task->enabled = true; + + talloc_set_destructor((TALLOC_CTX*)task, be_ptask_destructor); + + if (offline == BE_PTASK_OFFLINE_DISABLE) { + /* install offline and online callbacks */ + ret = be_add_online_cb(task, be_ctx, be_ptask_online_cb, task, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Unable to install online callback [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = be_add_offline_cb(task, be_ctx, be_ptask_offline_cb, task, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Unable to install offline callback [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + } + + DEBUG(SSSDBG_TRACE_FUNC, "Periodic task [%s] was created\n", task->name); + + be_ptask_schedule(task, BE_PTASK_FIRST_DELAY, BE_PTASK_SCHEDULE_FROM_NOW); + + if (_task != NULL) { + *_task = task; + } + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(task); + } + + return ret; +} + +void be_ptask_enable(struct be_ptask *task) +{ + if (task->enabled) { + DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: already enabled\n", + task->name); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: enabling task\n", task->name); + + task->enabled = true; + be_ptask_schedule(task, BE_PTASK_ENABLED_DELAY, BE_PTASK_SCHEDULE_FROM_NOW); +} + +/* Disable the task, but if a request already in progress, let it finish. */ +void be_ptask_disable(struct be_ptask *task) +{ + DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabling task\n", task->name); + + talloc_zfree(task->timer); + task->enabled = false; + task->period = task->orig_period; +} + +void be_ptask_destroy(struct be_ptask **task) +{ + talloc_zfree(*task); +} + +time_t be_ptask_get_period(struct be_ptask *task) +{ + return task->period; +} + +time_t be_ptask_get_timeout(struct be_ptask *task) +{ + return task->timeout; +} + +struct be_ptask_sync_ctx { + be_ptask_sync_t fn; + void *pvt; +}; + +struct be_ptask_sync_state { + int dummy; +}; + +/* This is not an asynchronous request so there is not any _done function. */ +static struct tevent_req * +be_ptask_sync_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt) +{ + struct be_ptask_sync_ctx *ctx = NULL; + struct be_ptask_sync_state *state = NULL; + struct tevent_req *req = NULL; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct be_ptask_sync_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + ctx = talloc_get_type(pvt, struct be_ptask_sync_ctx); + ret = ctx->fn(mem_ctx, ev, be_ctx, be_ptask, ctx->pvt); + + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + + return req; +} + +static errno_t be_ptask_sync_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + +errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + time_t period, + time_t first_delay, + time_t enabled_delay, + time_t random_offset, + time_t timeout, + enum be_ptask_offline offline, + time_t max_backoff, + be_ptask_sync_t fn, + void *pvt, + const char *name, + struct be_ptask **_task) +{ + errno_t ret; + struct be_ptask_sync_ctx *ctx = NULL; + + ctx = talloc_zero(mem_ctx, struct be_ptask_sync_ctx); + if (ctx == NULL) { + ret = ENOMEM; + goto done; + } + + ctx->fn = fn; + ctx->pvt = pvt; + + ret = be_ptask_create(mem_ctx, be_ctx, period, first_delay, + enabled_delay, random_offset, timeout, offline, + max_backoff, be_ptask_sync_send, be_ptask_sync_recv, + ctx, name, _task); + if (ret != EOK) { + goto done; + } + + talloc_steal(*_task, ctx); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(ctx); + } + + return ret; +} diff --git a/src/providers/be_ptask.h b/src/providers/be_ptask.h new file mode 100644 index 000000000..3b9755361 --- /dev/null +++ b/src/providers/be_ptask.h @@ -0,0 +1,131 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2013 Red Hat + + 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 3 of the License, or + (at your option) any later 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, see . +*/ + +#ifndef _DP_PTASK_H_ +#define _DP_PTASK_H_ + +#include +#include +#include + +/* solve circular dependency */ +struct be_ctx; + +struct be_ptask; + +/** + * Defines how should task behave when back end is offline. + */ +enum be_ptask_offline { + /* current request will be skipped and rescheduled to 'now + period' */ + BE_PTASK_OFFLINE_SKIP, + + /* An offline and online callback is registered. The task is disabled + * immediately when back end goes offline and then enabled again + * when back end goes back online */ + BE_PTASK_OFFLINE_DISABLE, + + /* current request will be executed as planned */ + BE_PTASK_OFFLINE_EXECUTE +}; + +typedef struct tevent_req * +(*be_ptask_send_t)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt); + +/** + * If EOK, task will be scheduled again to 'last_execution_time + period'. + * If other error code, task will be rescheduled to 'now + period'. + */ +typedef errno_t +(*be_ptask_recv_t)(struct tevent_req *req); + +/** + * If EOK, task will be scheduled again to 'last_execution_time + period'. + * If other error code, task will be rescheduled to 'now + period'. + */ +typedef errno_t +(*be_ptask_sync_t)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt); + +/** + * The first execution is scheduled first_delay seconds after the task is + * created. + * + * If request does not complete in timeout seconds, it will be + * cancelled and rescheduled to 'now + period'. + * + * If the task is reenabled, it will be scheduled again to + * 'now + enabled_delay'. + * + * The random_offset is maximum number of seconds added to the + * expected delay. Set to 0 if no randomization is needed. + + * If max_backoff is not 0 then the period is doubled + * every time the task is scheduled. The maximum value of + * period is max_backoff. The value of period will be reset to + * original value when the task is disabled. With max_backoff + * set to zero, this feature is disabled. + * + * If an internal error occurred, the task is automatically disabled. + */ +errno_t be_ptask_create(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + time_t period, + time_t first_delay, + time_t enabled_delay, + time_t random_offset, + time_t timeout, + enum be_ptask_offline offline, + time_t max_backoff, + be_ptask_send_t send_fn, + be_ptask_recv_t recv_fn, + void *pvt, + const char *name, + struct be_ptask **_task); + +errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + time_t period, + time_t first_delay, + time_t enabled_delay, + time_t random_offset, + time_t timeout, + enum be_ptask_offline offline, + time_t max_backoff, + be_ptask_sync_t fn, + void *pvt, + const char *name, + struct be_ptask **_task); + +void be_ptask_enable(struct be_ptask *task); +void be_ptask_disable(struct be_ptask *task); +void be_ptask_destroy(struct be_ptask **task); + +time_t be_ptask_get_period(struct be_ptask *task); +time_t be_ptask_get_timeout(struct be_ptask *task); + +#endif /* _DP_PTASK_H_ */ diff --git a/src/providers/be_ptask_private.h b/src/providers/be_ptask_private.h new file mode 100644 index 000000000..4144a3938 --- /dev/null +++ b/src/providers/be_ptask_private.h @@ -0,0 +1,48 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2014 Red Hat + + 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 3 of the License, or + (at your option) any later 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, see . +*/ + +#ifndef DP_PTASK_PRIVATE_H_ +#define DP_PTASK_PRIVATE_H_ + +struct be_ptask { + struct tevent_context *ev; + struct be_ctx *be_ctx; + time_t orig_period; + time_t first_delay; + time_t enabled_delay; + time_t random_offset; + unsigned int ro_seed; + time_t timeout; + time_t max_backoff; + enum be_ptask_offline offline; + be_ptask_send_t send_fn; + be_ptask_recv_t recv_fn; + void *pvt; + const char *name; + + time_t period; /* computed period */ + time_t next_execution; /* next time when the task is scheduled */ + time_t last_execution; /* last time when send was called */ + struct tevent_req *req; /* active tevent request */ + struct tevent_timer *timer; /* active tevent timer */ + bool enabled; +}; + +#endif /* DP_PTASK_PRIVATE_H_ */ diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index a653acd44..8ac1d062d 100644 --- a/src/providers/data_provider_be.c +++ b/src/providers/data_provider_be.c @@ -44,7 +44,7 @@ #include "providers/dp_backend.h" #include "providers/fail_over.h" #include "providers/dp_refresh.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" #include "util/child_common.h" #include "resolv/async_resolv.h" #include "monitor/monitor_interfaces.h" diff --git a/src/providers/dp_ptask.c b/src/providers/dp_ptask.c deleted file mode 100644 index 44db3f6f8..000000000 --- a/src/providers/dp_ptask.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - Authors: - Pavel Březina - - Copyright (C) 2013 Red Hat - - 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 3 of the License, or - (at your option) any later 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, see . -*/ - -#include -#include -#include -#include - -#include "util/util.h" -#include "providers/dp_backend.h" -#include "providers/dp_ptask_private.h" -#include "providers/dp_ptask.h" - -#define backoff_allowed(ptask) (ptask->max_backoff != 0) - -enum be_ptask_schedule { - BE_PTASK_SCHEDULE_FROM_NOW, - BE_PTASK_SCHEDULE_FROM_LAST -}; - -enum be_ptask_delay { - BE_PTASK_FIRST_DELAY, - BE_PTASK_ENABLED_DELAY, - BE_PTASK_PERIOD -}; - -static void be_ptask_schedule(struct be_ptask *task, - enum be_ptask_delay delay_type, - enum be_ptask_schedule from); - -static int be_ptask_destructor(void *pvt) -{ - struct be_ptask *task; - - task = talloc_get_type(pvt, struct be_ptask); - if (task == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "BUG: task is NULL\n"); - return 0; - } - - DEBUG(SSSDBG_TRACE_FUNC, "Terminating periodic task [%s]\n", task->name); - - return 0; -} - -static void be_ptask_online_cb(void *pvt) -{ - struct be_ptask *task = NULL; - - task = talloc_get_type(pvt, struct be_ptask); - if (task == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "BUG: task is NULL\n"); - return; - } - - DEBUG(SSSDBG_TRACE_FUNC, "Back end is online\n"); - be_ptask_enable(task); -} - -static void be_ptask_offline_cb(void *pvt) -{ - struct be_ptask *task = NULL; - task = talloc_get_type(pvt, struct be_ptask); - - DEBUG(SSSDBG_TRACE_FUNC, "Back end is offline\n"); - be_ptask_disable(task); -} - -static void be_ptask_timeout(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, - void *pvt) -{ - struct be_ptask *task = NULL; - task = talloc_get_type(pvt, struct be_ptask); - - DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: timed out\n", task->name); - - talloc_zfree(task->req); - be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); -} - -static void be_ptask_done(struct tevent_req *req); - -static void be_ptask_execute(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, - void *pvt) -{ - struct be_ptask *task = NULL; - struct tevent_timer *timeout = NULL; - - task = talloc_get_type(pvt, struct be_ptask); - task->timer = NULL; /* timer is freed by tevent */ - - if (be_is_offline(task->be_ctx)) { - DEBUG(SSSDBG_TRACE_FUNC, "Back end is offline\n"); - switch (task->offline) { - case BE_PTASK_OFFLINE_SKIP: - be_ptask_schedule(task, BE_PTASK_PERIOD, - BE_PTASK_SCHEDULE_FROM_NOW); - return; - case BE_PTASK_OFFLINE_DISABLE: - /* This case is normally handled by offline callback but we - * should handle it here as well since we can get here in some - * special cases for example unit tests or tevent events order. */ - be_ptask_disable(task); - return; - case BE_PTASK_OFFLINE_EXECUTE: - /* continue */ - break; - } - } - - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: executing task, timeout %lu " - "seconds\n", task->name, task->timeout); - - task->last_execution = tv.tv_sec; - - task->req = task->send_fn(task, task->ev, task->be_ctx, task, task->pvt); - if (task->req == NULL) { - /* skip this iteration and try again later */ - DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed to execute task, " - "will try again later\n", task->name); - - be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); - return; - } - - tevent_req_set_callback(task->req, be_ptask_done, task); - - /* schedule timeout */ - if (task->timeout > 0) { - tv = tevent_timeval_current_ofs(task->timeout, 0); - timeout = tevent_add_timer(task->ev, task->req, tv, - be_ptask_timeout, task); - if (timeout == NULL) { - /* If we can't guarantee a timeout, - * we need to cancel the request. */ - talloc_zfree(task->req); - - DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed to set timeout, " - "the task will be rescheduled\n", task->name); - - be_ptask_schedule(task, BE_PTASK_PERIOD, - BE_PTASK_SCHEDULE_FROM_NOW); - } - } - - return; -} - -static void be_ptask_done(struct tevent_req *req) -{ - struct be_ptask *task = NULL; - errno_t ret; - - task = tevent_req_callback_data(req, struct be_ptask); - - ret = task->recv_fn(req); - talloc_zfree(req); - task->req = NULL; - switch (ret) { - case EOK: - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: finished successfully\n", - task->name); - - be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_LAST); - break; - default: - DEBUG(SSSDBG_OP_FAILURE, "Task [%s]: failed with [%d]: %s\n", - task->name, ret, sss_strerror(ret)); - - be_ptask_schedule(task, BE_PTASK_PERIOD, BE_PTASK_SCHEDULE_FROM_NOW); - break; - } -} - -static void be_ptask_schedule(struct be_ptask *task, - enum be_ptask_delay delay_type, - enum be_ptask_schedule from) -{ - struct timeval tv = { 0, }; - time_t delay = 0; - - if (!task->enabled) { - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabled\n", task->name); - return; - } - - switch (delay_type) { - case BE_PTASK_FIRST_DELAY: - delay = task->first_delay; - break; - case BE_PTASK_ENABLED_DELAY: - delay = task->enabled_delay; - break; - case BE_PTASK_PERIOD: - delay = task->period; - - if (backoff_allowed(task) && task->period * 2 <= task->max_backoff) { - /* double the period for the next execution */ - task->period *= 2; - } - break; - } - - /* add random offset */ - if (task->random_offset != 0) { - delay = delay + (rand_r(&task->ro_seed) % task->random_offset); - } - - switch (from) { - case BE_PTASK_SCHEDULE_FROM_NOW: - tv = tevent_timeval_current_ofs(delay, 0); - - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds " - "from now [%lu]\n", task->name, delay, tv.tv_sec); - break; - case BE_PTASK_SCHEDULE_FROM_LAST: - tv = tevent_timeval_set(task->last_execution + delay, 0); - - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: scheduling task %lu seconds " - "from last execution time [%lu]\n", - task->name, delay, tv.tv_sec); - break; - } - - if (task->timer != NULL) { - DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: another timer is already " - "active?\n", task->name); - talloc_zfree(task->timer); - } - - task->timer = tevent_add_timer(task->ev, task, tv, be_ptask_execute, task); - if (task->timer == NULL) { - /* nothing we can do about it */ - DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Unable to schedule task [%s]\n", - task->name); - be_ptask_disable(task); - } - - task->next_execution = tv.tv_sec; -} - -errno_t be_ptask_create(TALLOC_CTX *mem_ctx, - struct be_ctx *be_ctx, - time_t period, - time_t first_delay, - time_t enabled_delay, - time_t random_offset, - time_t timeout, - enum be_ptask_offline offline, - time_t max_backoff, - be_ptask_send_t send_fn, - be_ptask_recv_t recv_fn, - void *pvt, - const char *name, - struct be_ptask **_task) -{ - struct be_ptask *task = NULL; - errno_t ret; - - if (be_ctx == NULL || period == 0 || send_fn == NULL || recv_fn == NULL - || name == NULL) { - return EINVAL; - } - - task = talloc_zero(mem_ctx, struct be_ptask); - if (task == NULL) { - ret = ENOMEM; - goto done; - } - - task->ev = be_ctx->ev; - task->be_ctx = be_ctx; - task->period = period; - task->orig_period = period; - task->first_delay = first_delay; - task->enabled_delay = enabled_delay; - task->random_offset = random_offset; - task->ro_seed = time(NULL) * getpid(); - task->max_backoff = max_backoff; - task->timeout = timeout; - task->offline = offline; - task->send_fn = send_fn; - task->recv_fn = recv_fn; - task->pvt = pvt; - task->name = talloc_strdup(task, name); - if (task->name == NULL) { - ret = ENOMEM; - goto done; - } - - task->enabled = true; - - talloc_set_destructor((TALLOC_CTX*)task, be_ptask_destructor); - - if (offline == BE_PTASK_OFFLINE_DISABLE) { - /* install offline and online callbacks */ - ret = be_add_online_cb(task, be_ctx, be_ptask_online_cb, task, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to install online callback [%d]: %s\n", - ret, sss_strerror(ret)); - goto done; - } - - ret = be_add_offline_cb(task, be_ctx, be_ptask_offline_cb, task, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to install offline callback [%d]: %s\n", - ret, sss_strerror(ret)); - goto done; - } - } - - DEBUG(SSSDBG_TRACE_FUNC, "Periodic task [%s] was created\n", task->name); - - be_ptask_schedule(task, BE_PTASK_FIRST_DELAY, BE_PTASK_SCHEDULE_FROM_NOW); - - if (_task != NULL) { - *_task = task; - } - - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(task); - } - - return ret; -} - -void be_ptask_enable(struct be_ptask *task) -{ - if (task->enabled) { - DEBUG(SSSDBG_MINOR_FAILURE, "Task [%s]: already enabled\n", - task->name); - return; - } - - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: enabling task\n", task->name); - - task->enabled = true; - be_ptask_schedule(task, BE_PTASK_ENABLED_DELAY, BE_PTASK_SCHEDULE_FROM_NOW); -} - -/* Disable the task, but if a request already in progress, let it finish. */ -void be_ptask_disable(struct be_ptask *task) -{ - DEBUG(SSSDBG_TRACE_FUNC, "Task [%s]: disabling task\n", task->name); - - talloc_zfree(task->timer); - task->enabled = false; - task->period = task->orig_period; -} - -void be_ptask_destroy(struct be_ptask **task) -{ - talloc_zfree(*task); -} - -time_t be_ptask_get_period(struct be_ptask *task) -{ - return task->period; -} - -time_t be_ptask_get_timeout(struct be_ptask *task) -{ - return task->timeout; -} - -struct be_ptask_sync_ctx { - be_ptask_sync_t fn; - void *pvt; -}; - -struct be_ptask_sync_state { - int dummy; -}; - -/* This is not an asynchronous request so there is not any _done function. */ -static struct tevent_req * -be_ptask_sync_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct be_ctx *be_ctx, - struct be_ptask *be_ptask, - void *pvt) -{ - struct be_ptask_sync_ctx *ctx = NULL; - struct be_ptask_sync_state *state = NULL; - struct tevent_req *req = NULL; - errno_t ret; - - req = tevent_req_create(mem_ctx, &state, struct be_ptask_sync_state); - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); - return NULL; - } - - ctx = talloc_get_type(pvt, struct be_ptask_sync_ctx); - ret = ctx->fn(mem_ctx, ev, be_ctx, be_ptask, ctx->pvt); - - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } - tevent_req_post(req, ev); - - return req; -} - -static errno_t be_ptask_sync_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx, - struct be_ctx *be_ctx, - time_t period, - time_t first_delay, - time_t enabled_delay, - time_t random_offset, - time_t timeout, - enum be_ptask_offline offline, - time_t max_backoff, - be_ptask_sync_t fn, - void *pvt, - const char *name, - struct be_ptask **_task) -{ - errno_t ret; - struct be_ptask_sync_ctx *ctx = NULL; - - ctx = talloc_zero(mem_ctx, struct be_ptask_sync_ctx); - if (ctx == NULL) { - ret = ENOMEM; - goto done; - } - - ctx->fn = fn; - ctx->pvt = pvt; - - ret = be_ptask_create(mem_ctx, be_ctx, period, first_delay, - enabled_delay, random_offset, timeout, offline, - max_backoff, be_ptask_sync_send, be_ptask_sync_recv, - ctx, name, _task); - if (ret != EOK) { - goto done; - } - - talloc_steal(*_task, ctx); - - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(ctx); - } - - return ret; -} diff --git a/src/providers/dp_ptask.h b/src/providers/dp_ptask.h deleted file mode 100644 index 3b9755361..000000000 --- a/src/providers/dp_ptask.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - Authors: - Pavel Březina - - Copyright (C) 2013 Red Hat - - 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 3 of the License, or - (at your option) any later 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, see . -*/ - -#ifndef _DP_PTASK_H_ -#define _DP_PTASK_H_ - -#include -#include -#include - -/* solve circular dependency */ -struct be_ctx; - -struct be_ptask; - -/** - * Defines how should task behave when back end is offline. - */ -enum be_ptask_offline { - /* current request will be skipped and rescheduled to 'now + period' */ - BE_PTASK_OFFLINE_SKIP, - - /* An offline and online callback is registered. The task is disabled - * immediately when back end goes offline and then enabled again - * when back end goes back online */ - BE_PTASK_OFFLINE_DISABLE, - - /* current request will be executed as planned */ - BE_PTASK_OFFLINE_EXECUTE -}; - -typedef struct tevent_req * -(*be_ptask_send_t)(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct be_ctx *be_ctx, - struct be_ptask *be_ptask, - void *pvt); - -/** - * If EOK, task will be scheduled again to 'last_execution_time + period'. - * If other error code, task will be rescheduled to 'now + period'. - */ -typedef errno_t -(*be_ptask_recv_t)(struct tevent_req *req); - -/** - * If EOK, task will be scheduled again to 'last_execution_time + period'. - * If other error code, task will be rescheduled to 'now + period'. - */ -typedef errno_t -(*be_ptask_sync_t)(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct be_ctx *be_ctx, - struct be_ptask *be_ptask, - void *pvt); - -/** - * The first execution is scheduled first_delay seconds after the task is - * created. - * - * If request does not complete in timeout seconds, it will be - * cancelled and rescheduled to 'now + period'. - * - * If the task is reenabled, it will be scheduled again to - * 'now + enabled_delay'. - * - * The random_offset is maximum number of seconds added to the - * expected delay. Set to 0 if no randomization is needed. - - * If max_backoff is not 0 then the period is doubled - * every time the task is scheduled. The maximum value of - * period is max_backoff. The value of period will be reset to - * original value when the task is disabled. With max_backoff - * set to zero, this feature is disabled. - * - * If an internal error occurred, the task is automatically disabled. - */ -errno_t be_ptask_create(TALLOC_CTX *mem_ctx, - struct be_ctx *be_ctx, - time_t period, - time_t first_delay, - time_t enabled_delay, - time_t random_offset, - time_t timeout, - enum be_ptask_offline offline, - time_t max_backoff, - be_ptask_send_t send_fn, - be_ptask_recv_t recv_fn, - void *pvt, - const char *name, - struct be_ptask **_task); - -errno_t be_ptask_create_sync(TALLOC_CTX *mem_ctx, - struct be_ctx *be_ctx, - time_t period, - time_t first_delay, - time_t enabled_delay, - time_t random_offset, - time_t timeout, - enum be_ptask_offline offline, - time_t max_backoff, - be_ptask_sync_t fn, - void *pvt, - const char *name, - struct be_ptask **_task); - -void be_ptask_enable(struct be_ptask *task); -void be_ptask_disable(struct be_ptask *task); -void be_ptask_destroy(struct be_ptask **task); - -time_t be_ptask_get_period(struct be_ptask *task); -time_t be_ptask_get_timeout(struct be_ptask *task); - -#endif /* _DP_PTASK_H_ */ diff --git a/src/providers/dp_ptask_private.h b/src/providers/dp_ptask_private.h deleted file mode 100644 index 4144a3938..000000000 --- a/src/providers/dp_ptask_private.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Authors: - Pavel Březina - - Copyright (C) 2014 Red Hat - - 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 3 of the License, or - (at your option) any later 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, see . -*/ - -#ifndef DP_PTASK_PRIVATE_H_ -#define DP_PTASK_PRIVATE_H_ - -struct be_ptask { - struct tevent_context *ev; - struct be_ctx *be_ctx; - time_t orig_period; - time_t first_delay; - time_t enabled_delay; - time_t random_offset; - unsigned int ro_seed; - time_t timeout; - time_t max_backoff; - enum be_ptask_offline offline; - be_ptask_send_t send_fn; - be_ptask_recv_t recv_fn; - void *pvt; - const char *name; - - time_t period; /* computed period */ - time_t next_execution; /* next time when the task is scheduled */ - time_t last_execution; /* last time when send was called */ - struct tevent_req *req; /* active tevent request */ - struct tevent_timer *timer; /* active tevent timer */ - bool enabled; -}; - -#endif /* DP_PTASK_PRIVATE_H_ */ diff --git a/src/providers/dp_refresh.c b/src/providers/dp_refresh.c index 589c280df..cfa8b12e6 100644 --- a/src/providers/dp_refresh.c +++ b/src/providers/dp_refresh.c @@ -24,7 +24,7 @@ #include #include "providers/dp_backend.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" #include "providers/dp_refresh.h" #include "util/util_errors.h" #include "db/sysdb.h" diff --git a/src/providers/dp_refresh.h b/src/providers/dp_refresh.h index 89ccfcfb4..927fa4a33 100644 --- a/src/providers/dp_refresh.h +++ b/src/providers/dp_refresh.h @@ -24,7 +24,7 @@ #include #include -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" /* solve circular dependency */ struct be_ctx; diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c index e7219d314..787422300 100644 --- a/src/providers/ipa/ipa_sudo_refresh.c +++ b/src/providers/ipa/ipa_sudo_refresh.c @@ -23,7 +23,7 @@ #include #include "util/util.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" #include "providers/ipa/ipa_sudo.h" #include "providers/ldap/sdap_sudo_shared.h" #include "db/sysdb_sudo.h" diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c index 62a97dd12..c54c3fa6f 100644 --- a/src/providers/ldap/sdap_sudo_refresh.c +++ b/src/providers/ldap/sdap_sudo_refresh.c @@ -23,7 +23,7 @@ #include #include "util/util.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" #include "providers/ldap/sdap_sudo.h" #include "providers/ldap/sdap_sudo_shared.h" #include "db/sysdb_sudo.h" diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c index b9e5182a2..807226020 100644 --- a/src/providers/ldap/sdap_sudo_shared.c +++ b/src/providers/ldap/sdap_sudo_shared.c @@ -23,7 +23,7 @@ #include #include "util/util.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" #include "providers/ldap/sdap.h" #include "providers/ldap/sdap_sudo_shared.h" #include "db/sysdb_sudo.h" diff --git a/src/providers/ldap/sdap_sudo_shared.h b/src/providers/ldap/sdap_sudo_shared.h index 76858d431..fcb45d693 100644 --- a/src/providers/ldap/sdap_sudo_shared.h +++ b/src/providers/ldap/sdap_sudo_shared.h @@ -22,7 +22,7 @@ #define _SDAP_SUDO_SHARED_H_ #include "providers/dp_backend.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask.h" errno_t sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, diff --git a/src/tests/cmocka/test_be_ptask.c b/src/tests/cmocka/test_be_ptask.c index 7129472ae..883ed81e8 100644 --- a/src/tests/cmocka/test_be_ptask.c +++ b/src/tests/cmocka/test_be_ptask.c @@ -25,8 +25,8 @@ #include #include "providers/dp_backend.h" -#include "providers/dp_ptask_private.h" -#include "providers/dp_ptask.h" +#include "providers/be_ptask_private.h" +#include "providers/be_ptask.h" #include "tests/cmocka/common_mock.h" #include "tests/cmocka/common_mock_be.h" #include "tests/common.h" -- cgit