blob: 61c150bfd996afb509da615b58cd78649b353952 [file] [log] [blame]
Willy Tarreau50e608d2007-05-13 18:26:08 +02001/*
2 * Memory management functions.
3 *
4 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreau12833bb2014-01-28 16:49:56 +010013#include <types/global.h>
Willy Tarreau50e608d2007-05-13 18:26:08 +020014#include <common/config.h>
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +020015#include <common/debug.h>
Willy Tarreau50e608d2007-05-13 18:26:08 +020016#include <common/memory.h>
17#include <common/mini-clist.h>
18#include <common/standard.h>
19
20#include <proto/log.h>
21
22static struct list pools = LIST_HEAD_INIT(pools);
Willy Tarreau6e064432012-05-08 15:40:42 +020023char mem_poison_byte = 0;
Willy Tarreau50e608d2007-05-13 18:26:08 +020024
25/* Try to find an existing shared pool with the same characteristics and
26 * returns it, otherwise creates this one. NULL is returned if no memory
27 * is available for a new creation.
28 */
29struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
30{
31 struct pool_head *pool;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020032 struct pool_head *entry;
33 struct list *start;
Willy Tarreau50e608d2007-05-13 18:26:08 +020034 unsigned int align;
35
36 /* We need to store at least a (void *) in the chunks. Since we know
37 * that the malloc() function will never return such a small size,
38 * let's round the size up to something slightly bigger, in order to
39 * ease merging of entries. Note that the rounding is a power of two.
40 */
41
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020042 align = 16;
Willy Tarreau50e608d2007-05-13 18:26:08 +020043 size = (size + align - 1) & -align;
44
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020045 start = &pools;
Willy Tarreau50e608d2007-05-13 18:26:08 +020046 pool = NULL;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020047
48 list_for_each_entry(entry, &pools, list) {
49 if (entry->size == size) {
50 /* either we can share this place and we take it, or
51 * we look for a sharable one or for the next position
52 * before which we will insert a new one.
53 */
54 if (flags & entry->flags & MEM_F_SHARED) {
55 /* we can share this one */
Willy Tarreau50e608d2007-05-13 18:26:08 +020056 pool = entry;
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +020057 DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name);
Willy Tarreau50e608d2007-05-13 18:26:08 +020058 break;
59 }
60 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020061 else if (entry->size > size) {
62 /* insert before this one */
63 start = &entry->list;
64 break;
65 }
Willy Tarreau50e608d2007-05-13 18:26:08 +020066 }
67
68 if (!pool) {
69 pool = CALLOC(1, sizeof(*pool));
70 if (!pool)
71 return NULL;
72 if (name)
73 strlcpy2(pool->name, name, sizeof(pool->name));
74 pool->size = size;
75 pool->flags = flags;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020076 LIST_ADDQ(start, &pool->list);
Willy Tarreau50e608d2007-05-13 18:26:08 +020077 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020078 pool->users++;
Willy Tarreau50e608d2007-05-13 18:26:08 +020079 return pool;
80}
81
Willy Tarreaua885f6d2014-12-03 15:25:28 +010082/* Allocates new entries for pool <pool> until there are at least <avail> + 1
83 * available, then returns the last one for immediate use, so that at least
84 * <avail> are left available in the pool upon return. NULL is returned if the
85 * last entry could not be allocated. It's important to note that at least one
86 * allocation is always performed even if there are enough entries in the pool.
87 * A call to the garbage collector is performed at most once in case malloc()
88 * returns an error, before returning NULL.
Willy Tarreau50e608d2007-05-13 18:26:08 +020089 */
Willy Tarreaua885f6d2014-12-03 15:25:28 +010090void *pool_refill_alloc(struct pool_head *pool, unsigned int avail)
Willy Tarreau50e608d2007-05-13 18:26:08 +020091{
Willy Tarreaua885f6d2014-12-03 15:25:28 +010092 void *ptr = NULL;
93 int failed = 0;
Willy Tarreau50e608d2007-05-13 18:26:08 +020094
Willy Tarreaua885f6d2014-12-03 15:25:28 +010095 /* stop point */
96 avail += pool->used;
97
98 while (1) {
99 if (pool->limit && pool->allocated >= pool->limit)
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200100 return NULL;
Willy Tarreaua885f6d2014-12-03 15:25:28 +0100101
102 ptr = MALLOC(pool->size);
103 if (!ptr) {
104 if (failed)
105 return NULL;
106 failed++;
107 pool_gc2();
108 continue;
109 }
110 if (++pool->allocated > avail)
111 break;
112
113 *(void **)ptr = (void *)pool->free_list;
114 pool->free_list = ptr;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200115 }
Willy Tarreau50e608d2007-05-13 18:26:08 +0200116 pool->used++;
Willy Tarreaua885f6d2014-12-03 15:25:28 +0100117 return ptr;
Willy Tarreau50e608d2007-05-13 18:26:08 +0200118}
119
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200120/*
121 * This function frees whatever can be freed in pool <pool>.
122 */
123void pool_flush2(struct pool_head *pool)
124{
125 void *temp, *next;
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200126 if (!pool)
127 return;
128
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200129 next = pool->free_list;
130 while (next) {
131 temp = next;
132 next = *(void **)temp;
133 pool->allocated--;
134 FREE(temp);
135 }
136 pool->free_list = next;
137
138 /* here, we should have pool->allocate == pool->used */
139}
140
141/*
142 * This function frees whatever can be freed in all pools, but respecting
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200143 * the minimum thresholds imposed by owners. It takes care of avoiding
144 * recursion because it may be called from a signal handler.
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200145 */
146void pool_gc2()
147{
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200148 static int recurse;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200149 struct pool_head *entry;
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200150
151 if (recurse++)
152 goto out;
153
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200154 list_for_each_entry(entry, &pools, list) {
155 void *temp, *next;
156 //qfprintf(stderr, "Flushing pool %s\n", entry->name);
157 next = entry->free_list;
158 while (next &&
Willy Tarreau57767b82014-12-22 21:40:55 +0100159 (int)(entry->allocated - entry->used) > (int)entry->minavail) {
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200160 temp = next;
161 next = *(void **)temp;
162 entry->allocated--;
163 FREE(temp);
164 }
165 entry->free_list = next;
166 }
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200167 out:
168 recurse--;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200169}
170
171/*
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200172 * This function destroys a pool by freeing it completely, unless it's still
173 * in use. This should be called only under extreme circumstances. It always
174 * returns NULL if the resulting pool is empty, easing the clearing of the old
175 * pointer, otherwise it returns the pool.
176 * .
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200177 */
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200178void *pool_destroy2(struct pool_head *pool)
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200179{
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200180 if (pool) {
181 pool_flush2(pool);
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200182 if (pool->used)
183 return pool;
184 pool->users--;
185 if (!pool->users) {
186 LIST_DEL(&pool->list);
187 FREE(pool);
188 }
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200189 }
190 return NULL;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200191}
192
Willy Tarreau12833bb2014-01-28 16:49:56 +0100193/* This function dumps memory usage information into the trash buffer. */
194void dump_pools_to_trash()
Willy Tarreau50e608d2007-05-13 18:26:08 +0200195{
196 struct pool_head *entry;
197 unsigned long allocated, used;
198 int nbpools;
199
200 allocated = used = nbpools = 0;
Willy Tarreau12833bb2014-01-28 16:49:56 +0100201 chunk_printf(&trash, "Dumping pools usage. Use SIGQUIT to flush them.\n");
Willy Tarreau50e608d2007-05-13 18:26:08 +0200202 list_for_each_entry(entry, &pools, list) {
Willy Tarreau12833bb2014-01-28 16:49:56 +0100203 chunk_appendf(&trash, " - Pool %s (%d bytes) : %d allocated (%u bytes), %d used, %d users%s\n",
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200204 entry->name, entry->size, entry->allocated,
205 entry->size * entry->allocated, entry->used,
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200206 entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
Willy Tarreau50e608d2007-05-13 18:26:08 +0200207
208 allocated += entry->allocated * entry->size;
209 used += entry->used * entry->size;
210 nbpools++;
211 }
Willy Tarreau12833bb2014-01-28 16:49:56 +0100212 chunk_appendf(&trash, "Total: %d pools, %lu bytes allocated, %lu used.\n",
Willy Tarreau50e608d2007-05-13 18:26:08 +0200213 nbpools, allocated, used);
214}
215
Willy Tarreau12833bb2014-01-28 16:49:56 +0100216/* Dump statistics on pools usage. */
217void dump_pools(void)
218{
219 dump_pools_to_trash();
220 qfprintf(stderr, "%s", trash.str);
221}
222
Willy Tarreau50e608d2007-05-13 18:26:08 +0200223/*
224 * Local variables:
225 * c-indent-level: 8
226 * c-basic-offset: 8
227 * End:
228 */