This commit is contained in:
Vladimir Kozlov 2013-06-21 15:56:24 -07:00
commit b390a2d8e3
629 changed files with 30523 additions and 8788 deletions

View file

@ -101,6 +101,12 @@
# include <inttypes.h>
# include <sys/ioctl.h>
// if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling
// getrusage() is prepared to handle the associated failure.
#ifndef RUSAGE_THREAD
#define RUSAGE_THREAD (1) /* only the calling thread */
#endif
#define MAX_PATH (2 * K)
// for timer info max values which include all bits
@ -145,6 +151,9 @@ 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;
@ -1338,15 +1347,19 @@ jlong os::elapsed_frequency() {
return (1000 * 1000);
}
// For now, we say that linux does not support vtime. I have no idea
// whether it can actually be made to (DLD, 9/13/05).
bool os::supports_vtime() { return false; }
bool os::supports_vtime() { return true; }
bool os::enable_vtime() { return false; }
bool os::vtime_enabled() { return false; }
double os::elapsedVTime() {
// better than nothing, but not much
return elapsedTime();
struct rusage usage;
int retval = getrusage(RUSAGE_THREAD, &usage);
if (retval == 0) {
return (double) (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) + (double) (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000 * 1000);
} else {
// better than nothing, but not much
return elapsedTime();
}
}
jlong os::javaTimeMillis() {
@ -2399,6 +2412,57 @@ 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 *);
@ -2438,6 +2502,7 @@ 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
@ -3551,9 +3616,6 @@ void os::hint_no_preempt() {}
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) {
@ -3573,7 +3635,7 @@ static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontex
// its signal handlers run and prevents sigwait()'s use with the
// mutex granting granting signal.
//
// Currently only ever called on the VMThread
// 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
@ -3582,38 +3644,46 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
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) {
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);
// 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
// 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()
// notify the caller
osthread->sr.set_suspended();
// get current set of blocked signals and unblock resume signal
pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
sigdelset(&suspend_set, SR_signum);
sigset_t suspend_set; // signals for sigsuspend()
sr_semaphore.signal();
// wait here until we are resumed
while (1) {
sigsuspend(&suspend_set);
// get current set of blocked signals and unblock resume signal
pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
sigdelset(&suspend_set, SR_signum);
os::SuspendResume::State result = osthread->sr.running();
if (result == os::SuspendResume::SR_RUNNING) {
sr_semaphore.signal();
break;
}
}
// 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);
} 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 {
assert(action == os::Linux::SuspendResume::SR_CONTINUE, "unexpected sr action");
// nothing special to do - just leave the handler
// ignore
}
errno = old_errno;
@ -3657,42 +3727,82 @@ static int SR_initialize() {
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) {
// 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");
assert(osthread->sr.is_running(), "thread should be running");
assert(!sr_semaphore.trywait(), "semaphore has invalid state");
// 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);
// 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");
osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_CONTINUE);
assert(!sr_semaphore.trywait(), "invalid semaphore state");
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);
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();
}
}
osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
guarantee(osthread->sr.is_running(), "Must be running!");
}
////////////////////////////////////////////////////////////////////////////////
@ -4463,6 +4573,40 @@ bool os::bind_to_processor(uint processor_id) {
///
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) {
@ -4470,22 +4614,9 @@ ExtendedPC os::get_thread_pc(Thread* thread) {
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;
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)
@ -5607,4 +5738,5 @@ void MemNotifyThread::start() {
new MemNotifyThread(fd);
}
}
#endif // JAVASE_EMBEDDED