/* * Copyright (C) 2006-2010 Red Hat, Inc. * * Author: Angus Salkeld * * This file is part of libqb. * * libqb is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libqb 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libqb. If not, see . */ #include "os_base.h" #include #include #include #include "loop_int.h" #include "util_int.h" struct qb_loop_job { struct qb_loop_item item; qb_loop_job_dispatch_fn dispatch_fn; }; static void job_dispatch(struct qb_loop_item *item, enum qb_loop_priority p) { struct qb_loop_job *job = qb_list_entry(item, struct qb_loop_job, item); job->dispatch_fn(job->item.user_data); free(job); /* * this is a one-shot so don't re-add */ } static int32_t get_more_jobs(struct qb_loop_source *s, int32_t ms_timeout) { int32_t p; int32_t new_jobs = 0; int32_t level_jobs = 0; /* * this is simple, move jobs from wait_head to job_head */ for (p = QB_LOOP_LOW; p <= QB_LOOP_HIGH; p++) { if (!qb_list_empty(&s->l->level[p].wait_head)) { level_jobs = qb_list_length(&s->l->level[p].wait_head); new_jobs += level_jobs; qb_list_splice_tail(&s->l->level[p].wait_head, &s->l->level[p].job_head); qb_list_init(&s->l->level[p].wait_head); s->l->level[p].todo += level_jobs; } } return new_jobs; } struct qb_loop_source * qb_loop_jobs_create(struct qb_loop *l) { struct qb_loop_source *s = malloc(sizeof(struct qb_loop_source)); if (s == NULL) { return NULL; } s->l = l; s->dispatch_and_take_back = job_dispatch; s->poll = get_more_jobs; return s; } void qb_loop_jobs_destroy(struct qb_loop *l) { free(l->job_source); } int32_t qb_loop_job_add(struct qb_loop *lp, enum qb_loop_priority p, void *data, qb_loop_job_dispatch_fn dispatch_fn) { struct qb_loop_job *job; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } if (l == NULL || dispatch_fn == NULL) { return -EINVAL; } if (p < QB_LOOP_LOW || p > QB_LOOP_HIGH) { return -EINVAL; } job = malloc(sizeof(struct qb_loop_job)); if (job == NULL) { return -ENOMEM; } job->dispatch_fn = dispatch_fn; job->item.user_data = data; job->item.source = l->job_source; job->item.type = QB_LOOP_JOB; qb_list_init(&job->item.list); qb_list_add_tail(&job->item.list, &l->level[p].wait_head); return 0; } int32_t qb_loop_job_del(struct qb_loop *lp, enum qb_loop_priority p, void *data, qb_loop_job_dispatch_fn dispatch_fn) { struct qb_loop_job *job; struct qb_loop_item *item; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } if (l == NULL || dispatch_fn == NULL) { return -EINVAL; } if (p > QB_LOOP_HIGH) { return -EINVAL; } qb_list_for_each_entry(item, &l->level[p].wait_head, list) { job = (struct qb_loop_job *)item; if (job->dispatch_fn == dispatch_fn && job->item.user_data == data && job->item.type == QB_LOOP_JOB) { qb_list_del(&job->item.list); free(job); return 0; } } qb_list_for_each_entry(item, &l->level[p].job_head, list) { if (item->type != QB_LOOP_JOB) { continue; } job = (struct qb_loop_job *)item; if (job->dispatch_fn == dispatch_fn && job->item.user_data == data) { qb_loop_level_item_del(&l->level[p], item); qb_util_log(LOG_DEBUG, "deleting job in JOBLIST"); return 0; } } return -ENOENT; }