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