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 20 #include "private.h" 21 22 #define DBGPRINTF(_m...) \ 23 xtl_log(xcall->logger, XTL_DEBUG, -1, "xencall:buffer", _m) 24 25 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) 26 27 pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER; 28 cache_lock(xencall_handle * xcall)29 static void cache_lock(xencall_handle *xcall) 30 { 31 int saved_errno = errno; 32 if ( xcall->flags & XENCALL_OPENFLAG_NON_REENTRANT ) 33 return; 34 pthread_mutex_lock(&cache_mutex); 35 /* Ignore pthread errors. */ 36 errno = saved_errno; 37 } 38 cache_unlock(xencall_handle * xcall)39 static void cache_unlock(xencall_handle *xcall) 40 { 41 int saved_errno = errno; 42 if ( xcall->flags & XENCALL_OPENFLAG_NON_REENTRANT ) 43 return; 44 pthread_mutex_unlock(&cache_mutex); 45 /* Ignore pthread errors. */ 46 errno = saved_errno; 47 } 48 cache_alloc(xencall_handle * xcall,size_t nr_pages)49 static void *cache_alloc(xencall_handle *xcall, size_t nr_pages) 50 { 51 void *p = NULL; 52 53 cache_lock(xcall); 54 55 xcall->buffer_total_allocations++; 56 xcall->buffer_current_allocations++; 57 if ( xcall->buffer_current_allocations > xcall->buffer_maximum_allocations ) 58 xcall->buffer_maximum_allocations = xcall->buffer_current_allocations; 59 60 if ( nr_pages > 1 ) 61 { 62 xcall->buffer_cache_toobig++; 63 } 64 else if ( xcall->buffer_cache_nr > 0 ) 65 { 66 p = xcall->buffer_cache[--xcall->buffer_cache_nr]; 67 xcall->buffer_cache_hits++; 68 } 69 else 70 { 71 xcall->buffer_cache_misses++; 72 } 73 74 cache_unlock(xcall); 75 76 return p; 77 } 78 cache_free(xencall_handle * xcall,void * p,size_t nr_pages)79 static int cache_free(xencall_handle *xcall, void *p, size_t nr_pages) 80 { 81 int rc = 0; 82 83 cache_lock(xcall); 84 85 xcall->buffer_total_releases++; 86 xcall->buffer_current_allocations--; 87 88 if ( nr_pages == 1 && 89 xcall->buffer_cache_nr < BUFFER_CACHE_SIZE ) 90 { 91 xcall->buffer_cache[xcall->buffer_cache_nr++] = p; 92 rc = 1; 93 } 94 95 cache_unlock(xcall); 96 97 return rc; 98 } 99 buffer_release_cache(xencall_handle * xcall)100 void buffer_release_cache(xencall_handle *xcall) 101 { 102 void *p; 103 104 cache_lock(xcall); 105 106 DBGPRINTF("total allocations:%d total releases:%d", 107 xcall->buffer_total_allocations, 108 xcall->buffer_total_releases); 109 DBGPRINTF("current allocations:%d maximum allocations:%d", 110 xcall->buffer_current_allocations, 111 xcall->buffer_maximum_allocations); 112 DBGPRINTF("cache current size:%d", 113 xcall->buffer_cache_nr); 114 DBGPRINTF("cache hits:%d misses:%d toobig:%d", 115 xcall->buffer_cache_hits, 116 xcall->buffer_cache_misses, 117 xcall->buffer_cache_toobig); 118 119 while ( xcall->buffer_cache_nr > 0 ) 120 { 121 p = xcall->buffer_cache[--xcall->buffer_cache_nr]; 122 osdep_free_pages(xcall, p, 1); 123 } 124 125 cache_unlock(xcall); 126 } 127 xencall_alloc_buffer_pages(xencall_handle * xcall,size_t nr_pages)128 void *xencall_alloc_buffer_pages(xencall_handle *xcall, size_t nr_pages) 129 { 130 void *p = cache_alloc(xcall, nr_pages); 131 132 if ( !p ) 133 p = osdep_alloc_pages(xcall, nr_pages); 134 135 if (!p) 136 return NULL; 137 138 memset(p, 0, nr_pages * PAGE_SIZE); 139 140 return p; 141 } 142 xencall_free_buffer_pages(xencall_handle * xcall,void * p,size_t nr_pages)143 void xencall_free_buffer_pages(xencall_handle *xcall, void *p, size_t nr_pages) 144 { 145 if ( p == NULL ) 146 return; 147 148 if ( !cache_free(xcall, p, nr_pages) ) 149 osdep_free_pages(xcall, p, nr_pages); 150 } 151 152 struct allocation_header { 153 int nr_pages; 154 int pad[3]; 155 }; 156 xencall_alloc_buffer(xencall_handle * xcall,size_t size)157 void *xencall_alloc_buffer(xencall_handle *xcall, size_t size) 158 { 159 size_t actual_size = ROUNDUP(size + sizeof(struct allocation_header), PAGE_SHIFT); 160 int nr_pages = actual_size >> PAGE_SHIFT; 161 struct allocation_header *hdr; 162 163 hdr = xencall_alloc_buffer_pages(xcall, nr_pages); 164 if ( hdr == NULL ) 165 return NULL; 166 167 hdr->nr_pages = nr_pages; 168 169 return (void *)(hdr+1); 170 } 171 xencall_free_buffer(xencall_handle * xcall,void * p)172 void xencall_free_buffer(xencall_handle *xcall, void *p) 173 { 174 struct allocation_header *hdr; 175 176 if (p == NULL) 177 return; 178 179 hdr = p; 180 --hdr; 181 182 xencall_free_buffer_pages(xcall, hdr, hdr->nr_pages); 183 } 184 185 /* 186 * Local variables: 187 * mode: C 188 * c-file-style: "BSD" 189 * c-basic-offset: 4 190 * tab-width: 4 191 * indent-tabs-mode: nil 192 * End: 193 */ 194