Skip to content

Commit 1977ef9

Browse files
committed
opcache find best candidate near .text segment for large maps on FreeBSD.
Follow up on #8890 using similar workflow, we go through the php binary mapping per address boundaries. Closes #8908.
1 parent 6d525a4 commit 1977ef9

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

NEWS

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ PHP NEWS
3939
for macOs Instrument. (David Carlier)
4040
. Fixed bug GH-8030 (Segfault with JIT and large match/switch statements).
4141
(Arnaud)
42-
. JIT support improvement for macOs for segments and executable permission
42+
. Added JIT support improvement for macOs for segments and executable permission
4343
bit handling. (David Carlier)
44+
. Added JIT buffer allocation near the .text section on FreeNSD. (David Carlier)
4445

4546
- PCRE:
4647
. Updated bundled libpcre to 10.40. (cmb)

ext/opcache/shared_alloc_mmap.c

+60-3
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,21 @@
3939
# define MAP_ANONYMOUS MAP_ANON
4040
#endif
4141
#if defined(MAP_ALIGNED_SUPER)
42+
# include <sys/types.h>
43+
# include <sys/sysctl.h>
44+
# include <sys/user.h>
4245
# define MAP_HUGETLB MAP_ALIGNED_SUPER
4346
#endif
4447

45-
#if defined(__linux__) && (defined(__x86_64__) || defined (__aarch64__))
48+
#if (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__))
4649
static void *find_prefered_mmap_base(size_t requested_size)
4750
{
48-
FILE *f;
4951
size_t huge_page_size = 2 * 1024 * 1024;
5052
uintptr_t last_free_addr = 0;
5153
uintptr_t last_candidate = (uintptr_t)MAP_FAILED;
5254
uintptr_t start, end, text_start = 0;
55+
#if defined(__linux__)
56+
FILE *f;
5357
char buffer[MAXPATHLEN];
5458

5559
f = fopen("/proc/self/maps", "r");
@@ -89,6 +93,59 @@ static void *find_prefered_mmap_base(size_t requested_size)
8993

9094
}
9195
fclose(f);
96+
#elif defined(__FreeBSD__)
97+
size_t s = 0;
98+
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
99+
if (sysctl(mib, 4, NULL, &s, NULL, 0) == 0) {
100+
s = s * 4 / 3;
101+
void *addr = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
102+
if (addr != MAP_FAILED) {
103+
if (sysctl(mib, 4, addr, &s, NULL, 0) == 0) {
104+
start = (uintptr_t)addr;
105+
end = start + s;
106+
while (start < end) {
107+
struct kinfo_vmentry *entry = (struct kinfo_vmentry *)start;
108+
size_t sz = entry->kve_structsize;
109+
if (sz == 0) {
110+
break;
111+
}
112+
uintptr_t e_start = entry->kve_start;
113+
uintptr_t e_end = entry->kve_end;
114+
if ((uintptr_t)execute_ex >= e_start) {
115+
/* the current segment lays before PHP .text segment or PHP .text segment itself */
116+
if (last_free_addr + requested_size <= e_start) {
117+
last_candidate = last_free_addr;
118+
}
119+
if ((uintptr_t)execute_ex < e_end) {
120+
/* the current segment is PHP .text segment itself */
121+
if (last_candidate != (uintptr_t)MAP_FAILED) {
122+
if (e_end - last_candidate < UINT32_MAX) {
123+
/* we have found a big enough hole before the text segment */
124+
break;
125+
}
126+
last_candidate = (uintptr_t)MAP_FAILED;
127+
}
128+
text_start = e_start;
129+
}
130+
} else {
131+
/* the current segment lays after PHP .text segment */
132+
if (last_free_addr + requested_size - text_start > UINT32_MAX) {
133+
/* the current segment and the following segments lay too far from PHP .text segment */
134+
break;
135+
}
136+
if (last_free_addr + requested_size <= e_start) {
137+
last_candidate = last_free_addr;
138+
break;
139+
}
140+
}
141+
last_free_addr = ZEND_MM_ALIGNED_SIZE_EX(e_end, huge_page_size);
142+
start += sz;
143+
}
144+
}
145+
munmap(addr, s);
146+
}
147+
}
148+
#endif
92149

93150
return (void*)last_candidate;
94151
}
@@ -109,7 +166,7 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
109166
#ifdef PROT_MAX
110167
flags |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
111168
#endif
112-
#if defined(__linux__) && (defined(__x86_64__) || defined (__aarch64__))
169+
#if (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__))
113170
void *hint = find_prefered_mmap_base(requested_size);
114171
if (hint != MAP_FAILED) {
115172
# ifdef MAP_HUGETLB

0 commit comments

Comments
 (0)