[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.