blob: bda9f923fd68516dd4fea9d83d115958f62e0ae2 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Platform specific code for Cygwin goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
30
31#include <errno.h>
32#include <pthread.h>
33#include <semaphore.h>
34#include <stdarg.h>
35#include <strings.h> // index
36#include <sys/time.h>
37#include <sys/mman.h> // mmap & munmap
38#include <unistd.h> // sysconf
39
40#undef MAP_TYPE
41
42#include "v8.h"
43
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000044#include "platform-posix.h"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000045#include "platform.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000046#include "simulator.h"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000047#include "v8threads.h"
48#include "vm-state-inl.h"
49#include "win32-headers.h"
50
51namespace v8 {
52namespace internal {
53
54// 0 is never a valid thread id
55static const pthread_t kNoThread = (pthread_t) 0;
56
57
58double ceiling(double x) {
59 return ceil(x);
60}
61
62
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000063static Mutex* limit_mutex = NULL;
64
65
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000066void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000067 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000068}
69
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000070uint64_t OS::CpuFeaturesImpliedByPlatform() {
71 return 0; // Nothing special about Cygwin.
72}
73
74
75int OS::ActivationFrameAlignment() {
76 // With gcc 4.4 the tree vectorization optimizer can generate code
77 // that requires 16 byte alignment such as movdqa on x86.
78 return 16;
79}
80
81
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000082const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000083 if (std::isnan(time)) return "";
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000084 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
85 struct tm* t = localtime(&tv);
86 if (NULL == t) return "";
87 return tzname[0]; // The location of the timezone string on Cygwin.
88}
89
90
91double OS::LocalTimeOffset() {
92 // On Cygwin, struct tm does not contain a tm_gmtoff field.
93 time_t utc = time(NULL);
94 ASSERT(utc != -1);
95 struct tm* loc = localtime(&utc);
96 ASSERT(loc != NULL);
97 // time - localtime includes any daylight savings offset, so subtract it.
98 return static_cast<double>((mktime(loc) - utc) * msPerSecond -
99 (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
100}
101
102
103// We keep the lowest and highest addresses mapped as a quick way of
104// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000105// and verification). The estimate is conservative, i.e., not all addresses in
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000106// 'allocated' space are actually allocated to our heap. The range is
107// [lowest, highest), inclusive on the low and and exclusive on the high end.
108static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
109static void* highest_ever_allocated = reinterpret_cast<void*>(0);
110
111
112static void UpdateAllocatedSpaceLimits(void* address, int size) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000113 ASSERT(limit_mutex != NULL);
114 ScopedLock lock(limit_mutex);
115
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000116 lowest_ever_allocated = Min(lowest_ever_allocated, address);
117 highest_ever_allocated =
118 Max(highest_ever_allocated,
119 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
120}
121
122
123bool OS::IsOutsideAllocatedSpace(void* address) {
124 return address < lowest_ever_allocated || address >= highest_ever_allocated;
125}
126
127
128size_t OS::AllocateAlignment() {
129 return sysconf(_SC_PAGESIZE);
130}
131
132
133void* OS::Allocate(const size_t requested,
134 size_t* allocated,
135 bool is_executable) {
136 const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
137 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
138 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
139 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000140 LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000141 return NULL;
142 }
143 *allocated = msize;
144 UpdateAllocatedSpaceLimits(mbase, msize);
145 return mbase;
146}
147
148
149void OS::Free(void* address, const size_t size) {
150 // TODO(1240712): munmap has a return value which is ignored here.
151 int result = munmap(address, size);
152 USE(result);
153 ASSERT(result == 0);
154}
155
156
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000157void OS::ProtectCode(void* address, const size_t size) {
158 DWORD old_protect;
159 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
160}
161
162
163void OS::Guard(void* address, const size_t size) {
164 DWORD oldprotect;
165 VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
166}
167
168
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000169void OS::Sleep(int milliseconds) {
170 unsigned int ms = static_cast<unsigned int>(milliseconds);
171 usleep(1000 * ms);
172}
173
174
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000175int OS::NumberOfCores() {
176 return sysconf(_SC_NPROCESSORS_ONLN);
177}
178
179
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000180void OS::Abort() {
181 // Redirect to std abort to signal abnormal program termination.
182 abort();
183}
184
185
186void OS::DebugBreak() {
187 asm("int $3");
188}
189
190
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000191void OS::DumpBacktrace() {
192 // Currently unsupported.
193}
194
195
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000196class PosixMemoryMappedFile : public OS::MemoryMappedFile {
197 public:
198 PosixMemoryMappedFile(FILE* file, void* memory, int size)
199 : file_(file), memory_(memory), size_(size) { }
200 virtual ~PosixMemoryMappedFile();
201 virtual void* memory() { return memory_; }
202 virtual int size() { return size_; }
203 private:
204 FILE* file_;
205 void* memory_;
206 int size_;
207};
208
209
210OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
211 FILE* file = fopen(name, "r+");
212 if (file == NULL) return NULL;
213
214 fseek(file, 0, SEEK_END);
215 int size = ftell(file);
216
217 void* memory =
218 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
219 return new PosixMemoryMappedFile(file, memory, size);
220}
221
222
223OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
224 void* initial) {
225 FILE* file = fopen(name, "w+");
226 if (file == NULL) return NULL;
227 int result = fwrite(initial, size, 1, file);
228 if (result < 1) {
229 fclose(file);
230 return NULL;
231 }
232 void* memory =
233 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
234 return new PosixMemoryMappedFile(file, memory, size);
235}
236
237
238PosixMemoryMappedFile::~PosixMemoryMappedFile() {
239 if (memory_) munmap(memory_, size_);
240 fclose(file_);
241}
242
243
244void OS::LogSharedLibraryAddresses() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000245 // This function assumes that the layout of the file is as follows:
246 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
247 // If we encounter an unexpected situation we abort scanning further entries.
248 FILE* fp = fopen("/proc/self/maps", "r");
249 if (fp == NULL) return;
250
251 // Allocate enough room to be able to store a full file name.
252 const int kLibNameLen = FILENAME_MAX + 1;
253 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000255 i::Isolate* isolate = ISOLATE;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000256 // This loop will terminate once the scanning hits an EOF.
257 while (true) {
258 uintptr_t start, end;
259 char attr_r, attr_w, attr_x, attr_p;
260 // Parse the addresses and permission bits at the beginning of the line.
261 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
262 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
263
264 int c;
265 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
266 // Found a read-only executable entry. Skip characters until we reach
267 // the beginning of the filename or the end of the line.
268 do {
269 c = getc(fp);
270 } while ((c != EOF) && (c != '\n') && (c != '/'));
271 if (c == EOF) break; // EOF: Was unexpected, just exit.
272
273 // Process the filename if found.
274 if (c == '/') {
275 ungetc(c, fp); // Push the '/' back into the stream to be read below.
276
277 // Read to the end of the line. Exit if the read fails.
278 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
279
280 // Drop the newline character read by fgets. We do not need to check
281 // for a zero-length string because we know that we at least read the
282 // '/' character.
283 lib_name[strlen(lib_name) - 1] = '\0';
284 } else {
285 // No library name found, just record the raw address range.
286 snprintf(lib_name, kLibNameLen,
287 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
288 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000289 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000290 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000291 // Entry not describing executable data. Skip to end of line to set up
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000292 // reading the next entry.
293 do {
294 c = getc(fp);
295 } while ((c != EOF) && (c != '\n'));
296 if (c == EOF) break;
297 }
298 }
299 free(lib_name);
300 fclose(fp);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000301}
302
303
304void OS::SignalCodeMovingGC() {
305 // Nothing to do on Cygwin.
306}
307
308
309int OS::StackWalk(Vector<OS::StackFrame> frames) {
310 // Not supported on Cygwin.
311 return 0;
312}
313
314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000315// The VirtualMemory implementation is taken from platform-win32.cc.
316// The mmap-based virtual memory implementation as it is used on most posix
317// platforms does not work well because Cygwin does not support MAP_FIXED.
318// This causes VirtualMemory::Commit to not always commit the memory region
319// specified.
320
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000321static void* GetRandomAddr() {
322 Isolate* isolate = Isolate::UncheckedCurrent();
323 // Note that the current isolate isn't set up in a call path via
324 // CpuFeatures::Probe. We don't care about randomization in this case because
325 // the code page is immediately freed.
326 if (isolate != NULL) {
327 // The address range used to randomize RWX allocations in OS::Allocate
328 // Try not to map pages into the default range that windows loads DLLs
329 // Use a multiple of 64k to prevent committing unused memory.
330 // Note: This does not guarantee RWX regions will be within the
331 // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
332#ifdef V8_HOST_ARCH_64_BIT
333 static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
334 static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
335#else
336 static const intptr_t kAllocationRandomAddressMin = 0x04000000;
337 static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
338#endif
339 uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits)
340 | kAllocationRandomAddressMin;
341 address &= kAllocationRandomAddressMax;
342 return reinterpret_cast<void *>(address);
343 }
344 return NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000345}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000346
347
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000348static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
349 LPVOID base = NULL;
350
351 if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
352 // For exectutable pages try and randomize the allocation address
353 for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
354 base = VirtualAlloc(GetRandomAddr(), size, action, protection);
355 }
356 }
357
358 // After three attempts give up and let the OS find an address to use.
359 if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
360
361 return base;
362}
363
364
365VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
366
367
368VirtualMemory::VirtualMemory(size_t size)
369 : address_(ReserveRegion(size)), size_(size) { }
370
371
372VirtualMemory::VirtualMemory(size_t size, size_t alignment)
373 : address_(NULL), size_(0) {
374 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
375 size_t request_size = RoundUp(size + alignment,
376 static_cast<intptr_t>(OS::AllocateAlignment()));
377 void* address = ReserveRegion(request_size);
378 if (address == NULL) return;
379 Address base = RoundUp(static_cast<Address>(address), alignment);
380 // Try reducing the size by freeing and then reallocating a specific area.
381 bool result = ReleaseRegion(address, request_size);
382 USE(result);
383 ASSERT(result);
384 address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
385 if (address != NULL) {
386 request_size = size;
387 ASSERT(base == static_cast<Address>(address));
388 } else {
389 // Resizing failed, just go with a bigger area.
390 address = ReserveRegion(request_size);
391 if (address == NULL) return;
392 }
393 address_ = address;
394 size_ = request_size;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000395}
396
397
398VirtualMemory::~VirtualMemory() {
399 if (IsReserved()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000400 bool result = ReleaseRegion(address_, size_);
401 ASSERT(result);
402 USE(result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000403 }
404}
405
406
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000407bool VirtualMemory::IsReserved() {
408 return address_ != NULL;
409}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000410
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000411
412void VirtualMemory::Reset() {
413 address_ = NULL;
414 size_ = 0;
415}
416
417
418bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
419 return CommitRegion(address, size, is_executable);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000420}
421
422
423bool VirtualMemory::Uncommit(void* address, size_t size) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000424 ASSERT(IsReserved());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000425 return UncommitRegion(address, size);
426}
427
428
429void* VirtualMemory::ReserveRegion(size_t size) {
430 return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
431}
432
433
434bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
435 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
436 if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
437 return false;
438 }
439
440 UpdateAllocatedSpaceLimits(base, static_cast<int>(size));
441 return true;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000442}
443
444
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000445bool VirtualMemory::Guard(void* address) {
446 if (NULL == VirtualAlloc(address,
447 OS::CommitPageSize(),
448 MEM_COMMIT,
449 PAGE_READONLY | PAGE_GUARD)) {
450 return false;
451 }
452 return true;
453}
454
455
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000456bool VirtualMemory::UncommitRegion(void* base, size_t size) {
457 return VirtualFree(base, size, MEM_DECOMMIT) != 0;
458}
459
460
461bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
462 return VirtualFree(base, 0, MEM_RELEASE) != 0;
463}
464
465
danno@chromium.org72204d52012-10-31 10:02:10 +0000466bool VirtualMemory::HasLazyCommits() {
467 // TODO(alph): implement for the platform.
468 return false;
469}
470
471
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000472class Thread::PlatformData : public Malloced {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000473 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000474 PlatformData() : thread_(kNoThread) {}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000475 pthread_t thread_; // Thread handle for pthread.
476};
477
478
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000479Thread::Thread(const Options& options)
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000480 : data_(new PlatformData()),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000481 stack_size_(options.stack_size()),
482 start_semaphore_(NULL) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000483 set_name(options.name());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000484}
485
486
487Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000488 delete data_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000489}
490
491
492static void* ThreadEntry(void* arg) {
493 Thread* thread = reinterpret_cast<Thread*>(arg);
494 // This is also initialized by the first argument to pthread_create() but we
495 // don't know which thread will run first (the original thread or the new
496 // one) so we initialize it here too.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000497 thread->data()->thread_ = pthread_self();
498 ASSERT(thread->data()->thread_ != kNoThread);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000499 thread->NotifyStartedAndRun();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000500 return NULL;
501}
502
503
504void Thread::set_name(const char* name) {
505 strncpy(name_, name, sizeof(name_));
506 name_[sizeof(name_) - 1] = '\0';
507}
508
509
510void Thread::Start() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000511 pthread_attr_t* attr_ptr = NULL;
512 pthread_attr_t attr;
513 if (stack_size_ > 0) {
514 pthread_attr_init(&attr);
515 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
516 attr_ptr = &attr;
517 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000518 pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
519 ASSERT(data_->thread_ != kNoThread);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000520}
521
522
523void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000524 pthread_join(data_->thread_, NULL);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000525}
526
527
528static inline Thread::LocalStorageKey PthreadKeyToLocalKey(
529 pthread_key_t pthread_key) {
530 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
531 // because pthread_key_t is a pointer type on Cygwin. This will probably not
532 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
533 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
534 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
535 return static_cast<Thread::LocalStorageKey>(ptr_key);
536}
537
538
539static inline pthread_key_t LocalKeyToPthreadKey(
540 Thread::LocalStorageKey local_key) {
541 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
542 intptr_t ptr_key = static_cast<intptr_t>(local_key);
543 return reinterpret_cast<pthread_key_t>(ptr_key);
544}
545
546
547Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
548 pthread_key_t key;
549 int result = pthread_key_create(&key, NULL);
550 USE(result);
551 ASSERT(result == 0);
552 return PthreadKeyToLocalKey(key);
553}
554
555
556void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
557 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
558 int result = pthread_key_delete(pthread_key);
559 USE(result);
560 ASSERT(result == 0);
561}
562
563
564void* Thread::GetThreadLocal(LocalStorageKey key) {
565 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
566 return pthread_getspecific(pthread_key);
567}
568
569
570void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
571 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
572 pthread_setspecific(pthread_key, value);
573}
574
575
576void Thread::YieldCPU() {
577 sched_yield();
578}
579
580
581class CygwinMutex : public Mutex {
582 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000583 CygwinMutex() {
584 pthread_mutexattr_t attrs;
585 memset(&attrs, 0, sizeof(attrs));
586
587 int result = pthread_mutexattr_init(&attrs);
588 ASSERT(result == 0);
589 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
590 ASSERT(result == 0);
591 result = pthread_mutex_init(&mutex_, &attrs);
592 ASSERT(result == 0);
593 }
594
595 virtual ~CygwinMutex() { pthread_mutex_destroy(&mutex_); }
596
597 virtual int Lock() {
598 int result = pthread_mutex_lock(&mutex_);
599 return result;
600 }
601
602 virtual int Unlock() {
603 int result = pthread_mutex_unlock(&mutex_);
604 return result;
605 }
606
607 virtual bool TryLock() {
608 int result = pthread_mutex_trylock(&mutex_);
609 // Return false if the lock is busy and locking failed.
610 if (result == EBUSY) {
611 return false;
612 }
613 ASSERT(result == 0); // Verify no other errors.
614 return true;
615 }
616
617 private:
618 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
619};
620
621
622Mutex* OS::CreateMutex() {
623 return new CygwinMutex();
624}
625
626
627class CygwinSemaphore : public Semaphore {
628 public:
629 explicit CygwinSemaphore(int count) { sem_init(&sem_, 0, count); }
630 virtual ~CygwinSemaphore() { sem_destroy(&sem_); }
631
632 virtual void Wait();
633 virtual bool Wait(int timeout);
634 virtual void Signal() { sem_post(&sem_); }
635 private:
636 sem_t sem_;
637};
638
639
640void CygwinSemaphore::Wait() {
641 while (true) {
642 int result = sem_wait(&sem_);
643 if (result == 0) return; // Successfully got semaphore.
644 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
645 }
646}
647
648
649#ifndef TIMEVAL_TO_TIMESPEC
650#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
651 (ts)->tv_sec = (tv)->tv_sec; \
652 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
653} while (false)
654#endif
655
656
657bool CygwinSemaphore::Wait(int timeout) {
658 const long kOneSecondMicros = 1000000; // NOLINT
659
660 // Split timeout into second and nanosecond parts.
661 struct timeval delta;
662 delta.tv_usec = timeout % kOneSecondMicros;
663 delta.tv_sec = timeout / kOneSecondMicros;
664
665 struct timeval current_time;
666 // Get the current time.
667 if (gettimeofday(&current_time, NULL) == -1) {
668 return false;
669 }
670
671 // Calculate time for end of timeout.
672 struct timeval end_time;
673 timeradd(&current_time, &delta, &end_time);
674
675 struct timespec ts;
676 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
677 // Wait for semaphore signalled or timeout.
678 while (true) {
679 int result = sem_timedwait(&sem_, &ts);
680 if (result == 0) return true; // Successfully got semaphore.
681 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
682 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
683 }
684}
685
686
687Semaphore* OS::CreateSemaphore(int count) {
688 return new CygwinSemaphore(count);
689}
690
691
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000692void OS::SetUp() {
693 // Seed the random number generator.
694 // Convert the current time to a 64-bit integer first, before converting it
695 // to an unsigned. Going directly can cause an overflow and the seed to be
696 // set to all ones. The seed will be identical for different instances that
697 // call this setup code within the same millisecond.
698 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
699 srandom(static_cast<unsigned int>(seed));
700 limit_mutex = CreateMutex();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000701}
702
703
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000704void OS::TearDown() {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000705 delete limit_mutex;
706}
707
708
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000709} } // namespace v8::internal