BUG/MAJOR: applet: use a separate run queue to maintain list integrity

If an applet wakes up and causes the next one to sleep, the active list
is corrupted and cannot be scanned anymore, as the process then loops
over the next element.

In order to avoid this problem, we move the active applet list to a run
queue and reinit the active list. Only the first element of this queue
is checked, and if the element is not removed, it is removed and requeued
into the active list.

Since we're using a distinct list, if an applet wants to requeue another
applet into the active list, it properly gets added to the active list
and not to the run queue.

This stops the infinite loop issue that could be caused with Lua applets,
and in any future configuration where two applets could be attached
together.
This commit is contained in:
Willy Tarreau 2015-09-25 17:56:16 +02:00
parent 64bca9d36a
commit 9994238adc

View File

@ -20,13 +20,29 @@
#include <proto/stream_interface.h>
struct list applet_active_queue = LIST_HEAD_INIT(applet_active_queue);
struct list applet_run_queue = LIST_HEAD_INIT(applet_run_queue);
void applet_run_active()
{
struct appctx *curr, *back;
struct appctx *curr;
struct stream_interface *si;
list_for_each_entry_safe(curr, back, &applet_active_queue, runq) {
if (LIST_ISEMPTY(&applet_active_queue))
return;
/* move active queue to run queue */
applet_active_queue.n->p = &applet_run_queue;
applet_active_queue.p->n = &applet_run_queue;
applet_run_queue = applet_active_queue;
LIST_INIT(&applet_active_queue);
/* The list is only scanned from the head. This guarantees that if any
* applet removes another one, there is no side effect while walking
* through the list.
*/
while (!LIST_ISEMPTY(&applet_run_queue)) {
curr = LIST_ELEM(applet_run_queue.n, typeof(curr), runq);
si = curr->owner;
/* now we'll need a buffer */
@ -46,5 +62,11 @@ void applet_run_active()
curr->applet->fct(curr);
si_applet_done(si);
if (applet_run_queue.n == &curr->runq) {
/* curr was left in the list, move it back to the active list */
LIST_DEL(&curr->runq);
LIST_ADDQ(&applet_active_queue, &curr->runq);
}
}
}