• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 
12 #define __VPX_MEM_C__
13 
14 #include "vpx_mem.h"
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "include/vpx_mem_intrnl.h"
19 
20 #if CONFIG_MEM_TRACKER
21 #ifndef VPX_NO_GLOBALS
22 static unsigned long g_alloc_count = 0;
23 #else
24 #include "vpx_global_handling.h"
25 #define g_alloc_count vpxglobalm(vpxmem,g_alloc_count)
26 #endif
27 #endif
28 
29 #if CONFIG_MEM_MANAGER
30 # include "heapmm.h"
31 # include "hmm_intrnl.h"
32 
33 # define SHIFT_HMM_ADDR_ALIGN_UNIT 5
34 # define TOTAL_MEMORY_TO_ALLOCATE  20971520 /* 20 * 1024 * 1024 */
35 
36 # define MM_DYNAMIC_MEMORY 1
37 # if MM_DYNAMIC_MEMORY
38 static unsigned char *g_p_mng_memory_raw = NULL;
39 static unsigned char *g_p_mng_memory     = NULL;
40 # else
41 static unsigned char g_p_mng_memory[TOTAL_MEMORY_TO_ALLOCATE];
42 # endif
43 
44 static size_t g_mm_memory_size = TOTAL_MEMORY_TO_ALLOCATE;
45 
46 static hmm_descriptor hmm_d;
47 static int g_mng_memory_allocated = 0;
48 
49 static int vpx_mm_create_heap_memory();
50 static void *vpx_mm_realloc(void *memblk, size_t size);
51 #endif /*CONFIG_MEM_MANAGER*/
52 
53 #if USE_GLOBAL_FUNCTION_POINTERS
54 struct GLOBAL_FUNC_POINTERS {
55   g_malloc_func g_malloc;
56   g_calloc_func g_calloc;
57   g_realloc_func g_realloc;
58   g_free_func g_free;
59   g_memcpy_func g_memcpy;
60   g_memset_func g_memset;
61   g_memmove_func g_memmove;
62 } *g_func = NULL;
63 
64 # define VPX_MALLOC_L  g_func->g_malloc
65 # define VPX_REALLOC_L g_func->g_realloc
66 # define VPX_FREE_L    g_func->g_free
67 # define VPX_MEMCPY_L  g_func->g_memcpy
68 # define VPX_MEMSET_L  g_func->g_memset
69 # define VPX_MEMMOVE_L g_func->g_memmove
70 #else
71 # define VPX_MALLOC_L  malloc
72 # define VPX_REALLOC_L realloc
73 # define VPX_FREE_L    free
74 # define VPX_MEMCPY_L  memcpy
75 # define VPX_MEMSET_L  memset
76 # define VPX_MEMMOVE_L memmove
77 #endif /* USE_GLOBAL_FUNCTION_POINTERS */
78 
vpx_mem_get_version()79 unsigned int vpx_mem_get_version() {
80   unsigned int ver = ((unsigned int)(unsigned char)VPX_MEM_VERSION_CHIEF << 24 |
81                       (unsigned int)(unsigned char)VPX_MEM_VERSION_MAJOR << 16 |
82                       (unsigned int)(unsigned char)VPX_MEM_VERSION_MINOR << 8  |
83                       (unsigned int)(unsigned char)VPX_MEM_VERSION_PATCH);
84   return ver;
85 }
86 
vpx_mem_set_heap_size(size_t size)87 int vpx_mem_set_heap_size(size_t size) {
88   int ret = -1;
89 
90 #if CONFIG_MEM_MANAGER
91 #if MM_DYNAMIC_MEMORY
92 
93   if (!g_mng_memory_allocated && size) {
94     g_mm_memory_size = size;
95     ret = 0;
96   } else
97     ret = -3;
98 
99 #else
100   ret = -2;
101 #endif
102 #else
103   (void)size;
104 #endif
105 
106   return ret;
107 }
108 
vpx_memalign(size_t align,size_t size)109 void *vpx_memalign(size_t align, size_t size) {
110   void *addr,
111        * x = NULL;
112 
113 #if CONFIG_MEM_MANAGER
114   int number_aau;
115 
116   if (vpx_mm_create_heap_memory() < 0) {
117     _P(printf("[vpx][mm] ERROR vpx_memalign() Couldn't create memory for Heap.\n");)
118   }
119 
120   number_aau = ((size + align - 1 + ADDRESS_STORAGE_SIZE) >>
121                 SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
122 
123   addr = hmm_alloc(&hmm_d, number_aau);
124 #else
125   addr = VPX_MALLOC_L(size + align - 1 + ADDRESS_STORAGE_SIZE);
126 #endif /*CONFIG_MEM_MANAGER*/
127 
128   if (addr) {
129     x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align);
130     /* save the actual malloc address */
131     ((size_t *)x)[-1] = (size_t)addr;
132   }
133 
134   return x;
135 }
136 
vpx_malloc(size_t size)137 void *vpx_malloc(size_t size) {
138   return vpx_memalign(DEFAULT_ALIGNMENT, size);
139 }
140 
vpx_calloc(size_t num,size_t size)141 void *vpx_calloc(size_t num, size_t size) {
142   void *x;
143 
144   x = vpx_memalign(DEFAULT_ALIGNMENT, num * size);
145 
146   if (x)
147     VPX_MEMSET_L(x, 0, num * size);
148 
149   return x;
150 }
151 
vpx_realloc(void * memblk,size_t size)152 void *vpx_realloc(void *memblk, size_t size) {
153   void *addr,
154        * new_addr = NULL;
155   int align = DEFAULT_ALIGNMENT;
156 
157   /*
158   The realloc() function changes the size of the object pointed to by
159   ptr to the size specified by size, and returns a pointer to the
160   possibly moved block. The contents are unchanged up to the lesser
161   of the new and old sizes. If ptr is null, realloc() behaves like
162   malloc() for the specified size. If size is zero (0) and ptr is
163   not a null pointer, the object pointed to is freed.
164   */
165   if (!memblk)
166     new_addr = vpx_malloc(size);
167   else if (!size)
168     vpx_free(memblk);
169   else {
170     addr   = (void *)(((size_t *)memblk)[-1]);
171     memblk = NULL;
172 
173 #if CONFIG_MEM_MANAGER
174     new_addr = vpx_mm_realloc(addr, size + align + ADDRESS_STORAGE_SIZE);
175 #else
176     new_addr = VPX_REALLOC_L(addr, size + align + ADDRESS_STORAGE_SIZE);
177 #endif
178 
179     if (new_addr) {
180       addr = new_addr;
181       new_addr = (void *)(((size_t)
182                            ((unsigned char *)new_addr + ADDRESS_STORAGE_SIZE) + (align - 1)) &
183                           (size_t) - align);
184       /* save the actual malloc address */
185       ((size_t *)new_addr)[-1] = (size_t)addr;
186     }
187   }
188 
189   return new_addr;
190 }
191 
vpx_free(void * memblk)192 void vpx_free(void *memblk) {
193   if (memblk) {
194     void *addr = (void *)(((size_t *)memblk)[-1]);
195 #if CONFIG_MEM_MANAGER
196     hmm_free(&hmm_d, addr);
197 #else
198     VPX_FREE_L(addr);
199 #endif
200   }
201 }
202 
203 #if CONFIG_MEM_TRACKER
xvpx_memalign(size_t align,size_t size,char * file,int line)204 void *xvpx_memalign(size_t align, size_t size, char *file, int line) {
205 #if TRY_BOUNDS_CHECK
206   unsigned char *x_bounds;
207 #endif
208 
209   void *x;
210 
211   if (g_alloc_count == 0) {
212 #if TRY_BOUNDS_CHECK
213     int i_rv = vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE);
214 #else
215     int i_rv = vpx_memory_tracker_init(0, 0);
216 #endif
217 
218     if (i_rv < 0) {
219       _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");)
220     }
221   }
222 
223 #if TRY_BOUNDS_CHECK
224   {
225     int i;
226     unsigned int tempme = BOUNDS_CHECK_VALUE;
227 
228     x_bounds = vpx_memalign(align, size + (BOUNDS_CHECK_PAD_SIZE * 2));
229 
230     if (x_bounds) {
231       /*we're aligning the address twice here but to keep things
232         consistent we want to have the padding come before the stored
233         address so no matter what free function gets called we will
234         attempt to free the correct address*/
235       x_bounds = (unsigned char *)(((size_t *)x_bounds)[-1]);
236       x = align_addr(x_bounds + BOUNDS_CHECK_PAD_SIZE + ADDRESS_STORAGE_SIZE,
237                      (int)align);
238       /* save the actual malloc address */
239       ((size_t *)x)[-1] = (size_t)x_bounds;
240 
241       for (i = 0; i < BOUNDS_CHECK_PAD_SIZE; i += sizeof(unsigned int)) {
242         VPX_MEMCPY_L(x_bounds + i, &tempme, sizeof(unsigned int));
243         VPX_MEMCPY_L((unsigned char *)x + size + i,
244                      &tempme, sizeof(unsigned int));
245       }
246     } else
247       x = NULL;
248   }
249 #else
250   x = vpx_memalign(align, size);
251 #endif /*TRY_BOUNDS_CHECK*/
252 
253   g_alloc_count++;
254 
255   vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1);
256 
257   return x;
258 }
259 
xvpx_malloc(size_t size,char * file,int line)260 void *xvpx_malloc(size_t size, char *file, int line) {
261   return xvpx_memalign(DEFAULT_ALIGNMENT, size, file, line);
262 }
263 
xvpx_calloc(size_t num,size_t size,char * file,int line)264 void *xvpx_calloc(size_t num, size_t size, char *file, int line) {
265   void *x = xvpx_memalign(DEFAULT_ALIGNMENT, num * size, file, line);
266 
267   if (x)
268     VPX_MEMSET_L(x, 0, num * size);
269 
270   return x;
271 }
272 
xvpx_realloc(void * memblk,size_t size,char * file,int line)273 void *xvpx_realloc(void *memblk, size_t size, char *file, int line) {
274   struct mem_block *p = NULL;
275   int orig_size = 0,
276       orig_line = 0;
277   char *orig_file = NULL;
278 
279 #if TRY_BOUNDS_CHECK
280   unsigned char *x_bounds = memblk ?
281                             (unsigned char *)(((size_t *)memblk)[-1]) :
282                             NULL;
283 #endif
284 
285   void *x;
286 
287   if (g_alloc_count == 0) {
288 #if TRY_BOUNDS_CHECK
289 
290     if (!vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE))
291 #else
292     if (!vpx_memory_tracker_init(0, 0))
293 #endif
294     {
295       _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");)
296     }
297   }
298 
299   if ((p = vpx_memory_tracker_find((size_t)memblk))) {
300     orig_size = p->size;
301     orig_file = p->file;
302     orig_line = p->line;
303   }
304 
305 #if TRY_BOUNDS_CHECK_ON_FREE
306   vpx_memory_tracker_check_integrity(file, line);
307 #endif
308 
309   /* have to do this regardless of success, because
310    * the memory that does get realloc'd may change
311    * the bounds values of this block
312    */
313   vpx_memory_tracker_remove((size_t)memblk);
314 
315 #if TRY_BOUNDS_CHECK
316   {
317     int i;
318     unsigned int tempme = BOUNDS_CHECK_VALUE;
319 
320     x_bounds = vpx_realloc(memblk, size + (BOUNDS_CHECK_PAD_SIZE * 2));
321 
322     if (x_bounds) {
323       x_bounds = (unsigned char *)(((size_t *)x_bounds)[-1]);
324       x = align_addr(x_bounds + BOUNDS_CHECK_PAD_SIZE + ADDRESS_STORAGE_SIZE,
325                      (int)DEFAULT_ALIGNMENT);
326       /* save the actual malloc address */
327       ((size_t *)x)[-1] = (size_t)x_bounds;
328 
329       for (i = 0; i < BOUNDS_CHECK_PAD_SIZE; i += sizeof(unsigned int)) {
330         VPX_MEMCPY_L(x_bounds + i, &tempme, sizeof(unsigned int));
331         VPX_MEMCPY_L((unsigned char *)x + size + i,
332                      &tempme, sizeof(unsigned int));
333       }
334     } else
335       x = NULL;
336   }
337 #else
338   x = vpx_realloc(memblk, size);
339 #endif /*TRY_BOUNDS_CHECK*/
340 
341   if (!memblk) ++g_alloc_count;
342 
343   if (x)
344     vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1);
345   else
346     vpx_memory_tracker_add((size_t)memblk, orig_size, orig_file, orig_line, 1);
347 
348   return x;
349 }
350 
xvpx_free(void * p_address,char * file,int line)351 void xvpx_free(void *p_address, char *file, int line) {
352 #if TRY_BOUNDS_CHECK
353   unsigned char *p_bounds_address = (unsigned char *)p_address;
354   /*p_bounds_address -= BOUNDS_CHECK_PAD_SIZE;*/
355 #endif
356 
357 #if !TRY_BOUNDS_CHECK_ON_FREE
358   (void)file;
359   (void)line;
360 #endif
361 
362   if (p_address) {
363 #if TRY_BOUNDS_CHECK_ON_FREE
364     vpx_memory_tracker_check_integrity(file, line);
365 #endif
366 
367     /* if the addr isn't found in the list, assume it was allocated via
368      * vpx_ calls not xvpx_, therefore it does not contain any padding
369      */
370     if (vpx_memory_tracker_remove((size_t)p_address) == -2) {
371       p_bounds_address = p_address;
372       _P(fprintf(stderr, "[vpx_mem][xvpx_free] addr: %p not found in"
373                  " list; freed from file:%s"
374                  " line:%d\n", p_address, file, line));
375     } else
376       --g_alloc_count;
377 
378 #if TRY_BOUNDS_CHECK
379     vpx_free(p_bounds_address);
380 #else
381     vpx_free(p_address);
382 #endif
383 
384     if (!g_alloc_count)
385       vpx_memory_tracker_destroy();
386   }
387 }
388 
389 #endif /*CONFIG_MEM_TRACKER*/
390 
391 #if CONFIG_MEM_CHECKS
392 #if defined(VXWORKS)
393 #include <task_lib.h> /*for task_delay()*/
394 /* This function is only used to get a stack trace of the player
395 object so we can se where we are having a problem. */
get_my_tt(int task)396 static int get_my_tt(int task) {
397   tt(task);
398 
399   return 0;
400 }
401 
vx_sleep(int msec)402 static void vx_sleep(int msec) {
403   int ticks_to_sleep = 0;
404 
405   if (msec) {
406     int msec_per_tick = 1000 / sys_clk_rate_get();
407 
408     if (msec < msec_per_tick)
409       ticks_to_sleep++;
410     else
411       ticks_to_sleep = msec / msec_per_tick;
412   }
413 
414   task_delay(ticks_to_sleep);
415 }
416 #endif
417 #endif
418 
vpx_memcpy(void * dest,const void * source,size_t length)419 void *vpx_memcpy(void *dest, const void *source, size_t length) {
420 #if CONFIG_MEM_CHECKS
421 
422   if (((int)dest < 0x4000) || ((int)source < 0x4000)) {
423     _P(printf("WARNING: vpx_memcpy dest:0x%x source:0x%x len:%d\n", (int)dest, (int)source, length);)
424 
425 #if defined(VXWORKS)
426     sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
427 
428     vx_sleep(10000);
429 #endif
430   }
431 
432 #endif
433 
434   return VPX_MEMCPY_L(dest, source, length);
435 }
436 
vpx_memset(void * dest,int val,size_t length)437 void *vpx_memset(void *dest, int val, size_t length) {
438 #if CONFIG_MEM_CHECKS
439 
440   if ((int)dest < 0x4000) {
441     _P(printf("WARNING: vpx_memset dest:0x%x val:%d len:%d\n", (int)dest, val, length);)
442 
443 #if defined(VXWORKS)
444     sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
445 
446     vx_sleep(10000);
447 #endif
448   }
449 
450 #endif
451 
452   return VPX_MEMSET_L(dest, val, length);
453 }
454 
vpx_memmove(void * dest,const void * src,size_t count)455 void *vpx_memmove(void *dest, const void *src, size_t count) {
456 #if CONFIG_MEM_CHECKS
457 
458   if (((int)dest < 0x4000) || ((int)src < 0x4000)) {
459     _P(printf("WARNING: vpx_memmove dest:0x%x src:0x%x count:%d\n", (int)dest, (int)src, count);)
460 
461 #if defined(VXWORKS)
462     sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
463 
464     vx_sleep(10000);
465 #endif
466   }
467 
468 #endif
469 
470   return VPX_MEMMOVE_L(dest, src, count);
471 }
472 
473 #if CONFIG_MEM_MANAGER
474 
vpx_mm_create_heap_memory()475 static int vpx_mm_create_heap_memory() {
476   int i_rv = 0;
477 
478   if (!g_mng_memory_allocated) {
479 #if MM_DYNAMIC_MEMORY
480     g_p_mng_memory_raw =
481       (unsigned char *)malloc(g_mm_memory_size + HMM_ADDR_ALIGN_UNIT);
482 
483     if (g_p_mng_memory_raw) {
484       g_p_mng_memory = (unsigned char *)((((unsigned int)g_p_mng_memory_raw) +
485                                           HMM_ADDR_ALIGN_UNIT - 1) &
486                                          -(int)HMM_ADDR_ALIGN_UNIT);
487 
488       _P(printf("[vpx][mm] total memory size:%d g_p_mng_memory_raw:0x%x g_p_mng_memory:0x%x\n"
489 , g_mm_memory_size + HMM_ADDR_ALIGN_UNIT
490 , (unsigned int)g_p_mng_memory_raw
491 , (unsigned int)g_p_mng_memory);)
492     } else {
493       _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n"
494 , g_mm_memory_size);)
495 
496       i_rv = -1;
497     }
498 
499     if (g_p_mng_memory)
500 #endif
501     {
502       int chunk_size = 0;
503 
504       g_mng_memory_allocated = 1;
505 
506       hmm_init(&hmm_d);
507 
508       chunk_size = g_mm_memory_size >> SHIFT_HMM_ADDR_ALIGN_UNIT;
509 
510       chunk_size -= DUMMY_END_BLOCK_BAUS;
511 
512       _P(printf("[vpx][mm] memory size:%d for vpx memory manager. g_p_mng_memory:0x%x  chunk_size:%d\n"
513 , g_mm_memory_size
514 , (unsigned int)g_p_mng_memory
515 , chunk_size);)
516 
517       hmm_new_chunk(&hmm_d, (void *)g_p_mng_memory, chunk_size);
518     }
519 
520 #if MM_DYNAMIC_MEMORY
521     else {
522       _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n"
523 , g_mm_memory_size);)
524 
525       i_rv = -1;
526     }
527 
528 #endif
529   }
530 
531   return i_rv;
532 }
533 
vpx_mm_realloc(void * memblk,size_t size)534 static void *vpx_mm_realloc(void *memblk, size_t size) {
535   void *p_ret = NULL;
536 
537   if (vpx_mm_create_heap_memory() < 0) {
538     _P(printf("[vpx][mm] ERROR vpx_mm_realloc() Couldn't create memory for Heap.\n");)
539   } else {
540     int i_rv = 0;
541     int old_num_aaus;
542     int new_num_aaus;
543 
544     old_num_aaus = hmm_true_size(memblk);
545     new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
546 
547     if (old_num_aaus == new_num_aaus) {
548       p_ret = memblk;
549     } else {
550       i_rv = hmm_resize(&hmm_d, memblk, new_num_aaus);
551 
552       if (i_rv == 0) {
553         p_ret = memblk;
554       } else {
555         /* Error. Try to malloc and then copy data. */
556         void *p_from_malloc;
557 
558         new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
559         p_from_malloc  = hmm_alloc(&hmm_d, new_num_aaus);
560 
561         if (p_from_malloc) {
562           vpx_memcpy(p_from_malloc, memblk, size);
563           hmm_free(&hmm_d, memblk);
564 
565           p_ret = p_from_malloc;
566         }
567       }
568     }
569   }
570 
571   return p_ret;
572 }
573 #endif /*CONFIG_MEM_MANAGER*/
574 
575 #if USE_GLOBAL_FUNCTION_POINTERS
576 # if CONFIG_MEM_TRACKER
577 extern int vpx_memory_tracker_set_functions(g_malloc_func g_malloc_l
578 , g_calloc_func g_calloc_l
579 , g_realloc_func g_realloc_l
580 , g_free_func g_free_l
581 , g_memcpy_func g_memcpy_l
582 , g_memset_func g_memset_l
583 , g_memmove_func g_memmove_l);
584 # endif
585 #endif /*USE_GLOBAL_FUNCTION_POINTERS*/
vpx_mem_set_functions(g_malloc_func g_malloc_l,g_calloc_func g_calloc_l,g_realloc_func g_realloc_l,g_free_func g_free_l,g_memcpy_func g_memcpy_l,g_memset_func g_memset_l,g_memmove_func g_memmove_l)586 int vpx_mem_set_functions(g_malloc_func g_malloc_l
587 , g_calloc_func g_calloc_l
588 , g_realloc_func g_realloc_l
589 , g_free_func g_free_l
590 , g_memcpy_func g_memcpy_l
591 , g_memset_func g_memset_l
592 , g_memmove_func g_memmove_l) {
593 #if USE_GLOBAL_FUNCTION_POINTERS
594 
595   /* If use global functions is turned on then the
596   application must set the global functions before
597   it does anything else or vpx_mem will have
598   unpredictable results. */
599   if (!g_func) {
600     g_func = (struct GLOBAL_FUNC_POINTERS *)
601              g_malloc_l(sizeof(struct GLOBAL_FUNC_POINTERS));
602 
603     if (!g_func) {
604       return -1;
605     }
606   }
607 
608 #if CONFIG_MEM_TRACKER
609   {
610     int rv = 0;
611     rv = vpx_memory_tracker_set_functions(g_malloc_l
612 , g_calloc_l
613 , g_realloc_l
614 , g_free_l
615 , g_memcpy_l
616 , g_memset_l
617 , g_memmove_l);
618 
619     if (rv < 0) {
620       return rv;
621     }
622   }
623 #endif
624 
625   g_func->g_malloc  = g_malloc_l;
626   g_func->g_calloc  = g_calloc_l;
627   g_func->g_realloc = g_realloc_l;
628   g_func->g_free    = g_free_l;
629   g_func->g_memcpy  = g_memcpy_l;
630   g_func->g_memset  = g_memset_l;
631   g_func->g_memmove = g_memmove_l;
632 
633   return 0;
634 #else
635   (void)g_malloc_l;
636   (void)g_calloc_l;
637   (void)g_realloc_l;
638   (void)g_free_l;
639   (void)g_memcpy_l;
640   (void)g_memset_l;
641   (void)g_memmove_l;
642   return -1;
643 #endif
644 }
645 
vpx_mem_unset_functions()646 int vpx_mem_unset_functions() {
647 #if USE_GLOBAL_FUNCTION_POINTERS
648 
649   if (g_func) {
650     g_free_func temp_free = g_func->g_free;
651     temp_free(g_func);
652     g_func = NULL;
653   }
654 
655 #endif
656   return 0;
657 }
658