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