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