mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-20 04:30:46 +00:00
4c7e4b7738
All files that were including one of the following include files have been updated to only include haproxy/api.h or haproxy/api-t.h once instead: - common/config.h - common/compat.h - common/compiler.h - common/defaults.h - common/initcall.h - common/tools.h The choice is simple: if the file only requires type definitions, it includes api-t.h, otherwise it includes the full api.h. In addition, in these files, explicit includes for inttypes.h and limits.h were dropped since these are now covered by api.h and api-t.h. No other change was performed, given that this patch is large and affects 201 files. At least one (tools.h) was already freestanding and didn't get the new one added.
219 lines
6.4 KiB
C
219 lines
6.4 KiB
C
/*
|
|
* include/common/buffer.h
|
|
* Buffer management definitions, macros and inline functions.
|
|
*
|
|
* Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation, version 2.1
|
|
* exclusively.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef _COMMON_BUFFER_H
|
|
#define _COMMON_BUFFER_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <haproxy/api.h>
|
|
#include <common/buf.h>
|
|
#include <common/chunk.h>
|
|
#include <common/ist.h>
|
|
#include <common/istbuf.h>
|
|
#include <common/memory.h>
|
|
|
|
#include <proto/activity.h>
|
|
|
|
/* an element of the <buffer_wq> list. It represents an object that need to
|
|
* acquire a buffer to continue its process. */
|
|
struct buffer_wait {
|
|
void *target; /* The waiting object that should be woken up */
|
|
int (*wakeup_cb)(void *); /* The function used to wake up the <target>, passed as argument */
|
|
struct mt_list list; /* Next element in the <buffer_wq> list */
|
|
};
|
|
|
|
extern struct pool_head *pool_head_buffer;
|
|
extern struct mt_list buffer_wq;
|
|
__decl_hathreads(extern HA_SPINLOCK_T buffer_wq_lock);
|
|
|
|
int init_buffer();
|
|
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
|
|
|
|
/*****************************************************************/
|
|
/* These functions are used to compute various buffer area sizes */
|
|
/*****************************************************************/
|
|
|
|
/* Return 1 if the buffer has less than 1/4 of its capacity free, otherwise 0 */
|
|
static inline int buffer_almost_full(const struct buffer *buf)
|
|
{
|
|
if (b_is_null(buf))
|
|
return 0;
|
|
|
|
return b_almost_full(buf);
|
|
}
|
|
|
|
/**************************************************/
|
|
/* Functions below are used for buffer allocation */
|
|
/**************************************************/
|
|
|
|
/* Allocates a buffer and assigns it to *buf. If no memory is available,
|
|
* ((char *)1) is assigned instead with a zero size. No control is made to
|
|
* check if *buf already pointed to another buffer. The allocated buffer is
|
|
* returned, or NULL in case no memory is available.
|
|
*/
|
|
static inline struct buffer *b_alloc(struct buffer *buf)
|
|
{
|
|
char *area;
|
|
|
|
*buf = BUF_WANTED;
|
|
area = pool_alloc_dirty(pool_head_buffer);
|
|
if (unlikely(!area)) {
|
|
activity[tid].buf_wait++;
|
|
return NULL;
|
|
}
|
|
|
|
buf->area = area;
|
|
buf->size = pool_head_buffer->size;
|
|
return buf;
|
|
}
|
|
|
|
/* Allocates a buffer and assigns it to *buf. If no memory is available,
|
|
* ((char *)1) is assigned instead with a zero size. No control is made to
|
|
* check if *buf already pointed to another buffer. The allocated buffer is
|
|
* returned, or NULL in case no memory is available. The difference with
|
|
* b_alloc() is that this function only picks from the pool and never calls
|
|
* malloc(), so it can fail even if some memory is available.
|
|
*/
|
|
static inline struct buffer *b_alloc_fast(struct buffer *buf)
|
|
{
|
|
char *area;
|
|
|
|
*buf = BUF_WANTED;
|
|
area = pool_get_first(pool_head_buffer);
|
|
if (unlikely(!area))
|
|
return NULL;
|
|
|
|
buf->area = area;
|
|
buf->size = pool_head_buffer->size;
|
|
return buf;
|
|
}
|
|
|
|
/* Releases buffer <buf> (no check of emptiness). The buffer's head is marked
|
|
* empty.
|
|
*/
|
|
static inline void __b_free(struct buffer *buf)
|
|
{
|
|
char *area = buf->area;
|
|
|
|
/* let's first clear the area to save an occasional "show sess all"
|
|
* glancing over our shoulder from getting a dangling pointer.
|
|
*/
|
|
*buf = BUF_NULL;
|
|
__ha_barrier_store();
|
|
pool_free(pool_head_buffer, area);
|
|
}
|
|
|
|
/* Releases buffer <buf> if allocated, and marks it empty. */
|
|
static inline void b_free(struct buffer *buf)
|
|
{
|
|
if (buf->size)
|
|
__b_free(buf);
|
|
}
|
|
|
|
/* Ensures that <buf> is allocated. If an allocation is needed, it ensures that
|
|
* there are still at least <margin> buffers available in the pool after this
|
|
* allocation so that we don't leave the pool in a condition where a session or
|
|
* a response buffer could not be allocated anymore, resulting in a deadlock.
|
|
* This means that we sometimes need to try to allocate extra entries even if
|
|
* only one buffer is needed.
|
|
*
|
|
* We need to lock the pool here to be sure to have <margin> buffers available
|
|
* after the allocation, regardless how many threads that doing it in the same
|
|
* time. So, we use internal and lockless memory functions (prefixed with '__').
|
|
*/
|
|
static inline struct buffer *b_alloc_margin(struct buffer *buf, int margin)
|
|
{
|
|
char *area;
|
|
ssize_t idx;
|
|
unsigned int cached;
|
|
|
|
if (buf->size)
|
|
return buf;
|
|
|
|
cached = 0;
|
|
idx = pool_get_index(pool_head_buffer);
|
|
if (idx >= 0)
|
|
cached = pool_cache[tid][idx].count;
|
|
|
|
*buf = BUF_WANTED;
|
|
|
|
#ifndef CONFIG_HAP_LOCKLESS_POOLS
|
|
HA_SPIN_LOCK(POOL_LOCK, &pool_head_buffer->lock);
|
|
#endif
|
|
|
|
/* fast path */
|
|
if ((pool_head_buffer->allocated - pool_head_buffer->used + cached) > margin) {
|
|
area = __pool_get_first(pool_head_buffer);
|
|
if (likely(area)) {
|
|
#ifndef CONFIG_HAP_LOCKLESS_POOLS
|
|
HA_SPIN_UNLOCK(POOL_LOCK, &pool_head_buffer->lock);
|
|
#endif
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* slow path, uses malloc() */
|
|
area = __pool_refill_alloc(pool_head_buffer, margin);
|
|
|
|
#ifndef CONFIG_HAP_LOCKLESS_POOLS
|
|
HA_SPIN_UNLOCK(POOL_LOCK, &pool_head_buffer->lock);
|
|
#endif
|
|
|
|
if (unlikely(!area)) {
|
|
activity[tid].buf_wait++;
|
|
return NULL;
|
|
}
|
|
|
|
done:
|
|
buf->area = area;
|
|
buf->size = pool_head_buffer->size;
|
|
return buf;
|
|
}
|
|
|
|
|
|
/* Offer a buffer currently belonging to target <from> to whoever needs one.
|
|
* Any pointer is valid for <from>, including NULL. Its purpose is to avoid
|
|
* passing a buffer to oneself in case of failed allocations (e.g. need two
|
|
* buffers, get one, fail, release it and wake up self again). In case of
|
|
* normal buffer release where it is expected that the caller is not waiting
|
|
* for a buffer, NULL is fine.
|
|
*/
|
|
void __offer_buffer(void *from, unsigned int threshold);
|
|
|
|
static inline void offer_buffers(void *from, unsigned int threshold)
|
|
{
|
|
if (!MT_LIST_ISEMPTY(&buffer_wq))
|
|
__offer_buffer(from, threshold);
|
|
}
|
|
|
|
|
|
#endif /* _COMMON_BUFFER_H */
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*/
|