1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
/* -*- linux-c -*-
* Preallocated memory pools
* Copyright (C) 2008 Red Hat Inc.
*
* This file is part of systemtap, and is free software. You can
* redistribute it and/or modify it under the terms of the GNU General
* Public License (GPL); either version 2, or (at your option) any
* later version.
*/
#ifndef _STP_MEMPOOL_C_
#define _STP_MEMPOOL_C_
/* An opaque struct identifying the memory pool. */
typedef struct {
struct list_head free_list;
unsigned num;
unsigned size;
spinlock_t lock;
} _stp_mempool_t;
/* for internal use only */
struct _stp_mem_buffer {
struct list_head list;
_stp_mempool_t *pool;
void *buf;
};
/* Delete a memory pool */
static void _stp_mempool_destroy(_stp_mempool_t *pool)
{
struct list_head *p, *tmp;
if (pool) {
list_for_each_safe(p, tmp, &pool->free_list) {
list_del(p);
_stp_kfree(p);
}
_stp_kfree(pool);
}
}
/* Create a new memory pool */
static _stp_mempool_t *_stp_mempool_init(size_t size, size_t num)
{
int i, alloc_size;
struct _stp_mem_buffer *m;
_stp_mempool_t *pool = (_stp_mempool_t *)_stp_kmalloc(sizeof(_stp_mempool_t));
if (unlikely(pool == NULL)) {
errk("Memory allocation failed.\n");
return NULL;
}
INIT_LIST_HEAD(&pool->free_list);
spin_lock_init(&pool->lock);
alloc_size = size + sizeof(struct _stp_mem_buffer) - sizeof(void *);
for (i = 0; i < num; i++) {
m = (struct _stp_mem_buffer *)_stp_kmalloc(alloc_size);
if (unlikely(m == NULL))
goto err;
m->pool = pool;
list_add((struct list_head *)m, &pool->free_list);
}
pool->num = num;
pool->size = alloc_size;
return pool;
err:
_stp_mempool_destroy(pool);
return NULL;
}
/* Resize a memory pool */
static int _stp_mempool_resize(_stp_mempool_t *pool, size_t num)
{
int i;
unsigned long flags;
struct _stp_mem_buffer *m;
if (unlikely(num == 0 || num == pool->num))
return pool->num;
if (num > pool->num) {
for (i = 0; i < num - pool->num; i++) {
m = (struct _stp_mem_buffer *)_stp_kmalloc(pool->size);
if (unlikely(m == NULL))
goto done;
m->pool = pool;
pool->num++;
spin_lock_irqsave(&pool->lock, flags);
list_add((struct list_head *)m, &pool->free_list);
spin_unlock_irqrestore(&pool->lock, flags);
}
} else {
for (i = 0; i < pool->num - num; i++) {
spin_lock_irqsave(&pool->lock, flags);
m = (struct _stp_mem_buffer *)pool->free_list.next;
list_del(&m->list);
spin_unlock_irqrestore(&pool->lock, flags);
_stp_kfree(m);
}
pool->num = num;
}
done:
return num;
}
/* allocate a buffer from a memory pool */
static void *_stp_mempool_alloc(_stp_mempool_t *pool)
{
unsigned long flags;
struct _stp_mem_buffer *ptr = NULL;
spin_lock_irqsave(&pool->lock, flags);
if (likely(!list_empty(&pool->free_list))) {
ptr = (struct _stp_mem_buffer *)pool->free_list.next;
list_del_init(&ptr->list);
spin_unlock_irqrestore(&pool->lock, flags);
return &ptr->buf;
}
spin_unlock_irqrestore(&pool->lock, flags);
return NULL;
}
/* return a buffer to its memory pool */
static void _stp_mempool_free(void *buf)
{
unsigned long flags;
struct _stp_mem_buffer *m = container_of(buf, struct _stp_mem_buffer, buf);
spin_lock_irqsave(&m->pool->lock, flags);
list_add(&m->list, &m->pool->free_list);
spin_unlock_irqrestore(&m->pool->lock, flags);
}
#endif /* _STP_MEMPOOL_C_ */
|