Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(444)

Side by Side Diff: src/platform-solaris.cc

Issue 545125: Initial Solaris support (Closed)
Patch Set: Fixed comments, simplified platform-solaris Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/platform-posix.cc ('k') | test/cctest/test-compiler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // 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()
38 #include <execinfo.h> // backtrace(), backtrace_symbols()
39 #include <pthread.h>
40 #include <sched.h> // for sched_yield
41 #include <semaphore.h>
42 #include <time.h>
43 #include <sys/time.h> // gettimeofday(), timeradd()
44 #include <errno.h>
45 #include <ieeefp.h> // finite()
46 #include <signal.h> // sigemptyset(), etc
47
48
49 #undef MAP_TYPE
50
51 #include "v8.h"
52
53 #include "platform.h"
54
55
56 namespace v8 {
57 namespace internal {
58
59
60 // 0 is never a valid thread id on Solaris since the main thread is 1 and
61 // subsequent have their ids incremented from there
62 static const pthread_t kNoThread = (pthread_t) 0;
63
64
65 double ceiling(double x) {
66 return ceil(x);
67 }
68
69
70 void OS::Setup() {
71 // Seed the random number generator.
72 // Convert the current time to a 64-bit integer first, before converting it
73 // to an unsigned. Going directly will cause an overflow and the seed to be
74 // set to all ones. The seed will be identical for different instances that
75 // call this setup code within the same millisecond.
76 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
77 srandom(static_cast<unsigned int>(seed));
78 }
79
80
81 uint64_t OS::CpuFeaturesImpliedByPlatform() {
82 return 0; // Solaris runs on a lot of things.
83 }
84
85
86 int OS::ActivationFrameAlignment() {
87 return STACK_ALIGN;
88 }
89
90
91 const char* OS::LocalTimezone(double time) {
92 if (isnan(time)) return "";
93 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
94 struct tm* t = localtime(&tv);
95 if (NULL == t) return "";
96 return tzname[0]; // The location of the timezone string on Solaris.
97 }
98
99
100 double OS::LocalTimeOffset() {
101 // On Solaris, struct tm does not contain a tm_gmtoff field.
102 time_t utc = time(NULL);
103 ASSERT(utc != -1);
104 struct tm* loc = localtime(&utc);
105 ASSERT(loc != NULL);
106 return static_cast<double>((mktime(loc) - utc) * msPerSecond);
107 }
108
109
110 // We keep the lowest and highest addresses mapped as a quick way of
111 // determining that pointers are outside the heap (used mostly in assertions
112 // and verification). The estimate is conservative, ie, not all addresses in
113 // 'allocated' space are actually allocated to our heap. The range is
114 // [lowest, highest), inclusive on the low and and exclusive on the high end.
115 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
116 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
117
118
119 static void UpdateAllocatedSpaceLimits(void* address, int size) {
120 lowest_ever_allocated = Min(lowest_ever_allocated, address);
121 highest_ever_allocated =
122 Max(highest_ever_allocated,
123 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
124 }
125
126
127 bool OS::IsOutsideAllocatedSpace(void* address) {
128 return address < lowest_ever_allocated || address >= highest_ever_allocated;
129 }
130
131
132 size_t OS::AllocateAlignment() {
133 return static_cast<size_t>(getpagesize());
134 }
135
136
137 void* OS::Allocate(const size_t requested,
138 size_t* allocated,
139 bool is_executable) {
140 const size_t msize = RoundUp(requested, getpagesize());
141 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
142 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
143
144 if (mbase == MAP_FAILED) {
145 LOG(StringEvent("OS::Allocate", "mmap failed"));
146 return NULL;
147 }
148 *allocated = msize;
149 UpdateAllocatedSpaceLimits(mbase, msize);
150 return mbase;
151 }
152
153
154 void OS::Free(void* address, const size_t size) {
155 // TODO(1240712): munmap has a return value which is ignored here.
156 int result = munmap(address, size);
157 USE(result);
158 ASSERT(result == 0);
159 }
160
161
162 #ifdef ENABLE_HEAP_PROTECTION
163
164 void OS::Protect(void* address, size_t size) {
165 // TODO(1240712): mprotect has a return value which is ignored here.
166 mprotect(address, size, PROT_READ);
167 }
168
169
170 void OS::Unprotect(void* address, size_t size, bool is_executable) {
171 // TODO(1240712): mprotect has a return value which is ignored here.
172 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
173 mprotect(address, size, prot);
174 }
175
176 #endif
177
178
179 void OS::Sleep(int milliseconds) {
180 useconds_t ms = static_cast<useconds_t>(milliseconds);
181 usleep(1000 * ms);
182 }
183
184
185 void OS::Abort() {
186 // Redirect to std abort to signal abnormal program termination.
187 abort();
188 }
189
190
191 void OS::DebugBreak() {
192 asm("int $3");
193 }
194
195
196 class 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 private:
203 FILE* file_;
204 void* memory_;
205 int size_;
206 };
207
208
209 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
210 void* initial) {
211 FILE* file = fopen(name, "w+");
212 if (file == NULL) return NULL;
213 int result = fwrite(initial, size, 1, file);
214 if (result < 1) {
215 fclose(file);
216 return NULL;
217 }
218 void* memory =
219 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
220 return new PosixMemoryMappedFile(file, memory, size);
221 }
222
223
224 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
225 if (memory_) munmap(memory_, size_);
226 fclose(file_);
227 }
228
229
230 void OS::LogSharedLibraryAddresses() {
231 }
232
233
234 int OS::StackWalk(Vector<OS::StackFrame> frames) {
235 int frames_size = frames.length();
236 void** addresses = NewArray<void*>(frames_size);
237
238 int frames_count = backtrace(addresses, frames_size);
239
240 char** symbols;
241 symbols = backtrace_symbols(addresses, frames_count);
242 if (symbols == NULL) {
243 DeleteArray(addresses);
244 return kStackWalkError;
245 }
246
247 for (int i = 0; i < frames_count; i++) {
248 frames[i].address = addresses[i];
249 // Format a text representation of the frame based on the information
250 // available.
251 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
252 "%s",
253 symbols[i]);
254 // Make sure line termination is in place.
255 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
256 }
257
258 DeleteArray(addresses);
259 free(symbols);
260
261 return frames_count;
262 }
263
264
265 // Constants used for mmap.
266 static const int kMmapFd = -1;
267 static const int kMmapFdOffset = 0;
268
269
270 VirtualMemory::VirtualMemory(size_t size) {
271 address_ = mmap(NULL, size, PROT_NONE,
272 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
273 kMmapFd, kMmapFdOffset);
274 size_ = size;
275 }
276
277
278 VirtualMemory::~VirtualMemory() {
279 if (IsReserved()) {
280 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
281 }
282 }
283
284
285 bool VirtualMemory::IsReserved() {
286 return address_ != MAP_FAILED;
287 }
288
289
290 bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
291 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
292 if (MAP_FAILED == mmap(address, size, prot,
293 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
294 kMmapFd, kMmapFdOffset)) {
295 return false;
296 }
297
298 UpdateAllocatedSpaceLimits(address, size);
299 return true;
300 }
301
302
303 bool VirtualMemory::Uncommit(void* address, size_t size) {
304 return mmap(address, size, PROT_NONE,
305 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
306 kMmapFd, kMmapFdOffset) != MAP_FAILED;
307 }
308
309
310 class ThreadHandle::PlatformData : public Malloced {
311 public:
312 explicit PlatformData(ThreadHandle::Kind kind) {
313 Initialize(kind);
314 }
315
316 void Initialize(ThreadHandle::Kind kind) {
317 switch (kind) {
318 case ThreadHandle::SELF: thread_ = pthread_self(); break;
319 case ThreadHandle::INVALID: thread_ = kNoThread; break;
320 }
321 }
322
323 pthread_t thread_; // Thread handle for pthread.
324 };
325
326
327 ThreadHandle::ThreadHandle(Kind kind) {
328 data_ = new PlatformData(kind);
329 }
330
331
332 void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
333 data_->Initialize(kind);
334 }
335
336
337 ThreadHandle::~ThreadHandle() {
338 delete data_;
339 }
340
341
342 bool ThreadHandle::IsSelf() const {
343 return pthread_equal(data_->thread_, pthread_self());
344 }
345
346
347 bool ThreadHandle::IsValid() const {
348 return data_->thread_ != kNoThread;
349 }
350
351
352 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
353 }
354
355
356 Thread::~Thread() {
357 }
358
359
360 static void* ThreadEntry(void* arg) {
361 Thread* thread = reinterpret_cast<Thread*>(arg);
362 // This is also initialized by the first argument to pthread_create() but we
363 // don't know which thread will run first (the original thread or the new
364 // one) so we initialize it here too.
365 thread->thread_handle_data()->thread_ = pthread_self();
366 ASSERT(thread->IsValid());
367 thread->Run();
368 return NULL;
369 }
370
371
372 void Thread::Start() {
373 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
374 ASSERT(IsValid());
375 }
376
377
378 void Thread::Join() {
379 pthread_join(thread_handle_data()->thread_, NULL);
380 }
381
382
383 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
384 pthread_key_t key;
385 int result = pthread_key_create(&key, NULL);
386 USE(result);
387 ASSERT(result == 0);
388 return static_cast<LocalStorageKey>(key);
389 }
390
391
392 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
393 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
394 int result = pthread_key_delete(pthread_key);
395 USE(result);
396 ASSERT(result == 0);
397 }
398
399
400 void* Thread::GetThreadLocal(LocalStorageKey key) {
401 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
402 return pthread_getspecific(pthread_key);
403 }
404
405
406 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
407 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
408 pthread_setspecific(pthread_key, value);
409 }
410
411
412 void Thread::YieldCPU() {
413 sched_yield();
414 }
415
416
417 class SolarisMutex : public Mutex {
418 public:
419
420 SolarisMutex() {
421 pthread_mutexattr_t attr;
422 pthread_mutexattr_init(&attr);
423 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
424 pthread_mutex_init(&mutex_, &attr);
425 }
426
427 ~SolarisMutex() { pthread_mutex_destroy(&mutex_); }
428
429 int Lock() { return pthread_mutex_lock(&mutex_); }
430
431 int Unlock() { return pthread_mutex_unlock(&mutex_); }
432
433 private:
434 pthread_mutex_t mutex_;
435 };
436
437
438 Mutex* OS::CreateMutex() {
439 return new SolarisMutex();
440 }
441
442
443 class SolarisSemaphore : public Semaphore {
444 public:
445 explicit SolarisSemaphore(int count) { sem_init(&sem_, 0, count); }
446 virtual ~SolarisSemaphore() { sem_destroy(&sem_); }
447
448 virtual void Wait();
449 virtual bool Wait(int timeout);
450 virtual void Signal() { sem_post(&sem_); }
451 private:
452 sem_t sem_;
453 };
454
455
456 void SolarisSemaphore::Wait() {
457 while (true) {
458 int result = sem_wait(&sem_);
459 if (result == 0) return; // Successfully got semaphore.
460 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
461 }
462 }
463
464
465 #ifndef TIMEVAL_TO_TIMESPEC
466 #define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
467 (ts)->tv_sec = (tv)->tv_sec; \
468 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
469 } while (false)
470 #endif
471
472
473 #ifndef timeradd
474 #define timeradd(a, b, result) \
475 do { \
476 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
477 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
478 if ((result)->tv_usec >= 1000000) { \
479 ++(result)->tv_sec; \
480 (result)->tv_usec -= 1000000; \
481 } \
482 } while (0)
483 #endif
484
485
486 bool SolarisSemaphore::Wait(int timeout) {
487 const long kOneSecondMicros = 1000000; // NOLINT
488
489 // Split timeout into second and nanosecond parts.
490 struct timeval delta;
491 delta.tv_usec = timeout % kOneSecondMicros;
492 delta.tv_sec = timeout / kOneSecondMicros;
493
494 struct timeval current_time;
495 // Get the current time.
496 if (gettimeofday(&current_time, NULL) == -1) {
497 return false;
498 }
499
500 // Calculate time for end of timeout.
501 struct timeval end_time;
502 timeradd(&current_time, &delta, &end_time);
503
504 struct timespec ts;
505 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
506 // Wait for semaphore signalled or timeout.
507 while (true) {
508 int result = sem_timedwait(&sem_, &ts);
509 if (result == 0) return true; // Successfully got semaphore.
510 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
511 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
512 }
513 }
514
515
516 Semaphore* OS::CreateSemaphore(int count) {
517 return new SolarisSemaphore(count);
518 }
519
520
521 #ifdef ENABLE_LOGGING_AND_PROFILING
522
523 static Sampler* active_sampler_ = NULL;
524
525 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
526 USE(info);
527 if (signal != SIGPROF) return;
528 if (active_sampler_ == NULL) return;
529
530 TickSample sample;
531 sample.pc = 0;
532 sample.sp = 0;
533 sample.fp = 0;
534
535 // We always sample the VM state.
536 sample.state = Logger::state();
537
538 active_sampler_->Tick(&sample);
539 }
540
541
542 class Sampler::PlatformData : public Malloced {
543 public:
544 PlatformData() {
545 signal_handler_installed_ = false;
546 }
547
548 bool signal_handler_installed_;
549 struct sigaction old_signal_handler_;
550 struct itimerval old_timer_value_;
551 };
552
553
554 Sampler::Sampler(int interval, bool profiling)
555 : interval_(interval), profiling_(profiling), active_(false) {
556 data_ = new PlatformData();
557 }
558
559
560 Sampler::~Sampler() {
561 delete data_;
562 }
563
564
565 void Sampler::Start() {
566 // There can only be one active sampler at the time on POSIX
567 // platforms.
568 if (active_sampler_ != NULL) return;
569
570 // Request profiling signals.
571 struct sigaction sa;
572 sa.sa_sigaction = ProfilerSignalHandler;
573 sigemptyset(&sa.sa_mask);
574 sa.sa_flags = SA_SIGINFO;
575 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
576 data_->signal_handler_installed_ = true;
577
578 // Set the itimer to generate a tick for each interval.
579 itimerval itimer;
580 itimer.it_interval.tv_sec = interval_ / 1000;
581 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
582 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
583 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
584 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
585
586 // Set this sampler as the active sampler.
587 active_sampler_ = this;
588 active_ = true;
589 }
590
591
592 void Sampler::Stop() {
593 // Restore old signal handler
594 if (data_->signal_handler_installed_) {
595 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
596 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
597 data_->signal_handler_installed_ = false;
598 }
599
600 // This sampler is no longer the active sampler.
601 active_sampler_ = NULL;
602 active_ = false;
603 }
604
605 #endif // ENABLE_LOGGING_AND_PROFILING
606
607 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/platform-posix.cc ('k') | test/cctest/test-compiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698