1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Platform-specific code for Win32. 6 7 // Secure API functions are not available using MinGW with msvcrt.dll 8 // on Windows XP. Make sure MINGW_HAS_SECURE_API is not defined to 9 // disable definition of secure API functions in standard headers that 10 // would conflict with our own implementation. 11 #ifdef __MINGW32__ 12 #include <_mingw.h> 13 #ifdef MINGW_HAS_SECURE_API 14 #undef MINGW_HAS_SECURE_API 15 #endif // MINGW_HAS_SECURE_API 16 #endif // __MINGW32__ 17 18 #include <limits> 19 20 #include "src/base/win32-headers.h" 21 22 #include "src/base/bits.h" 23 #include "src/base/lazy-instance.h" 24 #include "src/base/macros.h" 25 #include "src/base/platform/platform.h" 26 #include "src/base/platform/time.h" 27 #include "src/base/utils/random-number-generator.h" 28 29 30 // Extra functions for MinGW. Most of these are the _s functions which are in 31 // the Microsoft Visual Studio C++ CRT. 32 #ifdef __MINGW32__ 33 34 35 #ifndef __MINGW64_VERSION_MAJOR 36 37 #define _TRUNCATE 0 38 #define STRUNCATE 80 39 40 inline void MemoryBarrier() { 41 int barrier = 0; 42 __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier)); 43 } 44 45 #endif // __MINGW64_VERSION_MAJOR 46 47 48 int localtime_s(tm* out_tm, const time_t* time) { 49 tm* posix_local_time_struct = localtime(time); // NOLINT 50 if (posix_local_time_struct == NULL) return 1; 51 *out_tm = *posix_local_time_struct; 52 return 0; 53 } 54 55 56 int fopen_s(FILE** pFile, const char* filename, const char* mode) { 57 *pFile = fopen(filename, mode); 58 return *pFile != NULL ? 0 : 1; 59 } 60 61 int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count, 62 const char* format, va_list argptr) { 63 DCHECK(count == _TRUNCATE); 64 return _vsnprintf(buffer, sizeOfBuffer, format, argptr); 65 } 66 67 68 int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) { 69 CHECK(source != NULL); 70 CHECK(dest != NULL); 71 CHECK_GT(dest_size, 0); 72 73 if (count == _TRUNCATE) { 74 while (dest_size > 0 && *source != 0) { 75 *(dest++) = *(source++); 76 --dest_size; 77 } 78 if (dest_size == 0) { 79 *(dest - 1) = 0; 80 return STRUNCATE; 81 } 82 } else { 83 while (dest_size > 0 && count > 0 && *source != 0) { 84 *(dest++) = *(source++); 85 --dest_size; 86 --count; 87 } 88 } 89 CHECK_GT(dest_size, 0); 90 *dest = 0; 91 return 0; 92 } 93 94 #endif // __MINGW32__ 95 96 namespace v8 { 97 namespace base { 98 99 namespace { 100 101 bool g_hard_abort = false; 102 103 } // namespace 104 105 class TimezoneCache { 106 public: 107 TimezoneCache() : initialized_(false) { } 108 109 void Clear() { 110 initialized_ = false; 111 } 112 113 // Initialize timezone information. The timezone information is obtained from 114 // windows. If we cannot get the timezone information we fall back to CET. 115 void InitializeIfNeeded() { 116 // Just return if timezone information has already been initialized. 117 if (initialized_) return; 118 119 // Initialize POSIX time zone data. 120 _tzset(); 121 // Obtain timezone information from operating system. 122 memset(&tzinfo_, 0, sizeof(tzinfo_)); 123 if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) { 124 // If we cannot get timezone information we fall back to CET. 125 tzinfo_.Bias = -60; 126 tzinfo_.StandardDate.wMonth = 10; 127 tzinfo_.StandardDate.wDay = 5; 128 tzinfo_.StandardDate.wHour = 3; 129 tzinfo_.StandardBias = 0; 130 tzinfo_.DaylightDate.wMonth = 3; 131 tzinfo_.DaylightDate.wDay = 5; 132 tzinfo_.DaylightDate.wHour = 2; 133 tzinfo_.DaylightBias = -60; 134 } 135 136 // Make standard and DST timezone names. 137 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1, 138 std_tz_name_, kTzNameSize, NULL, NULL); 139 std_tz_name_[kTzNameSize - 1] = '\0'; 140 WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1, 141 dst_tz_name_, kTzNameSize, NULL, NULL); 142 dst_tz_name_[kTzNameSize - 1] = '\0'; 143 144 // If OS returned empty string or resource id (like "@tzres.dll,-211") 145 // simply guess the name from the UTC bias of the timezone. 146 // To properly resolve the resource identifier requires a library load, 147 // which is not possible in a sandbox. 148 if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') { 149 OS::SNPrintF(std_tz_name_, kTzNameSize - 1, 150 "%s Standard Time", 151 GuessTimezoneNameFromBias(tzinfo_.Bias)); 152 } 153 if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') { 154 OS::SNPrintF(dst_tz_name_, kTzNameSize - 1, 155 "%s Daylight Time", 156 GuessTimezoneNameFromBias(tzinfo_.Bias)); 157 } 158 // Timezone information initialized. 159 initialized_ = true; 160 } 161 162 // Guess the name of the timezone from the bias. 163 // The guess is very biased towards the northern hemisphere. 164 const char* GuessTimezoneNameFromBias(int bias) { 165 static const int kHour = 60; 166 switch (-bias) { 167 case -9*kHour: return "Alaska"; 168 case -8*kHour: return "Pacific"; 169 case -7*kHour: return "Mountain"; 170 case -6*kHour: return "Central"; 171 case -5*kHour: return "Eastern"; 172 case -4*kHour: return "Atlantic"; 173 case 0*kHour: return "GMT"; 174 case +1*kHour: return "Central Europe"; 175 case +2*kHour: return "Eastern Europe"; 176 case +3*kHour: return "Russia"; 177 case +5*kHour + 30: return "India"; 178 case +8*kHour: return "China"; 179 case +9*kHour: return "Japan"; 180 case +12*kHour: return "New Zealand"; 181 default: return "Local"; 182 } 183 } 184 185 186 private: 187 static const int kTzNameSize = 128; 188 bool initialized_; 189 char std_tz_name_[kTzNameSize]; 190 char dst_tz_name_[kTzNameSize]; 191 TIME_ZONE_INFORMATION tzinfo_; 192 friend class Win32Time; 193 }; 194 195 196 // ---------------------------------------------------------------------------- 197 // The Time class represents time on win32. A timestamp is represented as 198 // a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript 199 // timestamps are represented as a doubles in milliseconds since 00:00:00 UTC, 200 // January 1, 1970. 201 202 class Win32Time { 203 public: 204 // Constructors. 205 Win32Time(); 206 explicit Win32Time(double jstime); 207 Win32Time(int year, int mon, int day, int hour, int min, int sec); 208 209 // Convert timestamp to JavaScript representation. 210 double ToJSTime(); 211 212 // Set timestamp to current time. 213 void SetToCurrentTime(); 214 215 // Returns the local timezone offset in milliseconds east of UTC. This is 216 // the number of milliseconds you must add to UTC to get local time, i.e. 217 // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This 218 // routine also takes into account whether daylight saving is effect 219 // at the time. 220 int64_t LocalOffset(TimezoneCache* cache); 221 222 // Returns the daylight savings time offset for the time in milliseconds. 223 int64_t DaylightSavingsOffset(TimezoneCache* cache); 224 225 // Returns a string identifying the current timezone for the 226 // timestamp taking into account daylight saving. 227 char* LocalTimezone(TimezoneCache* cache); 228 229 private: 230 // Constants for time conversion. 231 static const int64_t kTimeEpoc = 116444736000000000LL; 232 static const int64_t kTimeScaler = 10000; 233 static const int64_t kMsPerMinute = 60000; 234 235 // Constants for timezone information. 236 static const bool kShortTzNames = false; 237 238 // Return whether or not daylight savings time is in effect at this time. 239 bool InDST(TimezoneCache* cache); 240 241 // Accessor for FILETIME representation. 242 FILETIME& ft() { return time_.ft_; } 243 244 // Accessor for integer representation. 245 int64_t& t() { return time_.t_; } 246 247 // Although win32 uses 64-bit integers for representing timestamps, 248 // these are packed into a FILETIME structure. The FILETIME structure 249 // is just a struct representing a 64-bit integer. The TimeStamp union 250 // allows access to both a FILETIME and an integer representation of 251 // the timestamp. 252 union TimeStamp { 253 FILETIME ft_; 254 int64_t t_; 255 }; 256 257 TimeStamp time_; 258 }; 259 260 261 // Initialize timestamp to start of epoc. 262 Win32Time::Win32Time() { 263 t() = 0; 264 } 265 266 267 // Initialize timestamp from a JavaScript timestamp. 268 Win32Time::Win32Time(double jstime) { 269 t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc; 270 } 271 272 273 // Initialize timestamp from date/time components. 274 Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) { 275 SYSTEMTIME st; 276 st.wYear = year; 277 st.wMonth = mon; 278 st.wDay = day; 279 st.wHour = hour; 280 st.wMinute = min; 281 st.wSecond = sec; 282 st.wMilliseconds = 0; 283 SystemTimeToFileTime(&st, &ft()); 284 } 285 286 287 // Convert timestamp to JavaScript timestamp. 288 double Win32Time::ToJSTime() { 289 return static_cast<double>((t() - kTimeEpoc) / kTimeScaler); 290 } 291 292 293 // Set timestamp to current time. 294 void Win32Time::SetToCurrentTime() { 295 // The default GetSystemTimeAsFileTime has a ~15.5ms resolution. 296 // Because we're fast, we like fast timers which have at least a 297 // 1ms resolution. 298 // 299 // timeGetTime() provides 1ms granularity when combined with 300 // timeBeginPeriod(). If the host application for v8 wants fast 301 // timers, it can use timeBeginPeriod to increase the resolution. 302 // 303 // Using timeGetTime() has a drawback because it is a 32bit value 304 // and hence rolls-over every ~49days. 305 // 306 // To use the clock, we use GetSystemTimeAsFileTime as our base; 307 // and then use timeGetTime to extrapolate current time from the 308 // start time. To deal with rollovers, we resync the clock 309 // any time when more than kMaxClockElapsedTime has passed or 310 // whenever timeGetTime creates a rollover. 311 312 static bool initialized = false; 313 static TimeStamp init_time; 314 static DWORD init_ticks; 315 static const int64_t kHundredNanosecondsPerSecond = 10000000; 316 static const int64_t kMaxClockElapsedTime = 317 60*kHundredNanosecondsPerSecond; // 1 minute 318 319 // If we are uninitialized, we need to resync the clock. 320 bool needs_resync = !initialized; 321 322 // Get the current time. 323 TimeStamp time_now; 324 GetSystemTimeAsFileTime(&time_now.ft_); 325 DWORD ticks_now = timeGetTime(); 326 327 // Check if we need to resync due to clock rollover. 328 needs_resync |= ticks_now < init_ticks; 329 330 // Check if we need to resync due to elapsed time. 331 needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime; 332 333 // Check if we need to resync due to backwards time change. 334 needs_resync |= time_now.t_ < init_time.t_; 335 336 // Resync the clock if necessary. 337 if (needs_resync) { 338 GetSystemTimeAsFileTime(&init_time.ft_); 339 init_ticks = ticks_now = timeGetTime(); 340 initialized = true; 341 } 342 343 // Finally, compute the actual time. Why is this so hard. 344 DWORD elapsed = ticks_now - init_ticks; 345 this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000); 346 } 347 348 349 // Return the local timezone offset in milliseconds east of UTC. This 350 // takes into account whether daylight saving is in effect at the time. 351 // Only times in the 32-bit Unix range may be passed to this function. 352 // Also, adding the time-zone offset to the input must not overflow. 353 // The function EquivalentTime() in date.js guarantees this. 354 int64_t Win32Time::LocalOffset(TimezoneCache* cache) { 355 cache->InitializeIfNeeded(); 356 357 Win32Time rounded_to_second(*this); 358 rounded_to_second.t() = 359 rounded_to_second.t() / 1000 / kTimeScaler * 1000 * kTimeScaler; 360 // Convert to local time using POSIX localtime function. 361 // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime() 362 // very slow. Other browsers use localtime(). 363 364 // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to 365 // POSIX seconds past 1/1/1970 0:00:00. 366 double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000; 367 if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) { 368 return 0; 369 } 370 // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int. 371 time_t posix_time = static_cast<time_t>(unchecked_posix_time); 372 373 // Convert to local time, as struct with fields for day, hour, year, etc. 374 tm posix_local_time_struct; 375 if (localtime_s(&posix_local_time_struct, &posix_time)) return 0; 376 377 if (posix_local_time_struct.tm_isdst > 0) { 378 return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute; 379 } else if (posix_local_time_struct.tm_isdst == 0) { 380 return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute; 381 } else { 382 return cache->tzinfo_.Bias * -kMsPerMinute; 383 } 384 } 385 386 387 // Return whether or not daylight savings time is in effect at this time. 388 bool Win32Time::InDST(TimezoneCache* cache) { 389 cache->InitializeIfNeeded(); 390 391 // Determine if DST is in effect at the specified time. 392 bool in_dst = false; 393 if (cache->tzinfo_.StandardDate.wMonth != 0 || 394 cache->tzinfo_.DaylightDate.wMonth != 0) { 395 // Get the local timezone offset for the timestamp in milliseconds. 396 int64_t offset = LocalOffset(cache); 397 398 // Compute the offset for DST. The bias parameters in the timezone info 399 // are specified in minutes. These must be converted to milliseconds. 400 int64_t dstofs = 401 -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute; 402 403 // If the local time offset equals the timezone bias plus the daylight 404 // bias then DST is in effect. 405 in_dst = offset == dstofs; 406 } 407 408 return in_dst; 409 } 410 411 412 // Return the daylight savings time offset for this time. 413 int64_t Win32Time::DaylightSavingsOffset(TimezoneCache* cache) { 414 return InDST(cache) ? 60 * kMsPerMinute : 0; 415 } 416 417 418 // Returns a string identifying the current timezone for the 419 // timestamp taking into account daylight saving. 420 char* Win32Time::LocalTimezone(TimezoneCache* cache) { 421 // Return the standard or DST time zone name based on whether daylight 422 // saving is in effect at the given time. 423 return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_; 424 } 425 426 427 // Returns the accumulated user time for thread. 428 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 429 FILETIME dummy; 430 uint64_t usertime; 431 432 // Get the amount of time that the thread has executed in user mode. 433 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy, 434 reinterpret_cast<FILETIME*>(&usertime))) return -1; 435 436 // Adjust the resolution to micro-seconds. 437 usertime /= 10; 438 439 // Convert to seconds and microseconds 440 *secs = static_cast<uint32_t>(usertime / 1000000); 441 *usecs = static_cast<uint32_t>(usertime % 1000000); 442 return 0; 443 } 444 445 446 // Returns current time as the number of milliseconds since 447 // 00:00:00 UTC, January 1, 1970. 448 double OS::TimeCurrentMillis() { 449 return Time::Now().ToJsTime(); 450 } 451 452 453 TimezoneCache* OS::CreateTimezoneCache() { 454 return new TimezoneCache(); 455 } 456 457 458 void OS::DisposeTimezoneCache(TimezoneCache* cache) { 459 delete cache; 460 } 461 462 463 void OS::ClearTimezoneCache(TimezoneCache* cache) { 464 cache->Clear(); 465 } 466 467 468 // Returns a string identifying the current timezone taking into 469 // account daylight saving. 470 const char* OS::LocalTimezone(double time, TimezoneCache* cache) { 471 return Win32Time(time).LocalTimezone(cache); 472 } 473 474 475 // Returns the local time offset in milliseconds east of UTC without 476 // taking daylight savings time into account. 477 double OS::LocalTimeOffset(TimezoneCache* cache) { 478 // Use current time, rounded to the millisecond. 479 Win32Time t(TimeCurrentMillis()); 480 // Time::LocalOffset inlcudes any daylight savings offset, so subtract it. 481 return static_cast<double>(t.LocalOffset(cache) - 482 t.DaylightSavingsOffset(cache)); 483 } 484 485 486 // Returns the daylight savings offset in milliseconds for the given 487 // time. 488 double OS::DaylightSavingsOffset(double time, TimezoneCache* cache) { 489 int64_t offset = Win32Time(time).DaylightSavingsOffset(cache); 490 return static_cast<double>(offset); 491 } 492 493 494 int OS::GetLastError() { 495 return ::GetLastError(); 496 } 497 498 499 int OS::GetCurrentProcessId() { 500 return static_cast<int>(::GetCurrentProcessId()); 501 } 502 503 504 int OS::GetCurrentThreadId() { 505 return static_cast<int>(::GetCurrentThreadId()); 506 } 507 508 509 // ---------------------------------------------------------------------------- 510 // Win32 console output. 511 // 512 // If a Win32 application is linked as a console application it has a normal 513 // standard output and standard error. In this case normal printf works fine 514 // for output. However, if the application is linked as a GUI application, 515 // the process doesn't have a console, and therefore (debugging) output is lost. 516 // This is the case if we are embedded in a windows program (like a browser). 517 // In order to be able to get debug output in this case the the debugging 518 // facility using OutputDebugString. This output goes to the active debugger 519 // for the process (if any). Else the output can be monitored using DBMON.EXE. 520 521 enum OutputMode { 522 UNKNOWN, // Output method has not yet been determined. 523 CONSOLE, // Output is written to stdout. 524 ODS // Output is written to debug facility. 525 }; 526 527 static OutputMode output_mode = UNKNOWN; // Current output mode. 528 529 530 // Determine if the process has a console for output. 531 static bool HasConsole() { 532 // Only check the first time. Eventual race conditions are not a problem, 533 // because all threads will eventually determine the same mode. 534 if (output_mode == UNKNOWN) { 535 // We cannot just check that the standard output is attached to a console 536 // because this would fail if output is redirected to a file. Therefore we 537 // say that a process does not have an output console if either the 538 // standard output handle is invalid or its file type is unknown. 539 if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE && 540 GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN) 541 output_mode = CONSOLE; 542 else 543 output_mode = ODS; 544 } 545 return output_mode == CONSOLE; 546 } 547 548 549 static void VPrintHelper(FILE* stream, const char* format, va_list args) { 550 if ((stream == stdout || stream == stderr) && !HasConsole()) { 551 // It is important to use safe print here in order to avoid 552 // overflowing the buffer. We might truncate the output, but this 553 // does not crash. 554 char buffer[4096]; 555 OS::VSNPrintF(buffer, sizeof(buffer), format, args); 556 OutputDebugStringA(buffer); 557 } else { 558 vfprintf(stream, format, args); 559 } 560 } 561 562 563 FILE* OS::FOpen(const char* path, const char* mode) { 564 FILE* result; 565 if (fopen_s(&result, path, mode) == 0) { 566 return result; 567 } else { 568 return NULL; 569 } 570 } 571 572 573 bool OS::Remove(const char* path) { 574 return (DeleteFileA(path) != 0); 575 } 576 577 char OS::DirectorySeparator() { return '\\'; } 578 579 bool OS::isDirectorySeparator(const char ch) { 580 return ch == '/' || ch == '\\'; 581 } 582 583 584 FILE* OS::OpenTemporaryFile() { 585 // tmpfile_s tries to use the root dir, don't use it. 586 char tempPathBuffer[MAX_PATH]; 587 DWORD path_result = 0; 588 path_result = GetTempPathA(MAX_PATH, tempPathBuffer); 589 if (path_result > MAX_PATH || path_result == 0) return NULL; 590 UINT name_result = 0; 591 char tempNameBuffer[MAX_PATH]; 592 name_result = GetTempFileNameA(tempPathBuffer, "", 0, tempNameBuffer); 593 if (name_result == 0) return NULL; 594 FILE* result = FOpen(tempNameBuffer, "w+"); // Same mode as tmpfile uses. 595 if (result != NULL) { 596 Remove(tempNameBuffer); // Delete on close. 597 } 598 return result; 599 } 600 601 602 // Open log file in binary mode to avoid /n -> /r/n conversion. 603 const char* const OS::LogFileOpenMode = "wb"; 604 605 606 // Print (debug) message to console. 607 void OS::Print(const char* format, ...) { 608 va_list args; 609 va_start(args, format); 610 VPrint(format, args); 611 va_end(args); 612 } 613 614 615 void OS::VPrint(const char* format, va_list args) { 616 VPrintHelper(stdout, format, args); 617 } 618 619 620 void OS::FPrint(FILE* out, const char* format, ...) { 621 va_list args; 622 va_start(args, format); 623 VFPrint(out, format, args); 624 va_end(args); 625 } 626 627 628 void OS::VFPrint(FILE* out, const char* format, va_list args) { 629 VPrintHelper(out, format, args); 630 } 631 632 633 // Print error message to console. 634 void OS::PrintError(const char* format, ...) { 635 va_list args; 636 va_start(args, format); 637 VPrintError(format, args); 638 va_end(args); 639 } 640 641 642 void OS::VPrintError(const char* format, va_list args) { 643 VPrintHelper(stderr, format, args); 644 } 645 646 647 int OS::SNPrintF(char* str, int length, const char* format, ...) { 648 va_list args; 649 va_start(args, format); 650 int result = VSNPrintF(str, length, format, args); 651 va_end(args); 652 return result; 653 } 654 655 656 int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { 657 int n = _vsnprintf_s(str, length, _TRUNCATE, format, args); 658 // Make sure to zero-terminate the string if the output was 659 // truncated or if there was an error. 660 if (n < 0 || n >= length) { 661 if (length > 0) 662 str[length - 1] = '\0'; 663 return -1; 664 } else { 665 return n; 666 } 667 } 668 669 670 char* OS::StrChr(char* str, int c) { 671 return const_cast<char*>(strchr(str, c)); 672 } 673 674 675 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { 676 // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small. 677 size_t buffer_size = static_cast<size_t>(length); 678 if (n + 1 > buffer_size) // count for trailing '\0' 679 n = _TRUNCATE; 680 int result = strncpy_s(dest, length, src, n); 681 USE(result); 682 DCHECK(result == 0 || (n == _TRUNCATE && result == STRUNCATE)); 683 } 684 685 686 #undef _TRUNCATE 687 #undef STRUNCATE 688 689 690 // Get the system's page size used by VirtualAlloc() or the next power 691 // of two. The reason for always returning a power of two is that the 692 // rounding up in OS::Allocate expects that. 693 static size_t GetPageSize() { 694 static size_t page_size = 0; 695 if (page_size == 0) { 696 SYSTEM_INFO info; 697 GetSystemInfo(&info); 698 page_size = base::bits::RoundUpToPowerOfTwo32(info.dwPageSize); 699 } 700 return page_size; 701 } 702 703 704 // The allocation alignment is the guaranteed alignment for 705 // VirtualAlloc'ed blocks of memory. 706 size_t OS::AllocateAlignment() { 707 static size_t allocate_alignment = 0; 708 if (allocate_alignment == 0) { 709 SYSTEM_INFO info; 710 GetSystemInfo(&info); 711 allocate_alignment = info.dwAllocationGranularity; 712 } 713 return allocate_alignment; 714 } 715 716 717 static LazyInstance<RandomNumberGenerator>::type 718 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER; 719 720 721 void OS::Initialize(int64_t random_seed, bool hard_abort, 722 const char* const gc_fake_mmap) { 723 if (random_seed) { 724 platform_random_number_generator.Pointer()->SetSeed(random_seed); 725 } 726 g_hard_abort = hard_abort; 727 } 728 729 730 void* OS::GetRandomMmapAddr() { 731 // The address range used to randomize RWX allocations in OS::Allocate 732 // Try not to map pages into the default range that windows loads DLLs 733 // Use a multiple of 64k to prevent committing unused memory. 734 // Note: This does not guarantee RWX regions will be within the 735 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax 736 #ifdef V8_HOST_ARCH_64_BIT 737 static const uintptr_t kAllocationRandomAddressMin = 0x0000000080000000; 738 static const uintptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000; 739 #else 740 static const uintptr_t kAllocationRandomAddressMin = 0x04000000; 741 static const uintptr_t kAllocationRandomAddressMax = 0x3FFF0000; 742 #endif 743 uintptr_t address; 744 platform_random_number_generator.Pointer()->NextBytes(&address, 745 sizeof(address)); 746 address <<= kPageSizeBits; 747 address += kAllocationRandomAddressMin; 748 address &= kAllocationRandomAddressMax; 749 return reinterpret_cast<void *>(address); 750 } 751 752 753 static void* RandomizedVirtualAlloc(size_t size, int action, int protection) { 754 LPVOID base = NULL; 755 static BOOL use_aslr = -1; 756 #ifdef V8_HOST_ARCH_32_BIT 757 // Don't bother randomizing on 32-bit hosts, because they lack the room and 758 // don't have viable ASLR anyway. 759 if (use_aslr == -1 && !IsWow64Process(GetCurrentProcess(), &use_aslr)) 760 use_aslr = FALSE; 761 #else 762 use_aslr = TRUE; 763 #endif 764 765 if (use_aslr && 766 (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS)) { 767 // For executable pages try and randomize the allocation address 768 for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) { 769 base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection); 770 } 771 } 772 773 // After three attempts give up and let the OS find an address to use. 774 if (base == NULL) base = VirtualAlloc(NULL, size, action, protection); 775 776 return base; 777 } 778 779 780 void* OS::Allocate(const size_t requested, 781 size_t* allocated, 782 bool is_executable) { 783 // VirtualAlloc rounds allocated size to page size automatically. 784 size_t msize = RoundUp(requested, static_cast<int>(GetPageSize())); 785 786 // Windows XP SP2 allows Data Excution Prevention (DEP). 787 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 788 789 LPVOID mbase = RandomizedVirtualAlloc(msize, 790 MEM_COMMIT | MEM_RESERVE, 791 prot); 792 793 if (mbase == NULL) return NULL; 794 795 DCHECK((reinterpret_cast<uintptr_t>(mbase) % OS::AllocateAlignment()) == 0); 796 797 *allocated = msize; 798 return mbase; 799 } 800 801 802 void OS::Free(void* address, const size_t size) { 803 // TODO(1240712): VirtualFree has a return value which is ignored here. 804 VirtualFree(address, 0, MEM_RELEASE); 805 USE(size); 806 } 807 808 809 intptr_t OS::CommitPageSize() { 810 return 4096; 811 } 812 813 814 void OS::ProtectCode(void* address, const size_t size) { 815 DWORD old_protect; 816 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 817 } 818 819 820 void OS::Guard(void* address, const size_t size) { 821 DWORD oldprotect; 822 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect); 823 } 824 825 826 void OS::Sleep(TimeDelta interval) { 827 ::Sleep(static_cast<DWORD>(interval.InMilliseconds())); 828 } 829 830 831 void OS::Abort() { 832 if (g_hard_abort) { 833 V8_IMMEDIATE_CRASH(); 834 } 835 // Make the MSVCRT do a silent abort. 836 raise(SIGABRT); 837 838 // Make sure function doesn't return. 839 abort(); 840 } 841 842 843 void OS::DebugBreak() { 844 #if V8_CC_MSVC 845 // To avoid Visual Studio runtime support the following code can be used 846 // instead 847 // __asm { int 3 } 848 __debugbreak(); 849 #else 850 ::DebugBreak(); 851 #endif 852 } 853 854 855 class Win32MemoryMappedFile final : public OS::MemoryMappedFile { 856 public: 857 Win32MemoryMappedFile(HANDLE file, HANDLE file_mapping, void* memory, 858 size_t size) 859 : file_(file), 860 file_mapping_(file_mapping), 861 memory_(memory), 862 size_(size) {} 863 ~Win32MemoryMappedFile() final; 864 void* memory() const final { return memory_; } 865 size_t size() const final { return size_; } 866 867 private: 868 HANDLE const file_; 869 HANDLE const file_mapping_; 870 void* const memory_; 871 size_t const size_; 872 }; 873 874 875 // static 876 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 877 // Open a physical file 878 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 879 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 880 if (file == INVALID_HANDLE_VALUE) return NULL; 881 882 DWORD size = GetFileSize(file, NULL); 883 884 // Create a file mapping for the physical file 885 HANDLE file_mapping = 886 CreateFileMapping(file, NULL, PAGE_READWRITE, 0, size, NULL); 887 if (file_mapping == NULL) return NULL; 888 889 // Map a view of the file into memory 890 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size); 891 return new Win32MemoryMappedFile(file, file_mapping, memory, size); 892 } 893 894 895 // static 896 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, 897 size_t size, void* initial) { 898 // Open a physical file 899 HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 900 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 901 OPEN_ALWAYS, 0, NULL); 902 if (file == NULL) return NULL; 903 // Create a file mapping for the physical file 904 HANDLE file_mapping = CreateFileMapping(file, NULL, PAGE_READWRITE, 0, 905 static_cast<DWORD>(size), NULL); 906 if (file_mapping == NULL) return NULL; 907 // Map a view of the file into memory 908 void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size); 909 if (memory) memmove(memory, initial, size); 910 return new Win32MemoryMappedFile(file, file_mapping, memory, size); 911 } 912 913 914 Win32MemoryMappedFile::~Win32MemoryMappedFile() { 915 if (memory_) UnmapViewOfFile(memory_); 916 CloseHandle(file_mapping_); 917 CloseHandle(file_); 918 } 919 920 921 // The following code loads functions defined in DbhHelp.h and TlHelp32.h 922 // dynamically. This is to avoid being depending on dbghelp.dll and 923 // tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to 924 // kernel32.dll at some point so loading functions defines in TlHelp32.h 925 // dynamically might not be necessary any more - for some versions of Windows?). 926 927 // Function pointers to functions dynamically loaded from dbghelp.dll. 928 #define DBGHELP_FUNCTION_LIST(V) \ 929 V(SymInitialize) \ 930 V(SymGetOptions) \ 931 V(SymSetOptions) \ 932 V(SymGetSearchPath) \ 933 V(SymLoadModule64) \ 934 V(StackWalk64) \ 935 V(SymGetSymFromAddr64) \ 936 V(SymGetLineFromAddr64) \ 937 V(SymFunctionTableAccess64) \ 938 V(SymGetModuleBase64) 939 940 // Function pointers to functions dynamically loaded from dbghelp.dll. 941 #define TLHELP32_FUNCTION_LIST(V) \ 942 V(CreateToolhelp32Snapshot) \ 943 V(Module32FirstW) \ 944 V(Module32NextW) 945 946 // Define the decoration to use for the type and variable name used for 947 // dynamically loaded DLL function.. 948 #define DLL_FUNC_TYPE(name) _##name##_ 949 #define DLL_FUNC_VAR(name) _##name 950 951 // Define the type for each dynamically loaded DLL function. The function 952 // definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros 953 // from the Windows include files are redefined here to have the function 954 // definitions to be as close to the ones in the original .h files as possible. 955 #ifndef IN 956 #define IN 957 #endif 958 #ifndef VOID 959 #define VOID void 960 #endif 961 962 // DbgHelp isn't supported on MinGW yet 963 #ifndef __MINGW32__ 964 // DbgHelp.h functions. 965 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess, 966 IN PSTR UserSearchPath, 967 IN BOOL fInvadeProcess); 968 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID); 969 typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions); 970 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))( 971 IN HANDLE hProcess, 972 OUT PSTR SearchPath, 973 IN DWORD SearchPathLength); 974 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))( 975 IN HANDLE hProcess, 976 IN HANDLE hFile, 977 IN PSTR ImageName, 978 IN PSTR ModuleName, 979 IN DWORD64 BaseOfDll, 980 IN DWORD SizeOfDll); 981 typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))( 982 DWORD MachineType, 983 HANDLE hProcess, 984 HANDLE hThread, 985 LPSTACKFRAME64 StackFrame, 986 PVOID ContextRecord, 987 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, 988 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, 989 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, 990 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); 991 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))( 992 IN HANDLE hProcess, 993 IN DWORD64 qwAddr, 994 OUT PDWORD64 pdwDisplacement, 995 OUT PIMAGEHLP_SYMBOL64 Symbol); 996 typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))( 997 IN HANDLE hProcess, 998 IN DWORD64 qwAddr, 999 OUT PDWORD pdwDisplacement, 1000 OUT PIMAGEHLP_LINE64 Line64); 1001 // DbgHelp.h typedefs. Implementation found in dbghelp.dll. 1002 typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))( 1003 HANDLE hProcess, 1004 DWORD64 AddrBase); // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64 1005 typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))( 1006 HANDLE hProcess, 1007 DWORD64 AddrBase); // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64 1008 1009 // TlHelp32.h functions. 1010 typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))( 1011 DWORD dwFlags, 1012 DWORD th32ProcessID); 1013 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot, 1014 LPMODULEENTRY32W lpme); 1015 typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot, 1016 LPMODULEENTRY32W lpme); 1017 1018 #undef IN 1019 #undef VOID 1020 1021 // Declare a variable for each dynamically loaded DLL function. 1022 #define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = NULL; 1023 DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION) 1024 TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION) 1025 #undef DEF_DLL_FUNCTION 1026 1027 // Load the functions. This function has a lot of "ugly" macros in order to 1028 // keep down code duplication. 1029 1030 static bool LoadDbgHelpAndTlHelp32() { 1031 static bool dbghelp_loaded = false; 1032 1033 if (dbghelp_loaded) return true; 1034 1035 HMODULE module; 1036 1037 // Load functions from the dbghelp.dll module. 1038 module = LoadLibrary(TEXT("dbghelp.dll")); 1039 if (module == NULL) { 1040 return false; 1041 } 1042 1043 #define LOAD_DLL_FUNC(name) \ 1044 DLL_FUNC_VAR(name) = \ 1045 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name)); 1046 1047 DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC) 1048 1049 #undef LOAD_DLL_FUNC 1050 1051 // Load functions from the kernel32.dll module (the TlHelp32.h function used 1052 // to be in tlhelp32.dll but are now moved to kernel32.dll). 1053 module = LoadLibrary(TEXT("kernel32.dll")); 1054 if (module == NULL) { 1055 return false; 1056 } 1057 1058 #define LOAD_DLL_FUNC(name) \ 1059 DLL_FUNC_VAR(name) = \ 1060 reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name)); 1061 1062 TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC) 1063 1064 #undef LOAD_DLL_FUNC 1065 1066 // Check that all functions where loaded. 1067 bool result = 1068 #define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != NULL) && 1069 1070 DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED) 1071 TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED) 1072 1073 #undef DLL_FUNC_LOADED 1074 true; 1075 1076 dbghelp_loaded = result; 1077 return result; 1078 // NOTE: The modules are never unloaded and will stay around until the 1079 // application is closed. 1080 } 1081 1082 #undef DBGHELP_FUNCTION_LIST 1083 #undef TLHELP32_FUNCTION_LIST 1084 #undef DLL_FUNC_VAR 1085 #undef DLL_FUNC_TYPE 1086 1087 1088 // Load the symbols for generating stack traces. 1089 static std::vector<OS::SharedLibraryAddress> LoadSymbols( 1090 HANDLE process_handle) { 1091 static std::vector<OS::SharedLibraryAddress> result; 1092 1093 static bool symbols_loaded = false; 1094 1095 if (symbols_loaded) return result; 1096 1097 BOOL ok; 1098 1099 // Initialize the symbol engine. 1100 ok = _SymInitialize(process_handle, // hProcess 1101 NULL, // UserSearchPath 1102 false); // fInvadeProcess 1103 if (!ok) return result; 1104 1105 DWORD options = _SymGetOptions(); 1106 options |= SYMOPT_LOAD_LINES; 1107 options |= SYMOPT_FAIL_CRITICAL_ERRORS; 1108 options = _SymSetOptions(options); 1109 1110 char buf[OS::kStackWalkMaxNameLen] = {0}; 1111 ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen); 1112 if (!ok) { 1113 int err = GetLastError(); 1114 OS::Print("%d\n", err); 1115 return result; 1116 } 1117 1118 HANDLE snapshot = _CreateToolhelp32Snapshot( 1119 TH32CS_SNAPMODULE, // dwFlags 1120 GetCurrentProcessId()); // th32ProcessId 1121 if (snapshot == INVALID_HANDLE_VALUE) return result; 1122 MODULEENTRY32W module_entry; 1123 module_entry.dwSize = sizeof(module_entry); // Set the size of the structure. 1124 BOOL cont = _Module32FirstW(snapshot, &module_entry); 1125 while (cont) { 1126 DWORD64 base; 1127 // NOTE the SymLoadModule64 function has the peculiarity of accepting a 1128 // both unicode and ASCII strings even though the parameter is PSTR. 1129 base = _SymLoadModule64( 1130 process_handle, // hProcess 1131 0, // hFile 1132 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName 1133 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName 1134 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll 1135 module_entry.modBaseSize); // SizeOfDll 1136 if (base == 0) { 1137 int err = GetLastError(); 1138 if (err != ERROR_MOD_NOT_FOUND && 1139 err != ERROR_INVALID_HANDLE) { 1140 result.clear(); 1141 return result; 1142 } 1143 } 1144 int lib_name_length = WideCharToMultiByte( 1145 CP_UTF8, 0, module_entry.szExePath, -1, NULL, 0, NULL, NULL); 1146 std::string lib_name(lib_name_length, 0); 1147 WideCharToMultiByte(CP_UTF8, 0, module_entry.szExePath, -1, &lib_name[0], 1148 lib_name_length, NULL, NULL); 1149 result.push_back(OS::SharedLibraryAddress( 1150 lib_name, reinterpret_cast<uintptr_t>(module_entry.modBaseAddr), 1151 reinterpret_cast<uintptr_t>(module_entry.modBaseAddr + 1152 module_entry.modBaseSize))); 1153 cont = _Module32NextW(snapshot, &module_entry); 1154 } 1155 CloseHandle(snapshot); 1156 1157 symbols_loaded = true; 1158 return result; 1159 } 1160 1161 1162 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { 1163 // SharedLibraryEvents are logged when loading symbol information. 1164 // Only the shared libraries loaded at the time of the call to 1165 // GetSharedLibraryAddresses are logged. DLLs loaded after 1166 // initialization are not accounted for. 1167 if (!LoadDbgHelpAndTlHelp32()) return std::vector<OS::SharedLibraryAddress>(); 1168 HANDLE process_handle = GetCurrentProcess(); 1169 return LoadSymbols(process_handle); 1170 } 1171 1172 1173 void OS::SignalCodeMovingGC() { 1174 } 1175 1176 1177 #else // __MINGW32__ 1178 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { 1179 return std::vector<OS::SharedLibraryAddress>(); 1180 } 1181 1182 1183 void OS::SignalCodeMovingGC() { } 1184 #endif // __MINGW32__ 1185 1186 1187 int OS::ActivationFrameAlignment() { 1188 #ifdef _WIN64 1189 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned. 1190 #elif defined(__MINGW32__) 1191 // With gcc 4.4 the tree vectorization optimizer can generate code 1192 // that requires 16 byte alignment such as movdqa on x86. 1193 return 16; 1194 #else 1195 return 8; // Floating-point math runs faster with 8-byte alignment. 1196 #endif 1197 } 1198 1199 1200 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { } 1201 1202 1203 VirtualMemory::VirtualMemory(size_t size) 1204 : address_(ReserveRegion(size)), size_(size) { } 1205 1206 1207 VirtualMemory::VirtualMemory(size_t size, size_t alignment) 1208 : address_(NULL), size_(0) { 1209 DCHECK((alignment % OS::AllocateAlignment()) == 0); 1210 size_t request_size = RoundUp(size + alignment, 1211 static_cast<intptr_t>(OS::AllocateAlignment())); 1212 void* address = ReserveRegion(request_size); 1213 if (address == NULL) return; 1214 uint8_t* base = RoundUp(static_cast<uint8_t*>(address), alignment); 1215 // Try reducing the size by freeing and then reallocating a specific area. 1216 bool result = ReleaseRegion(address, request_size); 1217 USE(result); 1218 DCHECK(result); 1219 address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS); 1220 if (address != NULL) { 1221 request_size = size; 1222 DCHECK(base == static_cast<uint8_t*>(address)); 1223 } else { 1224 // Resizing failed, just go with a bigger area. 1225 address = ReserveRegion(request_size); 1226 if (address == NULL) return; 1227 } 1228 address_ = address; 1229 size_ = request_size; 1230 } 1231 1232 1233 VirtualMemory::~VirtualMemory() { 1234 if (IsReserved()) { 1235 bool result = ReleaseRegion(address(), size()); 1236 DCHECK(result); 1237 USE(result); 1238 } 1239 } 1240 1241 1242 bool VirtualMemory::IsReserved() { 1243 return address_ != NULL; 1244 } 1245 1246 1247 void VirtualMemory::Reset() { 1248 address_ = NULL; 1249 size_ = 0; 1250 } 1251 1252 1253 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 1254 return CommitRegion(address, size, is_executable); 1255 } 1256 1257 1258 bool VirtualMemory::Uncommit(void* address, size_t size) { 1259 DCHECK(IsReserved()); 1260 return UncommitRegion(address, size); 1261 } 1262 1263 1264 bool VirtualMemory::Guard(void* address) { 1265 if (NULL == VirtualAlloc(address, 1266 OS::CommitPageSize(), 1267 MEM_COMMIT, 1268 PAGE_NOACCESS)) { 1269 return false; 1270 } 1271 return true; 1272 } 1273 1274 1275 void* VirtualMemory::ReserveRegion(size_t size) { 1276 return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS); 1277 } 1278 1279 1280 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { 1281 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 1282 if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) { 1283 return false; 1284 } 1285 return true; 1286 } 1287 1288 1289 bool VirtualMemory::UncommitRegion(void* base, size_t size) { 1290 return VirtualFree(base, size, MEM_DECOMMIT) != 0; 1291 } 1292 1293 1294 bool VirtualMemory::ReleaseRegion(void* base, size_t size) { 1295 return VirtualFree(base, 0, MEM_RELEASE) != 0; 1296 } 1297 1298 1299 bool VirtualMemory::HasLazyCommits() { 1300 // TODO(alph): implement for the platform. 1301 return false; 1302 } 1303 1304 1305 // ---------------------------------------------------------------------------- 1306 // Win32 thread support. 1307 1308 // Definition of invalid thread handle and id. 1309 static const HANDLE kNoThread = INVALID_HANDLE_VALUE; 1310 1311 // Entry point for threads. The supplied argument is a pointer to the thread 1312 // object. The entry function dispatches to the run method in the thread 1313 // object. It is important that this function has __stdcall calling 1314 // convention. 1315 static unsigned int __stdcall ThreadEntry(void* arg) { 1316 Thread* thread = reinterpret_cast<Thread*>(arg); 1317 thread->NotifyStartedAndRun(); 1318 return 0; 1319 } 1320 1321 1322 class Thread::PlatformData { 1323 public: 1324 explicit PlatformData(HANDLE thread) : thread_(thread) {} 1325 HANDLE thread_; 1326 unsigned thread_id_; 1327 }; 1328 1329 1330 // Initialize a Win32 thread object. The thread has an invalid thread 1331 // handle until it is started. 1332 1333 Thread::Thread(const Options& options) 1334 : stack_size_(options.stack_size()), 1335 start_semaphore_(NULL) { 1336 data_ = new PlatformData(kNoThread); 1337 set_name(options.name()); 1338 } 1339 1340 1341 void Thread::set_name(const char* name) { 1342 OS::StrNCpy(name_, sizeof(name_), name, strlen(name)); 1343 name_[sizeof(name_) - 1] = '\0'; 1344 } 1345 1346 1347 // Close our own handle for the thread. 1348 Thread::~Thread() { 1349 if (data_->thread_ != kNoThread) CloseHandle(data_->thread_); 1350 delete data_; 1351 } 1352 1353 1354 // Create a new thread. It is important to use _beginthreadex() instead of 1355 // the Win32 function CreateThread(), because the CreateThread() does not 1356 // initialize thread specific structures in the C runtime library. 1357 void Thread::Start() { 1358 data_->thread_ = reinterpret_cast<HANDLE>( 1359 _beginthreadex(NULL, 1360 static_cast<unsigned>(stack_size_), 1361 ThreadEntry, 1362 this, 1363 0, 1364 &data_->thread_id_)); 1365 } 1366 1367 1368 // Wait for thread to terminate. 1369 void Thread::Join() { 1370 if (data_->thread_id_ != GetCurrentThreadId()) { 1371 WaitForSingleObject(data_->thread_, INFINITE); 1372 } 1373 } 1374 1375 1376 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 1377 DWORD result = TlsAlloc(); 1378 DCHECK(result != TLS_OUT_OF_INDEXES); 1379 return static_cast<LocalStorageKey>(result); 1380 } 1381 1382 1383 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 1384 BOOL result = TlsFree(static_cast<DWORD>(key)); 1385 USE(result); 1386 DCHECK(result); 1387 } 1388 1389 1390 void* Thread::GetThreadLocal(LocalStorageKey key) { 1391 return TlsGetValue(static_cast<DWORD>(key)); 1392 } 1393 1394 1395 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 1396 BOOL result = TlsSetValue(static_cast<DWORD>(key), value); 1397 USE(result); 1398 DCHECK(result); 1399 } 1400 1401 } // namespace base 1402 } // namespace v8 1403