|
1 /***************************************************************** |
|
2 This file should be kept compatible with Python 2.3, see PEP 291. |
|
3 *****************************************************************/ |
|
4 |
|
5 #include <Python.h> |
|
6 #include <ffi.h> |
|
7 #ifdef MS_WIN32 |
|
8 #include <windows.h> |
|
9 #else |
|
10 #include <sys/mman.h> |
|
11 #include <unistd.h> |
|
12 # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
|
13 # define MAP_ANONYMOUS MAP_ANON |
|
14 # endif |
|
15 #endif |
|
16 #include "ctypes.h" |
|
17 |
|
18 /* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory |
|
19 overhead, but allocate less blocks from the system. It may be that some |
|
20 systems have a limit of how many mmap'd blocks can be open. |
|
21 */ |
|
22 |
|
23 #define BLOCKSIZE _pagesize |
|
24 |
|
25 /* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */ |
|
26 |
|
27 /******************************************************************/ |
|
28 |
|
29 typedef union _tagITEM { |
|
30 ffi_closure closure; |
|
31 union _tagITEM *next; |
|
32 } ITEM; |
|
33 |
|
34 static ITEM *free_list; |
|
35 int _pagesize; |
|
36 |
|
37 static void more_core(void) |
|
38 { |
|
39 ITEM *item; |
|
40 int count, i; |
|
41 |
|
42 /* determine the pagesize */ |
|
43 #ifdef MS_WIN32 |
|
44 if (!_pagesize) { |
|
45 SYSTEM_INFO systeminfo; |
|
46 GetSystemInfo(&systeminfo); |
|
47 _pagesize = systeminfo.dwPageSize; |
|
48 } |
|
49 #else |
|
50 if (!_pagesize) { |
|
51 #ifdef _SC_PAGESIZE |
|
52 _pagesize = sysconf(_SC_PAGESIZE); |
|
53 #else |
|
54 _pagesize = getpagesize(); |
|
55 #endif |
|
56 } |
|
57 #endif |
|
58 |
|
59 /* calculate the number of nodes to allocate */ |
|
60 count = BLOCKSIZE / sizeof(ITEM); |
|
61 |
|
62 /* allocate a memory block */ |
|
63 #ifdef MS_WIN32 |
|
64 item = (ITEM *)VirtualAlloc(NULL, |
|
65 count * sizeof(ITEM), |
|
66 MEM_COMMIT, |
|
67 PAGE_EXECUTE_READWRITE); |
|
68 if (item == NULL) |
|
69 return; |
|
70 #else |
|
71 item = (ITEM *)mmap(NULL, |
|
72 count * sizeof(ITEM), |
|
73 PROT_READ | PROT_WRITE | PROT_EXEC, |
|
74 MAP_PRIVATE | MAP_ANONYMOUS, |
|
75 -1, |
|
76 0); |
|
77 if (item == (void *)MAP_FAILED) |
|
78 return; |
|
79 #endif |
|
80 |
|
81 #ifdef MALLOC_CLOSURE_DEBUG |
|
82 printf("block at %p allocated (%d bytes), %d ITEMs\n", |
|
83 item, count * sizeof(ITEM), count); |
|
84 #endif |
|
85 /* put them into the free list */ |
|
86 for (i = 0; i < count; ++i) { |
|
87 item->next = free_list; |
|
88 free_list = item; |
|
89 ++item; |
|
90 } |
|
91 } |
|
92 |
|
93 /******************************************************************/ |
|
94 |
|
95 /* put the item back into the free list */ |
|
96 void FreeClosure(void *p) |
|
97 { |
|
98 ITEM *item = (ITEM *)p; |
|
99 item->next = free_list; |
|
100 free_list = item; |
|
101 } |
|
102 |
|
103 /* return one item from the free list, allocating more if needed */ |
|
104 void *MallocClosure(void) |
|
105 { |
|
106 ITEM *item; |
|
107 if (!free_list) |
|
108 more_core(); |
|
109 if (!free_list) |
|
110 return NULL; |
|
111 item = free_list; |
|
112 free_list = item->next; |
|
113 return item; |
|
114 } |