summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2011-05-05 17:59:00 -0400
committerAndreas Schneider <asn@samba.org>2011-08-10 18:14:03 +0200
commit595cce89fe88d0a93a2df00b9a8f880be56df0e8 (patch)
tree0b98b4e14eb8e0cd6797aa60bf4ba51b3cf3eaaf
parent1dd93f40c8ae22d4210e72df2bad60bf3e1da350 (diff)
downloadsamba-595cce89fe88d0a93a2df00b9a8f880be56df0e8.tar.gz
samba-595cce89fe88d0a93a2df00b9a8f880be56df0e8.tar.bz2
samba-595cce89fe88d0a93a2df00b9a8f880be56df0e8.zip
s3-spoolss: make listening asynchronous
This also allows to make each children serve more than one client at the same time if necessary. Signed-off-by: Andreas Schneider <asn@samba.org>
-rw-r--r--source3/printing/spoolssd.c86
1 files changed, 60 insertions, 26 deletions
diff --git a/source3/printing/spoolssd.c b/source3/printing/spoolssd.c
index e7bee0e0eb..b4444de52f 100644
--- a/source3/printing/spoolssd.c
+++ b/source3/printing/spoolssd.c
@@ -274,12 +274,11 @@ struct spoolss_children_data {
struct pf_worker_data *pf;
int listen_fd;
int lock_fd;
+
+ bool listening;
};
-static void spoolss_schedule_loop(void *pvt);
-static void spoolss_children_loop(struct tevent_context *ev_ctx,
- struct tevent_immediate *im,
- void *pvt);
+static void spoolss_next_client(void *pvt);
static int spoolss_children_main(struct tevent_context *ev_ctx,
struct pf_worker_data *pf,
@@ -305,11 +304,13 @@ static int spoolss_children_main(struct tevent_context *ev_ctx,
data->msg_ctx = msg_ctx;
data->lock_fd = lock_fd;
data->listen_fd = listen_fd;
-
- spoolss_schedule_loop(data);
+ data->listening = false;
/* loop until it is time to exit */
while (pf->status != PF_WORKER_EXITING) {
+ /* try to see if it is time to schedule the next client */
+ spoolss_next_client(data);
+
ret = tevent_loop_once(ev_ctx);
if (ret != 0) {
DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
@@ -335,13 +336,22 @@ static void spoolss_client_terminated(void *pvt)
return;
}
- spoolss_schedule_loop(pvt);
+ spoolss_next_client(pvt);
}
-static void spoolss_schedule_loop(void *pvt)
+struct spoolss_new_client {
+ struct spoolss_children_data *data;
+ struct sockaddr_un sunaddr;
+ socklen_t addrlen;
+};
+
+static void spoolss_handle_client(struct tevent_req *req);
+
+static void spoolss_next_client(void *pvt)
{
+ struct tevent_req *req;
struct spoolss_children_data *data;
- struct tevent_immediate *im;
+ struct spoolss_new_client *next;
data = talloc_get_type_abort(pvt, struct spoolss_children_data);
@@ -354,35 +364,59 @@ static void spoolss_schedule_loop(void *pvt)
return;
}
- im = tevent_create_immediate(data);
- if (!im) {
- DEBUG(1, ("Failed to create immediate event!\n"));
+ if (data->listening ||
+ data->pf->num_clients >= data->pf->allowed_clients) {
+ /* nothing to do for now we are already listening
+ * or reached the number of clients we are allowed
+ * to handle in parallel */
+ return;
+ }
+
+ next = talloc_zero(data, struct spoolss_new_client);
+ if (!next) {
+ DEBUG(1, ("Out of memory!?\n"));
+ return;
+ }
+ next->data = data;
+ next->addrlen = sizeof(next->sunaddr);
+
+ req = prefork_listen_send(next, data->ev_ctx, data->pf,
+ data->lock_fd, data->listen_fd,
+ (struct sockaddr *)&next->sunaddr,
+ &next->addrlen);
+ if (!req) {
+ DEBUG(1, ("Failed to make listening request!?\n"));
+ talloc_free(next);
return;
}
+ tevent_req_set_callback(req, spoolss_handle_client, next);
- tevent_schedule_immediate(im, data->ev_ctx,
- spoolss_children_loop, data);
+ data->listening = true;
}
-static void spoolss_children_loop(struct tevent_context *ev_ctx,
- struct tevent_immediate *im,
- void *pvt)
+static void spoolss_handle_client(struct tevent_req *req)
{
struct spoolss_children_data *data;
- struct sockaddr_un sunaddr;
- socklen_t addrlen = sizeof(sunaddr);
+ struct spoolss_new_client *client;
int ret;
int sd;
- data = talloc_get_type_abort(pvt, struct spoolss_children_data);
+ client = tevent_req_callback_data(req, struct spoolss_new_client);
+ data = client->data;
+ ret = prefork_listen_recv(req, &sd);
+
+ /* this will free the request too */
+ talloc_free(client);
+ /* we are done listening */
+ data->listening = false;
- /* FIXME: this call is blocking. */
- ret = prefork_wait_for_client(data->pf, data->lock_fd, data->listen_fd,
- (struct sockaddr *)(void *)&sunaddr,
- &addrlen, &sd);
if (ret > 0) {
- DEBUG(1, ("Failed to accept connection!\n"));
+ DEBUG(1, ("Failed to accept client connection!\n"));
+ /* bail out if we are not serving any other client */
+ if (data->pf->num_clients == 0) {
+ data->pf->status = PF_WORKER_EXITING;
+ }
return;
}
@@ -392,7 +426,7 @@ static void spoolss_children_loop(struct tevent_context *ev_ctx,
return;
}
- DEBUG(2, ("Spoolss preforked child %d activated!\n",
+ DEBUG(2, ("Spoolss preforked child %d got client connection!\n",
(int)(data->pf->pid)));
named_pipe_accept_function(data->ev_ctx, data->msg_ctx,