[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 07 of 21] blktap3/drivers: Introduce scheduling of events inside tapdisks
This patch copies the event scheduling functionality from blktap2 with most changes coming from blktap2.5. Signed-off-by: Thanos Makatos <thanos.makatos@xxxxxxxxxx> diff --git a/tools/blktap2/drivers/scheduler.c b/tools/blktap3/drivers/scheduler.c copy from tools/blktap2/drivers/scheduler.c copy to tools/blktap3/drivers/scheduler.c --- a/tools/blktap2/drivers/scheduler.c +++ b/tools/blktap3/drivers/scheduler.c @@ -25,59 +25,54 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/time.h> +#include <sys/select.h> +#include "tapdisk.h" #include "scheduler.h" #include "tapdisk-log.h" -#define DBG(_f, _a...) tlog_write(TLOG_DBG, _f, ##_a) +#define DBG(_f, _a...) if (0) { tlog_syslog(TLOG_DBG, _f, ##_a); } +#define BUG_ON(_cond) if (_cond) td_panic() #define SCHEDULER_MAX_TIMEOUT 600 #define SCHEDULER_POLL_FD (SCHEDULER_POLL_READ_FD | \ SCHEDULER_POLL_WRITE_FD | \ SCHEDULER_POLL_EXCEPT_FD) -#define MIN(a, b) ((a) <= (b) ? (a) : (b)) -#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#include <sys/param.h> -#define scheduler_for_each_event(s, event, tmp) \ - list_for_each_entry_safe(event, tmp, &(s)->events, next) +#define scheduler_for_each_event(s, event) \ + TAILQ_FOREACH(event, &(s)->events, entry) -typedef struct event { - char mode; - event_id_t id; - - int fd; - int timeout; - int deadline; - - event_cb_t cb; - void *private; - - struct list_head next; -} event_t; +#define scheduler_for_each_event_safe(s, event, tmp) \ + TAILQ_FOREACH_SAFE(event,&(s)->events, entry, tmp) static void scheduler_prepare_events(scheduler_t *s) { int diff; struct timeval now; - event_t *event, *tmp; + event_t *event; FD_ZERO(&s->read_fds); FD_ZERO(&s->write_fds); FD_ZERO(&s->except_fds); - s->max_fd = 0; + s->max_fd = -1; s->timeout = SCHEDULER_MAX_TIMEOUT; gettimeofday(&now, NULL); - scheduler_for_each_event(s, event, tmp) { + scheduler_for_each_event(s, event) { + if (event->masked || event->dead) + continue; + if (event->mode & SCHEDULER_POLL_READ_FD) { FD_SET(event->fd, &s->read_fds); s->max_fd = MAX(event->fd, s->max_fd); @@ -105,61 +100,118 @@ scheduler_prepare_events(scheduler_t *s) s->timeout = MIN(s->timeout, s->max_timeout); } -static void -scheduler_event_callback(event_t *event, char mode) +static int +scheduler_check_fd_events(scheduler_t *s, int nfds) { - if (event->mode & SCHEDULER_POLL_TIMEOUT) { - struct timeval now; - gettimeofday(&now, NULL); - event->deadline = now.tv_sec + event->timeout; - } + event_t *event; - event->cb(event->id, mode, event->private); -} + scheduler_for_each_event(s, event) { + if (!nfds) + break; -static void -scheduler_run_events(scheduler_t *s) -{ - struct timeval now; - event_t *event, *tmp; + if (event->dead) + continue; - gettimeofday(&now, NULL); - - again: - s->restart = 0; - - scheduler_for_each_event(s, event, tmp) { if ((event->mode & SCHEDULER_POLL_READ_FD) && FD_ISSET(event->fd, &s->read_fds)) { FD_CLR(event->fd, &s->read_fds); - scheduler_event_callback(event, SCHEDULER_POLL_READ_FD); - goto next; + event->pending |= SCHEDULER_POLL_READ_FD; + --nfds; } if ((event->mode & SCHEDULER_POLL_WRITE_FD) && FD_ISSET(event->fd, &s->write_fds)) { FD_CLR(event->fd, &s->write_fds); - scheduler_event_callback(event, SCHEDULER_POLL_WRITE_FD); - goto next; + event->pending |= SCHEDULER_POLL_WRITE_FD; + --nfds; } if ((event->mode & SCHEDULER_POLL_EXCEPT_FD) && FD_ISSET(event->fd, &s->except_fds)) { FD_CLR(event->fd, &s->except_fds); - scheduler_event_callback(event, SCHEDULER_POLL_EXCEPT_FD); - goto next; + event->pending |= SCHEDULER_POLL_EXCEPT_FD; + --nfds; + } } - if ((event->mode & SCHEDULER_POLL_TIMEOUT) && - (event->deadline <= now.tv_sec)) - scheduler_event_callback(event, SCHEDULER_POLL_TIMEOUT); + return nfds; +} - next: - if (s->restart) - goto again; +static void +scheduler_check_timeouts(scheduler_t *s) +{ + struct timeval now; + event_t *event; + + gettimeofday(&now, NULL); + + scheduler_for_each_event(s, event) { + BUG_ON(event->pending && event->masked); + + if (event->dead) + continue; + + if (event->pending) + continue; + + if (!(event->mode & SCHEDULER_POLL_TIMEOUT)) + continue; + + if (event->deadline > now.tv_sec) + continue; + + event->pending = SCHEDULER_POLL_TIMEOUT; } } +static int +scheduler_check_events(scheduler_t *s, int nfds) +{ + if (nfds) + nfds = scheduler_check_fd_events(s, nfds); + + scheduler_check_timeouts(s); + + return nfds; +} + +static void +scheduler_event_callback(event_t *event, char mode) +{ + if (event->mode & SCHEDULER_POLL_TIMEOUT) { + struct timeval now; + gettimeofday(&now, NULL); + event->deadline = now.tv_sec + event->timeout; + } + + if (!event->masked) + event->cb(event->id, mode, event->private); +} + +static int +scheduler_run_events(scheduler_t *s) +{ + event_t *event; + int n_dispatched = 0; + + scheduler_for_each_event(s, event) { + char pending; + + if (event->dead) + continue; + + pending = event->pending; + if (pending) { + event->pending = 0; + /* NB. must clear before cb */ + scheduler_event_callback(event, pending); + n_dispatched++; + } + } + + return n_dispatched; +} + int scheduler_register_event(scheduler_t *s, char mode, int fd, int timeout, event_cb_t cb, void *private) @@ -179,8 +231,6 @@ scheduler_register_event(scheduler_t *s, gettimeofday(&now, NULL); - INIT_LIST_HEAD(&event->next); - event->mode = mode; event->fd = fd; event->timeout = timeout; @@ -188,11 +238,12 @@ scheduler_register_event(scheduler_t *s, event->cb = cb; event->private = private; event->id = s->uuid++; + event->masked = 0; if (!s->uuid) s->uuid++; - list_add_tail(&event->next, &s->events); + TAILQ_INSERT_TAIL(&s->events, event, entry); return event->id; } @@ -200,20 +251,44 @@ scheduler_register_event(scheduler_t *s, void scheduler_unregister_event(scheduler_t *s, event_id_t id) { - event_t *event, *tmp; + event_t *event; if (!id) return; - scheduler_for_each_event(s, event, tmp) + scheduler_for_each_event(s, event) if (event->id == id) { - list_del(&event->next); - free(event); - s->restart = 1; + event->dead = 1; + break; + } +} + +void scheduler_mask_event(scheduler_t * s, event_id_t id, int masked) +{ + event_t *event; + + if (!id) + return; + + scheduler_for_each_event(s, event) + if (event->id == id) { + event->masked = ! !masked; break; } } +static void +scheduler_gc_events(scheduler_t *s) +{ + event_t *event, *next; + + scheduler_for_each_event_safe(s, event, next) + if (event->dead) { + TAILQ_REMOVE(&s->events, event, entry); + free(event); + } +} + void scheduler_set_max_timeout(scheduler_t *s, int timeout) { @@ -227,25 +302,41 @@ scheduler_wait_for_events(scheduler_t *s int ret; struct timeval tv; + s->depth++; + ret = 0; + + if (s->depth > 1 && scheduler_run_events(s)) + /* NB. recursive invocations continue with the pending + * event set. We return as soon as we made some + * progress. */ + goto out; + scheduler_prepare_events(s); tv.tv_sec = s->timeout; tv.tv_usec = 0; - DBG("timeout: %d, max_timeout: %d\n", - s->timeout, s->max_timeout); + DBG("timeout: %d, max_timeout: %d\n", s->timeout, s->max_timeout); ret = select(s->max_fd + 1, &s->read_fds, &s->write_fds, &s->except_fds, &tv); - s->restart = 0; + if (ret < 0) + goto out; + + ret = scheduler_check_events(s, ret); + BUG_ON(ret); + s->timeout = SCHEDULER_MAX_TIMEOUT; s->max_timeout = SCHEDULER_MAX_TIMEOUT; - if (ret < 0) - return ret; + scheduler_run_events(s); - scheduler_run_events(s); + if (s->depth == 1) + scheduler_gc_events(s); + + out: + s->depth--; return ret; } @@ -256,10 +347,11 @@ scheduler_initialize(scheduler_t *s) memset(s, 0, sizeof(scheduler_t)); s->uuid = 1; + s->depth = 0; FD_ZERO(&s->read_fds); FD_ZERO(&s->write_fds); FD_ZERO(&s->except_fds); - INIT_LIST_HEAD(&s->events); + TAILQ_INIT(&s->events); } _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |