1
/******************************************************
2
The interface to the operating system
3
process control primitives
7
Created 9/30/1995 Heikki Tuuri
8
*******************************************************/
20
How to get AWE to compile on Windows?
21
-------------------------------------
23
In the project settings of the innobase project the Visual C++ source,
24
__WIN2000__ has to be defined.
26
The Visual C++ has to be relatively recent and _WIN32_WINNT has to be
27
defined to a value >= 0x0500 when windows.h is included.
29
#define _WIN32_WINNT 0x0500
34
See the error message in os_awe_allocate_physical_mem().
36
How to assign privileges for mysqld to use AWE?
37
-----------------------------------------------
39
See the error message in os_awe_enable_lock_pages_in_mem().
41
Use Windows AWE functions in this order
42
---------------------------------------
44
(1) os_awe_enable_lock_pages_in_mem();
45
(2) os_awe_allocate_physical_mem();
46
(3) os_awe_allocate_virtual_mem_window();
47
(4) os_awe_map_physical_mem_to_window().
49
To test 'AWE' in a computer which does not have the AWE API,
50
you can compile with UNIV_SIMULATE_AWE defined in this file.
53
#ifdef UNIV_SIMULATE_AWE
54
/* If we simulate AWE, we allocate the 'physical memory' here */
55
byte* os_awe_simulate_mem;
56
ulint os_awe_simulate_mem_size;
57
os_awe_t* os_awe_simulate_page_info;
58
byte* os_awe_simulate_window;
59
ulint os_awe_simulate_window_size;
60
/* In simulated AWE the following contains a NULL pointer or a pointer
61
to a mapped 'physical page' for each 4 kB page in the AWE window */
62
byte** os_awe_simulate_map;
66
os_awe_t* os_awe_page_info;
69
ulint os_awe_window_size;
72
ibool os_use_large_pages;
73
/* Large page size. This may be a boot-time option on some platforms */
74
ulint os_large_page_size;
76
/********************************************************************
77
Windows AWE support. Tries to enable the "lock pages in memory" privilege for
78
the current process so that the current process can allocate memory-locked
79
virtual address space to act as the window where AWE maps physical memory. */
82
os_awe_enable_lock_pages_in_mem(void)
83
/*=================================*/
84
/* out: TRUE if success, FALSE if error;
85
prints error info to stderr if no success */
87
#ifdef UNIV_SIMULATE_AWE
91
#elif defined(__WIN2000__)
94
LUID_AND_ATTRIBUTES Privilege[1];
100
hProcess = GetCurrentProcess();
102
/* Open the token of the current process */
104
Result = OpenProcessToken(hProcess,
105
TOKEN_ADJUST_PRIVILEGES, &Token);
106
if (Result != TRUE) {
108
"InnoDB: AWE: Cannot open process token, error %lu\n",
109
(ulint)GetLastError());
115
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
117
/* Get the local unique identifier (LUID) of the SE_LOCK_MEMORY
120
Result = LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME,
121
&(Info.Privilege[0].Luid));
122
if (Result != TRUE) {
124
"InnoDB: AWE: Cannot get local privilege"
125
" value for %s, error %lu.\n",
126
SE_LOCK_MEMORY_NAME, (ulint)GetLastError());
131
/* Try to adjust the privilege */
133
Result = AdjustTokenPrivileges(Token, FALSE,
134
(PTOKEN_PRIVILEGES)&Info,
136
/* Check the result */
138
if (Result != TRUE) {
140
"InnoDB: AWE: Cannot adjust process token privileges,"
144
} else if (GetLastError() != ERROR_SUCCESS) {
146
"InnoDB: AWE: Cannot enable SE_LOCK_MEMORY privilege,"
148
"InnoDB: In Windows XP Home you cannot use AWE."
149
" In Windows 2000 and XP\n"
150
"InnoDB: Professional you must go to the"
151
" Control Panel, to\n"
152
"InnoDB: Security Settings, to Local Policies,"
154
"InnoDB: the 'lock pages in memory' privilege"
155
" for the user who runs\n"
156
"InnoDB: the MySQL server.\n", GetLastError());
167
"InnoDB: AWE: Error: to use AWE you must use"
168
" a ...-nt MySQL executable.\n");
174
/********************************************************************
175
Allocates physical RAM memory up to 64 GB in an Intel 32-bit x86
179
os_awe_allocate_physical_mem(
180
/*=========================*/
181
/* out: TRUE if success */
182
os_awe_t** page_info, /* out, own: array of opaque data containing
183
the info for allocated physical memory pages;
184
each allocated 4 kB physical memory page has
185
one slot of type os_awe_t in the array */
186
ulint n_megabytes) /* in: number of megabytes to allocate */
188
#ifdef UNIV_SIMULATE_AWE
189
os_awe_simulate_page_info = ut_malloc
190
(sizeof(os_awe_t) * n_megabytes
191
* ((1024 * 1024) / OS_AWE_X86_PAGE_SIZE));
194
= ut_align(ut_malloc(4096 + 1024 * 1024 * n_megabytes), 4096);
195
os_awe_simulate_mem_size = n_megabytes * 1024 * 1024;
197
*page_info = os_awe_simulate_page_info;
201
#elif defined(__WIN2000__)
203
os_awe_t NumberOfPages; /* Question: why does Windows
204
use the name ULONG_PTR for
205
a scalar integer type? Maybe
206
because we may also refer to
208
os_awe_t NumberOfPagesInitial;
209
SYSTEM_INFO sSysInfo;
212
if (n_megabytes > 64 * 1024) {
215
"InnoDB: AWE: Error: tried to allocate %lu MB.\n"
216
"InnoDB: AWE cannot allocate more than"
217
" 64 GB in any computer.\n", n_megabytes);
222
GetSystemInfo(&sSysInfo); /* fill the system information structure */
224
if ((ulint)OS_AWE_X86_PAGE_SIZE != (ulint)sSysInfo.dwPageSize) {
226
"InnoDB: AWE: Error: this computer has a page size"
228
"InnoDB: Should be 4096 bytes for"
229
" InnoDB AWE support to work.\n",
230
(ulint)sSysInfo.dwPageSize);
235
/* Calculate the number of pages of memory to request */
237
NumberOfPages = n_megabytes * ((1024 * 1024) / OS_AWE_X86_PAGE_SIZE);
239
/* Calculate the size of page_info for allocated physical pages */
241
PFNArraySize = NumberOfPages * sizeof(os_awe_t);
243
*page_info = (os_awe_t*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
245
if (*page_info == NULL) {
247
"InnoDB: AWE: Failed to allocate page info"
248
" array from process heap, error %lu\n",
249
(ulint)GetLastError());
254
ut_total_allocated_memory += PFNArraySize;
256
/* Enable this process' privilege to lock pages to physical memory */
258
if (!os_awe_enable_lock_pages_in_mem()) {
263
/* Allocate the physical memory */
265
NumberOfPagesInitial = NumberOfPages;
267
os_awe_page_info = *page_info;
268
os_awe_n_pages = (ulint)NumberOfPages;
270
/* Compilation note: if the compiler complains the function is not
271
defined, see the note at the start of this file */
273
bResult = AllocateUserPhysicalPages(GetCurrentProcess(),
274
&NumberOfPages, *page_info);
275
if (bResult != TRUE) {
277
"InnoDB: AWE: Cannot allocate physical pages,"
279
(ulint)GetLastError());
284
if (NumberOfPagesInitial != NumberOfPages) {
286
"InnoDB: AWE: Error: allocated only %lu pages"
287
" of %lu requested.\n"
288
"InnoDB: Check that you have enough free RAM.\n"
289
"InnoDB: In Windows XP Professional and"
290
" 2000 Professional\n"
291
"InnoDB: Windows PAE size is max 4 GB."
292
" In 2000 and .NET\n"
293
"InnoDB: Advanced Servers and 2000 Datacenter Server"
295
"InnoDB: and in .NET Datacenter Server it is 64 GB.\n"
296
"InnoDB: A Microsoft web page said that"
297
" the processor must be an Intel\n"
298
"InnoDB: processor.\n",
299
(ulint)NumberOfPages,
300
(ulint)NumberOfPagesInitial);
306
"InnoDB: Using Address Windowing Extensions (AWE);"
307
" allocated %lu MB\n",
312
UT_NOT_USED(n_megabytes);
313
UT_NOT_USED(page_info);
319
/********************************************************************
320
Allocates a window in the virtual address space where we can map then
321
pages of physical memory. */
324
os_awe_allocate_virtual_mem_window(
325
/*===============================*/
326
/* out, own: allocated memory, or NULL if did not
328
ulint size) /* in: virtual memory allocation size in bytes, must
331
#ifdef UNIV_SIMULATE_AWE
334
os_awe_simulate_window = ut_align(ut_malloc(4096 + size), 4096);
335
os_awe_simulate_window_size = size;
337
os_awe_simulate_map = ut_malloc(sizeof(byte*) * (size / 4096));
339
for (i = 0; i < (size / 4096); i++) {
340
*(os_awe_simulate_map + i) = NULL;
343
return(os_awe_simulate_window);
345
#elif defined(__WIN2000__)
348
if (size > (ulint)0x7FFFFFFFUL) {
350
"InnoDB: AWE: Cannot allocate %lu bytes"
351
" of virtual memory\n", size);
356
ptr = VirtualAlloc(NULL, (SIZE_T)size, MEM_RESERVE | MEM_PHYSICAL,
360
"InnoDB: AWE: Cannot allocate %lu bytes"
361
" of virtual memory, error %lu\n",
362
size, (ulint)GetLastError());
368
os_awe_window_size = size;
370
ut_total_allocated_memory += size;
380
/********************************************************************
381
With this function you can map parts of physical memory allocated with
382
the ..._allocate_physical_mem to the virtual address space allocated with
383
the previous function. Intel implements this so that the process page
384
tables are updated accordingly. A test on a 1.5 GHz AMD processor and XP
385
showed that this takes < 1 microsecond, much better than the estimated 80 us
386
for copying a 16 kB page memory to memory. But, the operation will at least
387
partially invalidate the translation lookaside buffer (TLB) of all
388
processors. Under a real-world load the performance hit may be bigger. */
391
os_awe_map_physical_mem_to_window(
392
/*==============================*/
393
/* out: TRUE if success; the function
394
calls exit(1) in case of an error */
395
byte* ptr, /* in: a page-aligned pointer to
396
somewhere in the virtual address
397
space window; we map the physical mem
399
ulint n_mem_pages, /* in: number of 4 kB mem pages to
401
os_awe_t* page_info) /* in: array of page infos for those
402
pages; each page has one slot in the
405
#ifdef UNIV_SIMULATE_AWE
411
ut_a(ptr >= os_awe_simulate_window);
412
ut_a(ptr < os_awe_simulate_window + os_awe_simulate_window_size);
413
ut_a(page_info >= os_awe_simulate_page_info);
414
ut_a(page_info < os_awe_simulate_page_info
415
+ (os_awe_simulate_mem_size / 4096));
417
/* First look if some other 'physical pages' are mapped at ptr,
418
and copy them back to where they were if yes */
420
map = os_awe_simulate_map
421
+ ((ulint)(ptr - os_awe_simulate_window)) / 4096;
424
for (i = 0; i < n_mem_pages; i++) {
426
ut_memcpy(*map, page, 4096);
432
/* Then copy to ptr the 'physical pages' determined by page_info; we
433
assume page_info is a segment of the array we created at the start */
435
phys_page = os_awe_simulate_mem
436
+ (ulint)(page_info - os_awe_simulate_page_info)
439
ut_memcpy(ptr, phys_page, n_mem_pages * 4096);
443
map = os_awe_simulate_map
444
+ ((ulint)(ptr - os_awe_simulate_window)) / 4096;
446
for (i = 0; i < n_mem_pages; i++) {
455
#elif defined(__WIN2000__)
459
n_pages = (os_awe_t)n_mem_pages;
461
if (!(ptr >= os_awe_window)) {
463
"InnoDB: AWE: Error: trying to map to address %lx"
464
" but AWE window start %lx\n",
465
(ulint)ptr, (ulint)os_awe_window);
469
if (!(ptr <= os_awe_window + os_awe_window_size - UNIV_PAGE_SIZE)) {
471
"InnoDB: AWE: Error: trying to map to address %lx"
472
" but AWE window end %lx\n",
473
(ulint)ptr, (ulint)os_awe_window + os_awe_window_size);
477
if (!(page_info >= os_awe_page_info)) {
479
"InnoDB: AWE: Error: trying to map page info"
480
" at %lx but array start %lx\n",
481
(ulint)page_info, (ulint)os_awe_page_info);
485
if (!(page_info <= os_awe_page_info + (os_awe_n_pages - 4))) {
487
"InnoDB: AWE: Error: trying to map page info"
488
" at %lx but array end %lx\n",
490
(ulint)(os_awe_page_info + os_awe_n_pages));
494
bResult = MapUserPhysicalPages((PVOID)ptr, n_pages, page_info);
496
if (bResult != TRUE) {
497
ut_print_timestamp(stderr);
499
" InnoDB: AWE: Mapping of %lu physical pages"
500
" to address %lx failed,\n"
501
"InnoDB: error %lu.\n"
502
"InnoDB: Cannot continue operation.\n",
503
n_mem_pages, (ulint)ptr, (ulint)GetLastError());
510
UT_NOT_USED(n_mem_pages);
511
UT_NOT_USED(page_info);
517
/********************************************************************
518
Converts the current process id to a number. It is not guaranteed that the
519
number is unique. In Linux returns the 'process number' of the current
520
thread. That number is the same as one sees in 'top', for example. In Linux
521
the thread id is not the same as one sees in 'top'. */
524
os_proc_get_number(void)
525
/*====================*/
528
return((ulint)GetCurrentProcessId());
530
return((ulint)getpid());
534
/********************************************************************
535
Allocates non-cacheable memory. */
538
os_mem_alloc_nocache(
539
/*=================*/
540
/* out: allocated memory */
541
ulint n) /* in: number of bytes */
546
ptr = VirtualAlloc(NULL, n, MEM_COMMIT,
547
PAGE_READWRITE | PAGE_NOCACHE);
552
return(ut_malloc(n));
556
/********************************************************************
557
Allocates large pages memory. */
562
/* out: allocated memory */
563
ulint n, /* in: number of bytes */
564
ibool set_to_zero, /* in: TRUE if allocated memory
565
should be set to zero if
566
UNIV_SET_MEM_TO_ZERO is defined */
567
ibool assert_on_error)/* in: if TRUE, we crash mysqld if
568
the memory cannot be allocated */
570
#ifdef HAVE_LARGE_PAGES
576
if (!os_use_large_pages || !os_large_page_size) {
581
/* Align block size to os_large_page_size */
582
size = ((n - 1) & ~(os_large_page_size - 1)) + os_large_page_size;
584
shmid = shmget(IPC_PRIVATE, (size_t)size, SHM_HUGETLB | SHM_R | SHM_W);
586
fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to allocate"
587
" %lu bytes. errno %d\n", n, errno);
589
ptr = shmat(shmid, NULL, 0);
590
if (ptr == (void *)-1) {
591
fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to"
592
" attach shared memory segment, errno %d\n",
596
/* Remove the shared memory segment so that it will be
597
automatically freed after memory is detached or
599
shmctl(shmid, IPC_RMID, &buf);
605
#ifdef UNIV_SET_MEM_TO_ZERO
606
memset(ptr, '\0', size);
613
fprintf(stderr, "InnoDB HugeTLB: Warning: Using conventional"
616
#endif /* HAVE_LARGE_PAGES */
618
return(ut_malloc_low(n, set_to_zero, assert_on_error));
621
/********************************************************************
622
Frees large pages memory. */
627
void *ptr) /* in: number of bytes */
629
#ifdef HAVE_LARGE_PAGES
630
if (os_use_large_pages && os_large_page_size
642
/********************************************************************
643
Sets the priority boost for threads released from waiting within the current
647
os_process_set_priority_boost(
648
/*==========================*/
649
ibool do_boost) /* in: TRUE if priority boost should be done,
665
/* Does not do anything currently!
666
SetProcessPriorityBoost(GetCurrentProcess(), no_boost);
668
fputs("Warning: process priority boost setting"
669
" currently not functional!\n",
672
UT_NOT_USED(do_boost);