pb_bufmgr_debug.c revision d16fcd07f876fe7fb29f5f4e3df4e83ff7de3422
1/************************************************************************** 2 * 3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/** 29 * \file 30 * Debug buffer manager to detect buffer under- and overflows. 31 * 32 * \author José Fonseca <jrfonseca@tungstengraphics.com> 33 */ 34 35 36#include "pipe/p_compiler.h" 37#include "pipe/p_debug.h" 38#include "pipe/p_winsys.h" 39#include "pipe/p_thread.h" 40#include "pipe/p_util.h" 41#include "util/u_double_list.h" 42#include "util/u_time.h" 43 44#include "pb_buffer.h" 45#include "pb_bufmgr.h" 46 47 48#ifdef DEBUG 49 50 51/** 52 * Convenience macro (type safe). 53 */ 54#define SUPER(__derived) (&(__derived)->base) 55 56 57struct pb_debug_manager; 58 59 60/** 61 * Wrapper around a pipe buffer which adds delayed destruction. 62 */ 63struct pb_debug_buffer 64{ 65 struct pb_buffer base; 66 67 struct pb_buffer *buffer; 68 struct pb_debug_manager *mgr; 69 70 size_t underflow_size; 71 size_t overflow_size; 72}; 73 74 75struct pb_debug_manager 76{ 77 struct pb_manager base; 78 79 struct pb_manager *provider; 80 81 size_t band_size; 82}; 83 84 85static INLINE struct pb_debug_buffer * 86pb_debug_buffer(struct pb_buffer *buf) 87{ 88 assert(buf); 89 return (struct pb_debug_buffer *)buf; 90} 91 92 93static INLINE struct pb_debug_manager * 94pb_debug_manager(struct pb_manager *mgr) 95{ 96 assert(mgr); 97 return (struct pb_debug_manager *)mgr; 98} 99 100 101static const uint8_t random_pattern[32] = { 102 0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a, 103 0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e, 104 0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4, 105 0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94 106}; 107 108 109static INLINE void 110fill_random_pattern(uint8_t *dst, size_t size) 111{ 112 unsigned i = 0; 113 while(size--) { 114 *dst++ = random_pattern[i++]; 115 i &= sizeof(random_pattern) - 1; 116 } 117} 118 119 120static INLINE boolean 121check_random_pattern(const uint8_t *dst, size_t size) 122{ 123 unsigned i = 0; 124 while(size--) { 125 if(*dst++ != random_pattern[i++]) 126 return FALSE; 127 i &= sizeof(random_pattern) - 1; 128 } 129 return TRUE; 130} 131 132 133static void 134pb_debug_buffer_destroy(struct pb_buffer *_buf) 135{ 136 struct pb_debug_buffer *buf = pb_debug_buffer(_buf); 137 uint8_t *map; 138 139 assert(!buf->base.base.refcount); 140 141 map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_READ); 142 assert(map); 143 if(map) { 144 if(!check_random_pattern(map, buf->underflow_size)) { 145 debug_printf("buffer underflow\n"); 146 debug_assert(0); 147 } 148 if(!check_random_pattern(map + buf->underflow_size + buf->base.base.size, 149 buf->overflow_size)) { 150 debug_printf("buffer overflow\n"); 151 debug_assert(0); 152 } 153 pb_unmap(buf->buffer); 154 } 155 156 pb_reference(&buf->buffer, NULL); 157 FREE(buf); 158} 159 160 161static void * 162pb_debug_buffer_map(struct pb_buffer *_buf, 163 unsigned flags) 164{ 165 struct pb_debug_buffer *buf = pb_debug_buffer(_buf); 166 void *map = pb_map(buf->buffer, flags); 167 if(!map) 168 return NULL; 169 return (uint8_t *)map + buf->underflow_size; 170} 171 172 173static void 174pb_debug_buffer_unmap(struct pb_buffer *_buf) 175{ 176 struct pb_debug_buffer *buf = pb_debug_buffer(_buf); 177 pb_unmap(buf->buffer); 178} 179 180 181static void 182pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf, 183 struct pb_buffer **base_buf, 184 unsigned *offset) 185{ 186 struct pb_debug_buffer *buf = pb_debug_buffer(_buf); 187 pb_get_base_buffer(buf->buffer, base_buf, offset); 188 *offset += buf->underflow_size; 189} 190 191 192const struct pb_vtbl 193pb_debug_buffer_vtbl = { 194 pb_debug_buffer_destroy, 195 pb_debug_buffer_map, 196 pb_debug_buffer_unmap, 197 pb_debug_buffer_get_base_buffer 198}; 199 200 201static struct pb_buffer * 202pb_debug_manager_create_buffer(struct pb_manager *_mgr, 203 size_t size, 204 const struct pb_desc *desc) 205{ 206 struct pb_debug_manager *mgr = pb_debug_manager(_mgr); 207 struct pb_debug_buffer *buf; 208 struct pb_desc real_desc; 209 size_t real_size; 210 uint8_t *map; 211 212 buf = CALLOC_STRUCT(pb_debug_buffer); 213 if(!buf) 214 return NULL; 215 216 real_size = size + 2*mgr->band_size; 217 real_desc = *desc; 218 real_desc.usage |= PIPE_BUFFER_USAGE_CPU_WRITE; 219 real_desc.usage |= PIPE_BUFFER_USAGE_CPU_READ; 220 221 buf->buffer = mgr->provider->create_buffer(mgr->provider, 222 real_size, 223 &real_desc); 224 if(!buf->buffer) { 225 FREE(buf); 226 return NULL; 227 } 228 229 assert(buf->buffer->base.refcount >= 1); 230 assert(pb_check_alignment(real_desc.alignment, buf->buffer->base.alignment)); 231 assert(pb_check_usage(real_desc.usage, buf->buffer->base.usage)); 232 assert(buf->buffer->base.size >= real_size); 233 234 buf->base.base.refcount = 1; 235 buf->base.base.alignment = desc->alignment; 236 buf->base.base.usage = desc->usage; 237 buf->base.base.size = size; 238 239 buf->base.vtbl = &pb_debug_buffer_vtbl; 240 buf->mgr = mgr; 241 242 buf->underflow_size = mgr->band_size; 243 buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size; 244 245 map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); 246 assert(map); 247 if(map) { 248 fill_random_pattern(map, buf->underflow_size); 249 fill_random_pattern(map + buf->underflow_size + size, buf->overflow_size); 250 pb_unmap(buf->buffer); 251 } 252 253 return &buf->base; 254} 255 256 257static void 258pb_debug_manager_destroy(struct pb_manager *_mgr) 259{ 260 struct pb_debug_manager *mgr = pb_debug_manager(_mgr); 261 mgr->provider->destroy(mgr->provider); 262 FREE(mgr); 263} 264 265 266struct pb_manager * 267pb_debug_manager_create(struct pb_manager *provider, size_t band_size) 268{ 269 struct pb_debug_manager *mgr; 270 271 if(!provider) 272 return NULL; 273 274 mgr = CALLOC_STRUCT(pb_debug_manager); 275 if (!mgr) 276 return NULL; 277 278 mgr->base.destroy = pb_debug_manager_destroy; 279 mgr->base.create_buffer = pb_debug_manager_create_buffer; 280 mgr->provider = provider; 281 mgr->band_size = band_size; 282 283 return &mgr->base; 284} 285 286 287#else /* !DEBUG */ 288 289 290struct pb_manager * 291pb_debug_manager_create(struct pb_manager *provider, size_t band_size) 292{ 293 return provider; 294} 295 296 297#endif /* !DEBUG */ 298