src/os/linux/vm/os_linux.cpp
Print this page
rev 4773 : 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>
*** 143,152 ****
--- 143,155 ----
sigset_t SR_sigset;
/* Used to protect dlsym() calls */
static pthread_mutex_t dl_mutex;
+ // Declarations
+ static void unpackTime(timespec* absTime, bool isAbsolute, jlong time);
+
#ifdef JAVASE_EMBEDDED
class MemNotifyThread: public Thread {
friend class VMStructs;
public:
virtual void run();
*** 2395,2404 ****
--- 2398,2458 ----
void* os::user_handler() {
return CAST_FROM_FN_PTR(void*, UserHandler);
}
+ class Semaphore : public StackObj {
+ public:
+ Semaphore();
+ ~Semaphore();
+ void signal();
+ void wait();
+ bool trywait();
+ bool timedwait(unsigned int sec, int nsec);
+ private:
+ sem_t _semaphore;
+ };
+
+
+ Semaphore::Semaphore() {
+ sem_init(&_semaphore, 0, 0);
+ }
+
+ Semaphore::~Semaphore() {
+ sem_destroy(&_semaphore);
+ }
+
+ void Semaphore::signal() {
+ sem_post(&_semaphore);
+ }
+
+ void Semaphore::wait() {
+ sem_wait(&_semaphore);
+ }
+
+ bool Semaphore::trywait() {
+ return sem_trywait(&_semaphore) == 0;
+ }
+
+ bool Semaphore::timedwait(unsigned int sec, int nsec) {
+ struct timespec ts;
+ unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
+
+ while (1) {
+ int result = sem_timedwait(&_semaphore, &ts);
+ if (result == 0) {
+ return true;
+ } else if (errno == EINTR) {
+ continue;
+ } else if (errno == ETIMEDOUT) {
+ return false;
+ } else {
+ return false;
+ }
+ }
+ }
+
extern "C" {
typedef void (*sa_handler_t)(int);
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
}
*** 2434,2443 ****
--- 2488,2498 ----
// a counter for each possible signal value
static volatile jint pending_signals[NSIG+1] = { 0 };
// Linux(POSIX) specific hand shaking semaphore.
static sem_t sig_sem;
+ static Semaphore sr_semaphore;
void os::signal_init_pd() {
// Initialize signal structures
::memset((void*)pending_signals, 0, sizeof(pending_signals));
*** 3547,3559 ****
//
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
osthread->set_siginfo(NULL);
-
- // notify the suspend action is completed, we have now resumed
- osthread->sr.clear_suspended();
}
static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontext_t* context) {
osthread->set_ucontext(context);
osthread->set_siginfo(siginfo);
--- 3602,3611 ----
*** 3569,3619 ****
// interface point of view, but sigwait() prevents the signal hander
// from being run. libpthread would get very confused by not having
// its signal handlers run and prevents sigwait()'s use with the
// mutex granting granting signal.
//
! // Currently only ever called on the VMThread
//
static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR
// after sigsuspend.
int old_errno = errno;
Thread* thread = Thread::current();
OSThread* osthread = thread->osthread();
! assert(thread->is_VM_thread(), "Must be VMThread");
! // read current suspend action
! int action = osthread->sr.suspend_action();
! if (action == os::Linux::SuspendResume::SR_SUSPEND) {
! suspend_save_context(osthread, siginfo, context);
!
! // Notify the suspend action is about to be completed. do_suspend()
! // waits until SR_SUSPENDED is set and then returns. We will wait
! // here for a resume signal and that completes the suspend-other
! // action. do_suspend/do_resume is always called as a pair from
! // the same thread - so there are no races
! // notify the caller
! osthread->sr.set_suspended();
sigset_t suspend_set; // signals for sigsuspend()
// get current set of blocked signals and unblock resume signal
pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
sigdelset(&suspend_set, SR_signum);
// wait here until we are resumed
! do {
sigsuspend(&suspend_set);
- // ignore all returns until we get a resume signal
- } while (osthread->sr.suspend_action() != os::Linux::SuspendResume::SR_CONTINUE);
! resume_clear_context(osthread);
} else {
! assert(action == os::Linux::SuspendResume::SR_CONTINUE, "unexpected sr action");
! // nothing special to do - just leave the handler
}
errno = old_errno;
}
--- 3621,3679 ----
// interface point of view, but sigwait() prevents the signal hander
// from being run. libpthread would get very confused by not having
// its signal handlers run and prevents sigwait()'s use with the
// mutex granting granting signal.
//
! // Currently only ever called on the VMThread and JavaThreads (PC sampling)
//
static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR
// after sigsuspend.
int old_errno = errno;
Thread* thread = Thread::current();
OSThread* osthread = thread->osthread();
! assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
! os::SuspendResume::State current = osthread->sr.state();
! if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
! suspend_save_context(osthread, siginfo, context);
+ // attempt to switch the state, we assume we had a SUSPEND_REQUEST
+ os::SuspendResume::State state = osthread->sr.suspended();
+ if (state == os::SuspendResume::SR_SUSPENDED) {
sigset_t suspend_set; // signals for sigsuspend()
// get current set of blocked signals and unblock resume signal
pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
sigdelset(&suspend_set, SR_signum);
+ sr_semaphore.signal();
// wait here until we are resumed
! while (1) {
sigsuspend(&suspend_set);
! os::SuspendResume::State result = osthread->sr.running();
! if (result == os::SuspendResume::SR_RUNNING) {
! sr_semaphore.signal();
! break;
! }
! }
+ } else if (state == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
} else {
! ShouldNotReachHere();
! }
!
! resume_clear_context(osthread);
! } else if (current == os::SuspendResume::SR_RUNNING) {
! // request was cancelled, continue
! } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) {
! // ignore
! } else {
! // ignore
}
errno = old_errno;
}
*** 3653,3698 ****
// Save signal flag
os::Linux::set_our_sigflags(SR_signum, act.sa_flags);
return 0;
}
// returns true on success and false on error - really an error is fatal
// but this seems the normal response to library errors
static bool do_suspend(OSThread* osthread) {
! // mark as suspended and send signal
! osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_SUSPEND);
! int status = pthread_kill(osthread->pthread_id(), SR_signum);
! assert_status(status == 0, status, "pthread_kill");
! // check status and wait until notified of suspension
! if (status == 0) {
! for (int i = 0; !osthread->sr.is_suspended(); i++) {
! os::yield_all(i);
}
! osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
! return true;
}
! else {
! osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
return false;
}
}
static void do_resume(OSThread* osthread) {
assert(osthread->sr.is_suspended(), "thread should be suspended");
! osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_CONTINUE);
! int status = pthread_kill(osthread->pthread_id(), SR_signum);
! assert_status(status == 0, status, "pthread_kill");
! // check status and wait unit notified of resumption
! if (status == 0) {
! for (int i = 0; osthread->sr.is_suspended(); i++) {
! os::yield_all(i);
}
}
! osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
}
////////////////////////////////////////////////////////////////////////////////
// interrupt support
--- 3713,3798 ----
// Save signal flag
os::Linux::set_our_sigflags(SR_signum, act.sa_flags);
return 0;
}
+ static int sr_notify(OSThread* osthread) {
+ int status = pthread_kill(osthread->pthread_id(), SR_signum);
+ assert_status(status == 0, status, "pthread_kill");
+ return status;
+ }
+
+ // "Randomly" selected value for how long we want to spin
+ // before bailing out on suspending a thread, also how often
+ // we send a signal to a thread we want to resume
+ static const int RANDOMLY_LARGE_INTEGER = 1000000;
+ static const int RANDOMLY_LARGE_INTEGER2 = 100;
// returns true on success and false on error - really an error is fatal
// but this seems the normal response to library errors
static bool do_suspend(OSThread* osthread) {
! assert(osthread->sr.is_running(), "thread should be running");
! assert(!sr_semaphore.trywait(), "semaphore has invalid state");
! // mark as suspended and send signal
! if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) {
! // failed to switch, state wasn't running?
! ShouldNotReachHere();
! return false;
}
!
! if (sr_notify(osthread) != 0) {
! ShouldNotReachHere();
}
!
! // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
! while (true) {
! if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
! break;
! } else {
! // timeout
! os::SuspendResume::State cancelled = osthread->sr.cancel_suspend();
! if (cancelled == os::SuspendResume::SR_RUNNING) {
! return false;
! } else if (cancelled == os::SuspendResume::SR_SUSPENDED) {
! // make sure that we consume the signal on the semaphore as well
! sr_semaphore.wait();
! break;
! } else {
! ShouldNotReachHere();
return false;
}
+ }
+ }
+
+ guarantee(osthread->sr.is_suspended(), "Must be suspended");
+ return true;
}
static void do_resume(OSThread* osthread) {
assert(osthread->sr.is_suspended(), "thread should be suspended");
! assert(!sr_semaphore.trywait(), "invalid semaphore state");
! if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) {
! // failed to switch to WAKEUP_REQUEST
! ShouldNotReachHere();
! return;
! }
!
! while (true) {
! if (sr_notify(osthread) == 0) {
! if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
! if (osthread->sr.is_running()) {
! return;
! }
}
+ } else {
+ ShouldNotReachHere();
}
! }
!
! guarantee(osthread->sr.is_running(), "Must be running!");
}
////////////////////////////////////////////////////////////////////////////////
// interrupt support
*** 4460,4492 ****
return false;
}
///
! // Suspends the target using the signal mechanism and then grabs the PC before
! // resuming the target. Used by the flat-profiler only
! ExtendedPC os::get_thread_pc(Thread* thread) {
! // Make sure that it is called by the watcher for the VMThread
! assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
! assert(thread->is_VM_thread(), "Can only be called for VMThread");
! ExtendedPC epc;
OSThread* osthread = thread->osthread();
- if (do_suspend(osthread)) {
if (osthread->ucontext() != NULL) {
! epc = os::Linux::ucontext_get_pc(osthread->ucontext());
} else {
// NULL context is unexpected, double-check this is the VMThread
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
}
! do_resume(osthread);
! }
! // failure means pthread_kill failed for some reason - arguably this is
! // a fatal problem, but such problems are ignored elsewhere
! return epc;
}
int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime)
{
if (is_NPTL()) {
--- 4560,4613 ----
return false;
}
///
! void os::SuspendedThreadTask::internal_do_task() {
! if (do_suspend(_thread->osthread())) {
! SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext());
! do_task(context);
! do_resume(_thread->osthread());
! }
! }
! class PcFetcher : public os::SuspendedThreadTask {
! public:
! PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
! ExtendedPC result();
! protected:
! void do_task(const os::SuspendedThreadTaskContext& context);
! private:
! ExtendedPC _epc;
! };
+ ExtendedPC PcFetcher::result() {
+ guarantee(is_done(), "task is not done yet.");
+ return _epc;
+ }
+
+ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
+ Thread* thread = context.thread();
OSThread* osthread = thread->osthread();
if (osthread->ucontext() != NULL) {
! _epc = os::Linux::ucontext_get_pc((ucontext_t *) context.ucontext());
} else {
// NULL context is unexpected, double-check this is the VMThread
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
}
! }
!
! // Suspends the target using the signal mechanism and then grabs the PC before
! // resuming the target. Used by the flat-profiler only
! ExtendedPC os::get_thread_pc(Thread* thread) {
! // Make sure that it is called by the watcher for the VMThread
! assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
! assert(thread->is_VM_thread(), "Can only be called for VMThread");
! PcFetcher fetcher(thread);
! fetcher.run();
! return fetcher.result();
}
int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime)
{
if (is_NPTL()) {
*** 5604,5609 ****
--- 5725,5731 ----
if (memnotify_thread() == NULL) {
new MemNotifyThread(fd);
}
}
+
#endif // JAVASE_EMBEDDED