Wed, 27 Mar 2013 19:21:18 +0100
7112912: Message "Error occurred during initialization of VM" on boxes with lots of RAM
Summary: Ergonomics now also takes available virtual memory into account when deciding for a heap size. The helper method to determine the maximum allocatable memory block now uses the appropriate OS specific calls to retrieve available virtual memory for the java process. In 32 bit environments this method now also searches for the maximum actually reservable amount of memory. Merge previously separate implementations for Linux/BSD/Solaris into a single method.
Reviewed-by: jmasa, tamao
1 /*
2 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 // no precompiled headers
26 #include "runtime/atomic.hpp"
27 #include "runtime/handles.inline.hpp"
28 #include "runtime/mutexLocker.hpp"
29 #include "runtime/os.hpp"
30 #include "runtime/osThread.hpp"
31 #include "runtime/safepoint.hpp"
32 #include "runtime/vmThread.hpp"
34 #include <signal.h>
36 // ***************************************************************
37 // Platform dependent initialization and cleanup
38 // ***************************************************************
40 void OSThread::pd_initialize() {
41 _thread_id = 0;
42 sigemptyset(&_caller_sigmask);
44 _current_callback = NULL;
45 _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL
46 : new Mutex(Mutex::suspend_resume, "Callback_lock", true);
48 _saved_interrupt_thread_state = _thread_new;
49 _vm_created_thread = false;
50 }
52 void OSThread::pd_destroy() {
53 }
55 // Synchronous interrupt support
56 //
57 // _current_callback == NULL no pending callback
58 // == 1 callback_in_progress
59 // == other value pointer to the pending callback
60 //
62 // CAS on v8 is implemented by using a global atomic_memory_operation_lock,
63 // which is shared by other atomic functions. It is OK for normal uses, but
64 // dangerous if used after some thread is suspended or if used in signal
65 // handlers. Instead here we use a special per-thread lock to synchronize
66 // updating _current_callback if we are running on v8. Note in general trying
67 // to grab locks after a thread is suspended is not safe, but it is safe for
68 // updating _current_callback, because synchronous interrupt callbacks are
69 // currently only used in:
70 // 1. GetThreadPC_Callback - used by WatcherThread to profile VM thread
71 // There is no overlap between the callbacks, which means we won't try to
72 // grab a thread's sync lock after the thread has been suspended while holding
73 // the same lock.
75 // used after a thread is suspended
76 static intptr_t compare_and_exchange_current_callback (
77 intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) {
78 if (VM_Version::supports_compare_and_exchange()) {
79 return Atomic::cmpxchg_ptr(callback, addr, compare_value);
80 } else {
81 MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
82 if (*addr == compare_value) {
83 *addr = callback;
84 return compare_value;
85 } else {
86 return callback;
87 }
88 }
89 }
91 // used in signal handler
92 static intptr_t exchange_current_callback(intptr_t callback, intptr_t *addr, Mutex *sync) {
93 if (VM_Version::supports_compare_and_exchange()) {
94 return Atomic::xchg_ptr(callback, addr);
95 } else {
96 MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
97 intptr_t cb = *addr;
98 *addr = callback;
99 return cb;
100 }
101 }
103 // one interrupt at a time. spin if _current_callback != NULL
104 int OSThread::set_interrupt_callback(Sync_Interrupt_Callback * cb) {
105 int count = 0;
106 while (compare_and_exchange_current_callback(
107 (intptr_t)cb, (intptr_t *)&_current_callback, (intptr_t)NULL, _current_callback_lock) != NULL) {
108 while (_current_callback != NULL) {
109 count++;
110 #ifdef ASSERT
111 if ((WarnOnStalledSpinLock > 0) &&
112 (count % WarnOnStalledSpinLock == 0)) {
113 warning("_current_callback seems to be stalled: %p", _current_callback);
114 }
115 #endif
116 os::yield_all(count);
117 }
118 }
119 return 0;
120 }
122 // reset _current_callback, spin if _current_callback is callback_in_progress
123 void OSThread::remove_interrupt_callback(Sync_Interrupt_Callback * cb) {
124 int count = 0;
125 while (compare_and_exchange_current_callback(
126 (intptr_t)NULL, (intptr_t *)&_current_callback, (intptr_t)cb, _current_callback_lock) != (intptr_t)cb) {
127 #ifdef ASSERT
128 intptr_t p = (intptr_t)_current_callback;
129 assert(p == (intptr_t)callback_in_progress ||
130 p == (intptr_t)cb, "wrong _current_callback value");
131 #endif
132 while (_current_callback != cb) {
133 count++;
134 #ifdef ASSERT
135 if ((WarnOnStalledSpinLock > 0) &&
136 (count % WarnOnStalledSpinLock == 0)) {
137 warning("_current_callback seems to be stalled: %p", _current_callback);
138 }
139 #endif
140 os::yield_all(count);
141 }
142 }
143 }
145 void OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args) {
146 Sync_Interrupt_Callback * cb;
147 cb = (Sync_Interrupt_Callback *)exchange_current_callback(
148 (intptr_t)callback_in_progress, (intptr_t *)&_current_callback, _current_callback_lock);
150 if (cb == NULL) {
151 // signal is delivered too late (thread is masking interrupt signal??).
152 // there is nothing we need to do because requesting thread has given up.
153 } else if ((intptr_t)cb == (intptr_t)callback_in_progress) {
154 fatal("invalid _current_callback state");
155 } else {
156 assert(cb->target()->osthread() == this, "wrong target");
157 cb->execute(args);
158 cb->leave_callback(); // notify the requester
159 }
161 // restore original _current_callback value
162 intptr_t p;
163 p = exchange_current_callback((intptr_t)cb, (intptr_t *)&_current_callback, _current_callback_lock);
164 assert(p == (intptr_t)callback_in_progress, "just checking");
165 }
167 // Called by the requesting thread to send a signal to target thread and
168 // execute "this" callback from the signal handler.
169 int OSThread::Sync_Interrupt_Callback::interrupt(Thread * target, int timeout) {
170 // Let signals to the vm_thread go even if the Threads_lock is not acquired
171 assert(Threads_lock->owned_by_self() || (target == VMThread::vm_thread()),
172 "must have threads lock to call this");
174 OSThread * osthread = target->osthread();
176 // may block if target thread already has a pending callback
177 osthread->set_interrupt_callback(this);
179 _target = target;
181 int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync());
182 assert(rslt == 0, "thr_kill != 0");
184 bool status = false;
185 jlong t1 = os::javaTimeMillis();
186 { // don't use safepoint check because we might be the watcher thread.
187 MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
188 while (!is_done()) {
189 status = _sync->wait(Mutex::_no_safepoint_check_flag, timeout);
191 // status == true if timed out
192 if (status) break;
194 // update timeout
195 jlong t2 = os::javaTimeMillis();
196 timeout -= t2 - t1;
197 t1 = t2;
198 }
199 }
201 // reset current_callback
202 osthread->remove_interrupt_callback(this);
204 return status;
205 }
207 void OSThread::Sync_Interrupt_Callback::leave_callback() {
208 if (!_sync->owned_by_self()) {
209 // notify requesting thread
210 MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
211 _is_done = true;
212 _sync->notify_all();
213 } else {
214 // Current thread is interrupted while it is holding the _sync lock, trying
215 // to grab it again will deadlock. The requester will timeout anyway,
216 // so just return.
217 _is_done = true;
218 }
219 }
221 // copied from synchronizer.cpp
223 void OSThread::handle_spinlock_contention(int tries) {
224 if (NoYieldsInMicrolock) return;
226 if (tries > 10) {
227 os::yield_all(tries); // Yield to threads of any priority
228 } else if (tries > 5) {
229 os::yield(); // Yield to threads of same or higher priority
230 }
231 }