blob: 2fe37662d71cf702b2d5032f578ffca5627fa86e [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);
22
23/* Try to find an existing shared pool with the same characteristics and
24 * returns it, otherwise creates this one. NULL is returned if no memory
25 * is available for a new creation.
26 */
27struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
28{
29 struct pool_head *pool;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020030 struct pool_head *entry;
31 struct list *start;
Willy Tarreau50e608d2007-05-13 18:26:08 +020032 unsigned int align;
33
34 /* We need to store at least a (void *) in the chunks. Since we know
35 * that the malloc() function will never return such a small size,
36 * let's round the size up to something slightly bigger, in order to
37 * ease merging of entries. Note that the rounding is a power of two.
38 */
39
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020040 align = 16;
Willy Tarreau50e608d2007-05-13 18:26:08 +020041 size = (size + align - 1) & -align;
42
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020043 start = &pools;
Willy Tarreau50e608d2007-05-13 18:26:08 +020044 pool = NULL;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020045
46 list_for_each_entry(entry, &pools, list) {
47 if (entry->size == size) {
48 /* either we can share this place and we take it, or
49 * we look for a sharable one or for the next position
50 * before which we will insert a new one.
51 */
52 if (flags & entry->flags & MEM_F_SHARED) {
53 /* we can share this one */
Willy Tarreau50e608d2007-05-13 18:26:08 +020054 pool = entry;
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +020055 DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name);
Willy Tarreau50e608d2007-05-13 18:26:08 +020056 break;
57 }
58 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020059 else if (entry->size > size) {
60 /* insert before this one */
61 start = &entry->list;
62 break;
63 }
Willy Tarreau50e608d2007-05-13 18:26:08 +020064 }
65
66 if (!pool) {
67 pool = CALLOC(1, sizeof(*pool));
68 if (!pool)
69 return NULL;
70 if (name)
71 strlcpy2(pool->name, name, sizeof(pool->name));
72 pool->size = size;
73 pool->flags = flags;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020074 LIST_ADDQ(start, &pool->list);
Willy Tarreau50e608d2007-05-13 18:26:08 +020075 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020076 pool->users++;
Willy Tarreau50e608d2007-05-13 18:26:08 +020077 return pool;
78}
79
80/* Allocate a new entry for pool <pool>, and return it for immediate use.
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020081 * NULL is returned if no memory is available for a new creation. A call
82 * to the garbage collector is performed before returning NULL.
Willy Tarreau50e608d2007-05-13 18:26:08 +020083 */
Willy Tarreaue6ce59d2007-05-13 19:38:49 +020084void *pool_refill_alloc(struct pool_head *pool)
Willy Tarreau50e608d2007-05-13 18:26:08 +020085{
86 void *ret;
87
88 if (pool->limit && (pool->allocated >= pool->limit))
89 return NULL;
90 ret = MALLOC(pool->size);
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020091 if (!ret) {
92 pool_gc2();
93 ret = MALLOC(pool->size);
94 if (!ret)
95 return NULL;
96 }
Willy Tarreau50e608d2007-05-13 18:26:08 +020097 pool->allocated++;
98 pool->used++;
99 return ret;
100}
101
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200102/*
103 * This function frees whatever can be freed in pool <pool>.
104 */
105void pool_flush2(struct pool_head *pool)
106{
107 void *temp, *next;
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200108 if (!pool)
109 return;
110
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200111 next = pool->free_list;
112 while (next) {
113 temp = next;
114 next = *(void **)temp;
115 pool->allocated--;
116 FREE(temp);
117 }
118 pool->free_list = next;
119
120 /* here, we should have pool->allocate == pool->used */
121}
122
123/*
124 * This function frees whatever can be freed in all pools, but respecting
125 * the minimum thresholds imposed by owners.
126 */
127void pool_gc2()
128{
129 struct pool_head *entry;
130 list_for_each_entry(entry, &pools, list) {
131 void *temp, *next;
132 //qfprintf(stderr, "Flushing pool %s\n", entry->name);
133 next = entry->free_list;
134 while (next &&
135 entry->allocated > entry->minavail &&
136 entry->allocated > entry->used) {
137 temp = next;
138 next = *(void **)temp;
139 entry->allocated--;
140 FREE(temp);
141 }
142 entry->free_list = next;
143 }
144}
145
146/*
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200147 * This function destroys a pool by freeing it completely, unless it's still
148 * in use. This should be called only under extreme circumstances. It always
149 * returns NULL if the resulting pool is empty, easing the clearing of the old
150 * pointer, otherwise it returns the pool.
151 * .
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200152 */
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200153void *pool_destroy2(struct pool_head *pool)
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200154{
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200155 if (pool) {
156 pool_flush2(pool);
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200157 if (pool->used)
158 return pool;
159 pool->users--;
160 if (!pool->users) {
161 LIST_DEL(&pool->list);
162 FREE(pool);
163 }
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200164 }
165 return NULL;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200166}
167
Willy Tarreau50e608d2007-05-13 18:26:08 +0200168/* Dump statistics on pools usage.
169 */
170void dump_pools(void)
171{
172 struct pool_head *entry;
173 unsigned long allocated, used;
174 int nbpools;
175
176 allocated = used = nbpools = 0;
177 qfprintf(stderr, "Dumping pools usage.\n");
178 list_for_each_entry(entry, &pools, list) {
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200179 qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%lu bytes), %d used, %d users%s\n",
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200180 entry->name, entry->size, entry->allocated,
181 entry->size * entry->allocated, entry->used,
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200182 entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
Willy Tarreau50e608d2007-05-13 18:26:08 +0200183
184 allocated += entry->allocated * entry->size;
185 used += entry->used * entry->size;
186 nbpools++;
187 }
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200188 qfprintf(stderr, "Total: %d pools, %lu bytes allocated, %lu used.\n",
Willy Tarreau50e608d2007-05-13 18:26:08 +0200189 nbpools, allocated, used);
190}
191
192/*
193 * Local variables:
194 * c-indent-level: 8
195 * c-basic-offset: 8
196 * End:
197 */