blob: b157cf0a06b5f732e0465cbb618bca447343267c [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>
14#include <common/memory.h>
15#include <common/mini-clist.h>
16#include <common/standard.h>
17
18#include <proto/log.h>
19
20static struct list pools = LIST_HEAD_INIT(pools);
21
22/* Try to find an existing shared pool with the same characteristics and
23 * returns it, otherwise creates this one. NULL is returned if no memory
24 * is available for a new creation.
25 */
26struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
27{
28 struct pool_head *pool;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020029 struct pool_head *entry;
30 struct list *start;
Willy Tarreau50e608d2007-05-13 18:26:08 +020031 unsigned int align;
32
33 /* We need to store at least a (void *) in the chunks. Since we know
34 * that the malloc() function will never return such a small size,
35 * let's round the size up to something slightly bigger, in order to
36 * ease merging of entries. Note that the rounding is a power of two.
37 */
38
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020039 align = 16;
Willy Tarreau50e608d2007-05-13 18:26:08 +020040 size = (size + align - 1) & -align;
41
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020042 start = &pools;
Willy Tarreau50e608d2007-05-13 18:26:08 +020043 pool = NULL;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020044
45 list_for_each_entry(entry, &pools, list) {
46 if (entry->size == size) {
47 /* either we can share this place and we take it, or
48 * we look for a sharable one or for the next position
49 * before which we will insert a new one.
50 */
51 if (flags & entry->flags & MEM_F_SHARED) {
52 /* we can share this one */
Willy Tarreau50e608d2007-05-13 18:26:08 +020053 pool = entry;
54 break;
55 }
56 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020057 else if (entry->size > size) {
58 /* insert before this one */
59 start = &entry->list;
60 break;
61 }
Willy Tarreau50e608d2007-05-13 18:26:08 +020062 }
63
64 if (!pool) {
65 pool = CALLOC(1, sizeof(*pool));
66 if (!pool)
67 return NULL;
68 if (name)
69 strlcpy2(pool->name, name, sizeof(pool->name));
70 pool->size = size;
71 pool->flags = flags;
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020072 LIST_ADDQ(start, &pool->list);
Willy Tarreau50e608d2007-05-13 18:26:08 +020073 }
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020074 pool->users++;
Willy Tarreau50e608d2007-05-13 18:26:08 +020075 return pool;
76}
77
78/* Allocate a new entry for pool <pool>, and return it for immediate use.
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020079 * NULL is returned if no memory is available for a new creation. A call
80 * to the garbage collector is performed before returning NULL.
Willy Tarreau50e608d2007-05-13 18:26:08 +020081 */
Willy Tarreaue6ce59d2007-05-13 19:38:49 +020082void *pool_refill_alloc(struct pool_head *pool)
Willy Tarreau50e608d2007-05-13 18:26:08 +020083{
84 void *ret;
85
86 if (pool->limit && (pool->allocated >= pool->limit))
87 return NULL;
88 ret = MALLOC(pool->size);
Willy Tarreau7dcd46d2007-05-14 00:16:13 +020089 if (!ret) {
90 pool_gc2();
91 ret = MALLOC(pool->size);
92 if (!ret)
93 return NULL;
94 }
Willy Tarreau50e608d2007-05-13 18:26:08 +020095 pool->allocated++;
96 pool->used++;
97 return ret;
98}
99
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200100/*
101 * This function frees whatever can be freed in pool <pool>.
102 */
103void pool_flush2(struct pool_head *pool)
104{
105 void *temp, *next;
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200106 if (!pool)
107 return;
108
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200109 next = pool->free_list;
110 while (next) {
111 temp = next;
112 next = *(void **)temp;
113 pool->allocated--;
114 FREE(temp);
115 }
116 pool->free_list = next;
117
118 /* here, we should have pool->allocate == pool->used */
119}
120
121/*
122 * This function frees whatever can be freed in all pools, but respecting
123 * the minimum thresholds imposed by owners.
124 */
125void pool_gc2()
126{
127 struct pool_head *entry;
128 list_for_each_entry(entry, &pools, list) {
129 void *temp, *next;
130 //qfprintf(stderr, "Flushing pool %s\n", entry->name);
131 next = entry->free_list;
132 while (next &&
133 entry->allocated > entry->minavail &&
134 entry->allocated > entry->used) {
135 temp = next;
136 next = *(void **)temp;
137 entry->allocated--;
138 FREE(temp);
139 }
140 entry->free_list = next;
141 }
142}
143
144/*
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200145 * This function destroys a pool by freeing it completely, unless it's still
146 * in use. This should be called only under extreme circumstances. It always
147 * returns NULL if the resulting pool is empty, easing the clearing of the old
148 * pointer, otherwise it returns the pool.
149 * .
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200150 */
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200151void *pool_destroy2(struct pool_head *pool)
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200152{
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200153 if (pool) {
154 pool_flush2(pool);
Willy Tarreaudae4aa82007-06-16 23:19:53 +0200155 if (pool->used)
156 return pool;
157 pool->users--;
158 if (!pool->users) {
159 LIST_DEL(&pool->list);
160 FREE(pool);
161 }
Willy Tarreau4d2d0982007-05-14 00:39:29 +0200162 }
163 return NULL;
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200164}
165
Willy Tarreau50e608d2007-05-13 18:26:08 +0200166/* Dump statistics on pools usage.
167 */
168void dump_pools(void)
169{
170 struct pool_head *entry;
171 unsigned long allocated, used;
172 int nbpools;
173
174 allocated = used = nbpools = 0;
175 qfprintf(stderr, "Dumping pools usage.\n");
176 list_for_each_entry(entry, &pools, list) {
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200177 qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%lu bytes), %d used, %d users%s\n",
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200178 entry->name, entry->size, entry->allocated,
179 entry->size * entry->allocated, entry->used,
Willy Tarreau7dcd46d2007-05-14 00:16:13 +0200180 entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
Willy Tarreau50e608d2007-05-13 18:26:08 +0200181
182 allocated += entry->allocated * entry->size;
183 used += entry->used * entry->size;
184 nbpools++;
185 }
Willy Tarreaue6ce59d2007-05-13 19:38:49 +0200186 qfprintf(stderr, "Total: %d pools, %lu bytes allocated, %lu used.\n",
Willy Tarreau50e608d2007-05-13 18:26:08 +0200187 nbpools, allocated, used);
188}
189
190/*
191 * Local variables:
192 * c-indent-level: 8
193 * c-basic-offset: 8
194 * End:
195 */