2015-04-13 15:11:11 +00:00
|
|
|
/*
|
|
|
|
* Functions managing applets
|
|
|
|
*
|
|
|
|
* Copyright 2000-2015 Willy Tarreau <w@1wt.eu>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <common/config.h>
|
|
|
|
#include <common/mini-clist.h>
|
|
|
|
#include <proto/applet.h>
|
BUG/MAJOR: Fix how the list of entities waiting for a buffer is handled
When an entity tries to get a buffer, if it cannot be allocted, for example
because the number of buffers which may be allocated per process is limited,
this entity is added in a list (called <buffer_wq>) and wait for an available
buffer.
Historically, the <buffer_wq> list was logically attached to streams because it
were the only entities likely to be added in it. Now, applets can also be
waiting for a free buffer. And with filters, we could imagine to have more other
entities waiting for a buffer. So it make sense to have a generic list.
Anyway, with the current design there is a bug. When an applet failed to get a
buffer, it will wait. But we add the stream attached to the applet in
<buffer_wq>, instead of the applet itself. So when a buffer is available, we
wake up the stream and not the waiting applet. So, it is possible to have
waiting applets and never awakened.
So, now, <buffer_wq> is independant from streams. And we really add the waiting
entity in <buffer_wq>. To be generic, the entity is responsible to define the
callback used to awaken it.
In addition, applets will still request an input buffer when they become
active. But they will not be sleeped anymore if no buffer are available. So this
is the responsibility to the applet I/O handler to check if this buffer is
allocated or not. This way, an applet can decide if this buffer is required or
not and can do additional processing if not.
[wt: backport to 1.7 and 1.6]
2016-12-09 16:30:18 +00:00
|
|
|
#include <proto/channel.h>
|
2015-04-19 07:59:31 +00:00
|
|
|
#include <proto/stream.h>
|
|
|
|
#include <proto/stream_interface.h>
|
2018-05-25 14:58:52 +00:00
|
|
|
#include <proto/task.h>
|
2015-04-13 15:11:11 +00:00
|
|
|
|
2016-12-06 08:13:22 +00:00
|
|
|
unsigned int nb_applets = 0;
|
2017-06-19 10:38:55 +00:00
|
|
|
|
2018-11-06 16:32:37 +00:00
|
|
|
/* Callback used to wake up an applet when a buffer is available. The applet
|
|
|
|
* <appctx> is woken up if an input buffer was requested for the associated
|
|
|
|
* stream interface. In this case the buffer is immediately allocated and the
|
|
|
|
* function returns 1. Otherwise it returns 0. Note that this automatically
|
|
|
|
* covers multiple wake-up attempts by ensuring that the same buffer will not
|
|
|
|
* be accounted for multiple times.
|
|
|
|
*/
|
|
|
|
int appctx_buf_available(void *arg)
|
|
|
|
{
|
|
|
|
struct appctx *appctx = arg;
|
|
|
|
struct stream_interface *si = appctx->owner;
|
|
|
|
|
|
|
|
/* allocation requested ? */
|
2018-11-14 14:12:08 +00:00
|
|
|
if (!(si->flags & SI_FL_RXBLK_BUFF))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
si_rx_buff_rdy(si);
|
|
|
|
|
|
|
|
/* was already allocated another way ? if so, don't take this one */
|
|
|
|
if (c_size(si_ic(si)) || si_ic(si)->pipe)
|
2018-11-06 16:32:37 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* allocation possible now ? */
|
2018-11-14 14:12:08 +00:00
|
|
|
if (!b_alloc_margin(&si_ic(si)->buf, global.tune.reserved_bufs)) {
|
|
|
|
si_rx_buff_blk(si);
|
2018-11-06 16:32:37 +00:00
|
|
|
return 0;
|
2018-11-14 14:12:08 +00:00
|
|
|
}
|
2018-11-06 16:32:37 +00:00
|
|
|
|
|
|
|
task_wakeup(appctx->t, TASK_WOKEN_RES);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Default applet handler */
|
2018-05-25 14:58:52 +00:00
|
|
|
struct task *task_run_applet(struct task *t, void *context, unsigned short state)
|
2015-04-19 07:59:31 +00:00
|
|
|
{
|
2018-05-25 14:58:52 +00:00
|
|
|
struct appctx *app = context;
|
|
|
|
struct stream_interface *si = app->owner;
|
2015-04-19 07:59:31 +00:00
|
|
|
|
2018-05-25 14:58:52 +00:00
|
|
|
if (app->state & APPLET_WANT_DIE) {
|
|
|
|
__appctx_free(app);
|
|
|
|
return NULL;
|
2017-06-26 14:36:53 +00:00
|
|
|
}
|
2018-05-25 14:58:52 +00:00
|
|
|
|
|
|
|
/* We always pretend the applet can't get and doesn't want to
|
|
|
|
* put, it's up to it to change this if needed. This ensures
|
|
|
|
* that one applet which ignores any event will not spin.
|
2015-09-25 15:56:16 +00:00
|
|
|
*/
|
2018-11-06 17:46:37 +00:00
|
|
|
si_cant_get(si);
|
2018-11-14 16:54:13 +00:00
|
|
|
si_rx_endp_done(si);
|
2015-04-19 07:59:31 +00:00
|
|
|
|
2018-11-14 14:12:08 +00:00
|
|
|
/* Now we'll try to allocate the input buffer. We wake up the applet in
|
|
|
|
* all cases. So this is the applet's responsibility to check if this
|
|
|
|
* buffer was allocated or not. This leaves a chance for applets to do
|
|
|
|
* some other processing if needed. The applet doesn't have anything to
|
|
|
|
* do if it needs the buffer, it will be called again upon readiness.
|
|
|
|
*/
|
|
|
|
if (!si_alloc_ibuf(si, &app->buffer_wait))
|
2018-11-14 16:54:13 +00:00
|
|
|
si_rx_endp_more(si);
|
2018-11-14 14:12:08 +00:00
|
|
|
|
2018-05-25 14:58:52 +00:00
|
|
|
app->applet->fct(app);
|
|
|
|
si_applet_wake_cb(si);
|
|
|
|
channel_release_buffer(si_ic(si), &app->buffer_wait);
|
|
|
|
return t;
|
2015-04-19 07:59:31 +00:00
|
|
|
}
|
2017-06-19 10:38:55 +00:00
|
|
|
|