aboutsummaryrefslogtreecommitdiff
path: root/C/Alloc.c
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2021-12-27 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2022-03-18 15:35:13 +0500
commitf19f813537c7aea1c20749c914e756b54a9c3cf5 (patch)
tree816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /C/Alloc.c
parent98e06a519b63b81986abe76d28887f6984a7732b (diff)
download7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.gz
7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.bz2
7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.zip
'21.07'21.07
Diffstat (limited to 'C/Alloc.c')
-rw-r--r--C/Alloc.c463
1 files changed, 463 insertions, 0 deletions
diff --git a/C/Alloc.c b/C/Alloc.c
new file mode 100644
index 0000000..d1af76c
--- /dev/null
+++ b/C/Alloc.c
@@ -0,0 +1,463 @@
1/* Alloc.c -- Memory allocation functions
22021-07-13 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include <stdio.h>
7
8#ifdef _WIN32
9#include <Windows.h>
10#endif
11#include <stdlib.h>
12
13#include "Alloc.h"
14
15/* #define _SZ_ALLOC_DEBUG */
16
17/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
18#ifdef _SZ_ALLOC_DEBUG
19
20#include <stdio.h>
21int g_allocCount = 0;
22int g_allocCountMid = 0;
23int g_allocCountBig = 0;
24
25
26#define CONVERT_INT_TO_STR(charType, tempSize) \
27 unsigned char temp[tempSize]; unsigned i = 0; \
28 while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
29 *s++ = (charType)('0' + (unsigned)val); \
30 while (i != 0) { i--; *s++ = temp[i]; } \
31 *s = 0;
32
33static void ConvertUInt64ToString(UInt64 val, char *s)
34{
35 CONVERT_INT_TO_STR(char, 24);
36}
37
38#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
39
40static void ConvertUInt64ToHex(UInt64 val, char *s)
41{
42 UInt64 v = val;
43 unsigned i;
44 for (i = 1;; i++)
45 {
46 v >>= 4;
47 if (v == 0)
48 break;
49 }
50 s[i] = 0;
51 do
52 {
53 unsigned t = (unsigned)(val & 0xF);
54 val >>= 4;
55 s[--i] = GET_HEX_CHAR(t);
56 }
57 while (i);
58}
59
60#define DEBUG_OUT_STREAM stderr
61
62static void Print(const char *s)
63{
64 fputs(s, DEBUG_OUT_STREAM);
65}
66
67static void PrintAligned(const char *s, size_t align)
68{
69 size_t len = strlen(s);
70 for(;;)
71 {
72 fputc(' ', DEBUG_OUT_STREAM);
73 if (len >= align)
74 break;
75 ++len;
76 }
77 Print(s);
78}
79
80static void PrintLn()
81{
82 Print("\n");
83}
84
85static void PrintHex(UInt64 v, size_t align)
86{
87 char s[32];
88 ConvertUInt64ToHex(v, s);
89 PrintAligned(s, align);
90}
91
92static void PrintDec(UInt64 v, size_t align)
93{
94 char s[32];
95 ConvertUInt64ToString(v, s);
96 PrintAligned(s, align);
97}
98
99static void PrintAddr(void *p)
100{
101 PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
102}
103
104
105#define PRINT_ALLOC(name, cnt, size, ptr) \
106 Print(name " "); \
107 PrintDec(cnt++, 10); \
108 PrintHex(size, 10); \
109 PrintAddr(ptr); \
110 PrintLn();
111
112#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
113 Print(name " "); \
114 PrintDec(--cnt, 10); \
115 PrintAddr(ptr); \
116 PrintLn(); }
117
118#else
119
120#define PRINT_ALLOC(name, cnt, size, ptr)
121#define PRINT_FREE(name, cnt, ptr)
122#define Print(s)
123#define PrintLn()
124#define PrintHex(v, align)
125#define PrintAddr(p)
126
127#endif
128
129
130
131void *MyAlloc(size_t size)
132{
133 if (size == 0)
134 return NULL;
135 PRINT_ALLOC("Alloc ", g_allocCount, size, NULL);
136 #ifdef _SZ_ALLOC_DEBUG
137 {
138 void *p = malloc(size);
139 // PRINT_ALLOC("Alloc ", g_allocCount, size, p);
140 return p;
141 }
142 #else
143 return malloc(size);
144 #endif
145}
146
147void MyFree(void *address)
148{
149 PRINT_FREE("Free ", g_allocCount, address);
150
151 free(address);
152}
153
154#ifdef _WIN32
155
156void *MidAlloc(size_t size)
157{
158 if (size == 0)
159 return NULL;
160
161 PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL);
162
163 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
164}
165
166void MidFree(void *address)
167{
168 PRINT_FREE("Free-Mid", g_allocCountMid, address);
169
170 if (!address)
171 return;
172 VirtualFree(address, 0, MEM_RELEASE);
173}
174
175#ifdef _7ZIP_LARGE_PAGES
176
177#ifdef MEM_LARGE_PAGES
178 #define MY__MEM_LARGE_PAGES MEM_LARGE_PAGES
179#else
180 #define MY__MEM_LARGE_PAGES 0x20000000
181#endif
182
183extern
184SIZE_T g_LargePageSize;
185SIZE_T g_LargePageSize = 0;
186typedef SIZE_T (WINAPI *GetLargePageMinimumP)(VOID);
187
188#endif // _7ZIP_LARGE_PAGES
189
190void SetLargePageSize()
191{
192 #ifdef _7ZIP_LARGE_PAGES
193 SIZE_T size;
194 GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
195 GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
196 if (!largePageMinimum)
197 return;
198 size = largePageMinimum();
199 if (size == 0 || (size & (size - 1)) != 0)
200 return;
201 g_LargePageSize = size;
202 #endif
203}
204
205
206void *BigAlloc(size_t size)
207{
208 if (size == 0)
209 return NULL;
210
211 PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);
212
213 #ifdef _7ZIP_LARGE_PAGES
214 {
215 SIZE_T ps = g_LargePageSize;
216 if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
217 {
218 size_t size2;
219 ps--;
220 size2 = (size + ps) & ~ps;
221 if (size2 >= size)
222 {
223 void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MY__MEM_LARGE_PAGES, PAGE_READWRITE);
224 if (res)
225 return res;
226 }
227 }
228 }
229 #endif
230
231 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
232}
233
234void BigFree(void *address)
235{
236 PRINT_FREE("Free-Big", g_allocCountBig, address);
237
238 if (!address)
239 return;
240 VirtualFree(address, 0, MEM_RELEASE);
241}
242
243#endif
244
245
246static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }
247static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }
248const ISzAlloc g_Alloc = { SzAlloc, SzFree };
249
250#ifdef _WIN32
251static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }
252static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }
253static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }
254static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }
255const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
256const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
257#endif
258
259/*
260 uintptr_t : <stdint.h> C99 (optional)
261 : unsupported in VS6
262*/
263
264#ifdef _WIN32
265 typedef UINT_PTR UIntPtr;
266#else
267 /*
268 typedef uintptr_t UIntPtr;
269 */
270 typedef ptrdiff_t UIntPtr;
271#endif
272
273
274#define ADJUST_ALLOC_SIZE 0
275/*
276#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
277*/
278/*
279 Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
280 MyAlloc() can return address that is NOT multiple of sizeof(void *).
281*/
282
283
284/*
285#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))
286*/
287#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))
288
289
290#if !defined(_WIN32) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
291 #define USE_posix_memalign
292#endif
293
294#ifndef USE_posix_memalign
295#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
296#endif
297
298/*
299 This posix_memalign() is for test purposes only.
300 We also need special Free() function instead of free(),
301 if this posix_memalign() is used.
302*/
303
304/*
305static int posix_memalign(void **ptr, size_t align, size_t size)
306{
307 size_t newSize = size + align;
308 void *p;
309 void *pAligned;
310 *ptr = NULL;
311 if (newSize < size)
312 return 12; // ENOMEM
313 p = MyAlloc(newSize);
314 if (!p)
315 return 12; // ENOMEM
316 pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
317 ((void **)pAligned)[-1] = p;
318 *ptr = pAligned;
319 return 0;
320}
321*/
322
323/*
324 ALLOC_ALIGN_SIZE >= sizeof(void *)
325 ALLOC_ALIGN_SIZE >= cache_line_size
326*/
327
328#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
329
330static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
331{
332 #ifndef USE_posix_memalign
333
334 void *p;
335 void *pAligned;
336 size_t newSize;
337 UNUSED_VAR(pp);
338
339 /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
340 block to prevent cache line sharing with another allocated blocks */
341
342 newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
343 if (newSize < size)
344 return NULL;
345
346 p = MyAlloc(newSize);
347
348 if (!p)
349 return NULL;
350 pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
351
352 Print(" size="); PrintHex(size, 8);
353 Print(" a_size="); PrintHex(newSize, 8);
354 Print(" ptr="); PrintAddr(p);
355 Print(" a_ptr="); PrintAddr(pAligned);
356 PrintLn();
357
358 ((void **)pAligned)[-1] = p;
359
360 return pAligned;
361
362 #else
363
364 void *p;
365 UNUSED_VAR(pp);
366 if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
367 return NULL;
368
369 Print(" posix_memalign="); PrintAddr(p);
370 PrintLn();
371
372 return p;
373
374 #endif
375}
376
377
378static void SzAlignedFree(ISzAllocPtr pp, void *address)
379{
380 UNUSED_VAR(pp);
381 #ifndef USE_posix_memalign
382 if (address)
383 MyFree(((void **)address)[-1]);
384 #else
385 free(address);
386 #endif
387}
388
389
390const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
391
392
393
394#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
395
396/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
397#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
398/*
399#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]
400*/
401
402static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
403{
404 CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
405 void *adr;
406 void *pAligned;
407 size_t newSize;
408 size_t extra;
409 size_t alignSize = (size_t)1 << p->numAlignBits;
410
411 if (alignSize < sizeof(void *))
412 alignSize = sizeof(void *);
413
414 if (p->offset >= alignSize)
415 return NULL;
416
417 /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
418 block to prevent cache line sharing with another allocated blocks */
419 extra = p->offset & (sizeof(void *) - 1);
420 newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
421 if (newSize < size)
422 return NULL;
423
424 adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
425
426 if (!adr)
427 return NULL;
428
429 pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
430 alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
431
432 PrintLn();
433 Print("- Aligned: ");
434 Print(" size="); PrintHex(size, 8);
435 Print(" a_size="); PrintHex(newSize, 8);
436 Print(" ptr="); PrintAddr(adr);
437 Print(" a_ptr="); PrintAddr(pAligned);
438 PrintLn();
439
440 REAL_BLOCK_PTR_VAR(pAligned) = adr;
441
442 return pAligned;
443}
444
445
446static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
447{
448 if (address)
449 {
450 CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
451 PrintLn();
452 Print("- Aligned Free: ");
453 PrintLn();
454 ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
455 }
456}
457
458
459void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
460{
461 p->vt.Alloc = AlignOffsetAlloc_Alloc;
462 p->vt.Free = AlignOffsetAlloc_Free;
463}