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