|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 07 of 21 RESEND] 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 |