1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation;
5 * version 2.1 of the License.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include <errno.h>
17 #include <string.h>
18 #include <pthread.h>
19 #include <xen-tools/common-macros.h>
20
21 #include "private.h"
22
23 #define DBGPRINTF(_m...) \
24 xtl_log(xcall->logger, XTL_DEBUG, -1, "xencall:buffer", _m)
25
26 pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
27
cache_lock(xencall_handle * xcall)28 static void cache_lock(xencall_handle *xcall)
29 {
30 int saved_errno = errno;
31 if ( xcall->flags & XENCALL_OPENFLAG_NON_REENTRANT )
32 return;
33 pthread_mutex_lock(&cache_mutex);
34 /* Ignore pthread errors. */
35 errno = saved_errno;
36 }
37
cache_unlock(xencall_handle * xcall)38 static void cache_unlock(xencall_handle *xcall)
39 {
40 int saved_errno = errno;
41 if ( xcall->flags & XENCALL_OPENFLAG_NON_REENTRANT )
42 return;
43 pthread_mutex_unlock(&cache_mutex);
44 /* Ignore pthread errors. */
45 errno = saved_errno;
46 }
47
cache_alloc(xencall_handle * xcall,size_t nr_pages)48 static void *cache_alloc(xencall_handle *xcall, size_t nr_pages)
49 {
50 void *p = NULL;
51
52 cache_lock(xcall);
53
54 xcall->buffer_total_allocations++;
55 xcall->buffer_current_allocations++;
56 if ( xcall->buffer_current_allocations > xcall->buffer_maximum_allocations )
57 xcall->buffer_maximum_allocations = xcall->buffer_current_allocations;
58
59 if ( nr_pages > 1 )
60 {
61 xcall->buffer_cache_toobig++;
62 }
63 else if ( xcall->buffer_cache_nr > 0 )
64 {
65 p = xcall->buffer_cache[--xcall->buffer_cache_nr];
66 xcall->buffer_cache_hits++;
67 }
68 else
69 {
70 xcall->buffer_cache_misses++;
71 }
72
73 cache_unlock(xcall);
74
75 return p;
76 }
77
cache_free(xencall_handle * xcall,void * p,size_t nr_pages)78 static int cache_free(xencall_handle *xcall, void *p, size_t nr_pages)
79 {
80 int rc = 0;
81
82 cache_lock(xcall);
83
84 xcall->buffer_total_releases++;
85 xcall->buffer_current_allocations--;
86
87 if ( nr_pages == 1 &&
88 xcall->buffer_cache_nr < BUFFER_CACHE_SIZE )
89 {
90 xcall->buffer_cache[xcall->buffer_cache_nr++] = p;
91 rc = 1;
92 }
93
94 cache_unlock(xcall);
95
96 return rc;
97 }
98
buffer_release_cache(xencall_handle * xcall)99 void buffer_release_cache(xencall_handle *xcall)
100 {
101 void *p;
102
103 cache_lock(xcall);
104
105 DBGPRINTF("total allocations:%d total releases:%d",
106 xcall->buffer_total_allocations,
107 xcall->buffer_total_releases);
108 DBGPRINTF("current allocations:%d maximum allocations:%d",
109 xcall->buffer_current_allocations,
110 xcall->buffer_maximum_allocations);
111 DBGPRINTF("cache current size:%d",
112 xcall->buffer_cache_nr);
113 DBGPRINTF("cache hits:%d misses:%d toobig:%d",
114 xcall->buffer_cache_hits,
115 xcall->buffer_cache_misses,
116 xcall->buffer_cache_toobig);
117
118 while ( xcall->buffer_cache_nr > 0 )
119 {
120 p = xcall->buffer_cache[--xcall->buffer_cache_nr];
121 osdep_free_pages(xcall, p, 1);
122 }
123
124 cache_unlock(xcall);
125 }
126
xencall_alloc_buffer_pages(xencall_handle * xcall,size_t nr_pages)127 void *xencall_alloc_buffer_pages(xencall_handle *xcall, size_t nr_pages)
128 {
129 void *p = cache_alloc(xcall, nr_pages);
130
131 if ( !p )
132 p = osdep_alloc_pages(xcall, nr_pages);
133
134 if (!p)
135 return NULL;
136
137 memset(p, 0, nr_pages * PAGE_SIZE);
138
139 return p;
140 }
141
xencall_free_buffer_pages(xencall_handle * xcall,void * p,size_t nr_pages)142 void xencall_free_buffer_pages(xencall_handle *xcall, void *p, size_t nr_pages)
143 {
144 if ( p == NULL )
145 return;
146
147 if ( !cache_free(xcall, p, nr_pages) )
148 osdep_free_pages(xcall, p, nr_pages);
149 }
150
151 struct allocation_header {
152 int nr_pages;
153 int pad[3];
154 };
155
xencall_alloc_buffer(xencall_handle * xcall,size_t size)156 void *xencall_alloc_buffer(xencall_handle *xcall, size_t size)
157 {
158 size_t actual_size = ROUNDUP(size + sizeof(struct allocation_header), PAGE_SHIFT);
159 int nr_pages = actual_size >> PAGE_SHIFT;
160 struct allocation_header *hdr;
161
162 hdr = xencall_alloc_buffer_pages(xcall, nr_pages);
163 if ( hdr == NULL )
164 return NULL;
165
166 hdr->nr_pages = nr_pages;
167
168 return (void *)(hdr+1);
169 }
170
xencall_free_buffer(xencall_handle * xcall,void * p)171 void xencall_free_buffer(xencall_handle *xcall, void *p)
172 {
173 struct allocation_header *hdr;
174
175 if (p == NULL)
176 return;
177
178 hdr = p;
179 --hdr;
180
181 xencall_free_buffer_pages(xcall, hdr, hdr->nr_pages);
182 }
183
184 /*
185 * Local variables:
186 * mode: C
187 * c-file-style: "BSD"
188 * c-basic-offset: 4
189 * tab-width: 4
190 * indent-tabs-mode: nil
191 * End:
192 */
193