Mercurial > hg > graal-compiler
comparison src/os/solaris/vm/os_solaris.cpp @ 10405:f2110083203d
8005849: JEP 167: Event-Based JVM Tracing
Reviewed-by: acorn, coleenp, sla
Contributed-by: Karen Kinnear <karen.kinnear@oracle.com>, Bengt Rutisson <bengt.rutisson@oracle.com>, Calvin Cheung <calvin.cheung@oracle.com>, Erik Gahlin <erik.gahlin@oracle.com>, Erik Helin <erik.helin@oracle.com>, Jesper Wilhelmsson <jesper.wilhelmsson@oracle.com>, Keith McGuigan <keith.mcguigan@oracle.com>, Mattias Tobiasson <mattias.tobiasson@oracle.com>, Markus Gronlund <markus.gronlund@oracle.com>, Mikael Auno <mikael.auno@oracle.com>, Nils Eliasson <nils.eliasson@oracle.com>, Nils Loodin <nils.loodin@oracle.com>, Rickard Backman <rickard.backman@oracle.com>, Staffan Larsen <staffan.larsen@oracle.com>, Stefan Karlsson <stefan.karlsson@oracle.com>, Yekaterina Kantserova <yekaterina.kantserova@oracle.com>
author | sla |
---|---|
date | Mon, 10 Jun 2013 11:30:51 +0200 |
parents | 9ce110b1d14a |
children | 836a62f43af9 a837fa3d3f86 |
comparison
equal
deleted
inserted
replaced
10404:d0add7016434 | 10405:f2110083203d |
---|---|
237 // "default" initializers for pthread-based synchronization | 237 // "default" initializers for pthread-based synchronization |
238 extern "C" { | 238 extern "C" { |
239 static int pthread_mutex_default_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; } | 239 static int pthread_mutex_default_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; } |
240 static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; } | 240 static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; } |
241 } | 241 } |
242 | |
243 static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); | |
242 | 244 |
243 // Thread Local Storage | 245 // Thread Local Storage |
244 // This is common to all Solaris platforms so it is defined here, | 246 // This is common to all Solaris platforms so it is defined here, |
245 // in this common file. | 247 // in this common file. |
246 // The declarations are in the os_cpu threadLS*.hpp files. | 248 // The declarations are in the os_cpu threadLS*.hpp files. |
2578 | 2580 |
2579 void* os::user_handler() { | 2581 void* os::user_handler() { |
2580 return CAST_FROM_FN_PTR(void*, UserHandler); | 2582 return CAST_FROM_FN_PTR(void*, UserHandler); |
2581 } | 2583 } |
2582 | 2584 |
2585 class Semaphore : public StackObj { | |
2586 public: | |
2587 Semaphore(); | |
2588 ~Semaphore(); | |
2589 void signal(); | |
2590 void wait(); | |
2591 bool trywait(); | |
2592 bool timedwait(unsigned int sec, int nsec); | |
2593 private: | |
2594 sema_t _semaphore; | |
2595 }; | |
2596 | |
2597 | |
2598 Semaphore::Semaphore() { | |
2599 sema_init(&_semaphore, 0, NULL, NULL); | |
2600 } | |
2601 | |
2602 Semaphore::~Semaphore() { | |
2603 sema_destroy(&_semaphore); | |
2604 } | |
2605 | |
2606 void Semaphore::signal() { | |
2607 sema_post(&_semaphore); | |
2608 } | |
2609 | |
2610 void Semaphore::wait() { | |
2611 sema_wait(&_semaphore); | |
2612 } | |
2613 | |
2614 bool Semaphore::trywait() { | |
2615 return sema_trywait(&_semaphore) == 0; | |
2616 } | |
2617 | |
2618 bool Semaphore::timedwait(unsigned int sec, int nsec) { | |
2619 struct timespec ts; | |
2620 unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); | |
2621 | |
2622 while (1) { | |
2623 int result = sema_timedwait(&_semaphore, &ts); | |
2624 if (result == 0) { | |
2625 return true; | |
2626 } else if (errno == EINTR) { | |
2627 continue; | |
2628 } else if (errno == ETIME) { | |
2629 return false; | |
2630 } else { | |
2631 return false; | |
2632 } | |
2633 } | |
2634 } | |
2635 | |
2583 extern "C" { | 2636 extern "C" { |
2584 typedef void (*sa_handler_t)(int); | 2637 typedef void (*sa_handler_t)(int); |
2585 typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); | 2638 typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); |
2586 } | 2639 } |
2587 | 2640 |
4162 // Void return because it's a hint and can fail. | 4215 // Void return because it's a hint and can fail. |
4163 void os::hint_no_preempt() { | 4216 void os::hint_no_preempt() { |
4164 schedctl_start(schedctl_init()); | 4217 schedctl_start(schedctl_init()); |
4165 } | 4218 } |
4166 | 4219 |
4220 static void resume_clear_context(OSThread *osthread) { | |
4221 osthread->set_ucontext(NULL); | |
4222 } | |
4223 | |
4224 static void suspend_save_context(OSThread *osthread, ucontext_t* context) { | |
4225 osthread->set_ucontext(context); | |
4226 } | |
4227 | |
4228 static Semaphore sr_semaphore; | |
4229 | |
4230 void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) { | |
4231 // Save and restore errno to avoid confusing native code with EINTR | |
4232 // after sigsuspend. | |
4233 int old_errno = errno; | |
4234 | |
4235 OSThread* osthread = thread->osthread(); | |
4236 assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread"); | |
4237 | |
4238 os::SuspendResume::State current = osthread->sr.state(); | |
4239 if (current == os::SuspendResume::SR_SUSPEND_REQUEST) { | |
4240 suspend_save_context(osthread, uc); | |
4241 | |
4242 // attempt to switch the state, we assume we had a SUSPEND_REQUEST | |
4243 os::SuspendResume::State state = osthread->sr.suspended(); | |
4244 if (state == os::SuspendResume::SR_SUSPENDED) { | |
4245 sigset_t suspend_set; // signals for sigsuspend() | |
4246 | |
4247 // get current set of blocked signals and unblock resume signal | |
4248 thr_sigsetmask(SIG_BLOCK, NULL, &suspend_set); | |
4249 sigdelset(&suspend_set, os::Solaris::SIGasync()); | |
4250 | |
4251 sr_semaphore.signal(); | |
4252 // wait here until we are resumed | |
4253 while (1) { | |
4254 sigsuspend(&suspend_set); | |
4255 | |
4256 os::SuspendResume::State result = osthread->sr.running(); | |
4257 if (result == os::SuspendResume::SR_RUNNING) { | |
4258 sr_semaphore.signal(); | |
4259 break; | |
4260 } | |
4261 } | |
4262 | |
4263 } else if (state == os::SuspendResume::SR_RUNNING) { | |
4264 // request was cancelled, continue | |
4265 } else { | |
4266 ShouldNotReachHere(); | |
4267 } | |
4268 | |
4269 resume_clear_context(osthread); | |
4270 } else if (current == os::SuspendResume::SR_RUNNING) { | |
4271 // request was cancelled, continue | |
4272 } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) { | |
4273 // ignore | |
4274 } else { | |
4275 // ignore | |
4276 } | |
4277 | |
4278 errno = old_errno; | |
4279 } | |
4280 | |
4281 | |
4167 void os::interrupt(Thread* thread) { | 4282 void os::interrupt(Thread* thread) { |
4168 assert(Thread::current() == thread || Threads_lock->owned_by_self(), "possibility of dangling Thread pointer"); | 4283 assert(Thread::current() == thread || Threads_lock->owned_by_self(), "possibility of dangling Thread pointer"); |
4169 | 4284 |
4170 OSThread* osthread = thread->osthread(); | 4285 OSThread* osthread = thread->osthread(); |
4171 | 4286 |
4245 while (::read(0, buf, sizeof(buf)) <= 0) { ::sleep(100); } | 4360 while (::read(0, buf, sizeof(buf)) <= 0) { ::sleep(100); } |
4246 | 4361 |
4247 return buf[0] == 'y' || buf[0] == 'Y'; | 4362 return buf[0] == 'y' || buf[0] == 'Y'; |
4248 } | 4363 } |
4249 | 4364 |
4365 static int sr_notify(OSThread* osthread) { | |
4366 int status = thr_kill(osthread->thread_id(), os::Solaris::SIGasync()); | |
4367 assert_status(status == 0, status, "thr_kill"); | |
4368 return status; | |
4369 } | |
4370 | |
4371 // "Randomly" selected value for how long we want to spin | |
4372 // before bailing out on suspending a thread, also how often | |
4373 // we send a signal to a thread we want to resume | |
4374 static const int RANDOMLY_LARGE_INTEGER = 1000000; | |
4375 static const int RANDOMLY_LARGE_INTEGER2 = 100; | |
4376 | |
4377 static bool do_suspend(OSThread* osthread) { | |
4378 assert(osthread->sr.is_running(), "thread should be running"); | |
4379 assert(!sr_semaphore.trywait(), "semaphore has invalid state"); | |
4380 | |
4381 // mark as suspended and send signal | |
4382 if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) { | |
4383 // failed to switch, state wasn't running? | |
4384 ShouldNotReachHere(); | |
4385 return false; | |
4386 } | |
4387 | |
4388 if (sr_notify(osthread) != 0) { | |
4389 ShouldNotReachHere(); | |
4390 } | |
4391 | |
4392 // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED | |
4393 while (true) { | |
4394 if (sr_semaphore.timedwait(0, 2000 * NANOSECS_PER_MILLISEC)) { | |
4395 break; | |
4396 } else { | |
4397 // timeout | |
4398 os::SuspendResume::State cancelled = osthread->sr.cancel_suspend(); | |
4399 if (cancelled == os::SuspendResume::SR_RUNNING) { | |
4400 return false; | |
4401 } else if (cancelled == os::SuspendResume::SR_SUSPENDED) { | |
4402 // make sure that we consume the signal on the semaphore as well | |
4403 sr_semaphore.wait(); | |
4404 break; | |
4405 } else { | |
4406 ShouldNotReachHere(); | |
4407 return false; | |
4408 } | |
4409 } | |
4410 } | |
4411 | |
4412 guarantee(osthread->sr.is_suspended(), "Must be suspended"); | |
4413 return true; | |
4414 } | |
4415 | |
4416 static void do_resume(OSThread* osthread) { | |
4417 assert(osthread->sr.is_suspended(), "thread should be suspended"); | |
4418 assert(!sr_semaphore.trywait(), "invalid semaphore state"); | |
4419 | |
4420 if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) { | |
4421 // failed to switch to WAKEUP_REQUEST | |
4422 ShouldNotReachHere(); | |
4423 return; | |
4424 } | |
4425 | |
4426 while (true) { | |
4427 if (sr_notify(osthread) == 0) { | |
4428 if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { | |
4429 if (osthread->sr.is_running()) { | |
4430 return; | |
4431 } | |
4432 } | |
4433 } else { | |
4434 ShouldNotReachHere(); | |
4435 } | |
4436 } | |
4437 | |
4438 guarantee(osthread->sr.is_running(), "Must be running!"); | |
4439 } | |
4440 | |
4441 void os::SuspendedThreadTask::internal_do_task() { | |
4442 if (do_suspend(_thread->osthread())) { | |
4443 SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext()); | |
4444 do_task(context); | |
4445 do_resume(_thread->osthread()); | |
4446 } | |
4447 } | |
4448 | |
4449 class PcFetcher : public os::SuspendedThreadTask { | |
4450 public: | |
4451 PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {} | |
4452 ExtendedPC result(); | |
4453 protected: | |
4454 void do_task(const os::SuspendedThreadTaskContext& context); | |
4455 private: | |
4456 ExtendedPC _epc; | |
4457 }; | |
4458 | |
4459 ExtendedPC PcFetcher::result() { | |
4460 guarantee(is_done(), "task is not done yet."); | |
4461 return _epc; | |
4462 } | |
4463 | |
4464 void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { | |
4465 Thread* thread = context.thread(); | |
4466 OSThread* osthread = thread->osthread(); | |
4467 if (osthread->ucontext() != NULL) { | |
4468 _epc = os::Solaris::ucontext_get_pc((ucontext_t *) context.ucontext()); | |
4469 } else { | |
4470 // NULL context is unexpected, double-check this is the VMThread | |
4471 guarantee(thread->is_VM_thread(), "can only be called for VMThread"); | |
4472 } | |
4473 } | |
4474 | |
4250 // A lightweight implementation that does not suspend the target thread and | 4475 // A lightweight implementation that does not suspend the target thread and |
4251 // thus returns only a hint. Used for profiling only! | 4476 // thus returns only a hint. Used for profiling only! |
4252 ExtendedPC os::get_thread_pc(Thread* thread) { | 4477 ExtendedPC os::get_thread_pc(Thread* thread) { |
4253 // Make sure that it is called by the watcher and the Threads lock is owned. | 4478 // Make sure that it is called by the watcher and the Threads lock is owned. |
4254 assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock"); | 4479 assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock"); |
4255 // For now, is only used to profile the VM Thread | 4480 // For now, is only used to profile the VM Thread |
4256 assert(thread->is_VM_thread(), "Can only be called for VMThread"); | 4481 assert(thread->is_VM_thread(), "Can only be called for VMThread"); |
4257 ExtendedPC epc; | 4482 PcFetcher fetcher(thread); |
4258 | 4483 fetcher.run(); |
4259 GetThreadPC_Callback cb(ProfileVM_lock); | 4484 return fetcher.result(); |
4260 OSThread *osthread = thread->osthread(); | |
4261 const int time_to_wait = 400; // 400ms wait for initial response | |
4262 int status = cb.interrupt(thread, time_to_wait); | |
4263 | |
4264 if (cb.is_done() ) { | |
4265 epc = cb.addr(); | |
4266 } else { | |
4267 DEBUG_ONLY(tty->print_cr("Failed to get pc for thread: %d got %d status", | |
4268 osthread->thread_id(), status);); | |
4269 // epc is already NULL | |
4270 } | |
4271 return epc; | |
4272 } | 4485 } |
4273 | 4486 |
4274 | 4487 |
4275 // This does not do anything on Solaris. This is basically a hook for being | 4488 // This does not do anything on Solaris. This is basically a hook for being |
4276 // able to use structured exception handling (thread-local exception filters) on, e.g., Win32. | 4489 // able to use structured exception handling (thread-local exception filters) on, e.g., Win32. |