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