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