* so that the compiler can optimize it away if changed immediately after the
* call to this function. By default, it is set to the full size of the buffer.
* This implies that buffer_init() must only be called once ->size is set !
- * The BF_EMPTY flags is set.
+ * The BF_OUT_EMPTY flags is set.
*/
static inline void buffer_init(struct buffer *buf)
{
buf->pipe = NULL;
buf->analysers = 0;
buf->cons = NULL;
- buf->flags = BF_EMPTY;
+ buf->flags = BF_OUT_EMPTY;
buf->r = buf->lr = buf->w = buf->data;
buf->max_len = buf->size;
}
-/* returns 1 if the buffer is empty, 0 otherwise */
-static inline int buffer_isempty(const struct buffer *buf)
-{
- return buf->l == 0;
-}
-
-/* returns 1 if the buffer is full, 0 otherwise */
-static inline int buffer_isfull(const struct buffer *buf) {
- return buf->l == buf->size;
-}
-
/* Check buffer timeouts, and set the corresponding flags. The
* likely/unlikely have been optimized for fastest normal path.
* The read/write timeouts are not set if there was activity on the buffer.
{
unsigned int data_left;
+ if (!bytes)
+ return;
+ buf->flags &= ~BF_OUT_EMPTY;
data_left = buf->l - buf->send_max;
if (data_left >= bytes) {
buf->send_max += bytes;
{
if (buf->send_max < buf->l)
buf->send_max = buf->l;
+ if (buf->send_max)
+ buf->flags &= ~BF_OUT_EMPTY;
}
/* Erase any content from buffer <buf> and adjusts flags accordingly. Note
buf->to_forward = 0;
buf->r = buf->lr = buf->w = buf->data;
buf->l = 0;
- buf->flags |= BF_EMPTY | BF_FULL;
- if (buf->max_len)
- buf->flags &= ~BF_FULL;
+ buf->flags &= ~(BF_FULL | BF_OUT_EMPTY);
+ if (!buf->pipe)
+ buf->flags |= BF_OUT_EMPTY;
+ if (!buf->max_len)
+ buf->flags |= BF_FULL;
}
/* Cut the "tail" of the buffer, which means strip it to the length of unsent
if (buf->r >= buf->data + buf->size)
buf->r -= buf->size;
buf->lr = buf->r;
- buf->flags &= ~(BF_EMPTY|BF_FULL);
+ buf->flags &= ~BF_FULL;
if (buf->l >= buf->max_len)
buf->flags |= BF_FULL;
}
buf->w = buf->data; /* wrap around the buffer */
buf->l -= len;
- if (!buf->l) {
+ if (!buf->l)
buf->r = buf->w = buf->lr = buf->data;
- if (!buf->pipe)
- buf->flags |= BF_EMPTY;
- }
if (buf->l < buf->max_len)
buf->flags &= ~BF_FULL;
buf->send_max -= len;
+ if (!buf->send_max && !buf->pipe)
+ buf->flags |= BF_OUT_EMPTY;
}
/*
if (buf->flags & BF_FULL)
return 0;
- if (buf->flags & BF_EMPTY) {
- buf->flags &= ~BF_EMPTY;
- buf->r = buf->w = buf->lr = buf->data;
- }
-
*buf->r = c;
buf->l++;
if ((signed)(buf->to_forward - 1) >= 0) {
buf->to_forward--;
buf->send_max++;
+ buf->flags &= ~BF_OUT_EMPTY;
}
buf->total++;
#define BF_WRITE_ERROR 0x000800 /* unrecoverable error on consumer side */
#define BF_WRITE_ACTIVITY (BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_WRITE_ERROR)
-#define BF_EMPTY 0x001000 /* buffer is empty */
+#define BF_OUT_EMPTY 0x001000 /* send_max and pipe are empty. Set by last change. */
#define BF_SHUTW 0x002000 /* consumer has already shut down */
#define BF_SHUTW_NOW 0x004000 /* the consumer must shut down for writes ASAP */
#define BF_AUTO_CLOSE 0x008000 /* producer can forward shutdown to other side */
#define BF_MASK_ANALYSER (BF_READ_ATTACHED|BF_READ_ACTIVITY|BF_READ_TIMEOUT|BF_ANA_TIMEOUT|BF_WRITE_ACTIVITY)
/* Mask for static flags which are not events, but might change during processing */
-#define BF_MASK_STATIC (BF_EMPTY|BF_FULL|BF_HIJACK|BF_AUTO_CLOSE|BF_AUTO_CONNECT|BF_SHUTR|BF_SHUTW|BF_SHUTR_NOW|BF_SHUTW_NOW)
+#define BF_MASK_STATIC (BF_OUT_EMPTY|BF_FULL|BF_HIJACK|BF_AUTO_CLOSE|BF_AUTO_CONNECT|BF_SHUTR|BF_SHUTW|BF_SHUTR_NOW|BF_SHUTW_NOW)
/* Analysers (buffer->analysers).
if (buf->r == buf->data + buf->size)
buf->r = buf->data;
- buf->flags &= ~(BF_EMPTY|BF_FULL);
- if (buf->l == 0)
- buf->flags |= BF_EMPTY;
+ buf->flags &= ~(BF_OUT_EMPTY|BF_FULL);
if (buf->l >= buf->max_len)
buf->flags |= BF_FULL;
int fwd = MIN(buf->to_forward, len);
buf->send_max += fwd;
buf->to_forward -= fwd;
+ buf->flags &= ~BF_OUT_EMPTY;
}
if (buf->r == buf->data + buf->size)
buf->r = buf->data;
- buf->flags &= ~(BF_EMPTY|BF_FULL);
+ buf->flags &= ~BF_FULL;
if (buf->l >= buf->max_len)
buf->flags |= BF_FULL;
* <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
* the shift value (positive or negative) is returned.
* If there's no space left, the move is not done.
+ * The function does not adjust ->send_max nor BF_OUT_EMPTY because it does not
+ * make sense to use it on data scheduled to be sent.
*
*/
int buffer_replace(struct buffer *b, char *pos, char *end, const char *str)
if (b->lr > pos) b->lr += delta;
b->l += delta;
- b->flags &= ~(BF_EMPTY|BF_FULL);
+ b->flags &= ~BF_FULL;
if (b->l == 0)
- b->flags |= BF_EMPTY;
+ b->r = b->w = b->lr = b->data;
if (b->l >= b->max_len)
b->flags |= BF_FULL;
if (b->lr > pos) b->lr += delta;
b->l += delta;
- b->flags &= ~(BF_EMPTY|BF_FULL);
+ b->flags &= ~BF_FULL;
if (b->l == 0)
- b->flags |= BF_EMPTY;
+ b->r = b->w = b->lr = b->data;
if (b->l >= b->max_len)
b->flags |= BF_FULL;
if (b->lr > pos) b->lr += delta;
b->l += delta;
- b->flags &= ~(BF_EMPTY|BF_FULL);
- if (b->l == 0)
- b->flags |= BF_EMPTY;
+ b->flags &= ~BF_FULL;
if (b->l >= b->max_len)
b->flags |= BF_FULL;
/* OK, maybe we want to abort */
if (unlikely((rep->flags & BF_SHUTW) ||
((req->flags & BF_SHUTW_NOW) && /* FIXME: this should not prevent a connection from establishing */
- (((req->flags & (BF_EMPTY|BF_WRITE_ACTIVITY)) == BF_EMPTY) ||
+ (((req->flags & (BF_OUT_EMPTY|BF_WRITE_ACTIVITY)) == BF_OUT_EMPTY) ||
s->be->options & PR_O_ABRT_CLOSE)))) {
/* give up */
si->shutw(si);
/* Connection remains in queue, check if we have to abort it */
if ((si->ob->flags & (BF_READ_ERROR)) ||
((si->ob->flags & BF_SHUTW_NOW) && /* empty and client aborted */
- (si->ob->flags & BF_EMPTY || s->be->options & PR_O_ABRT_CLOSE))) {
+ (si->ob->flags & BF_OUT_EMPTY || s->be->options & PR_O_ABRT_CLOSE))) {
/* give up */
si->exp = TICK_ETERNITY;
s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
/* Connection request might be aborted */
if ((si->ob->flags & (BF_READ_ERROR)) ||
((si->ob->flags & BF_SHUTW_NOW) && /* empty and client aborted */
- (si->ob->flags & BF_EMPTY || s->be->options & PR_O_ABRT_CLOSE))) {
+ (si->ob->flags & BF_OUT_EMPTY || s->be->options & PR_O_ABRT_CLOSE))) {
/* give up */
si->exp = TICK_ETERNITY;
si->shutr(si);
((s->req->cons->state == SI_ST_EST) &&
(s->be->options & PR_O_FORCE_CLO) &&
(s->rep->flags & BF_READ_ACTIVITY))))
- buffer_shutw_now(s->req);
+ buffer_shutw_now(s->req);
}
/* shutdown(write) pending */
- if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_EMPTY)) == (BF_SHUTW_NOW|BF_EMPTY)))
+ if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_OUT_EMPTY)) == (BF_SHUTW_NOW|BF_OUT_EMPTY)))
s->req->cons->shutw(s->req->cons);
/* shutdown(write) done on server side, we must stop the client too */
*/
if (s->req->cons->state == SI_ST_INI) {
if (!(s->req->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
- if ((s->req->flags & BF_AUTO_CONNECT) ||
- (s->req->send_max || s->req->pipe)) {
+ if ((s->req->flags & (BF_AUTO_CONNECT|BF_OUT_EMPTY)) != BF_OUT_EMPTY) {
/* If we have a ->connect method, we need to perform a connection request,
* otherwise we immediately switch to the connected state.
*/
buffer_shutw_now(s->rep);
/* shutdown(write) pending */
- if (unlikely((s->rep->flags & (BF_SHUTW|BF_EMPTY|BF_SHUTW_NOW)) == (BF_EMPTY|BF_SHUTW_NOW)))
+ if (unlikely((s->rep->flags & (BF_SHUTW|BF_OUT_EMPTY|BF_SHUTW_NOW)) == (BF_OUT_EMPTY|BF_SHUTW_NOW)))
s->rep->cons->shutw(s->rep->cons);
/* shutdown(write) done on the client side, we must stop the server too */
* BF_READ_NULL
* BF_READ_PARTIAL
* BF_WRITE_PARTIAL (during copy)
- * BF_EMPTY (during copy)
+ * BF_OUT_EMPTY (during copy)
* SI_FL_ERR
* SI_FL_WAIT_ROOM
* (SI_FL_WAIT_RECV)
b->total += ret;
b->pipe->data += ret;
b->flags |= BF_READ_PARTIAL;
- b->flags &= ~BF_EMPTY; /* to prevent shutdowns */
+ b->flags &= ~BF_OUT_EMPTY;
if (b->pipe->data >= SPLICE_FULL_HINT ||
ret >= global.tune.recv_enough) {
int fwd = MIN(b->to_forward, ret);
b->send_max += fwd;
b->to_forward -= fwd;
+ b->flags &= ~BF_OUT_EMPTY;
}
if (fdtab[fd].state == FD_STCONN)
fdtab[fd].state = FD_STREADY;
b->flags |= BF_READ_PARTIAL;
- b->flags &= ~BF_EMPTY;
if (b->r == b->data + b->size) {
b->r = b->data; /* wrap around the buffer */
out_wakeup:
/* We might have some data the consumer is waiting for */
- if ((b->send_max || b->pipe) && (b->cons->flags & SI_FL_WAIT_DATA)) {
+ if (!(b->flags & BF_OUT_EMPTY) && (b->cons->flags & SI_FL_WAIT_DATA)) {
int last_len = b->pipe ? b->pipe->data : 0;
b->cons->chk_snd(b->cons);
/* At this point, the pipe is empty, but we may still have data pending
* in the normal buffer.
*/
- if (!b->l) {
- b->flags |= BF_EMPTY;
- return retval;
- }
#endif
- if (!b->send_max)
+ if (!b->send_max) {
+ b->flags |= BF_OUT_EMPTY;
return retval;
+ }
/* when we're in this loop, we already know that there is no spliced
* data left, and that there are sendable buffered data.
if (likely(b->l < b->max_len))
b->flags &= ~BF_FULL;
- if (likely(!b->l)) {
+ if (likely(!b->l))
/* optimize data alignment in the buffer */
b->r = b->w = b->lr = b->data;
- if (likely(!b->pipe))
- b->flags |= BF_EMPTY;
- }
b->send_max -= ret;
- if (!b->send_max || !b->l)
+ if (!b->send_max) {
+ if (likely(!b->pipe))
+ b->flags |= BF_OUT_EMPTY;
break;
+ }
/* if the system buffer is full, don't insist */
if (ret < max)
if (b->flags & BF_SHUTW)
goto out_wakeup;
- if (likely(!(b->flags & BF_EMPTY))) {
+ if (likely(!(b->flags & BF_OUT_EMPTY))) {
/* OK there are data waiting to be sent */
retval = stream_sock_write_loop(si, b);
if (retval < 0)
*/
}
- if (!b->pipe && !b->send_max) {
+ if (b->flags & BF_OUT_EMPTY) {
/* the connection is established but we can't write. Either the
* buffer is empty, or we just refrain from sending because the
* send_max limit was reached. Maybe we just wrote the last
goto out_wakeup;
}
- if ((b->flags & (BF_EMPTY|BF_SHUTW)) == BF_EMPTY)
+ if ((b->flags & (BF_SHUTW|BF_FULL|BF_HIJACK)) == 0)
si->flags |= SI_FL_WAIT_DATA;
EV_FD_CLR(fd, DIR_WR);
out_may_wakeup:
if (b->flags & BF_WRITE_ACTIVITY) {
/* update timeout if we have written something */
- if ((b->send_max || b->pipe) &&
- (b->flags & (BF_SHUTW|BF_WRITE_PARTIAL)) == BF_WRITE_PARTIAL)
+ if ((b->flags & (BF_OUT_EMPTY|BF_SHUTW|BF_WRITE_PARTIAL)) == BF_WRITE_PARTIAL)
b->wex = tick_add_ifset(now_ms, b->wto);
out_wakeup:
* any more data to forward and it's not planned to send any more.
*/
if (likely((b->flags & (BF_WRITE_NULL|BF_WRITE_ERROR|BF_SHUTW)) ||
- (!b->to_forward && !b->send_max && !b->pipe) ||
+ ((b->flags & BF_OUT_EMPTY) && !b->to_forward) ||
si->state != SI_ST_EST ||
b->prod->state != SI_ST_EST))
task_wakeup(si->owner, TASK_WOKEN_IO);
/* Check if we need to close the write side */
if (!(ob->flags & BF_SHUTW)) {
/* Write not closed, update FD status and timeout for writes */
- if ((ob->send_max == 0 && !ob->pipe) || (ob->flags & BF_EMPTY)) {
+ if (ob->flags & BF_OUT_EMPTY) {
/* stop writing */
- if ((ob->flags & (BF_EMPTY|BF_HIJACK)) == BF_EMPTY)
+ if ((ob->flags & (BF_FULL|BF_HIJACK)) == 0)
si->flags |= SI_FL_WAIT_DATA;
EV_FD_COND_C(fd, DIR_WR);
ob->wex = TICK_ETERNITY;
if (!(si->flags & SI_FL_WAIT_DATA) || /* not waiting for data */
(fdtab[si->fd].ev & FD_POLL_OUT) || /* we'll be called anyway */
- !(ob->send_max || ob->pipe)) /* called with nothing to send ! */
+ (ob->flags & BF_OUT_EMPTY)) /* called with nothing to send ! */
return;
retval = stream_sock_write_loop(si, ob);
* been sent, and that we may have to poll first. We have to do that
* too if the buffer is not empty.
*/
- if (ob->send_max == 0 && !ob->pipe) {
+ if (ob->flags & BF_OUT_EMPTY) {
/* the connection is established but we can't write. Either the
* buffer is empty, or we just refrain from sending because the
* send_max limit was reached. Maybe we just wrote the last
goto out_wakeup;
}
- if ((ob->flags & (BF_SHUTW|BF_EMPTY|BF_HIJACK)) == BF_EMPTY)
+ if ((ob->flags & (BF_SHUTW|BF_FULL|BF_HIJACK)) == 0)
si->flags |= SI_FL_WAIT_DATA;
ob->wex = TICK_ETERNITY;
}
if (likely(ob->flags & BF_WRITE_ACTIVITY)) {
/* update timeout if we have written something */
- if ((ob->send_max || ob->pipe) &&
- (ob->flags & (BF_SHUTW|BF_WRITE_PARTIAL)) == BF_WRITE_PARTIAL)
+ if ((ob->flags & (BF_OUT_EMPTY|BF_SHUTW|BF_WRITE_PARTIAL)) == BF_WRITE_PARTIAL)
ob->wex = tick_add_ifset(now_ms, ob->wto);
if (tick_isset(si->ib->rex)) {
* have to notify the task.
*/
if (likely((ob->flags & (BF_WRITE_NULL|BF_WRITE_ERROR|BF_SHUTW)) ||
- (!ob->to_forward && !ob->send_max && !ob->pipe) ||
+ ((ob->flags & BF_OUT_EMPTY) && !ob->to_forward) ||
si->state != SI_ST_EST)) {
out_wakeup:
task_wakeup(si->owner, TASK_WOKEN_IO);