]> git.ipfire.org Git - thirdparty/squid.git/blame - src/helper.cc
get rid of "storage class specified for field `rm_b'"
[thirdparty/squid.git] / src / helper.cc
CommitLineData
f740a279 1
2/*
e6ccf245 3 * $Id: helper.cc,v 1.48 2002/10/13 20:35:01 robertc Exp $
f740a279 4 *
17bb3486 5 * DEBUG: section 84 Helper process maintenance
f740a279 6 * AUTHOR: Harvest Derived?
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
f740a279 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
f740a279 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
74addf6c 36#include "squid.h"
e6ccf245 37#include "Store.h"
74addf6c 38
39#define HELPER_MAX_ARGS 64
40
41static PF helperHandleRead;
94439e4e 42static PF helperStatefulHandleRead;
1f5f60dd 43static PF helperServerFree;
94439e4e 44static PF helperStatefulServerFree;
74addf6c 45static void Enqueue(helper * hlp, helper_request *);
46static helper_request *Dequeue(helper * hlp);
94439e4e 47static helper_stateful_request *StatefulDequeue(statefulhelper * hlp);
74addf6c 48static helper_server *GetFirstAvailable(helper * hlp);
94439e4e 49static helper_stateful_server *StatefulGetFirstAvailable(statefulhelper * hlp);
74addf6c 50static void helperDispatch(helper_server * srv, helper_request * r);
94439e4e 51static void helperStatefulDispatch(helper_stateful_server * srv, helper_stateful_request * r);
74addf6c 52static void helperKickQueue(helper * hlp);
94439e4e 53static void helperStatefulKickQueue(statefulhelper * hlp);
74addf6c 54static void helperRequestFree(helper_request * r);
94439e4e 55static void helperStatefulRequestFree(helper_stateful_request * r);
56static void StatefulEnqueue(statefulhelper * hlp, helper_stateful_request * r);
57static helper_stateful_request *StatefulServerDequeue(helper_stateful_server * srv);
58static void StatefulServerEnqueue(helper_stateful_server * srv, helper_stateful_request * r);
59static void helperStatefulServerKickQueue(helper_stateful_server * srv);
74addf6c 60
61void
62helperOpenServers(helper * hlp)
63{
64 char *s;
65 char *progname;
66 char *shortname;
67 char *procname;
a2c963ae 68 const char *args[HELPER_MAX_ARGS];
74addf6c 69 char fd_note_buf[FD_DESC_SZ];
70 helper_server *srv;
71 int nargs = 0;
72 int k;
73 int x;
74 int rfd;
75 int wfd;
76 wordlist *w;
77 if (hlp->cmdline == NULL)
78 return;
79 progname = hlp->cmdline->key;
74addf6c 80 if ((s = strrchr(progname, '/')))
81 shortname = xstrdup(s + 1);
82 else
83 shortname = xstrdup(progname);
17bb3486 84 debug(84, 1) ("helperOpenServers: Starting %d '%s' processes\n",
74addf6c 85 hlp->n_to_start, shortname);
e6ccf245 86 procname = (char *)xmalloc(strlen(shortname) + 3);
74addf6c 87 snprintf(procname, strlen(shortname) + 3, "(%s)", shortname);
88 args[nargs++] = procname;
89 for (w = hlp->cmdline->next; w && nargs < HELPER_MAX_ARGS; w = w->next)
90 args[nargs++] = w->key;
91 args[nargs++] = NULL;
92 assert(nargs <= HELPER_MAX_ARGS);
93 for (k = 0; k < hlp->n_to_start; k++) {
c68e9c6b 94 getCurrentTime();
74addf6c 95 rfd = wfd = -1;
96 x = ipcCreate(hlp->ipc_type,
97 progname,
98 args,
99 shortname,
100 &rfd,
101 &wfd);
102 if (x < 0) {
17bb3486 103 debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname);
74addf6c 104 continue;
105 }
106 hlp->n_running++;
72711e31 107 srv = cbdataAlloc(helper_server);
7d2bd2b5 108 srv->pid = x;
74addf6c 109 srv->flags.alive = 1;
110 srv->index = k;
111 srv->rfd = rfd;
112 srv->wfd = wfd;
e6ccf245 113 srv->buf = (char *)memAllocate(MEM_8K_BUF);
74addf6c 114 srv->buf_sz = 8192;
115 srv->offset = 0;
fa80a8ef 116 srv->parent = cbdataReference(hlp);
74addf6c 117 dlinkAddTail(srv, &srv->link, &hlp->servers);
118 if (rfd == wfd) {
119 snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
120 fd_note(rfd, fd_note_buf);
121 } else {
122 snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
123 fd_note(rfd, fd_note_buf);
124 snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
125 fd_note(wfd, fd_note_buf);
126 }
127 commSetNonBlocking(rfd);
128 if (wfd != rfd)
129 commSetNonBlocking(wfd);
1f5f60dd 130 comm_add_close_handler(rfd, helperServerFree, srv);
74addf6c 131 }
132 safe_free(shortname);
133 safe_free(procname);
838b993c 134 helperKickQueue(hlp);
74addf6c 135}
136
94439e4e 137void
138helperStatefulOpenServers(statefulhelper * hlp)
139{
140 char *s;
141 char *progname;
142 char *shortname;
143 char *procname;
a2c963ae 144 const char *args[HELPER_MAX_ARGS];
94439e4e 145 char fd_note_buf[FD_DESC_SZ];
146 helper_stateful_server *srv;
147 int nargs = 0;
148 int k;
149 int x;
150 int rfd;
151 int wfd;
152 wordlist *w;
153 if (hlp->cmdline == NULL)
154 return;
155 progname = hlp->cmdline->key;
156 if ((s = strrchr(progname, '/')))
157 shortname = xstrdup(s + 1);
158 else
159 shortname = xstrdup(progname);
17bb3486 160 debug(84, 1) ("helperStatefulOpenServers: Starting %d '%s' processes\n",
94439e4e 161 hlp->n_to_start, shortname);
e6ccf245 162 procname = (char *)xmalloc(strlen(shortname) + 3);
94439e4e 163 snprintf(procname, strlen(shortname) + 3, "(%s)", shortname);
164 args[nargs++] = procname;
165 for (w = hlp->cmdline->next; w && nargs < HELPER_MAX_ARGS; w = w->next)
166 args[nargs++] = w->key;
167 args[nargs++] = NULL;
168 assert(nargs <= HELPER_MAX_ARGS);
169 for (k = 0; k < hlp->n_to_start; k++) {
170 getCurrentTime();
171 rfd = wfd = -1;
172 x = ipcCreate(hlp->ipc_type,
173 progname,
174 args,
175 shortname,
176 &rfd,
177 &wfd);
178 if (x < 0) {
17bb3486 179 debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname);
94439e4e 180 continue;
181 }
182 hlp->n_running++;
72711e31 183 srv = cbdataAlloc(helper_stateful_server);
5d146f7d 184 srv->pid = x;
94439e4e 185 srv->flags.alive = 1;
186 srv->flags.reserved = S_HELPER_FREE;
187 srv->deferred_requests = 0;
60d096f4 188 srv->stats.deferbyfunc = 0;
189 srv->stats.deferbycb = 0;
190 srv->stats.submits = 0;
191 srv->stats.releases = 0;
94439e4e 192 srv->index = k;
193 srv->rfd = rfd;
194 srv->wfd = wfd;
e6ccf245 195 srv->buf = (char *)memAllocate(MEM_8K_BUF);
94439e4e 196 srv->buf_sz = 8192;
197 srv->offset = 0;
fa80a8ef 198 srv->parent = cbdataReference(hlp);
94439e4e 199 if (hlp->datapool != NULL)
200 srv->data = memPoolAlloc(hlp->datapool);
94439e4e 201 dlinkAddTail(srv, &srv->link, &hlp->servers);
202 if (rfd == wfd) {
203 snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
204 fd_note(rfd, fd_note_buf);
205 } else {
206 snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
207 fd_note(rfd, fd_note_buf);
208 snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
209 fd_note(wfd, fd_note_buf);
210 }
211 commSetNonBlocking(rfd);
212 if (wfd != rfd)
213 commSetNonBlocking(wfd);
214 comm_add_close_handler(rfd, helperStatefulServerFree, srv);
215 }
216 safe_free(shortname);
217 safe_free(procname);
218 helperStatefulKickQueue(hlp);
219}
220
221
74addf6c 222void
223helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data)
224{
e6ccf245 225 helper_request *r = (helper_request *)memAllocate(MEM_HELPER_REQUEST);
74addf6c 226 helper_server *srv;
5b5f9257 227 if (hlp == NULL) {
17bb3486 228 debug(84, 3) ("helperSubmit: hlp == NULL\n");
5b5f9257 229 callback(data, NULL);
230 return;
231 }
74addf6c 232 r->callback = callback;
fa80a8ef 233 r->data = cbdataReference(data);
74addf6c 234 r->buf = xstrdup(buf);
74addf6c 235 if ((srv = GetFirstAvailable(hlp)))
236 helperDispatch(srv, r);
237 else
238 Enqueue(hlp, r);
17bb3486 239 debug(84, 9) ("helperSubmit: %s\n", buf);
94439e4e 240}
241
721b0310 242/* lastserver = "server last used as part of a deferred or reserved
243 * request sequence"
244 */
94439e4e 245void
246helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPSCB * callback, void *data, helper_stateful_server * lastserver)
247{
e6ccf245 248 helper_stateful_request *r = (helper_stateful_request *)memAllocate(MEM_HELPER_STATEFUL_REQUEST);
94439e4e 249 helper_stateful_server *srv;
250 if (hlp == NULL) {
17bb3486 251 debug(84, 3) ("helperStatefulSubmit: hlp == NULL\n");
94439e4e 252 callback(data, 0, NULL);
253 return;
254 }
255 r->callback = callback;
fa80a8ef 256 r->data = cbdataReference(data);
721b0310 257 if (buf != NULL) {
94439e4e 258 r->buf = xstrdup(buf);
721b0310 259 r->placeholder = 0;
260 } else {
261 r->buf = NULL;
94439e4e 262 r->placeholder = 1;
721b0310 263 }
94439e4e 264 if ((buf != NULL) && lastserver) {
17bb3486 265 debug(84, 5) ("StatefulSubmit with lastserver %p\n", lastserver);
60d096f4 266 /* the queue doesn't count for this assert because queued requests
267 * have already gone through here and been tested.
268 * It's legal to have deferred_requests == 0 and queue entries
269 * and status of S_HELPEER_DEFERRED.
270 * BUT: It's not legal to submit a new request w/lastserver in
271 * that state.
272 */
273 assert(!(lastserver->deferred_requests == 0 &&
274 lastserver->flags.reserved == S_HELPER_DEFERRED));
275 if (lastserver->flags.reserved != S_HELPER_RESERVED) {
276 lastserver->stats.submits++;
94439e4e 277 lastserver->deferred_requests--;
60d096f4 278 }
94439e4e 279 if (!(lastserver->request)) {
17bb3486 280 debug(84, 5) ("StatefulSubmit dispatching\n");
94439e4e 281 helperStatefulDispatch(lastserver, r);
282 } else {
17bb3486 283 debug(84, 5) ("StatefulSubmit queuing\n");
94439e4e 284 StatefulServerEnqueue(lastserver, r);
285 }
286 } else {
287 if ((srv = StatefulGetFirstAvailable(hlp))) {
288 helperStatefulDispatch(srv, r);
289 } else
290 StatefulEnqueue(hlp, r);
291 }
17bb3486 292 debug(84, 9) ("helperStatefulSubmit: placeholder: '%d', buf '%s'.\n", r->placeholder, buf);
94439e4e 293}
294
295helper_stateful_server *
296helperStatefulDefer(statefulhelper * hlp)
297/* find and add a deferred request to a server */
298{
299 dlink_node *n;
300 helper_stateful_server *srv = NULL, *rv = NULL;
301 if (hlp == NULL) {
17bb3486 302 debug(84, 3) ("helperStatefulReserve: hlp == NULL\n");
94439e4e 303 return NULL;
304 }
17bb3486 305 debug(84, 5) ("helperStatefulDefer: Running servers %d.\n", hlp->n_running);
94439e4e 306 if (hlp->n_running == 0) {
17bb3486 307 debug(84, 1) ("helperStatefulDefer: No running servers!. \n");
94439e4e 308 return NULL;
309 }
310 srv = StatefulGetFirstAvailable(hlp);
311 /* all currently busy:loop through servers and find server with the shortest queue */
312 rv = srv;
313 if (rv == NULL)
314 for (n = hlp->servers.head; n != NULL; n = n->next) {
e6ccf245 315 srv = (helper_stateful_server *)n->data;
94439e4e 316 if (srv->flags.reserved == S_HELPER_RESERVED)
317 continue;
318 if (!srv->flags.alive)
319 continue;
320 if ((hlp->IsAvailable != NULL) && (srv->data != NULL) &&
321 !(hlp->IsAvailable(srv->data)))
322 continue;
323 if ((rv != NULL) && (rv->deferred_requests < srv->deferred_requests))
324 continue;
325 rv = srv;
326 }
327 if (rv == NULL) {
17bb3486 328 debug(84, 1) ("helperStatefulDefer: None available.\n");
94439e4e 329 return NULL;
330 }
60d096f4 331 /* consistency check:
332 * when the deferred count is 0,
333 * submits + releases == deferbyfunc + deferbycb
334 * Or in english, when there are no deferred requests, the amount
335 * we have submitted to the queue or cancelled must equal the amount
336 * we have said we wanted to be able to submit or cancel
337 */
338 if (rv->deferred_requests == 0)
339 assert(rv->stats.submits + rv->stats.releases ==
340 rv->stats.deferbyfunc + rv->stats.deferbycb);
341
94439e4e 342 rv->flags.reserved = S_HELPER_DEFERRED;
343 rv->deferred_requests++;
60d096f4 344 rv->stats.deferbyfunc++;
94439e4e 345 return rv;
346}
347
348void
349helperStatefulReset(helper_stateful_server * srv)
350/* puts this helper back in the queue. the calling app is required to
351 * manage the state in the helper.
352 */
353{
354 statefulhelper *hlp = srv->parent;
355 helper_stateful_request *r;
356 r = srv->request;
357 if (r != NULL) {
358 /* reset attempt DURING an outstaning request */
17bb3486 359 debug(84, 1) ("helperStatefulReset: RESET During request %s \n",
94439e4e 360 hlp->id_name);
361 srv->flags.busy = 0;
362 srv->offset = 0;
363 helperStatefulRequestFree(r);
364 srv->request = NULL;
365 }
94439e4e 366 srv->flags.busy = 0;
367 if (srv->queue.head) {
368 srv->flags.reserved = S_HELPER_DEFERRED;
369 helperStatefulServerKickQueue(srv);
370 } else {
371 srv->flags.reserved = S_HELPER_FREE;
372 if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
373 srv->parent->OnEmptyQueue(srv->data);
374 helperStatefulKickQueue(hlp);
375 }
376}
377
378void
379helperStatefulReleaseServer(helper_stateful_server * srv)
380/*decrease the number of 'waiting' clients that set the helper to be DEFERRED */
381{
60d096f4 382 srv->stats.releases++;
383 if (srv->flags.reserved == S_HELPER_DEFERRED) {
384 assert(srv->deferred_requests);
94439e4e 385 srv->deferred_requests--;
60d096f4 386 }
94439e4e 387 if (!(srv->deferred_requests) && (srv->flags.reserved == S_HELPER_DEFERRED) && !(srv->queue.head)) {
388 srv->flags.reserved = S_HELPER_FREE;
389 if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
390 srv->parent->OnEmptyQueue(srv->data);
391 }
392}
393
394void *
395helperStatefulServerGetData(helper_stateful_server * srv)
396/* return a pointer to the stateful routines data area */
397{
398 return srv->data;
74addf6c 399}
400
401void
402helperStats(StoreEntry * sentry, helper * hlp)
403{
404 helper_server *srv;
405 dlink_node *link;
f4ae18d0 406 double tt;
74addf6c 407 storeAppendPrintf(sentry, "number running: %d of %d\n",
408 hlp->n_running, hlp->n_to_start);
409 storeAppendPrintf(sentry, "requests sent: %d\n",
410 hlp->stats.requests);
411 storeAppendPrintf(sentry, "replies received: %d\n",
412 hlp->stats.replies);
413 storeAppendPrintf(sentry, "queue length: %d\n",
414 hlp->stats.queue_size);
a15d85ea 415 storeAppendPrintf(sentry, "avg service time: %.2f msec\n",
416 (double) hlp->stats.avg_svc_time / 1000.0);
74addf6c 417 storeAppendPrintf(sentry, "\n");
09c1ece1 418 storeAppendPrintf(sentry, "%7s\t%7s\t%7s\t%11s\t%s\t%7s\t%7s\t%7s\n",
74addf6c 419 "#",
420 "FD",
f0b7ed32 421 "PID",
74addf6c 422 "# Requests",
423 "Flags",
424 "Time",
592da4ec 425 "Offset",
426 "Request");
74addf6c 427 for (link = hlp->servers.head; link; link = link->next) {
e6ccf245 428 srv = (helper_server*)link->data;
a15d85ea 429 tt = 0.001 * tvSubMsec(srv->dispatch_time,
430 srv->flags.busy ? current_time : srv->answer_time);
09c1ece1 431 storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%c%c%c%c\t%7.3f\t%7d\t%s\n",
74addf6c 432 srv->index + 1,
433 srv->rfd,
a1be6c8c 434 srv->pid,
74addf6c 435 srv->stats.uses,
436 srv->flags.alive ? 'A' : ' ',
437 srv->flags.busy ? 'B' : ' ',
438 srv->flags.closing ? 'C' : ' ',
439 srv->flags.shutdown ? 'S' : ' ',
f4ae18d0 440 tt < 0.0 ? 0.0 : tt,
592da4ec 441 (int) srv->offset,
442 srv->request ? log_quote(srv->request->buf) : "(none)");
74addf6c 443 }
444 storeAppendPrintf(sentry, "\nFlags key:\n\n");
445 storeAppendPrintf(sentry, " A = ALIVE\n");
446 storeAppendPrintf(sentry, " B = BUSY\n");
447 storeAppendPrintf(sentry, " C = CLOSING\n");
448 storeAppendPrintf(sentry, " S = SHUTDOWN\n");
449}
450
94439e4e 451void
452helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp)
453{
454 helper_stateful_server *srv;
455 dlink_node *link;
456 double tt;
457 storeAppendPrintf(sentry, "number running: %d of %d\n",
458 hlp->n_running, hlp->n_to_start);
459 storeAppendPrintf(sentry, "requests sent: %d\n",
460 hlp->stats.requests);
461 storeAppendPrintf(sentry, "replies received: %d\n",
462 hlp->stats.replies);
463 storeAppendPrintf(sentry, "queue length: %d\n",
464 hlp->stats.queue_size);
465 storeAppendPrintf(sentry, "avg service time: %d msec\n",
466 hlp->stats.avg_svc_time);
467 storeAppendPrintf(sentry, "\n");
38650cc8 468 storeAppendPrintf(sentry, "%7s\t%7s\t%7s\t%11s\t%s\t%7s\t%7s\t%7s\t%7s\n",
94439e4e 469 "#",
470 "FD",
5d146f7d 471 "PID",
94439e4e 472 "# Requests",
473 "# Deferred Requests",
474 "Flags",
475 "Time",
476 "Offset",
477 "Request");
478 for (link = hlp->servers.head; link; link = link->next) {
e6ccf245 479 srv = (helper_stateful_server *)link->data;
94439e4e 480 tt = 0.001 * tvSubMsec(srv->dispatch_time, current_time);
5d146f7d 481 storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%11d\t%c%c%c%c%c%c\t%7.3f\t%7d\t%s\n",
94439e4e 482 srv->index + 1,
483 srv->rfd,
5d146f7d 484 srv->pid,
94439e4e 485 srv->stats.uses,
32754419 486 (int) srv->deferred_requests,
94439e4e 487 srv->flags.alive ? 'A' : ' ',
488 srv->flags.busy ? 'B' : ' ',
489 srv->flags.closing ? 'C' : ' ',
490 srv->flags.reserved != S_HELPER_FREE ? 'R' : ' ',
491 srv->flags.shutdown ? 'S' : ' ',
5d146f7d 492 srv->request ? (srv->request->placeholder ? 'P' : ' ') : ' ',
94439e4e 493 tt < 0.0 ? 0.0 : tt,
494 (int) srv->offset,
495 srv->request ? log_quote(srv->request->buf) : "(none)");
496 }
497 storeAppendPrintf(sentry, "\nFlags key:\n\n");
498 storeAppendPrintf(sentry, " A = ALIVE\n");
499 storeAppendPrintf(sentry, " B = BUSY\n");
500 storeAppendPrintf(sentry, " C = CLOSING\n");
501 storeAppendPrintf(sentry, " R = RESERVED or DEFERRED\n");
502 storeAppendPrintf(sentry, " S = SHUTDOWN\n");
5d146f7d 503 storeAppendPrintf(sentry, " P = PLACEHOLDER\n");
94439e4e 504}
505
74addf6c 506void
507helperShutdown(helper * hlp)
508{
c68e9c6b 509 dlink_node *link = hlp->servers.head;
c68e9c6b 510 while (link) {
70160b49 511 helper_server *srv;
e6ccf245 512 srv = (helper_server *)link->data;
c68e9c6b 513 link = link->next;
74addf6c 514 if (!srv->flags.alive) {
515 debug(34, 3) ("helperShutdown: %s #%d is NOT ALIVE.\n",
516 hlp->id_name, srv->index + 1);
517 continue;
518 }
1f5f60dd 519 srv->flags.shutdown = 1; /* request it to shut itself down */
74addf6c 520 if (srv->flags.busy) {
521 debug(34, 3) ("helperShutdown: %s #%d is BUSY.\n",
522 hlp->id_name, srv->index + 1);
74addf6c 523 continue;
524 }
525 if (srv->flags.closing) {
526 debug(34, 3) ("helperShutdown: %s #%d is CLOSING.\n",
527 hlp->id_name, srv->index + 1);
528 continue;
529 }
74addf6c 530 srv->flags.closing = 1;
357099e5 531 /* the rest of the details is dealt with in the helperServerFree
532 * close handler
533 */
534 comm_close(srv->rfd);
74addf6c 535 }
536}
537
94439e4e 538void
539helperStatefulShutdown(statefulhelper * hlp)
540{
541 dlink_node *link = hlp->servers.head;
542 helper_stateful_server *srv;
543 while (link) {
e6ccf245 544 srv = (helper_stateful_server *)link->data;
94439e4e 545 link = link->next;
546 if (!srv->flags.alive) {
547 debug(34, 3) ("helperStatefulShutdown: %s #%d is NOT ALIVE.\n",
548 hlp->id_name, srv->index + 1);
549 continue;
550 }
551 srv->flags.shutdown = 1; /* request it to shut itself down */
552 if (srv->flags.busy) {
553 debug(34, 3) ("helperStatefulShutdown: %s #%d is BUSY.\n",
554 hlp->id_name, srv->index + 1);
555 continue;
556 }
557 if (srv->flags.closing) {
558 debug(34, 3) ("helperStatefulShutdown: %s #%d is CLOSING.\n",
559 hlp->id_name, srv->index + 1);
560 continue;
561 }
562 if (srv->flags.reserved != S_HELPER_FREE) {
563 debug(34, 3) ("helperStatefulShutdown: %s #%d is RESERVED.\n",
564 hlp->id_name, srv->index + 1);
565 continue;
566 }
567 if (srv->deferred_requests) {
568 debug(34, 3) ("helperStatefulShutdown: %s #%d has DEFERRED requests.\n",
569 hlp->id_name, srv->index + 1);
570 continue;
571 }
572 srv->flags.closing = 1;
357099e5 573 /* the rest of the details is dealt with in the helperStatefulServerFree
574 * close handler
575 */
576 comm_close(srv->rfd);
94439e4e 577 }
578}
579
580
1f5f60dd 581helper *
582helperCreate(const char *name)
583{
28c60158 584 helper *hlp;
72711e31 585 hlp = cbdataAlloc(helper);
1f5f60dd 586 hlp->id_name = name;
587 return hlp;
588}
589
94439e4e 590statefulhelper *
591helperStatefulCreate(const char *name)
592{
593 statefulhelper *hlp;
72711e31 594 hlp = cbdataAlloc(statefulhelper);
94439e4e 595 hlp->id_name = name;
596 return hlp;
597}
598
599
1f5f60dd 600void
601helperFree(helper * hlp)
602{
5dae8514 603 if (!hlp)
604 return;
1f5f60dd 605 /* note, don't free hlp->name, it probably points to static memory */
fe73896c 606 if (hlp->queue.head)
17bb3486 607 debug(84, 0) ("WARNING: freeing %s helper with %d requests queued\n",
fe73896c 608 hlp->id_name, hlp->stats.queue_size);
1f5f60dd 609 cbdataFree(hlp);
610}
611
94439e4e 612void
613helperStatefulFree(statefulhelper * hlp)
614{
5dae8514 615 if (!hlp)
616 return;
94439e4e 617 /* note, don't free hlp->name, it probably points to static memory */
618 if (hlp->queue.head)
17bb3486 619 debug(84, 0) ("WARNING: freeing %s helper with %d requests queued\n",
94439e4e 620 hlp->id_name, hlp->stats.queue_size);
621 cbdataFree(hlp);
622}
623
624
74addf6c 625/* ====================================================================== */
626/* LOCAL FUNCTIONS */
627/* ====================================================================== */
628
629static void
1f5f60dd 630helperServerFree(int fd, void *data)
74addf6c 631{
e6ccf245 632 helper_server *srv = (helper_server *)data;
74addf6c 633 helper *hlp = srv->parent;
ac750329 634 helper_request *r;
74addf6c 635 assert(srv->rfd == fd);
636 if (srv->buf) {
db1cd23c 637 memFree(srv->buf, MEM_8K_BUF);
74addf6c 638 srv->buf = NULL;
639 }
ac750329 640 if ((r = srv->request)) {
fa80a8ef 641 void *cbdata;
642 if (cbdataReferenceValidDone(r->data, &cbdata))
643 r->callback(cbdata, srv->buf);
ac750329 644 helperRequestFree(r);
63758217 645 srv->request = NULL;
ac750329 646 }
3cdb7cd0 647 if (srv->wfd != srv->rfd && srv->wfd != -1)
74addf6c 648 comm_close(srv->wfd);
649 dlinkDelete(&srv->link, &hlp->servers);
74addf6c 650 hlp->n_running--;
651 assert(hlp->n_running >= 0);
1f5f60dd 652 if (!srv->flags.shutdown) {
653 debug(34, 0) ("WARNING: %s #%d (FD %d) exited\n",
14e87a44 654 hlp->id_name, srv->index + 1, fd);
1f5f60dd 655 if (hlp->n_running < hlp->n_to_start / 2)
14e87a44 656 fatalf("Too few %s processes are running", hlp->id_name);
657 }
fa80a8ef 658 cbdataReferenceDone(srv->parent);
14e87a44 659 cbdataFree(srv);
74addf6c 660}
661
94439e4e 662static void
663helperStatefulServerFree(int fd, void *data)
664{
e6ccf245 665 helper_stateful_server *srv = (helper_stateful_server *)data;
94439e4e 666 statefulhelper *hlp = srv->parent;
667 helper_stateful_request *r;
668 assert(srv->rfd == fd);
669 if (srv->buf) {
670 memFree(srv->buf, MEM_8K_BUF);
671 srv->buf = NULL;
672 }
673 if ((r = srv->request)) {
fa80a8ef 674 void *cbdata;
675 if (cbdataReferenceValidDone(r->data, &cbdata))
676 r->callback(cbdata, srv, srv->buf);
94439e4e 677 helperStatefulRequestFree(r);
678 srv->request = NULL;
679 }
3c641669 680 /* TODO: walk the local queue of requests and carry them all out */
94439e4e 681 if (srv->wfd != srv->rfd && srv->wfd != -1)
682 comm_close(srv->wfd);
683 dlinkDelete(&srv->link, &hlp->servers);
684 hlp->n_running--;
685 assert(hlp->n_running >= 0);
686 if (!srv->flags.shutdown) {
687 debug(34, 0) ("WARNING: %s #%d (FD %d) exited\n",
688 hlp->id_name, srv->index + 1, fd);
689 if (hlp->n_running < hlp->n_to_start / 2)
690 fatalf("Too few %s processes are running", hlp->id_name);
691 }
692 if (srv->data != NULL)
693 memPoolFree(hlp->datapool, srv->data);
fa80a8ef 694 cbdataReferenceDone(srv->parent);
94439e4e 695 cbdataFree(srv);
696}
697
698
74addf6c 699static void
700helperHandleRead(int fd, void *data)
701{
702 int len;
703 char *t = NULL;
e6ccf245 704 helper_server *srv = (helper_server *)data;
74addf6c 705 helper_request *r;
706 helper *hlp = srv->parent;
707 assert(fd == srv->rfd);
fa80a8ef 708 assert(cbdataReferenceValid(data));
83704487 709 statCounter.syscalls.sock.reads++;
1f7c9178 710 len = FD_READ_METHOD(fd, srv->buf + srv->offset, srv->buf_sz - srv->offset);
74addf6c 711 fd_bytes(fd, len, FD_READ);
17bb3486 712 debug(84, 5) ("helperHandleRead: %d bytes from %s #%d.\n",
74addf6c 713 len, hlp->id_name, srv->index + 1);
714 if (len <= 0) {
715 if (len < 0)
716 debug(50, 1) ("helperHandleRead: FD %d read: %s\n", fd, xstrerror());
717 comm_close(fd);
718 return;
719 }
720 srv->offset += len;
721 srv->buf[srv->offset] = '\0';
722 r = srv->request;
723 if (r == NULL) {
724 /* someone spoke without being spoken to */
17bb3486 725 debug(84, 1) ("helperHandleRead: unexpected read from %s #%d, %d bytes\n",
74addf6c 726 hlp->id_name, srv->index + 1, len);
727 srv->offset = 0;
728 } else if ((t = strchr(srv->buf, '\n'))) {
729 /* end of reply found */
fa80a8ef 730 HLPCB *callback;
731 void *cbdata;
17bb3486 732 debug(84, 3) ("helperHandleRead: end of reply found\n");
74addf6c 733 *t = '\0';
fa80a8ef 734 callback = r->callback;
735 r->callback = NULL;
736 if (cbdataReferenceValidDone(r->data, &cbdata))
737 callback(cbdata, srv->buf);
74addf6c 738 srv->flags.busy = 0;
739 srv->offset = 0;
740 helperRequestFree(r);
63758217 741 srv->request = NULL;
74addf6c 742 hlp->stats.replies++;
a15d85ea 743 srv->answer_time = current_time;
74addf6c 744 hlp->stats.avg_svc_time =
745 intAverage(hlp->stats.avg_svc_time,
a15d85ea 746 tvSubUsec(srv->dispatch_time, current_time),
74addf6c 747 hlp->stats.replies, REDIRECT_AV_FACTOR);
3cdb7cd0 748 if (srv->flags.shutdown) {
70160b49 749 int wfd = srv->wfd;
3cdb7cd0 750 srv->wfd = -1;
70160b49 751 comm_close(wfd);
3cdb7cd0 752 } else
c68e9c6b 753 helperKickQueue(hlp);
74addf6c 754 } else {
755 commSetSelect(srv->rfd, COMM_SELECT_READ, helperHandleRead, srv, 0);
756 }
74addf6c 757}
758
94439e4e 759static void
760helperStatefulHandleRead(int fd, void *data)
761{
762 int len;
763 char *t = NULL;
e6ccf245 764 helper_stateful_server *srv = (helper_stateful_server *)data;
94439e4e 765 helper_stateful_request *r;
766 statefulhelper *hlp = srv->parent;
767 assert(fd == srv->rfd);
fa80a8ef 768 assert(cbdataReferenceValid(data));
94439e4e 769 statCounter.syscalls.sock.reads++;
e7981f61 770 len = FD_READ_METHOD(fd, srv->buf + srv->offset, srv->buf_sz - srv->offset);
94439e4e 771 fd_bytes(fd, len, FD_READ);
17bb3486 772 debug(84, 5) ("helperStatefulHandleRead: %d bytes from %s #%d.\n",
94439e4e 773 len, hlp->id_name, srv->index + 1);
774 if (len <= 0) {
775 if (len < 0)
776 debug(50, 1) ("helperStatefulHandleRead: FD %d read: %s\n", fd, xstrerror());
777 comm_close(fd);
778 return;
779 }
780 srv->offset += len;
781 srv->buf[srv->offset] = '\0';
782 r = srv->request;
783 if (r == NULL) {
784 /* someone spoke without being spoken to */
17bb3486 785 debug(84, 1) ("helperStatefulHandleRead: unexpected read from %s #%d, %d bytes\n",
94439e4e 786 hlp->id_name, srv->index + 1, len);
787 srv->offset = 0;
788 } else if ((t = strchr(srv->buf, '\n'))) {
789 /* end of reply found */
17bb3486 790 debug(84, 3) ("helperStatefulHandleRead: end of reply found\n");
94439e4e 791 *t = '\0';
fa80a8ef 792 if (cbdataReferenceValid(r->data)) {
94439e4e 793 switch ((r->callback(r->data, srv, srv->buf))) { /*if non-zero reserve helper */
794 case S_HELPER_UNKNOWN:
795 fatal("helperStatefulHandleRead: either a non-state aware callback was give to the stateful helper routines, or an uninitialised callback response was recieved.\n");
796 break;
797 case S_HELPER_RELEASE: /* helper finished with */
60d096f4 798 if (!srv->deferred_requests && !srv->queue.head) {
94439e4e 799 srv->flags.reserved = S_HELPER_FREE;
800 if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
801 srv->parent->OnEmptyQueue(srv->data);
17bb3486 802 debug(84, 5) ("StatefulHandleRead: releasing %s #%d\n", hlp->id_name, srv->index + 1);
94439e4e 803 } else {
804 srv->flags.reserved = S_HELPER_DEFERRED;
17bb3486 805 debug(84, 5) ("StatefulHandleRead: outstanding deferred requests on %s #%d. reserving for deferred requests.\n", hlp->id_name, srv->index + 1);
94439e4e 806 }
807 break;
808 case S_HELPER_RESERVE: /* 'pin' this helper for the caller */
809 if (!srv->queue.head) {
60d096f4 810 assert(srv->deferred_requests == 0);
94439e4e 811 srv->flags.reserved = S_HELPER_RESERVED;
17bb3486 812 debug(84, 5) ("StatefulHandleRead: reserving %s #%d\n", hlp->id_name, srv->index + 1);
94439e4e 813 } else {
814 fatal("StatefulHandleRead: Callback routine attempted to reserve a stateful helper with deferred requests. This can lead to deadlock.\n");
815 }
816 break;
817 case S_HELPER_DEFER:
818 /* the helper is still needed, but can
819 * be used for other requests in the meantime.
820 */
821 srv->flags.reserved = S_HELPER_DEFERRED;
822 srv->deferred_requests++;
60d096f4 823 srv->stats.deferbycb++;
17bb3486 824 debug(84, 5) ("StatefulHandleRead: reserving %s #%d for deferred requests.\n", hlp->id_name, srv->index + 1);
94439e4e 825 break;
826 default:
827 fatal("helperStatefulHandleRead: unknown stateful helper callback result.\n");
828 }
829
830 } else {
17bb3486 831 debug(84, 1) ("StatefulHandleRead: no callback data registered\n");
94439e4e 832 }
833 srv->flags.busy = 0;
834 srv->offset = 0;
835 helperStatefulRequestFree(r);
836 srv->request = NULL;
837 hlp->stats.replies++;
838 hlp->stats.avg_svc_time =
839 intAverage(hlp->stats.avg_svc_time,
840 tvSubMsec(srv->dispatch_time, current_time),
841 hlp->stats.replies, REDIRECT_AV_FACTOR);
5d146f7d 842 if (srv->flags.shutdown
843 && srv->flags.reserved == S_HELPER_FREE
844 && !srv->deferred_requests) {
70160b49 845 int wfd = srv->wfd;
94439e4e 846 srv->wfd = -1;
70160b49 847 comm_close(wfd);
94439e4e 848 } else {
849 if (srv->queue.head)
850 helperStatefulServerKickQueue(srv);
851 else
852 helperStatefulKickQueue(hlp);
853 }
854 } else {
855 commSetSelect(srv->rfd, COMM_SELECT_READ, helperStatefulHandleRead, srv, 0);
856 }
857}
858
74addf6c 859static void
860Enqueue(helper * hlp, helper_request * r)
861{
e6ccf245 862 dlink_node *link = (dlink_node *)memAllocate(MEM_DLINK_NODE);
74addf6c 863 dlinkAddTail(r, link, &hlp->queue);
864 hlp->stats.queue_size++;
865 if (hlp->stats.queue_size < hlp->n_running)
866 return;
867 if (squid_curtime - hlp->last_queue_warn < 600)
868 return;
fe73896c 869 if (shutting_down || reconfiguring)
870 return;
74addf6c 871 hlp->last_queue_warn = squid_curtime;
c916b75b 872 debug(84, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
873 debug(84, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
74addf6c 874 if (hlp->stats.queue_size > hlp->n_running * 2)
875 fatalf("Too many queued %s requests", hlp->id_name);
c916b75b 876 debug(84, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
74addf6c 877}
878
94439e4e 879static void
880StatefulEnqueue(statefulhelper * hlp, helper_stateful_request * r)
881{
e6ccf245 882 dlink_node *link = (dlink_node *)memAllocate(MEM_DLINK_NODE);
94439e4e 883 dlinkAddTail(r, link, &hlp->queue);
884 hlp->stats.queue_size++;
885 if (hlp->stats.queue_size < hlp->n_running)
886 return;
893cbac6 887 if (hlp->stats.queue_size > hlp->n_running * 2)
888 fatalf("Too many queued %s requests", hlp->id_name);
94439e4e 889 if (squid_curtime - hlp->last_queue_warn < 600)
890 return;
891 if (shutting_down || reconfiguring)
892 return;
893 hlp->last_queue_warn = squid_curtime;
c916b75b 894 debug(84, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
895 debug(84, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
896 debug(84, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
94439e4e 897}
898
899static void
900StatefulServerEnqueue(helper_stateful_server * srv, helper_stateful_request * r)
901{
e6ccf245 902 dlink_node *link = (dlink_node *)memAllocate(MEM_DLINK_NODE);
94439e4e 903 dlinkAddTail(r, link, &srv->queue);
2d70df72 904/* TODO: warning if the queue on this server is more than X
905 * We don't check the queue size at the moment, because
906 * requests hitting here are deferrable
907 */
908/* hlp->stats.queue_size++;
909 * if (hlp->stats.queue_size < hlp->n_running)
910 * return;
911 * if (squid_curtime - hlp->last_queue_warn < 600)
912 * return;
913 * if (shutting_down || reconfiguring)
914 * return;
915 * hlp->last_queue_warn = squid_curtime;
c916b75b 916 * debug(84, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
917 * debug(84, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
2d70df72 918 * if (hlp->stats.queue_size > hlp->n_running * 2)
919 * fatalf("Too many queued %s requests", hlp->id_name);
c916b75b 920 * debug(84, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name); */
94439e4e 921}
922
923
74addf6c 924static helper_request *
925Dequeue(helper * hlp)
926{
927 dlink_node *link;
928 helper_request *r = NULL;
929 if ((link = hlp->queue.head)) {
e6ccf245 930 r = (helper_request *)link->data;
74addf6c 931 dlinkDelete(link, &hlp->queue);
db1cd23c 932 memFree(link, MEM_DLINK_NODE);
74addf6c 933 hlp->stats.queue_size--;
934 }
935 return r;
936}
937
94439e4e 938static helper_stateful_request *
939StatefulServerDequeue(helper_stateful_server * srv)
940{
941 dlink_node *link;
942 helper_stateful_request *r = NULL;
943 if ((link = srv->queue.head)) {
e6ccf245 944 r = (helper_stateful_request *)link->data;
94439e4e 945 dlinkDelete(link, &srv->queue);
946 memFree(link, MEM_DLINK_NODE);
947 }
948 return r;
949}
950
951static helper_stateful_request *
952StatefulDequeue(statefulhelper * hlp)
953{
954 dlink_node *link;
955 helper_stateful_request *r = NULL;
956 if ((link = hlp->queue.head)) {
e6ccf245 957 r = (helper_stateful_request *)link->data;
94439e4e 958 dlinkDelete(link, &hlp->queue);
959 memFree(link, MEM_DLINK_NODE);
960 hlp->stats.queue_size--;
961 }
962 return r;
963}
964
74addf6c 965static helper_server *
966GetFirstAvailable(helper * hlp)
967{
968 dlink_node *n;
969 helper_server *srv = NULL;
fe73896c 970 if (hlp->n_running == 0)
971 return NULL;
74addf6c 972 for (n = hlp->servers.head; n != NULL; n = n->next) {
e6ccf245 973 srv = (helper_server *)n->data;
74addf6c 974 if (srv->flags.busy)
975 continue;
976 if (!srv->flags.alive)
977 continue;
978 return srv;
979 }
980 return NULL;
981}
982
94439e4e 983static helper_stateful_server *
984StatefulGetFirstAvailable(statefulhelper * hlp)
985{
986 dlink_node *n;
987 helper_stateful_server *srv = NULL;
17bb3486 988 debug(84, 5) ("StatefulGetFirstAvailable: Running servers %d.\n", hlp->n_running);
94439e4e 989 if (hlp->n_running == 0)
990 return NULL;
991 for (n = hlp->servers.head; n != NULL; n = n->next) {
e6ccf245 992 srv = (helper_stateful_server *)n->data;
94439e4e 993 if (srv->flags.busy)
994 continue;
995 if (srv->flags.reserved == S_HELPER_RESERVED)
996 continue;
997 if (!srv->flags.alive)
998 continue;
999 if ((hlp->IsAvailable != NULL) && (srv->data != NULL) && !(hlp->IsAvailable(srv->data)))
1000 continue;
1001 return srv;
1002 }
17bb3486 1003 debug(84, 5) ("StatefulGetFirstAvailable: None available.\n");
94439e4e 1004 return NULL;
1005}
1006
1007
74addf6c 1008static void
1009helperDispatch(helper_server * srv, helper_request * r)
1010{
1011 helper *hlp = srv->parent;
fa80a8ef 1012 if (!cbdataReferenceValid(r->data)) {
17bb3486 1013 debug(84, 1) ("helperDispatch: invalid callback data\n");
74addf6c 1014 helperRequestFree(r);
1015 return;
1016 }
1017 assert(!srv->flags.busy);
1018 srv->flags.busy = 1;
1019 srv->request = r;
1020 srv->dispatch_time = current_time;
1021 comm_write(srv->wfd,
1022 r->buf,
1023 strlen(r->buf),
1024 NULL, /* Handler */
1025 NULL, /* Handler-data */
1026 NULL); /* free */
1027 commSetSelect(srv->rfd,
1028 COMM_SELECT_READ,
1029 helperHandleRead,
1030 srv, 0);
17bb3486 1031 debug(84, 5) ("helperDispatch: Request sent to %s #%d, %d bytes\n",
32754419 1032 hlp->id_name, srv->index + 1, (int) strlen(r->buf));
74addf6c 1033 srv->stats.uses++;
1034 hlp->stats.requests++;
1035}
1036
94439e4e 1037static void
1038helperStatefulDispatch(helper_stateful_server * srv, helper_stateful_request * r)
1039{
1040 statefulhelper *hlp = srv->parent;
fa80a8ef 1041 if (!cbdataReferenceValid(r->data)) {
17bb3486 1042 debug(84, 1) ("helperStatefulDispatch: invalid callback data\n");
94439e4e 1043 helperStatefulRequestFree(r);
1044 return;
1045 }
17bb3486 1046 debug(84, 9) ("helperStatefulDispatch busying helper %s #%d\n", hlp->id_name, srv->index + 1);
94439e4e 1047 if (r->placeholder == 1) {
1048 /* a callback is needed before this request can _use_ a helper. */
721b0310 1049 /* we don't care about releasing/deferring this helper. The request NEVER
1050 * gets to the helper. So we throw away the return code */
1051 r->callback(r->data, srv, NULL);
1052 /* throw away the placeholder */
1053 helperStatefulRequestFree(r);
1054 /* and push the queue. Note that the callback may have submitted a new
1055 * request to the helper which is why we test for the request*/
1056 if (srv->request == NULL) {
5d146f7d 1057 if (srv->flags.shutdown
1058 && srv->flags.reserved == S_HELPER_FREE
1059 && !srv->deferred_requests) {
9272e015 1060 int wfd = srv->wfd;
721b0310 1061 srv->wfd = -1;
9272e015 1062 comm_close(wfd);
721b0310 1063 } else {
1064 if (srv->queue.head)
1065 helperStatefulServerKickQueue(srv);
1066 else
1067 helperStatefulKickQueue(hlp);
94439e4e 1068 }
1069 }
1070 return;
1071 }
1072 srv->flags.busy = 1;
1073 srv->request = r;
1074 srv->dispatch_time = current_time;
1075 comm_write(srv->wfd,
1076 r->buf,
1077 strlen(r->buf),
1078 NULL, /* Handler */
1079 NULL, /* Handler-data */
1080 NULL); /* free */
1081 commSetSelect(srv->rfd,
1082 COMM_SELECT_READ,
1083 helperStatefulHandleRead,
1084 srv, 0);
17bb3486 1085 debug(84, 5) ("helperStatefulDispatch: Request sent to %s #%d, %d bytes\n",
32754419 1086 hlp->id_name, srv->index + 1, (int) strlen(r->buf));
94439e4e 1087 srv->stats.uses++;
1088 hlp->stats.requests++;
1089}
1090
1091
74addf6c 1092static void
1093helperKickQueue(helper * hlp)
1094{
1095 helper_request *r;
1096 helper_server *srv;
1097 while ((srv = GetFirstAvailable(hlp)) && (r = Dequeue(hlp)))
1098 helperDispatch(srv, r);
1099}
1100
94439e4e 1101static void
1102helperStatefulKickQueue(statefulhelper * hlp)
1103{
1104 helper_stateful_request *r;
1105 helper_stateful_server *srv;
1106 while ((srv = StatefulGetFirstAvailable(hlp)) && (r = StatefulDequeue(hlp)))
1107 helperStatefulDispatch(srv, r);
1108}
1109
1110static void
1111helperStatefulServerKickQueue(helper_stateful_server * srv)
1112{
1113 helper_stateful_request *r;
1114 if ((r = StatefulServerDequeue(srv)))
1115 helperStatefulDispatch(srv, r);
1116}
1117
74addf6c 1118static void
1119helperRequestFree(helper_request * r)
1120{
fa80a8ef 1121 cbdataReferenceDone(r->data);
74addf6c 1122 xfree(r->buf);
db1cd23c 1123 memFree(r, MEM_HELPER_REQUEST);
74addf6c 1124}
94439e4e 1125
1126static void
1127helperStatefulRequestFree(helper_stateful_request * r)
1128{
fa80a8ef 1129 cbdataReferenceDone(r->data);
94439e4e 1130 xfree(r->buf);
1131 memFree(r, MEM_HELPER_STATEFUL_REQUEST);
1132}