gst: Don't fail gst_init() if updating the registry fails
[platform/upstream/gstreamer.git] / subprojects / gstreamer / gst / gstallocator.c
1 /* GStreamer
2  * Copyright (C) 2011 Wim Taymans <wim.taymans@gmail.be>
3  *
4  * gstallocator.c: memory block allocator
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., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 /**
23  * SECTION:gstallocator
24  * @title: GstAllocator
25  * @short_description: allocate memory blocks
26  * @see_also: #GstMemory
27  * @auto-sort: false
28  * @symbols:
29  * - GstAllocator
30  *
31  * Memory is usually created by allocators with a gst_allocator_alloc()
32  * method call. When %NULL is used as the allocator, the default allocator will
33  * be used.
34  *
35  * New allocators can be registered with gst_allocator_register().
36  * Allocators are identified by name and can be retrieved with
37  * gst_allocator_find(). gst_allocator_set_default() can be used to change the
38  * default allocator.
39  *
40  * New memory can be created with gst_memory_new_wrapped() that wraps the memory
41  * allocated elsewhere.
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "gst_private.h"
49 #include "gstmemory.h"
50
51 GST_DEBUG_CATEGORY_STATIC (gst_allocator_debug);
52 #define GST_CAT_DEFAULT gst_allocator_debug
53
54 struct _GstAllocatorPrivate
55 {
56   gpointer dummy;
57 };
58
59 #if defined(MEMORY_ALIGNMENT_MALLOC)
60 gsize gst_memory_alignment = 7;
61 #elif defined(MEMORY_ALIGNMENT_PAGESIZE)
62 /* we fill this in in the _init method */
63 gsize gst_memory_alignment = 0;
64 #elif defined(MEMORY_ALIGNMENT)
65 gsize gst_memory_alignment = MEMORY_ALIGNMENT - 1;
66 #else
67 #error "No memory alignment configured"
68 gsize gst_memory_alignment = 0;
69 #endif
70
71 /* the default allocator */
72 static GstAllocator *_default_allocator;
73
74 static GstAllocator *_sysmem_allocator;
75
76 /* registered allocators */
77 static GRWLock lock;
78 static GHashTable *allocators;
79
80 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstAllocator, gst_allocator,
81     GST_TYPE_OBJECT);
82
83 static void
84 gst_allocator_class_init (GstAllocatorClass * klass)
85 {
86   GST_DEBUG_CATEGORY_INIT (gst_allocator_debug, "allocator", 0,
87       "allocator debug");
88 }
89
90 static GstMemory *
91 _fallback_mem_copy (GstMemory * mem, gssize offset, gssize size)
92 {
93   GstMemory *copy;
94   GstMapInfo sinfo, dinfo;
95   GstAllocationParams params = { 0, mem->align, 0, 0, };
96   GstAllocator *allocator;
97
98   if (!gst_memory_map (mem, &sinfo, GST_MAP_READ))
99     return NULL;
100
101   if (size == -1)
102     size = sinfo.size > offset ? sinfo.size - offset : 0;
103
104   /* use the same allocator as the memory we copy  */
105   allocator = mem->allocator;
106   if (GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC))
107     allocator = NULL;
108   copy = gst_allocator_alloc (allocator, size, &params);
109
110   if (!gst_memory_map (copy, &dinfo, GST_MAP_WRITE)) {
111     GST_CAT_WARNING (GST_CAT_MEMORY, "could not write map memory %p", copy);
112     gst_allocator_free (mem->allocator, copy);
113     gst_memory_unmap (mem, &sinfo);
114     return NULL;
115   }
116
117   GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
118       "memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, mem, copy);
119   memcpy (dinfo.data, sinfo.data + offset, size);
120   gst_memory_unmap (copy, &dinfo);
121   gst_memory_unmap (mem, &sinfo);
122
123   return copy;
124 }
125
126 static gboolean
127 _fallback_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
128 {
129   return FALSE;
130 }
131
132 static void
133 gst_allocator_init (GstAllocator * allocator)
134 {
135   allocator->priv = gst_allocator_get_instance_private (allocator);
136
137   allocator->mem_copy = _fallback_mem_copy;
138   allocator->mem_is_span = _fallback_mem_is_span;
139 }
140
141 G_DEFINE_BOXED_TYPE (GstAllocationParams, gst_allocation_params,
142     (GBoxedCopyFunc) gst_allocation_params_copy,
143     (GBoxedFreeFunc) gst_allocation_params_free);
144
145 /**
146  * gst_allocation_params_new:
147  *
148  * Create a new #GstAllocationParams on the heap.  This function is for
149  * use in GStreamer language bindings.  In your own code, you can just
150  * declare a #GstAllocationParams on the stack or in a struct, and
151  * call gst_allocation_params_init() to initialize it.
152  *
153  * You do not need to call gst_allocation_params_init() on the instance
154  * returned by this function.
155  *
156  * Returns: (transfer full) (not nullable): a new #GstAllocationParams
157  *
158  * Since: 1.20
159  */
160 GstAllocationParams *
161 gst_allocation_params_new (void)
162 {
163   /* Call new() and then init(), rather than calling new0(), in case
164    * init() ever changes to something other than a memset(). */
165   GstAllocationParams *result = g_slice_new (GstAllocationParams);
166   gst_allocation_params_init (result);
167   return result;
168 }
169
170 /**
171  * gst_allocation_params_init:
172  * @params: a #GstAllocationParams
173  *
174  * Initialize @params to its default values
175  */
176 void
177 gst_allocation_params_init (GstAllocationParams * params)
178 {
179   g_return_if_fail (params != NULL);
180
181   memset (params, 0, sizeof (GstAllocationParams));
182 }
183
184 /**
185  * gst_allocation_params_copy:
186  * @params: (transfer none) (nullable): a #GstAllocationParams
187  *
188  * Create a copy of @params.
189  *
190  * Returns: (transfer full) (nullable): a new #GstAllocationParams.
191  */
192 GstAllocationParams *
193 gst_allocation_params_copy (const GstAllocationParams * params)
194 {
195   GstAllocationParams *result = NULL;
196
197   if (params) {
198     result =
199         (GstAllocationParams *) g_slice_copy (sizeof (GstAllocationParams),
200         params);
201   }
202   return result;
203 }
204
205 /**
206  * gst_allocation_params_free:
207  * @params: (in) (transfer full): a #GstAllocationParams
208  *
209  * Free @params
210  */
211 void
212 gst_allocation_params_free (GstAllocationParams * params)
213 {
214   g_slice_free (GstAllocationParams, params);
215 }
216
217 /**
218  * gst_allocator_register:
219  * @name: the name of the allocator
220  * @allocator: (transfer full): #GstAllocator
221  *
222  * Registers the memory @allocator with @name.
223  */
224 void
225 gst_allocator_register (const gchar * name, GstAllocator * allocator)
226 {
227   g_return_if_fail (name != NULL);
228   g_return_if_fail (allocator != NULL);
229
230   GST_CAT_DEBUG (GST_CAT_MEMORY, "registering allocator %p with name \"%s\"",
231       allocator, name);
232
233   g_rw_lock_writer_lock (&lock);
234   /* The ref will never be released */
235   GST_OBJECT_FLAG_SET (allocator, GST_OBJECT_FLAG_MAY_BE_LEAKED);
236   g_hash_table_insert (allocators, (gpointer) name, (gpointer) allocator);
237   g_rw_lock_writer_unlock (&lock);
238 }
239
240 /**
241  * gst_allocator_find:
242  * @name: (allow-none): the name of the allocator
243  *
244  * Find a previously registered allocator with @name. When @name is %NULL, the
245  * default allocator will be returned.
246  *
247  * Returns: (transfer full) (nullable): a #GstAllocator or %NULL when
248  * the allocator with @name was not registered.
249  */
250 GstAllocator *
251 gst_allocator_find (const gchar * name)
252 {
253   GstAllocator *allocator;
254
255   g_rw_lock_reader_lock (&lock);
256   if (name) {
257     allocator = g_hash_table_lookup (allocators, (gconstpointer) name);
258   } else {
259     allocator = _default_allocator;
260   }
261   if (allocator)
262     gst_object_ref (allocator);
263   g_rw_lock_reader_unlock (&lock);
264
265   return allocator;
266 }
267
268 /**
269  * gst_allocator_set_default:
270  * @allocator: (transfer full): a #GstAllocator
271  *
272  * Set the default allocator.
273  */
274 void
275 gst_allocator_set_default (GstAllocator * allocator)
276 {
277   GstAllocator *old;
278
279   g_return_if_fail (GST_IS_ALLOCATOR (allocator));
280
281   g_rw_lock_writer_lock (&lock);
282   old = _default_allocator;
283   _default_allocator = allocator;
284   g_rw_lock_writer_unlock (&lock);
285
286   if (old)
287     gst_object_unref (old);
288 }
289
290 /**
291  * gst_allocator_alloc:
292  * @allocator: (transfer none) (allow-none): a #GstAllocator to use
293  * @size: size of the visible memory area
294  * @params: (transfer none) (allow-none): optional parameters
295  *
296  * Use @allocator to allocate a new memory block with memory that is at least
297  * @size big.
298  *
299  * The optional @params can specify the prefix and padding for the memory. If
300  * %NULL is passed, no flags, no extra prefix/padding and a default alignment is
301  * used.
302  *
303  * The prefix/padding will be filled with 0 if flags contains
304  * #GST_MEMORY_FLAG_ZERO_PREFIXED and #GST_MEMORY_FLAG_ZERO_PADDED respectively.
305  *
306  * When @allocator is %NULL, the default allocator will be used.
307  *
308  * The alignment in @params is given as a bitmask so that @align + 1 equals
309  * the amount of bytes to align to. For example, to align to 8 bytes,
310  * use an alignment of 7.
311  *
312  * Returns: (transfer full) (nullable): a new #GstMemory.
313  */
314 GstMemory *
315 gst_allocator_alloc (GstAllocator * allocator, gsize size,
316     GstAllocationParams * params)
317 {
318   GstMemory *mem;
319   static GstAllocationParams defparams = { 0, 0, 0, 0, };
320   GstAllocatorClass *aclass;
321
322   if (params) {
323     g_return_val_if_fail (((params->align + 1) & params->align) == 0, NULL);
324   } else {
325     params = &defparams;
326   }
327
328   if (allocator == NULL)
329     allocator = _default_allocator;
330
331   aclass = GST_ALLOCATOR_GET_CLASS (allocator);
332   if (aclass->alloc)
333     mem = aclass->alloc (allocator, size, params);
334   else
335     mem = NULL;
336
337   return mem;
338 }
339
340 /**
341  * gst_allocator_free:
342  * @allocator: (transfer none): a #GstAllocator to use
343  * @memory: (transfer full): the memory to free
344  *
345  * Free @memory that was previously allocated with gst_allocator_alloc().
346  */
347 void
348 gst_allocator_free (GstAllocator * allocator, GstMemory * memory)
349 {
350   GstAllocatorClass *aclass;
351
352   g_return_if_fail (GST_IS_ALLOCATOR (allocator));
353   g_return_if_fail (memory != NULL);
354   g_return_if_fail (memory->allocator == allocator);
355
356   aclass = GST_ALLOCATOR_GET_CLASS (allocator);
357   if (aclass->free)
358     aclass->free (allocator, memory);
359 }
360
361 /* default memory implementation */
362 typedef struct
363 {
364   GstMemory mem;
365
366   gsize slice_size;
367   guint8 *data;
368
369   gpointer user_data;
370   GDestroyNotify notify;
371 } GstMemorySystem;
372
373 typedef struct
374 {
375   GstAllocator parent;
376 } GstAllocatorSysmem;
377
378 typedef struct
379 {
380   GstAllocatorClass parent_class;
381 } GstAllocatorSysmemClass;
382
383 static GType gst_allocator_sysmem_get_type (void);
384 G_DEFINE_TYPE (GstAllocatorSysmem, gst_allocator_sysmem, GST_TYPE_ALLOCATOR);
385
386 /* initialize the fields */
387 static inline void
388 _sysmem_init (GstMemorySystem * mem, GstMemoryFlags flags,
389     GstMemory * parent, gsize slice_size,
390     gpointer data, gsize maxsize, gsize align, gsize offset, gsize size,
391     gpointer user_data, GDestroyNotify notify)
392 {
393   gst_memory_init (GST_MEMORY_CAST (mem),
394       flags, _sysmem_allocator, parent, maxsize, align, offset, size);
395
396   mem->slice_size = slice_size;
397   mem->data = data;
398   mem->user_data = user_data;
399   mem->notify = notify;
400 }
401
402 /* create a new memory block that manages the given memory */
403 static inline GstMemorySystem *
404 _sysmem_new (GstMemoryFlags flags,
405     GstMemory * parent, gpointer data, gsize maxsize, gsize align, gsize offset,
406     gsize size, gpointer user_data, GDestroyNotify notify)
407 {
408   GstMemorySystem *mem;
409   gsize slice_size;
410
411   slice_size = sizeof (GstMemorySystem);
412
413   mem = g_slice_alloc (slice_size);
414   _sysmem_init (mem, flags, parent, slice_size,
415       data, maxsize, align, offset, size, user_data, notify);
416
417   return mem;
418 }
419
420 /* allocate the memory and structure in one block */
421 static GstMemorySystem *
422 _sysmem_new_block (GstMemoryFlags flags,
423     gsize maxsize, gsize align, gsize offset, gsize size)
424 {
425   GstMemorySystem *mem;
426   gsize aoffset, slice_size, padding;
427   guint8 *data;
428
429   /* ensure configured alignment */
430   align |= gst_memory_alignment;
431   /* allocate more to compensate for alignment */
432   maxsize += align;
433   /* alloc header and data in one block */
434   slice_size = sizeof (GstMemorySystem) + maxsize;
435
436   mem = g_slice_alloc (slice_size);
437   if (mem == NULL)
438     return NULL;
439
440   data = (guint8 *) mem + sizeof (GstMemorySystem);
441
442   /* do alignment */
443   if ((aoffset = ((guintptr) data & align))) {
444     aoffset = (align + 1) - aoffset;
445     data += aoffset;
446     maxsize -= aoffset;
447   }
448
449   if (offset && (flags & GST_MEMORY_FLAG_ZERO_PREFIXED))
450     memset (data, 0, offset);
451
452   padding = maxsize - (offset + size);
453   if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))
454     memset (data + offset + size, 0, padding);
455
456   _sysmem_init (mem, flags, NULL, slice_size, data, maxsize,
457       align, offset, size, NULL, NULL);
458
459   return mem;
460 }
461
462 static gpointer
463 _sysmem_map (GstMemorySystem * mem, gsize maxsize, GstMapFlags flags)
464 {
465   return mem->data;
466 }
467
468 static gboolean
469 _sysmem_unmap (GstMemorySystem * mem)
470 {
471   return TRUE;
472 }
473
474 static GstMemorySystem *
475 _sysmem_copy (GstMemorySystem * mem, gssize offset, gsize size)
476 {
477   GstMemorySystem *copy;
478
479   if (size == -1)
480     size = mem->mem.size > offset ? mem->mem.size - offset : 0;
481
482   copy = _sysmem_new_block (0, size, mem->mem.align, 0, size);
483   GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
484       "memcpy %" G_GSIZE_FORMAT " memory %p -> %p", size, mem, copy);
485   memcpy (copy->data, mem->data + mem->mem.offset + offset, size);
486
487   return copy;
488 }
489
490 static GstMemorySystem *
491 _sysmem_share (GstMemorySystem * mem, gssize offset, gsize size)
492 {
493   GstMemorySystem *sub;
494   GstMemory *parent;
495
496   /* find the real parent */
497   if ((parent = mem->mem.parent) == NULL)
498     parent = (GstMemory *) mem;
499
500   if (size == -1)
501     size = mem->mem.size - offset;
502
503   /* the shared memory is always readonly */
504   sub =
505       _sysmem_new (GST_MINI_OBJECT_FLAGS (parent) |
506       GST_MINI_OBJECT_FLAG_LOCK_READONLY, parent, mem->data, mem->mem.maxsize,
507       mem->mem.align, mem->mem.offset + offset, size, NULL, NULL);
508
509   return sub;
510 }
511
512 static gboolean
513 _sysmem_is_span (GstMemorySystem * mem1, GstMemorySystem * mem2, gsize * offset)
514 {
515
516   if (offset) {
517     GstMemorySystem *parent;
518
519     parent = (GstMemorySystem *) mem1->mem.parent;
520
521     *offset = mem1->mem.offset - parent->mem.offset;
522   }
523
524   /* and memory is contiguous */
525   return mem1->data + mem1->mem.offset + mem1->mem.size ==
526       mem2->data + mem2->mem.offset;
527 }
528
529 static GstMemory *
530 default_alloc (GstAllocator * allocator, gsize size,
531     GstAllocationParams * params)
532 {
533   gsize maxsize = size + params->prefix + params->padding;
534
535   return (GstMemory *) _sysmem_new_block (params->flags,
536       maxsize, params->align, params->prefix, size);
537 }
538
539 static void
540 default_free (GstAllocator * allocator, GstMemory * mem)
541 {
542   GstMemorySystem *dmem = (GstMemorySystem *) mem;
543   gsize slice_size;
544
545   if (dmem->notify)
546     dmem->notify (dmem->user_data);
547
548   slice_size = dmem->slice_size;
549
550 #ifdef USE_POISONING
551   /* just poison the structs, not all the data */
552   memset (mem, 0xff, sizeof (GstMemorySystem));
553 #endif
554
555   g_slice_free1 (slice_size, mem);
556 }
557
558 static void
559 gst_allocator_sysmem_finalize (GObject * obj)
560 {
561   /* Don't raise warnings if we are shutting down */
562   if (_default_allocator)
563     g_warning ("The default memory allocator was freed!");
564
565   ((GObjectClass *) gst_allocator_sysmem_parent_class)->finalize (obj);
566 }
567
568 static void
569 gst_allocator_sysmem_class_init (GstAllocatorSysmemClass * klass)
570 {
571   GObjectClass *gobject_class;
572   GstAllocatorClass *allocator_class;
573
574   gobject_class = (GObjectClass *) klass;
575   allocator_class = (GstAllocatorClass *) klass;
576
577   gobject_class->finalize = gst_allocator_sysmem_finalize;
578
579   allocator_class->alloc = default_alloc;
580   allocator_class->free = default_free;
581 }
582
583 static void
584 gst_allocator_sysmem_init (GstAllocatorSysmem * allocator)
585 {
586   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
587
588   GST_CAT_DEBUG (GST_CAT_MEMORY, "init allocator %p", allocator);
589
590   alloc->mem_type = GST_ALLOCATOR_SYSMEM;
591   alloc->mem_map = (GstMemoryMapFunction) _sysmem_map;
592   alloc->mem_unmap = (GstMemoryUnmapFunction) _sysmem_unmap;
593   alloc->mem_copy = (GstMemoryCopyFunction) _sysmem_copy;
594   alloc->mem_share = (GstMemoryShareFunction) _sysmem_share;
595   alloc->mem_is_span = (GstMemoryIsSpanFunction) _sysmem_is_span;
596 }
597
598 void
599 _priv_gst_allocator_initialize (void)
600 {
601   g_rw_lock_init (&lock);
602   allocators = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
603       gst_object_unref);
604
605 #ifdef HAVE_GETPAGESIZE
606 #ifdef MEMORY_ALIGNMENT_PAGESIZE
607   gst_memory_alignment = getpagesize () - 1;
608 #endif
609 #endif
610
611   GST_CAT_DEBUG (GST_CAT_MEMORY, "memory alignment: %" G_GSIZE_FORMAT,
612       gst_memory_alignment);
613
614   _sysmem_allocator = g_object_new (gst_allocator_sysmem_get_type (), NULL);
615
616   /* Clear floating flag */
617   gst_object_ref_sink (_sysmem_allocator);
618
619   gst_allocator_register (GST_ALLOCATOR_SYSMEM,
620       gst_object_ref (_sysmem_allocator));
621
622   _default_allocator = gst_object_ref (_sysmem_allocator);
623 }
624
625 void
626 _priv_gst_allocator_cleanup (void)
627 {
628   gst_object_unref (_sysmem_allocator);
629   _sysmem_allocator = NULL;
630
631   gst_object_unref (_default_allocator);
632   _default_allocator = NULL;
633
634   g_clear_pointer (&allocators, g_hash_table_unref);
635 }
636
637 /**
638  * gst_memory_new_wrapped:
639  * @flags: #GstMemoryFlags
640  * @data: (array length=size) (element-type guint8) (transfer none): data to
641  *   wrap
642  * @maxsize: allocated size of @data
643  * @offset: offset in @data
644  * @size: size of valid data
645  * @user_data: (allow-none): user_data
646  * @notify: (allow-none) (scope async) (closure user_data): called with @user_data when the memory is freed
647  *
648  * Allocate a new memory block that wraps the given @data.
649  *
650  * The prefix/padding must be filled with 0 if @flags contains
651  * #GST_MEMORY_FLAG_ZERO_PREFIXED and #GST_MEMORY_FLAG_ZERO_PADDED respectively.
652  *
653  * Returns: (transfer full) (nullable): a new #GstMemory.
654  */
655 GstMemory *
656 gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data,
657     gsize maxsize, gsize offset, gsize size, gpointer user_data,
658     GDestroyNotify notify)
659 {
660   GstMemorySystem *mem;
661
662   g_return_val_if_fail (data != NULL, NULL);
663   g_return_val_if_fail (offset + size <= maxsize, NULL);
664
665   mem =
666       _sysmem_new (flags, NULL, data, maxsize, 0, offset, size, user_data,
667       notify);
668
669   return (GstMemory *) mem;
670 }