1 /*****************************************************************************
2
3 Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2019, MariaDB Corporation.
5
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17
18 *****************************************************************************/
19
20 /**************************************************//**
21 @file os/os0proc.cc
22 The interface to the operating system
23 process control primitives
24
25 Created 9/30/1995 Heikki Tuuri
26 *******************************************************/
27
28 #include "univ.i"
29 #ifdef HAVE_LINUX_LARGE_PAGES
30 # include "mysqld.h"
31 #endif
32 #include "my_valgrind.h"
33
34 /* FreeBSD for example has only MAP_ANON, Linux has MAP_ANONYMOUS and
35 MAP_ANON but MAP_ANON is marked as deprecated */
36 #if defined(MAP_ANONYMOUS)
37 #define OS_MAP_ANON MAP_ANONYMOUS
38 #elif defined(MAP_ANON)
39 #define OS_MAP_ANON MAP_ANON
40 #endif
41
42 /** The total amount of memory currently allocated from the operating
43 system with os_mem_alloc_large(). */
44 ulint os_total_large_mem_allocated = 0;
45
46 /** Converts the current process id to a number.
47 @return process id as a number */
48 ulint
os_proc_get_number(void)49 os_proc_get_number(void)
50 /*====================*/
51 {
52 #ifdef _WIN32
53 return(static_cast<ulint>(GetCurrentProcessId()));
54 #else
55 return(static_cast<ulint>(getpid()));
56 #endif
57 }
58
59 /** Allocates large pages memory.
60 @param[in,out] n Number of bytes to allocate
61 @return allocated memory */
62 void*
os_mem_alloc_large(ulint * n)63 os_mem_alloc_large(
64 ulint* n)
65 {
66 void* ptr;
67 ulint size;
68 #ifdef HAVE_LINUX_LARGE_PAGES
69 int shmid;
70 struct shmid_ds buf;
71
72 if (!my_use_large_pages || !opt_large_page_size) {
73 goto skip;
74 }
75
76 /* Align block size to opt_large_page_size */
77 ut_ad(ut_is_2pow(opt_large_page_size));
78 size = ut_2pow_round(*n + opt_large_page_size - 1,
79 ulint(opt_large_page_size));
80
81 shmid = shmget(IPC_PRIVATE, (size_t) size, SHM_HUGETLB | SHM_R | SHM_W);
82 if (shmid < 0) {
83 ib::warn() << "Failed to allocate " << size
84 << " bytes. errno " << errno;
85 ptr = NULL;
86 } else {
87 ptr = shmat(shmid, NULL, 0);
88 if (ptr == (void*)-1) {
89 ib::warn() << "Failed to attach shared memory segment,"
90 " errno " << errno;
91 ptr = NULL;
92 }
93
94 /* Remove the shared memory segment so that it will be
95 automatically freed after memory is detached or
96 process exits */
97 shmctl(shmid, IPC_RMID, &buf);
98 }
99
100 if (ptr) {
101 *n = size;
102 my_atomic_addlint(
103 &os_total_large_mem_allocated, size);
104
105 MEM_UNDEFINED(ptr, size);
106 return(ptr);
107 }
108
109 ib::warn() << "Using conventional memory pool";
110 skip:
111 #endif /* HAVE_LINUX_LARGE_PAGES */
112
113 #ifdef _WIN32
114 SYSTEM_INFO system_info;
115 GetSystemInfo(&system_info);
116
117 /* Align block size to system page size */
118 ut_ad(ut_is_2pow(system_info.dwPageSize));
119 size = *n = ut_2pow_round<ulint>(*n + (system_info.dwPageSize - 1),
120 system_info.dwPageSize);
121 ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE,
122 PAGE_READWRITE);
123 if (!ptr) {
124 ib::info() << "VirtualAlloc(" << size << " bytes) failed;"
125 " Windows error " << GetLastError();
126 } else {
127 my_atomic_addlint(
128 &os_total_large_mem_allocated, size);
129 MEM_UNDEFINED(ptr, size);
130 }
131 #else
132 size = getpagesize();
133 /* Align block size to system page size */
134 ut_ad(ut_is_2pow(size));
135 size = *n = ut_2pow_round(*n + (size - 1), size);
136 ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
137 MAP_PRIVATE | OS_MAP_ANON, -1, 0);
138 if (UNIV_UNLIKELY(ptr == (void*) -1)) {
139 ib::error() << "mmap(" << size << " bytes) failed;"
140 " errno " << errno;
141 ptr = NULL;
142 } else {
143 my_atomic_addlint(
144 &os_total_large_mem_allocated, size);
145 MEM_UNDEFINED(ptr, size);
146 }
147 #endif
148 return(ptr);
149 }
150
151 /** Frees large pages memory.
152 @param[in] ptr pointer returned by os_mem_alloc_large()
153 @param[in] size size returned by os_mem_alloc_large() */
154 void
os_mem_free_large(void * ptr,ulint size)155 os_mem_free_large(
156 void *ptr,
157 ulint size)
158 {
159 ut_a(os_total_large_mem_allocated >= size);
160
161 #ifdef __SANITIZE_ADDRESS__
162 // We could have manually poisoned that memory for ASAN.
163 // And we must unpoison it by ourself as specified in documentation
164 // for __asan_poison_memory_region() in sanitizer/asan_interface.h
165 // munmap() doesn't do it for us automatically.
166 MEM_MAKE_ADDRESSABLE(ptr, size);
167 #endif /* __SANITIZE_ADDRESS__ */
168
169 #ifdef HAVE_LINUX_LARGE_PAGES
170 if (my_use_large_pages && opt_large_page_size && !shmdt(ptr)) {
171 my_atomic_addlint(
172 &os_total_large_mem_allocated, -size);
173 return;
174 }
175 #endif /* HAVE_LINUX_LARGE_PAGES */
176 #ifdef _WIN32
177 /* When RELEASE memory, the size parameter must be 0.
178 Do not use MEM_RELEASE with MEM_DECOMMIT. */
179 if (!VirtualFree(ptr, 0, MEM_RELEASE)) {
180 ib::error() << "VirtualFree(" << ptr << ", " << size
181 << ") failed; Windows error " << GetLastError();
182 } else {
183 my_atomic_addlint(
184 &os_total_large_mem_allocated, -lint(size));
185 }
186 #elif !defined OS_MAP_ANON
187 ut_free(ptr);
188 #else
189 # if defined(UNIV_SOLARIS)
190 if (munmap(static_cast<caddr_t>(ptr), size)) {
191 # else
192 if (munmap(ptr, size)) {
193 # endif /* UNIV_SOLARIS */
194 ib::error() << "munmap(" << ptr << ", " << size << ") failed;"
195 " errno " << errno;
196 } else {
197 my_atomic_addlint(
198 &os_total_large_mem_allocated, -size);
199 }
200 #endif
201 }
202