blob: 128f6ef125173f154662a2f1ad983fd266b5bd16 [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
13#include <common/config.h>
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +020014#include <common/debug.h>
Willy Tarreau50e608d2007-05-13 18:26:08 +020015#include <common/memory.h>
16#include <common/mini-clist.h>
17#include <common/standard.h>
18
19#include <proto/log.h>
20
21static struct list pools = LIST_HEAD_INIT(pools);
Willy Tarreau6e064432012-05-08 15:40:42 +020022char mem_poison_byte = 0;
Willy Tarreau50e608d2007-05-13 18:26:08 +020023
24/* Try to find an existing shared pool with the same characteristics and
25 * returns it, otherwise creates this one. NULL is returned if no memory
26 * is available for a new creation.
27 */
28struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
29{
30 struct pool_head *pool;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020031 struct pool_head *entry;
32 struct list *start;
Willy Tarreau50e608d2007-05-13 18:26:08 +020033 unsigned int align;
34
35 /* We need to store at least a (void *) in the chunks. Since we know
36 * that the malloc() function will never return such a small size,
37 * let's round the size up to something slightly bigger, in order to
38 * ease merging of entries. Note that the rounding is a power of two.
39 */
40
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020041 align = 16;
Willy Tarreau50e608d2007-05-13 18:26:08 +020042 size = (size + align - 1) & -align;
43
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020044 start = &pools;
Willy Tarreau50e608d2007-05-13 18:26:08 +020045 pool = NULL;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020046
47 list_for_each_entry(entry, &pools, list) {
48 if (entry->size == size) {
49 /* either we can share this place and we take it, or
50 * we look for a sharable one or for the next position
51 * before which we will insert a new one.
52 */
53 if (flags & entry->flags & MEM_F_SHARED) {
54 /* we can share this one */
Willy Tarreau50e608d2007-05-13 18:26:08 +020055 pool = entry;
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +020056 DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name);
Willy Tarreau50e608d2007-05-13 18:26:08 +020057 break;
58 }
59 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020060 else if (entry->size > size) {
61 /* insert before this one */
62 start = &entry->list;
63 break;
64 }
Willy Tarreau50e608d2007-05-13 18:26:08 +020065 }
66
67 if (!pool) {
68 pool = CALLOC(1, sizeof(*pool));
69 if (!pool)
70 return NULL;
71 if (name)
72 strlcpy2(pool->name, name, sizeof(pool->name));
73 pool->size = size;
74 pool->flags = flags;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020075 LIST_ADDQ(start, &pool->list);
Willy Tarreau50e608d2007-05-13 18:26:08 +020076 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020077 pool->users++;
Willy Tarreau50e608d2007-05-13 18:26:08 +020078 return pool;
79}
80
81/* Allocate a new entry for pool <pool>, and return it for immediate use.
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020082 * NULL is returned if no memory is available for a new creation. A call
83 * to the garbage collector is performed before returning NULL.
Willy Tarreau50e608d2007-05-13 18:26:08 +020084 */
Willy Tarreaue6ce59d2007-05-13 19:38:49 +020085void *pool_refill_alloc(struct pool_head *pool)
Willy Tarreau50e608d2007-05-13 18:26:08 +020086{
87 void *ret;
88
89 if (pool->limit && (pool->allocated >= pool->limit))
90 return NULL;
Willy Tarreau6e064432012-05-08 15:40:42 +020091 ret = CALLOC(1, pool->size);
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020092 if (!ret) {
93 pool_gc2();
Willy Tarreau6e064432012-05-08 15:40:42 +020094 ret = CALLOC(1, pool->size);
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020095 if (!ret)
96 return NULL;
97 }
Willy Tarreau6e064432012-05-08 15:40:42 +020098 if (mem_poison_byte)
99 memset(ret, mem_poison_byte, pool->size);
Willy Tarreau50e608d2007-05-13 18:26:08 +0200100 pool->allocated++;
101 pool->used++;
102 return ret;
103}
104
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200105/*
106 * This function frees whatever can be freed in pool <pool>.
107 */
108void pool_flush2(struct pool_head *pool)
109{
110 void *temp, *next;
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200111 if (!pool)
112 return;
113
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200114 next = pool->free_list;
115 while (next) {
116 temp = next;
117 next = *(void **)temp;
118 pool->allocated--;
119 FREE(temp);
120 }
121 pool->free_list = next;
122
123 /* here, we should have pool->allocate == pool->used */
124}
125
126/*
127 * This function frees whatever can be freed in all pools, but respecting
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200128 * the minimum thresholds imposed by owners. It takes care of avoiding
129 * recursion because it may be called from a signal handler.
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200130 */
131void pool_gc2()
132{
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200133 static int recurse;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200134 struct pool_head *entry;
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200135
136 if (recurse++)
137 goto out;
138
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200139 list_for_each_entry(entry, &pools, list) {
140 void *temp, *next;
141 //qfprintf(stderr, "Flushing pool %s\n", entry->name);
142 next = entry->free_list;
143 while (next &&
144 entry->allocated > entry->minavail &&
145 entry->allocated > entry->used) {
146 temp = next;
147 next = *(void **)temp;
148 entry->allocated--;
149 FREE(temp);
150 }
151 entry->free_list = next;
152 }
Willy Tarreaub7f9d122009-04-21 02:17:45 +0200153 out:
154 recurse--;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200155}
156
157/*
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200158 * This function destroys a pool by freeing it completely, unless it's still
159 * in use. This should be called only under extreme circumstances. It always
160 * returns NULL if the resulting pool is empty, easing the clearing of the old
161 * pointer, otherwise it returns the pool.
162 * .
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200163 */
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200164void *pool_destroy2(struct pool_head *pool)
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200165{
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200166 if (pool) {
167 pool_flush2(pool);
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200168 if (pool->used)
169 return pool;
170 pool->users--;
171 if (!pool->users) {
172 LIST_DEL(&pool->list);
173 FREE(pool);
174 }
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200175 }
176 return NULL;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200177}
178
Willy Tarreau50e608d2007-05-13 18:26:08 +0200179/* Dump statistics on pools usage.
180 */
181void dump_pools(void)
182{
183 struct pool_head *entry;
184 unsigned long allocated, used;
185 int nbpools;
186
187 allocated = used = nbpools = 0;
188 qfprintf(stderr, "Dumping pools usage.\n");
189 list_for_each_entry(entry, &pools, list) {
Willy Tarreau1772ece2009-04-03 14:49:12 +0200190 qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%u bytes), %d used, %d users%s\n",
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200191 entry->name, entry->size, entry->allocated,
192 entry->size * entry->allocated, entry->used,
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200193 entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
Willy Tarreau50e608d2007-05-13 18:26:08 +0200194
195 allocated += entry->allocated * entry->size;
196 used += entry->used * entry->size;
197 nbpools++;
198 }
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200199 qfprintf(stderr, "Total: %d pools, %lu bytes allocated, %lu used.\n",
Willy Tarreau50e608d2007-05-13 18:26:08 +0200200 nbpools, allocated, used);
201}
202
203/*
204 * Local variables:
205 * c-indent-level: 8
206 * c-basic-offset: 8
207 * End:
208 */