diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 0dddf24327..6f556d49ef 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -69,6 +69,7 @@ static int xce_pollfd_idx = -1; static struct pollfd *fds; static unsigned int current_array_size; static unsigned int nr_fds; +static unsigned int delayed_requests; static int sock = -1; @@ -255,6 +256,53 @@ static bool write_messages(struct connection *conn) return true; } +static int undelay_request(void *_req) +{ + struct delayed_request *req = _req; + + list_del(&req->list); + delayed_requests--; + + return 0; +} + +static void call_delayed(struct connection *conn, struct delayed_request *req) +{ + assert(conn->in == NULL); + conn->in = req->in; + + if (req->func(req)) { + undelay_request(req); + talloc_set_destructor(req, NULL); + } + + conn->in = NULL; +} + +int delay_request(struct connection *conn, struct buffered_data *in, + bool (*func)(struct delayed_request *), void *data) +{ + struct delayed_request *req; + + req = talloc(in, struct delayed_request); + if (!req) + return ENOMEM; + + /* For the case of connection being closed. */ + talloc_set_destructor(req, undelay_request); + + req->in = in; + req->func = func; + req->data = data; + + delayed_requests++; + list_add(&req->list, &conn->delayed); + + conn->in = NULL; + + return 0; +} + static int destroy_conn(void *_conn) { struct connection *conn = _conn; @@ -321,7 +369,8 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout) memset(fds, 0, sizeof(struct pollfd) * current_array_size); nr_fds = 0; - *ptimeout = -1; + /* In case of delayed requests pause for max 1 second. */ + *ptimeout = delayed_requests ? 1000 : -1; if (sock != -1) *p_sock_pollfd_idx = set_fd(sock, POLLIN|POLLPRI); @@ -1524,6 +1573,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) INIT_LIST_HEAD(&new->out_list); INIT_LIST_HEAD(&new->watches); INIT_LIST_HEAD(&new->transaction_list); + INIT_LIST_HEAD(&new->delayed); list_add_tail(&new->list, &connections); talloc_set_destructor(new, destroy_conn); @@ -2215,6 +2265,16 @@ int main(int argc, char *argv[]) } } + if (delayed_requests) { + list_for_each_entry(conn, &connections, list) { + struct delayed_request *req, *tmp; + + list_for_each_entry_safe(req, tmp, + &conn->delayed, list) + call_delayed(conn, req); + } + } + initialize_fds(&sock_pollfd_idx, &timeout); } } diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index 27826c125c..d5cdf17160 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -61,6 +61,20 @@ struct buffered_data char default_buffer[DEFAULT_BUFFER_SIZE]; }; +struct delayed_request { + /* Next delayed request. */ + struct list_head list; + + /* The delayed request. */ + struct buffered_data *in; + + /* Function to call. */ + bool (*func)(struct delayed_request *req); + + /* Further data. */ + void *data; +}; + struct connection; typedef int connwritefn_t(struct connection *, const void *, unsigned int); typedef int connreadfn_t(struct connection *, void *, unsigned int); @@ -94,6 +108,9 @@ struct connection uint32_t next_transaction_id; unsigned int transaction_started; + /* List of delayed requests. */ + struct list_head delayed; + /* The domain I'm associated with, if any. */ struct domain *domain; @@ -177,6 +194,10 @@ bool is_valid_nodename(const char *node); /* Get name of parent node. */ char *get_parent(const void *ctx, const char *node); +/* Delay a request. */ +int delay_request(struct connection *conn, struct buffered_data *in, + bool (*func)(struct delayed_request *), void *data); + /* Tracing infrastructure. */ void trace_create(const void *data, const char *type); void trace_destroy(const void *data, const char *type);