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