aboutsummaryrefslogtreecommitdiff
path: root/src/os
diff options
context:
space:
mode:
authornever <none@none>2011-09-25 16:03:29 -0700
committernever <none@none>2011-09-25 16:03:29 -0700
commit648f9f0c853014324b4a738a5bf0d2ccfcd42b96 (patch)
treeb819735f7d53af887ecae0edc46fba2e224cb04e /src/os
parent6ea580c1b174574421d6df0c9ff03cbb85df7d65 (diff)
7089790: integrate bsd-port changes
Reviewed-by: kvn, twisti, jrose Contributed-by: Kurt Miller <kurt@intricatesoftware.com>, Greg Lewis <glewis@eyesbeyond.com>, Jung-uk Kim <jkim@freebsd.org>, Christos Zoulas <christos@zoulas.com>, Landon Fuller <landonf@plausible.coop>, The FreeBSD Foundation <board@freebsdfoundation.org>, Michael Franz <mvfranz@gmail.com>, Roger Hoover <rhoover@apple.com>, Alexander Strange <astrange@apple.com>
Diffstat (limited to 'src/os')
-rw-r--r--src/os/bsd/vm/attachListener_bsd.cpp520
-rw-r--r--src/os/bsd/vm/c1_globals_bsd.hpp36
-rw-r--r--src/os/bsd/vm/c2_globals_bsd.hpp36
-rw-r--r--src/os/bsd/vm/chaitin_bsd.cpp42
-rw-r--r--src/os/bsd/vm/decoder_bsd.cpp66
-rw-r--r--src/os/bsd/vm/dtraceJSDT_bsd.cpp47
-rw-r--r--src/os/bsd/vm/globals_bsd.hpp55
-rw-r--r--src/os/bsd/vm/interfaceSupport_bsd.hpp34
-rw-r--r--src/os/bsd/vm/jsig.c225
-rw-r--r--src/os/bsd/vm/jvm_bsd.cpp192
-rw-r--r--src/os/bsd/vm/jvm_bsd.h120
-rw-r--r--src/os/bsd/vm/mutex_bsd.cpp33
-rw-r--r--src/os/bsd/vm/mutex_bsd.inline.hpp37
-rw-r--r--src/os/bsd/vm/osThread_bsd.cpp67
-rw-r--r--src/os/bsd/vm/osThread_bsd.hpp165
-rw-r--r--src/os/bsd/vm/os_bsd.cpp5709
-rw-r--r--src/os/bsd/vm/os_bsd.hpp368
-rw-r--r--src/os/bsd/vm/os_bsd.inline.hpp302
-rw-r--r--src/os/bsd/vm/os_share_bsd.hpp37
-rw-r--r--src/os/bsd/vm/perfMemory_bsd.cpp1041
-rw-r--r--src/os/bsd/vm/stubRoutines_bsd.cpp27
-rw-r--r--src/os/bsd/vm/threadCritical_bsd.cpp67
-rw-r--r--src/os/bsd/vm/thread_bsd.inline.hpp47
-rw-r--r--src/os/bsd/vm/vmError_bsd.cpp115
-rw-r--r--src/os/linux/vm/os_linux.cpp2
-rw-r--r--src/os/posix/launcher/java_md.c74
-rw-r--r--src/os/posix/launcher/launcher.script2
27 files changed, 9455 insertions, 11 deletions
diff --git a/src/os/bsd/vm/attachListener_bsd.cpp b/src/os/bsd/vm/attachListener_bsd.cpp
new file mode 100644
index 000000000..f74247063
--- /dev/null
+++ b/src/os/bsd/vm/attachListener_bsd.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/os.hpp"
+#include "services/attachListener.hpp"
+#include "services/dtraceAttacher.hpp"
+
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
+#endif
+
+// The attach mechanism on Bsd uses a UNIX domain socket. An attach listener
+// thread is created at startup or is created on-demand via a signal from
+// the client tool. The attach listener creates a socket and binds it to a file
+// in the filesystem. The attach listener then acts as a simple (single-
+// threaded) server - it waits for a client to connect, reads the request,
+// executes it, and returns the response to the client via the socket
+// connection.
+//
+// As the socket is a UNIX domain socket it means that only clients on the
+// local machine can connect. In addition there are two other aspects to
+// the security:
+// 1. The well known file that the socket is bound to has permission 400
+// 2. When a client connect, the SO_PEERCRED socket option is used to
+// obtain the credentials of client. We check that the effective uid
+// of the client matches this process.
+
+// forward reference
+class BsdAttachOperation;
+
+class BsdAttachListener: AllStatic {
+ private:
+ // the path to which we bind the UNIX domain socket
+ static char _path[UNIX_PATH_MAX];
+ static bool _has_path;
+
+ // the file descriptor for the listening socket
+ static int _listener;
+
+ static void set_path(char* path) {
+ if (path == NULL) {
+ _has_path = false;
+ } else {
+ strncpy(_path, path, UNIX_PATH_MAX);
+ _path[UNIX_PATH_MAX-1] = '\0';
+ _has_path = true;
+ }
+ }
+
+ static void set_listener(int s) { _listener = s; }
+
+ // reads a request from the given connected socket
+ static BsdAttachOperation* read_request(int s);
+
+ public:
+ enum {
+ ATTACH_PROTOCOL_VER = 1 // protocol version
+ };
+ enum {
+ ATTACH_ERROR_BADVERSION = 101 // error codes
+ };
+
+ // initialize the listener, returns 0 if okay
+ static int init();
+
+ static char* path() { return _path; }
+ static bool has_path() { return _has_path; }
+ static int listener() { return _listener; }
+
+ // write the given buffer to a socket
+ static int write_fully(int s, char* buf, int len);
+
+ static BsdAttachOperation* dequeue();
+};
+
+class BsdAttachOperation: public AttachOperation {
+ private:
+ // the connection to the client
+ int _socket;
+
+ public:
+ void complete(jint res, bufferedStream* st);
+
+ void set_socket(int s) { _socket = s; }
+ int socket() const { return _socket; }
+
+ BsdAttachOperation(char* name) : AttachOperation(name) {
+ set_socket(-1);
+ }
+};
+
+// statics
+char BsdAttachListener::_path[UNIX_PATH_MAX];
+bool BsdAttachListener::_has_path;
+int BsdAttachListener::_listener = -1;
+
+// Supporting class to help split a buffer into individual components
+class ArgumentIterator : public StackObj {
+ private:
+ char* _pos;
+ char* _end;
+ public:
+ ArgumentIterator(char* arg_buffer, size_t arg_size) {
+ _pos = arg_buffer;
+ _end = _pos + arg_size - 1;
+ }
+ char* next() {
+ if (*_pos == '\0') {
+ return NULL;
+ }
+ char* res = _pos;
+ char* next_pos = strchr(_pos, '\0');
+ if (next_pos < _end) {
+ next_pos++;
+ }
+ _pos = next_pos;
+ return res;
+ }
+};
+
+
+// atexit hook to stop listener and unlink the file that it is
+// bound too.
+extern "C" {
+ static void listener_cleanup() {
+ static int cleanup_done;
+ if (!cleanup_done) {
+ cleanup_done = 1;
+ int s = BsdAttachListener::listener();
+ if (s != -1) {
+ ::close(s);
+ }
+ if (BsdAttachListener::has_path()) {
+ ::unlink(BsdAttachListener::path());
+ }
+ }
+ }
+}
+
+// Initialization - create a listener socket and bind it to a file
+
+int BsdAttachListener::init() {
+ char path[UNIX_PATH_MAX]; // socket file
+ char initial_path[UNIX_PATH_MAX]; // socket file during setup
+ int listener; // listener socket (file descriptor)
+
+ // register function to cleanup
+ ::atexit(listener_cleanup);
+
+ int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
+ os::get_temp_directory(), os::current_process_id());
+ if (n < (int)UNIX_PATH_MAX) {
+ n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path);
+ }
+ if (n >= (int)UNIX_PATH_MAX) {
+ return -1;
+ }
+
+ // create the listener socket
+ listener = ::socket(PF_UNIX, SOCK_STREAM, 0);
+ if (listener == -1) {
+ return -1;
+ }
+
+ // bind socket
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, initial_path);
+ ::unlink(initial_path);
+ int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
+ if (res == -1) {
+ RESTARTABLE(::close(listener), res);
+ return -1;
+ }
+
+ // put in listen mode, set permissions, and rename into place
+ res = ::listen(listener, 5);
+ if (res == 0) {
+ RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
+ if (res == 0) {
+ res = ::rename(initial_path, path);
+ }
+ }
+ if (res == -1) {
+ RESTARTABLE(::close(listener), res);
+ ::unlink(initial_path);
+ return -1;
+ }
+ set_path(path);
+ set_listener(listener);
+
+ return 0;
+}
+
+// Given a socket that is connected to a peer we read the request and
+// create an AttachOperation. As the socket is blocking there is potential
+// for a denial-of-service if the peer does not response. However this happens
+// after the peer credentials have been checked and in the worst case it just
+// means that the attach listener thread is blocked.
+//
+BsdAttachOperation* BsdAttachListener::read_request(int s) {
+ char ver_str[8];
+ sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER);
+
+ // The request is a sequence of strings so we first figure out the
+ // expected count and the maximum possible length of the request.
+ // The request is:
+ // <ver>0<cmd>0<arg>0<arg>0<arg>0
+ // where <ver> is the protocol version (1), <cmd> is the command
+ // name ("load", "datadump", ...), and <arg> is an argument
+ int expected_str_count = 2 + AttachOperation::arg_count_max;
+ const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) +
+ AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1);
+
+ char buf[max_len];
+ int str_count = 0;
+
+ // Read until all (expected) strings have been read, the buffer is
+ // full, or EOF.
+
+ int off = 0;
+ int left = max_len;
+
+ do {
+ int n;
+ RESTARTABLE(read(s, buf+off, left), n);
+ if (n == -1) {
+ return NULL; // reset by peer or other error
+ }
+ if (n == 0) {
+ break;
+ }
+ for (int i=0; i<n; i++) {
+ if (buf[off+i] == 0) {
+ // EOS found
+ str_count++;
+
+ // The first string is <ver> so check it now to
+ // check for protocol mis-match
+ if (str_count == 1) {
+ if ((strlen(buf) != strlen(ver_str)) ||
+ (atoi(buf) != ATTACH_PROTOCOL_VER)) {
+ char msg[32];
+ sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION);
+ write_fully(s, msg, strlen(msg));
+ return NULL;
+ }
+ }
+ }
+ }
+ off += n;
+ left -= n;
+ } while (left > 0 && str_count < expected_str_count);
+
+ if (str_count != expected_str_count) {
+ return NULL; // incomplete request
+ }
+
+ // parse request
+
+ ArgumentIterator args(buf, (max_len)-left);
+
+ // version already checked
+ char* v = args.next();
+
+ char* name = args.next();
+ if (name == NULL || strlen(name) > AttachOperation::name_length_max) {
+ return NULL;
+ }
+
+ BsdAttachOperation* op = new BsdAttachOperation(name);
+
+ for (int i=0; i<AttachOperation::arg_count_max; i++) {
+ char* arg = args.next();
+ if (arg == NULL) {
+ op->set_arg(i, NULL);
+ } else {
+ if (strlen(arg) > AttachOperation::arg_length_max) {
+ delete op;
+ return NULL;
+ }
+ op->set_arg(i, arg);
+ }
+ }
+
+ op->set_socket(s);
+ return op;
+}
+
+
+// Dequeue an operation
+//
+// In the Bsd implementation there is only a single operation and clients
+// cannot queue commands (except at the socket level).
+//
+BsdAttachOperation* BsdAttachListener::dequeue() {
+ for (;;) {
+ int s;
+
+ // wait for client to connect
+ struct sockaddr addr;
+ socklen_t len = sizeof(addr);
+ RESTARTABLE(::accept(listener(), &addr, &len), s);
+ if (s == -1) {
+ return NULL; // log a warning?
+ }
+
+ // get the credentials of the peer and check the effective uid/guid
+ // - check with jeff on this.
+#ifdef _ALLBSD_SOURCE
+ uid_t puid;
+ gid_t pgid;
+ if (::getpeereid(s, &puid, &pgid) != 0) {
+ int res;
+ RESTARTABLE(::close(s), res);
+ continue;
+ }
+#else
+ struct ucred cred_info;
+ socklen_t optlen = sizeof(cred_info);
+ if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) {
+ int res;
+ RESTARTABLE(::close(s), res);
+ continue;
+ }
+ uid_t puid = cred_info.uid;
+ gid_t pgid = cred_info.gid;
+#endif
+ uid_t euid = geteuid();
+ gid_t egid = getegid();
+
+ if (puid != euid || pgid != egid) {
+ int res;
+ RESTARTABLE(::close(s), res);
+ continue;
+ }
+
+ // peer credential look okay so we read the request
+ BsdAttachOperation* op = read_request(s);
+ if (op == NULL) {
+ int res;
+ RESTARTABLE(::close(s), res);
+ continue;
+ } else {
+ return op;
+ }
+ }
+}
+
+// write the given buffer to the socket
+int BsdAttachListener::write_fully(int s, char* buf, int len) {
+ do {
+ int n = ::write(s, buf, len);
+ if (n == -1) {
+ if (errno != EINTR) return -1;
+ } else {
+ buf += n;
+ len -= n;
+ }
+ }
+ while (len > 0);
+ return 0;
+}
+
+// Complete an operation by sending the operation result and any result
+// output to the client. At this time the socket is in blocking mode so
+// potentially we can block if there is a lot of data and the client is
+// non-responsive. For most operations this is a non-issue because the
+// default send buffer is sufficient to buffer everything. In the future
+// if there are operations that involves a very big reply then it the
+// socket could be made non-blocking and a timeout could be used.
+
+void BsdAttachOperation::complete(jint result, bufferedStream* st) {
+ JavaThread* thread = JavaThread::current();
+ ThreadBlockInVM tbivm(thread);
+
+ thread->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or
+ // java_suspend_self() via check_and_wait_while_suspended()
+
+ // write operation result
+ char msg[32];
+ sprintf(msg, "%d\n", result);
+ int rc = BsdAttachListener::write_fully(this->socket(), msg, strlen(msg));
+
+ // write any result data
+ if (rc == 0) {
+ BsdAttachListener::write_fully(this->socket(), (char*) st->base(), st->size());
+ ::shutdown(this->socket(), 2);
+ }
+
+ // done
+ RESTARTABLE(::close(this->socket()), rc);
+
+ // were we externally suspended while we were waiting?
+ thread->check_and_wait_while_suspended();
+
+ delete this;
+}
+
+
+// AttachListener functions
+
+AttachOperation* AttachListener::dequeue() {
+ JavaThread* thread = JavaThread::current();
+ ThreadBlockInVM tbivm(thread);
+
+ thread->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or
+ // java_suspend_self() via check_and_wait_while_suspended()
+
+ AttachOperation* op = BsdAttachListener::dequeue();
+
+ // were we externally suspended while we were waiting?
+ thread->check_and_wait_while_suspended();
+
+ return op;
+}
+
+int AttachListener::pd_init() {
+ JavaThread* thread = JavaThread::current();
+ ThreadBlockInVM tbivm(thread);
+
+ thread->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or
+ // java_suspend_self() via check_and_wait_while_suspended()
+
+ int ret_code = BsdAttachListener::init();
+
+ // were we externally suspended while we were waiting?
+ thread->check_and_wait_while_suspended();
+
+ return ret_code;
+}
+
+// Attach Listener is started lazily except in the case when
+// +ReduseSignalUsage is used
+bool AttachListener::init_at_startup() {
+ if (ReduceSignalUsage) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// If the file .attach_pid<pid> exists in the working directory
+// or /tmp then this is the trigger to start the attach mechanism
+bool AttachListener::is_init_trigger() {
+ if (init_at_startup() || is_initialized()) {
+ return false; // initialized at startup or already initialized
+ }
+ char path[PATH_MAX + 1];
+ int ret;
+ struct stat st;
+
+ snprintf(path, PATH_MAX + 1, "%s/.attach_pid%d",
+ os::get_temp_directory(), os::current_process_id());
+ RESTARTABLE(::stat(path, &st), ret);
+ if (ret == 0) {
+ // simple check to avoid starting the attach mechanism when
+ // a bogus user creates the file
+ if (st.st_uid == geteuid()) {
+ init();
+ return true;
+ }
+ }
+ return false;
+}
+
+// if VM aborts then remove listener
+void AttachListener::abort() {
+ listener_cleanup();
+}
+
+void AttachListener::pd_data_dump() {
+ os::signal_notify(SIGQUIT);
+}
+
+AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) {
+ return NULL;
+}
+
+jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
+ out->print_cr("flag '%s' cannot be changed", op->arg(0));
+ return JNI_ERR;
+}
+
+void AttachListener::pd_detachall() {
+ // do nothing for now
+}
diff --git a/src/os/bsd/vm/c1_globals_bsd.hpp b/src/os/bsd/vm/c1_globals_bsd.hpp
new file mode 100644
index 000000000..27e26af11
--- /dev/null
+++ b/src/os/bsd/vm/c1_globals_bsd.hpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_C1_GLOBALS_BSD_HPP
+#define OS_BSD_VM_C1_GLOBALS_BSD_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for operating system dependent flags used by the
+// client compiler. (see c1_globals.hpp)
+//
+
+#endif // OS_BSD_VM_C1_GLOBALS_BSD_HPP
diff --git a/src/os/bsd/vm/c2_globals_bsd.hpp b/src/os/bsd/vm/c2_globals_bsd.hpp
new file mode 100644
index 000000000..21737f19b
--- /dev/null
+++ b/src/os/bsd/vm/c2_globals_bsd.hpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_C2_GLOBALS_BSD_HPP
+#define OS_BSD_VM_C2_GLOBALS_BSD_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for operating system dependent flags used by the
+// server compiler. (see c2_globals.hpp)
+//
+
+#endif // OS_BSD_VM_C2_GLOBALS_BSD_HPP
diff --git a/src/os/bsd/vm/chaitin_bsd.cpp b/src/os/bsd/vm/chaitin_bsd.cpp
new file mode 100644
index 000000000..e4925644d
--- /dev/null
+++ b/src/os/bsd/vm/chaitin_bsd.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "opto/chaitin.hpp"
+#include "opto/machnode.hpp"
+
+void PhaseRegAlloc::pd_preallocate_hook() {
+ // no action
+}
+
+#ifdef ASSERT
+void PhaseRegAlloc::pd_postallocate_verify_hook() {
+ // no action
+}
+#endif
+
+
+// Reconciliation History
+// chaitin_solaris.cpp 1.7 99/07/12 23:54:22
+// End
diff --git a/src/os/bsd/vm/decoder_bsd.cpp b/src/os/bsd/vm/decoder_bsd.cpp
new file mode 100644
index 000000000..dd959298f
--- /dev/null
+++ b/src/os/bsd/vm/decoder_bsd.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "prims/jvm.h"
+#include "utilities/decoder.hpp"
+
+#include <cxxabi.h>
+
+#ifdef __APPLE__
+
+void Decoder::initialize() {
+ _initialized = true;
+}
+
+void Decoder::uninitialize() {
+ _initialized = false;
+}
+
+bool Decoder::can_decode_C_frame_in_vm() {
+ return false;
+}
+
+Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) {
+ return symbol_not_found;
+}
+
+
+#endif
+
+bool Decoder::demangle(const char* symbol, char *buf, int buflen) {
+ int status;
+ char* result;
+ size_t size = (size_t)buflen;
+
+ // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small,
+ // __cxa_demangle will call system "realloc" for additional memory, which
+ // may use different malloc/realloc mechanism that allocates 'buf'.
+ if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) {
+ jio_snprintf(buf, buflen, "%s", result);
+ // call c library's free
+ ::free(result);
+ return true;
+ }
+ return false;
+}
diff --git a/src/os/bsd/vm/dtraceJSDT_bsd.cpp b/src/os/bsd/vm/dtraceJSDT_bsd.cpp
new file mode 100644
index 000000000..0f340fb57
--- /dev/null
+++ b/src/os/bsd/vm/dtraceJSDT_bsd.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "code/codeBlob.hpp"
+#include "memory/allocation.hpp"
+#include "prims/jvm.h"
+#include "runtime/dtraceJSDT.hpp"
+#include "runtime/jniHandles.hpp"
+#include "runtime/os.hpp"
+#include "runtime/signature.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+int DTraceJSDT::pd_activate(
+ void* baseAddress, jstring module,
+ jint providers_count, JVM_DTraceProvider* providers) {
+ return -1;
+}
+
+void DTraceJSDT::pd_dispose(int handle) {
+}
+
+jboolean DTraceJSDT::pd_is_supported() {
+ return false;
+}
diff --git a/src/os/bsd/vm/globals_bsd.hpp b/src/os/bsd/vm/globals_bsd.hpp
new file mode 100644
index 000000000..213f47009
--- /dev/null
+++ b/src/os/bsd/vm/globals_bsd.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_GLOBALS_BSD_HPP
+#define OS_BSD_VM_GLOBALS_BSD_HPP
+
+//
+// Defines Bsd specific flags. They are not available on other platforms.
+//
+#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
+ product(bool, UseOprofile, false, \
+ "enable support for Oprofile profiler") \
+ \
+ product(bool, UseBsdPosixThreadCPUClocks, true, \
+ "enable fast Bsd Posix clocks where available") \
+/* NB: The default value of UseBsdPosixThreadCPUClocks may be \
+ overridden in Arguments::parse_each_vm_init_arg. */ \
+ \
+ product(bool, UseHugeTLBFS, false, \
+ "Use MAP_HUGETLB for large pages") \
+ \
+ product(bool, UseSHM, false, \
+ "Use SYSV shared memory for large pages")
+
+//
+// Defines Bsd-specific default values. The flags are available on all
+// platforms, but they may have different default values on other platforms.
+//
+define_pd_global(bool, UseLargePages, false);
+define_pd_global(bool, UseLargePagesIndividualAllocation, false);
+define_pd_global(bool, UseOSErrorReporting, false);
+define_pd_global(bool, UseThreadPriorities, true) ;
+
+#endif // OS_BSD_VM_GLOBALS_BSD_HPP
diff --git a/src/os/bsd/vm/interfaceSupport_bsd.hpp b/src/os/bsd/vm/interfaceSupport_bsd.hpp
new file mode 100644
index 000000000..795bf4d16
--- /dev/null
+++ b/src/os/bsd/vm/interfaceSupport_bsd.hpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_INTERFACESUPPORT_BSD_HPP
+#define OS_BSD_VM_INTERFACESUPPORT_BSD_HPP
+
+// Contains inlined functions for class InterfaceSupport
+
+static inline void serialize_memory(JavaThread *thread) {
+ os::write_memory_serialize_page(thread);
+}
+
+#endif // OS_BSD_VM_INTERFACESUPPORT_BSD_HPP
diff --git a/src/os/bsd/vm/jsig.c b/src/os/bsd/vm/jsig.c
new file mode 100644
index 000000000..a8d98a084
--- /dev/null
+++ b/src/os/bsd/vm/jsig.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/* CopyrightVersion 1.2 */
+
+/* This is a special library that should be loaded before libc &
+ * libthread to interpose the signal handler installation functions:
+ * sigaction(), signal(), sigset().
+ * Used for signal-chaining. See RFE 4381843.
+ */
+
+#include <signal.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define MAXSIGNUM 32
+#define MASK(sig) ((unsigned int)1 << sig)
+
+static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */
+static unsigned int jvmsigs = 0; /* signals used by jvm */
+
+/* used to synchronize the installation of signal handlers */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_t tid = 0;
+
+typedef void (*sa_handler_t)(int);
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+typedef sa_handler_t (*signal_t)(int, sa_handler_t);
+typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
+
+static signal_t os_signal = 0; /* os's version of signal()/sigset() */
+static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
+
+static bool jvm_signal_installing = false;
+static bool jvm_signal_installed = false;
+
+static void signal_lock() {
+ pthread_mutex_lock(&mutex);
+ /* When the jvm is installing its set of signal handlers, threads
+ * other than the jvm thread should wait */
+ if (jvm_signal_installing) {
+ if (tid != pthread_self()) {
+ pthread_cond_wait(&cond, &mutex);
+ }
+ }
+}
+
+static void signal_unlock() {
+ pthread_mutex_unlock(&mutex);
+}
+
+static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
+ bool is_sigset) {
+ if (os_signal == NULL) {
+ if (!is_sigset) {
+ os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
+ } else {
+ os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
+ }
+ if (os_signal == NULL) {
+ printf("%s\n", dlerror());
+ exit(0);
+ }
+ }
+ return (*os_signal)(sig, disp);
+}
+
+static void save_signal_handler(int sig, sa_handler_t disp) {
+ sigset_t set;
+ sact[sig].sa_handler = disp;
+ sigemptyset(&set);
+ sact[sig].sa_mask = set;
+ sact[sig].sa_flags = 0;
+}
+
+static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
+ sa_handler_t oldhandler;
+ bool sigused;
+
+ signal_lock();
+
+ sigused = (MASK(sig) & jvmsigs) != 0;
+ if (jvm_signal_installed && sigused) {
+ /* jvm has installed its signal handler for this signal. */
+ /* Save the handler. Don't really install it. */
+ oldhandler = sact[sig].sa_handler;
+ save_signal_handler(sig, disp);
+
+ signal_unlock();
+ return oldhandler;
+ } else if (jvm_signal_installing) {
+ /* jvm is installing its signal handlers. Install the new
+ * handlers and save the old ones. jvm uses sigaction().
+ * Leave the piece here just in case. */
+ oldhandler = call_os_signal(sig, disp, is_sigset);
+ save_signal_handler(sig, oldhandler);
+
+ /* Record the signals used by jvm */
+ jvmsigs |= MASK(sig);
+
+ signal_unlock();
+ return oldhandler;
+ } else {
+ /* jvm has no relation with this signal (yet). Install the
+ * the handler. */
+ oldhandler = call_os_signal(sig, disp, is_sigset);
+
+ signal_unlock();
+ return oldhandler;
+ }
+}
+
+sa_handler_t signal(int sig, sa_handler_t disp) {
+ return set_signal(sig, disp, false);
+}
+
+sa_handler_t sigset(int sig, sa_handler_t disp) {
+ printf("sigset() is not supported by BSD");
+ exit(0);
+ }
+
+static int call_os_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact) {
+ if (os_sigaction == NULL) {
+ os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
+ if (os_sigaction == NULL) {
+ printf("%s\n", dlerror());
+ exit(0);
+ }
+ }
+ return (*os_sigaction)(sig, act, oact);
+}
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
+ int res;
+ bool sigused;
+ struct sigaction oldAct;
+
+ signal_lock();
+
+ sigused = (MASK(sig) & jvmsigs) != 0;
+ if (jvm_signal_installed && sigused) {
+ /* jvm has installed its signal handler for this signal. */
+ /* Save the handler. Don't really install it. */
+ if (oact != NULL) {
+ *oact = sact[sig];
+ }
+ if (act != NULL) {
+ sact[sig] = *act;
+ }
+
+ signal_unlock();
+ return 0;
+ } else if (jvm_signal_installing) {
+ /* jvm is installing its signal handlers. Install the new
+ * handlers and save the old ones. */
+ res = call_os_sigaction(sig, act, &oldAct);
+ sact[sig] = oldAct;
+ if (oact != NULL) {
+ *oact = oldAct;
+ }
+
+ /* Record the signals used by jvm */
+ jvmsigs |= MASK(sig);
+
+ signal_unlock();
+ return res;
+ } else {
+ /* jvm has no relation with this signal (yet). Install the
+ * the handler. */
+ res = call_os_sigaction(sig, act, oact);
+
+ signal_unlock();
+ return res;
+ }
+}
+
+/* The three functions for the jvm to call into */
+void JVM_begin_signal_setting() {
+ signal_lock();
+ jvm_signal_installing = true;
+ tid = pthread_self();
+ signal_unlock();
+}
+
+void JVM_end_signal_setting() {
+ signal_lock();
+ jvm_signal_installed = true;
+ jvm_signal_installing = false;
+ pthread_cond_broadcast(&cond);
+ signal_unlock();
+}
+
+struct sigaction *JVM_get_signal_action(int sig) {
+ /* Does race condition make sense here? */
+ if ((MASK(sig) & jvmsigs) != 0) {
+ return &sact[sig];
+ }
+ return NULL;
+}
diff --git a/src/os/bsd/vm/jvm_bsd.cpp b/src/os/bsd/vm/jvm_bsd.cpp
new file mode 100644
index 000000000..a82863135
--- /dev/null
+++ b/src/os/bsd/vm/jvm_bsd.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "prims/jvm.h"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/osThread.hpp"
+
+#include <signal.h>
+
+
+// sun.misc.Signal ///////////////////////////////////////////////////////////
+// Signal code is mostly copied from classic vm, signals_md.c 1.4 98/08/23
+/*
+ * This function is included primarily as a debugging aid. If Java is
+ * running in a console window, then pressing <CTRL-\\> will cause
+ * the current state of all active threads and monitors to be written
+ * to the console window.
+ */
+
+JVM_ENTRY_NO_ENV(void*, JVM_RegisterSignal(jint sig, void* handler))
+ // Copied from classic vm
+ // signals_md.c 1.4 98/08/23
+ void* newHandler = handler == (void *)2
+ ? os::user_handler()
+ : handler;
+ switch (sig) {
+ /* The following are already used by the VM. */
+ case INTERRUPT_SIGNAL:
+ case SIGFPE:
+ case SIGILL:
+ case SIGSEGV:
+
+ /* The following signal is used by the VM to dump thread stacks unless
+ ReduceSignalUsage is set, in which case the user is allowed to set
+ his own _native_ handler for this signal; thus, in either case,
+ we do not allow JVM_RegisterSignal to change the handler. */
+ case BREAK_SIGNAL:
+ return (void *)-1;
+
+ /* The following signals are used for Shutdown Hooks support. However, if
+ ReduceSignalUsage (-Xrs) is set, Shutdown Hooks must be invoked via
+ System.exit(), Java is not allowed to use these signals, and the the
+ user is allowed to set his own _native_ handler for these signals and
+ invoke System.exit() as needed. Terminator.setup() is avoiding
+ registration of these signals when -Xrs is present.
+ - If the HUP signal is ignored (from the nohup) command, then Java
+ is not allowed to use this signal.
+ */
+
+ case SHUTDOWN1_SIGNAL:
+ case SHUTDOWN2_SIGNAL:
+ case SHUTDOWN3_SIGNAL:
+ if (ReduceSignalUsage) return (void*)-1;
+ if (os::Bsd::is_sig_ignored(sig)) return (void*)1;
+ }
+
+ void* oldHandler = os::signal(sig, newHandler);
+ if (oldHandler == os::user_handler()) {
+ return (void *)2;
+ } else {
+ return oldHandler;
+ }
+JVM_END
+
+
+JVM_ENTRY_NO_ENV(jboolean, JVM_RaiseSignal(jint sig))
+ if (ReduceSignalUsage) {
+ // do not allow SHUTDOWN1_SIGNAL,SHUTDOWN2_SIGNAL,SHUTDOWN3_SIGNAL,
+ // BREAK_SIGNAL to be raised when ReduceSignalUsage is set, since
+ // no handler for them is actually registered in JVM or via
+ // JVM_RegisterSignal.
+ if (sig == SHUTDOWN1_SIGNAL || sig == SHUTDOWN2_SIGNAL ||
+ sig == SHUTDOWN3_SIGNAL || sig == BREAK_SIGNAL) {
+ return JNI_FALSE;
+ }
+ }
+ else if ((sig == SHUTDOWN1_SIGNAL || sig == SHUTDOWN2_SIGNAL ||
+ sig == SHUTDOWN3_SIGNAL) && os::Bsd::is_sig_ignored(sig)) {
+ // do not allow SHUTDOWN1_SIGNAL to be raised when SHUTDOWN1_SIGNAL
+ // is ignored, since no handler for them is actually registered in JVM
+ // or via JVM_RegisterSignal.
+ // This also applies for SHUTDOWN2_SIGNAL and SHUTDOWN3_SIGNAL
+ return JNI_FALSE;
+ }
+
+ os::signal_raise(sig);
+ return JNI_TRUE;
+JVM_END
+
+/*
+ All the defined signal names for Bsd.
+
+ NOTE that not all of these names are accepted by our Java implementation
+
+ Via an existing claim by the VM, sigaction restrictions, or
+ the "rules of Unix" some of these names will be rejected at runtime.
+ For example the VM sets up to handle USR1, sigaction returns EINVAL for
+ STOP, and Bsd simply doesn't allow catching of KILL.
+
+ Here are the names currently accepted by a user of sun.misc.Signal with
+ 1.4.1 (ignoring potential interaction with use of chaining, etc):
+
+ HUP, INT, TRAP, ABRT, IOT, BUS, USR2, PIPE, ALRM, TERM, STKFLT,
+ CLD, CHLD, CONT, TSTP, TTIN, TTOU, URG, XCPU, XFSZ, VTALRM, PROF,
+ WINCH, POLL, IO, PWR, SYS
+
+*/
+
+struct siglabel {
+ const char *name;
+ int number;
+};
+
+struct siglabel siglabels[] = {
+ /* derived from /usr/include/bits/signum.h on RH7.2 */
+ "HUP", SIGHUP, /* Hangup (POSIX). */
+ "INT", SIGINT, /* Interrupt (ANSI). */
+ "QUIT", SIGQUIT, /* Quit (POSIX). */
+ "ILL", SIGILL, /* Illegal instruction (ANSI). */
+ "TRAP", SIGTRAP, /* Trace trap (POSIX). */
+ "ABRT", SIGABRT, /* Abort (ANSI). */
+ "EMT", SIGEMT, /* EMT trap */
+ "FPE", SIGFPE, /* Floating-point exception (ANSI). */
+ "KILL", SIGKILL, /* Kill, unblockable (POSIX). */
+ "BUS", SIGBUS, /* BUS error (4.2 BSD). */
+ "SEGV", SIGSEGV, /* Segmentation violation (ANSI). */
+ "SYS", SIGSYS, /* Bad system call. Only on some Bsden! */
+ "PIPE", SIGPIPE, /* Broken pipe (POSIX). */
+ "ALRM", SIGALRM, /* Alarm clock (POSIX). */
+ "TERM", SIGTERM, /* Termination (ANSI). */
+ "URG", SIGURG, /* Urgent condition on socket (4.2 BSD). */
+ "STOP", SIGSTOP, /* Stop, unblockable (POSIX). */
+ "TSTP", SIGTSTP, /* Keyboard stop (POSIX). */
+ "CONT", SIGCONT, /* Continue (POSIX). */
+ "CHLD", SIGCHLD, /* Child status has changed (POSIX). */
+ "TTIN", SIGTTIN, /* Background read from tty (POSIX). */
+ "TTOU", SIGTTOU, /* Background write to tty (POSIX). */
+ "IO", SIGIO, /* I/O now possible (4.2 BSD). */
+ "XCPU", SIGXCPU, /* CPU limit exceeded (4.2 BSD). */
+ "XFSZ", SIGXFSZ, /* File size limit exceeded (4.2 BSD). */
+ "VTALRM", SIGVTALRM, /* Virtual alarm clock (4.2 BSD). */
+ "PROF", SIGPROF, /* Profiling alarm clock (4.2 BSD). */
+ "WINCH", SIGWINCH, /* Window size change (4.3 BSD, Sun). */
+ "INFO", SIGINFO, /* Information request. */
+ "USR1", SIGUSR1, /* User-defined signal 1 (POSIX). */
+ "USR2", SIGUSR2 /* User-defined signal 2 (POSIX). */
+ };
+
+JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
+
+ /* find and return the named signal's number */
+
+ for(uint i=0; i<ARRAY_SIZE(siglabels); i++)
+ if(!strcmp(name, siglabels[i].name))
+ return siglabels[i].number;
+
+ return -1;
+
+JVM_END
+
+// used by os::exception_name()
+extern bool signal_name(int signo, char* buf, size_t len) {
+ for(uint i = 0; i < ARRAY_SIZE(siglabels); i++) {
+ if (signo == siglabels[i].number) {
+ jio_snprintf(buf, len, "SIG%s", siglabels[i].name);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/os/bsd/vm/jvm_bsd.h b/src/os/bsd/vm/jvm_bsd.h
new file mode 100644
index 000000000..971d98ac4
--- /dev/null
+++ b/src/os/bsd/vm/jvm_bsd.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_JVM_BSD_H
+#define OS_BSD_VM_JVM_BSD_H
+
+/*
+// HotSpot integration note:
+//
+// This is derived from the JDK classic file:
+// "$JDK/src/solaris/javavm/export/jvm_md.h":15 (ver. 1.10 98/04/22)
+// All local includes have been commented out.
+*/
+
+
+#ifndef JVM_MD_H
+#define JVM_MD_H
+
+/*
+ * This file is currently collecting system-specific dregs for the
+ * JNI conversion, which should be sorted out later.
+ */
+
+#include <dirent.h> /* For DIR */
+#include <sys/param.h> /* For MAXPATHLEN */
+#include <unistd.h> /* For F_OK, R_OK, W_OK */
+
+#define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"}
+#define JNI_ONUNLOAD_SYMBOLS {"JNI_OnUnload"}
+#define JVM_ONLOAD_SYMBOLS {"JVM_OnLoad"}
+#define AGENT_ONLOAD_SYMBOLS {"Agent_OnLoad"}
+#define AGENT_ONUNLOAD_SYMBOLS {"Agent_OnUnload"}
+#define AGENT_ONATTACH_SYMBOLS {"Agent_OnAttach"}
+
+#define JNI_LIB_PREFIX "lib"
+#ifdef __APPLE__
+#define JNI_LIB_SUFFIX ".dylib"
+#else
+#define JNI_LIB_SUFFIX ".so"
+#endif
+
+// Hack: MAXPATHLEN is 4095 on some Bsd and 4096 on others. This may
+// cause problems if JVM and the rest of JDK are built on different
+// Bsd releases. Here we define JVM_MAXPATHLEN to be MAXPATHLEN + 1,
+// so buffers declared in VM are always >= 4096.
+#define JVM_MAXPATHLEN MAXPATHLEN + 1
+
+#define JVM_R_OK R_OK
+#define JVM_W_OK W_OK
+#define JVM_X_OK X_OK
+#define JVM_F_OK F_OK
+
+/*
+ * File I/O
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* O Flags */
+
+#define JVM_O_RDONLY O_RDONLY
+#define JVM_O_WRONLY O_WRONLY
+#define JVM_O_RDWR O_RDWR
+#define JVM_O_O_APPEND O_APPEND
+#define JVM_O_EXCL O_EXCL
+#define JVM_O_CREAT O_CREAT
+
+/* Signal definitions */
+
+#define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
+#define INTERRUPT_SIGNAL SIGUSR1 /* Interruptible I/O support. */
+#define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */
+#define SHUTDOWN2_SIGNAL SIGINT
+#define SHUTDOWN3_SIGNAL SIGTERM
+
+#ifndef SIGRTMIN
+#ifdef __OpenBSD__
+#define SIGRTMIN 1
+#else
+#define SIGRTMIN 33
+#endif
+#endif
+#ifndef SIGRTMAX
+#ifdef __OpenBSD__
+#define SIGRTMAX 31
+#else
+#define SIGRTMAX 63
+#endif
+#endif
+#endif /* JVM_MD_H */
+
+// Reconciliation History
+// jvm_solaris.h 1.6 99/06/22 16:38:47
+// End
+
+#endif // OS_BSD_VM_JVM_BSD_H
diff --git a/src/os/bsd/vm/mutex_bsd.cpp b/src/os/bsd/vm/mutex_bsd.cpp
new file mode 100644
index 000000000..f39482ea6
--- /dev/null
+++ b/src/os/bsd/vm/mutex_bsd.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "mutex_bsd.inline.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/mutex.hpp"
+#include "thread_bsd.inline.hpp"
+#include "utilities/events.hpp"
+
+// put OS-includes here
+# include <signal.h>
diff --git a/src/os/bsd/vm/mutex_bsd.inline.hpp b/src/os/bsd/vm/mutex_bsd.inline.hpp
new file mode 100644
index 000000000..f75267fb5
--- /dev/null
+++ b/src/os/bsd/vm/mutex_bsd.inline.hpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_MUTEX_BSD_INLINE_HPP
+#define OS_BSD_VM_MUTEX_BSD_INLINE_HPP
+
+#include "os_bsd.inline.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "thread_bsd.inline.hpp"
+
+
+// Reconciliation History
+// mutex_solaris.inline.hpp 1.5 99/06/22 16:38:49
+// End
+
+#endif // OS_BSD_VM_MUTEX_BSD_INLINE_HPP
diff --git a/src/os/bsd/vm/osThread_bsd.cpp b/src/os/bsd/vm/osThread_bsd.cpp
new file mode 100644
index 000000000..efac80376
--- /dev/null
+++ b/src/os/bsd/vm/osThread_bsd.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// no precompiled headers
+#include "runtime/atomic.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/vmThread.hpp"
+#ifdef TARGET_ARCH_x86
+# include "assembler_x86.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "assembler_sparc.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "assembler_zero.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "assembler_arm.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "assembler_ppc.inline.hpp"
+#endif
+
+
+void OSThread::pd_initialize() {
+ assert(this != NULL, "check");
+ _thread_id = NULL;
+ _pthread_id = NULL;
+ _siginfo = NULL;
+ _ucontext = NULL;
+ _expanding_stack = 0;
+ _alt_sig_stack = NULL;
+
+ sigemptyset(&_caller_sigmask);
+
+ _startThread_lock = new Monitor(Mutex::event, "startThread_lock", true);
+ assert(_startThread_lock !=NULL, "check");
+}
+
+void OSThread::pd_destroy() {
+ delete _startThread_lock;
+}
diff --git a/src/os/bsd/vm/osThread_bsd.hpp b/src/os/bsd/vm/osThread_bsd.hpp
new file mode 100644
index 000000000..82dd34fcb
--- /dev/null
+++ b/src/os/bsd/vm/osThread_bsd.hpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_OSTHREAD_BSD_HPP
+#define OS_BSD_VM_OSTHREAD_BSD_HPP
+
+ private:
+ int _thread_type;
+
+ public:
+
+ int thread_type() const {
+ return _thread_type;
+ }
+ void set_thread_type(int type) {
+ _thread_type = type;
+ }
+
+ private:
+
+#ifdef _ALLBSD_SOURCE
+ // _thread_id and _pthread_id are the same on BSD
+ // keep both to minimize code divergence in os_bsd.cpp
+ pthread_t _thread_id;
+ pthread_t _pthread_id;
+#else
+ // _thread_id is kernel thread id (similar to LWP id on Solaris). Each
+ // thread has a unique thread_id (BsdThreads or NPTL). It can be used
+ // to access /proc.
+ pid_t _thread_id;
+
+ // _pthread_id is the pthread id, which is used by library calls
+ // (e.g. pthread_kill).
+ pthread_t _pthread_id;
+#endif
+
+ sigset_t _caller_sigmask; // Caller's signal mask
+
+ public:
+
+ // Methods to save/restore caller's signal mask
+ sigset_t caller_sigmask() const { return _caller_sigmask; }
+ void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; }
+
+#ifdef _ALLBSD_SOURCE
+ pthread_t thread_id() const {
+ return _thread_id;
+ }
+#else
+ pid_t thread_id() const {
+ return _thread_id;
+ }
+#endif
+#ifndef PRODUCT
+ // Used for debugging, return a unique integer for each thread.
+ intptr_t thread_identifier() const { return (intptr_t)_pthread_id; }
+#endif
+#ifdef ASSERT
+ // We expect no reposition failures so kill vm if we get one.
+ //
+ bool valid_reposition_failure() {
+ return false;
+ }
+#endif // ASSERT
+#ifdef _ALLBSD_SOURCE
+ void set_thread_id(pthread_t id) {
+ _thread_id = id;
+ }
+#else
+ void set_thread_id(pid_t id) {
+ _thread_id = id;
+ }
+#endif
+ pthread_t pthread_id() const {
+ return _pthread_id;
+ }
+ void set_pthread_id(pthread_t tid) {
+ _pthread_id = tid;
+ }
+
+ // ***************************************************************
+ // suspension support.
+ // ***************************************************************
+
+public:
+ // flags that support signal based suspend/resume on Bsd are in a
+ // separate class to avoid confusion with many flags in OSThread that
+ // are used by VM level suspend/resume.
+ os::Bsd::SuspendResume sr;
+
+ // _ucontext and _siginfo are used by SR_handler() to save thread context,
+ // and they will later be used to walk the stack or reposition thread PC.
+ // If the thread is not suspended in SR_handler() (e.g. self suspend),
+ // the value in _ucontext is meaningless, so we must use the last Java
+ // frame information as the frame. This will mean that for threads
+ // that are parked on a mutex the profiler (and safepoint mechanism)
+ // will see the thread as if it were still in the Java frame. This
+ // not a problem for the profiler since the Java frame is a close
+ // enough result. For the safepoint mechanism when the give it the
+ // Java frame we are not at a point where the safepoint needs the
+ // frame to that accurate (like for a compiled safepoint) since we
+ // should be in a place where we are native and will block ourselves
+ // if we transition.
+private:
+ void* _siginfo;
+ ucontext_t* _ucontext;
+ int _expanding_stack; /* non zero if manually expanding stack */
+ address _alt_sig_stack; /* address of base of alternate signal stack */
+
+public:
+ void* siginfo() const { return _siginfo; }
+ void set_siginfo(void* ptr) { _siginfo = ptr; }
+ ucontext_t* ucontext() const { return _ucontext; }
+ void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; }
+ void set_expanding_stack(void) { _expanding_stack = 1; }
+ void clear_expanding_stack(void) { _expanding_stack = 0; }
+ int expanding_stack(void) { return _expanding_stack; }
+
+ void set_alt_sig_stack(address val) { _alt_sig_stack = val; }
+ address alt_sig_stack(void) { return _alt_sig_stack; }
+
+private:
+ Monitor* _startThread_lock; // sync parent and child in thread creation
+
+public:
+
+ Monitor* startThread_lock() const {
+ return _startThread_lock;
+ }
+
+ // ***************************************************************
+ // Platform dependent initialization and cleanup
+ // ***************************************************************
+
+private:
+
+ void pd_initialize();
+ void pd_destroy();
+
+// Reconciliation History
+// osThread_solaris.hpp 1.24 99/08/27 13:11:54
+// End
+
+#endif // OS_BSD_VM_OSTHREAD_BSD_HPP
diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp
new file mode 100644
index 000000000..b783de69f
--- /dev/null
+++ b/src/os/bsd/vm/os_bsd.cpp
@@ -0,0 +1,5709 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// no precompiled headers
+#include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "code/icBuffer.hpp"
+#include "code/vtableStubs.hpp"
+#include "compiler/compileBroker.hpp"
+#include "interpreter/interpreter.hpp"
+#include "jvm_bsd.h"
+#include "memory/allocation.inline.hpp"
+#include "memory/filemap.hpp"
+#include "mutex_bsd.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "os_share_bsd.hpp"
+#include "prims/jniFastGetField.hpp"
+#include "prims/jvm.h"
+#include "prims/jvm_misc.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/extendedPC.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/java.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/perfMemory.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/statSampler.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/threadCritical.hpp"
+#include "runtime/timer.hpp"
+#include "services/attachListener.hpp"
+#include "services/runtimeService.hpp"
+#include "thread_bsd.inline.hpp"
+#include "utilities/decoder.hpp"
+#include "utilities/defaultStream.hpp"
+#include "utilities/events.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/vmError.hpp"
+#ifdef TARGET_ARCH_x86
+# include "assembler_x86.inline.hpp"
+# include "nativeInst_x86.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "assembler_sparc.inline.hpp"
+# include "nativeInst_sparc.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "assembler_zero.inline.hpp"
+# include "nativeInst_zero.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "assembler_arm.inline.hpp"
+# include "nativeInst_arm.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "assembler_ppc.inline.hpp"
+# include "nativeInst_ppc.hpp"
+#endif
+#ifdef COMPILER1
+#include "c1/c1_Runtime1.hpp"
+#endif
+#ifdef COMPILER2
+#include "opto/runtime.hpp"
+#endif
+
+// put OS-includes here
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+# include <sys/select.h>
+# include <pthread.h>
+# include <signal.h>
+# include <errno.h>
+# include <dlfcn.h>
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/resource.h>
+# include <pthread.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <sys/times.h>
+# include <sys/utsname.h>
+# include <sys/socket.h>
+# include <sys/wait.h>
+# include <time.h>
+# include <pwd.h>
+# include <poll.h>
+# include <semaphore.h>
+# include <fcntl.h>
+# include <string.h>
+#ifdef _ALLBSD_SOURCE
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#else
+# include <syscall.h>
+# include <sys/sysinfo.h>
+# include <gnu/libc-version.h>
+#endif
+# include <sys/ipc.h>
+# include <sys/shm.h>
+#ifndef __APPLE__
+# include <link.h>
+#endif
+# include <stdint.h>
+# include <inttypes.h>
+# include <sys/ioctl.h>
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+# include <elf.h>
+#endif
+
+#ifdef __APPLE__
+#include <mach/mach.h> // semaphore_* API
+#include <mach-o/dyld.h>
+#endif
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#define MAX_PATH (2 * K)
+
+// for timer info max values which include all bits
+#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
+#define SEC_IN_NANOSECS 1000000000LL
+
+#define LARGEPAGES_BIT (1 << 6)
+////////////////////////////////////////////////////////////////////////////////
+// global variables
+julong os::Bsd::_physical_memory = 0;
+
+#ifndef _ALLBSD_SOURCE
+address os::Bsd::_initial_thread_stack_bottom = NULL;
+uintptr_t os::Bsd::_initial_thread_stack_size = 0;
+#endif
+
+int (*os::Bsd::_clock_gettime)(clockid_t, struct timespec *) = NULL;
+#ifndef _ALLBSD_SOURCE
+int (*os::Bsd::_pthread_getcpuclockid)(pthread_t, clockid_t *) = NULL;
+Mutex* os::Bsd::_createThread_lock = NULL;
+#endif
+pthread_t os::Bsd::_main_thread;
+int os::Bsd::_page_size = -1;
+#ifndef _ALLBSD_SOURCE
+bool os::Bsd::_is_floating_stack = false;
+bool os::Bsd::_is_NPTL = false;
+bool os::Bsd::_supports_fast_thread_cpu_time = false;
+const char * os::Bsd::_glibc_version = NULL;
+const char * os::Bsd::_libpthread_version = NULL;
+#endif
+
+static jlong initial_time_count=0;
+
+static int clock_tics_per_sec = 100;
+
+// For diagnostics to print a message once. see run_periodic_checks
+static sigset_t check_signal_done;
+static bool check_signals = true;;
+
+static pid_t _initial_pid = 0;
+
+/* Signal number used to suspend/resume a thread */
+
+/* do not use any signal number less than SIGSEGV, see 4355769 */
+static int SR_signum = SIGUSR2;
+sigset_t SR_sigset;
+
+
+////////////////////////////////////////////////////////////////////////////////
+// utility functions
+
+static int SR_initialize();
+static int SR_finalize();
+
+julong os::available_memory() {
+ return Bsd::available_memory();
+}
+
+julong os::Bsd::available_memory() {
+#ifdef _ALLBSD_SOURCE
+ // XXXBSD: this is just a stopgap implementation
+ return physical_memory() >> 2;
+#else
+ // values in struct sysinfo are "unsigned long"
+ struct sysinfo si;
+ sysinfo(&si);
+
+ return (julong)si.freeram * si.mem_unit;
+#endif
+}
+
+julong os::physical_memory() {
+ return Bsd::physical_memory();
+}
+
+julong os::allocatable_physical_memory(julong size) {
+#ifdef _LP64
+ return size;
+#else
+ julong result = MIN2(size, (julong)3800*M);
+ if (!is_allocatable(result)) {
+ // See comments under solaris for alignment considerations
+ julong reasonable_size = (julong)2*G - 2 * os::vm_page_size();
+ result = MIN2(size, reasonable_size);
+ }
+ return result;
+#endif // _LP64
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// environment support
+
+bool os::getenv(const char* name, char* buf, int len) {
+ const char* val = ::getenv(name);
+ if (val != NULL && strlen(val) < (size_t)len) {
+ strcpy(buf, val);
+ return true;
+ }
+ if (len > 0) buf[0] = 0; // return a null string
+ return false;
+}
+
+
+// Return true if user is running as root.
+
+bool os::have_special_privileges() {
+ static bool init = false;
+ static bool privileges = false;
+ if (!init) {
+ privileges = (getuid() != geteuid()) || (getgid() != getegid());
+ init = true;
+ }
+ return privileges;
+}
+
+
+#ifndef _ALLBSD_SOURCE
+#ifndef SYS_gettid
+// i386: 224, ia64: 1105, amd64: 186, sparc 143
+#ifdef __ia64__
+#define SYS_gettid 1105
+#elif __i386__
+#define SYS_gettid 224
+#elif __amd64__
+#define SYS_gettid 186
+#elif __sparc__
+#define SYS_gettid 143
+#else
+#error define gettid for the arch
+#endif
+#endif
+#endif
+
+// Cpu architecture string
+#if defined(ZERO)
+static char cpu_arch[] = ZERO_LIBARCH;
+#elif defined(IA64)
+static char cpu_arch[] = "ia64";
+#elif defined(IA32)
+static char cpu_arch[] = "i386";
+#elif defined(AMD64)
+static char cpu_arch[] = "amd64";
+#elif defined(ARM)
+static char cpu_arch[] = "arm";
+#elif defined(PPC)
+static char cpu_arch[] = "ppc";
+#elif defined(SPARC)
+# ifdef _LP64
+static char cpu_arch[] = "sparcv9";
+# else
+static char cpu_arch[] = "sparc";
+# endif
+#else
+#error Add appropriate cpu_arch setting
+#endif
+
+
+#ifndef _ALLBSD_SOURCE
+// pid_t gettid()
+//
+// Returns the kernel thread id of the currently running thread. Kernel
+// thread id is used to access /proc.
+//
+// (Note that getpid() on BsdThreads returns kernel thread id too; but
+// on NPTL, it returns the same pid for all threads, as required by POSIX.)
+//
+pid_t os::Bsd::gettid() {
+ int rslt = syscall(SYS_gettid);
+ if (rslt == -1) {
+ // old kernel, no NPTL support
+ return getpid();
+ } else {
+ return (pid_t)rslt;
+ }
+}
+
+// Most versions of bsd have a bug where the number of processors are
+// determined by looking at the /proc file system. In a chroot environment,
+// the system call returns 1. This causes the VM to act as if it is
+// a single processor and elide locking (see is_MP() call).
+static bool unsafe_chroot_detected = false;
+static const char *unstable_chroot_error = "/proc file system not found.\n"
+ "Java may be unstable running multithreaded in a chroot "
+ "environment on Bsd when /proc filesystem is not mounted.";
+#endif
+
+#ifdef _ALLBSD_SOURCE
+void os::Bsd::initialize_system_info() {
+ int mib[2];
+ size_t len;
+ int cpu_val;
+ u_long mem_val;
+
+ /* get processors count via hw.ncpus sysctl */
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(cpu_val);
+ if (sysctl(mib, 2, &cpu_val, &len, NULL, 0) != -1 && cpu_val >= 1) {
+ set_processor_count(cpu_val);
+ }
+ else {
+ set_processor_count(1); // fallback
+ }
+
+ /* get physical memory via hw.usermem sysctl (hw.usermem is used
+ * instead of hw.physmem because we need size of allocatable memory
+ */
+ mib[0] = CTL_HW;
+ mib[1] = HW_USERMEM;
+ len = sizeof(mem_val);
+ if (sysctl(mib, 2, &mem_val, &len, NULL, 0) != -1)
+ _physical_memory = mem_val;
+ else
+ _physical_memory = 256*1024*1024; // fallback (XXXBSD?)
+
+#ifdef __OpenBSD__
+ {
+ // limit _physical_memory memory view on OpenBSD since
+ // datasize rlimit restricts us anyway.
+ struct rlimit limits;
+ getrlimit(RLIMIT_DATA, &limits);
+ _physical_memory = MIN2(_physical_memory, (julong)limits.rlim_cur);
+ }
+#endif
+}
+#else
+void os::Bsd::initialize_system_info() {
+ set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
+ if (processor_count() == 1) {
+ pid_t pid = os::Bsd::gettid();
+ char fname[32];
+ jio_snprintf(fname, sizeof(fname), "/proc/%d", pid);
+ FILE *fp = fopen(fname, "r");
+ if (fp == NULL) {
+ unsafe_chroot_detected = true;
+ } else {
+ fclose(fp);
+ }
+ }
+ _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
+ assert(processor_count() > 0, "bsd error");
+}
+#endif
+
+void os::init_system_properties_values() {
+// char arch[12];
+// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch));
+
+ // The next steps are taken in the product version:
+ //
+ // Obtain the JAVA_HOME value from the location of libjvm[_g].so.
+ // This library should be located at:
+ // <JAVA_HOME>/jre/lib/<arch>/{client|server}/libjvm[_g].so.
+ //
+ // If "/jre/lib/" appears at the right place in the path, then we
+ // assume libjvm[_g].so is installed in a JDK and we use this path.
+ //
+ // Otherwise exit with message: "Could not create the Java virtual machine."
+ //
+ // The following extra steps are taken in the debugging version:
+ //
+ // If "/jre/lib/" does NOT appear at the right place in the path
+ // instead of exit check for $JAVA_HOME environment variable.
+ //
+ // If it is defined and we are able to locate $JAVA_HOME/jre/lib/<arch>,
+ // then we append a fake suffix "hotspot/libjvm[_g].so" to this path so
+ // it looks like libjvm[_g].so is installed there
+ // <JAVA_HOME>/jre/lib/<arch>/hotspot/libjvm[_g].so.
+ //
+ // Otherwise exit.
+ //
+ // Important note: if the location of libjvm.so changes this
+ // code needs to be changed accordingly.
+
+ // The next few definitions allow the code to be verbatim:
+#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n))
+#define getenv(n) ::getenv(n)
+
+/*
+ * See ld(1):
+ * The linker uses the following search paths to locate required
+ * shared libraries:
+ * 1: ...
+ * ...
+ * 7: The default directories, normally /lib and /usr/lib.
+ */
+#ifndef DEFAULT_LIBPATH
+#define DEFAULT_LIBPATH "/lib:/usr/lib"
+#endif
+
+#define EXTENSIONS_DIR "/lib/ext"
+#define ENDORSED_DIR "/lib/endorsed"
+#define REG_DIR "/usr/java/packages"
+
+ {
+ /* sysclasspath, java_home, dll_dir */
+ {
+ char *home_path;
+ char *dll_path;
+ char *pslash;
+ char buf[MAXPATHLEN];
+ os::jvm_path(buf, sizeof(buf));
+
+ // Found the full path to libjvm.so.
+ // Now cut the path to <java_home>/jre if we can.
+ *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */
+ pslash = strrchr(buf, '/');
+ if (pslash != NULL)
+ *pslash = '\0'; /* get rid of /{client|server|hotspot} */
+ dll_path = malloc(strlen(buf) + 1);
+ if (dll_path == NULL)
+ return;
+ strcpy(dll_path, buf);
+ Arguments::set_dll_dir(dll_path);
+
+ if (pslash != NULL) {
+ pslash = strrchr(buf, '/');
+ if (pslash != NULL) {
+ *pslash = '\0'; /* get rid of /<arch> */
+ pslash = strrchr(buf, '/');
+ if (pslash != NULL)
+ *pslash = '\0'; /* get rid of /lib */
+ }
+ }
+
+ home_path = malloc(strlen(buf) + 1);
+ if (home_path == NULL)
+ return;
+ strcpy(home_path, buf);
+ Arguments::set_java_home(home_path);
+
+ if (!set_boot_path('/', ':'))
+ return;
+ }
+
+ /*
+ * Where to look for native libraries
+ *
+ * Note: Due to a legacy implementation, most of the library path
+ * is set in the launcher. This was to accomodate linking restrictions
+ * on legacy Bsd implementations (which are no longer supported).
+ * Eventually, all the library path setting will be done here.
+ *
+ * However, to prevent the proliferation of improperly built native
+ * libraries, the new path component /usr/java/packages is added here.
+ * Eventually, all the library path setting will be done here.
+ */
+ {
+ char *ld_library_path;
+
+ /*
+ * Construct the invariant part of ld_library_path. Note that the
+ * space for the colon and the trailing null are provided by the
+ * nulls included by the sizeof operator (so actually we allocate
+ * a byte more than necessary).
+ */
+ ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") +
+ strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH));
+ sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch);
+
+ /*
+ * Get the user setting of LD_LIBRARY_PATH, and prepended it. It
+ * should always exist (until the legacy problem cited above is
+ * addressed).
+ */
+#ifdef __APPLE__
+ char *v = getenv("DYLD_LIBRARY_PATH");
+#else
+ char *v = getenv("LD_LIBRARY_PATH");
+#endif
+ if (v != NULL) {
+ char *t = ld_library_path;
+ /* That's +1 for the colon and +1 for the trailing '\0' */
+ ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1);
+ sprintf(ld_library_path, "%s:%s", v, t);
+ }
+ Arguments::set_library_path(ld_library_path);
+ }
+
+ /*
+ * Extensions directories.
+ *
+ * Note that the space for the colon and the trailing null are provided
+ * by the nulls included by the sizeof operator (so actually one byte more
+ * than necessary is allocated).
+ */
+ {
+ char *buf = malloc(strlen(Arguments::get_java_home()) +
+ sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR));
+ sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR,
+ Arguments::get_java_home());
+ Arguments::set_ext_dirs(buf);
+ }
+
+ /* Endorsed standards default directory. */
+ {
+ char * buf;
+ buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR));
+ sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
+ Arguments::set_endorsed_dirs(buf);
+ }
+ }
+
+#undef malloc
+#undef getenv
+#undef EXTENSIONS_DIR
+#undef ENDORSED_DIR
+
+ // Done
+ return;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// breakpoint support
+
+void os::breakpoint() {
+ BREAKPOINT;
+}
+
+extern "C" void breakpoint() {
+ // use debugger to set breakpoint here
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// signal support
+
+debug_only(static bool signal_sets_initialized = false);
+static sigset_t unblocked_sigs, vm_sigs, allowdebug_blocked_sigs;
+
+bool os::Bsd::is_sig_ignored(int sig) {
+ struct sigaction oact;
+ sigaction(sig, (struct sigaction*)NULL, &oact);
+ void* ohlr = oact.sa_sigaction ? CAST_FROM_FN_PTR(void*, oact.sa_sigaction)
+ : CAST_FROM_FN_PTR(void*, oact.sa_handler);
+ if (ohlr == CAST_FROM_FN_PTR(void*, SIG_IGN))
+ return true;
+ else
+ return false;
+}
+
+void os::Bsd::signal_sets_init() {
+ // Should also have an assertion stating we are still single-threaded.
+ assert(!signal_sets_initialized, "Already initialized");
+ // Fill in signals that are necessarily unblocked for all threads in
+ // the VM. Currently, we unblock the following signals:
+ // SHUTDOWN{1,2,3}_SIGNAL: for shutdown hooks support (unless over-ridden
+ // by -Xrs (=ReduceSignalUsage));
+ // BREAK_SIGNAL which is unblocked only by the VM thread and blocked by all
+ // other threads. The "ReduceSignalUsage" boolean tells us not to alter
+ // the dispositions or masks wrt these signals.
+ // Programs embedding the VM that want to use the above signals for their
+ // own purposes must, at this time, use the "-Xrs" option to prevent
+ // interference with shutdown hooks and BREAK_SIGNAL thread dumping.
+ // (See bug 4345157, and other related bugs).
+ // In reality, though, unblocking these signals is really a nop, since
+ // these signals are not blocked by default.
+ sigemptyset(&unblocked_sigs);
+ sigemptyset(&allowdebug_blocked_sigs);
+ sigaddset(&unblocked_sigs, SIGILL);
+ sigaddset(&unblocked_sigs, SIGSEGV);
+ sigaddset(&unblocked_sigs, SIGBUS);
+ sigaddset(&unblocked_sigs, SIGFPE);
+ sigaddset(&unblocked_sigs, SR_signum);
+
+ if (!ReduceSignalUsage) {
+ if (!os::Bsd::is_sig_ignored(SHUTDOWN1_SIGNAL)) {
+ sigaddset(&unblocked_sigs, SHUTDOWN1_SIGNAL);
+ sigaddset(&allowdebug_blocked_sigs, SHUTDOWN1_SIGNAL);
+ }
+ if (!os::Bsd::is_sig_ignored(SHUTDOWN2_SIGNAL)) {
+ sigaddset(&unblocked_sigs, SHUTDOWN2_SIGNAL);
+ sigaddset(&allowdebug_blocked_sigs, SHUTDOWN2_SIGNAL);
+ }
+ if (!os::Bsd::is_sig_ignored(SHUTDOWN3_SIGNAL)) {
+ sigaddset(&unblocked_sigs, SHUTDOWN3_SIGNAL);
+ sigaddset(&allowdebug_blocked_sigs, SHUTDOWN3_SIGNAL);
+ }
+ }
+ // Fill in signals that are blocked by all but the VM thread.
+ sigemptyset(&vm_sigs);
+ if (!ReduceSignalUsage)
+ sigaddset(&vm_sigs, BREAK_SIGNAL);
+ debug_only(signal_sets_initialized = true);
+
+}
+
+// These are signals that are unblocked while a thread is running Java.
+// (For some reason, they get blocked by default.)
+sigset_t* os::Bsd::unblocked_signals() {
+ assert(signal_sets_initialized, "Not initialized");
+ return &unblocked_sigs;
+}
+
+// These are the signals that are blocked while a (non-VM) thread is
+// running Java. Only the VM thread handles these signals.
+sigset_t* os::Bsd::vm_signals() {
+ assert(signal_sets_initialized, "Not initialized");
+ return &vm_sigs;
+}
+
+// These are signals that are blocked during cond_wait to allow debugger in
+sigset_t* os::Bsd::allowdebug_blocked_signals() {
+ assert(signal_sets_initialized, "Not initialized");
+ return &allowdebug_blocked_sigs;
+}
+
+void os::Bsd::hotspot_sigmask(Thread* thread) {
+
+ //Save caller's signal mask before setting VM signal mask
+ sigset_t caller_sigmask;
+ pthread_sigmask(SIG_BLOCK, NULL, &caller_sigmask);
+
+ OSThread* osthread = thread->osthread();
+ osthread->set_caller_sigmask(caller_sigmask);
+
+ pthread_sigmask(SIG_UNBLOCK, os::Bsd::unblocked_signals(), NULL);
+
+ if (!ReduceSignalUsage) {
+ if (thread->is_VM_thread()) {
+ // Only the VM thread handles BREAK_SIGNAL ...
+ pthread_sigmask(SIG_UNBLOCK, vm_signals(), NULL);
+ } else {
+ // ... all other threads block BREAK_SIGNAL
+ pthread_sigmask(SIG_BLOCK, vm_signals(), NULL);
+ }
+ }
+}
+
+#ifndef _ALLBSD_SOURCE
+//////////////////////////////////////////////////////////////////////////////
+// detecting pthread library
+
+void os::Bsd::libpthread_init() {
+ // Save glibc and pthread version strings. Note that _CS_GNU_LIBC_VERSION
+ // and _CS_GNU_LIBPTHREAD_VERSION are supported in glibc >= 2.3.2. Use a
+ // generic name for earlier versions.
+ // Define macros here so we can build HotSpot on old systems.
+# ifndef _CS_GNU_LIBC_VERSION
+# define _CS_GNU_LIBC_VERSION 2
+# endif
+# ifndef _CS_GNU_LIBPTHREAD_VERSION
+# define _CS_GNU_LIBPTHREAD_VERSION 3
+# endif
+
+ size_t n = confstr(_CS_GNU_LIBC_VERSION, NULL, 0);
+ if (n > 0) {
+ char *str = (char *)malloc(n);
+ confstr(_CS_GNU_LIBC_VERSION, str, n);
+ os::Bsd::set_glibc_version(str);
+ } else {
+ // _CS_GNU_LIBC_VERSION is not supported, try gnu_get_libc_version()
+ static char _gnu_libc_version[32];
+ jio_snprintf(_gnu_libc_version, sizeof(_gnu_libc_version),
+ "glibc %s %s", gnu_get_libc_version(), gnu_get_libc_release());
+ os::Bsd::set_glibc_version(_gnu_libc_version);
+ }
+
+ n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
+ if (n > 0) {
+ char *str = (char *)malloc(n);
+ confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
+ // Vanilla RH-9 (glibc 2.3.2) has a bug that confstr() always tells
+ // us "NPTL-0.29" even we are running with BsdThreads. Check if this
+ // is the case. BsdThreads has a hard limit on max number of threads.
+ // So sysconf(_SC_THREAD_THREADS_MAX) will return a positive value.
+ // On the other hand, NPTL does not have such a limit, sysconf()
+ // will return -1 and errno is not changed. Check if it is really NPTL.
+ if (strcmp(os::Bsd::glibc_version(), "glibc 2.3.2") == 0 &&
+ strstr(str, "NPTL") &&
+ sysconf(_SC_THREAD_THREADS_MAX) > 0) {
+ free(str);
+ os::Bsd::set_libpthread_version("bsdthreads");
+ } else {
+ os::Bsd::set_libpthread_version(str);
+ }
+ } else {
+ // glibc before 2.3.2 only has BsdThreads.
+ os::Bsd::set_libpthread_version("bsdthreads");
+ }
+
+ if (strstr(libpthread_version(), "NPTL")) {
+ os::Bsd::set_is_NPTL();
+ } else {
+ os::Bsd::set_is_BsdThreads();
+ }
+
+ // BsdThreads have two flavors: floating-stack mode, which allows variable
+ // stack size; and fixed-stack mode. NPTL is always floating-stack.
+ if (os::Bsd::is_NPTL() || os::Bsd::supports_variable_stack_size()) {
+ os::Bsd::set_is_floating_stack();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// thread stack
+
+// Force Bsd kernel to expand current thread stack. If "bottom" is close
+// to the stack guard, caller should block all signals.
+//
+// MAP_GROWSDOWN:
+// A special mmap() flag that is used to implement thread stacks. It tells
+// kernel that the memory region should extend downwards when needed. This
+// allows early versions of BsdThreads to only mmap the first few pages
+// when creating a new thread. Bsd kernel will automatically expand thread
+// stack as needed (on page faults).
+//
+// However, because the memory region of a MAP_GROWSDOWN stack can grow on
+// demand, if a page fault happens outside an already mapped MAP_GROWSDOWN
+// region, it's hard to tell if the fault is due to a legitimate stack
+// access or because of reading/writing non-exist memory (e.g. buffer
+// overrun). As a rule, if the fault happens below current stack pointer,
+// Bsd kernel does not expand stack, instead a SIGSEGV is sent to the
+// application (see Bsd kernel fault.c).
+//
+// This Bsd feature can cause SIGSEGV when VM bangs thread stack for
+// stack overflow detection.
+//
+// Newer version of BsdThreads (since glibc-2.2, or, RH-7.x) and NPTL do
+// not use this flag. However, the stack of initial thread is not created
+// by pthread, it is still MAP_GROWSDOWN. Also it's possible (though
+// unlikely) that user code can create a thread with MAP_GROWSDOWN stack
+// and then attach the thread to JVM.
+//
+// To get around the problem and allow stack banging on Bsd, we need to
+// manually expand thread stack after receiving the SIGSEGV.
+//
+// There are two ways to expand thread stack to address "bottom", we used
+// both of them in JVM before 1.5:
+// 1. adjust stack pointer first so that it is below "bottom", and then
+// touch "bottom"
+// 2. mmap() the page in question
+//
+// Now alternate signal stack is gone, it's harder to use 2. For instance,
+// if current sp is already near the lower end of page 101, and we need to
+// call mmap() to map page 100, it is possible that part of the mmap() frame
+// will be placed in page 100. When page 100 is mapped, it is zero-filled.
+// That will destroy the mmap() frame and cause VM to crash.
+//
+// The following code works by adjusting sp first, then accessing the "bottom"
+// page to force a page fault. Bsd kernel will then automatically expand the
+// stack mapping.
+//
+// _expand_stack_to() assumes its frame size is less than page size, which
+// should always be true if the function is not inlined.
+
+#if __GNUC__ < 3 // gcc 2.x does not support noinline attribute
+#define NOINLINE
+#else
+#define NOINLINE __attribute__ ((noinline))
+#endif
+
+static void _expand_stack_to(address bottom) NOINLINE;
+
+static void _expand_stack_to(address bottom) {
+ address sp;
+ size_t size;
+ volatile char *p;
+
+ // Adjust bottom to point to the largest address within the same page, it
+ // gives us a one-page buffer if alloca() allocates slightly more memory.
+ bottom = (address)align_size_down((uintptr_t)bottom, os::Bsd::page_size());
+ bottom += os::Bsd::page_size() - 1;
+
+ // sp might be slightly above current stack pointer; if that's the case, we
+ // will alloca() a little more space than necessary, which is OK. Don't use
+ // os::current_stack_pointer(), as its result can be slightly below current
+ // stack pointer, causing us to not alloca enough to reach "bottom".
+ sp = (address)&sp;
+
+ if (sp > bottom) {
+ size = sp - bottom;
+ p = (volatile char *)alloca(size);
+ assert(p != NULL && p <= (volatile char *)bottom, "alloca problem?");
+ p[0] = '\0';
+ }
+}
+
+bool os::Bsd::manually_expand_stack(JavaThread * t, address addr) {
+ assert(t!=NULL, "just checking");
+ assert(t->osthread()->expanding_stack(), "expand should be set");
+ assert(t->stack_base() != NULL, "stack_base was not initialized");
+
+ if (addr < t->stack_base() && addr >= t->stack_yellow_zone_base()) {
+ sigset_t mask_all, old_sigset;
+ sigfillset(&mask_all);
+ pthread_sigmask(SIG_SETMASK, &mask_all, &old_sigset);
+ _expand_stack_to(addr);
+ pthread_sigmask(SIG_SETMASK, &old_sigset, NULL);
+ return true;
+ }
+ return false;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+// create new thread
+
+static address highest_vm_reserved_address();
+
+// check if it's safe to start a new thread
+static bool _thread_safety_check(Thread* thread) {
+#ifdef _ALLBSD_SOURCE
+ return true;
+#else
+ if (os::Bsd::is_BsdThreads() && !os::Bsd::is_floating_stack()) {
+ // Fixed stack BsdThreads (SuSE Bsd/x86, and some versions of Redhat)
+ // Heap is mmap'ed at lower end of memory space. Thread stacks are
+ // allocated (MAP_FIXED) from high address space. Every thread stack
+ // occupies a fixed size slot (usually 2Mbytes, but user can change
+ // it to other values if they rebuild BsdThreads).
+ //
+ // Problem with MAP_FIXED is that mmap() can still succeed even part of
+ // the memory region has already been mmap'ed. That means if we have too
+ // many threads and/or very large heap, eventually thread stack will
+ // collide with heap.
+ //
+ // Here we try to prevent heap/stack collision by comparing current
+ // stack bottom with the highest address that has been mmap'ed by JVM
+ // plus a safety margin for memory maps created by native code.
+ //
+ // This feature can be disabled by setting ThreadSafetyMargin to 0
+ //
+ if (ThreadSafetyMargin > 0) {
+ address stack_bottom = os::current_stack_base() - os::current_stack_size();
+
+ // not safe if our stack extends below the safety margin
+ return stack_bottom - ThreadSafetyMargin >= highest_vm_reserved_address();
+ } else {
+ return true;
+ }
+ } else {
+ // Floating stack BsdThreads or NPTL:
+ // Unlike fixed stack BsdThreads, thread stacks are not MAP_FIXED. When
+ // there's not enough space left, pthread_create() will fail. If we come
+ // here, that means enough space has been reserved for stack.
+ return true;
+ }
+#endif
+}
+
+// Thread start routine for all newly created threads
+static void *java_start(Thread *thread) {
+ // Try to randomize the cache line index of hot stack frames.
+ // This helps when threads of the same stack traces evict each other's
+ // cache lines. The threads can be either from the same JVM instance, or
+ // from different JVM instances. The benefit is especially true for
+ // processors with hyperthreading technology.
+ static int counter = 0;
+ int pid = os::current_process_id();
+ alloca(((pid ^ counter++) & 7) * 128);
+
+ ThreadLocalStorage::set_thread(thread);
+
+ OSThread* osthread = thread->osthread();
+ Monitor* sync = osthread->startThread_lock();
+
+ // non floating stack BsdThreads needs extra check, see above
+ if (!_thread_safety_check(thread)) {
+ // notify parent thread
+ MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
+ osthread->set_state(ZOMBIE);
+ sync->notify_all();
+ return NULL;
+ }
+
+#ifdef _ALLBSD_SOURCE
+ // thread_id is pthread_id on BSD
+ osthread->set_thread_id(::pthread_self());
+#else
+ // thread_id is kernel thread id (similar to Solaris LWP id)
+ osthread->set_thread_id(os::Bsd::gettid());
+
+ if (UseNUMA) {
+ int lgrp_id = os::numa_get_group_id();
+ if (lgrp_id != -1) {
+ thread->set_lgrp_id(lgrp_id);
+ }
+ }
+#endif
+ // initialize signal mask for this thread
+ os::Bsd::hotspot_sigmask(thread);
+
+ // initialize floating point control register
+ os::Bsd::init_thread_fpu_state();
+
+ // handshaking with parent thread
+ {
+ MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
+
+ // notify parent thread
+ osthread->set_state(INITIALIZED);
+ sync->notify_all();
+
+ // wait until os::start_thread()
+ while (osthread->get_state() == INITIALIZED) {
+ sync->wait(Mutex::_no_safepoint_check_flag);
+ }
+ }
+
+ // call one more level start routine
+ thread->run();
+
+ return 0;
+}
+
+bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
+ assert(thread->osthread() == NULL, "caller responsible");
+
+ // Allocate the OSThread object
+ OSThread* osthread = new OSThread(NULL, NULL);
+ if (osthread == NULL) {
+ return false;
+ }
+
+ // set the correct thread state
+ osthread->set_thread_type(thr_type);
+
+ // Initial state is ALLOCATED but not INITIALIZED
+ osthread->set_state(ALLOCATED);
+
+ thread->set_osthread(osthread);
+
+ // init thread attributes
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ // stack size
+ if (os::Bsd::supports_variable_stack_size()) {
+ // calculate stack size if it's not specified by caller
+ if (stack_size == 0) {
+ stack_size = os::Bsd::default_stack_size(thr_type);
+
+ switch (thr_type) {
+ case os::java_thread:
+ // Java threads use ThreadStackSize which default value can be
+ // changed with the flag -Xss
+ assert (JavaThread::stack_size_at_create() > 0, "this should be set");
+ stack_size = JavaThread::stack_size_at_create();
+ break;
+ case os::compiler_thread:
+ if (CompilerThreadStackSize > 0) {
+ stack_size = (size_t)(CompilerThreadStackSize * K);
+ break;
+ } // else fall through:
+ // use VMThreadStackSize if CompilerThreadStackSize is not defined
+ case os::vm_thread:
+ case os::pgc_thread:
+ case os::cgc_thread:
+ case os::watcher_thread:
+ if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
+ break;
+ }
+ }
+
+ stack_size = MAX2(stack_size, os::Bsd::min_stack_allowed);
+ pthread_attr_setstacksize(&attr, stack_size);
+ } else {
+ // let pthread_create() pick the default value.
+ }
+
+#ifndef _ALLBSD_SOURCE
+ // glibc guard page
+ pthread_attr_setguardsize(&attr, os::Bsd::default_guard_size(thr_type));
+#endif
+
+ ThreadState state;
+
+ {
+
+#ifndef _ALLBSD_SOURCE
+ // Serialize thread creation if we are running with fixed stack BsdThreads
+ bool lock = os::Bsd::is_BsdThreads() && !os::Bsd::is_floating_stack();
+ if (lock) {
+ os::Bsd::createThread_lock()->lock_without_safepoint_check();
+ }
+#endif
+
+ pthread_t tid;
+ int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
+
+ pthread_attr_destroy(&attr);
+
+ if (ret != 0) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
+ perror("pthread_create()");
+ }
+ // Need to clean up stuff we've allocated so far
+ thread->set_osthread(NULL);
+ delete osthread;
+#ifndef _ALLBSD_SOURCE
+ if (lock) os::Bsd::createThread_lock()->unlock();
+#endif
+ return false;
+ }
+
+ // Store pthread info into the OSThread
+ osthread->set_pthread_id(tid);
+
+ // Wait until child thread is either initialized or aborted
+ {
+ Monitor* sync_with_child = osthread->startThread_lock();
+ MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
+ while ((state = osthread->get_state()) == ALLOCATED) {
+ sync_with_child->wait(Mutex::_no_safepoint_check_flag);
+ }
+ }
+
+#ifndef _ALLBSD_SOURCE
+ if (lock) {
+ os::Bsd::createThread_lock()->unlock();
+ }
+#endif
+ }
+
+ // Aborted due to thread limit being reached
+ if (state == ZOMBIE) {
+ thread->set_osthread(NULL);
+ delete osthread;
+ return false;
+ }
+
+ // The thread is returned suspended (in state INITIALIZED),
+ // and is started higher up in the call chain
+ assert(state == INITIALIZED, "race condition");
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// attach existing thread
+
+// bootstrap the main thread
+bool os::create_main_thread(JavaThread* thread) {
+ assert(os::Bsd::_main_thread == pthread_self(), "should be called inside main thread");
+ return create_attached_thread(thread);
+}
+
+bool os::create_attached_thread(JavaThread* thread) {
+#ifdef ASSERT
+ thread->verify_not_published();
+#endif
+
+ // Allocate the OSThread object
+ OSThread* osthread = new OSThread(NULL, NULL);
+
+ if (osthread == NULL) {
+ return false;
+ }
+
+ // Store pthread info into the OSThread
+#ifdef _ALLBSD_SOURCE
+ osthread->set_thread_id(::pthread_self());
+#else
+ osthread->set_thread_id(os::Bsd::gettid());
+#endif
+ osthread->set_pthread_id(::pthread_self());
+
+ // initialize floating point control register
+ os::Bsd::init_thread_fpu_state();
+
+ // Initial thread state is RUNNABLE
+ osthread->set_state(RUNNABLE);
+
+ thread->set_osthread(osthread);
+
+#ifndef _ALLBSD_SOURCE
+ if (UseNUMA) {
+ int lgrp_id = os::numa_get_group_id();
+ if (lgrp_id != -1) {
+ thread->set_lgrp_id(lgrp_id);
+ }
+ }
+
+ if (os::Bsd::is_initial_thread()) {
+ // If current thread is initial thread, its stack is mapped on demand,
+ // see notes about MAP_GROWSDOWN. Here we try to force kernel to map
+ // the entire stack region to avoid SEGV in stack banging.
+ // It is also useful to get around the heap-stack-gap problem on SuSE
+ // kernel (see 4821821 for details). We first expand stack to the top
+ // of yellow zone, then enable stack yellow zone (order is significant,
+ // enabling yellow zone first will crash JVM on SuSE Bsd), so there
+ // is no gap between the last two virtual memory regions.
+
+ JavaThread *jt = (JavaThread *)thread;
+ address addr = jt->stack_yellow_zone_base();
+ assert(addr != NULL, "initialization problem?");
+ assert(jt->stack_available(addr) > 0, "stack guard should not be enabled");
+
+ osthread->set_expanding_stack();
+ os::Bsd::manually_expand_stack(jt, addr);
+ osthread->clear_expanding_stack();
+ }
+#endif
+
+ // initialize signal mask for this thread
+ // and save the caller's signal mask
+ os::Bsd::hotspot_sigmask(thread);
+
+ return true;
+}
+
+void os::pd_start_thread(Thread* thread) {
+ OSThread * osthread = thread->osthread();
+ assert(osthread->get_state() != INITIALIZED, "just checking");
+ Monitor* sync_with_child = osthread->startThread_lock();
+ MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
+ sync_with_child->notify();
+}
+
+// Free Bsd resources related to the OSThread
+void os::free_thread(OSThread* osthread) {
+ assert(osthread != NULL, "osthread not set");
+
+ if (Thread::current()->osthread() == osthread) {
+ // Restore caller's signal mask
+ sigset_t sigmask = osthread->caller_sigmask();
+ pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
+ }
+
+ delete osthread;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// thread local storage
+
+int os::allocate_thread_local_storage() {
+ pthread_key_t key;
+ int rslt = pthread_key_create(&key, NULL);
+ assert(rslt == 0, "cannot allocate thread local storage");
+ return (int)key;
+}
+
+// Note: This is currently not used by VM, as we don't destroy TLS key
+// on VM exit.
+void os::free_thread_local_storage(int index) {
+ int rslt = pthread_key_delete((pthread_key_t)index);
+ assert(rslt == 0, "invalid index");
+}
+
+void os::thread_local_storage_at_put(int index, void* value) {
+ int rslt = pthread_setspecific((pthread_key_t)index, value);
+ assert(rslt == 0, "pthread_setspecific failed");
+}
+
+extern "C" Thread* get_thread() {
+ return ThreadLocalStorage::thread();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// initial thread
+
+#ifndef _ALLBSD_SOURCE
+// Check if current thread is the initial thread, similar to Solaris thr_main.
+bool os::Bsd::is_initial_thread(void) {
+ char dummy;
+ // If called before init complete, thread stack bottom will be null.
+ // Can be called if fatal error occurs before initialization.
+ if (initial_thread_stack_bottom() == NULL) return false;
+ assert(initial_thread_stack_bottom() != NULL &&
+ initial_thread_stack_size() != 0,
+ "os::init did not locate initial thread's stack region");
+ if ((address)&dummy >= initial_thread_stack_bottom() &&
+ (address)&dummy < initial_thread_stack_bottom() + initial_thread_stack_size())
+ return true;
+ else return false;
+}
+
+// Find the virtual memory area that contains addr
+static bool find_vma(address addr, address* vma_low, address* vma_high) {
+ FILE *fp = fopen("/proc/self/maps", "r");
+ if (fp) {
+ address low, high;
+ while (!feof(fp)) {
+ if (fscanf(fp, "%p-%p", &low, &high) == 2) {
+ if (low <= addr && addr < high) {
+ if (vma_low) *vma_low = low;
+ if (vma_high) *vma_high = high;
+ fclose (fp);
+ return true;
+ }
+ }
+ for (;;) {
+ int ch = fgetc(fp);
+ if (ch == EOF || ch == (int)'\n') break;
+ }
+ }
+ fclose(fp);
+ }
+ return false;
+}
+
+// Locate initial thread stack. This special handling of initial thread stack
+// is needed because pthread_getattr_np() on most (all?) Bsd distros returns
+// bogus value for initial thread.
+void os::Bsd::capture_initial_stack(size_t max_size) {
+ // stack size is the easy part, get it from RLIMIT_STACK
+ size_t stack_size;
+ struct rlimit rlim;
+ getrlimit(RLIMIT_STACK, &rlim);
+ stack_size = rlim.rlim_cur;
+
+ // 6308388: a bug in ld.so will relocate its own .data section to the
+ // lower end of primordial stack; reduce ulimit -s value a little bit
+ // so we won't install guard page on ld.so's data section.
+ stack_size -= 2 * page_size();
+
+ // 4441425: avoid crash with "unlimited" stack size on SuSE 7.1 or Redhat
+ // 7.1, in both cases we will get 2G in return value.
+ // 4466587: glibc 2.2.x compiled w/o "--enable-kernel=2.4.0" (RH 7.0,
+ // SuSE 7.2, Debian) can not handle alternate signal stack correctly
+ // for initial thread if its stack size exceeds 6M. Cap it at 2M,
+ // in case other parts in glibc still assumes 2M max stack size.
+ // FIXME: alt signal stack is gone, maybe we can relax this constraint?
+#ifndef IA64
+ if (stack_size > 2 * K * K) stack_size = 2 * K * K;
+#else
+ // Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small
+ if (stack_size > 4 * K * K) stack_size = 4 * K * K;
+#endif
+
+ // Try to figure out where the stack base (top) is. This is harder.
+ //
+ // When an application is started, glibc saves the initial stack pointer in
+ // a global variable "__libc_stack_end", which is then used by system
+ // libraries. __libc_stack_end should be pretty close to stack top. The
+ // variable is available since the very early days. However, because it is
+ // a private interface, it could disappear in the future.
+ //
+ // Bsd kernel saves start_stack information in /proc/<pid>/stat. Similar
+ // to __libc_stack_end, it is very close to stack top, but isn't the real
+ // stack top. Note that /proc may not exist if VM is running as a chroot
+ // program, so reading /proc/<pid>/stat could fail. Also the contents of
+ // /proc/<pid>/stat could change in the future (though unlikely).
+ //
+ // We try __libc_stack_end first. If that doesn't work, look for
+ // /proc/<pid>/stat. If neither of them works, we use current stack pointer
+ // as a hint, which should work well in most cases.
+
+ uintptr_t stack_start;
+
+ // try __libc_stack_end first
+ uintptr_t *p = (uintptr_t *)dlsym(RTLD_DEFAULT, "__libc_stack_end");
+ if (p && *p) {
+ stack_start = *p;
+ } else {
+ // see if we can get the start_stack field from /proc/self/stat
+ FILE *fp;
+ int pid;
+ char state;
+ int ppid;
+ int pgrp;
+ int session;
+ int nr;
+ int tpgrp;
+ unsigned long flags;
+ unsigned long minflt;
+ unsigned long cminflt;
+ unsigned long majflt;
+ unsigned long cmajflt;
+ unsigned long utime;
+ unsigned long stime;
+ long cutime;
+ long cstime;
+ long prio;
+ long nice;
+ long junk;
+ long it_real;
+ uintptr_t start;
+ uintptr_t vsize;
+ intptr_t rss;
+ uintptr_t rsslim;
+ uintptr_t scodes;
+ uintptr_t ecode;
+ int i;
+
+ // Figure what the primordial thread stack base is. Code is inspired
+ // by email from Hans Boehm. /proc/self/stat begins with current pid,
+ // followed by command name surrounded by parentheses, state, etc.
+ char stat[2048];
+ int statlen;
+
+ fp = fopen("/proc/self/stat", "r");
+ if (fp) {
+ statlen = fread(stat, 1, 2047, fp);
+ stat[statlen] = '\0';
+ fclose(fp);
+
+ // Skip pid and the command string. Note that we could be dealing with
+ // weird command names, e.g. user could decide to rename java launcher
+ // to "java 1.4.2 :)", then the stat file would look like
+ // 1234 (java 1.4.2 :)) R ... ...
+ // We don't really need to know the command string, just find the last
+ // occurrence of ")" and then start parsing from there. See bug 4726580.
+ char * s = strrchr(stat, ')');
+
+ i = 0;
+ if (s) {
+ // Skip blank chars
+ do s++; while (isspace(*s));
+
+#define _UFM UINTX_FORMAT
+#define _DFM INTX_FORMAT
+
+ /* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 */
+ /* 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 */
+ i = sscanf(s, "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld " _UFM _UFM _DFM _UFM _UFM _UFM _UFM,
+ &state, /* 3 %c */
+ &ppid, /* 4 %d */
+ &pgrp, /* 5 %d */
+ &session, /* 6 %d */
+ &nr, /* 7 %d */
+ &tpgrp, /* 8 %d */
+ &flags, /* 9 %lu */
+ &minflt, /* 10 %lu */
+ &cminflt, /* 11 %lu */
+ &majflt, /* 12 %lu */
+ &cmajflt, /* 13 %lu */
+ &utime, /* 14 %lu */
+ &stime, /* 15 %lu */
+ &cutime, /* 16 %ld */
+ &cstime, /* 17 %ld */
+ &prio, /* 18 %ld */
+ &nice, /* 19 %ld */
+ &junk, /* 20 %ld */
+ &it_real, /* 21 %ld */
+ &start, /* 22 UINTX_FORMAT */
+ &vsize, /* 23 UINTX_FORMAT */
+ &rss, /* 24 INTX_FORMAT */
+ &rsslim, /* 25 UINTX_FORMAT */
+ &scodes, /* 26 UINTX_FORMAT */
+ &ecode, /* 27 UINTX_FORMAT */
+ &stack_start); /* 28 UINTX_FORMAT */
+ }
+
+#undef _UFM
+#undef _DFM
+
+ if (i != 28 - 2) {
+ assert(false, "Bad conversion from /proc/self/stat");
+ // product mode - assume we are the initial thread, good luck in the
+ // embedded case.
+ warning("Can't detect initial thread stack location - bad conversion");
+ stack_start = (uintptr_t) &rlim;
+ }
+ } else {
+ // For some reason we can't open /proc/self/stat (for example, running on
+ // FreeBSD with a Bsd emulator, or inside chroot), this should work for
+ // most cases, so don't abort:
+ warning("Can't detect initial thread stack location - no /proc/self/stat");
+ stack_start = (uintptr_t) &rlim;
+ }
+ }
+
+ // Now we have a pointer (stack_start) very close to the stack top, the
+ // next thing to do is to figure out the exact location of stack top. We
+ // can find out the virtual memory area that contains stack_start by
+ // reading /proc/self/maps, it should be the last vma in /proc/self/maps,
+ // and its upper limit is the real stack top. (again, this would fail if
+ // running inside chroot, because /proc may not exist.)
+
+ uintptr_t stack_top;
+ address low, high;
+ if (find_vma((address)stack_start, &low, &high)) {
+ // success, "high" is the true stack top. (ignore "low", because initial
+ // thread stack grows on demand, its real bottom is high - RLIMIT_STACK.)
+ stack_top = (uintptr_t)high;
+ } else {
+ // failed, likely because /proc/self/maps does not exist
+ warning("Can't detect initial thread stack location - find_vma failed");
+ // best effort: stack_start is normally within a few pages below the real
+ // stack top, use it as stack top, and reduce stack size so we won't put
+ // guard page outside stack.
+ stack_top = stack_start;
+ stack_size -= 16 * page_size();
+ }
+
+ // stack_top could be partially down the page so align it
+ stack_top = align_size_up(stack_top, page_size());
+
+ if (max_size && stack_size > max_size) {
+ _initial_thread_stack_size = max_size;
+ } else {
+ _initial_thread_stack_size = stack_size;
+ }
+
+ _initial_thread_stack_size = align_size_down(_initial_thread_stack_size, page_size());
+ _initial_thread_stack_bottom = (address)stack_top - _initial_thread_stack_size;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// time support
+
+// Time since start-up in seconds to a fine granularity.
+// Used by VMSelfDestructTimer and the MemProfiler.
+double os::elapsedTime() {
+
+ return (double)(os::elapsed_counter()) * 0.000001;
+}
+
+jlong os::elapsed_counter() {
+ timeval time;
+ int status = gettimeofday(&time, NULL);
+ return jlong(time.tv_sec) * 1000 * 1000 + jlong(time.tv_usec) - initial_time_count;
+}
+
+jlong os::elapsed_frequency() {
+ return (1000 * 1000);
+}
+
+// XXX: For now, code this as if BSD does not support vtime.
+bool os::supports_vtime() { return false; }
+bool os::enable_vtime() { return false; }
+bool os::vtime_enabled() { return false; }
+double os::elapsedVTime() {
+ // better than nothing, but not much
+ return elapsedTime();
+}
+
+jlong os::javaTimeMillis() {
+ timeval time;
+ int status = gettimeofday(&time, NULL);
+ assert(status != -1, "bsd error");
+ return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000);
+}
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC (1)
+#endif
+
+#ifdef __APPLE__
+void os::Bsd::clock_init() {
+ // XXXDARWIN: Investigate replacement monotonic clock
+}
+#elif defined(_ALLBSD_SOURCE)
+void os::Bsd::clock_init() {
+ struct timespec res;
+ struct timespec tp;
+ if (::clock_getres(CLOCK_MONOTONIC, &res) == 0 &&
+ ::clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
+ // yes, monotonic clock is supported
+ _clock_gettime = ::clock_gettime;
+ }
+}
+#else
+void os::Bsd::clock_init() {
+ // we do dlopen's in this particular order due to bug in bsd
+ // dynamical loader (see 6348968) leading to crash on exit
+ void* handle = dlopen("librt.so.1", RTLD_LAZY);
+ if (handle == NULL) {
+ handle = dlopen("librt.so", RTLD_LAZY);
+ }
+
+ if (handle) {
+ int (*clock_getres_func)(clockid_t, struct timespec*) =
+ (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
+ int (*clock_gettime_func)(clockid_t, struct timespec*) =
+ (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
+ if (clock_getres_func && clock_gettime_func) {
+ // See if monotonic clock is supported by the kernel. Note that some
+ // early implementations simply return kernel jiffies (updated every
+ // 1/100 or 1/1000 second). It would be bad to use such a low res clock
+ // for nano time (though the monotonic property is still nice to have).
+ // It's fixed in newer kernels, however clock_getres() still returns
+ // 1/HZ. We check if clock_getres() works, but will ignore its reported
+ // resolution for now. Hopefully as people move to new kernels, this
+ // won't be a problem.
+ struct timespec res;
+ struct timespec tp;
+ if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
+ clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
+ // yes, monotonic clock is supported
+ _clock_gettime = clock_gettime_func;
+ } else {
+ // close librt if there is no monotonic clock
+ dlclose(handle);
+ }
+ }
+ }
+}
+#endif
+
+#ifndef _ALLBSD_SOURCE
+#ifndef SYS_clock_getres
+
+#if defined(IA32) || defined(AMD64)
+#define SYS_clock_getres IA32_ONLY(266) AMD64_ONLY(229)
+#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
+#else
+#warning "SYS_clock_getres not defined for this platform, disabling fast_thread_cpu_time"
+#define sys_clock_getres(x,y) -1
+#endif
+
+#else
+#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
+#endif
+
+void os::Bsd::fast_thread_clock_init() {
+ if (!UseBsdPosixThreadCPUClocks) {
+ return;
+ }
+ clockid_t clockid;
+ struct timespec tp;
+ int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) =
+ (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid");
+
+ // Switch to using fast clocks for thread cpu time if
+ // the sys_clock_getres() returns 0 error code.
+ // Note, that some kernels may support the current thread
+ // clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks
+ // returned by the pthread_getcpuclockid().
+ // If the fast Posix clocks are supported then the sys_clock_getres()
+ // must return at least tp.tv_sec == 0 which means a resolution
+ // better than 1 sec. This is extra check for reliability.
+
+ if(pthread_getcpuclockid_func &&
+ pthread_getcpuclockid_func(_main_thread, &clockid) == 0 &&
+ sys_clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) {
+
+ _supports_fast_thread_cpu_time = true;
+ _pthread_getcpuclockid = pthread_getcpuclockid_func;
+ }
+}
+#endif
+
+jlong os::javaTimeNanos() {
+ if (Bsd::supports_monotonic_clock()) {
+ struct timespec tp;
+ int status = Bsd::clock_gettime(CLOCK_MONOTONIC, &tp);
+ assert(status == 0, "gettime error");
+ jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
+ return result;
+ } else {
+ timeval time;
+ int status = gettimeofday(&time, NULL);
+ assert(status != -1, "bsd error");
+ jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
+ return 1000 * usecs;
+ }
+}
+
+void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
+ if (Bsd::supports_monotonic_clock()) {
+ info_ptr->max_value = ALL_64_BITS;
+
+ // CLOCK_MONOTONIC - amount of time since some arbitrary point in the past
+ info_ptr->may_skip_backward = false; // not subject to resetting or drifting
+ info_ptr->may_skip_forward = false; // not subject to resetting or drifting
+ } else {
+ // gettimeofday - based on time in seconds since the Epoch thus does not wrap
+ info_ptr->max_value = ALL_64_BITS;
+
+ // gettimeofday is a real time clock so it skips
+ info_ptr->may_skip_backward = true;
+ info_ptr->may_skip_forward = true;
+ }
+
+ info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
+}
+
+// Return the real, user, and system times in seconds from an
+// arbitrary fixed point in the past.
+bool os::getTimesSecs(double* process_real_time,
+ double* process_user_time,
+ double* process_system_time) {
+ struct tms ticks;
+ clock_t real_ticks = times(&ticks);
+
+ if (real_ticks == (clock_t) (-1)) {
+ return false;
+ } else {
+ double ticks_per_second = (double) clock_tics_per_sec;
+ *process_user_time = ((double) ticks.tms_utime) / ticks_per_second;
+ *process_system_time = ((double) ticks.tms_stime) / ticks_per_second;
+ *process_real_time = ((double) real_ticks) / ticks_per_second;
+
+ return true;
+ }
+}
+
+
+char * os::local_time_string(char *buf, size_t buflen) {
+ struct tm t;
+ time_t long_time;
+ time(&long_time);
+ localtime_r(&long_time, &t);
+ jio_snprintf(buf, buflen, "%d-%02d-%02d %02d:%02d:%02d",
+ t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
+ t.tm_hour, t.tm_min, t.tm_sec);
+ return buf;
+}
+
+struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
+ return localtime_r(clock, res);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// runtime exit support
+
+// Note: os::shutdown() might be called very early during initialization, or
+// called from signal handler. Before adding something to os::shutdown(), make
+// sure it is async-safe and can handle partially initialized VM.
+void os::shutdown() {
+
+ // allow PerfMemory to attempt cleanup of any persistent resources
+ perfMemory_exit();
+
+ // needs to remove object in file system
+ AttachListener::abort();
+
+ // flush buffered output, finish log files
+ ostream_abort();
+
+ // Check for abort hook
+ abort_hook_t abort_hook = Arguments::abort_hook();
+ if (abort_hook != NULL) {
+ abort_hook();
+ }
+
+}
+
+// Note: os::abort() might be called very early during initialization, or
+// called from signal handler. Before adding something to os::abort(), make
+// sure it is async-safe and can handle partially initialized VM.
+void os::abort(bool dump_core) {
+ os::shutdown();
+ if (dump_core) {
+#ifndef PRODUCT
+ fdStream out(defaultStream::output_fd());
+ out.print_raw("Current thread is ");
+ char buf[16];
+ jio_snprintf(buf, sizeof(buf), UINTX_FORMAT, os::current_thread_id());
+ out.print_raw_cr(buf);
+ out.print_raw_cr("Dumping core ...");
+#endif
+ ::abort(); // dump core
+ }
+
+ ::exit(1);
+}
+
+// Die immediately, no exit hook, no abort hook, no cleanup.
+void os::die() {
+ // _exit() on BsdThreads only kills current thread
+ ::abort();
+}
+
+// unused on bsd for now.
+void os::set_error_file(const char *logfile) {}
+
+
+// This method is a copy of JDK's sysGetLastErrorString
+// from src/solaris/hpi/src/system_md.c
+
+size_t os::lasterror(char *buf, size_t len) {
+
+ if (errno == 0) return 0;
+
+ const char *s = ::strerror(errno);
+ size_t n = ::strlen(s);
+ if (n >= len) {
+ n = len - 1;
+ }
+ ::strncpy(buf, s, n);
+ buf[n] = '\0';
+ return n;
+}
+
+intx os::current_thread_id() { return (intx)pthread_self(); }
+int os::current_process_id() {
+
+ // Under the old bsd thread library, bsd gives each thread
+ // its own process id. Because of this each thread will return
+ // a different pid if this method were to return the result
+ // of getpid(2). Bsd provides no api that returns the pid
+ // of the launcher thread for the vm. This implementation
+ // returns a unique pid, the pid of the launcher thread
+ // that starts the vm 'process'.
+
+ // Under the NPTL, getpid() returns the same pid as the
+ // launcher thread rather than a unique pid per thread.
+ // Use gettid() if you want the old pre NPTL behaviour.
+
+ // if you are looking for the result of a call to getpid() that
+ // returns a unique pid for the calling thread, then look at the
+ // OSThread::thread_id() method in osThread_bsd.hpp file
+
+ return (int)(_initial_pid ? _initial_pid : getpid());
+}
+
+// DLL functions
+
+#define JNI_LIB_PREFIX "lib"
+#ifdef __APPLE__
+#define JNI_LIB_SUFFIX ".dylib"
+#else
+#define JNI_LIB_SUFFIX ".so"
+#endif
+
+const char* os::dll_file_extension() { return JNI_LIB_SUFFIX; }
+
+// This must be hard coded because it's the system's temporary
+// directory not the java application's temp directory, ala java.io.tmpdir.
+const char* os::get_temp_directory() { return "/tmp"; }
+
+static bool file_exists(const char* filename) {
+ struct stat statbuf;
+ if (filename == NULL || strlen(filename) == 0) {
+ return false;
+ }
+ return os::stat(filename, &statbuf) == 0;
+}
+
+void os::dll_build_name(char* buffer, size_t buflen,
+ const char* pname, const char* fname) {
+ // Copied from libhpi
+ const size_t pnamelen = pname ? strlen(pname) : 0;
+
+ // Quietly truncate on buffer overflow. Should be an error.
+ if (pnamelen + strlen(fname) + strlen(JNI_LIB_PREFIX) + strlen(JNI_LIB_SUFFIX) + 2 > buflen) {
+ *buffer = '\0';
+ return;
+ }
+
+ if (pnamelen == 0) {
+ snprintf(buffer, buflen, JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, fname);
+ } else if (strchr(pname, *os::path_separator()) != NULL) {
+ int n;
+ char** pelements = split_path(pname, &n);
+ for (int i = 0 ; i < n ; i++) {
+ // Really shouldn't be NULL, but check can't hurt
+ if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
+ continue; // skip the empty path values
+ }
+ snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX,
+ pelements[i], fname);
+ if (file_exists(buffer)) {
+ break;
+ }
+ }
+ // release the storage
+ for (int i = 0 ; i < n ; i++) {
+ if (pelements[i] != NULL) {
+ FREE_C_HEAP_ARRAY(char, pelements[i]);
+ }
+ }
+ if (pelements != NULL) {
+ FREE_C_HEAP_ARRAY(char*, pelements);
+ }
+ } else {
+ snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, pname, fname);
+ }
+}
+
+const char* os::get_current_directory(char *buf, int buflen) {
+ return getcwd(buf, buflen);
+}
+
+// check if addr is inside libjvm[_g].so
+bool os::address_is_in_vm(address addr) {
+ static address libjvm_base_addr;
+ Dl_info dlinfo;
+
+ if (libjvm_base_addr == NULL) {
+ dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo);
+ libjvm_base_addr = (address)dlinfo.dli_fbase;
+ assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
+ }
+
+ if (dladdr((void *)addr, &dlinfo)) {
+ if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
+ }
+
+ return false;
+}
+
+bool os::dll_address_to_function_name(address addr, char *buf,
+ int buflen, int *offset) {
+ Dl_info dlinfo;
+
+ if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
+ if (buf != NULL) {
+ if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
+ jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
+ }
+ }
+ if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
+ return true;
+ } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
+ if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
+ dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) {
+ return true;
+ }
+ }
+
+ if (buf != NULL) buf[0] = '\0';
+ if (offset != NULL) *offset = -1;
+ return false;
+}
+
+#ifdef _ALLBSD_SOURCE
+// ported from solaris version
+bool os::dll_address_to_library_name(address addr, char* buf,
+ int buflen, int* offset) {
+ Dl_info dlinfo;
+
+ if (dladdr((void*)addr, &dlinfo)){
+ if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
+ if (offset) *offset = addr - (address)dlinfo.dli_fbase;
+ return true;
+ } else {
+ if (buf) buf[0] = '\0';
+ if (offset) *offset = -1;
+ return false;
+ }
+}
+#else
+struct _address_to_library_name {
+ address addr; // input : memory address
+ size_t buflen; // size of fname
+ char* fname; // output: library name
+ address base; // library base addr
+};
+
+static int address_to_library_name_callback(struct dl_phdr_info *info,
+ size_t size, void *data) {
+ int i;
+ bool found = false;
+ address libbase = NULL;
+ struct _address_to_library_name * d = (struct _address_to_library_name *)data;
+
+ // iterate through all loadable segments
+ for (i = 0; i < info->dlpi_phnum; i++) {
+ address segbase = (address)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+ if (info->dlpi_phdr[i].p_type == PT_LOAD) {
+ // base address of a library is the lowest address of its loaded
+ // segments.
+ if (libbase == NULL || libbase > segbase) {
+ libbase = segbase;
+ }
+ // see if 'addr' is within current segment
+ if (segbase <= d->addr &&
+ d->addr < segbase + info->dlpi_phdr[i].p_memsz) {
+ found = true;
+ }
+ }
+ }
+
+ // dlpi_name is NULL or empty if the ELF file is executable, return 0
+ // so dll_address_to_library_name() can fall through to use dladdr() which
+ // can figure out executable name from argv[0].
+ if (found && info->dlpi_name && info->dlpi_name[0]) {
+ d->base = libbase;
+ if (d->fname) {
+ jio_snprintf(d->fname, d->buflen, "%s", info->dlpi_name);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+bool os::dll_address_to_library_name(address addr, char* buf,
+ int buflen, int* offset) {
+ Dl_info dlinfo;
+ struct _address_to_library_name data;
+
+ // There is a bug in old glibc dladdr() implementation that it could resolve
+ // to wrong library name if the .so file has a base address != NULL. Here
+ // we iterate through the program headers of all loaded libraries to find
+ // out which library 'addr' really belongs to. This workaround can be
+ // removed once the minimum requirement for glibc is moved to 2.3.x.
+ data.addr = addr;
+ data.fname = buf;
+ data.buflen = buflen;
+ data.base = NULL;
+ int rslt = dl_iterate_phdr(address_to_library_name_callback, (void *)&data);
+
+ if (rslt) {
+ // buf already contains library name
+ if (offset) *offset = addr - data.base;
+ return true;
+ } else if (dladdr((void*)addr, &dlinfo)){
+ if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
+ if (offset) *offset = addr - (address)dlinfo.dli_fbase;
+ return true;
+ } else {
+ if (buf) buf[0] = '\0';
+ if (offset) *offset = -1;
+ return false;
+ }
+}
+#endif
+
+ // Loads .dll/.so and
+ // in case of error it checks if .dll/.so was built for the
+ // same architecture as Hotspot is running on
+
+#ifdef __APPLE__
+void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
+ void * result= ::dlopen(filename, RTLD_LAZY);
+ if (result != NULL) {
+ // Successful loading
+ return result;
+ }
+
+ // Read system error message into ebuf
+ ::strncpy(ebuf, ::dlerror(), ebuflen-1);
+ ebuf[ebuflen-1]='\0';
+
+ return NULL;
+}
+#else
+void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
+{
+ void * result= ::dlopen(filename, RTLD_LAZY);
+ if (result != NULL) {
+ // Successful loading
+ return result;
+ }
+
+ Elf32_Ehdr elf_head;
+
+ // Read system error message into ebuf
+ // It may or may not be overwritten below
+ ::strncpy(ebuf, ::dlerror(), ebuflen-1);
+ ebuf[ebuflen-1]='\0';
+ int diag_msg_max_length=ebuflen-strlen(ebuf);
+ char* diag_msg_buf=ebuf+strlen(ebuf);
+
+ if (diag_msg_max_length==0) {
+ // No more space in ebuf for additional diagnostics message
+ return NULL;
+ }
+
+
+ int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK);
+
+ if (file_descriptor < 0) {
+ // Can't open library, report dlerror() message
+ return NULL;
+ }
+
+ bool failed_to_read_elf_head=
+ (sizeof(elf_head)!=
+ (::read(file_descriptor, &elf_head,sizeof(elf_head)))) ;
+
+ ::close(file_descriptor);
+ if (failed_to_read_elf_head) {
+ // file i/o error - report dlerror() msg
+ return NULL;
+ }
+
+ typedef struct {
+ Elf32_Half code; // Actual value as defined in elf.h
+ Elf32_Half compat_class; // Compatibility of archs at VM's sense
+ char elf_class; // 32 or 64 bit
+ char endianess; // MSB or LSB
+ char* name; // String representation
+ } arch_t;
+
+ #ifndef EM_486
+ #define EM_486 6 /* Intel 80486 */
+ #endif
+
+ #ifndef EM_MIPS_RS3_LE
+ #define EM_MIPS_RS3_LE 10 /* MIPS */
+ #endif
+
+ #ifndef EM_PPC64
+ #define EM_PPC64 21 /* PowerPC64 */
+ #endif
+
+ #ifndef EM_S390
+ #define EM_S390 22 /* IBM System/390 */
+ #endif
+
+ #ifndef EM_IA_64
+ #define EM_IA_64 50 /* HP/Intel IA-64 */
+ #endif
+
+ #ifndef EM_X86_64
+ #define EM_X86_64 62 /* AMD x86-64 */
+ #endif
+
+ static const arch_t arch_array[]={
+ {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
+ {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
+ {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"},
+ {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"},
+ {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
+ {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
+ {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
+ {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
+ {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
+ {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
+ {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"},
+ {EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"},
+ {EM_MIPS_RS3_LE, EM_MIPS_RS3_LE, ELFCLASS32, ELFDATA2LSB, (char*)"MIPSel"},
+ {EM_MIPS, EM_MIPS, ELFCLASS32, ELFDATA2MSB, (char*)"MIPS"},
+ {EM_PARISC, EM_PARISC, ELFCLASS32, ELFDATA2MSB, (char*)"PARISC"},
+ {EM_68K, EM_68K, ELFCLASS32, ELFDATA2MSB, (char*)"M68k"}
+ };
+
+ #if (defined IA32)
+ static Elf32_Half running_arch_code=EM_386;
+ #elif (defined AMD64)
+ static Elf32_Half running_arch_code=EM_X86_64;
+ #elif (defined IA64)
+ static Elf32_Half running_arch_code=EM_IA_64;
+ #elif (defined __sparc) && (defined _LP64)
+ static Elf32_Half running_arch_code=EM_SPARCV9;
+ #elif (defined __sparc) && (!defined _LP64)
+ static Elf32_Half running_arch_code=EM_SPARC;
+ #elif (defined __powerpc64__)
+ static Elf32_Half running_arch_code=EM_PPC64;
+ #elif (defined __powerpc__)
+ static Elf32_Half running_arch_code=EM_PPC;
+ #elif (defined ARM)
+ static Elf32_Half running_arch_code=EM_ARM;
+ #elif (defined S390)
+ static Elf32_Half running_arch_code=EM_S390;
+ #elif (defined ALPHA)
+ static Elf32_Half running_arch_code=EM_ALPHA;
+ #elif (defined MIPSEL)
+ static Elf32_Half running_arch_code=EM_MIPS_RS3_LE;
+ #elif (defined PARISC)
+ static Elf32_Half running_arch_code=EM_PARISC;
+ #elif (defined MIPS)
+ static Elf32_Half running_arch_code=EM_MIPS;
+ #elif (defined M68K)
+ static Elf32_Half running_arch_code=EM_68K;
+ #else
+ #error Method os::dll_load requires that one of following is defined:\
+ IA32, AMD64, IA64, __sparc, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K
+ #endif
+
+ // Identify compatability class for VM's architecture and library's architecture
+ // Obtain string descriptions for architectures
+
+ arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL};
+ int running_arch_index=-1;
+
+ for (unsigned int i=0 ; i < ARRAY_SIZE(arch_array) ; i++ ) {
+ if (running_arch_code == arch_array[i].code) {
+ running_arch_index = i;
+ }
+ if (lib_arch.code == arch_array[i].code) {
+ lib_arch.compat_class = arch_array[i].compat_class;
+ lib_arch.name = arch_array[i].name;
+ }
+ }
+
+ assert(running_arch_index != -1,
+ "Didn't find running architecture code (running_arch_code) in arch_array");
+ if (running_arch_index == -1) {
+ // Even though running architecture detection failed
+ // we may still continue with reporting dlerror() message
+ return NULL;
+ }
+
+ if (lib_arch.endianess != arch_array[running_arch_index].endianess) {
+ ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)");
+ return NULL;
+ }
+
+#ifndef S390
+ if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) {
+ ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: architecture word width mismatch)");
+ return NULL;
+ }
+#endif // !S390
+
+ if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) {
+ if ( lib_arch.name!=NULL ) {
+ ::snprintf(diag_msg_buf, diag_msg_max_length-1,
+ " (Possible cause: can't load %s-bit .so on a %s-bit platform)",
+ lib_arch.name, arch_array[running_arch_index].name);
+ } else {
+ ::snprintf(diag_msg_buf, diag_msg_max_length-1,
+ " (Possible cause: can't load this .so (machine code=0x%x) on a %s-bit platform)",
+ lib_arch.code,
+ arch_array[running_arch_index].name);
+ }
+ }
+
+ return NULL;
+}
+#endif /* !__APPLE__ */
+
+// XXX: Do we need a lock around this as per Linux?
+void* os::dll_lookup(void* handle, const char* name) {
+ return dlsym(handle, name);
+}
+
+
+static bool _print_ascii_file(const char* filename, outputStream* st) {
+ int fd = ::open(filename, O_RDONLY);
+ if (fd == -1) {
+ return false;
+ }
+
+ char buf[32];
+ int bytes;
+ while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) {
+ st->print_raw(buf, bytes);
+ }
+
+ ::close(fd);
+
+ return true;
+}
+
+void os::print_dll_info(outputStream *st) {
+ st->print_cr("Dynamic libraries:");
+#ifdef _ALLBSD_SOURCE
+#ifdef RTLD_DI_LINKMAP
+ Dl_info dli;
+ void *handle;
+ Link_map *map;
+ Link_map *p;
+
+ if (!dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli)) {
+ st->print_cr("Error: Cannot print dynamic libraries.");
+ return;
+ }
+ handle = dlopen(dli.dli_fname, RTLD_LAZY);
+ if (handle == NULL) {
+ st->print_cr("Error: Cannot print dynamic libraries.");
+ return;
+ }
+ dlinfo(handle, RTLD_DI_LINKMAP, &map);
+ if (map == NULL) {
+ st->print_cr("Error: Cannot print dynamic libraries.");
+ return;
+ }
+
+ while (map->l_prev != NULL)
+ map = map->l_prev;
+
+ while (map != NULL) {
+ st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
+ map = map->l_next;
+ }
+
+ dlclose(handle);
+#elif defined(__APPLE__)
+ uint32_t count;
+ uint32_t i;
+
+ count = _dyld_image_count();
+ for (i = 1; i < count; i++) {
+ const char *name = _dyld_get_image_name(i);
+ intptr_t slide = _dyld_get_image_vmaddr_slide(i);
+ st->print_cr(PTR_FORMAT " \t%s", slide, name);
+ }
+#else
+ st->print_cr("Error: Cannot print dynamic libraries.");
+#endif
+#else
+ char fname[32];
+ pid_t pid = os::Bsd::gettid();
+
+ jio_snprintf(fname, sizeof(fname), "/proc/%d/maps", pid);
+
+ if (!_print_ascii_file(fname, st)) {
+ st->print("Can not get library information for pid = %d\n", pid);
+ }
+#endif
+}
+
+
+void os::print_os_info(outputStream* st) {
+ st->print("OS:");
+
+ // Try to identify popular distros.
+ // Most Bsd distributions have /etc/XXX-release file, which contains
+ // the OS version string. Some have more than one /etc/XXX-release file
+ // (e.g. Mandrake has both /etc/mandrake-release and /etc/redhat-release.),
+ // so the order is important.
+ if (!_print_ascii_file("/etc/mandrake-release", st) &&
+ !_print_ascii_file("/etc/sun-release", st) &&
+ !_print_ascii_file("/etc/redhat-release", st) &&
+ !_print_ascii_file("/etc/SuSE-release", st) &&
+ !_print_ascii_file("/etc/turbobsd-release", st) &&
+ !_print_ascii_file("/etc/gentoo-release", st) &&
+ !_print_ascii_file("/etc/debian_version", st) &&
+ !_print_ascii_file("/etc/ltib-release", st) &&
+ !_print_ascii_file("/etc/angstrom-version", st)) {
+ st->print("Bsd");
+ }
+ st->cr();
+
+ // kernel
+ st->print("uname:");
+ struct utsname name;
+ uname(&name);
+ st->print(name.sysname); st->print(" ");
+ st->print(name.release); st->print(" ");
+ st->print(name.version); st->print(" ");
+ st->print(name.machine);
+ st->cr();
+
+#ifndef _ALLBSD_SOURCE
+ // Print warning if unsafe chroot environment detected
+ if (unsafe_chroot_detected) {
+ st->print("WARNING!! ");
+ st->print_cr(unstable_chroot_error);
+ }
+
+ // libc, pthread
+ st->print("libc:");
+ st->print(os::Bsd::glibc_version()); st->print(" ");
+ st->print(os::Bsd::libpthread_version()); st->print(" ");
+ if (os::Bsd::is_BsdThreads()) {
+ st->print("(%s stack)", os::Bsd::is_floating_stack() ? "floating" : "fixed");
+ }
+ st->cr();
+#endif
+
+ // rlimit
+ st->print("rlimit:");
+ struct rlimit rlim;
+
+ st->print(" STACK ");
+ getrlimit(RLIMIT_STACK, &rlim);
+ if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
+ else st->print("%uk", rlim.rlim_cur >> 10);
+
+ st->print(", CORE ");
+ getrlimit(RLIMIT_CORE, &rlim);
+ if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
+ else st->print("%uk", rlim.rlim_cur >> 10);
+
+ st->print(", NPROC ");
+ getrlimit(RLIMIT_NPROC, &rlim);
+ if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
+ else st->print("%d", rlim.rlim_cur);
+
+ st->print(", NOFILE ");
+ getrlimit(RLIMIT_NOFILE, &rlim);
+ if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
+ else st->print("%d", rlim.rlim_cur);
+
+#ifndef _ALLBSD_SOURCE
+ st->print(", AS ");
+ getrlimit(RLIMIT_AS, &rlim);
+ if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
+ else st->print("%uk", rlim.rlim_cur >> 10);
+ st->cr();
+
+ // load average
+ st->print("load average:");
+ double loadavg[3];
+ os::loadavg(loadavg, 3);
+ st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]);
+ st->cr();
+#endif
+}
+
+void os::pd_print_cpu_info(outputStream* st) {
+ // Nothing to do for now.
+}
+
+void os::print_memory_info(outputStream* st) {
+
+ st->print("Memory:");
+ st->print(" %dk page", os::vm_page_size()>>10);
+
+#ifndef _ALLBSD_SOURCE
+ // values in struct sysinfo are "unsigned long"
+ struct sysinfo si;
+ sysinfo(&si);
+#endif
+
+ st->print(", physical " UINT64_FORMAT "k",
+ os::physical_memory() >> 10);
+ st->print("(" UINT64_FORMAT "k free)",
+ os::available_memory() >> 10);
+#ifndef _ALLBSD_SOURCE
+ st->print(", swap " UINT64_FORMAT "k",
+ ((jlong)si.totalswap * si.mem_unit) >> 10);
+ st->print("(" UINT64_FORMAT "k free)",
+ ((jlong)si.freeswap * si.mem_unit) >> 10);
+#endif
+ st->cr();
+
+ // meminfo
+ st->print("\n/proc/meminfo:\n");
+ _print_ascii_file("/proc/meminfo", st);
+ st->cr();
+}
+
+// Taken from /usr/include/bits/siginfo.h Supposed to be architecture specific
+// but they're the same for all the bsd arch that we support
+// and they're the same for solaris but there's no common place to put this.
+const char *ill_names[] = { "ILL0", "ILL_ILLOPC", "ILL_ILLOPN", "ILL_ILLADR",
+ "ILL_ILLTRP", "ILL_PRVOPC", "ILL_PRVREG",
+ "ILL_COPROC", "ILL_BADSTK" };
+
+const char *fpe_names[] = { "FPE0", "FPE_INTDIV", "FPE_INTOVF", "FPE_FLTDIV",
+ "FPE_FLTOVF", "FPE_FLTUND", "FPE_FLTRES",
+ "FPE_FLTINV", "FPE_FLTSUB", "FPE_FLTDEN" };
+
+const char *segv_names[] = { "SEGV0", "SEGV_MAPERR", "SEGV_ACCERR" };
+
+const char *bus_names[] = { "BUS0", "BUS_ADRALN", "BUS_ADRERR", "BUS_OBJERR" };
+
+void os::print_siginfo(outputStream* st, void* siginfo) {
+ st->print("siginfo:");
+
+ const int buflen = 100;
+ char buf[buflen];
+ siginfo_t *si = (siginfo_t*)siginfo;
+ st->print("si_signo=%s: ", os::exception_name(si->si_signo, buf, buflen));
+ if (si->si_errno != 0 && strerror_r(si->si_errno, buf, buflen) == 0) {
+ st->print("si_errno=%s", buf);
+ } else {
+ st->print("si_errno=%d", si->si_errno);
+ }
+ const int c = si->si_code;
+ assert(c > 0, "unexpected si_code");
+ switch (si->si_signo) {
+ case SIGILL:
+ st->print(", si_code=%d (%s)", c, c > 8 ? "" : ill_names[c]);
+ st->print(", si_addr=" PTR_FORMAT, si->si_addr);
+ break;
+ case SIGFPE:
+ st->print(", si_code=%d (%s)", c, c > 9 ? "" : fpe_names[c]);
+ st->print(", si_addr=" PTR_FORMAT, si->si_addr);
+ break;
+ case SIGSEGV:
+ st->print(", si_code=%d (%s)", c, c > 2 ? "" : segv_names[c]);
+ st->print(", si_addr=" PTR_FORMAT, si->si_addr);
+ break;
+ case SIGBUS:
+ st->print(", si_code=%d (%s)", c, c > 3 ? "" : bus_names[c]);
+ st->print(", si_addr=" PTR_FORMAT, si->si_addr);
+ break;
+ default:
+ st->print(", si_code=%d", si->si_code);
+ // no si_addr
+ }
+
+ if ((si->si_signo == SIGBUS || si->si_signo == SIGSEGV) &&
+ UseSharedSpaces) {
+ FileMapInfo* mapinfo = FileMapInfo::current_info();
+ if (mapinfo->is_in_shared_space(si->si_addr)) {
+ st->print("\n\nError accessing class data sharing archive." \
+ " Mapped file inaccessible during execution, " \
+ " possible disk/network problem.");
+ }
+ }
+ st->cr();
+}
+
+
+static void print_signal_handler(outputStream* st, int sig,
+ char* buf, size_t buflen);
+
+void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
+ st->print_cr("Signal Handlers:");
+ print_signal_handler(st, SIGSEGV, buf, buflen);
+ print_signal_handler(st, SIGBUS , buf, buflen);
+ print_signal_handler(st, SIGFPE , buf, buflen);
+ print_signal_handler(st, SIGPIPE, buf, buflen);
+ print_signal_handler(st, SIGXFSZ, buf, buflen);
+ print_signal_handler(st, SIGILL , buf, buflen);
+ print_signal_handler(st, INTERRUPT_SIGNAL, buf, buflen);
+ print_signal_handler(st, SR_signum, buf, buflen);
+ print_signal_handler(st, SHUTDOWN1_SIGNAL, buf, buflen);
+ print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
+ print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen);
+ print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
+}
+
+static char saved_jvm_path[MAXPATHLEN] = {0};
+
+// Find the full path to the current module, libjvm.so or libjvm_g.so
+void os::jvm_path(char *buf, jint buflen) {
+ // Error checking.
+ if (buflen < MAXPATHLEN) {
+ assert(false, "must use a large-enough buffer");
+ buf[0] = '\0';
+ return;
+ }
+ // Lazy resolve the path to current module.
+ if (saved_jvm_path[0] != 0) {
+ strcpy(buf, saved_jvm_path);
+ return;
+ }
+
+ char dli_fname[MAXPATHLEN];
+ bool ret = dll_address_to_library_name(
+ CAST_FROM_FN_PTR(address, os::jvm_path),
+ dli_fname, sizeof(dli_fname), NULL);
+ assert(ret != 0, "cannot locate libjvm");
+ char *rp = realpath(dli_fname, buf);
+ if (rp == NULL)
+ return;
+
+ if (Arguments::created_by_gamma_launcher()) {
+ // Support for the gamma launcher. Typical value for buf is
+ // "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so". If "/jre/lib/" appears at
+ // the right place in the string, then assume we are installed in a JDK and
+ // we're done. Otherwise, check for a JAVA_HOME environment variable and fix
+ // up the path so it looks like libjvm.so is installed there (append a
+ // fake suffix hotspot/libjvm.so).
+ const char *p = buf + strlen(buf) - 1;
+ for (int count = 0; p > buf && count < 5; ++count) {
+ for (--p; p > buf && *p != '/'; --p)
+ /* empty */ ;
+ }
+
+ if (strncmp(p, "/jre/lib/", 9) != 0) {
+ // Look for JAVA_HOME in the environment.
+ char* java_home_var = ::getenv("JAVA_HOME");
+ if (java_home_var != NULL && java_home_var[0] != 0) {
+ char* jrelib_p;
+ int len;
+
+ // Check the current module name "libjvm.so" or "libjvm_g.so".
+ p = strrchr(buf, '/');
+ assert(strstr(p, "/libjvm") == p, "invalid library name");
+ p = strstr(p, "_g") ? "_g" : "";
+
+ rp = realpath(java_home_var, buf);
+ if (rp == NULL)
+ return;
+
+ // determine if this is a legacy image or modules image
+ // modules image doesn't have "jre" subdirectory
+ len = strlen(buf);
+ jrelib_p = buf + len;
+ snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch);
+ if (0 != access(buf, F_OK)) {
+ snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch);
+ }
+
+ if (0 == access(buf, F_OK)) {
+ // Use current module name "libjvm[_g].so" instead of
+ // "libjvm"debug_only("_g")".so" since for fastdebug version
+ // we should have "libjvm.so" but debug_only("_g") adds "_g"!
+ len = strlen(buf);
+ snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p);
+ } else {
+ // Go back to path of .so
+ rp = realpath(dli_fname, buf);
+ if (rp == NULL)
+ return;
+ }
+ }
+ }
+ }
+
+ strcpy(saved_jvm_path, buf);
+}
+
+void os::print_jni_name_prefix_on(outputStream* st, int args_size) {
+ // no prefix required, not even "_"
+}
+
+void os::print_jni_name_suffix_on(outputStream* st, int args_size) {
+ // no suffix required
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// sun.misc.Signal support
+
+static volatile jint sigint_count = 0;
+
+static void
+UserHandler(int sig, void *siginfo, void *context) {
+ // 4511530 - sem_post is serialized and handled by the manager thread. When
+ // the program is interrupted by Ctrl-C, SIGINT is sent to every thread. We
+ // don't want to flood the manager thread with sem_post requests.
+ if (sig == SIGINT && Atomic::add(1, &sigint_count) > 1)
+ return;
+
+ // Ctrl-C is pressed during error reporting, likely because the error
+ // handler fails to abort. Let VM die immediately.
+ if (sig == SIGINT && is_error_reported()) {
+ os::die();
+ }
+
+ os::signal_notify(sig);
+}
+
+void* os::user_handler() {
+ return CAST_FROM_FN_PTR(void*, UserHandler);
+}
+
+extern "C" {
+ typedef void (*sa_handler_t)(int);
+ typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+}
+
+void* os::signal(int signal_number, void* handler) {
+ struct sigaction sigAct, oldSigAct;
+
+ sigfillset(&(sigAct.sa_mask));
+ sigAct.sa_flags = SA_RESTART|SA_SIGINFO;
+ sigAct.sa_handler = CAST_TO_FN_PTR(sa_handler_t, handler);
+
+ if (sigaction(signal_number, &sigAct, &oldSigAct)) {
+ // -1 means registration failed
+ return (void *)-1;
+ }
+
+ return CAST_FROM_FN_PTR(void*, oldSigAct.sa_handler);
+}
+
+void os::signal_raise(int signal_number) {
+ ::raise(signal_number);
+}
+
+/*
+ * The following code is moved from os.cpp for making this
+ * code platform specific, which it is by its very nature.
+ */
+
+// Will be modified when max signal is changed to be dynamic
+int os::sigexitnum_pd() {
+ return NSIG;
+}
+
+// a counter for each possible signal value
+static volatile jint pending_signals[NSIG+1] = { 0 };
+
+// Bsd(POSIX) specific hand shaking semaphore.
+#ifdef __APPLE__
+static semaphore_t sig_sem;
+#define SEM_INIT(sem, value) semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, value)
+#define SEM_WAIT(sem) semaphore_wait(sem);
+#define SEM_POST(sem) semaphore_signal(sem);
+#else
+static sem_t sig_sem;
+#define SEM_INIT(sem, value) sem_init(&sem, 0, value)
+#define SEM_WAIT(sem) sem_wait(&sem);
+#define SEM_POST(sem) sem_post(&sem);
+#endif
+
+void os::signal_init_pd() {
+ // Initialize signal structures
+ ::memset((void*)pending_signals, 0, sizeof(pending_signals));
+
+ // Initialize signal semaphore
+ ::SEM_INIT(sig_sem, 0);
+}
+
+void os::signal_notify(int sig) {
+ Atomic::inc(&pending_signals[sig]);
+ ::SEM_POST(sig_sem);
+}
+
+static int check_pending_signals(bool wait) {
+ Atomic::store(0, &sigint_count);
+ for (;;) {
+ for (int i = 0; i < NSIG + 1; i++) {
+ jint n = pending_signals[i];
+ if (n > 0 && n == Atomic::cmpxchg(n - 1, &pending_signals[i], n)) {
+ return i;
+ }
+ }
+ if (!wait) {
+ return -1;
+ }
+ JavaThread *thread = JavaThread::current();
+ ThreadBlockInVM tbivm(thread);
+
+ bool threadIsSuspended;
+ do {
+ thread->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
+ ::SEM_WAIT(sig_sem);
+
+ // were we externally suspended while we were waiting?
+ threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
+ if (threadIsSuspended) {
+ //
+ // The semaphore has been incremented, but while we were waiting
+ // another thread suspended us. We don't want to continue running
+ // while suspended because that would surprise the thread that
+ // suspended us.
+ //
+ ::SEM_POST(sig_sem);
+
+ thread->java_suspend_self();
+ }
+ } while (threadIsSuspended);
+ }
+}
+
+int os::signal_lookup() {
+ return check_pending_signals(false);
+}
+
+int os::signal_wait() {
+ return check_pending_signals(true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Virtual Memory
+
+int os::vm_page_size() {
+ // Seems redundant as all get out
+ assert(os::Bsd::page_size() != -1, "must call os::init");
+ return os::Bsd::page_size();
+}
+
+// Solaris allocates memory by pages.
+int os::vm_allocation_granularity() {
+ assert(os::Bsd::page_size() != -1, "must call os::init");
+ return os::Bsd::page_size();
+}
+
+// Rationale behind this function:
+// current (Mon Apr 25 20:12:18 MSD 2005) oprofile drops samples without executable
+// mapping for address (see lookup_dcookie() in the kernel module), thus we cannot get
+// samples for JITted code. Here we create private executable mapping over the code cache
+// and then we can use standard (well, almost, as mapping can change) way to provide
+// info for the reporting script by storing timestamp and location of symbol
+void bsd_wrap_code(char* base, size_t size) {
+ static volatile jint cnt = 0;
+
+ if (!UseOprofile) {
+ return;
+ }
+
+ char buf[PATH_MAX + 1];
+ int num = Atomic::add(1, &cnt);
+
+ snprintf(buf, PATH_MAX + 1, "%s/hs-vm-%d-%d",
+ os::get_temp_directory(), os::current_process_id(), num);
+ unlink(buf);
+
+ int fd = ::open(buf, O_CREAT | O_RDWR, S_IRWXU);
+
+ if (fd != -1) {
+ off_t rv = ::lseek(fd, size-2, SEEK_SET);
+ if (rv != (off_t)-1) {
+ if (::write(fd, "", 1) == 1) {
+ mmap(base, size,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE, fd, 0);
+ }
+ }
+ ::close(fd);
+ unlink(buf);
+ }
+}
+
+// NOTE: Bsd kernel does not really reserve the pages for us.
+// All it does is to check if there are enough free pages
+// left at the time of mmap(). This could be a potential
+// problem.
+bool os::commit_memory(char* addr, size_t size, bool exec) {
+ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
+#ifdef __OpenBSD__
+ // XXX: Work-around mmap/MAP_FIXED bug temporarily on OpenBSD
+ return ::mprotect(addr, size, prot) == 0;
+#else
+ uintptr_t res = (uintptr_t) ::mmap(addr, size, prot,
+ MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
+ return res != (uintptr_t) MAP_FAILED;
+#endif
+}
+
+#ifndef _ALLBSD_SOURCE
+// Define MAP_HUGETLB here so we can build HotSpot on old systems.
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000
+#endif
+
+// Define MADV_HUGEPAGE here so we can build HotSpot on old systems.
+#ifndef MADV_HUGEPAGE
+#define MADV_HUGEPAGE 14
+#endif
+#endif
+
+bool os::commit_memory(char* addr, size_t size, size_t alignment_hint,
+ bool exec) {
+#ifndef _ALLBSD_SOURCE
+ if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
+ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
+ uintptr_t res =
+ (uintptr_t) ::mmap(addr, size, prot,
+ MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB,
+ -1, 0);
+ return res != (uintptr_t) MAP_FAILED;
+ }
+#endif
+
+ return commit_memory(addr, size, exec);
+}
+
+void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
+#ifndef _ALLBSD_SOURCE
+ if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
+ // We don't check the return value: madvise(MADV_HUGEPAGE) may not
+ // be supported or the memory may already be backed by huge pages.
+ ::madvise(addr, bytes, MADV_HUGEPAGE);
+ }
+#endif
+}
+
+void os::free_memory(char *addr, size_t bytes) {
+ ::madvise(addr, bytes, MADV_DONTNEED);
+}
+
+void os::numa_make_global(char *addr, size_t bytes) {
+}
+
+void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
+}
+
+bool os::numa_topology_changed() { return false; }
+
+size_t os::numa_get_groups_num() {
+ return 1;
+}
+
+int os::numa_get_group_id() {
+ return 0;
+}
+
+size_t os::numa_get_leaf_groups(int *ids, size_t size) {
+ if (size > 0) {
+ ids[0] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+bool os::get_page_info(char *start, page_info* info) {
+ return false;
+}
+
+char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info* page_found) {
+ return end;
+}
+
+#ifndef _ALLBSD_SOURCE
+// Something to do with the numa-aware allocator needs these symbols
+extern "C" JNIEXPORT void numa_warn(int number, char *where, ...) { }
+extern "C" JNIEXPORT void numa_error(char *where) { }
+extern "C" JNIEXPORT int fork1() { return fork(); }
+
+
+// If we are running with libnuma version > 2, then we should
+// be trying to use symbols with versions 1.1
+// If we are running with earlier version, which did not have symbol versions,
+// we should use the base version.
+void* os::Bsd::libnuma_dlsym(void* handle, const char *name) {
+ void *f = dlvsym(handle, name, "libnuma_1.1");
+ if (f == NULL) {
+ f = dlsym(handle, name);
+ }
+ return f;
+}
+
+bool os::Bsd::libnuma_init() {
+ // sched_getcpu() should be in libc.
+ set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t,
+ dlsym(RTLD_DEFAULT, "sched_getcpu")));
+
+ if (sched_getcpu() != -1) { // Does it work?
+ void *handle = dlopen("libnuma.so.1", RTLD_LAZY);
+ if (handle != NULL) {
+ set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t,
+ libnuma_dlsym(handle, "numa_node_to_cpus")));
+ set_numa_max_node(CAST_TO_FN_PTR(numa_max_node_func_t,
+ libnuma_dlsym(handle, "numa_max_node")));
+ set_numa_available(CAST_TO_FN_PTR(numa_available_func_t,
+ libnuma_dlsym(handle, "numa_available")));
+ set_numa_tonode_memory(CAST_TO_FN_PTR(numa_tonode_memory_func_t,
+ libnuma_dlsym(handle, "numa_tonode_memory")));
+ set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t,
+ libnuma_dlsym(handle, "numa_interleave_memory")));
+
+
+ if (numa_available() != -1) {
+ set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes"));
+ // Create a cpu -> node mapping
+ _cpu_to_node = new (ResourceObj::C_HEAP) GrowableArray<int>(0, true);
+ rebuild_cpu_to_node_map();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// rebuild_cpu_to_node_map() constructs a table mapping cpud id to node id.
+// The table is later used in get_node_by_cpu().
+void os::Bsd::rebuild_cpu_to_node_map() {
+ const size_t NCPUS = 32768; // Since the buffer size computation is very obscure
+ // in libnuma (possible values are starting from 16,
+ // and continuing up with every other power of 2, but less
+ // than the maximum number of CPUs supported by kernel), and
+ // is a subject to change (in libnuma version 2 the requirements
+ // are more reasonable) we'll just hardcode the number they use
+ // in the library.
+ const size_t BitsPerCLong = sizeof(long) * CHAR_BIT;
+
+ size_t cpu_num = os::active_processor_count();
+ size_t cpu_map_size = NCPUS / BitsPerCLong;
+ size_t cpu_map_valid_size =
+ MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size);
+
+ cpu_to_node()->clear();
+ cpu_to_node()->at_grow(cpu_num - 1);
+ size_t node_num = numa_get_groups_num();
+
+ unsigned long *cpu_map = NEW_C_HEAP_ARRAY(unsigned long, cpu_map_size);
+ for (size_t i = 0; i < node_num; i++) {
+ if (numa_node_to_cpus(i, cpu_map, cpu_map_size * sizeof(unsigned long)) != -1) {
+ for (size_t j = 0; j < cpu_map_valid_size; j++) {
+ if (cpu_map[j] != 0) {
+ for (size_t k = 0; k < BitsPerCLong; k++) {
+ if (cpu_map[j] & (1UL << k)) {
+ cpu_to_node()->at_put(j * BitsPerCLong + k, i);
+ }
+ }
+ }
+ }
+ }
+ }
+ FREE_C_HEAP_ARRAY(unsigned long, cpu_map);
+}
+
+int os::Bsd::get_node_by_cpu(int cpu_id) {
+ if (cpu_to_node() != NULL && cpu_id >= 0 && cpu_id < cpu_to_node()->length()) {
+ return cpu_to_node()->at(cpu_id);
+ }
+ return -1;
+}
+
+GrowableArray<int>* os::Bsd::_cpu_to_node;
+os::Bsd::sched_getcpu_func_t os::Bsd::_sched_getcpu;
+os::Bsd::numa_node_to_cpus_func_t os::Bsd::_numa_node_to_cpus;
+os::Bsd::numa_max_node_func_t os::Bsd::_numa_max_node;
+os::Bsd::numa_available_func_t os::Bsd::_numa_available;
+os::Bsd::numa_tonode_memory_func_t os::Bsd::_numa_tonode_memory;
+os::Bsd::numa_interleave_memory_func_t os::Bsd::_numa_interleave_memory;
+unsigned long* os::Bsd::_numa_all_nodes;
+#endif
+
+bool os::uncommit_memory(char* addr, size_t size) {
+#ifdef __OpenBSD__
+ // XXX: Work-around mmap/MAP_FIXED bug temporarily on OpenBSD
+ return ::mprotect(addr, size, PROT_NONE) == 0;
+#else
+ uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE,
+ MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
+ return res != (uintptr_t) MAP_FAILED;
+#endif
+}
+
+bool os::create_stack_guard_pages(char* addr, size_t size) {
+ return os::commit_memory(addr, size);
+}
+
+// If this is a growable mapping, remove the guard pages entirely by
+// munmap()ping them. If not, just call uncommit_memory().
+bool os::remove_stack_guard_pages(char* addr, size_t size) {
+ return os::uncommit_memory(addr, size);
+}
+
+static address _highest_vm_reserved_address = NULL;
+
+// If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory
+// at 'requested_addr'. If there are existing memory mappings at the same
+// location, however, they will be overwritten. If 'fixed' is false,
+// 'requested_addr' is only treated as a hint, the return value may or
+// may not start from the requested address. Unlike Bsd mmap(), this
+// function returns NULL to indicate failure.
+static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) {
+ char * addr;
+ int flags;
+
+ flags = MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS;
+ if (fixed) {
+ assert((uintptr_t)requested_addr % os::Bsd::page_size() == 0, "unaligned address");
+ flags |= MAP_FIXED;
+ }
+
+ // Map uncommitted pages PROT_READ and PROT_WRITE, change access
+ // to PROT_EXEC if executable when we commit the page.
+ addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
+ flags, -1, 0);
+
+ if (addr != MAP_FAILED) {
+ // anon_mmap() should only get called during VM initialization,
+ // don't need lock (actually we can skip locking even it can be called
+ // from multiple threads, because _highest_vm_reserved_address is just a
+ // hint about the upper limit of non-stack memory regions.)
+ if ((address)addr + bytes > _highest_vm_reserved_address) {
+ _highest_vm_reserved_address = (address)addr + bytes;
+ }
+ }
+
+ return addr == MAP_FAILED ? NULL : addr;
+}
+
+// Don't update _highest_vm_reserved_address, because there might be memory
+// regions above addr + size. If so, releasing a memory region only creates
+// a hole in the address space, it doesn't help prevent heap-stack collision.
+//
+static int anon_munmap(char * addr, size_t size) {
+ return ::munmap(addr, size) == 0;
+}
+
+char* os::reserve_memory(size_t bytes, char* requested_addr,
+ size_t alignment_hint) {
+ return anon_mmap(requested_addr, bytes, (requested_addr != NULL));
+}
+
+bool os::release_memory(char* addr, size_t size) {
+ return anon_munmap(addr, size);
+}
+
+static address highest_vm_reserved_address() {
+ return _highest_vm_reserved_address;
+}
+
+static bool bsd_mprotect(char* addr, size_t size, int prot) {
+ // Bsd wants the mprotect address argument to be page aligned.
+ char* bottom = (char*)align_size_down((intptr_t)addr, os::Bsd::page_size());
+
+ // According to SUSv3, mprotect() should only be used with mappings
+ // established by mmap(), and mmap() always maps whole pages. Unaligned
+ // 'addr' likely indicates problem in the VM (e.g. trying to change
+ // protection of malloc'ed or statically allocated memory). Check the
+ // caller if you hit this assert.
+ assert(addr == bottom, "sanity check");
+
+ size = align_size_up(pointer_delta(addr, bottom, 1) + size, os::Bsd::page_size());
+ return ::mprotect(bottom, size, prot) == 0;
+}
+
+// Set protections specified
+bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
+ bool is_committed) {
+ unsigned int p = 0;
+ switch (prot) {
+ case MEM_PROT_NONE: p = PROT_NONE; break;
+ case MEM_PROT_READ: p = PROT_READ; break;
+ case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break;
+ case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
+ default:
+ ShouldNotReachHere();
+ }
+ // is_committed is unused.
+ return bsd_mprotect(addr, bytes, p);
+}
+
+bool os::guard_memory(char* addr, size_t size) {
+ return bsd_mprotect(addr, size, PROT_NONE);
+}
+
+bool os::unguard_memory(char* addr, size_t size) {
+ return bsd_mprotect(addr, size, PROT_READ|PROT_WRITE);
+}
+
+bool os::Bsd::hugetlbfs_sanity_check(bool warn, size_t page_size) {
+ bool result = false;
+#ifndef _ALLBSD_SOURCE
+ void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
+ -1, 0);
+
+ if (p != (void *) -1) {
+ // We don't know if this really is a huge page or not.
+ FILE *fp = fopen("/proc/self/maps", "r");
+ if (fp) {
+ while (!feof(fp)) {
+ char chars[257];
+ long x = 0;
+ if (fgets(chars, sizeof(chars), fp)) {
+ if (sscanf(chars, "%lx-%*x", &x) == 1
+ && x == (long)p) {
+ if (strstr (chars, "hugepage")) {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ }
+ munmap (p, page_size);
+ if (result)
+ return true;
+ }
+
+ if (warn) {
+ warning("HugeTLBFS is not supported by the operating system.");
+ }
+#endif
+
+ return result;
+}
+
+/*
+* Set the coredump_filter bits to include largepages in core dump (bit 6)
+*
+* From the coredump_filter documentation:
+*
+* - (bit 0) anonymous private memory
+* - (bit 1) anonymous shared memory
+* - (bit 2) file-backed private memory
+* - (bit 3) file-backed shared memory
+* - (bit 4) ELF header pages in file-backed private memory areas (it is
+* effective only if the bit 2 is cleared)
+* - (bit 5) hugetlb private memory
+* - (bit 6) hugetlb shared memory
+*/
+static void set_coredump_filter(void) {
+ FILE *f;
+ long cdm;
+
+ if ((f = fopen("/proc/self/coredump_filter", "r+")) == NULL) {
+ return;
+ }
+
+ if (fscanf(f, "%lx", &cdm) != 1) {
+ fclose(f);
+ return;
+ }
+
+ rewind(f);
+
+ if ((cdm & LARGEPAGES_BIT) == 0) {
+ cdm |= LARGEPAGES_BIT;
+ fprintf(f, "%#lx", cdm);
+ }
+
+ fclose(f);
+}
+
+// Large page support
+
+static size_t _large_page_size = 0;
+
+void os::large_page_init() {
+#ifndef _ALLBSD_SOURCE
+ if (!UseLargePages) {
+ UseHugeTLBFS = false;
+ UseSHM = false;
+ return;
+ }
+
+ if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) {
+ // If UseLargePages is specified on the command line try both methods,
+ // if it's default, then try only HugeTLBFS.
+ if (FLAG_IS_DEFAULT(UseLargePages)) {
+ UseHugeTLBFS = true;
+ } else {
+ UseHugeTLBFS = UseSHM = true;
+ }
+ }
+
+ if (LargePageSizeInBytes) {
+ _large_page_size = LargePageSizeInBytes;
+ } else {
+ // large_page_size on Bsd is used to round up heap size. x86 uses either
+ // 2M or 4M page, depending on whether PAE (Physical Address Extensions)
+ // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
+ // page as large as 256M.
+ //
+ // Here we try to figure out page size by parsing /proc/meminfo and looking
+ // for a line with the following format:
+ // Hugepagesize: 2048 kB
+ //
+ // If we can't determine the value (e.g. /proc is not mounted, or the text
+ // format has been changed), we'll use the largest page size supported by
+ // the processor.
+
+#ifndef ZERO
+ _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
+ ARM_ONLY(2 * M) PPC_ONLY(4 * M);
+#endif // ZERO
+
+ FILE *fp = fopen("/proc/meminfo", "r");
+ if (fp) {
+ while (!feof(fp)) {
+ int x = 0;
+ char buf[16];
+ if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
+ if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
+ _large_page_size = x * K;
+ break;
+ }
+ } else {
+ // skip to next line
+ for (;;) {
+ int ch = fgetc(fp);
+ if (ch == EOF || ch == (int)'\n') break;
+ }
+ }
+ }
+ fclose(fp);
+ }
+ }
+
+ // print a warning if any large page related flag is specified on command line
+ bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
+
+ const size_t default_page_size = (size_t)Bsd::page_size();
+ if (_large_page_size > default_page_size) {
+ _page_sizes[0] = _large_page_size;
+ _page_sizes[1] = default_page_size;
+ _page_sizes[2] = 0;
+ }
+ UseHugeTLBFS = UseHugeTLBFS &&
+ Bsd::hugetlbfs_sanity_check(warn_on_failure, _large_page_size);
+
+ if (UseHugeTLBFS)
+ UseSHM = false;
+
+ UseLargePages = UseHugeTLBFS || UseSHM;
+
+ set_coredump_filter();
+#endif
+}
+
+#ifndef _ALLBSD_SOURCE
+#ifndef SHM_HUGETLB
+#define SHM_HUGETLB 04000
+#endif
+#endif
+
+char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
+ // "exec" is passed in but not used. Creating the shared image for
+ // the code cache doesn't have an SHM_X executable permission to check.
+ assert(UseLargePages && UseSHM, "only for SHM large pages");
+
+ key_t key = IPC_PRIVATE;
+ char *addr;
+
+ bool warn_on_failure = UseLargePages &&
+ (!FLAG_IS_DEFAULT(UseLargePages) ||
+ !FLAG_IS_DEFAULT(LargePageSizeInBytes)
+ );
+ char msg[128];
+
+ // Create a large shared memory region to attach to based on size.
+ // Currently, size is the total size of the heap
+#ifndef _ALLBSD_SOURCE
+ int shmid = shmget(key, bytes, SHM_HUGETLB|IPC_CREAT|SHM_R|SHM_W);
+#else
+ int shmid = shmget(key, bytes, IPC_CREAT|SHM_R|SHM_W);
+#endif
+ if (shmid == -1) {
+ // Possible reasons for shmget failure:
+ // 1. shmmax is too small for Java heap.
+ // > check shmmax value: cat /proc/sys/kernel/shmmax
+ // > increase shmmax value: echo "0xffffffff" > /proc/sys/kernel/shmmax
+ // 2. not enough large page memory.
+ // > check available large pages: cat /proc/meminfo
+ // > increase amount of large pages:
+ // echo new_value > /proc/sys/vm/nr_hugepages
+ // Note 1: different Bsd may use different name for this property,
+ // e.g. on Redhat AS-3 it is "hugetlb_pool".
+ // Note 2: it's possible there's enough physical memory available but
+ // they are so fragmented after a long run that they can't
+ // coalesce into large pages. Try to reserve large pages when
+ // the system is still "fresh".
+ if (warn_on_failure) {
+ jio_snprintf(msg, sizeof(msg), "Failed to reserve shared memory (errno = %d).", errno);
+ warning(msg);
+ }
+ return NULL;
+ }
+
+ // attach to the region
+ addr = (char*)shmat(shmid, req_addr, 0);
+ int err = errno;
+
+ // Remove shmid. If shmat() is successful, the actual shared memory segment
+ // will be deleted when it's detached by shmdt() or when the process
+ // terminates. If shmat() is not successful this will remove the shared
+ // segment immediately.
+ shmctl(shmid, IPC_RMID, NULL);
+
+ if ((intptr_t)addr == -1) {
+ if (warn_on_failure) {
+ jio_snprintf(msg, sizeof(msg), "Failed to attach shared memory (errno = %d).", err);
+ warning(msg);
+ }
+ return NULL;
+ }
+
+ return addr;
+}
+
+bool os::release_memory_special(char* base, size_t bytes) {
+ // detaching the SHM segment will also delete it, see reserve_memory_special()
+ int rslt = shmdt(base);
+ return rslt == 0;
+}
+
+size_t os::large_page_size() {
+ return _large_page_size;
+}
+
+// HugeTLBFS allows application to commit large page memory on demand;
+// with SysV SHM the entire memory region must be allocated as shared
+// memory.
+bool os::can_commit_large_page_memory() {
+ return UseHugeTLBFS;
+}
+
+bool os::can_execute_large_page_memory() {
+ return UseHugeTLBFS;
+}
+
+// Reserve memory at an arbitrary address, only if that area is
+// available (and not reserved for something else).
+
+char* os::attempt_reserve_memory_at(size_t bytes, char* requested_addr) {
+ const int max_tries = 10;
+ char* base[max_tries];
+ size_t size[max_tries];
+ const size_t gap = 0x000000;
+
+ // Assert only that the size is a multiple of the page size, since
+ // that's all that mmap requires, and since that's all we really know
+ // about at this low abstraction level. If we need higher alignment,
+ // we can either pass an alignment to this method or verify alignment
+ // in one of the methods further up the call chain. See bug 5044738.
+ assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
+
+ // Repeatedly allocate blocks until the block is allocated at the
+ // right spot. Give up after max_tries. Note that reserve_memory() will
+ // automatically update _highest_vm_reserved_address if the call is
+ // successful. The variable tracks the highest memory address every reserved
+ // by JVM. It is used to detect heap-stack collision if running with
+ // fixed-stack BsdThreads. Because here we may attempt to reserve more
+ // space than needed, it could confuse the collision detecting code. To
+ // solve the problem, save current _highest_vm_reserved_address and
+ // calculate the correct value before return.
+ address old_highest = _highest_vm_reserved_address;
+
+ // Bsd mmap allows caller to pass an address as hint; give it a try first,
+ // if kernel honors the hint then we can return immediately.
+ char * addr = anon_mmap(requested_addr, bytes, false);
+ if (addr == requested_addr) {
+ return requested_addr;
+ }
+
+ if (addr != NULL) {
+ // mmap() is successful but it fails to reserve at the requested address
+ anon_munmap(addr, bytes);
+ }
+
+ int i;
+ for (i = 0; i < max_tries; ++i) {
+ base[i] = reserve_memory(bytes);
+
+ if (base[i] != NULL) {
+ // Is this the block we wanted?
+ if (base[i] == requested_addr) {
+ size[i] = bytes;
+ break;
+ }
+
+ // Does this overlap the block we wanted? Give back the overlapped
+ // parts and try again.
+
+ size_t top_overlap = requested_addr + (bytes + gap) - base[i];
+ if (top_overlap >= 0 && top_overlap < bytes) {
+ unmap_memory(base[i], top_overlap);
+ base[i] += top_overlap;
+ size[i] = bytes - top_overlap;
+ } else {
+ size_t bottom_overlap = base[i] + bytes - requested_addr;
+ if (bottom_overlap >= 0 && bottom_overlap < bytes) {
+ unmap_memory(requested_addr, bottom_overlap);
+ size[i] = bytes - bottom_overlap;
+ } else {
+ size[i] = bytes;
+ }
+ }
+ }
+ }
+
+ // Give back the unused reserved pieces.
+
+ for (int j = 0; j < i; ++j) {
+ if (base[j] != NULL) {
+ unmap_memory(base[j], size[j]);
+ }
+ }
+
+ if (i < max_tries) {
+ _highest_vm_reserved_address = MAX2(old_highest, (address)requested_addr + bytes);
+ return requested_addr;
+ } else {
+ _highest_vm_reserved_address = old_highest;
+ return NULL;
+ }
+}
+
+size_t os::read(int fd, void *buf, unsigned int nBytes) {
+ RESTARTABLE_RETURN_INT(::read(fd, buf, nBytes));
+}
+
+// TODO-FIXME: reconcile Solaris' os::sleep with the bsd variation.
+// Solaris uses poll(), bsd uses park().
+// Poll() is likely a better choice, assuming that Thread.interrupt()
+// generates a SIGUSRx signal. Note that SIGUSR1 can interfere with
+// SIGSEGV, see 4355769.
+
+const int NANOSECS_PER_MILLISECS = 1000000;
+
+int os::sleep(Thread* thread, jlong millis, bool interruptible) {
+ assert(thread == Thread::current(), "thread consistency check");
+
+ ParkEvent * const slp = thread->_SleepEvent ;
+ slp->reset() ;
+ OrderAccess::fence() ;
+
+ if (interruptible) {
+ jlong prevtime = javaTimeNanos();
+
+ for (;;) {
+ if (os::is_interrupted(thread, true)) {
+ return OS_INTRPT;
+ }
+
+ jlong newtime = javaTimeNanos();
+
+ if (newtime - prevtime < 0) {
+ // time moving backwards, should only happen if no monotonic clock
+ // not a guarantee() because JVM should not abort on kernel/glibc bugs
+ assert(!Bsd::supports_monotonic_clock(), "time moving backwards");
+ } else {
+ millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
+ }
+
+ if(millis <= 0) {
+ return OS_OK;
+ }
+
+ prevtime = newtime;
+
+ {
+ assert(thread->is_Java_thread(), "sanity check");
+ JavaThread *jt = (JavaThread *) thread;
+ ThreadBlockInVM tbivm(jt);
+ OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
+
+ jt->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or
+ // java_suspend_self() via check_and_wait_while_suspended()
+
+ slp->park(millis);
+
+ // were we externally suspended while we were waiting?
+ jt->check_and_wait_while_suspended();
+ }
+ }
+ } else {
+ OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
+ jlong prevtime = javaTimeNanos();
+
+ for (;;) {
+ // It'd be nice to avoid the back-to-back javaTimeNanos() calls on
+ // the 1st iteration ...
+ jlong newtime = javaTimeNanos();
+
+ if (newtime - prevtime < 0) {
+ // time moving backwards, should only happen if no monotonic clock
+ // not a guarantee() because JVM should not abort on kernel/glibc bugs
+ assert(!Bsd::supports_monotonic_clock(), "time moving backwards");
+ } else {
+ millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
+ }
+
+ if(millis <= 0) break ;
+
+ prevtime = newtime;
+ slp->park(millis);
+ }
+ return OS_OK ;
+ }
+}
+
+int os::naked_sleep() {
+ // %% make the sleep time an integer flag. for now use 1 millisec.
+ return os::sleep(Thread::current(), 1, false);
+}
+
+// Sleep forever; naked call to OS-specific sleep; use with CAUTION
+void os::infinite_sleep() {
+ while (true) { // sleep forever ...
+ ::sleep(100); // ... 100 seconds at a time
+ }
+}
+
+// Used to convert frequent JVM_Yield() to nops
+bool os::dont_yield() {
+ return DontYieldALot;
+}
+
+void os::yield() {
+ sched_yield();
+}
+
+os::YieldResult os::NakedYield() { sched_yield(); return os::YIELD_UNKNOWN ;}
+
+void os::yield_all(int attempts) {
+ // Yields to all threads, including threads with lower priorities
+ // Threads on Bsd are all with same priority. The Solaris style
+ // os::yield_all() with nanosleep(1ms) is not necessary.
+ sched_yield();
+}
+
+// Called from the tight loops to possibly influence time-sharing heuristics
+void os::loop_breaker(int attempts) {
+ os::yield_all(attempts);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// thread priority support
+
+// Note: Normal Bsd applications are run with SCHED_OTHER policy. SCHED_OTHER
+// only supports dynamic priority, static priority must be zero. For real-time
+// applications, Bsd supports SCHED_RR which allows static priority (1-99).
+// However, for large multi-threaded applications, SCHED_RR is not only slower
+// than SCHED_OTHER, but also very unstable (my volano tests hang hard 4 out
+// of 5 runs - Sep 2005).
+//
+// The following code actually changes the niceness of kernel-thread/LWP. It
+// has an assumption that setpriority() only modifies one kernel-thread/LWP,
+// not the entire user process, and user level threads are 1:1 mapped to kernel
+// threads. It has always been the case, but could change in the future. For
+// this reason, the code should not be used as default (ThreadPriorityPolicy=0).
+// It is only used when ThreadPriorityPolicy=1 and requires root privilege.
+
+#if defined(_ALLBSD_SOURCE) && !defined(__APPLE__)
+int os::java_to_os_priority[MaxPriority + 1] = {
+ 19, // 0 Entry should never be used
+
+ 0, // 1 MinPriority
+ 3, // 2
+ 6, // 3
+
+ 10, // 4
+ 15, // 5 NormPriority
+ 18, // 6
+
+ 21, // 7
+ 25, // 8
+ 28, // 9 NearMaxPriority
+
+ 31 // 10 MaxPriority
+};
+#elif defined(__APPLE__)
+/* Using Mach high-level priority assignments */
+int os::java_to_os_priority[MaxPriority + 1] = {
+ 0, // 0 Entry should never be used (MINPRI_USER)
+
+ 27, // 1 MinPriority
+ 28, // 2
+ 29, // 3
+
+ 30, // 4
+ 31, // 5 NormPriority (BASEPRI_DEFAULT)
+ 32, // 6
+
+ 33, // 7
+ 34, // 8
+ 35, // 9 NearMaxPriority
+
+ 36 // 10 MaxPriority
+};
+#else
+int os::java_to_os_priority[MaxPriority + 1] = {
+ 19, // 0 Entry should never be used
+
+ 4, // 1 MinPriority
+ 3, // 2
+ 2, // 3
+
+ 1, // 4
+ 0, // 5 NormPriority
+ -1, // 6
+
+ -2, // 7
+ -3, // 8
+ -4, // 9 NearMaxPriority
+
+ -5 // 10 MaxPriority
+};
+#endif
+
+static int prio_init() {
+ if (ThreadPriorityPolicy == 1) {
+ // Only root can raise thread priority. Don't allow ThreadPriorityPolicy=1
+ // if effective uid is not root. Perhaps, a more elegant way of doing
+ // this is to test CAP_SYS_NICE capability, but that will require libcap.so
+ if (geteuid() != 0) {
+ if (!FLAG_IS_DEFAULT(ThreadPriorityPolicy)) {
+ warning("-XX:ThreadPriorityPolicy requires root privilege on Bsd");
+ }
+ ThreadPriorityPolicy = 0;
+ }
+ }
+ return 0;
+}
+
+OSReturn os::set_native_priority(Thread* thread, int newpri) {
+ if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) return OS_OK;
+
+#ifdef __OpenBSD__
+ // OpenBSD pthread_setprio starves low priority threads
+ return OS_OK;
+#elif defined(__FreeBSD__)
+ int ret = pthread_setprio(thread->osthread()->pthread_id(), newpri);
+#elif defined(__APPLE__) || defined(__NetBSD__)
+ struct sched_param sp;
+ int policy;
+ pthread_t self = pthread_self();
+
+ if (pthread_getschedparam(self, &policy, &sp) != 0)
+ return OS_ERR;
+
+ sp.sched_priority = newpri;
+ if (pthread_setschedparam(self, policy, &sp) != 0)
+ return OS_ERR;
+
+ return OS_OK;
+#else
+ int ret = setpriority(PRIO_PROCESS, thread->osthread()->thread_id(), newpri);
+ return (ret == 0) ? OS_OK : OS_ERR;
+#endif
+}
+
+OSReturn os::get_native_priority(const Thread* const thread, int *priority_ptr) {
+ if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) {
+ *priority_ptr = java_to_os_priority[NormPriority];
+ return OS_OK;
+ }
+
+ errno = 0;
+#if defined(__OpenBSD__) || defined(__FreeBSD__)
+ *priority_ptr = pthread_getprio(thread->osthread()->pthread_id());
+#elif defined(__APPLE__) || defined(__NetBSD__)
+ int policy;
+ struct sched_param sp;
+
+ pthread_getschedparam(pthread_self(), &policy, &sp);
+ *priority_ptr = sp.sched_priority;
+#else
+ *priority_ptr = getpriority(PRIO_PROCESS, thread->osthread()->thread_id());
+#endif
+ return (*priority_ptr != -1 || errno == 0 ? OS_OK : OS_ERR);
+}
+
+// Hint to the underlying OS that a task switch would not be good.
+// Void return because it's a hint and can fail.
+void os::hint_no_preempt() {}
+
+////////////////////////////////////////////////////////////////////////////////
+// suspend/resume support
+
+// the low-level signal-based suspend/resume support is a remnant from the
+// old VM-suspension that used to be for java-suspension, safepoints etc,
+// within hotspot. Now there is a single use-case for this:
+// - calling get_thread_pc() on the VMThread by the flat-profiler task
+// that runs in the watcher thread.
+// The remaining code is greatly simplified from the more general suspension
+// code that used to be used.
+//
+// The protocol is quite simple:
+// - suspend:
+// - sends a signal to the target thread
+// - polls the suspend state of the osthread using a yield loop
+// - target thread signal handler (SR_handler) sets suspend state
+// and blocks in sigsuspend until continued
+// - resume:
+// - sets target osthread state to continue
+// - sends signal to end the sigsuspend loop in the SR_handler
+//
+// Note that the SR_lock plays no role in this suspend/resume protocol.
+//
+
+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);
+}
+
+//
+// Handler function invoked when a thread's execution is suspended or
+// resumed. We have to be careful that only async-safe functions are
+// called here (Note: most pthread functions are not async safe and
+// should be avoided.)
+//
+// Note: sigwait() is a more natural fit than sigsuspend() from an
+// 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 == 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() != SR_CONTINUE);
+
+ resume_clear_context(osthread);
+
+ } else {
+ assert(action == SR_CONTINUE, "unexpected sr action");
+ // nothing special to do - just leave the handler
+ }
+
+ errno = old_errno;
+}
+
+
+static int SR_initialize() {
+ struct sigaction act;
+ char *s;
+ /* Get signal number to use for suspend/resume */
+ if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) {
+ int sig = ::strtol(s, 0, 10);
+ if (sig > 0 || sig < NSIG) {
+ SR_signum = sig;
+ }
+ }
+
+ assert(SR_signum > SIGSEGV && SR_signum > SIGBUS,
+ "SR_signum must be greater than max(SIGSEGV, SIGBUS), see 4355769");
+
+ sigemptyset(&SR_sigset);
+ sigaddset(&SR_sigset, SR_signum);
+
+ /* Set up signal handler for suspend/resume */
+ act.sa_flags = SA_RESTART|SA_SIGINFO;
+ act.sa_handler = (void (*)(int)) SR_handler;
+
+ // SR_signum is blocked by default.
+ // 4528190 - We also need to block pthread restart signal (32 on all
+ // supported Bsd platforms). Note that BsdThreads need to block
+ // this signal for all threads to work properly. So we don't have
+ // to use hard-coded signal number when setting up the mask.
+ pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask);
+
+ if (sigaction(SR_signum, &act, 0) == -1) {
+ return -1;
+ }
+
+ // Save signal flag
+ os::Bsd::set_our_sigflags(SR_signum, act.sa_flags);
+ return 0;
+}
+
+static int SR_finalize() {
+ 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(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(SR_NONE);
+ return true;
+ }
+ else {
+ osthread->sr.set_suspend_action(SR_NONE);
+ return false;
+ }
+}
+
+static void do_resume(OSThread* osthread) {
+ assert(osthread->sr.is_suspended(), "thread should be suspended");
+ osthread->sr.set_suspend_action(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(SR_NONE);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// interrupt support
+
+void os::interrupt(Thread* thread) {
+ assert(Thread::current() == thread || Threads_lock->owned_by_self(),
+ "possibility of dangling Thread pointer");
+
+ OSThread* osthread = thread->osthread();
+
+ if (!osthread->interrupted()) {
+ osthread->set_interrupted(true);
+ // More than one thread can get here with the same value of osthread,
+ // resulting in multiple notifications. We do, however, want the store
+ // to interrupted() to be visible to other threads before we execute unpark().
+ OrderAccess::fence();
+ ParkEvent * const slp = thread->_SleepEvent ;
+ if (slp != NULL) slp->unpark() ;
+ }
+
+ // For JSR166. Unpark even if interrupt status already was set
+ if (thread->is_Java_thread())
+ ((JavaThread*)thread)->parker()->unpark();
+
+ ParkEvent * ev = thread->_ParkEvent ;
+ if (ev != NULL) ev->unpark() ;
+
+}
+
+bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
+ assert(Thread::current() == thread || Threads_lock->owned_by_self(),
+ "possibility of dangling Thread pointer");
+
+ OSThread* osthread = thread->osthread();
+
+ bool interrupted = osthread->interrupted();
+
+ if (interrupted && clear_interrupted) {
+ osthread->set_interrupted(false);
+ // consider thread->_SleepEvent->reset() ... optional optimization
+ }
+
+ return interrupted;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+// signal handling (except suspend/resume)
+
+// This routine may be used by user applications as a "hook" to catch signals.
+// The user-defined signal handler must pass unrecognized signals to this
+// routine, and if it returns true (non-zero), then the signal handler must
+// return immediately. If the flag "abort_if_unrecognized" is true, then this
+// routine will never retun false (zero), but instead will execute a VM panic
+// routine kill the process.
+//
+// If this routine returns false, it is OK to call it again. This allows
+// the user-defined signal handler to perform checks either before or after
+// the VM performs its own checks. Naturally, the user code would be making
+// a serious error if it tried to handle an exception (such as a null check
+// or breakpoint) that the VM was generating for its own correct operation.
+//
+// This routine may recognize any of the following kinds of signals:
+// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1.
+// It should be consulted by handlers for any of those signals.
+//
+// The caller of this routine must pass in the three arguments supplied
+// to the function referred to in the "sa_sigaction" (not the "sa_handler")
+// field of the structure passed to sigaction(). This routine assumes that
+// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
+//
+// Note that the VM will print warnings if it detects conflicting signal
+// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
+//
+extern "C" JNIEXPORT int
+JVM_handle_bsd_signal(int signo, siginfo_t* siginfo,
+ void* ucontext, int abort_if_unrecognized);
+
+void signalHandler(int sig, siginfo_t* info, void* uc) {
+ assert(info != NULL && uc != NULL, "it must be old kernel");
+ JVM_handle_bsd_signal(sig, info, uc, true);
+}
+
+
+// This boolean allows users to forward their own non-matching signals
+// to JVM_handle_bsd_signal, harmlessly.
+bool os::Bsd::signal_handlers_are_installed = false;
+
+// For signal-chaining
+struct sigaction os::Bsd::sigact[MAXSIGNUM];
+unsigned int os::Bsd::sigs = 0;
+bool os::Bsd::libjsig_is_loaded = false;
+typedef struct sigaction *(*get_signal_t)(int);
+get_signal_t os::Bsd::get_signal_action = NULL;
+
+struct sigaction* os::Bsd::get_chained_signal_action(int sig) {
+ struct sigaction *actp = NULL;
+
+ if (libjsig_is_loaded) {
+ // Retrieve the old signal handler from libjsig
+ actp = (*get_signal_action)(sig);
+ }
+ if (actp == NULL) {
+ // Retrieve the preinstalled signal handler from jvm
+ actp = get_preinstalled_handler(sig);
+ }
+
+ return actp;
+}
+
+static bool call_chained_handler(struct sigaction *actp, int sig,
+ siginfo_t *siginfo, void *context) {
+ // Call the old signal handler
+ if (actp->sa_handler == SIG_DFL) {
+ // It's more reasonable to let jvm treat it as an unexpected exception
+ // instead of taking the default action.
+ return false;
+ } else if (actp->sa_handler != SIG_IGN) {
+ if ((actp->sa_flags & SA_NODEFER) == 0) {
+ // automaticlly block the signal
+ sigaddset(&(actp->sa_mask), sig);
+ }
+
+ sa_handler_t hand;
+ sa_sigaction_t sa;
+ bool siginfo_flag_set = (actp->sa_flags & SA_SIGINFO) != 0;
+ // retrieve the chained handler
+ if (siginfo_flag_set) {
+ sa = actp->sa_sigaction;
+ } else {
+ hand = actp->sa_handler;
+ }
+
+ if ((actp->sa_flags & SA_RESETHAND) != 0) {
+ actp->sa_handler = SIG_DFL;
+ }
+
+ // try to honor the signal mask
+ sigset_t oset;
+ pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset);
+
+ // call into the chained handler
+ if (siginfo_flag_set) {
+ (*sa)(sig, siginfo, context);
+ } else {
+ (*hand)(sig);
+ }
+
+ // restore the signal mask
+ pthread_sigmask(SIG_SETMASK, &oset, 0);
+ }
+ // Tell jvm's signal handler the signal is taken care of.
+ return true;
+}
+
+bool os::Bsd::chained_handler(int sig, siginfo_t* siginfo, void* context) {
+ bool chained = false;
+ // signal-chaining
+ if (UseSignalChaining) {
+ struct sigaction *actp = get_chained_signal_action(sig);
+ if (actp != NULL) {
+ chained = call_chained_handler(actp, sig, siginfo, context);
+ }
+ }
+ return chained;
+}
+
+struct sigaction* os::Bsd::get_preinstalled_handler(int sig) {
+ if ((( (unsigned int)1 << sig ) & sigs) != 0) {
+ return &sigact[sig];
+ }
+ return NULL;
+}
+
+void os::Bsd::save_preinstalled_handler(int sig, struct sigaction& oldAct) {
+ assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
+ sigact[sig] = oldAct;
+ sigs |= (unsigned int)1 << sig;
+}
+
+// for diagnostic
+int os::Bsd::sigflags[MAXSIGNUM];
+
+int os::Bsd::get_our_sigflags(int sig) {
+ assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
+ return sigflags[sig];
+}
+
+void os::Bsd::set_our_sigflags(int sig, int flags) {
+ assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
+ sigflags[sig] = flags;
+}
+
+void os::Bsd::set_signal_handler(int sig, bool set_installed) {
+ // Check for overwrite.
+ struct sigaction oldAct;
+ sigaction(sig, (struct sigaction*)NULL, &oldAct);
+
+ void* oldhand = oldAct.sa_sigaction
+ ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
+ : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
+ if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
+ oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
+ oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)signalHandler)) {
+ if (AllowUserSignalHandlers || !set_installed) {
+ // Do not overwrite; user takes responsibility to forward to us.
+ return;
+ } else if (UseSignalChaining) {
+ // save the old handler in jvm
+ save_preinstalled_handler(sig, oldAct);
+ // libjsig also interposes the sigaction() call below and saves the
+ // old sigaction on it own.
+ } else {
+ fatal(err_msg("Encountered unexpected pre-existing sigaction handler "
+ "%#lx for signal %d.", (long)oldhand, sig));
+ }
+ }
+
+ struct sigaction sigAct;
+ sigfillset(&(sigAct.sa_mask));
+ sigAct.sa_handler = SIG_DFL;
+ if (!set_installed) {
+ sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
+ } else {
+ sigAct.sa_sigaction = signalHandler;
+ sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
+ }
+ // Save flags, which are set by ours
+ assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
+ sigflags[sig] = sigAct.sa_flags;
+
+ int ret = sigaction(sig, &sigAct, &oldAct);
+ assert(ret == 0, "check");
+
+ void* oldhand2 = oldAct.sa_sigaction
+ ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
+ : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
+ assert(oldhand2 == oldhand, "no concurrent signal handler installation");
+}
+
+// install signal handlers for signals that HotSpot needs to
+// handle in order to support Java-level exception handling.
+
+void os::Bsd::install_signal_handlers() {
+ if (!signal_handlers_are_installed) {
+ signal_handlers_are_installed = true;
+
+ // signal-chaining
+ typedef void (*signal_setting_t)();
+ signal_setting_t begin_signal_setting = NULL;
+ signal_setting_t end_signal_setting = NULL;
+ begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
+ dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting"));
+ if (begin_signal_setting != NULL) {
+ end_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
+ dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
+ get_signal_action = CAST_TO_FN_PTR(get_signal_t,
+ dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
+ libjsig_is_loaded = true;
+ assert(UseSignalChaining, "should enable signal-chaining");
+ }
+ if (libjsig_is_loaded) {
+ // Tell libjsig jvm is setting signal handlers
+ (*begin_signal_setting)();
+ }
+
+ set_signal_handler(SIGSEGV, true);
+ set_signal_handler(SIGPIPE, true);
+ set_signal_handler(SIGBUS, true);
+ set_signal_handler(SIGILL, true);
+ set_signal_handler(SIGFPE, true);
+ set_signal_handler(SIGXFSZ, true);
+
+#if defined(__APPLE__)
+ // In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including
+ // signals caught and handled by the JVM. To work around this, we reset the mach task
+ // signal handler that's placed on our process by CrashReporter. This disables
+ // CrashReporter-based reporting.
+ //
+ // This work-around is not necessary for 10.5+, as CrashReporter no longer intercedes
+ // on caught fatal signals.
+ //
+ // Additionally, gdb installs both standard BSD signal handlers, and mach exception
+ // handlers. By replacing the existing task exception handler, we disable gdb's mach
+ // exception handling, while leaving the standard BSD signal handlers functional.
+ kern_return_t kr;
+ kr = task_set_exception_ports(mach_task_self(),
+ EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC,
+ MACH_PORT_NULL,
+ EXCEPTION_STATE_IDENTITY,
+ MACHINE_THREAD_STATE);
+
+ assert(kr == KERN_SUCCESS, "could not set mach task signal handler");
+#endif
+
+ if (libjsig_is_loaded) {
+ // Tell libjsig jvm finishes setting signal handlers
+ (*end_signal_setting)();
+ }
+
+ // We don't activate signal checker if libjsig is in place, we trust ourselves
+ // and if UserSignalHandler is installed all bets are off
+ if (CheckJNICalls) {
+ if (libjsig_is_loaded) {
+ tty->print_cr("Info: libjsig is activated, all active signal checking is disabled");
+ check_signals = false;
+ }
+ if (AllowUserSignalHandlers) {
+ tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
+ check_signals = false;
+ }
+ }
+ }
+}
+
+#ifndef _ALLBSD_SOURCE
+// This is the fastest way to get thread cpu time on Bsd.
+// Returns cpu time (user+sys) for any thread, not only for current.
+// POSIX compliant clocks are implemented in the kernels 2.6.16+.
+// It might work on 2.6.10+ with a special kernel/glibc patch.
+// For reference, please, see IEEE Std 1003.1-2004:
+// http://www.unix.org/single_unix_specification
+
+jlong os::Bsd::fast_thread_cpu_time(clockid_t clockid) {
+ struct timespec tp;
+ int rc = os::Bsd::clock_gettime(clockid, &tp);
+ assert(rc == 0, "clock_gettime is expected to return 0 code");
+
+ return (tp.tv_sec * SEC_IN_NANOSECS) + tp.tv_nsec;
+}
+#endif
+
+/////
+// glibc on Bsd platform uses non-documented flag
+// to indicate, that some special sort of signal
+// trampoline is used.
+// We will never set this flag, and we should
+// ignore this flag in our diagnostic
+#ifdef SIGNIFICANT_SIGNAL_MASK
+#undef SIGNIFICANT_SIGNAL_MASK
+#endif
+#define SIGNIFICANT_SIGNAL_MASK (~0x04000000)
+
+static const char* get_signal_handler_name(address handler,
+ char* buf, int buflen) {
+ int offset;
+ bool found = os::dll_address_to_library_name(handler, buf, buflen, &offset);
+ if (found) {
+ // skip directory names
+ const char *p1, *p2;
+ p1 = buf;
+ size_t len = strlen(os::file_separator());
+ while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len;
+ jio_snprintf(buf, buflen, "%s+0x%x", p1, offset);
+ } else {
+ jio_snprintf(buf, buflen, PTR_FORMAT, handler);
+ }
+ return buf;
+}
+
+static void print_signal_handler(outputStream* st, int sig,
+ char* buf, size_t buflen) {
+ struct sigaction sa;
+
+ sigaction(sig, NULL, &sa);
+
+ // See comment for SIGNIFICANT_SIGNAL_MASK define
+ sa.sa_flags &= SIGNIFICANT_SIGNAL_MASK;
+
+ st->print("%s: ", os::exception_name(sig, buf, buflen));
+
+ address handler = (sa.sa_flags & SA_SIGINFO)
+ ? CAST_FROM_FN_PTR(address, sa.sa_sigaction)
+ : CAST_FROM_FN_PTR(address, sa.sa_handler);
+
+ if (handler == CAST_FROM_FN_PTR(address, SIG_DFL)) {
+ st->print("SIG_DFL");
+ } else if (handler == CAST_FROM_FN_PTR(address, SIG_IGN)) {
+ st->print("SIG_IGN");
+ } else {
+ st->print("[%s]", get_signal_handler_name(handler, buf, buflen));
+ }
+
+ st->print(", sa_mask[0]=" PTR32_FORMAT, *(uint32_t*)&sa.sa_mask);
+
+ address rh = VMError::get_resetted_sighandler(sig);
+ // May be, handler was resetted by VMError?
+ if(rh != NULL) {
+ handler = rh;
+ sa.sa_flags = VMError::get_resetted_sigflags(sig) & SIGNIFICANT_SIGNAL_MASK;
+ }
+
+ st->print(", sa_flags=" PTR32_FORMAT, sa.sa_flags);
+
+ // Check: is it our handler?
+ if(handler == CAST_FROM_FN_PTR(address, (sa_sigaction_t)signalHandler) ||
+ handler == CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler)) {
+ // It is our signal handler
+ // check for flags, reset system-used one!
+ if((int)sa.sa_flags != os::Bsd::get_our_sigflags(sig)) {
+ st->print(
+ ", flags was changed from " PTR32_FORMAT ", consider using jsig library",
+ os::Bsd::get_our_sigflags(sig));
+ }
+ }
+ st->cr();
+}
+
+
+#define DO_SIGNAL_CHECK(sig) \
+ if (!sigismember(&check_signal_done, sig)) \
+ os::Bsd::check_signal_handler(sig)
+
+// This method is a periodic task to check for misbehaving JNI applications
+// under CheckJNI, we can add any periodic checks here
+
+void os::run_periodic_checks() {
+
+ if (check_signals == false) return;
+
+ // SEGV and BUS if overridden could potentially prevent
+ // generation of hs*.log in the event of a crash, debugging
+ // such a case can be very challenging, so we absolutely
+ // check the following for a good measure:
+ DO_SIGNAL_CHECK(SIGSEGV);
+ DO_SIGNAL_CHECK(SIGILL);
+ DO_SIGNAL_CHECK(SIGFPE);
+ DO_SIGNAL_CHECK(SIGBUS);
+ DO_SIGNAL_CHECK(SIGPIPE);
+ DO_SIGNAL_CHECK(SIGXFSZ);
+
+
+ // ReduceSignalUsage allows the user to override these handlers
+ // see comments at the very top and jvm_solaris.h
+ if (!ReduceSignalUsage) {
+ DO_SIGNAL_CHECK(SHUTDOWN1_SIGNAL);
+ DO_SIGNAL_CHECK(SHUTDOWN2_SIGNAL);
+ DO_SIGNAL_CHECK(SHUTDOWN3_SIGNAL);
+ DO_SIGNAL_CHECK(BREAK_SIGNAL);
+ }
+
+ DO_SIGNAL_CHECK(SR_signum);
+ DO_SIGNAL_CHECK(INTERRUPT_SIGNAL);
+}
+
+typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
+
+static os_sigaction_t os_sigaction = NULL;
+
+void os::Bsd::check_signal_handler(int sig) {
+ char buf[O_BUFLEN];
+ address jvmHandler = NULL;
+
+
+ struct sigaction act;
+ if (os_sigaction == NULL) {
+ // only trust the default sigaction, in case it has been interposed
+ os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction");
+ if (os_sigaction == NULL) return;
+ }
+
+ os_sigaction(sig, (struct sigaction*)NULL, &act);
+
+
+ act.sa_flags &= SIGNIFICANT_SIGNAL_MASK;
+
+ address thisHandler = (act.sa_flags & SA_SIGINFO)
+ ? CAST_FROM_FN_PTR(address, act.sa_sigaction)
+ : CAST_FROM_FN_PTR(address, act.sa_handler) ;
+
+
+ switch(sig) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGPIPE:
+ case SIGILL:
+ case SIGXFSZ:
+ jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)signalHandler);
+ break;
+
+ case SHUTDOWN1_SIGNAL:
+ case SHUTDOWN2_SIGNAL:
+ case SHUTDOWN3_SIGNAL:
+ case BREAK_SIGNAL:
+ jvmHandler = (address)user_handler();
+ break;
+
+ case INTERRUPT_SIGNAL:
+ jvmHandler = CAST_FROM_FN_PTR(address, SIG_DFL);
+ break;
+
+ default:
+ if (sig == SR_signum) {
+ jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler);
+ } else {
+ return;
+ }
+ break;
+ }
+
+ if (thisHandler != jvmHandler) {
+ tty->print("Warning: %s handler ", exception_name(sig, buf, O_BUFLEN));
+ tty->print("expected:%s", get_signal_handler_name(jvmHandler, buf, O_BUFLEN));
+ tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN));
+ // No need to check this sig any longer
+ sigaddset(&check_signal_done, sig);
+ } else if(os::Bsd::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Bsd::get_our_sigflags(sig)) {
+ tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
+ tty->print("expected:" PTR32_FORMAT, os::Bsd::get_our_sigflags(sig));
+ tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ // No need to check this sig any longer
+ sigaddset(&check_signal_done, sig);
+ }
+
+ // Dump all the signal
+ if (sigismember(&check_signal_done, sig)) {
+ print_signal_handlers(tty, buf, O_BUFLEN);
+ }
+}
+
+extern void report_error(char* file_name, int line_no, char* title, char* format, ...);
+
+extern bool signal_name(int signo, char* buf, size_t len);
+
+const char* os::exception_name(int exception_code, char* buf, size_t size) {
+ if (0 < exception_code && exception_code <= SIGRTMAX) {
+ // signal
+ if (!signal_name(exception_code, buf, size)) {
+ jio_snprintf(buf, size, "SIG%d", exception_code);
+ }
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+// this is called _before_ the most of global arguments have been parsed
+void os::init(void) {
+ char dummy; /* used to get a guess on initial stack address */
+// first_hrtime = gethrtime();
+
+ // With BsdThreads the JavaMain thread pid (primordial thread)
+ // is different than the pid of the java launcher thread.
+ // So, on Bsd, the launcher thread pid is passed to the VM
+ // via the sun.java.launcher.pid property.
+ // Use this property instead of getpid() if it was correctly passed.
+ // See bug 6351349.
+ pid_t java_launcher_pid = (pid_t) Arguments::sun_java_launcher_pid();
+
+ _initial_pid = (java_launcher_pid > 0) ? java_launcher_pid : getpid();
+
+ clock_tics_per_sec = CLK_TCK;
+
+ init_random(1234567);
+
+ ThreadCritical::initialize();
+
+ Bsd::set_page_size(getpagesize());
+ if (Bsd::page_size() == -1) {
+ fatal(err_msg("os_bsd.cpp: os::init: sysconf failed (%s)",
+ strerror(errno)));
+ }
+ init_page_sizes((size_t) Bsd::page_size());
+
+ Bsd::initialize_system_info();
+
+ // main_thread points to the aboriginal thread
+ Bsd::_main_thread = pthread_self();
+
+ Bsd::clock_init();
+ initial_time_count = os::elapsed_counter();
+
+#ifdef __APPLE__
+ // XXXDARWIN
+ // Work around the unaligned VM callbacks in hotspot's
+ // sharedRuntime. The callbacks don't use SSE2 instructions, and work on
+ // Linux, Solaris, and FreeBSD. On Mac OS X, dyld (rightly so) enforces
+ // alignment when doing symbol lookup. To work around this, we force early
+ // binding of all symbols now, thus binding when alignment is known-good.
+ _dyld_bind_fully_image_containing_address((const void *) &os::init);
+#endif
+}
+
+// To install functions for atexit system call
+extern "C" {
+ static void perfMemory_exit_helper() {
+ perfMemory_exit();
+ }
+}
+
+// this is called _after_ the global arguments have been parsed
+jint os::init_2(void)
+{
+#ifndef _ALLBSD_SOURCE
+ Bsd::fast_thread_clock_init();
+#endif
+
+ // Allocate a single page and mark it as readable for safepoint polling
+ address polling_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ guarantee( polling_page != MAP_FAILED, "os::init_2: failed to allocate polling page" );
+
+ os::set_polling_page( polling_page );
+
+#ifndef PRODUCT
+ if(Verbose && PrintMiscellaneous)
+ tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", (intptr_t)polling_page);
+#endif
+
+ if (!UseMembar) {
+ address mem_serialize_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ guarantee( mem_serialize_page != NULL, "mmap Failed for memory serialize page");
+ os::set_memory_serialize_page( mem_serialize_page );
+
+#ifndef PRODUCT
+ if(Verbose && PrintMiscellaneous)
+ tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page);
+#endif
+ }
+
+ os::large_page_init();
+
+ // initialize suspend/resume support - must do this before signal_sets_init()
+ if (SR_initialize() != 0) {
+ perror("SR_initialize failed");
+ return JNI_ERR;
+ }
+
+ Bsd::signal_sets_init();
+ Bsd::install_signal_handlers();
+
+ // Check minimum allowable stack size for thread creation and to initialize
+ // the java system classes, including StackOverflowError - depends on page
+ // size. Add a page for compiler2 recursion in main thread.
+ // Add in 2*BytesPerWord times page size to account for VM stack during
+ // class initialization depending on 32 or 64 bit VM.
+ os::Bsd::min_stack_allowed = MAX2(os::Bsd::min_stack_allowed,
+ (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
+ 2*BytesPerWord COMPILER2_PRESENT(+1)) * Bsd::page_size());
+
+ size_t threadStackSizeInBytes = ThreadStackSize * K;
+ if (threadStackSizeInBytes != 0 &&
+ threadStackSizeInBytes < os::Bsd::min_stack_allowed) {
+ tty->print_cr("\nThe stack size specified is too small, "
+ "Specify at least %dk",
+ os::Bsd::min_stack_allowed/ K);
+ return JNI_ERR;
+ }
+
+ // Make the stack size a multiple of the page size so that
+ // the yellow/red zones can be guarded.
+ JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes,
+ vm_page_size()));
+
+#ifndef _ALLBSD_SOURCE
+ Bsd::capture_initial_stack(JavaThread::stack_size_at_create());
+
+ Bsd::libpthread_init();
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
+ tty->print_cr("[HotSpot is running with %s, %s(%s)]\n",
+ Bsd::glibc_version(), Bsd::libpthread_version(),
+ Bsd::is_floating_stack() ? "floating stack" : "fixed stack");
+ }
+
+ if (UseNUMA) {
+ if (!Bsd::libnuma_init()) {
+ UseNUMA = false;
+ } else {
+ if ((Bsd::numa_max_node() < 1)) {
+ // There's only one node(they start from 0), disable NUMA.
+ UseNUMA = false;
+ }
+ }
+ // With SHM large pages we cannot uncommit a page, so there's not way
+ // we can make the adaptive lgrp chunk resizing work. If the user specified
+ // both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and
+ // disable adaptive resizing.
+ if (UseNUMA && UseLargePages && UseSHM) {
+ if (!FLAG_IS_DEFAULT(UseNUMA)) {
+ if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) {
+ UseLargePages = false;
+ } else {
+ warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing");
+ UseAdaptiveSizePolicy = false;
+ UseAdaptiveNUMAChunkSizing = false;
+ }
+ } else {
+ UseNUMA = false;
+ }
+ }
+ if (!UseNUMA && ForceNUMA) {
+ UseNUMA = true;
+ }
+ }
+#endif
+
+ if (MaxFDLimit) {
+ // set the number of file descriptors to max. print out error
+ // if getrlimit/setrlimit fails but continue regardless.
+ struct rlimit nbr_files;
+ int status = getrlimit(RLIMIT_NOFILE, &nbr_files);
+ if (status != 0) {
+ if (PrintMiscellaneous && (Verbose || WizardMode))
+ perror("os::init_2 getrlimit failed");
+ } else {
+ nbr_files.rlim_cur = nbr_files.rlim_max;
+
+#ifdef __APPLE__
+ // Darwin returns RLIM_INFINITY for rlim_max, but fails with EINVAL if
+ // you attempt to use RLIM_INFINITY. As per setrlimit(2), OPEN_MAX must
+ // be used instead
+ nbr_files.rlim_cur = MIN(OPEN_MAX, nbr_files.rlim_cur);
+#endif
+
+ status = setrlimit(RLIMIT_NOFILE, &nbr_files);
+ if (status != 0) {
+ if (PrintMiscellaneous && (Verbose || WizardMode))
+ perror("os::init_2 setrlimit failed");
+ }
+ }
+ }
+
+#ifndef _ALLBSD_SOURCE
+ // Initialize lock used to serialize thread creation (see os::create_thread)
+ Bsd::set_createThread_lock(new Mutex(Mutex::leaf, "createThread_lock", false));
+#endif
+
+ // at-exit methods are called in the reverse order of their registration.
+ // atexit functions are called on return from main or as a result of a
+ // call to exit(3C). There can be only 32 of these functions registered
+ // and atexit() does not set errno.
+
+ if (PerfAllowAtExitRegistration) {
+ // only register atexit functions if PerfAllowAtExitRegistration is set.
+ // atexit functions can be delayed until process exit time, which
+ // can be problematic for embedded VM situations. Embedded VMs should
+ // call DestroyJavaVM() to assure that VM resources are released.
+
+ // note: perfMemory_exit_helper atexit function may be removed in
+ // the future if the appropriate cleanup code can be added to the
+ // VM_Exit VMOperation's doit method.
+ if (atexit(perfMemory_exit_helper) != 0) {
+ warning("os::init2 atexit(perfMemory_exit_helper) failed");
+ }
+ }
+
+ // initialize thread priority policy
+ prio_init();
+
+ return JNI_OK;
+}
+
+// this is called at the end of vm_initialization
+void os::init_3(void) { }
+
+// Mark the polling page as unreadable
+void os::make_polling_page_unreadable(void) {
+ if( !guard_memory((char*)_polling_page, Bsd::page_size()) )
+ fatal("Could not disable polling page");
+};
+
+// Mark the polling page as readable
+void os::make_polling_page_readable(void) {
+ if( !bsd_mprotect((char *)_polling_page, Bsd::page_size(), PROT_READ)) {
+ fatal("Could not enable polling page");
+ }
+};
+
+int os::active_processor_count() {
+#ifdef _ALLBSD_SOURCE
+ return _processor_count;
+#else
+ // Bsd doesn't yet have a (official) notion of processor sets,
+ // so just return the number of online processors.
+ int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
+ assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check");
+ return online_cpus;
+#endif
+}
+
+bool os::distribute_processes(uint length, uint* distribution) {
+ // Not yet implemented.
+ return false;
+}
+
+bool os::bind_to_processor(uint processor_id) {
+ // Not yet implemented.
+ 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::Bsd::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::Bsd::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime)
+{
+#ifdef _ALLBSD_SOURCE
+ return pthread_cond_timedwait(_cond, _mutex, _abstime);
+#else
+ if (is_NPTL()) {
+ return pthread_cond_timedwait(_cond, _mutex, _abstime);
+ } else {
+#ifndef IA64
+ // 6292965: BsdThreads pthread_cond_timedwait() resets FPU control
+ // word back to default 64bit precision if condvar is signaled. Java
+ // wants 53bit precision. Save and restore current value.
+ int fpu = get_fpu_control_word();
+#endif // IA64
+ int status = pthread_cond_timedwait(_cond, _mutex, _abstime);
+#ifndef IA64
+ set_fpu_control_word(fpu);
+#endif // IA64
+ return status;
+ }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// debug support
+
+static address same_page(address x, address y) {
+ int page_bits = -os::vm_page_size();
+ if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits))
+ return x;
+ else if (x > y)
+ return (address)(intptr_t(y) | ~page_bits) + 1;
+ else
+ return (address)(intptr_t(y) & page_bits);
+}
+
+bool os::find(address addr, outputStream* st) {
+ Dl_info dlinfo;
+ memset(&dlinfo, 0, sizeof(dlinfo));
+ if (dladdr(addr, &dlinfo)) {
+ st->print(PTR_FORMAT ": ", addr);
+ if (dlinfo.dli_sname != NULL) {
+ st->print("%s+%#x", dlinfo.dli_sname,
+ addr - (intptr_t)dlinfo.dli_saddr);
+ } else if (dlinfo.dli_fname) {
+ st->print("<offset %#x>", addr - (intptr_t)dlinfo.dli_fbase);
+ } else {
+ st->print("<absolute address>");
+ }
+ if (dlinfo.dli_fname) {
+ st->print(" in %s", dlinfo.dli_fname);
+ }
+ if (dlinfo.dli_fbase) {
+ st->print(" at " PTR_FORMAT, dlinfo.dli_fbase);
+ }
+ st->cr();
+
+ if (Verbose) {
+ // decode some bytes around the PC
+ address begin = same_page(addr-40, addr);
+ address end = same_page(addr+40, addr);
+ address lowest = (address) dlinfo.dli_sname;
+ if (!lowest) lowest = (address) dlinfo.dli_fbase;
+ if (begin < lowest) begin = lowest;
+ Dl_info dlinfo2;
+ if (dladdr(end, &dlinfo2) && dlinfo2.dli_saddr != dlinfo.dli_saddr
+ && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin)
+ end = (address) dlinfo2.dli_saddr;
+ Disassembler::decode(begin, end, st);
+ }
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// misc
+
+// This does not do anything on Bsd. This is basically a hook for being
+// able to use structured exception handling (thread-local exception filters)
+// on, e.g., Win32.
+void
+os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method,
+ JavaCallArguments* args, Thread* thread) {
+ f(value, method, args, thread);
+}
+
+void os::print_statistics() {
+}
+
+int os::message_box(const char* title, const char* message) {
+ int i;
+ fdStream err(defaultStream::error_fd());
+ for (i = 0; i < 78; i++) err.print_raw("=");
+ err.cr();
+ err.print_raw_cr(title);
+ for (i = 0; i < 78; i++) err.print_raw("-");
+ err.cr();
+ err.print_raw_cr(message);
+ for (i = 0; i < 78; i++) err.print_raw("=");
+ err.cr();
+
+ char buf[16];
+ // Prevent process from exiting upon "read error" without consuming all CPU
+ while (::read(0, buf, sizeof(buf)) <= 0) { ::sleep(100); }
+
+ return buf[0] == 'y' || buf[0] == 'Y';
+}
+
+int os::stat(const char *path, struct stat *sbuf) {
+ char pathbuf[MAX_PATH];
+ if (strlen(path) > MAX_PATH - 1) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ os::native_path(strcpy(pathbuf, path));
+ return ::stat(pathbuf, sbuf);
+}
+
+bool os::check_heap(bool force) {
+ return true;
+}
+
+int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) {
+ return ::vsnprintf(buf, count, format, args);
+}
+
+// Is a (classpath) directory empty?
+bool os::dir_is_empty(const char* path) {
+ DIR *dir = NULL;
+ struct dirent *ptr;
+
+ dir = opendir(path);
+ if (dir == NULL) return true;
+
+ /* Scan the directory */
+ bool result = true;
+ char buf[sizeof(struct dirent) + MAX_PATH];
+ while (result && (ptr = ::readdir(dir)) != NULL) {
+ if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {
+ result = false;
+ }
+ }
+ closedir(dir);
+ return result;
+}
+
+// This code originates from JDK's sysOpen and open64_w
+// from src/solaris/hpi/src/system_md.c
+
+#ifndef O_DELETE
+#define O_DELETE 0x10000
+#endif
+
+// Open a file. Unlink the file immediately after open returns
+// if the specified oflag has the O_DELETE flag set.
+// O_DELETE is used only in j2se/src/share/native/java/util/zip/ZipFile.c
+
+int os::open(const char *path, int oflag, int mode) {
+
+ if (strlen(path) > MAX_PATH - 1) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ int fd;
+ int o_delete = (oflag & O_DELETE);
+ oflag = oflag & ~O_DELETE;
+
+ fd = ::open(path, oflag, mode);
+ if (fd == -1) return -1;
+
+ //If the open succeeded, the file might still be a directory
+ {
+ struct stat buf;
+ int ret = ::fstat(fd, &buf);
+ int st_mode = buf.st_mode;
+
+ if (ret != -1) {
+ if ((st_mode & S_IFMT) == S_IFDIR) {
+ errno = EISDIR;
+ ::close(fd);
+ return -1;
+ }
+ } else {
+ ::close(fd);
+ return -1;
+ }
+ }
+
+ /*
+ * All file descriptors that are opened in the JVM and not
+ * specifically destined for a subprocess should have the
+ * close-on-exec flag set. If we don't set it, then careless 3rd
+ * party native code might fork and exec without closing all
+ * appropriate file descriptors (e.g. as we do in closeDescriptors in
+ * UNIXProcess.c), and this in turn might:
+ *
+ * - cause end-of-file to fail to be detected on some file
+ * descriptors, resulting in mysterious hangs, or
+ *
+ * - might cause an fopen in the subprocess to fail on a system
+ * suffering from bug 1085341.
+ *
+ * (Yes, the default setting of the close-on-exec flag is a Unix
+ * design flaw)
+ *
+ * See:
+ * 1085341: 32-bit stdio routines should support file descriptors >255
+ * 4843136: (process) pipe file descriptor from Runtime.exec not being closed
+ * 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9
+ */
+#ifdef FD_CLOEXEC
+ {
+ int flags = ::fcntl(fd, F_GETFD);
+ if (flags != -1)
+ ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ }
+#endif
+
+ if (o_delete != 0) {
+ ::unlink(path);
+ }
+ return fd;
+}
+
+
+// create binary file, rewriting existing file if required
+int os::create_binary_file(const char* path, bool rewrite_existing) {
+ int oflags = O_WRONLY | O_CREAT;
+ if (!rewrite_existing) {
+ oflags |= O_EXCL;
+ }
+ return ::open(path, oflags, S_IREAD | S_IWRITE);
+}
+
+// return current position of file pointer
+jlong os::current_file_offset(int fd) {
+ return (jlong)::lseek(fd, (off_t)0, SEEK_CUR);
+}
+
+// move file pointer to the specified offset
+jlong os::seek_to_file_offset(int fd, jlong offset) {
+ return (jlong)::lseek(fd, (off_t)offset, SEEK_SET);
+}
+
+// This code originates from JDK's sysAvailable
+// from src/solaris/hpi/src/native_threads/src/sys_api_td.c
+
+int os::available(int fd, jlong *bytes) {
+ jlong cur, end;
+ int mode;
+ struct stat buf;
+
+ if (::fstat(fd, &buf) >= 0) {
+ mode = buf.st_mode;
+ if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
+ /*
+ * XXX: is the following call interruptible? If so, this might
+ * need to go through the INTERRUPT_IO() wrapper as for other
+ * blocking, interruptible calls in this file.
+ */
+ int n;
+ if (::ioctl(fd, FIONREAD, &n) >= 0) {
+ *bytes = n;
+ return 1;
+ }
+ }
+ }
+ if ((cur = ::lseek(fd, 0L, SEEK_CUR)) == -1) {
+ return 0;
+ } else if ((end = ::lseek(fd, 0L, SEEK_END)) == -1) {
+ return 0;
+ } else if (::lseek(fd, cur, SEEK_SET) == -1) {
+ return 0;
+ }
+ *bytes = end - cur;
+ return 1;
+}
+
+int os::socket_available(int fd, jint *pbytes) {
+ if (fd < 0)
+ return OS_OK;
+
+ int ret;
+
+ RESTARTABLE(::ioctl(fd, FIONREAD, pbytes), ret);
+
+ //%% note ioctl can return 0 when successful, JVM_SocketAvailable
+ // is expected to return 0 on failure and 1 on success to the jdk.
+
+ return (ret == OS_ERR) ? 0 : 1;
+}
+
+// Map a block of memory.
+char* os::map_memory(int fd, const char* file_name, size_t file_offset,
+ char *addr, size_t bytes, bool read_only,
+ bool allow_exec) {
+ int prot;
+ int flags;
+
+ if (read_only) {
+ prot = PROT_READ;
+ flags = MAP_SHARED;
+ } else {
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_PRIVATE;
+ }
+
+ if (allow_exec) {
+ prot |= PROT_EXEC;
+ }
+
+ if (addr != NULL) {
+ flags |= MAP_FIXED;
+ }
+
+ char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags,
+ fd, file_offset);
+ if (mapped_address == MAP_FAILED) {
+ return NULL;
+ }
+ return mapped_address;
+}
+
+
+// Remap a block of memory.
+char* os::remap_memory(int fd, const char* file_name, size_t file_offset,
+ char *addr, size_t bytes, bool read_only,
+ bool allow_exec) {
+ // same as map_memory() on this OS
+ return os::map_memory(fd, file_name, file_offset, addr, bytes, read_only,
+ allow_exec);
+}
+
+
+// Unmap a block of memory.
+bool os::unmap_memory(char* addr, size_t bytes) {
+ return munmap(addr, bytes) == 0;
+}
+
+#ifndef _ALLBSD_SOURCE
+static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time);
+
+static clockid_t thread_cpu_clockid(Thread* thread) {
+ pthread_t tid = thread->osthread()->pthread_id();
+ clockid_t clockid;
+
+ // Get thread clockid
+ int rc = os::Bsd::pthread_getcpuclockid(tid, &clockid);
+ assert(rc == 0, "pthread_getcpuclockid is expected to return 0 code");
+ return clockid;
+}
+#endif
+
+// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
+// are used by JVM M&M and JVMTI to get user+sys or user CPU time
+// of a thread.
+//
+// current_thread_cpu_time() and thread_cpu_time(Thread*) returns
+// the fast estimate available on the platform.
+
+jlong os::current_thread_cpu_time() {
+#ifdef __APPLE__
+ return os::thread_cpu_time(Thread::current(), true /* user + sys */);
+#elif !defined(_ALLBSD_SOURCE)
+ if (os::Bsd::supports_fast_thread_cpu_time()) {
+ return os::Bsd::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
+ } else {
+ // return user + sys since the cost is the same
+ return slow_thread_cpu_time(Thread::current(), true /* user + sys */);
+ }
+#endif
+}
+
+jlong os::thread_cpu_time(Thread* thread) {
+#ifndef _ALLBSD_SOURCE
+ // consistent with what current_thread_cpu_time() returns
+ if (os::Bsd::supports_fast_thread_cpu_time()) {
+ return os::Bsd::fast_thread_cpu_time(thread_cpu_clockid(thread));
+ } else {
+ return slow_thread_cpu_time(thread, true /* user + sys */);
+ }
+#endif
+}
+
+jlong os::current_thread_cpu_time(bool user_sys_cpu_time) {
+#ifdef __APPLE__
+ return os::thread_cpu_time(Thread::current(), user_sys_cpu_time);
+#elif !defined(_ALLBSD_SOURCE)
+ if (user_sys_cpu_time && os::Bsd::supports_fast_thread_cpu_time()) {
+ return os::Bsd::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
+ } else {
+ return slow_thread_cpu_time(Thread::current(), user_sys_cpu_time);
+ }
+#endif
+}
+
+jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
+#ifdef __APPLE__
+ struct thread_basic_info tinfo;
+ mach_msg_type_number_t tcount = THREAD_INFO_MAX;
+ kern_return_t kr;
+ mach_port_t mach_thread;
+
+ mach_thread = pthread_mach_thread_np(thread->osthread()->thread_id());
+ kr = thread_info(mach_thread, THREAD_BASIC_INFO, (thread_info_t)&tinfo, &tcount);
+ if (kr != KERN_SUCCESS)
+ return -1;
+
+ if (user_sys_cpu_time) {
+ jlong nanos;
+ nanos = ((jlong) tinfo.system_time.seconds + tinfo.user_time.seconds) * (jlong)1000000000;
+ nanos += ((jlong) tinfo.system_time.microseconds + (jlong) tinfo.user_time.microseconds) * (jlong)1000;
+ return nanos;
+ } else {
+ return ((jlong)tinfo.user_time.seconds * 1000000000) + ((jlong)tinfo.user_time.microseconds * (jlong)1000);
+ }
+#elif !defined(_ALLBSD_SOURCE)
+ if (user_sys_cpu_time && os::Bsd::supports_fast_thread_cpu_time()) {
+ return os::Bsd::fast_thread_cpu_time(thread_cpu_clockid(thread));
+ } else {
+ return slow_thread_cpu_time(thread, user_sys_cpu_time);
+ }
+#endif
+}
+
+#ifndef _ALLBSD_SOURCE
+//
+// -1 on error.
+//
+
+static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
+ static bool proc_pid_cpu_avail = true;
+ static bool proc_task_unchecked = true;
+ static const char *proc_stat_path = "/proc/%d/stat";
+ pid_t tid = thread->osthread()->thread_id();
+ int i;
+ char *s;
+ char stat[2048];
+ int statlen;
+ char proc_name[64];
+ int count;
+ long sys_time, user_time;
+ char string[64];
+ char cdummy;
+ int idummy;
+ long ldummy;
+ FILE *fp;
+
+ // We first try accessing /proc/<pid>/cpu since this is faster to
+ // process. If this file is not present (bsd kernels 2.5 and above)
+ // then we open /proc/<pid>/stat.
+ if ( proc_pid_cpu_avail ) {
+ sprintf(proc_name, "/proc/%d/cpu", tid);
+ fp = fopen(proc_name, "r");
+ if ( fp != NULL ) {
+ count = fscanf( fp, "%s %lu %lu\n", string, &user_time, &sys_time);
+ fclose(fp);
+ if ( count != 3 ) return -1;
+
+ if (user_sys_cpu_time) {
+ return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec);
+ } else {
+ return (jlong)user_time * (1000000000 / clock_tics_per_sec);
+ }
+ }
+ else proc_pid_cpu_avail = false;
+ }
+
+ // The /proc/<tid>/stat aggregates per-process usage on
+ // new Bsd kernels 2.6+ where NPTL is supported.
+ // The /proc/self/task/<tid>/stat still has the per-thread usage.
+ // See bug 6328462.
+ // There can be no directory /proc/self/task on kernels 2.4 with NPTL
+ // and possibly in some other cases, so we check its availability.
+ if (proc_task_unchecked && os::Bsd::is_NPTL()) {
+ // This is executed only once
+ proc_task_unchecked = false;
+ fp = fopen("/proc/self/task", "r");
+ if (fp != NULL) {
+ proc_stat_path = "/proc/self/task/%d/stat";
+ fclose(fp);
+ }
+ }
+
+ sprintf(proc_name, proc_stat_path, tid);
+ fp = fopen(proc_name, "r");
+ if ( fp == NULL ) return -1;
+ statlen = fread(stat, 1, 2047, fp);
+ stat[statlen] = '\0';
+ fclose(fp);
+
+ // Skip pid and the command string. Note that we could be dealing with
+ // weird command names, e.g. user could decide to rename java launcher
+ // to "java 1.4.2 :)", then the stat file would look like
+ // 1234 (java 1.4.2 :)) R ... ...
+ // We don't really need to know the command string, just find the last
+ // occurrence of ")" and then start parsing from there. See bug 4726580.
+ s = strrchr(stat, ')');
+ i = 0;
+ if (s == NULL ) return -1;
+
+ // Skip blank chars
+ do s++; while (isspace(*s));
+
+ count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu",
+ &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy,
+ &ldummy, &ldummy, &ldummy, &ldummy, &ldummy,
+ &user_time, &sys_time);
+ if ( count != 13 ) return -1;
+ if (user_sys_cpu_time) {
+ return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec);
+ } else {
+ return (jlong)user_time * (1000000000 / clock_tics_per_sec);
+ }
+}
+#endif
+
+void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
+ info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
+ info_ptr->may_skip_backward = false; // elapsed time not wall time
+ info_ptr->may_skip_forward = false; // elapsed time not wall time
+ info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
+}
+
+void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
+ info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
+ info_ptr->may_skip_backward = false; // elapsed time not wall time
+ info_ptr->may_skip_forward = false; // elapsed time not wall time
+ info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned
+}
+
+bool os::is_thread_cpu_time_supported() {
+#ifdef __APPLE__
+ return true;
+#elif defined(_ALLBSD_SOURCE)
+ return false;
+#else
+ return true;
+#endif
+}
+
+// System loadavg support. Returns -1 if load average cannot be obtained.
+// Bsd doesn't yet have a (official) notion of processor sets,
+// so just return the system wide load average.
+int os::loadavg(double loadavg[], int nelem) {
+ return ::getloadavg(loadavg, nelem);
+}
+
+void os::pause() {
+ char filename[MAX_PATH];
+ if (PauseAtStartupFile && PauseAtStartupFile[0]) {
+ jio_snprintf(filename, MAX_PATH, PauseAtStartupFile);
+ } else {
+ jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id());
+ }
+
+ int fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd != -1) {
+ struct stat buf;
+ ::close(fd);
+ while (::stat(filename, &buf) == 0) {
+ (void)::poll(NULL, 0, 100);
+ }
+ } else {
+ jio_fprintf(stderr,
+ "Could not open pause file '%s', continuing immediately.\n", filename);
+ }
+}
+
+
+// Refer to the comments in os_solaris.cpp park-unpark.
+//
+// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
+// hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
+// For specifics regarding the bug see GLIBC BUGID 261237 :
+// http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html.
+// Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future
+// will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar
+// is used. (The simple C test-case provided in the GLIBC bug report manifests the
+// hang). The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos()
+// and monitorenter when we're using 1-0 locking. All those operations may result in
+// calls to pthread_cond_timedwait(). Using LD_ASSUME_KERNEL to use an older version
+// of libpthread avoids the problem, but isn't practical.
+//
+// Possible remedies:
+//
+// 1. Establish a minimum relative wait time. 50 to 100 msecs seems to work.
+// This is palliative and probabilistic, however. If the thread is preempted
+// between the call to compute_abstime() and pthread_cond_timedwait(), more
+// than the minimum period may have passed, and the abstime may be stale (in the
+// past) resultin in a hang. Using this technique reduces the odds of a hang
+// but the JVM is still vulnerable, particularly on heavily loaded systems.
+//
+// 2. Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead
+// of the usual flag-condvar-mutex idiom. The write side of the pipe is set
+// NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo)
+// reduces to poll()+read(). This works well, but consumes 2 FDs per extant
+// thread.
+//
+// 3. Embargo pthread_cond_timedwait() and implement a native "chron" thread
+// that manages timeouts. We'd emulate pthread_cond_timedwait() by enqueuing
+// a timeout request to the chron thread and then blocking via pthread_cond_wait().
+// This also works well. In fact it avoids kernel-level scalability impediments
+// on certain platforms that don't handle lots of active pthread_cond_timedwait()
+// timers in a graceful fashion.
+//
+// 4. When the abstime value is in the past it appears that control returns
+// correctly from pthread_cond_timedwait(), but the condvar is left corrupt.
+// Subsequent timedwait/wait calls may hang indefinitely. Given that, we
+// can avoid the problem by reinitializing the condvar -- by cond_destroy()
+// followed by cond_init() -- after all calls to pthread_cond_timedwait().
+// It may be possible to avoid reinitialization by checking the return
+// value from pthread_cond_timedwait(). In addition to reinitializing the
+// condvar we must establish the invariant that cond_signal() is only called
+// within critical sections protected by the adjunct mutex. This prevents
+// cond_signal() from "seeing" a condvar that's in the midst of being
+// reinitialized or that is corrupt. Sadly, this invariant obviates the
+// desirable signal-after-unlock optimization that avoids futile context switching.
+//
+// I'm also concerned that some versions of NTPL might allocate an auxilliary
+// structure when a condvar is used or initialized. cond_destroy() would
+// release the helper structure. Our reinitialize-after-timedwait fix
+// put excessive stress on malloc/free and locks protecting the c-heap.
+//
+// We currently use (4). See the WorkAroundNTPLTimedWaitHang flag.
+// It may be possible to refine (4) by checking the kernel and NTPL verisons
+// and only enabling the work-around for vulnerable environments.
+
+// utility to compute the abstime argument to timedwait:
+// millis is the relative timeout time
+// abstime will be the absolute timeout time
+// TODO: replace compute_abstime() with unpackTime()
+
+static struct timespec* compute_abstime(struct timespec* abstime, jlong millis) {
+ if (millis < 0) millis = 0;
+ struct timeval now;
+ int status = gettimeofday(&now, NULL);
+ assert(status == 0, "gettimeofday");
+ jlong seconds = millis / 1000;
+ millis %= 1000;
+ if (seconds > 50000000) { // see man cond_timedwait(3T)
+ seconds = 50000000;
+ }
+ abstime->tv_sec = now.tv_sec + seconds;
+ long usec = now.tv_usec + millis * 1000;
+ if (usec >= 1000000) {
+ abstime->tv_sec += 1;
+ usec -= 1000000;
+ }
+ abstime->tv_nsec = usec * 1000;
+ return abstime;
+}
+
+
+// Test-and-clear _Event, always leaves _Event set to 0, returns immediately.
+// Conceptually TryPark() should be equivalent to park(0).
+
+int os::PlatformEvent::TryPark() {
+ for (;;) {
+ const int v = _Event ;
+ guarantee ((v == 0) || (v == 1), "invariant") ;
+ if (Atomic::cmpxchg (0, &_Event, v) == v) return v ;
+ }
+}
+
+void os::PlatformEvent::park() { // AKA "down()"
+ // Invariant: Only the thread associated with the Event/PlatformEvent
+ // may call park().
+ // TODO: assert that _Assoc != NULL or _Assoc == Self
+ int v ;
+ for (;;) {
+ v = _Event ;
+ if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ;
+ }
+ guarantee (v >= 0, "invariant") ;
+ if (v == 0) {
+ // Do this the hard way by blocking ...
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ guarantee (_nParked == 0, "invariant") ;
+ ++ _nParked ;
+ while (_Event < 0) {
+ status = pthread_cond_wait(_cond, _mutex);
+ // for some reason, under 2.7 lwp_cond_wait() may return ETIME ...
+ // Treat this the same as if the wait was interrupted
+ if (status == ETIMEDOUT) { status = EINTR; }
+ assert_status(status == 0 || status == EINTR, status, "cond_wait");
+ }
+ -- _nParked ;
+
+ // In theory we could move the ST of 0 into _Event past the unlock(),
+ // but then we'd need a MEMBAR after the ST.
+ _Event = 0 ;
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+ }
+ guarantee (_Event >= 0, "invariant") ;
+}
+
+int os::PlatformEvent::park(jlong millis) {
+ guarantee (_nParked == 0, "invariant") ;
+
+ int v ;
+ for (;;) {
+ v = _Event ;
+ if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ;
+ }
+ guarantee (v >= 0, "invariant") ;
+ if (v != 0) return OS_OK ;
+
+ // We do this the hard way, by blocking the thread.
+ // Consider enforcing a minimum timeout value.
+ struct timespec abst;
+ compute_abstime(&abst, millis);
+
+ int ret = OS_TIMEOUT;
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ guarantee (_nParked == 0, "invariant") ;
+ ++_nParked ;
+
+ // Object.wait(timo) will return because of
+ // (a) notification
+ // (b) timeout
+ // (c) thread.interrupt
+ //
+ // Thread.interrupt and object.notify{All} both call Event::set.
+ // That is, we treat thread.interrupt as a special case of notification.
+ // The underlying Solaris implementation, cond_timedwait, admits
+ // spurious/premature wakeups, but the JLS/JVM spec prevents the
+ // JVM from making those visible to Java code. As such, we must
+ // filter out spurious wakeups. We assume all ETIME returns are valid.
+ //
+ // TODO: properly differentiate simultaneous notify+interrupt.
+ // In that case, we should propagate the notify to another waiter.
+
+ while (_Event < 0) {
+ status = os::Bsd::safe_cond_timedwait(_cond, _mutex, &abst);
+ if (status != 0 && WorkAroundNPTLTimedWaitHang) {
+ pthread_cond_destroy (_cond);
+ pthread_cond_init (_cond, NULL) ;
+ }
+ assert_status(status == 0 || status == EINTR ||
+ status == ETIMEDOUT,
+ status, "cond_timedwait");
+ if (!FilterSpuriousWakeups) break ; // previous semantics
+ if (status == ETIMEDOUT) break ;
+ // We consume and ignore EINTR and spurious wakeups.
+ }
+ --_nParked ;
+ if (_Event >= 0) {
+ ret = OS_OK;
+ }
+ _Event = 0 ;
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+ assert (_nParked == 0, "invariant") ;
+ return ret;
+}
+
+void os::PlatformEvent::unpark() {
+ int v, AnyWaiters ;
+ for (;;) {
+ v = _Event ;
+ if (v > 0) {
+ // The LD of _Event could have reordered or be satisfied
+ // by a read-aside from this processor's write buffer.
+ // To avoid problems execute a barrier and then
+ // ratify the value.
+ OrderAccess::fence() ;
+ if (_Event == v) return ;
+ continue ;
+ }
+ if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
+ }
+ if (v < 0) {
+ // Wait for the thread associated with the event to vacate
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ AnyWaiters = _nParked ;
+ assert (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
+ if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
+ AnyWaiters = 0 ;
+ pthread_cond_signal (_cond);
+ }
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+ if (AnyWaiters != 0) {
+ status = pthread_cond_signal(_cond);
+ assert_status(status == 0, status, "cond_signal");
+ }
+ }
+
+ // Note that we signal() _after dropping the lock for "immortal" Events.
+ // This is safe and avoids a common class of futile wakeups. In rare
+ // circumstances this can cause a thread to return prematurely from
+ // cond_{timed}wait() but the spurious wakeup is benign and the victim will
+ // simply re-test the condition and re-park itself.
+}
+
+
+// JSR166
+// -------------------------------------------------------
+
+/*
+ * The solaris and bsd implementations of park/unpark are fairly
+ * conservative for now, but can be improved. They currently use a
+ * mutex/condvar pair, plus a a count.
+ * Park decrements count if > 0, else does a condvar wait. Unpark
+ * sets count to 1 and signals condvar. Only one thread ever waits
+ * on the condvar. Contention seen when trying to park implies that someone
+ * is unparking you, so don't wait. And spurious returns are fine, so there
+ * is no need to track notifications.
+ */
+
+
+#define NANOSECS_PER_SEC 1000000000
+#define NANOSECS_PER_MILLISEC 1000000
+#define MAX_SECS 100000000
+/*
+ * This code is common to bsd and solaris and will be moved to a
+ * common place in dolphin.
+ *
+ * The passed in time value is either a relative time in nanoseconds
+ * or an absolute time in milliseconds. Either way it has to be unpacked
+ * into suitable seconds and nanoseconds components and stored in the
+ * given timespec structure.
+ * Given time is a 64-bit value and the time_t used in the timespec is only
+ * a signed-32-bit value (except on 64-bit Bsd) we have to watch for
+ * overflow if times way in the future are given. Further on Solaris versions
+ * prior to 10 there is a restriction (see cond_timedwait) that the specified
+ * number of seconds, in abstime, is less than current_time + 100,000,000.
+ * As it will be 28 years before "now + 100000000" will overflow we can
+ * ignore overflow and just impose a hard-limit on seconds using the value
+ * of "now + 100,000,000". This places a limit on the timeout of about 3.17
+ * years from "now".
+ */
+
+static void unpackTime(struct timespec* absTime, bool isAbsolute, jlong time) {
+ assert (time > 0, "convertTime");
+
+ struct timeval now;
+ int status = gettimeofday(&now, NULL);
+ assert(status == 0, "gettimeofday");
+
+ time_t max_secs = now.tv_sec + MAX_SECS;
+
+ if (isAbsolute) {
+ jlong secs = time / 1000;
+ if (secs > max_secs) {
+ absTime->tv_sec = max_secs;
+ }
+ else {
+ absTime->tv_sec = secs;
+ }
+ absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC;
+ }
+ else {
+ jlong secs = time / NANOSECS_PER_SEC;
+ if (secs >= MAX_SECS) {
+ absTime->tv_sec = max_secs;
+ absTime->tv_nsec = 0;
+ }
+ else {
+ absTime->tv_sec = now.tv_sec + secs;
+ absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000;
+ if (absTime->tv_nsec >= NANOSECS_PER_SEC) {
+ absTime->tv_nsec -= NANOSECS_PER_SEC;
+ ++absTime->tv_sec; // note: this must be <= max_secs
+ }
+ }
+ }
+ assert(absTime->tv_sec >= 0, "tv_sec < 0");
+ assert(absTime->tv_sec <= max_secs, "tv_sec > max_secs");
+ assert(absTime->tv_nsec >= 0, "tv_nsec < 0");
+ assert(absTime->tv_nsec < NANOSECS_PER_SEC, "tv_nsec >= nanos_per_sec");
+}
+
+void Parker::park(bool isAbsolute, jlong time) {
+ // Optional fast-path check:
+ // Return immediately if a permit is available.
+ if (_counter > 0) {
+ _counter = 0 ;
+ OrderAccess::fence();
+ return ;
+ }
+
+ Thread* thread = Thread::current();
+ assert(thread->is_Java_thread(), "Must be JavaThread");
+ JavaThread *jt = (JavaThread *)thread;
+
+ // Optional optimization -- avoid state transitions if there's an interrupt pending.
+ // Check interrupt before trying to wait
+ if (Thread::is_interrupted(thread, false)) {
+ return;
+ }
+
+ // Next, demultiplex/decode time arguments
+ struct timespec absTime;
+ if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
+ return;
+ }
+ if (time > 0) {
+ unpackTime(&absTime, isAbsolute, time);
+ }
+
+
+ // Enter safepoint region
+ // Beware of deadlocks such as 6317397.
+ // The per-thread Parker:: mutex is a classic leaf-lock.
+ // In particular a thread must never block on the Threads_lock while
+ // holding the Parker:: mutex. If safepoints are pending both the
+ // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
+ ThreadBlockInVM tbivm(jt);
+
+ // Don't wait if cannot get lock since interference arises from
+ // unblocking. Also. check interrupt before trying wait
+ if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
+ return;
+ }
+
+ int status ;
+ if (_counter > 0) { // no wait needed
+ _counter = 0;
+ status = pthread_mutex_unlock(_mutex);
+ assert (status == 0, "invariant") ;
+ OrderAccess::fence();
+ return;
+ }
+
+#ifdef ASSERT
+ // Don't catch signals while blocked; let the running threads have the signals.
+ // (This allows a debugger to break into the running thread.)
+ sigset_t oldsigs;
+ sigset_t* allowdebug_blocked = os::Bsd::allowdebug_blocked_signals();
+ pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);
+#endif
+
+ OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
+ jt->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
+
+ if (time == 0) {
+ status = pthread_cond_wait (_cond, _mutex) ;
+ } else {
+ status = os::Bsd::safe_cond_timedwait (_cond, _mutex, &absTime) ;
+ if (status != 0 && WorkAroundNPTLTimedWaitHang) {
+ pthread_cond_destroy (_cond) ;
+ pthread_cond_init (_cond, NULL);
+ }
+ }
+ assert_status(status == 0 || status == EINTR ||
+ status == ETIMEDOUT,
+ status, "cond_timedwait");
+
+#ifdef ASSERT
+ pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
+#endif
+
+ _counter = 0 ;
+ status = pthread_mutex_unlock(_mutex) ;
+ assert_status(status == 0, status, "invariant") ;
+ // If externally suspended while waiting, re-suspend
+ if (jt->handle_special_suspend_equivalent_condition()) {
+ jt->java_suspend_self();
+ }
+
+ OrderAccess::fence();
+}
+
+void Parker::unpark() {
+ int s, status ;
+ status = pthread_mutex_lock(_mutex);
+ assert (status == 0, "invariant") ;
+ s = _counter;
+ _counter = 1;
+ if (s < 1) {
+ if (WorkAroundNPTLTimedWaitHang) {
+ status = pthread_cond_signal (_cond) ;
+ assert (status == 0, "invariant") ;
+ status = pthread_mutex_unlock(_mutex);
+ assert (status == 0, "invariant") ;
+ } else {
+ status = pthread_mutex_unlock(_mutex);
+ assert (status == 0, "invariant") ;
+ status = pthread_cond_signal (_cond) ;
+ assert (status == 0, "invariant") ;
+ }
+ } else {
+ pthread_mutex_unlock(_mutex);
+ assert (status == 0, "invariant") ;
+ }
+}
+
+
+/* Darwin has no "environ" in a dynamic library. */
+#ifdef __APPLE__
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+#else
+extern char** environ;
+#endif
+
+// Run the specified command in a separate process. Return its exit value,
+// or -1 on failure (e.g. can't fork a new process).
+// Unlike system(), this function can be called from signal handler. It
+// doesn't block SIGINT et al.
+int os::fork_and_exec(char* cmd) {
+ const char * argv[4] = {"sh", "-c", cmd, NULL};
+
+ // fork() in BsdThreads/NPTL is not async-safe. It needs to run
+ // pthread_atfork handlers and reset pthread library. All we need is a
+ // separate process to execve. Make a direct syscall to fork process.
+ // On IA64 there's no fork syscall, we have to use fork() and hope for
+ // the best...
+ pid_t pid = fork();
+
+ if (pid < 0) {
+ // fork failed
+ return -1;
+
+ } else if (pid == 0) {
+ // child process
+
+ // execve() in BsdThreads will call pthread_kill_other_threads_np()
+ // first to kill every thread on the thread list. Because this list is
+ // not reset by fork() (see notes above), execve() will instead kill
+ // every thread in the parent process. We know this is the only thread
+ // in the new process, so make a system call directly.
+ // IA64 should use normal execve() from glibc to match the glibc fork()
+ // above.
+ execve("/bin/sh", (char* const*)argv, environ);
+
+ // execve failed
+ _exit(-1);
+
+ } else {
+ // copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
+ // care about the actual exit code, for now.
+
+ int status;
+
+ // Wait for the child process to exit. This returns immediately if
+ // the child has already exited. */
+ while (waitpid(pid, &status, 0) < 0) {
+ switch (errno) {
+ case ECHILD: return 0;
+ case EINTR: break;
+ default: return -1;
+ }
+ }
+
+ if (WIFEXITED(status)) {
+ // The child exited normally; get its exit code.
+ return WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ // The child exited because of a signal
+ // The best value to return is 0x80 + signal number,
+ // because that is what all Unix shells do, and because
+ // it allows callers to distinguish between process exit and
+ // process death by signal.
+ return 0x80 + WTERMSIG(status);
+ } else {
+ // Unknown exit code; pass it through
+ return status;
+ }
+ }
+}
+
+// is_headless_jre()
+//
+// Test for the existence of libmawt in motif21 or xawt directories
+// in order to report if we are running in a headless jre
+//
+bool os::is_headless_jre() {
+ struct stat statbuf;
+ char buf[MAXPATHLEN];
+ char libmawtpath[MAXPATHLEN];
+ const char *xawtstr = "/xawt/libmawt.so";
+ const char *motifstr = "/motif21/libmawt.so";
+ char *p;
+
+ // Get path to libjvm.so
+ os::jvm_path(buf, sizeof(buf));
+
+ // Get rid of libjvm.so
+ p = strrchr(buf, '/');
+ if (p == NULL) return false;
+ else *p = '\0';
+
+ // Get rid of client or server
+ p = strrchr(buf, '/');
+ if (p == NULL) return false;
+ else *p = '\0';
+
+ // check xawt/libmawt.so
+ strcpy(libmawtpath, buf);
+ strcat(libmawtpath, xawtstr);
+ if (::stat(libmawtpath, &statbuf) == 0) return false;
+
+ // check motif21/libmawt.so
+ strcpy(libmawtpath, buf);
+ strcat(libmawtpath, motifstr);
+ if (::stat(libmawtpath, &statbuf) == 0) return false;
+
+ return true;
+}
diff --git a/src/os/bsd/vm/os_bsd.hpp b/src/os/bsd/vm/os_bsd.hpp
new file mode 100644
index 000000000..271d1e291
--- /dev/null
+++ b/src/os/bsd/vm/os_bsd.hpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_OS_BSD_HPP
+#define OS_BSD_VM_OS_BSD_HPP
+
+// Bsd_OS defines the interface to Bsd operating systems
+
+/* pthread_getattr_np comes with BsdThreads-0.9-7 on RedHat 7.1 */
+typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *);
+
+#ifdef __APPLE__
+// Mac OS X doesn't support clock_gettime. Stub out the type, it is
+// unused
+typedef int clockid_t;
+#endif
+
+class Bsd {
+ friend class os;
+
+ // For signal-chaining
+#define MAXSIGNUM 32
+ static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions
+ static unsigned int sigs; // mask of signals that have
+ // preinstalled signal handlers
+ static bool libjsig_is_loaded; // libjsig that interposes sigaction(),
+ // __sigaction(), signal() is loaded
+ static struct sigaction *(*get_signal_action)(int);
+ static struct sigaction *get_preinstalled_handler(int);
+ static void save_preinstalled_handler(int, struct sigaction&);
+
+ static void check_signal_handler(int sig);
+
+ // For signal flags diagnostics
+ static int sigflags[MAXSIGNUM];
+
+ static int (*_clock_gettime)(clockid_t, struct timespec *);
+#ifndef _ALLBSD_SOURCE
+ static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
+
+ static address _initial_thread_stack_bottom;
+ static uintptr_t _initial_thread_stack_size;
+
+ static const char *_glibc_version;
+ static const char *_libpthread_version;
+
+ static bool _is_floating_stack;
+ static bool _is_NPTL;
+ static bool _supports_fast_thread_cpu_time;
+#endif
+
+ static GrowableArray<int>* _cpu_to_node;
+
+ protected:
+
+ static julong _physical_memory;
+ static pthread_t _main_thread;
+#ifndef _ALLBSD_SOURCE
+ static Mutex* _createThread_lock;
+#endif
+ static int _page_size;
+
+ static julong available_memory();
+ static julong physical_memory() { return _physical_memory; }
+ static void initialize_system_info();
+
+#ifndef _ALLBSD_SOURCE
+ static void set_glibc_version(const char *s) { _glibc_version = s; }
+ static void set_libpthread_version(const char *s) { _libpthread_version = s; }
+#endif
+
+ static bool supports_variable_stack_size();
+
+#ifndef _ALLBSD_SOURCE
+ static void set_is_NPTL() { _is_NPTL = true; }
+ static void set_is_BsdThreads() { _is_NPTL = false; }
+ static void set_is_floating_stack() { _is_floating_stack = true; }
+#endif
+
+ static void rebuild_cpu_to_node_map();
+ static GrowableArray<int>* cpu_to_node() { return _cpu_to_node; }
+
+ static bool hugetlbfs_sanity_check(bool warn, size_t page_size);
+
+ public:
+
+ static void init_thread_fpu_state();
+#ifndef _ALLBSD_SOURCE
+ static int get_fpu_control_word();
+ static void set_fpu_control_word(int fpu_control);
+#endif
+ static pthread_t main_thread(void) { return _main_thread; }
+
+#ifndef _ALLBSD_SOURCE
+ // returns kernel thread id (similar to LWP id on Solaris), which can be
+ // used to access /proc
+ static pid_t gettid();
+ static void set_createThread_lock(Mutex* lk) { _createThread_lock = lk; }
+ static Mutex* createThread_lock(void) { return _createThread_lock; }
+#endif
+ static void hotspot_sigmask(Thread* thread);
+
+#ifndef _ALLBSD_SOURCE
+ static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; }
+ static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; }
+#endif
+ static bool is_initial_thread(void);
+
+ static int page_size(void) { return _page_size; }
+ static void set_page_size(int val) { _page_size = val; }
+
+ static address ucontext_get_pc(ucontext_t* uc);
+ static intptr_t* ucontext_get_sp(ucontext_t* uc);
+ static intptr_t* ucontext_get_fp(ucontext_t* uc);
+
+ // For Analyzer Forte AsyncGetCallTrace profiling support:
+ //
+ // This interface should be declared in os_bsd_i486.hpp, but
+ // that file provides extensions to the os class and not the
+ // Bsd class.
+ static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc,
+ intptr_t** ret_sp, intptr_t** ret_fp);
+
+ // This boolean allows users to forward their own non-matching signals
+ // to JVM_handle_bsd_signal, harmlessly.
+ static bool signal_handlers_are_installed;
+
+ static int get_our_sigflags(int);
+ static void set_our_sigflags(int, int);
+ static void signal_sets_init();
+ static void install_signal_handlers();
+ static void set_signal_handler(int, bool);
+ static bool is_sig_ignored(int sig);
+
+ static sigset_t* unblocked_signals();
+ static sigset_t* vm_signals();
+ static sigset_t* allowdebug_blocked_signals();
+
+ // For signal-chaining
+ static struct sigaction *get_chained_signal_action(int sig);
+ static bool chained_handler(int sig, siginfo_t* siginfo, void* context);
+
+#ifndef _ALLBSD_SOURCE
+ // GNU libc and libpthread version strings
+ static const char *glibc_version() { return _glibc_version; }
+ static const char *libpthread_version() { return _libpthread_version; }
+
+ // NPTL or BsdThreads?
+ static bool is_BsdThreads() { return !_is_NPTL; }
+ static bool is_NPTL() { return _is_NPTL; }
+
+ // NPTL is always floating stack. BsdThreads could be using floating
+ // stack or fixed stack.
+ static bool is_floating_stack() { return _is_floating_stack; }
+
+ static void libpthread_init();
+ static bool libnuma_init();
+ static void* libnuma_dlsym(void* handle, const char* name);
+#endif
+ // Minimum stack size a thread can be created with (allowing
+ // the VM to completely create the thread and enter user code)
+ static size_t min_stack_allowed;
+
+ // Return default stack size or guard size for the specified thread type
+ static size_t default_stack_size(os::ThreadType thr_type);
+ static size_t default_guard_size(os::ThreadType thr_type);
+
+#ifndef _ALLBSD_SOURCE
+ static void capture_initial_stack(size_t max_size);
+
+ // Stack overflow handling
+ static bool manually_expand_stack(JavaThread * t, address addr);
+ static int max_register_window_saves_before_flushing();
+#endif
+
+ // Real-time clock functions
+ static void clock_init(void);
+
+#ifndef _ALLBSD_SOURCE
+ // fast POSIX clocks support
+ static void fast_thread_clock_init(void);
+#endif
+
+ static bool supports_monotonic_clock() {
+ return _clock_gettime != NULL;
+ }
+
+ static int clock_gettime(clockid_t clock_id, struct timespec *tp) {
+ return _clock_gettime ? _clock_gettime(clock_id, tp) : -1;
+ }
+
+#ifndef _ALLBSD_SOURCE
+ static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) {
+ return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1;
+ }
+
+ static bool supports_fast_thread_cpu_time() {
+ return _supports_fast_thread_cpu_time;
+ }
+
+ static jlong fast_thread_cpu_time(clockid_t clockid);
+#endif
+
+ // Stack repair handling
+
+ // none present
+
+ // BsdThreads work-around for 6292965
+ static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime);
+
+
+ // Bsd suspend/resume support - this helper is a shadow of its former
+ // self now that low-level suspension is barely used, and old workarounds
+ // for BsdThreads are no longer needed.
+ class SuspendResume {
+ private:
+ volatile int _suspend_action;
+ // values for suspend_action:
+ #define SR_NONE (0x00)
+ #define SR_SUSPEND (0x01) // suspend request
+ #define SR_CONTINUE (0x02) // resume request
+
+ volatile jint _state;
+ // values for _state: + SR_NONE
+ #define SR_SUSPENDED (0x20)
+ public:
+ SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; }
+
+ int suspend_action() const { return _suspend_action; }
+ void set_suspend_action(int x) { _suspend_action = x; }
+
+ // atomic updates for _state
+ void set_suspended() {
+ jint temp, temp2;
+ do {
+ temp = _state;
+ temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp);
+ } while (temp2 != temp);
+ }
+ void clear_suspended() {
+ jint temp, temp2;
+ do {
+ temp = _state;
+ temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp);
+ } while (temp2 != temp);
+ }
+ bool is_suspended() { return _state & SR_SUSPENDED; }
+
+ #undef SR_SUSPENDED
+ };
+
+private:
+ typedef int (*sched_getcpu_func_t)(void);
+ typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen);
+ typedef int (*numa_max_node_func_t)(void);
+ typedef int (*numa_available_func_t)(void);
+ typedef int (*numa_tonode_memory_func_t)(void *start, size_t size, int node);
+ typedef void (*numa_interleave_memory_func_t)(void *start, size_t size, unsigned long *nodemask);
+
+ static sched_getcpu_func_t _sched_getcpu;
+ static numa_node_to_cpus_func_t _numa_node_to_cpus;
+ static numa_max_node_func_t _numa_max_node;
+ static numa_available_func_t _numa_available;
+ static numa_tonode_memory_func_t _numa_tonode_memory;
+ static numa_interleave_memory_func_t _numa_interleave_memory;
+ static unsigned long* _numa_all_nodes;
+
+ static void set_sched_getcpu(sched_getcpu_func_t func) { _sched_getcpu = func; }
+ static void set_numa_node_to_cpus(numa_node_to_cpus_func_t func) { _numa_node_to_cpus = func; }
+ static void set_numa_max_node(numa_max_node_func_t func) { _numa_max_node = func; }
+ static void set_numa_available(numa_available_func_t func) { _numa_available = func; }
+ static void set_numa_tonode_memory(numa_tonode_memory_func_t func) { _numa_tonode_memory = func; }
+ static void set_numa_interleave_memory(numa_interleave_memory_func_t func) { _numa_interleave_memory = func; }
+ static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; }
+public:
+ static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; }
+ static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) {
+ return _numa_node_to_cpus != NULL ? _numa_node_to_cpus(node, buffer, bufferlen) : -1;
+ }
+ static int numa_max_node() { return _numa_max_node != NULL ? _numa_max_node() : -1; }
+ static int numa_available() { return _numa_available != NULL ? _numa_available() : -1; }
+ static int numa_tonode_memory(void *start, size_t size, int node) {
+ return _numa_tonode_memory != NULL ? _numa_tonode_memory(start, size, node) : -1;
+ }
+ static void numa_interleave_memory(void *start, size_t size) {
+ if (_numa_interleave_memory != NULL && _numa_all_nodes != NULL) {
+ _numa_interleave_memory(start, size, _numa_all_nodes);
+ }
+ }
+ static int get_node_by_cpu(int cpu_id);
+};
+
+
+class PlatformEvent : public CHeapObj {
+ private:
+ double CachePad [4] ; // increase odds that _mutex is sole occupant of cache line
+ volatile int _Event ;
+ volatile int _nParked ;
+ pthread_mutex_t _mutex [1] ;
+ pthread_cond_t _cond [1] ;
+ double PostPad [2] ;
+ Thread * _Assoc ;
+
+ public: // TODO-FIXME: make dtor private
+ ~PlatformEvent() { guarantee (0, "invariant") ; }
+
+ public:
+ PlatformEvent() {
+ int status;
+ status = pthread_cond_init (_cond, NULL);
+ assert_status(status == 0, status, "cond_init");
+ status = pthread_mutex_init (_mutex, NULL);
+ assert_status(status == 0, status, "mutex_init");
+ _Event = 0 ;
+ _nParked = 0 ;
+ _Assoc = NULL ;
+ }
+
+ // Use caution with reset() and fired() -- they may require MEMBARs
+ void reset() { _Event = 0 ; }
+ int fired() { return _Event; }
+ void park () ;
+ void unpark () ;
+ int TryPark () ;
+ int park (jlong millis) ;
+ void SetAssociation (Thread * a) { _Assoc = a ; }
+} ;
+
+class PlatformParker : public CHeapObj {
+ protected:
+ pthread_mutex_t _mutex [1] ;
+ pthread_cond_t _cond [1] ;
+
+ public: // TODO-FIXME: make dtor private
+ ~PlatformParker() { guarantee (0, "invariant") ; }
+
+ public:
+ PlatformParker() {
+ int status;
+ status = pthread_cond_init (_cond, NULL);
+ assert_status(status == 0, status, "cond_init");
+ status = pthread_mutex_init (_mutex, NULL);
+ assert_status(status == 0, status, "mutex_init");
+ }
+} ;
+
+#endif // OS_BSD_VM_OS_BSD_HPP
diff --git a/src/os/bsd/vm/os_bsd.inline.hpp b/src/os/bsd/vm/os_bsd.inline.hpp
new file mode 100644
index 000000000..731a7e61e
--- /dev/null
+++ b/src/os/bsd/vm/os_bsd.inline.hpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_OS_BSD_INLINE_HPP
+#define OS_BSD_VM_OS_BSD_INLINE_HPP
+
+#include "runtime/atomic.hpp"
+#include "runtime/os.hpp"
+#ifdef TARGET_OS_ARCH_bsd_x86
+# include "atomic_bsd_x86.inline.hpp"
+# include "orderAccess_bsd_x86.inline.hpp"
+#endif
+#ifdef TARGET_OS_ARCH_bsd_zero
+# include "atomic_bsd_zero.inline.hpp"
+# include "orderAccess_bsd_zero.inline.hpp"
+#endif
+
+// System includes
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netdb.h>
+
+inline void* os::thread_local_storage_at(int index) {
+ return pthread_getspecific((pthread_key_t)index);
+}
+
+inline const char* os::file_separator() {
+ return "/";
+}
+
+inline const char* os::line_separator() {
+ return "\n";
+}
+
+inline const char* os::path_separator() {
+ return ":";
+}
+
+inline const char* os::jlong_format_specifier() {
+ return "%lld";
+}
+
+inline const char* os::julong_format_specifier() {
+ return "%llu";
+}
+
+// File names are case-sensitive on windows only
+inline int os::file_name_strcmp(const char* s1, const char* s2) {
+ return strcmp(s1, s2);
+}
+
+inline bool os::obsolete_option(const JavaVMOption *option) {
+ return false;
+}
+
+inline bool os::uses_stack_guard_pages() {
+ return true;
+}
+
+inline bool os::allocate_stack_guard_pages() {
+ assert(uses_stack_guard_pages(), "sanity check");
+#if !defined(__FreeBSD__) || __FreeBSD__ < 5
+ // Since FreeBSD 4 uses malloc() for allocating the thread stack
+ // there is no need to do anything extra to allocate the guard pages
+ return false;
+#else
+ // FreeBSD 5+ uses mmap MAP_STACK for allocating the thread stacks.
+ // Must 'allocate' them or guard pages are ignored.
+ return true;
+#endif
+}
+
+
+// On Bsd, reservations are made on a page by page basis, nothing to do.
+inline void os::split_reserved_memory(char *base, size_t size,
+ size_t split, bool realloc) {
+}
+
+
+// Bang the shadow pages if they need to be touched to be mapped.
+inline void os::bang_stack_shadow_pages() {
+}
+
+inline void os::dll_unload(void *lib) {
+ ::dlclose(lib);
+}
+
+inline const int os::default_file_open_flags() { return 0;}
+
+inline DIR* os::opendir(const char* dirname)
+{
+ assert(dirname != NULL, "just checking");
+ return ::opendir(dirname);
+}
+
+inline int os::readdir_buf_size(const char *path)
+{
+ return NAME_MAX + sizeof(dirent) + 1;
+}
+
+inline jlong os::lseek(int fd, jlong offset, int whence) {
+ return (jlong) ::lseek(fd, offset, whence);
+}
+
+inline int os::fsync(int fd) {
+ return ::fsync(fd);
+}
+
+inline char* os::native_path(char *path) {
+ return path;
+}
+
+inline int os::ftruncate(int fd, jlong length) {
+ return ::ftruncate(fd, length);
+}
+
+inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf)
+{
+ dirent* p;
+ int status;
+ assert(dirp != NULL, "just checking");
+
+ // NOTE: Bsd readdir_r (on RH 6.2 and 7.2 at least) is NOT like the POSIX
+ // version. Here is the doc for this function:
+ // http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_262.html
+
+ if((status = ::readdir_r(dirp, dbuf, &p)) != 0) {
+ errno = status;
+ return NULL;
+ } else
+ return p;
+}
+
+inline int os::closedir(DIR *dirp) {
+ assert(dirp != NULL, "argument is NULL");
+ return ::closedir(dirp);
+}
+
+// macros for restartable system calls
+
+#define RESTARTABLE(_cmd, _result) do { \
+ _result = _cmd; \
+ } while(((int)_result == OS_ERR) && (errno == EINTR))
+
+#define RESTARTABLE_RETURN_INT(_cmd) do { \
+ int _result; \
+ RESTARTABLE(_cmd, _result); \
+ return _result; \
+} while(false)
+
+inline bool os::numa_has_static_binding() { return true; }
+inline bool os::numa_has_group_homing() { return false; }
+
+inline size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) {
+ size_t res;
+ RESTARTABLE( (size_t) ::read(fd, buf, (size_t) nBytes), res);
+ return res;
+}
+
+inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
+ size_t res;
+ RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res);
+ return res;
+}
+
+inline int os::close(int fd) {
+ RESTARTABLE_RETURN_INT(::close(fd));
+}
+
+inline int os::socket_close(int fd) {
+ RESTARTABLE_RETURN_INT(::close(fd));
+}
+
+inline int os::socket(int domain, int type, int protocol) {
+ return ::socket(domain, type, protocol);
+}
+
+inline int os::recv(int fd, char *buf, int nBytes, int flags) {
+ RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, (unsigned int) flags));
+}
+
+inline int os::send(int fd, char *buf, int nBytes, int flags) {
+ RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, (unsigned int) flags));
+}
+
+inline int os::raw_send(int fd, char *buf, int nBytes, int flags) {
+ return os::send(fd, buf, nBytes, flags);
+}
+
+inline int os::timeout(int fd, long timeout) {
+ julong prevtime,newtime;
+ struct timeval t;
+
+ gettimeofday(&t, NULL);
+ prevtime = ((julong)t.tv_sec * 1000) + t.tv_usec / 1000;
+
+ for(;;) {
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLERR;
+
+ int res = ::poll(&pfd, 1, timeout);
+
+ if (res == OS_ERR && errno == EINTR) {
+
+ // On Bsd any value < 0 means "forever"
+
+ if(timeout >= 0) {
+ gettimeofday(&t, NULL);
+ newtime = ((julong)t.tv_sec * 1000) + t.tv_usec / 1000;
+ timeout -= newtime - prevtime;
+ if(timeout <= 0)
+ return OS_OK;
+ prevtime = newtime;
+ }
+ } else
+ return res;
+ }
+}
+
+inline int os::listen(int fd, int count) {
+ return ::listen(fd, count);
+}
+
+inline int os::connect(int fd, struct sockaddr *him, int len) {
+ RESTARTABLE_RETURN_INT(::connect(fd, him, len));
+}
+
+inline int os::accept(int fd, struct sockaddr *him, int *len) {
+ // This cast is from int to unsigned int on bsd. Since we
+ // only pass the parameter "len" around the vm and don't try to
+ // fetch it's value, this cast is safe for now. The java.net group
+ // may need and want to change this interface someday if socklen_t goes
+ // to 64 bits on some platform that we support.
+
+ // At least OpenBSD and FreeBSD can return EINTR from accept.
+ RESTARTABLE_RETURN_INT(::accept(fd, him, (socklen_t *)len));
+}
+
+inline int os::recvfrom(int fd, char *buf, int nBytes, int flags,
+ sockaddr *from, int *fromlen) {
+ RESTARTABLE_RETURN_INT(::recvfrom(fd, buf, nBytes, (unsigned int) flags, from, (socklen_t *)fromlen));
+}
+
+inline int os::sendto(int fd, char *buf, int len, int flags,
+ struct sockaddr *to, int tolen) {
+ RESTARTABLE_RETURN_INT(::sendto(fd, buf, len, (unsigned int) flags, to, tolen));
+}
+
+inline int os::socket_shutdown(int fd, int howto){
+ return ::shutdown(fd, howto);
+}
+
+inline int os::bind(int fd, struct sockaddr *him, int len){
+ return ::bind(fd, him, len);
+}
+
+inline int os::get_sock_name(int fd, struct sockaddr *him, int *len){
+ return ::getsockname(fd, him, (socklen_t *)len);
+}
+
+inline int os::get_host_name(char* name, int namelen){
+ return ::gethostname(name, namelen);
+}
+
+inline struct hostent* os::get_host_by_name(char* name) {
+ return ::gethostbyname(name);
+}
+inline int os::get_sock_opt(int fd, int level, int optname,
+ char *optval, int* optlen){
+ return ::getsockopt(fd, level, optname, optval, (socklen_t *)optlen);
+}
+
+inline int os::set_sock_opt(int fd, int level, int optname,
+ const char *optval, int optlen){
+ return ::setsockopt(fd, level, optname, optval, optlen);
+}
+#endif // OS_BSD_VM_OS_BSD_INLINE_HPP
diff --git a/src/os/bsd/vm/os_share_bsd.hpp b/src/os/bsd/vm/os_share_bsd.hpp
new file mode 100644
index 000000000..5caa7825c
--- /dev/null
+++ b/src/os/bsd/vm/os_share_bsd.hpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_OS_SHARE_BSD_HPP
+#define OS_BSD_VM_OS_SHARE_BSD_HPP
+
+// misc
+void signalHandler(int, siginfo_t*, ucontext_t*);
+void handle_unexpected_exception(Thread* thread, int sig, siginfo_t* info, address pc, address adjusted_pc);
+#ifndef PRODUCT
+void continue_with_dump(void);
+#endif
+
+#define PROCFILE_LENGTH 128
+
+#endif // OS_BSD_VM_OS_SHARE_BSD_HPP
diff --git a/src/os/bsd/vm/perfMemory_bsd.cpp b/src/os/bsd/vm/perfMemory_bsd.cpp
new file mode 100644
index 000000000..c93289e59
--- /dev/null
+++ b/src/os/bsd/vm/perfMemory_bsd.cpp
@@ -0,0 +1,1041 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+#include "os_bsd.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/perfMemory.hpp"
+#include "utilities/exceptions.hpp"
+
+// put OS-includes here
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <errno.h>
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/stat.h>
+# include <signal.h>
+# include <pwd.h>
+
+static char* backing_store_file_name = NULL; // name of the backing store
+ // file, if successfully created.
+
+// Standard Memory Implementation Details
+
+// create the PerfData memory region in standard memory.
+//
+static char* create_standard_memory(size_t size) {
+
+ // allocate an aligned chuck of memory
+ char* mapAddress = os::reserve_memory(size);
+
+ if (mapAddress == NULL) {
+ return NULL;
+ }
+
+ // commit memory
+ if (!os::commit_memory(mapAddress, size)) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("Could not commit PerfData memory\n");
+ }
+ os::release_memory(mapAddress, size);
+ return NULL;
+ }
+
+ return mapAddress;
+}
+
+// delete the PerfData memory region
+//
+static void delete_standard_memory(char* addr, size_t size) {
+
+ // there are no persistent external resources to cleanup for standard
+ // memory. since DestroyJavaVM does not support unloading of the JVM,
+ // cleanup of the memory resource is not performed. The memory will be
+ // reclaimed by the OS upon termination of the process.
+ //
+ return;
+}
+
+// save the specified memory region to the given file
+//
+// Note: this function might be called from signal handler (by os::abort()),
+// don't allocate heap memory.
+//
+static void save_memory_to_file(char* addr, size_t size) {
+
+ const char* destfile = PerfMemory::get_perfdata_file_path();
+ assert(destfile[0] != '\0', "invalid PerfData file path");
+
+ int result;
+
+ RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE),
+ result);;
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("Could not create Perfdata save file: %s: %s\n",
+ destfile, strerror(errno));
+ }
+ } else {
+ int fd = result;
+
+ for (size_t remaining = size; remaining > 0;) {
+
+ RESTARTABLE(::write(fd, addr, remaining), result);
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("Could not write Perfdata save file: %s: %s\n",
+ destfile, strerror(errno));
+ }
+ break;
+ }
+
+ remaining -= (size_t)result;
+ addr += result;
+ }
+
+ RESTARTABLE(::close(fd), result);
+ if (PrintMiscellaneous && Verbose) {
+ if (result == OS_ERR) {
+ warning("Could not close %s: %s\n", destfile, strerror(errno));
+ }
+ }
+ }
+ FREE_C_HEAP_ARRAY(char, destfile);
+}
+
+
+// Shared Memory Implementation Details
+
+// Note: the solaris and bsd shared memory implementation uses the mmap
+// interface with a backing store file to implement named shared memory.
+// Using the file system as the name space for shared memory allows a
+// common name space to be supported across a variety of platforms. It
+// also provides a name space that Java applications can deal with through
+// simple file apis.
+//
+// The solaris and bsd implementations store the backing store file in
+// a user specific temporary directory located in the /tmp file system,
+// which is always a local file system and is sometimes a RAM based file
+// system.
+
+// return the user specific temporary directory name.
+//
+// the caller is expected to free the allocated memory.
+//
+static char* get_user_tmp_dir(const char* user) {
+
+ const char* tmpdir = os::get_temp_directory();
+ const char* perfdir = PERFDATA_NAME;
+ size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
+ char* dirname = NEW_C_HEAP_ARRAY(char, nbytes);
+
+ // construct the path name to user specific tmp directory
+ snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user);
+
+ return dirname;
+}
+
+// convert the given file name into a process id. if the file
+// does not meet the file naming constraints, return 0.
+//
+static pid_t filename_to_pid(const char* filename) {
+
+ // a filename that doesn't begin with a digit is not a
+ // candidate for conversion.
+ //
+ if (!isdigit(*filename)) {
+ return 0;
+ }
+
+ // check if file name can be converted to an integer without
+ // any leftover characters.
+ //
+ char* remainder = NULL;
+ errno = 0;
+ pid_t pid = (pid_t)strtol(filename, &remainder, 10);
+
+ if (errno != 0) {
+ return 0;
+ }
+
+ // check for left over characters. If any, then the filename is
+ // not a candidate for conversion.
+ //
+ if (remainder != NULL && *remainder != '\0') {
+ return 0;
+ }
+
+ // successful conversion, return the pid
+ return pid;
+}
+
+
+// check if the given path is considered a secure directory for
+// the backing store files. Returns true if the directory exists
+// and is considered a secure location. Returns false if the path
+// is a symbolic link or if an error occurred.
+//
+static bool is_directory_secure(const char* path) {
+ struct stat statbuf;
+ int result = 0;
+
+ RESTARTABLE(::lstat(path, &statbuf), result);
+ if (result == OS_ERR) {
+ return false;
+ }
+
+ // the path exists, now check it's mode
+ if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) {
+ // the path represents a link or some non-directory file type,
+ // which is not what we expected. declare it insecure.
+ //
+ return false;
+ }
+ else {
+ // we have an existing directory, check if the permissions are safe.
+ //
+ if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
+ // the directory is open for writing and could be subjected
+ // to a symlnk attack. declare it insecure.
+ //
+ return false;
+ }
+ }
+ return true;
+}
+
+
+// return the user name for the given user id
+//
+// the caller is expected to free the allocated memory.
+//
+static char* get_user_name(uid_t uid) {
+
+ struct passwd pwent;
+
+ // determine the max pwbuf size from sysconf, and hardcode
+ // a default if this not available through sysconf.
+ //
+ long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufsize == -1)
+ bufsize = 1024;
+
+ char* pwbuf = NEW_C_HEAP_ARRAY(char, bufsize);
+
+ // POSIX interface to getpwuid_r is used on LINUX
+ struct passwd* p;
+ int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p);
+
+ if (result != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {
+ if (PrintMiscellaneous && Verbose) {
+ if (result != 0) {
+ warning("Could not retrieve passwd entry: %s\n",
+ strerror(result));
+ }
+ else if (p == NULL) {
+ // this check is added to protect against an observed problem
+ // with getpwuid_r() on RedHat 9 where getpwuid_r returns 0,
+ // indicating success, but has p == NULL. This was observed when
+ // inserting a file descriptor exhaustion fault prior to the call
+ // getpwuid_r() call. In this case, error is set to the appropriate
+ // error condition, but this is undocumented behavior. This check
+ // is safe under any condition, but the use of errno in the output
+ // message may result in an erroneous message.
+ // Bug Id 89052 was opened with RedHat.
+ //
+ warning("Could not retrieve passwd entry: %s\n",
+ strerror(errno));
+ }
+ else {
+ warning("Could not determine user name: %s\n",
+ p->pw_name == NULL ? "pw_name = NULL" :
+ "pw_name zero length");
+ }
+ }
+ FREE_C_HEAP_ARRAY(char, pwbuf);
+ return NULL;
+ }
+
+ char* user_name = NEW_C_HEAP_ARRAY(char, strlen(p->pw_name) + 1);
+ strcpy(user_name, p->pw_name);
+
+ FREE_C_HEAP_ARRAY(char, pwbuf);
+ return user_name;
+}
+
+// return the name of the user that owns the process identified by vmid.
+//
+// This method uses a slow directory search algorithm to find the backing
+// store file for the specified vmid and returns the user name, as determined
+// by the user name suffix of the hsperfdata_<username> directory name.
+//
+// the caller is expected to free the allocated memory.
+//
+static char* get_user_name_slow(int vmid, TRAPS) {
+
+ // short circuit the directory search if the process doesn't even exist.
+ if (kill(vmid, 0) == OS_ERR) {
+ if (errno == ESRCH) {
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "Process not found");
+ }
+ else /* EPERM */ {
+ THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ }
+ }
+
+ // directory search
+ char* oldest_user = NULL;
+ time_t oldest_ctime = 0;
+
+ const char* tmpdirname = os::get_temp_directory();
+
+ DIR* tmpdirp = os::opendir(tmpdirname);
+
+ if (tmpdirp == NULL) {
+ return NULL;
+ }
+
+ // for each entry in the directory that matches the pattern hsperfdata_*,
+ // open the directory and check if the file for the given vmid exists.
+ // The file with the expected name and the latest creation date is used
+ // to determine the user name for the process id.
+ //
+ struct dirent* dentry;
+ char* tdbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(tmpdirname));
+ errno = 0;
+ while ((dentry = os::readdir(tmpdirp, (struct dirent *)tdbuf)) != NULL) {
+
+ // check if the directory entry is a hsperfdata file
+ if (strncmp(dentry->d_name, PERFDATA_NAME, strlen(PERFDATA_NAME)) != 0) {
+ continue;
+ }
+
+ char* usrdir_name = NEW_C_HEAP_ARRAY(char,
+ strlen(tmpdirname) + strlen(dentry->d_name) + 2);
+ strcpy(usrdir_name, tmpdirname);
+ strcat(usrdir_name, "/");
+ strcat(usrdir_name, dentry->d_name);
+
+ DIR* subdirp = os::opendir(usrdir_name);
+
+ if (subdirp == NULL) {
+ FREE_C_HEAP_ARRAY(char, usrdir_name);
+ continue;
+ }
+
+ // Since we don't create the backing store files in directories
+ // pointed to by symbolic links, we also don't follow them when
+ // looking for the files. We check for a symbolic link after the
+ // call to opendir in order to eliminate a small window where the
+ // symlink can be exploited.
+ //
+ if (!is_directory_secure(usrdir_name)) {
+ FREE_C_HEAP_ARRAY(char, usrdir_name);
+ os::closedir(subdirp);
+ continue;
+ }
+
+ struct dirent* udentry;
+ char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name));
+ errno = 0;
+ while ((udentry = os::readdir(subdirp, (struct dirent *)udbuf)) != NULL) {
+
+ if (filename_to_pid(udentry->d_name) == vmid) {
+ struct stat statbuf;
+ int result;
+
+ char* filename = NEW_C_HEAP_ARRAY(char,
+ strlen(usrdir_name) + strlen(udentry->d_name) + 2);
+
+ strcpy(filename, usrdir_name);
+ strcat(filename, "/");
+ strcat(filename, udentry->d_name);
+
+ // don't follow symbolic links for the file
+ RESTARTABLE(::lstat(filename, &statbuf), result);
+ if (result == OS_ERR) {
+ FREE_C_HEAP_ARRAY(char, filename);
+ continue;
+ }
+
+ // skip over files that are not regular files.
+ if (!S_ISREG(statbuf.st_mode)) {
+ FREE_C_HEAP_ARRAY(char, filename);
+ continue;
+ }
+
+ // compare and save filename with latest creation time
+ if (statbuf.st_size > 0 && statbuf.st_ctime > oldest_ctime) {
+
+ if (statbuf.st_ctime > oldest_ctime) {
+ char* user = strchr(dentry->d_name, '_') + 1;
+
+ if (oldest_user != NULL) FREE_C_HEAP_ARRAY(char, oldest_user);
+ oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1);
+
+ strcpy(oldest_user, user);
+ oldest_ctime = statbuf.st_ctime;
+ }
+ }
+
+ FREE_C_HEAP_ARRAY(char, filename);
+ }
+ }
+ os::closedir(subdirp);
+ FREE_C_HEAP_ARRAY(char, udbuf);
+ FREE_C_HEAP_ARRAY(char, usrdir_name);
+ }
+ os::closedir(tmpdirp);
+ FREE_C_HEAP_ARRAY(char, tdbuf);
+
+ return(oldest_user);
+}
+
+// return the name of the user that owns the JVM indicated by the given vmid.
+//
+static char* get_user_name(int vmid, TRAPS) {
+ return get_user_name_slow(vmid, CHECK_NULL);
+}
+
+// return the file name of the backing store file for the named
+// shared memory region for the given user name and vmid.
+//
+// the caller is expected to free the allocated memory.
+//
+static char* get_sharedmem_filename(const char* dirname, int vmid) {
+
+ // add 2 for the file separator and a null terminator.
+ size_t nbytes = strlen(dirname) + UINT_CHARS + 2;
+
+ char* name = NEW_C_HEAP_ARRAY(char, nbytes);
+ snprintf(name, nbytes, "%s/%d", dirname, vmid);
+
+ return name;
+}
+
+
+// remove file
+//
+// this method removes the file specified by the given path
+//
+static void remove_file(const char* path) {
+
+ int result;
+
+ // if the file is a directory, the following unlink will fail. since
+ // we don't expect to find directories in the user temp directory, we
+ // won't try to handle this situation. even if accidentially or
+ // maliciously planted, the directory's presence won't hurt anything.
+ //
+ RESTARTABLE(::unlink(path), result);
+ if (PrintMiscellaneous && Verbose && result == OS_ERR) {
+ if (errno != ENOENT) {
+ warning("Could not unlink shared memory backing"
+ " store file %s : %s\n", path, strerror(errno));
+ }
+ }
+}
+
+
+// remove file
+//
+// this method removes the file with the given file name in the
+// named directory.
+//
+static void remove_file(const char* dirname, const char* filename) {
+
+ size_t nbytes = strlen(dirname) + strlen(filename) + 2;
+ char* path = NEW_C_HEAP_ARRAY(char, nbytes);
+
+ strcpy(path, dirname);
+ strcat(path, "/");
+ strcat(path, filename);
+
+ remove_file(path);
+
+ FREE_C_HEAP_ARRAY(char, path);
+}
+
+
+// cleanup stale shared memory resources
+//
+// This method attempts to remove all stale shared memory files in
+// the named user temporary directory. It scans the named directory
+// for files matching the pattern ^$[0-9]*$. For each file found, the
+// process id is extracted from the file name and a test is run to
+// determine if the process is alive. If the process is not alive,
+// any stale file resources are removed.
+//
+static void cleanup_sharedmem_resources(const char* dirname) {
+
+ // open the user temp directory
+ DIR* dirp = os::opendir(dirname);
+
+ if (dirp == NULL) {
+ // directory doesn't exist, so there is nothing to cleanup
+ return;
+ }
+
+ if (!is_directory_secure(dirname)) {
+ // the directory is not a secure directory
+ return;
+ }
+
+ // for each entry in the directory that matches the expected file
+ // name pattern, determine if the file resources are stale and if
+ // so, remove the file resources. Note, instrumented HotSpot processes
+ // for this user may start and/or terminate during this search and
+ // remove or create new files in this directory. The behavior of this
+ // loop under these conditions is dependent upon the implementation of
+ // opendir/readdir.
+ //
+ struct dirent* entry;
+ char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname));
+ errno = 0;
+ while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
+
+ pid_t pid = filename_to_pid(entry->d_name);
+
+ if (pid == 0) {
+
+ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
+
+ // attempt to remove all unexpected files, except "." and ".."
+ remove_file(dirname, entry->d_name);
+ }
+
+ errno = 0;
+ continue;
+ }
+
+ // we now have a file name that converts to a valid integer
+ // that could represent a process id . if this process id
+ // matches the current process id or the process is not running,
+ // then remove the stale file resources.
+ //
+ // process liveness is detected by sending signal number 0 to
+ // the process id (see kill(2)). if kill determines that the
+ // process does not exist, then the file resources are removed.
+ // if kill determines that that we don't have permission to
+ // signal the process, then the file resources are assumed to
+ // be stale and are removed because the resources for such a
+ // process should be in a different user specific directory.
+ //
+ if ((pid == os::current_process_id()) ||
+ (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
+
+ remove_file(dirname, entry->d_name);
+ }
+ errno = 0;
+ }
+ os::closedir(dirp);
+ FREE_C_HEAP_ARRAY(char, dbuf);
+}
+
+// make the user specific temporary directory. Returns true if
+// the directory exists and is secure upon return. Returns false
+// if the directory exists but is either a symlink, is otherwise
+// insecure, or if an error occurred.
+//
+static bool make_user_tmp_dir(const char* dirname) {
+
+ // create the directory with 0755 permissions. note that the directory
+ // will be owned by euid::egid, which may not be the same as uid::gid.
+ //
+ if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) {
+ if (errno == EEXIST) {
+ // The directory already exists and was probably created by another
+ // JVM instance. However, this could also be the result of a
+ // deliberate symlink. Verify that the existing directory is safe.
+ //
+ if (!is_directory_secure(dirname)) {
+ // directory is not secure
+ if (PrintMiscellaneous && Verbose) {
+ warning("%s directory is insecure\n", dirname);
+ }
+ return false;
+ }
+ }
+ else {
+ // we encountered some other failure while attempting
+ // to create the directory
+ //
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not create directory %s: %s\n",
+ dirname, strerror(errno));
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+// create the shared memory file resources
+//
+// This method creates the shared memory file with the given size
+// This method also creates the user specific temporary directory, if
+// it does not yet exist.
+//
+static int create_sharedmem_resources(const char* dirname, const char* filename, size_t size) {
+
+ // make the user temporary directory
+ if (!make_user_tmp_dir(dirname)) {
+ // could not make/find the directory or the found directory
+ // was not secure
+ return -1;
+ }
+
+ int result;
+
+ RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not create file %s: %s\n", filename, strerror(errno));
+ }
+ return -1;
+ }
+
+ // save the file descriptor
+ int fd = result;
+
+ // set the file size
+ RESTARTABLE(::ftruncate(fd, (off_t)size), result);
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not set shared memory file size: %s\n", strerror(errno));
+ }
+ RESTARTABLE(::close(fd), result);
+ return -1;
+ }
+
+ // Verify that we have enough disk space for this file.
+ // We'll get random SIGBUS crashes on memory accesses if
+ // we don't.
+
+ for (size_t seekpos = 0; seekpos < size; seekpos += os::vm_page_size()) {
+ int zero_int = 0;
+ result = (int)os::seek_to_file_offset(fd, (jlong)(seekpos));
+ if (result == -1 ) break;
+ RESTARTABLE(::write(fd, &zero_int, 1), result);
+ if (result != 1) {
+ if (errno == ENOSPC) {
+ warning("Insufficient space for shared memory file:\n %s\nTry using the -Djava.io.tmpdir= option to select an alternate temp location.\n", filename);
+ }
+ break;
+ }
+ }
+
+ if (result != -1) {
+ return fd;
+ } else {
+ RESTARTABLE(::close(fd), result);
+ return -1;
+ }
+}
+
+// open the shared memory file for the given user and vmid. returns
+// the file descriptor for the open file or -1 if the file could not
+// be opened.
+//
+static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
+
+ // open the file
+ int result;
+ RESTARTABLE(::open(filename, oflags), result);
+ if (result == OS_ERR) {
+ if (errno == ENOENT) {
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "Process not found");
+ }
+ else if (errno == EACCES) {
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "Permission denied");
+ }
+ else {
+ THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ }
+ }
+
+ return result;
+}
+
+// create a named shared memory region. returns the address of the
+// memory region on success or NULL on failure. A return value of
+// NULL will ultimately disable the shared memory feature.
+//
+// On Solaris and Bsd, the name space for shared memory objects
+// is the file system name space.
+//
+// A monitoring application attaching to a JVM does not need to know
+// the file system name of the shared memory object. However, it may
+// be convenient for applications to discover the existence of newly
+// created and terminating JVMs by watching the file system name space
+// for files being created or removed.
+//
+static char* mmap_create_shared(size_t size) {
+
+ int result;
+ int fd;
+ char* mapAddress;
+
+ int vmid = os::current_process_id();
+
+ char* user_name = get_user_name(geteuid());
+
+ if (user_name == NULL)
+ return NULL;
+
+ char* dirname = get_user_tmp_dir(user_name);
+ char* filename = get_sharedmem_filename(dirname, vmid);
+
+ // cleanup any stale shared memory files
+ cleanup_sharedmem_resources(dirname);
+
+ assert(((size > 0) && (size % os::vm_page_size() == 0)),
+ "unexpected PerfMemory region size");
+
+ fd = create_sharedmem_resources(dirname, filename, size);
+
+ FREE_C_HEAP_ARRAY(char, user_name);
+ FREE_C_HEAP_ARRAY(char, dirname);
+
+ if (fd == -1) {
+ FREE_C_HEAP_ARRAY(char, filename);
+ return NULL;
+ }
+
+ mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+ // attempt to close the file - restart it if it was interrupted,
+ // but ignore other failures
+ RESTARTABLE(::close(fd), result);
+ assert(result != OS_ERR, "could not close file");
+
+ if (mapAddress == MAP_FAILED) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("mmap failed - %s\n", strerror(errno));
+ }
+ remove_file(filename);
+ FREE_C_HEAP_ARRAY(char, filename);
+ return NULL;
+ }
+
+ // save the file name for use in delete_shared_memory()
+ backing_store_file_name = filename;
+
+ // clear the shared memory region
+ (void)::memset((void*) mapAddress, 0, size);
+
+ return mapAddress;
+}
+
+// release a named shared memory region
+//
+static void unmap_shared(char* addr, size_t bytes) {
+ os::release_memory(addr, bytes);
+}
+
+// create the PerfData memory region in shared memory.
+//
+static char* create_shared_memory(size_t size) {
+
+ // create the shared memory region.
+ return mmap_create_shared(size);
+}
+
+// delete the shared PerfData memory region
+//
+static void delete_shared_memory(char* addr, size_t size) {
+
+ // cleanup the persistent shared memory resources. since DestroyJavaVM does
+ // not support unloading of the JVM, unmapping of the memory resource is
+ // not performed. The memory will be reclaimed by the OS upon termination of
+ // the process. The backing store file is deleted from the file system.
+
+ assert(!PerfDisableSharedMem, "shouldn't be here");
+
+ if (backing_store_file_name != NULL) {
+ remove_file(backing_store_file_name);
+ // Don't.. Free heap memory could deadlock os::abort() if it is called
+ // from signal handler. OS will reclaim the heap memory.
+ // FREE_C_HEAP_ARRAY(char, backing_store_file_name);
+ backing_store_file_name = NULL;
+ }
+}
+
+// return the size of the file for the given file descriptor
+// or 0 if it is not a valid size for a shared memory file
+//
+static size_t sharedmem_filesize(int fd, TRAPS) {
+
+ struct stat statbuf;
+ int result;
+
+ RESTARTABLE(::fstat(fd, &statbuf), result);
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("fstat failed: %s\n", strerror(errno));
+ }
+ THROW_MSG_0(vmSymbols::java_io_IOException(),
+ "Could not determine PerfMemory size");
+ }
+
+ if ((statbuf.st_size == 0) ||
+ ((size_t)statbuf.st_size % os::vm_page_size() != 0)) {
+ THROW_MSG_0(vmSymbols::java_lang_Exception(),
+ "Invalid PerfMemory size");
+ }
+
+ return (size_t)statbuf.st_size;
+}
+
+// attach to a named shared memory region.
+//
+static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemoryMode mode, char** addr, size_t* sizep, TRAPS) {
+
+ char* mapAddress;
+ int result;
+ int fd;
+ size_t size;
+ const char* luser = NULL;
+
+ int mmap_prot;
+ int file_flags;
+
+ ResourceMark rm;
+
+ // map the high level access mode to the appropriate permission
+ // constructs for the file and the shared memory mapping.
+ if (mode == PerfMemory::PERF_MODE_RO) {
+ mmap_prot = PROT_READ;
+ file_flags = O_RDONLY;
+ }
+ else if (mode == PerfMemory::PERF_MODE_RW) {
+#ifdef LATER
+ mmap_prot = PROT_READ | PROT_WRITE;
+ file_flags = O_RDWR;
+#else
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ "Unsupported access mode");
+#endif
+ }
+ else {
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ "Illegal access mode");
+ }
+
+ if (user == NULL || strlen(user) == 0) {
+ luser = get_user_name(vmid, CHECK);
+ }
+ else {
+ luser = user;
+ }
+
+ if (luser == NULL) {
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ "Could not map vmid to user Name");
+ }
+
+ char* dirname = get_user_tmp_dir(luser);
+
+ // since we don't follow symbolic links when creating the backing
+ // store file, we don't follow them when attaching either.
+ //
+ if (!is_directory_secure(dirname)) {
+ FREE_C_HEAP_ARRAY(char, dirname);
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+ "Process not found");
+ }
+
+ char* filename = get_sharedmem_filename(dirname, vmid);
+
+ // copy heap memory to resource memory. the open_sharedmem_file
+ // method below need to use the filename, but could throw an
+ // exception. using a resource array prevents the leak that
+ // would otherwise occur.
+ char* rfilename = NEW_RESOURCE_ARRAY(char, strlen(filename) + 1);
+ strcpy(rfilename, filename);
+
+ // free the c heap resources that are no longer needed
+ if (luser != user) FREE_C_HEAP_ARRAY(char, luser);
+ FREE_C_HEAP_ARRAY(char, dirname);
+ FREE_C_HEAP_ARRAY(char, filename);
+
+ // open the shared memory file for the give vmid
+ fd = open_sharedmem_file(rfilename, file_flags, CHECK);
+ assert(fd != OS_ERR, "unexpected value");
+
+ if (*sizep == 0) {
+ size = sharedmem_filesize(fd, CHECK);
+ assert(size != 0, "unexpected size");
+ }
+
+ mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0);
+
+ // attempt to close the file - restart if it gets interrupted,
+ // but ignore other failures
+ RESTARTABLE(::close(fd), result);
+ assert(result != OS_ERR, "could not close file");
+
+ if (mapAddress == MAP_FAILED) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("mmap failed: %s\n", strerror(errno));
+ }
+ THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
+ "Could not map PerfMemory");
+ }
+
+ *addr = mapAddress;
+ *sizep = size;
+
+ if (PerfTraceMemOps) {
+ tty->print("mapped " SIZE_FORMAT " bytes for vmid %d at "
+ INTPTR_FORMAT "\n", size, vmid, (void*)mapAddress);
+ }
+}
+
+
+
+
+// create the PerfData memory region
+//
+// This method creates the memory region used to store performance
+// data for the JVM. The memory may be created in standard or
+// shared memory.
+//
+void PerfMemory::create_memory_region(size_t size) {
+
+ if (PerfDisableSharedMem) {
+ // do not share the memory for the performance data.
+ _start = create_standard_memory(size);
+ }
+ else {
+ _start = create_shared_memory(size);
+ if (_start == NULL) {
+
+ // creation of the shared memory region failed, attempt
+ // to create a contiguous, non-shared memory region instead.
+ //
+ if (PrintMiscellaneous && Verbose) {
+ warning("Reverting to non-shared PerfMemory region.\n");
+ }
+ PerfDisableSharedMem = true;
+ _start = create_standard_memory(size);
+ }
+ }
+
+ if (_start != NULL) _capacity = size;
+
+}
+
+// delete the PerfData memory region
+//
+// This method deletes the memory region used to store performance
+// data for the JVM. The memory region indicated by the <address, size>
+// tuple will be inaccessible after a call to this method.
+//
+void PerfMemory::delete_memory_region() {
+
+ assert((start() != NULL && capacity() > 0), "verify proper state");
+
+ // If user specifies PerfDataSaveFile, it will save the performance data
+ // to the specified file name no matter whether PerfDataSaveToFile is specified
+ // or not. In other word, -XX:PerfDataSaveFile=.. overrides flag
+ // -XX:+PerfDataSaveToFile.
+ if (PerfDataSaveToFile || PerfDataSaveFile != NULL) {
+ save_memory_to_file(start(), capacity());
+ }
+
+ if (PerfDisableSharedMem) {
+ delete_standard_memory(start(), capacity());
+ }
+ else {
+ delete_shared_memory(start(), capacity());
+ }
+}
+
+// attach to the PerfData memory region for another JVM
+//
+// This method returns an <address, size> tuple that points to
+// a memory buffer that is kept reasonably synchronized with
+// the PerfData memory region for the indicated JVM. This
+// buffer may be kept in synchronization via shared memory
+// or some other mechanism that keeps the buffer updated.
+//
+// If the JVM chooses not to support the attachability feature,
+// this method should throw an UnsupportedOperation exception.
+//
+// This implementation utilizes named shared memory to map
+// the indicated process's PerfData memory region into this JVMs
+// address space.
+//
+void PerfMemory::attach(const char* user, int vmid, PerfMemoryMode mode, char** addrp, size_t* sizep, TRAPS) {
+
+ if (vmid == 0 || vmid == os::current_process_id()) {
+ *addrp = start();
+ *sizep = capacity();
+ return;
+ }
+
+ mmap_attach_shared(user, vmid, mode, addrp, sizep, CHECK);
+}
+
+// detach from the PerfData memory region of another JVM
+//
+// This method detaches the PerfData memory region of another
+// JVM, specified as an <address, size> tuple of a buffer
+// in this process's address space. This method may perform
+// arbitrary actions to accomplish the detachment. The memory
+// region specified by <address, size> will be inaccessible after
+// a call to this method.
+//
+// If the JVM chooses not to support the attachability feature,
+// this method should throw an UnsupportedOperation exception.
+//
+// This implementation utilizes named shared memory to detach
+// the indicated process's PerfData memory region from this
+// process's address space.
+//
+void PerfMemory::detach(char* addr, size_t bytes, TRAPS) {
+
+ assert(addr != 0, "address sanity check");
+ assert(bytes > 0, "capacity sanity check");
+
+ if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) {
+ // prevent accidental detachment of this process's PerfMemory region
+ return;
+ }
+
+ unmap_shared(addr, bytes);
+}
+
+char* PerfMemory::backing_store_filename() {
+ return backing_store_file_name;
+}
diff --git a/src/os/bsd/vm/stubRoutines_bsd.cpp b/src/os/bsd/vm/stubRoutines_bsd.cpp
new file mode 100644
index 000000000..1fa7d3a9f
--- /dev/null
+++ b/src/os/bsd/vm/stubRoutines_bsd.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "runtime/stubRoutines.hpp"
diff --git a/src/os/bsd/vm/threadCritical_bsd.cpp b/src/os/bsd/vm/threadCritical_bsd.cpp
new file mode 100644
index 000000000..e337a5bd5
--- /dev/null
+++ b/src/os/bsd/vm/threadCritical_bsd.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/threadCritical.hpp"
+#include "thread_bsd.inline.hpp"
+
+// put OS-includes here
+# include <pthread.h>
+
+//
+// See threadCritical.hpp for details of this class.
+//
+
+static pthread_t tc_owner = 0;
+static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int tc_count = 0;
+
+void ThreadCritical::initialize() {
+}
+
+void ThreadCritical::release() {
+}
+
+ThreadCritical::ThreadCritical() {
+ pthread_t self = pthread_self();
+ if (self != tc_owner) {
+ int ret = pthread_mutex_lock(&tc_mutex);
+ guarantee(ret == 0, "fatal error with pthread_mutex_lock()");
+ assert(tc_count == 0, "Lock acquired with illegal reentry count.");
+ tc_owner = self;
+ }
+ tc_count++;
+}
+
+ThreadCritical::~ThreadCritical() {
+ assert(tc_owner == pthread_self(), "must have correct owner");
+ assert(tc_count > 0, "must have correct count");
+
+ tc_count--;
+ if (tc_count == 0) {
+ tc_owner = 0;
+ int ret = pthread_mutex_unlock(&tc_mutex);
+ guarantee(ret == 0, "fatal error with pthread_mutex_unlock()");
+ }
+}
diff --git a/src/os/bsd/vm/thread_bsd.inline.hpp b/src/os/bsd/vm/thread_bsd.inline.hpp
new file mode 100644
index 000000000..290f47786
--- /dev/null
+++ b/src/os/bsd/vm/thread_bsd.inline.hpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_THREAD_BSD_INLINE_HPP
+#define OS_BSD_VM_THREAD_BSD_INLINE_HPP
+
+#include "runtime/atomic.hpp"
+#include "runtime/prefetch.hpp"
+#include "runtime/thread.hpp"
+#include "runtime/threadLocalStorage.hpp"
+#ifdef TARGET_OS_ARCH_bsd_x86
+# include "atomic_bsd_x86.inline.hpp"
+# include "orderAccess_bsd_x86.inline.hpp"
+# include "prefetch_bsd_x86.inline.hpp"
+#endif
+#ifdef TARGET_OS_ARCH_bsd_zero
+# include "atomic_bsd_zero.inline.hpp"
+# include "orderAccess_bsd_zero.inline.hpp"
+# include "prefetch_bsd_zero.inline.hpp"
+#endif
+
+// Contains inlined functions for class Thread and ThreadLocalStorage
+
+inline void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do
+
+#endif // OS_BSD_VM_THREAD_BSD_INLINE_HPP
diff --git a/src/os/bsd/vm/vmError_bsd.cpp b/src/os/bsd/vm/vmError_bsd.cpp
new file mode 100644
index 000000000..8ec6ca04c
--- /dev/null
+++ b/src/os/bsd/vm/vmError_bsd.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/vmError.hpp"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <signal.h>
+
+void VMError::show_message_box(char *buf, int buflen) {
+ bool yes;
+ do {
+ error_string(buf, buflen);
+ int len = (int)strlen(buf);
+ char *p = &buf[len];
+
+ jio_snprintf(p, buflen - len,
+ "\n\n"
+ "Do you want to debug the problem?\n\n"
+ "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " INTX_FORMAT " (" INTPTR_FORMAT ")\n"
+ "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n"
+ "Otherwise, press RETURN to abort...",
+ os::current_process_id(), os::current_process_id(),
+ os::current_thread_id(), os::current_thread_id());
+
+ yes = os::message_box("Unexpected Error", buf);
+
+ if (yes) {
+ // yes, user asked VM to launch debugger
+ jio_snprintf(buf, buflen, "gdb /proc/%d/exe %d",
+ os::current_process_id(), os::current_process_id());
+
+ os::fork_and_exec(buf);
+ yes = false;
+ }
+ } while (yes);
+}
+
+// Space for our "saved" signal flags and handlers
+static int resettedSigflags[2];
+static address resettedSighandler[2];
+
+static void save_signal(int idx, int sig)
+{
+ struct sigaction sa;
+ sigaction(sig, NULL, &sa);
+ resettedSigflags[idx] = sa.sa_flags;
+ resettedSighandler[idx] = (sa.sa_flags & SA_SIGINFO)
+ ? CAST_FROM_FN_PTR(address, sa.sa_sigaction)
+ : CAST_FROM_FN_PTR(address, sa.sa_handler);
+}
+
+int VMError::get_resetted_sigflags(int sig) {
+ if(SIGSEGV == sig) {
+ return resettedSigflags[0];
+ } else if(SIGBUS == sig) {
+ return resettedSigflags[1];
+ }
+ return -1;
+}
+
+address VMError::get_resetted_sighandler(int sig) {
+ if(SIGSEGV == sig) {
+ return resettedSighandler[0];
+ } else if(SIGBUS == sig) {
+ return resettedSighandler[1];
+ }
+ return NULL;
+}
+
+static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
+ // unmask current signal
+ sigset_t newset;
+ sigemptyset(&newset);
+ sigaddset(&newset, sig);
+ sigprocmask(SIG_UNBLOCK, &newset, NULL);
+
+ VMError err(NULL, sig, NULL, info, ucVoid);
+ err.report_and_die();
+}
+
+void VMError::reset_signal_handlers() {
+ // Save sigflags for resetted signals
+ save_signal(0, SIGSEGV);
+ save_signal(1, SIGBUS);
+ os::signal(SIGSEGV, CAST_FROM_FN_PTR(void *, crash_handler));
+ os::signal(SIGBUS, CAST_FROM_FN_PTR(void *, crash_handler));
+}
diff --git a/src/os/linux/vm/os_linux.cpp b/src/os/linux/vm/os_linux.cpp
index f1e6f1597..3eab0b267 100644
--- a/src/os/linux/vm/os_linux.cpp
+++ b/src/os/linux/vm/os_linux.cpp
@@ -22,8 +22,6 @@
*
*/
-# define __STDC_FORMAT_MACROS
-
// no precompiled headers
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
diff --git a/src/os/posix/launcher/java_md.c b/src/os/posix/launcher/java_md.c
index 3ee0f20a7..63cee98e3 100644
--- a/src/os/posix/launcher/java_md.c
+++ b/src/os/posix/launcher/java_md.c
@@ -41,14 +41,21 @@
#include "version_comp.h"
#endif
-#ifdef __linux__
+#if defined(__linux__) || defined(_ALLBSD_SOURCE)
#include <pthread.h>
#else
#include <thread.h>
#endif
+#ifdef __APPLE__
+#define JVM_DLL "libjvm.dylib"
+#define JAVA_DLL "libjava.dylib"
+#define LD_LIBRARY_PATH "DYLD_LIBRARY_PATH"
+#else
#define JVM_DLL "libjvm.so"
#define JAVA_DLL "libjava.so"
+#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
+#endif
#ifndef GAMMA /* launcher.make defines ARCH */
/*
@@ -423,10 +430,10 @@ CreateExecutionEnvironment(int *_argcp,
* If not on Solaris, assume only a single LD_LIBRARY_PATH
* variable.
*/
- runpath = getenv("LD_LIBRARY_PATH");
+ runpath = getenv(LD_LIBRARY_PATH);
#endif /* __sun */
-#ifdef __linux
+#if defined(__linux__)
/*
* On linux, if a binary is running as sgid or suid, glibc sets
* LD_LIBRARY_PATH to the empty string for security purposes. (In
@@ -442,6 +449,22 @@ CreateExecutionEnvironment(int *_argcp,
if((getgid() != getegid()) || (getuid() != geteuid()) ) {
return;
}
+#elif defined(_ALLBSD_SOURCE)
+ /*
+ * On BSD, if a binary is running as sgid or suid, libc sets
+ * LD_LIBRARY_PATH to the empty string for security purposes. (In
+ * contrast, on Solaris the LD_LIBRARY_PATH variable for a
+ * privileged binary does not lose its settings; but the dynamic
+ * linker does apply more scrutiny to the path.) The launcher uses
+ * the value of LD_LIBRARY_PATH to prevent an exec loop.
+ * Therefore, if we are running sgid or suid, this function's
+ * setting of LD_LIBRARY_PATH will be ineffective and we should
+ * return from the function now. Getting the right libraries to
+ * be found must be handled through other mechanisms.
+ */
+ if(issetugid()) {
+ return;
+ }
#endif
/* runpath contains current effective LD_LIBRARY_PATH setting */
@@ -450,7 +473,7 @@ CreateExecutionEnvironment(int *_argcp,
new_runpath = JLI_MemAlloc( ((runpath!=NULL)?strlen(runpath):0) +
2*strlen(jrepath) + 2*strlen(arch) +
strlen(jvmpath) + 52);
- newpath = new_runpath + strlen("LD_LIBRARY_PATH=");
+ newpath = new_runpath + strlen(LD_LIBRARY_PATH "=");
/*
@@ -465,7 +488,7 @@ CreateExecutionEnvironment(int *_argcp,
/* jvmpath, ((running != wanted)?((wanted==64)?"/"LIBARCH64NAME:"/.."):""), */
- sprintf(new_runpath, "LD_LIBRARY_PATH="
+ sprintf(new_runpath, LD_LIBRARY_PATH "="
"%s:"
"%s/lib/%s:"
"%s/../lib/%s",
@@ -792,7 +815,7 @@ error:
jboolean
GetApplicationHome(char *buf, jint bufsize)
{
-#ifdef __linux__
+#if defined(__linux__) || defined(_ALLBSD_SOURCE)
char *execname = GetExecname();
if (execname) {
strncpy(buf, execname, bufsize-1);
@@ -1175,7 +1198,7 @@ get_cpuid(uint32_t arg,
#endif /* __sun && i586 */
-#if defined(__linux__) && defined(i586)
+#if (defined(__linux__) || defined(_ALLBSD_SOURCE)) && defined(i586)
/*
* A utility method for asking the CPU about itself.
@@ -1452,6 +1475,39 @@ linux_i586_ServerClassMachine(void) {
#endif /* __linux__ && i586 */
+#if defined(_ALLBSD_SOURCE) && defined(i586)
+
+/* The definition of a server-class machine for bsd-i586 */
+jboolean
+bsd_i586_ServerClassMachine(void) {
+ jboolean result = JNI_FALSE;
+ /* How big is a server class machine? */
+ const unsigned long server_processors = 2UL;
+ const uint64_t server_memory = 2UL * GB;
+ /*
+ * We seem not to get our full complement of memory.
+ * We allow some part (1/8?) of the memory to be "missing",
+ * based on the sizes of DIMMs, and maybe graphics cards.
+ */
+ const uint64_t missing_memory = 256UL * MB;
+ const uint64_t actual_memory = physical_memory();
+
+ /* Is this a server class machine? */
+ if (actual_memory >= (server_memory - missing_memory)) {
+ const unsigned long actual_processors = physical_processors();
+ if (actual_processors >= server_processors) {
+ result = JNI_TRUE;
+ }
+ }
+ if (_launcher_debug) {
+ printf("linux_" LIBARCHNAME "_ServerClassMachine: %s\n",
+ (result == JNI_TRUE ? "true" : "false"));
+ }
+ return result;
+}
+
+#endif /* _ALLBSD_SOURCE && i586 */
+
/* Dispatch to the platform-specific definition of "server-class" */
jboolean
ServerClassMachine(void) {
@@ -1466,6 +1522,8 @@ ServerClassMachine(void) {
result = solaris_i586_ServerClassMachine();
#elif defined(__linux__) && defined(i586)
result = linux_i586_ServerClassMachine();
+#elif defined(_ALLBSD_SOURCE) && defined(i586)
+ result = bsd_i586_ServerClassMachine();
#else
if (_launcher_debug) {
printf("ServerClassMachine: returns default value of %s\n",
@@ -1821,7 +1879,7 @@ jlong_format_specifier() {
int
ContinueInNewThread(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
int rslt;
-#ifdef __linux__
+#if defined(__linux__) || defined(_ALLBSD_SOURCE)
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
diff --git a/src/os/posix/launcher/launcher.script b/src/os/posix/launcher/launcher.script
index 22ed66b9c..21bf44e92 100644
--- a/src/os/posix/launcher/launcher.script
+++ b/src/os/posix/launcher/launcher.script
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.