Annotation of libaitsess/src/mem.c, revision 1.1.2.2
1.1.2.2 ! misho 1: /*************************************************************************
! 2: * (C) 2012 AITNET ltd - Sofia/Bulgaria - <misho@elwix.org>
! 3: * by Michael Pounov <misho@openbsd-bg.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: defs.h,v 1.4.2.1 2012/02/27 17:43:33 misho Exp $
! 7: *
! 8: **************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
1.1.2.1 misho 46: #include "global.h"
47:
48:
49: /*
50: * mpool_init() - Init memory pool
51: *
52: * return: =NULL error or !=NULL new allocated pool
53: */
54: mpool_t *
55: mpool_init(void)
56: {
57: mpool_t *mp;
58:
59: mp = malloc(sizeof(mpool_t));
60: if (!mp) {
61: LOGERR;
62: return NULL;
63: } else
64: memset(mp, 0, sizeof(mpool_t));
65:
66: pthread_mutex_init(&mp->pool_mtx, NULL);
67: return mp;
68: }
69:
70: /*
71: * mpool_destroy() - Destroy memory pool
72: *
73: * @mp = Memory pool
74: * return: none
75: */
76: void
77: mpool_destroy(mpool_t ** __restrict mp)
78: {
79: struct tagAlloc *m;
80: register int i;
81:
82: if (!mp && !*mp)
83: return;
84:
85: mpool_lock(*mp);
86:
87: for (i = 0; i < MEM_BUCKETS; i++) {
88: while ((m = TAILQ_FIRST(&(*mp)->pool_active[i]))) {
89: TAILQ_REMOVE(&(*mp)->pool_active[i], m, alloc_node);
90: if (m->alloc_mem)
91: free(m->alloc_mem);
92: free(m);
93: }
94: while ((m = TAILQ_FIRST(&(*mp)->pool_inactive[i]))) {
95: TAILQ_REMOVE(&(*mp)->pool_inactive[i], m, alloc_node);
96: if (m->alloc_mem)
97: free(m->alloc_mem);
98: free(m);
99: }
100: }
101:
102: mpool_unlock(*mp);
103: pthread_mutex_destroy(&(*mp)->pool_mtx);
104:
105: free(*mp);
106: *mp = NULL;
107: }
108:
109: /* ----------------------------------------------------------- */
110:
111: static inline long
112: BucketIndex(u_int size)
113: {
114: register long b;
115:
116: if (!size--)
117: return 0; /* min bucket position in array */
118:
119: for (b = MEM_MIN_BUCKET; b < MEM_MAX_BUCKET; b++)
120: if (!(size >> b))
121: break;
122:
123: return b - MEM_MIN_BUCKET; /* convert to bucket array index */
124: }
125:
126: static inline struct tagAlloc *
127: pullInactive(mpool_t * __restrict mp, int idx)
128: {
129: struct tagAlloc *m = NULL;
130:
131: /* must be locked pool before use this function */
132: if ((m = TAILQ_FIRST(&mp->pool_inactive[idx]))) {
133: TAILQ_REMOVE(&mp->pool_inactive[idx], m, alloc_node);
134:
135: /* clear name */
136: *m->alloc_name = 0;
137: /* clear flags */
138: m->alloc_flags ^= m->alloc_flags;
139: }
140:
141: return m;
142: }
143:
144: /*
145: * mpool_malloc() - Memory allocation
146: *
147: * @mp = Memory pool
148: * @size = Size
149: * @memname = Optional memory block name
150: * return: NULL error or !=NULL ok allocated memory
151: */
152: void *
153: mpool_malloc(mpool_t * __restrict mp, u_int size, const char *memname)
154: {
155: struct tagAlloc *m;
156: int idx, align;
157:
158: if (!mp) {
159: sess_SetErr(EINVAL, "Pool not specified");
160: return NULL;
161: }
162: if (size > MEM_ALLOC_MAX) {
163: sess_SetErr(ENOMEM, "Memory size is too large");
164: return NULL;
165: } else
166: size = (size + 3) & ~3; /* must align to 4 because needed room for sentinels */
167:
168: idx = BucketIndex(size);
169:
170: mpool_lock(mp);
171:
172: /* get memory from cache if exists */
173: if (!(m = pullInactive(mp, idx))) {
174: /* quota */
175: if (mp->pool_quota.max &&
176: (mp->pool_quota.curr + size) > mp->pool_quota.max) {
177: sess_SetErr(ENOMEM, "Max.allocate memory quota has been reached");
178: mpool_unlock(mp);
179: return NULL;
180: }
181:
182: m = malloc(sizeof(struct tagAlloc));
183: if (!m) {
184: LOGERR;
185: mpool_unlock(mp);
186: return NULL;
187: } else
188: memset(m, 0, sizeof(struct tagAlloc));
189: }
190:
191: if (memname)
192: strlcpy(m->alloc_name, memname, sizeof m->alloc_name);
193:
194: if (!m->alloc_mem) {
195: align = 1 << (idx + MEM_MIN_BUCKET);
196: m->alloc_mem = malloc(align + 12); /* +12 sentinel bytes */
197: if (!m->alloc_mem) {
198: LOGERR;
199: free(m);
200: mpool_unlock(mp);
201: return NULL;
202: } else /* quota */
203: mp->pool_quota.curr += size;
204: }
205:
206: m->alloc_mem[0] = size / sizeof(u_int);
207: m->alloc_mem[1] = MEM_MAGIC_START;
208: m->alloc_mem[2 + size / sizeof(u_int)] = MEM_MAGIC_STOP;
209: TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node);
210: /* statistics */
211: mp->pool_calls.alloc++;
212: mp->pool_bytes.alloc += size;
213:
214: mpool_unlock(mp);
215: return mem_data(m, void*);
216: }
217:
218: /*
219: * mpool_free() Free allocated memory with mpool_alloc()
220: *
221: * @mp = Memory pool
222: * @data = Allocated memory data
223: * @purge = if !=0 force release memory block
224: * return: <0 error or 0 ok released memory block
225: */
226: int
227: mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge)
228: {
229: int idx;
230: struct tagAlloc *m;
231:
232: if (!mp) {
233: sess_SetErr(EINVAL, "Pool not specified");
234: return -1;
235: }
236: /* check address range & sentinel */
237: if (MEM_BADADDR(data) || MEM_CORRUPT(data)) {
238: sess_SetErr(EFAULT, "Corrupted memory address");
239: return -2;
240: } else
241: idx = BucketIndex(((u_int*)data)[-2]);
242:
243: mpool_lock(mp);
244: TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node)
245: if (mem_data(m, void*) == data) {
246: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
247:
248: if (!purge) {
249: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
250: /* statistics */
251: mp->pool_calls.cache++;
252: mp->pool_bytes.cache += mem_size(m);
253: } else {
254: if (m->alloc_mem)
255: free(m->alloc_mem);
256: free(m);
257: /* statistics */
258: mp->pool_calls.free++;
259: mp->pool_bytes.free += mem_size(m);
260: }
261: break;
262: }
263: mpool_unlock(mp);
264:
265: return 0;
266: }
267:
268: /*
269: * mpool_free2() Free allocated memory with mpool_alloc() by size and memory name
270: *
271: * @mp = Memory pool
272: * @size = Allocated memory data size
273: * @memname = Memory name
274: * @purge = if !=0 force release memory block
275: * return: <0 error or 0 ok released memory block
276: */
277: int
278: mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge)
279: {
280: int idx;
281: struct tagAlloc *m;
282:
283: if (!mp || !memname) {
284: sess_SetErr(EINVAL, "Pool or memory name is not specified");
285: return -1;
286: } else
287: idx = BucketIndex(size);
288:
289: mpool_lock(mp);
290: TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node)
291: if (!strcmp(m->alloc_name, memname)) {
292: TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node);
293:
294: if (!purge) {
295: TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node);
296: /* statistics */
297: mp->pool_calls.cache++;
298: mp->pool_bytes.cache += mem_size(m);
299: } else {
300: if (m->alloc_mem)
301: free(m->alloc_mem);
302: free(m);
303: /* statistics */
304: mp->pool_calls.free++;
305: mp->pool_bytes.free += mem_size(m);
306: }
307: break;
308: }
309: mpool_unlock(mp);
310:
311: return 0;
312: }
313:
314: /*
315: * mpool_getmembynam() Find allocated memory block by size and memory name
316: *
317: * @mp = Memory pool
318: * @size = Memory size
319: * @memname = Memory name
320: * return: NULL error or not found and !=NULL allocated memory
321: */
322: inline struct tagAlloc *
323: mpool_getmembynam(mpool_t * __restrict mp, u_int size, const char *memname)
324: {
325: int idx;
326: struct tagAlloc *m = NULL;
327:
328: if (!mp || !memname)
329: return NULL;
330:
331: idx = BucketIndex(size);
332: TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node)
333: if (!strcmp(m->alloc_name, memname))
334: break;
335:
336: return mem_data(m, void*);
337: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>