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