diff options
author | Simo Sorce <idra@samba.org> | 2011-05-05 17:59:00 -0400 |
---|---|---|
committer | Andreas Schneider <asn@samba.org> | 2011-08-10 18:14:03 +0200 |
commit | 595cce89fe88d0a93a2df00b9a8f880be56df0e8 (patch) | |
tree | 0b98b4e14eb8e0cd6797aa60bf4ba51b3cf3eaaf | |
parent | 1dd93f40c8ae22d4210e72df2bad60bf3e1da350 (diff) | |
download | samba-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.c | 86 |
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, |