Remove unused variables in _class_init
[platform/upstream/gstreamer.git] / gst / debugutils / efence.c
1 /*
2  * GStreamer
3  * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
4  * Copyright (C) 2002 David A. Schleef <ds@schleef.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <gst/gst.h>
26
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/mman.h>
30
31 #include "efence.h"
32
33 #ifndef MAP_ANONYMOUS
34 #ifdef MAP_ANON
35 #define MAP_ANONYMOUS MAP_ANON
36 #else
37 /* assume we don't need it */
38 #define MAP_ANONYMOUS 0
39 #endif
40 #endif
41
42 GST_DEBUG_CATEGORY_STATIC (gst_efence_debug);
43 #define GST_CAT_DEFAULT  gst_efence_debug
44
45 static const GstElementDetails plugin_details =
46 GST_ELEMENT_DETAILS ("Electric Fence",
47     "Testing",
48     "This element converts a stream of normal GStreamer buffers into a "
49     "stream of buffers that are allocated in such a way that out-of-bounds "
50     "access to data in the buffer is more likely to cause segmentation "
51     "faults.  This allocation method is very similar to the debugging tool "
52     "\"Electric Fence\".",
53     "David A. Schleef <ds@schleef.org>");
54
55 /* Filter signals and args */
56 enum
57 {
58   /* FILL ME */
59   LAST_SIGNAL
60 };
61
62 enum
63 {
64   ARG_0,
65   ARG_FENCE_TOP
66 };
67
68 static GstStaticPadTemplate gst_efence_sink_factory =
69 GST_STATIC_PAD_TEMPLATE ("sink",
70     GST_PAD_SINK,
71     GST_PAD_ALWAYS,
72     GST_STATIC_CAPS_ANY);
73
74 static GstStaticPadTemplate gst_efence_src_factory =
75 GST_STATIC_PAD_TEMPLATE ("src",
76     GST_PAD_SRC,
77     GST_PAD_ALWAYS,
78     GST_STATIC_CAPS_ANY);
79
80 static void gst_efence_base_init (gpointer g_class);
81 static void gst_efence_class_init (GstEFenceClass * klass);
82 static void gst_efence_init (GstEFence * filter);
83
84 static void gst_efence_set_property (GObject * object, guint prop_id,
85     const GValue * value, GParamSpec * pspec);
86 static void gst_efence_get_property (GObject * object, guint prop_id,
87     GValue * value, GParamSpec * pspec);
88
89 static GstFlowReturn gst_efence_chain (GstPad * pad, GstBuffer * buf);
90 static GstFlowReturn gst_efence_getrange (GstPad * pad, guint64 offset,
91     guint length, GstBuffer ** buffer);
92 static gboolean gst_efence_checkgetrange (GstPad * pad);
93 static gboolean gst_efence_activate_src_pull (GstPad * pad, gboolean active);
94
95 static GstElementClass *parent_class = NULL;
96
97 typedef struct _GstFencedBuffer GstFencedBuffer;
98 struct _GstFencedBuffer
99 {
100   GstBuffer buffer;
101   void *region;
102   unsigned int length;
103 };
104
105 GType gst_fenced_buffer_get_type (void);
106 static void gst_fenced_buffer_finalize (GstFencedBuffer * buf);
107 static GstFencedBuffer *gst_fenced_buffer_copy (const GstBuffer * buffer);
108 static void *gst_fenced_buffer_alloc (GstBuffer * buffer, unsigned int length,
109     gboolean fence_top);
110 static GstFlowReturn gst_efence_buffer_alloc (GstPad * pad, guint64 offset,
111     guint size, GstCaps * caps, GstBuffer ** buf);
112
113 #define GST_TYPE_FENCED_BUFFER (gst_fenced_buffer_get_type())
114
115 #define GST_IS_FENCED_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FENCED_BUFFER))
116 #define GST_FENCED_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_FENCED_BUFFER, GstFencedBuffer))
117
118 GType
119 gst_gst_efence_get_type (void)
120 {
121   static GType plugin_type = 0;
122
123   if (!plugin_type) {
124     static const GTypeInfo plugin_info = {
125       sizeof (GstEFenceClass),
126       gst_efence_base_init,
127       NULL,
128       (GClassInitFunc) gst_efence_class_init,
129       NULL,
130       NULL,
131       sizeof (GstEFence),
132       0,
133       (GInstanceInitFunc) gst_efence_init,
134     };
135
136     plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
137         "GstEFence", &plugin_info, 0);
138   }
139   return plugin_type;
140 }
141
142 static void
143 gst_efence_base_init (gpointer g_class)
144 {
145   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
146
147   gst_element_class_add_pad_template (element_class,
148       gst_static_pad_template_get (&gst_efence_sink_factory));
149   gst_element_class_add_pad_template (element_class,
150       gst_static_pad_template_get (&gst_efence_src_factory));
151   gst_element_class_set_details (element_class, &plugin_details);
152 }
153
154 /* initialize the plugin's class */
155 static void
156 gst_efence_class_init (GstEFenceClass * klass)
157 {
158   GObjectClass *gobject_class;
159
160   gobject_class = (GObjectClass *) klass;
161
162   parent_class = g_type_class_peek_parent (klass);
163
164   gobject_class->set_property = gst_efence_set_property;
165   gobject_class->get_property = gst_efence_get_property;
166
167   g_object_class_install_property (gobject_class, ARG_FENCE_TOP,
168       g_param_spec_boolean ("fence_top", "Fence Top",
169           "Align buffers with top of fenced region", TRUE, G_PARAM_READWRITE));
170 }
171
172 /* initialize the new element
173  * instantiate pads and add them to element
174  * set functions
175  * initialize structure
176  */
177 static void
178 gst_efence_init (GstEFence * filter)
179 {
180   filter->sinkpad =
181       gst_pad_new_from_static_template (&gst_efence_sink_factory, "sink");
182   gst_pad_set_getcaps_function (filter->sinkpad,
183       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
184   gst_pad_set_setcaps_function (filter->sinkpad,
185       GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
186   gst_pad_set_chain_function (filter->sinkpad,
187       GST_DEBUG_FUNCPTR (gst_efence_chain));
188   gst_pad_set_bufferalloc_function (filter->sinkpad,
189       GST_DEBUG_FUNCPTR (gst_efence_buffer_alloc));
190   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
191
192   filter->srcpad =
193       gst_pad_new_from_static_template (&gst_efence_src_factory, "src");
194   gst_pad_set_getcaps_function (filter->srcpad,
195       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
196   gst_pad_set_setcaps_function (filter->srcpad,
197       GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
198   gst_pad_set_checkgetrange_function (filter->srcpad,
199       GST_DEBUG_FUNCPTR (gst_efence_checkgetrange));
200   gst_pad_set_getrange_function (filter->srcpad,
201       GST_DEBUG_FUNCPTR (gst_efence_getrange));
202   gst_pad_set_activatepull_function (filter->srcpad,
203       GST_DEBUG_FUNCPTR (gst_efence_activate_src_pull));
204
205   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
206
207   filter->fence_top = TRUE;
208 }
209
210 /* chain function
211  * this function does the actual processing
212  */
213
214 static GstFlowReturn
215 gst_efence_chain (GstPad * pad, GstBuffer * buffer)
216 {
217   GstEFence *efence;
218   GstBuffer *copy;
219
220   efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
221   g_return_val_if_fail (GST_IS_EFENCE (efence), GST_FLOW_ERROR);
222
223   if (GST_IS_FENCED_BUFFER (buffer)) {
224     GST_DEBUG_OBJECT (efence, "Passing on existing fenced buffer with caps %"
225         GST_PTR_FORMAT, GST_BUFFER_CAPS (buffer));
226     return gst_pad_push (efence->srcpad, buffer);
227   }
228
229   copy = (GstBuffer *) gst_fenced_buffer_copy (buffer);
230
231   GST_DEBUG_OBJECT (efence, "Pushing newly fenced buffer with caps %"
232       GST_PTR_FORMAT ", data=%p, size=%u", GST_BUFFER_CAPS (copy),
233       GST_BUFFER_DATA (copy), GST_BUFFER_SIZE (copy));
234
235   gst_buffer_unref (buffer);
236
237   return gst_pad_push (efence->srcpad, copy);
238 }
239
240 static GstFlowReturn
241 gst_efence_getrange (GstPad * pad, guint64 offset,
242     guint length, GstBuffer ** buffer)
243 {
244   GstEFence *efence;
245   GstFlowReturn ret;
246   GstBuffer *ownbuf;
247   GstPad *peer;
248
249   efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
250
251   peer = gst_pad_get_peer (efence->sinkpad);
252   if (!peer)
253     return GST_FLOW_NOT_LINKED;
254
255   if ((ret = gst_pad_get_range (peer, offset, length, buffer)) != GST_FLOW_OK)
256     goto beach;
257
258   ownbuf = (GstBuffer *) gst_fenced_buffer_copy (*buffer);
259   gst_buffer_unref ((GstBuffer *) * buffer);
260   *buffer = ownbuf;
261
262 beach:
263   gst_object_unref (peer);
264   return ret;
265 }
266
267 static gboolean
268 gst_efence_checkgetrange (GstPad * pad)
269 {
270   GstEFence *efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
271
272   return gst_pad_check_pull_range (efence->sinkpad);
273 }
274
275 static gboolean
276 gst_efence_activate_src_pull (GstPad * pad, gboolean active)
277 {
278   GstEFence *efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
279
280   return gst_pad_activate_pull (efence->sinkpad, active);
281 }
282
283 static GstFlowReturn
284 gst_efence_buffer_alloc (GstPad * pad, guint64 offset,
285     guint size, GstCaps * caps, GstBuffer ** buf)
286 {
287   GstBuffer *buffer;
288   GstEFence *efence;
289
290   g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
291   g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
292
293   efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
294
295   buffer = (GstBuffer *) gst_mini_object_new (GST_TYPE_FENCED_BUFFER);
296
297   GST_BUFFER_DATA (buffer) = gst_fenced_buffer_alloc (buffer, size,
298       efence->fence_top);
299   GST_BUFFER_SIZE (buffer) = size;
300   GST_BUFFER_OFFSET (buffer) = offset;
301
302   if (caps)
303     gst_buffer_set_caps (buffer, caps);
304
305   *buf = buffer;
306
307   GST_DEBUG_OBJECT (efence, "Allocated buffer of size %u, caps: %"
308       GST_PTR_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_CAPS (buffer));
309
310   return GST_FLOW_OK;
311 }
312
313 static void
314 gst_efence_set_property (GObject * object, guint prop_id,
315     const GValue * value, GParamSpec * pspec)
316 {
317   GstEFence *filter;
318
319   g_return_if_fail (GST_IS_EFENCE (object));
320   filter = GST_EFENCE (object);
321
322   switch (prop_id) {
323     case ARG_FENCE_TOP:
324       filter->fence_top = g_value_get_boolean (value);
325       break;
326     default:
327       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328       break;
329   }
330 }
331
332 static void
333 gst_efence_get_property (GObject * object, guint prop_id,
334     GValue * value, GParamSpec * pspec)
335 {
336   GstEFence *filter;
337
338   g_return_if_fail (GST_IS_EFENCE (object));
339   filter = GST_EFENCE (object);
340
341   switch (prop_id) {
342     case ARG_FENCE_TOP:
343       g_value_set_boolean (value, filter->fence_top);
344       break;
345     default:
346       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
347       break;
348   }
349 }
350
351 /* entry point to initialize the plug-in
352  * initialize the plug-in itself
353  * register the element factories and pad templates
354  * register the features
355  */
356 static gboolean
357 plugin_init (GstPlugin * plugin)
358 {
359   if (!gst_element_register (plugin, "efence", GST_RANK_NONE, GST_TYPE_EFENCE))
360     return FALSE;
361
362   GST_DEBUG_CATEGORY_INIT (gst_efence_debug, "efence", 0,
363       "Debug output from the efence element");
364
365   /* plugin initialisation succeeded */
366   return TRUE;
367 }
368
369 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
370     GST_VERSION_MINOR,
371     "efence",
372     "This element converts a stream of normal GStreamer buffers into a "
373     "stream of buffers that are allocated in such a way that out-of-bounds "
374     "access to data in the buffer is more likely to cause segmentation "
375     "faults.  This allocation method is very similar to the debugging tool "
376     "\"Electric Fence\".",
377     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
378
379
380 static GstBufferClass *fenced_buffer_parent_class = NULL;
381
382 static void
383 gst_fenced_buffer_finalize (GstFencedBuffer * buffer)
384 {
385   GstFencedBuffer *fenced_buffer;
386
387   GST_DEBUG ("free buffer=%p", buffer);
388
389   fenced_buffer = GST_FENCED_BUFFER (buffer);
390
391   /* free our data */
392   if (GST_BUFFER_DATA (buffer)) {
393     GST_DEBUG ("free region %p %d", fenced_buffer->region,
394         fenced_buffer->length);
395     munmap (fenced_buffer->region, fenced_buffer->length);
396   }
397
398   GST_MINI_OBJECT_CLASS (fenced_buffer_parent_class)->finalize (GST_MINI_OBJECT
399       (buffer));
400 }
401
402 static GstFencedBuffer *
403 gst_fenced_buffer_copy (const GstBuffer * buffer)
404 {
405   GstBuffer *copy;
406   void *ptr;
407   guint mask;
408
409   g_return_val_if_fail (buffer != NULL, NULL);
410
411   /* create a fresh new buffer */
412   copy = (GstBuffer *) gst_mini_object_new (GST_TYPE_FENCED_BUFFER);
413
414   /* we simply copy everything from our parent */
415   ptr = gst_fenced_buffer_alloc (GST_BUFFER (copy),
416       GST_BUFFER_SIZE (buffer), TRUE);
417   memcpy (ptr, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
418
419   /* copy relevant flags */
420   mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
421       GST_BUFFER_FLAG_DELTA_UNIT;
422   GST_MINI_OBJECT (copy)->flags |= GST_MINI_OBJECT (buffer)->flags & mask;
423
424   GST_BUFFER_DATA (copy) = ptr;
425   GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
426   GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
427   GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
428   GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
429   GST_BUFFER_OFFSET_END (copy) = GST_BUFFER_OFFSET_END (buffer);
430
431   if (GST_BUFFER_CAPS (buffer))
432     GST_BUFFER_CAPS (copy) = gst_caps_ref (GST_BUFFER_CAPS (buffer));
433   else
434     GST_BUFFER_CAPS (copy) = NULL;
435
436   GST_DEBUG ("Copied buffer %p with ts %" GST_TIME_FORMAT
437       ", caps: %" GST_PTR_FORMAT, buffer,
438       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (copy)), GST_BUFFER_CAPS (copy));
439
440   return GST_FENCED_BUFFER (copy);
441 }
442
443 void *
444 gst_fenced_buffer_alloc (GstBuffer * buffer, unsigned int length,
445     gboolean fence_top)
446 {
447   int alloc_size;
448   void *region;
449   GstFencedBuffer *fenced_buffer = (GstFencedBuffer *) buffer;
450   int page_size;
451
452   GST_DEBUG ("buffer=%p length=%d fence_top=%d", buffer, length, fence_top);
453
454   if (length == 0)
455     return NULL;
456
457 #ifdef _SC_PAGESIZE
458   page_size = sysconf (_SC_PAGESIZE);
459 #else
460   page_size = getpagesize ();
461 #endif
462
463   /* Allocate a complete page, and one on either side */
464   alloc_size = ((length - 1) & ~(page_size - 1)) + page_size;
465   alloc_size += 2 * page_size;
466
467   region = mmap (NULL, alloc_size, PROT_READ | PROT_WRITE,
468       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
469   if (region == MAP_FAILED) {
470     g_warning ("mmap failed");
471     return NULL;
472   }
473 #if 0
474   munmap (region, page_size);
475   munmap (region + alloc_size - page_size, page_size);
476
477   fenced_buffer->region = region + page_size;
478   fenced_buffer->length = alloc_size - page_size;
479 #else
480   mprotect (region, page_size, PROT_NONE);
481   mprotect ((char *) region + alloc_size - page_size, page_size, PROT_NONE);
482
483   fenced_buffer->region = region;
484   fenced_buffer->length = alloc_size;
485 #endif
486
487   GST_DEBUG ("new region %p %d", fenced_buffer->region, fenced_buffer->length);
488
489   if (fence_top) {
490     int offset;
491
492     /* Align to top of region, but force alignment to 4 bytes */
493     offset = alloc_size - page_size - length;
494     offset &= ~0x3;
495     return (void *) ((char *) region + offset);
496   } else {
497     return (void *) ((char *) region + page_size);
498   }
499 }
500
501 static void
502 gst_fenced_buffer_class_init (gpointer g_class, gpointer class_data)
503 {
504   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
505
506   fenced_buffer_parent_class = g_type_class_peek_parent (g_class);
507
508   mini_object_class->finalize =
509       (GstMiniObjectFinalizeFunction) gst_fenced_buffer_finalize;
510   mini_object_class->copy = (GstMiniObjectCopyFunction) gst_fenced_buffer_copy;
511 }
512
513 GType
514 gst_fenced_buffer_get_type (void)
515 {
516   static GType fenced_buf_type = 0;
517
518   if (G_UNLIKELY (!fenced_buf_type)) {
519     static const GTypeInfo fenced_buf_info = {
520       sizeof (GstBufferClass),
521       NULL,
522       NULL,
523       (GClassInitFunc) gst_fenced_buffer_class_init,
524       NULL,
525       NULL,
526       sizeof (GstFencedBuffer),
527       0,
528       NULL,
529     };
530
531     fenced_buf_type = g_type_register_static (GST_TYPE_BUFFER,
532         "GstFencedBuffer", &fenced_buf_info, 0);
533   }
534   return fenced_buf_type;
535 }