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