• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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