xref: /petsc/src/sys/memory/mal.c (revision da93591f59bc1e95f467c6fc21a755040df0b8f3)
1 #define PETSC_DLL
2 /*
3     Code that allows a user to dictate what malloc() PETSc uses.
4 */
5 #include "petsc.h"             /*I   "petsc.h"   I*/
6 #include "petscsys.h"
7 #if defined(PETSC_HAVE_STDLIB_H)
8 #include <stdlib.h>
9 #endif
10 #if defined(PETSC_HAVE_MALLOC_H)
11 #include <malloc.h>
12 #endif
13 #include "petscfix.h"
14 
15 
16 /*
17         We want to make sure that all mallocs of double or complex numbers are complex aligned.
18     1) on systems with memalign() we call that routine to get an aligned memory location
19     2) on systems without memalign() we
20        - allocate one sizeof(PetscScalar) extra space
21        - we shift the pointer up slightly if needed to get PetscScalar aligned
22        - if shifted we store at ptr[-1] the amount of shift (plus a cookie)
23 */
24 #define SHIFT_COOKIE 456123
25 
26 #undef __FUNCT__
27 #define __FUNCT__ "PetscMallocAlign"
28 PetscErrorCode PETSC_DLLEXPORT PetscMallocAlign(size_t mem,int line,const char func[],const char file[],const char dir[],void** result)
29 {
30 #if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
31   *result = malloc(mem);
32 #elif defined(PETSC_HAVE_MEMALIGN)
33   *result = memalign(PETSC_MEMALIGN,mem);
34 #else
35   {
36     int *ptr,shift;
37     /*
38       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
39     */
40     ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
41     if (ptr) {
42       shift        = (int)(((unsigned long) ptr) % PETSC_MEMALIGN);
43       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
44       ptr[shift-1] = shift + SHIFT_COOKIE ;
45       ptr         += shift;
46       *result      = (void*)ptr;
47     } else {
48       *result      = 0;
49     }
50   }
51 #endif
52   if (!*result)  SETERRQ1(PETSC_ERR_MEM,"Memory requested %.0f",(PetscLogDouble)mem);
53   return 0;
54 }
55 
56 #undef __FUNCT__
57 #define __FUNCT__ "PetscFreeAlign"
58 PetscErrorCode PETSC_DLLEXPORT PetscFreeAlign(void *ptr,int line,const char func[],const char file[],const char dir[])
59 {
60 #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
61   int shift;
62   /*
63        Previous int tells us how many ints the pointer has been shifted from
64     the original address provided by the system malloc().
65   */
66   shift = *(((int*)ptr)-1) - SHIFT_COOKIE;
67   if (shift > PETSC_MEMALIGN-1) return PetscError(line,func,file,dir,1,1,"Likely memory corruption in heap");
68   if (shift < 0) return PetscError(line,func,file,dir,1,1,"Likely memory corruption in heap");
69   ptr   = (void*)(((int*)ptr) - shift);
70 #endif
71 
72 #if defined(PETSC_HAVE_FREE_RETURN_INT)
73   int err = free(ptr);
74   if (err) {
75     return PetscError(line,func,file,dir,1,1,"System free returned error %d\n",err);
76   }
77 #else
78   free(ptr);
79 #endif
80   return 0;
81 }
82 
83 /*
84         We never use the system free directly because on many machines it
85     does not return an error code.
86 */
87 #undef __FUNCT__
88 #define __FUNCT__ "PetscFreeDefault"
89 PetscErrorCode PETSC_DLLEXPORT PetscFreeDefault(void *ptr,int line,char *func,char *file,char *dir)
90 {
91 #if defined(PETSC_HAVE_FREE_RETURN_INT)
92   int err = free(ptr);
93   if (err) {
94     return PetscError(line,func,file,dir,1,1,"System free returned error %d\n",err);
95   }
96 #else
97   free(ptr);
98 #endif
99   return 0;
100 }
101 
102 PetscErrorCode  PETSC_DLLEXPORT (*PetscTrMalloc)(size_t,int,const char[],const char[],const char[],void**) = PetscMallocAlign;
103 PetscErrorCode  PETSC_DLLEXPORT (*PetscTrFree)(void*,int,const char[],const char[],const char[])          = PetscFreeAlign;
104 
105 PetscTruth petscsetmallocvisited = PETSC_FALSE;
106 
107 #undef __FUNCT__
108 #define __FUNCT__ "PetscMallocSet"
109 /*@C
110    PetscMallocSet - Sets the routines used to do mallocs and frees.
111    This routine MUST be called before PetscInitialize() and may be
112    called only once.
113 
114    Not Collective
115 
116    Input Parameters:
117 +  malloc - the malloc routine
118 -  free - the free routine
119 
120    Level: developer
121 
122    Concepts: malloc
123    Concepts: memory^allocation
124 
125 @*/
126 PetscErrorCode PETSC_DLLEXPORT PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],const char[],void**),
127                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[],const char[]))
128 {
129   PetscFunctionBegin;
130   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_ERR_SUP,"cannot call multiple times");
131   PetscTrMalloc               = imalloc;
132   PetscTrFree                 = ifree;
133   petscsetmallocvisited       = PETSC_TRUE;
134   PetscFunctionReturn(0);
135 }
136 
137 #undef __FUNCT__
138 #define __FUNCT__ "PetscMallocClear"
139 /*@C
140    PetscMallocClear - Resets the routines used to do mallocs and frees to the
141         defaults.
142 
143    Not Collective
144 
145    Level: developer
146 
147    Notes:
148     In general one should never run a PETSc program with different malloc() and
149     free() settings for different parts; this is because one NEVER wants to
150     free() an address that was malloced by a different memory management system
151 
152 @*/
153 PetscErrorCode PETSC_DLLEXPORT PetscMallocClear(void)
154 {
155   PetscFunctionBegin;
156   PetscTrMalloc         = PetscMallocAlign;
157   PetscTrFree           = PetscFreeAlign;
158   petscsetmallocvisited = PETSC_FALSE;
159   PetscFunctionReturn(0);
160 }
161