blob: 4b0094fb22fe6cc2e8df3c5b9c9fc112f858adb4 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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 Solaris 10 goes here. For the POSIX comaptible
29// parts the implementation is in platform-posix.cc.
30
31#ifdef __sparc
32# error "V8 does not support the SPARC CPU architecture."
33#endif
34
35#include <sys/stack.h> // for stack alignment
36#include <unistd.h> // getpagesize(), usleep()
37#include <sys/mman.h> // mmap()
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000038#include <ucontext.h> // walkstack(), getcontext()
39#include <dlfcn.h> // dladdr
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040#include <pthread.h>
41#include <sched.h> // for sched_yield
42#include <semaphore.h>
43#include <time.h>
44#include <sys/time.h> // gettimeofday(), timeradd()
45#include <errno.h>
46#include <ieeefp.h> // finite()
47#include <signal.h> // sigemptyset(), etc
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000048#include <sys/regset.h>
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000049
50
51#undef MAP_TYPE
52
53#include "v8.h"
54
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000055#include "platform-posix.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000056#include "platform.h"
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +000057#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000058#include "vm-state-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000059
60
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000061// It seems there is a bug in some Solaris distributions (experienced in
62// SunOS 5.10 Generic_141445-09) which make it difficult or impossible to
63// access signbit() despite the availability of other C99 math functions.
64#ifndef signbit
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000065namespace std {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000066// Test sign - usually defined in math.h
67int signbit(double x) {
68 // We need to take care of the special case of both positive and negative
69 // versions of zero.
70 if (x == 0) {
71 return fpclass(x) & FP_NZERO;
72 } else {
73 // This won't detect negative NaN but that should be okay since we don't
74 // assume that behavior.
75 return x < 0;
76 }
77}
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000078} // namespace std
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000079#endif // signbit
80
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000081namespace v8 {
82namespace internal {
83
84
85// 0 is never a valid thread id on Solaris since the main thread is 1 and
86// subsequent have their ids incremented from there
87static const pthread_t kNoThread = (pthread_t) 0;
88
89
90double ceiling(double x) {
91 return ceil(x);
92}
93
94
ricow@chromium.org4f693d62011-07-04 14:01:31 +000095static Mutex* limit_mutex = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000096
97
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000098void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000099 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000100}
101
102
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000103uint64_t OS::CpuFeaturesImpliedByPlatform() {
104 return 0; // Solaris runs on a lot of things.
105}
106
107
108int OS::ActivationFrameAlignment() {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000109 // GCC generates code that requires 16 byte alignment such as movdqa.
110 return Max(STACK_ALIGN, 16);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000111}
112
113
114const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000115 if (std::isnan(time)) return "";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000116 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
117 struct tm* t = localtime(&tv);
118 if (NULL == t) return "";
119 return tzname[0]; // The location of the timezone string on Solaris.
120}
121
122
123double OS::LocalTimeOffset() {
danno@chromium.org72204d52012-10-31 10:02:10 +0000124 tzset();
125 return -static_cast<double>(timezone * msPerSecond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126}
127
128
129// We keep the lowest and highest addresses mapped as a quick way of
130// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000131// and verification). The estimate is conservative, i.e., not all addresses in
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132// 'allocated' space are actually allocated to our heap. The range is
133// [lowest, highest), inclusive on the low and and exclusive on the high end.
134static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
135static void* highest_ever_allocated = reinterpret_cast<void*>(0);
136
137
138static void UpdateAllocatedSpaceLimits(void* address, int size) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000139 ASSERT(limit_mutex != NULL);
140 ScopedLock lock(limit_mutex);
141
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 lowest_ever_allocated = Min(lowest_ever_allocated, address);
143 highest_ever_allocated =
144 Max(highest_ever_allocated,
145 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
146}
147
148
149bool OS::IsOutsideAllocatedSpace(void* address) {
150 return address < lowest_ever_allocated || address >= highest_ever_allocated;
151}
152
153
154size_t OS::AllocateAlignment() {
155 return static_cast<size_t>(getpagesize());
156}
157
158
159void* OS::Allocate(const size_t requested,
160 size_t* allocated,
161 bool is_executable) {
162 const size_t msize = RoundUp(requested, getpagesize());
163 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
164 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
165
166 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000167 LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 return NULL;
169 }
170 *allocated = msize;
171 UpdateAllocatedSpaceLimits(mbase, msize);
172 return mbase;
173}
174
175
176void OS::Free(void* address, const size_t size) {
177 // TODO(1240712): munmap has a return value which is ignored here.
178 int result = munmap(address, size);
179 USE(result);
180 ASSERT(result == 0);
181}
182
183
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184void OS::Sleep(int milliseconds) {
185 useconds_t ms = static_cast<useconds_t>(milliseconds);
186 usleep(1000 * ms);
187}
188
189
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000190int OS::NumberOfCores() {
191 return sysconf(_SC_NPROCESSORS_ONLN);
192}
193
194
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000195void OS::Abort() {
196 // Redirect to std abort to signal abnormal program termination.
197 abort();
198}
199
200
201void OS::DebugBreak() {
202 asm("int $3");
203}
204
205
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000206void OS::DumpBacktrace() {
207 // Currently unsupported.
208}
209
210
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211class PosixMemoryMappedFile : public OS::MemoryMappedFile {
212 public:
213 PosixMemoryMappedFile(FILE* file, void* memory, int size)
214 : file_(file), memory_(memory), size_(size) { }
215 virtual ~PosixMemoryMappedFile();
216 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000217 virtual int size() { return size_; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000218 private:
219 FILE* file_;
220 void* memory_;
221 int size_;
222};
223
224
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000225OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000226 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000227 if (file == NULL) return NULL;
228
229 fseek(file, 0, SEEK_END);
230 int size = ftell(file);
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
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
239 void* initial) {
240 FILE* file = fopen(name, "w+");
241 if (file == NULL) return NULL;
242 int result = fwrite(initial, size, 1, file);
243 if (result < 1) {
244 fclose(file);
245 return NULL;
246 }
247 void* memory =
248 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
249 return new PosixMemoryMappedFile(file, memory, size);
250}
251
252
253PosixMemoryMappedFile::~PosixMemoryMappedFile() {
254 if (memory_) munmap(memory_, size_);
255 fclose(file_);
256}
257
258
259void OS::LogSharedLibraryAddresses() {
260}
261
262
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000263void OS::SignalCodeMovingGC() {
264}
265
266
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000267struct StackWalker {
268 Vector<OS::StackFrame>& frames;
269 int index;
270};
271
272
273static int StackWalkCallback(uintptr_t pc, int signo, void* data) {
274 struct StackWalker* walker = static_cast<struct StackWalker*>(data);
275 Dl_info info;
276
277 int i = walker->index;
278
279 walker->frames[i].address = reinterpret_cast<void*>(pc);
280
281 // Make sure line termination is in place.
282 walker->frames[i].text[OS::kStackWalkMaxTextLen - 1] = '\0';
283
284 Vector<char> text = MutableCStrVector(walker->frames[i].text,
285 OS::kStackWalkMaxTextLen);
286
287 if (dladdr(reinterpret_cast<void*>(pc), &info) == 0) {
288 OS::SNPrintF(text, "[0x%p]", pc);
289 } else if ((info.dli_fname != NULL && info.dli_sname != NULL)) {
290 // We have symbol info.
291 OS::SNPrintF(text, "%s'%s+0x%x", info.dli_fname, info.dli_sname, pc);
292 } else {
293 // No local symbol info.
294 OS::SNPrintF(text,
295 "%s'0x%p [0x%p]",
296 info.dli_fname,
297 pc - reinterpret_cast<uintptr_t>(info.dli_fbase),
298 pc);
299 }
300 walker->index++;
301 return 0;
302}
303
304
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000305int OS::StackWalk(Vector<OS::StackFrame> frames) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000306 ucontext_t ctx;
307 struct StackWalker walker = { frames, 0 };
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000308
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000309 if (getcontext(&ctx) < 0) return kStackWalkError;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000310
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000311 if (!walkcontext(&ctx, StackWalkCallback, &walker)) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000312 return kStackWalkError;
313 }
314
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000315 return walker.index;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000316}
317
318
319// Constants used for mmap.
320static const int kMmapFd = -1;
321static const int kMmapFdOffset = 0;
322
323
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000324VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
325
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000326
327VirtualMemory::VirtualMemory(size_t size)
328 : address_(ReserveRegion(size)), size_(size) { }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000329
330
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000331VirtualMemory::VirtualMemory(size_t size, size_t alignment)
332 : address_(NULL), size_(0) {
333 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
334 size_t request_size = RoundUp(size + alignment,
335 static_cast<intptr_t>(OS::AllocateAlignment()));
336 void* reservation = mmap(OS::GetRandomMmapAddr(),
337 request_size,
338 PROT_NONE,
339 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
340 kMmapFd,
341 kMmapFdOffset);
342 if (reservation == MAP_FAILED) return;
343
344 Address base = static_cast<Address>(reservation);
345 Address aligned_base = RoundUp(base, alignment);
346 ASSERT_LE(base, aligned_base);
347
348 // Unmap extra memory reserved before and after the desired block.
349 if (aligned_base != base) {
350 size_t prefix_size = static_cast<size_t>(aligned_base - base);
351 OS::Free(base, prefix_size);
352 request_size -= prefix_size;
353 }
354
355 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
356 ASSERT_LE(aligned_size, request_size);
357
358 if (aligned_size != request_size) {
359 size_t suffix_size = request_size - aligned_size;
360 OS::Free(aligned_base + aligned_size, suffix_size);
361 request_size -= suffix_size;
362 }
363
364 ASSERT(aligned_size == request_size);
365
366 address_ = static_cast<void*>(aligned_base);
367 size_ = aligned_size;
368}
369
370
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000371VirtualMemory::~VirtualMemory() {
372 if (IsReserved()) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000373 bool result = ReleaseRegion(address(), size());
374 ASSERT(result);
375 USE(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000376 }
377}
378
379
380bool VirtualMemory::IsReserved() {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000381 return address_ != NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000382}
383
384
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000385void VirtualMemory::Reset() {
386 address_ = NULL;
387 size_ = 0;
388}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000389
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000390
391bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
392 return CommitRegion(address, size, is_executable);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000393}
394
395
396bool VirtualMemory::Uncommit(void* address, size_t size) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000397 return UncommitRegion(address, size);
398}
399
400
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000401bool VirtualMemory::Guard(void* address) {
402 OS::Guard(address, OS::CommitPageSize());
403 return true;
404}
405
406
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000407void* VirtualMemory::ReserveRegion(size_t size) {
408 void* result = mmap(OS::GetRandomMmapAddr(),
409 size,
410 PROT_NONE,
411 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
412 kMmapFd,
413 kMmapFdOffset);
414
415 if (result == MAP_FAILED) return NULL;
416
417 return result;
418}
419
420
421bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
422 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
423 if (MAP_FAILED == mmap(base,
424 size,
425 prot,
426 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
427 kMmapFd,
428 kMmapFdOffset)) {
429 return false;
430 }
431
432 UpdateAllocatedSpaceLimits(base, size);
433 return true;
434}
435
436
437bool VirtualMemory::UncommitRegion(void* base, size_t size) {
438 return mmap(base,
439 size,
440 PROT_NONE,
441 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
442 kMmapFd,
443 kMmapFdOffset) != MAP_FAILED;
444}
445
446
447bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
448 return munmap(base, size) == 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000449}
450
451
danno@chromium.org72204d52012-10-31 10:02:10 +0000452bool VirtualMemory::HasLazyCommits() {
453 // TODO(alph): implement for the platform.
454 return false;
455}
456
457
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000458class Thread::PlatformData : public Malloced {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000459 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000460 PlatformData() : thread_(kNoThread) { }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000461
462 pthread_t thread_; // Thread handle for pthread.
463};
464
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000466Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000467 : data_(new PlatformData()),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000468 stack_size_(options.stack_size()),
469 start_semaphore_(NULL) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000470 set_name(options.name());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000471}
472
473
474Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000475 delete data_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000476}
477
478
479static void* ThreadEntry(void* arg) {
480 Thread* thread = reinterpret_cast<Thread*>(arg);
481 // This is also initialized by the first argument to pthread_create() but we
482 // don't know which thread will run first (the original thread or the new
483 // one) so we initialize it here too.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000484 thread->data()->thread_ = pthread_self();
485 ASSERT(thread->data()->thread_ != kNoThread);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000486 thread->NotifyStartedAndRun();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000487 return NULL;
488}
489
490
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000491void Thread::set_name(const char* name) {
492 strncpy(name_, name, sizeof(name_));
493 name_[sizeof(name_) - 1] = '\0';
494}
495
496
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000497void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 pthread_attr_t attr;
499 if (stack_size_ > 0) {
500 pthread_attr_init(&attr);
501 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000503 pthread_create(&data_->thread_, NULL, ThreadEntry, this);
504 ASSERT(data_->thread_ != kNoThread);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000505}
506
507
508void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000509 pthread_join(data_->thread_, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000510}
511
512
513Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
514 pthread_key_t key;
515 int result = pthread_key_create(&key, NULL);
516 USE(result);
517 ASSERT(result == 0);
518 return static_cast<LocalStorageKey>(key);
519}
520
521
522void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
523 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
524 int result = pthread_key_delete(pthread_key);
525 USE(result);
526 ASSERT(result == 0);
527}
528
529
530void* Thread::GetThreadLocal(LocalStorageKey key) {
531 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
532 return pthread_getspecific(pthread_key);
533}
534
535
536void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
537 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
538 pthread_setspecific(pthread_key, value);
539}
540
541
542void Thread::YieldCPU() {
543 sched_yield();
544}
545
546
547class SolarisMutex : public Mutex {
548 public:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000549 SolarisMutex() {
550 pthread_mutexattr_t attr;
551 pthread_mutexattr_init(&attr);
552 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
553 pthread_mutex_init(&mutex_, &attr);
554 }
555
556 ~SolarisMutex() { pthread_mutex_destroy(&mutex_); }
557
558 int Lock() { return pthread_mutex_lock(&mutex_); }
559
560 int Unlock() { return pthread_mutex_unlock(&mutex_); }
561
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000562 virtual bool TryLock() {
563 int result = pthread_mutex_trylock(&mutex_);
564 // Return false if the lock is busy and locking failed.
565 if (result == EBUSY) {
566 return false;
567 }
568 ASSERT(result == 0); // Verify no other errors.
569 return true;
570 }
571
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572 private:
573 pthread_mutex_t mutex_;
574};
575
576
577Mutex* OS::CreateMutex() {
578 return new SolarisMutex();
579}
580
581
582class SolarisSemaphore : public Semaphore {
583 public:
584 explicit SolarisSemaphore(int count) { sem_init(&sem_, 0, count); }
585 virtual ~SolarisSemaphore() { sem_destroy(&sem_); }
586
587 virtual void Wait();
588 virtual bool Wait(int timeout);
589 virtual void Signal() { sem_post(&sem_); }
590 private:
591 sem_t sem_;
592};
593
594
595void SolarisSemaphore::Wait() {
596 while (true) {
597 int result = sem_wait(&sem_);
598 if (result == 0) return; // Successfully got semaphore.
599 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
600 }
601}
602
603
604#ifndef TIMEVAL_TO_TIMESPEC
605#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
606 (ts)->tv_sec = (tv)->tv_sec; \
607 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
608} while (false)
609#endif
610
611
612#ifndef timeradd
613#define timeradd(a, b, result) \
614 do { \
615 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
616 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
617 if ((result)->tv_usec >= 1000000) { \
618 ++(result)->tv_sec; \
619 (result)->tv_usec -= 1000000; \
620 } \
621 } while (0)
622#endif
623
624
625bool SolarisSemaphore::Wait(int timeout) {
626 const long kOneSecondMicros = 1000000; // NOLINT
627
628 // Split timeout into second and nanosecond parts.
629 struct timeval delta;
630 delta.tv_usec = timeout % kOneSecondMicros;
631 delta.tv_sec = timeout / kOneSecondMicros;
632
633 struct timeval current_time;
634 // Get the current time.
635 if (gettimeofday(&current_time, NULL) == -1) {
636 return false;
637 }
638
639 // Calculate time for end of timeout.
640 struct timeval end_time;
641 timeradd(&current_time, &delta, &end_time);
642
643 struct timespec ts;
644 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
645 // Wait for semaphore signalled or timeout.
646 while (true) {
647 int result = sem_timedwait(&sem_, &ts);
648 if (result == 0) return true; // Successfully got semaphore.
649 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
650 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
651 }
652}
653
654
655Semaphore* OS::CreateSemaphore(int count) {
656 return new SolarisSemaphore(count);
657}
658
659
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000660void OS::SetUp() {
661 // Seed the random number generator.
662 // Convert the current time to a 64-bit integer first, before converting it
663 // to an unsigned. Going directly will cause an overflow and the seed to be
664 // set to all ones. The seed will be identical for different instances that
665 // call this setup code within the same millisecond.
666 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
667 srandom(static_cast<unsigned int>(seed));
668 limit_mutex = CreateMutex();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000669}
670
671
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000672void OS::TearDown() {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000673 delete limit_mutex;
674}
675
676
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000677} } // namespace v8::internal