xref: /petsc/src/sys/memory/mal.c (revision c0174eb74783e1ccfa817272a5782dd72b4cfcef)
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) {
72     return PetscError(PETSC_COMM_SELF,line,func,file,dir,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
73   }
74 #else
75   free(ptr);
76 #endif
77   return 0;
78 }
79 
80 /*
81         We never use the system free directly because on many machines it
82     does not return an error code.
83 */
84 #undef __FUNCT__
85 #define __FUNCT__ "PetscFreeDefault"
86 PetscErrorCode  PetscFreeDefault(void *ptr,int line,char *func,char *file,char *dir)
87 {
88 #if defined(PETSC_HAVE_FREE_RETURN_INT)
89   int err = free(ptr);
90   if (err) {
91     return PetscError(PETSC_COMM_SELF,line,func,file,dir,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
92   }
93 #else
94   free(ptr);
95 #endif
96   return 0;
97 }
98 
99 PetscErrorCode   (*PetscTrMalloc)(size_t,int,const char[],const char[],const char[],void**) = PetscMallocAlign;
100 PetscErrorCode   (*PetscTrFree)(void*,int,const char[],const char[],const char[])          = PetscFreeAlign;
101 
102 PetscBool  petscsetmallocvisited = PETSC_FALSE;
103 
104 #undef __FUNCT__
105 #define __FUNCT__ "PetscMallocSet"
106 /*@C
107    PetscMallocSet - Sets the routines used to do mallocs and frees.
108    This routine MUST be called before PetscInitialize() and may be
109    called only once.
110 
111    Not Collective
112 
113    Input Parameters:
114 +  malloc - the malloc routine
115 -  free - the free routine
116 
117    Level: developer
118 
119    Concepts: malloc
120    Concepts: memory^allocation
121 
122 @*/
123 PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],const char[],void**),
124                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[],const char[]))
125 {
126   PetscFunctionBegin;
127   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
128   PetscTrMalloc               = imalloc;
129   PetscTrFree                 = ifree;
130   petscsetmallocvisited       = PETSC_TRUE;
131   PetscFunctionReturn(0);
132 }
133 
134 #undef __FUNCT__
135 #define __FUNCT__ "PetscMallocClear"
136 /*@C
137    PetscMallocClear - Resets the routines used to do mallocs and frees to the
138         defaults.
139 
140    Not Collective
141 
142    Level: developer
143 
144    Notes:
145     In general one should never run a PETSc program with different malloc() and
146     free() settings for different parts; this is because one NEVER wants to
147     free() an address that was malloced by a different memory management system
148 
149 @*/
150 PetscErrorCode  PetscMallocClear(void)
151 {
152   PetscFunctionBegin;
153   PetscTrMalloc         = PetscMallocAlign;
154   PetscTrFree           = PetscFreeAlign;
155   petscsetmallocvisited = PETSC_FALSE;
156   PetscFunctionReturn(0);
157 }
158