gettext: update to 0.23.1
[oi-userland.git] / components / runtime / openjdk-24 / patches / restore_os_solaris.patch
blobfe1efc38fa40cf005c6275fe320c0b2400708218
1 diff -urN /tmp/a/attachListener_solaris.cpp b/src/hotspot/os/solaris/attachListener_solaris.cpp
2 --- /tmp/a/attachListener_solaris.cpp 1970-01-01 01:00:00.000000000 +0100
3 +++ b/src/hotspot/os/solaris/attachListener_solaris.cpp 2024-09-16 14:41:33.965885977 +0100
4 @@ -0,0 +1,719 @@
5 +/*
6 + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
7 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 + *
9 + * This code is free software; you can redistribute it and/or modify it
10 + * under the terms of the GNU General Public License version 2 only, as
11 + * published by the Free Software Foundation.
12 + *
13 + * This code is distributed in the hope that it will be useful, but WITHOUT
14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 + * version 2 for more details (a copy is included in the LICENSE file that
17 + * accompanied this code).
18 + *
19 + * You should have received a copy of the GNU General Public License version
20 + * 2 along with this work; if not, write to the Free Software Foundation,
21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 + *
23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
24 + * or visit www.oracle.com if you need additional information or have any
25 + * questions.
26 + *
27 + */
29 +#include "precompiled.hpp"
30 +#include "logging/log.hpp"
31 +#include "runtime/interfaceSupport.inline.hpp"
32 +#include "runtime/os.inline.hpp"
33 +#include "services/attachListener.hpp"
34 +#include "services/dtraceAttacher.hpp"
35 +#include "utilities/vmError.hpp"
37 +#include <door.h>
38 +#include <limits.h>
39 +#include <string.h>
40 +#include <signal.h>
41 +#include <sys/types.h>
42 +#include <sys/socket.h>
43 +#include <sys/stat.h>
45 +// stropts.h uses STR in stream ioctl defines
46 +#undef STR
47 +#include <stropts.h>
48 +#undef STR
49 +#define STR(a) #a
51 +// The attach mechanism on Solaris is implemented using the Doors IPC
52 +// mechanism. The first tool to attempt to attach causes the attach
53 +// listener thread to startup. This thread creates a door that is
54 +// associated with a function that enqueues an operation to the attach
55 +// listener. The door is attached to a file in the file system so that
56 +// client (tools) can locate it. To enqueue an operation to the VM the
57 +// client calls through the door which invokes the enqueue function in
58 +// this process. The credentials of the client are checked and if the
59 +// effective uid matches this process then the operation is enqueued.
60 +// When an operation completes the attach listener is required to send the
61 +// operation result and any result data to the client. In this implementation
62 +// the result is returned via a UNIX domain socket. A pair of connected
63 +// sockets (socketpair) is created in the enqueue function and the file
64 +// descriptor for one of the sockets is returned to the client as the
65 +// return from the door call. The other end is retained in this process.
66 +// When the operation completes the result is sent to the client and
67 +// the socket is closed.
69 +// forward reference
70 +class SolarisAttachOperation;
72 +class SolarisAttachListener: AllStatic {
73 + private:
75 + // the path to which we attach the door file descriptor
76 + static char _door_path[PATH_MAX+1];
77 + static volatile bool _has_door_path;
79 + // door descriptor returned by door_create
80 + static int _door_descriptor;
82 + static bool _atexit_registered;
84 + // mutex to protect operation list
85 + static pthread_mutex_t _mutex;
87 + // semaphore to wakeup listener thread
88 + static sema_t _wakeup;
90 + static pthread_mutex_t* mutex() { return &_mutex; }
91 + static sema_t* wakeup() { return &_wakeup; }
93 + // enqueued operation list
94 + static SolarisAttachOperation* _head;
95 + static SolarisAttachOperation* _tail;
97 + static SolarisAttachOperation* head() { return _head; }
98 + static void set_head(SolarisAttachOperation* head) { _head = head; }
100 + static SolarisAttachOperation* tail() { return _tail; }
101 + static void set_tail(SolarisAttachOperation* tail) { _tail = tail; }
103 + // create the door
104 + static int create_door();
106 + public:
107 + enum {
108 + ATTACH_PROTOCOL_VER = 1 // protocol version
109 + };
110 + enum {
111 + ATTACH_ERROR_BADREQUEST = 100, // error codes
112 + ATTACH_ERROR_BADVERSION = 101,
113 + ATTACH_ERROR_RESOURCE = 102,
114 + ATTACH_ERROR_INTERNAL = 103,
115 + ATTACH_ERROR_DENIED = 104
116 + };
118 + static void set_door_path(char* path) {
119 + if (path == NULL) {
120 + _door_path[0] = '\0';
121 + _has_door_path = false;
122 + } else {
123 + strncpy(_door_path, path, PATH_MAX);
124 + _door_path[PATH_MAX] = '\0';
125 + _has_door_path = true;
129 + static void set_door_descriptor(int dd) { _door_descriptor = dd; }
131 + // initialize the listener, returns 0 if okay
132 + static int init();
134 + static char* door_path() { return _door_path; }
135 + static bool has_door_path() { return _has_door_path; }
136 + static int door_descriptor() { return _door_descriptor; }
138 + // enqueue an operation
139 + static void enqueue(SolarisAttachOperation* op);
141 + // dequeue an operation
142 + static SolarisAttachOperation* dequeue();
146 +// SolarisAttachOperation is an AttachOperation that additionally encapsulates
147 +// a socket connection to the requesting client/tool. SolarisAttachOperation
148 +// can additionally be held in a linked list.
150 +class SolarisAttachOperation: public AttachOperation {
151 + private:
152 + friend class SolarisAttachListener;
154 + // connection to client
155 + int _socket;
157 + // linked list support
158 + SolarisAttachOperation* _next;
160 + SolarisAttachOperation* next() { return _next; }
161 + void set_next(SolarisAttachOperation* next) { _next = next; }
163 + public:
164 + void complete(jint res, bufferedStream* st);
166 + void set_socket(int s) { _socket = s; }
167 + int socket() const { return _socket; }
169 + SolarisAttachOperation(char* name) : AttachOperation(name) {
170 + set_socket(-1);
171 + set_next(NULL);
175 +// statics
176 +char SolarisAttachListener::_door_path[PATH_MAX+1];
177 +volatile bool SolarisAttachListener::_has_door_path;
178 +int SolarisAttachListener::_door_descriptor = -1;
179 +bool SolarisAttachListener::_atexit_registered = false;
180 +pthread_mutex_t SolarisAttachListener::_mutex;
181 +sema_t SolarisAttachListener::_wakeup;
182 +SolarisAttachOperation* SolarisAttachListener::_head = NULL;
183 +SolarisAttachOperation* SolarisAttachListener::_tail = NULL;
185 +// Supporting class to help split a buffer into individual components
186 +class ArgumentIterator : public StackObj {
187 + private:
188 + char* _pos;
189 + char* _end;
190 + public:
191 + ArgumentIterator(char* arg_buffer, size_t arg_size) {
192 + _pos = arg_buffer;
193 + _end = _pos + arg_size - 1;
195 + char* next() {
196 + if (*_pos == '\0') {
197 + // advance the iterator if possible (null arguments)
198 + if (_pos < _end) {
199 + _pos += 1;
201 + return NULL;
203 + char* res = _pos;
204 + char* next_pos = strchr(_pos, '\0');
205 + if (next_pos < _end) {
206 + next_pos++;
208 + _pos = next_pos;
209 + return res;
213 +// Calls from the door function to check that the client credentials
214 +// match this process. Returns 0 if credentials okay, otherwise -1.
215 +static int check_credentials() {
216 + ucred_t *cred_info = NULL;
217 + int ret = -1; // deny by default
219 + // get client credentials
220 + if (door_ucred(&cred_info) == -1) {
221 + return -1; // unable to get them, deny
224 + // get euid/egid from ucred_free
225 + uid_t ucred_euid = ucred_geteuid(cred_info);
226 + gid_t ucred_egid = ucred_getegid(cred_info);
228 + // check that the effective uid/gid matches
229 + if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) {
230 + ret = 0; // allow
233 + ucred_free(cred_info);
234 + return ret;
238 +// Parses the argument buffer to create an AttachOperation that we should
239 +// enqueue to the attach listener.
240 +// The buffer is expected to be formatted as follows:
241 +// <ver>0<cmd>0<arg>0<arg>0<arg>0
242 +// where <ver> is the version number (must be "1"), <cmd> is the command
243 +// name ("load, "datadump", ...) and <arg> is an argument.
245 +static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) {
246 + // assume bad request until parsed
247 + *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST;
249 + if (arg_size < 2 || argp[arg_size-1] != '\0') {
250 + return NULL; // no ver or not null terminated
253 + // Use supporting class to iterate over the buffer
254 + ArgumentIterator args(argp, arg_size);
256 + // First check the protocol version
257 + char* ver = args.next();
258 + if (ver == NULL) {
259 + return NULL;
261 + if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) {
262 + *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION;
263 + return NULL;
266 + // Get command name and create the operation
267 + char* name = args.next();
268 + if (name == NULL || strlen(name) > AttachOperation::name_length_max) {
269 + return NULL;
271 + SolarisAttachOperation* op = new SolarisAttachOperation(name);
273 + // Iterate over the arguments
274 + for (int i=0; i<AttachOperation::arg_count_max; i++) {
275 + char* arg = args.next();
276 + if (arg == NULL) {
277 + op->set_arg(i, NULL);
278 + } else {
279 + if (strlen(arg) > AttachOperation::arg_length_max) {
280 + delete op;
281 + return NULL;
283 + op->set_arg(i, arg);
287 + // return operation
288 + *err = 0;
289 + return op;
292 +// This is door function which the client executes via a door_call.
293 +extern "C" {
294 + static void enqueue_proc(void* cookie, char* argp, size_t arg_size,
295 + door_desc_t* dt, uint_t n_desc)
297 + int return_fd = -1;
298 + SolarisAttachOperation* op = NULL;
300 + // wait up to 10 seconds for listener to be up and running
301 + jint res = 0;
302 + int sleep_count = 0;
303 + while (!AttachListener::is_initialized()) {
304 + sleep(1); // 1 second
305 + sleep_count++;
306 + if (sleep_count > 10) { // try for 10 seconds
307 + debug_only(warning("door_call when not enabled"));
308 + res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL;
309 + break;
313 + // check client credentials
314 + if (res == 0) {
315 + if (check_credentials() != 0) {
316 + res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED;
320 + // if we are stopped at ShowMessageBoxOnError then maybe we can
321 + // load a diagnostic library
322 + if (res == 0 && VMError::is_error_reported()) {
323 + if (ShowMessageBoxOnError) {
324 + // TBD - support loading of diagnostic library here
327 + // can't enqueue operation after fatal error
328 + res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
331 + // create the operation
332 + if (res == 0) {
333 + int err;
334 + op = create_operation(argp, arg_size, &err);
335 + res = (op == NULL) ? (jint)err : 0;
338 + // create a pair of connected sockets. Store the file descriptor
339 + // for one end in the operation and enqueue the operation. The
340 + // file descriptor for the other end will be returned to the client.
341 + if (res == 0) {
342 + int s[2];
343 + if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) {
344 + delete op;
345 + res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
346 + } else {
347 + op->set_socket(s[0]);
348 + return_fd = s[1];
349 + SolarisAttachListener::enqueue(op);
353 + // Return 0 (success) + file descriptor, or non-0 (error)
354 + if (res == 0) {
355 + door_desc_t desc;
356 + // DOOR_RELEASE flag makes sure fd is closed after passing it to
357 + // the client. See door_return(3DOOR) man page.
358 + desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
359 + desc.d_data.d_desc.d_descriptor = return_fd;
360 + door_return((char*)&res, sizeof(res), &desc, 1);
361 + } else {
362 + door_return((char*)&res, sizeof(res), NULL, 0);
367 +// atexit hook to detach the door and remove the file
368 +extern "C" {
369 + static void listener_cleanup() {
370 + int dd = SolarisAttachListener::door_descriptor();
371 + if (dd >= 0) {
372 + SolarisAttachListener::set_door_descriptor(-1);
373 + ::close(dd);
375 + if (SolarisAttachListener::has_door_path()) {
376 + char* path = SolarisAttachListener::door_path();
377 + ::fdetach(path);
378 + ::unlink(path);
379 + SolarisAttachListener::set_door_path(NULL);
384 +// Create the door
385 +int SolarisAttachListener::create_door() {
386 + char door_path[PATH_MAX];
387 + char initial_path[PATH_MAX];
388 + int fd, res;
390 + // register function to cleanup
391 + if (!_atexit_registered) {
392 + _atexit_registered = true;
393 + ::atexit(listener_cleanup);
396 + // create the door descriptor
397 + int dd = ::door_create(enqueue_proc, NULL, 0);
398 + if (dd < 0) {
399 + return -1;
402 + int n = snprintf(door_path, PATH_MAX, "%s/.java_pid%d",
403 + os::get_temp_directory(), os::current_process_id());
404 + if (n < (int)PATH_MAX) {
405 + snprintf(initial_path, PATH_MAX, "%s.tmp", door_path);
407 + if (n >= (int)PATH_MAX) {
408 + return -1;
410 + RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
411 + if (fd == -1) {
412 + log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno);
413 + ::door_revoke(dd);
414 + return -1;
416 + assert(fd >= 0, "bad file descriptor");
417 + ::close(fd);
419 + // attach the door descriptor to the file
420 + if ((res = ::fattach(dd, initial_path)) == -1) {
421 + // if busy then detach and try again
422 + if (errno == EBUSY) {
423 + ::fdetach(initial_path);
424 + res = ::fattach(dd, initial_path);
426 + if (res == -1) {
427 + log_debug(attach)("unable to create door - fattach failed (%d)", errno);
428 + ::door_revoke(dd);
429 + dd = -1;
433 + // rename file so that clients can attach
434 + if (dd >= 0) {
435 + if (::rename(initial_path, door_path) == -1) {
436 + ::close(dd);
437 + ::fdetach(initial_path);
438 + log_debug(attach)("unable to create door - rename %s to %s failed (%d)", initial_path, door_path, errno);
439 + dd = -1;
442 + if (dd >= 0) {
443 + set_door_descriptor(dd);
444 + set_door_path(door_path);
445 + log_trace(attach)("door file %s created successfully", door_path);
446 + } else {
447 + // unable to create door, attach it to file, or rename file into place
448 + ::unlink(initial_path);
449 + return -1;
452 + return 0;
455 +// Initialization - create the door, locks, and other initialization
456 +int SolarisAttachListener::init() {
457 + if (create_door()) {
458 + return -1;
461 + int status = pthread_mutex_init(&_mutex, NULL);
462 + assert_status(status==0, status, "mutex_init");
464 + status = ::sema_init(&_wakeup, 0, NULL, NULL);
465 + assert_status(status==0, status, "sema_init");
467 + set_head(NULL);
468 + set_tail(NULL);
470 + return 0;
473 +// Dequeue an operation
474 +SolarisAttachOperation* SolarisAttachListener::dequeue() {
475 + for (;;) {
476 + int res;
478 + // wait for somebody to enqueue something
479 + while ((res = ::sema_wait(wakeup())) == EINTR)
481 + if (res) {
482 + warning("sema_wait failed: %s", os::strerror(res));
483 + return NULL;
486 + // lock the list
487 + res = pthread_mutex_lock(mutex());
488 + assert(res == 0, "mutex_lock failed");
490 + // remove the head of the list
491 + SolarisAttachOperation* op = head();
492 + if (op != NULL) {
493 + set_head(op->next());
494 + if (head() == NULL) {
495 + set_tail(NULL);
499 + // unlock
500 + pthread_mutex_unlock(mutex());
502 + // if we got an operation when return it.
503 + if (op != NULL) {
504 + return op;
509 +// Enqueue an operation
510 +void SolarisAttachListener::enqueue(SolarisAttachOperation* op) {
511 + // lock list
512 + int res = pthread_mutex_lock(mutex());
513 + assert(res == 0, "mutex_lock failed");
515 + // enqueue at tail
516 + op->set_next(NULL);
517 + if (head() == NULL) {
518 + set_head(op);
519 + } else {
520 + tail()->set_next(op);
522 + set_tail(op);
524 + // wakeup the attach listener
525 + RESTARTABLE(::sema_post(wakeup()), res);
526 + assert(res == 0, "sema_post failed");
528 + // unlock
529 + pthread_mutex_unlock(mutex());
533 +// support function - writes the (entire) buffer to a socket
534 +static int write_fully(int s, char* buf, int len) {
535 + do {
536 + int n = ::write(s, buf, len);
537 + if (n == -1) {
538 + if (errno != EINTR) return -1;
539 + } else {
540 + buf += n;
541 + len -= n;
544 + while (len > 0);
545 + return 0;
548 +// Complete an operation by sending the operation result and any result
549 +// output to the client. At this time the socket is in blocking mode so
550 +// potentially we can block if there is a lot of data and the client is
551 +// non-responsive. For most operations this is a non-issue because the
552 +// default send buffer is sufficient to buffer everything. In the future
553 +// if there are operations that involves a very big reply then it the
554 +// socket could be made non-blocking and a timeout could be used.
556 +void SolarisAttachOperation::complete(jint res, bufferedStream* st) {
557 + if (this->socket() >= 0) {
558 + JavaThread* thread = JavaThread::current();
559 + ThreadBlockInVM tbivm(thread);
561 + // write operation result
562 + char msg[32];
563 + sprintf(msg, "%d\n", res);
564 + int rc = write_fully(this->socket(), msg, strlen(msg));
566 + // write any result data
567 + if (rc == 0) {
568 + write_fully(this->socket(), (char*) st->base(), st->size());
569 + ::shutdown(this->socket(), 2);
572 + // done
573 + ::close(this->socket());
575 + delete this;
579 +// AttachListener functions
581 +AttachOperation* AttachListener::dequeue() {
582 + JavaThread* thread = JavaThread::current();
583 + ThreadBlockInVM tbivm(thread);
585 + AttachOperation* op = SolarisAttachListener::dequeue();
587 + return op;
591 +// Performs initialization at vm startup
592 +// For Solaris we remove any stale .java_pid file which could cause
593 +// an attaching process to think we are ready to receive a door_call
594 +// before we are properly initialized
596 +void AttachListener::vm_start() {
597 + char fn[PATH_MAX+1];
598 + struct stat64 st;
599 + int ret;
601 + int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d",
602 + os::get_temp_directory(), os::current_process_id());
603 + assert(n < sizeof(fn), "java_pid file name buffer overflow");
605 + RESTARTABLE(::stat64(fn, &st), ret);
606 + if (ret == 0) {
607 + ret = ::unlink(fn);
608 + if (ret == -1) {
609 + log_debug(attach)("Failed to remove stale attach pid file at %s", fn);
614 +int AttachListener::pd_init() {
615 + JavaThread* thread = JavaThread::current();
616 + ThreadBlockInVM tbivm(thread);
618 + int ret_code = SolarisAttachListener::init();
620 + return ret_code;
623 +bool AttachListener::check_socket_file() {
624 + int ret;
625 + struct stat64 st;
626 + ret = stat64(SolarisAttachListener::door_path(), &st);
627 + if (ret == -1) { // need to restart attach listener.
628 + log_debug(attach)("Door file %s does not exist - Restart Attach Listener",
629 + SolarisAttachListener::door_path());
631 + listener_cleanup();
633 + // wait to terminate current attach listener instance...
634 + while (AttachListener::transit_state(AL_INITIALIZING,
635 + AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
636 + os::naked_yield();
638 + return is_init_trigger();
640 + return false;
643 +// Attach Listener is started lazily except in the case when
644 +// +ReduseSignalUsage is used
645 +bool AttachListener::init_at_startup() {
646 + if (ReduceSignalUsage) {
647 + return true;
648 + } else {
649 + return false;
653 +// If the file .attach_pid<pid> exists in the working directory
654 +// or /tmp then this is the trigger to start the attach mechanism
655 +bool AttachListener::is_init_trigger() {
656 + if (init_at_startup() || is_initialized()) {
657 + return false; // initialized at startup or already initialized
659 + char fn[PATH_MAX + 1];
660 + int ret;
661 + struct stat64 st;
662 + sprintf(fn, ".attach_pid%d", os::current_process_id());
663 + RESTARTABLE(::stat64(fn, &st), ret);
664 + if (ret == -1) {
665 + log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
666 + snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
667 + os::get_temp_directory(), os::current_process_id());
668 + RESTARTABLE(::stat64(fn, &st), ret);
669 + if (ret == -1) {
670 + log_debug(attach)("Failed to find attach file: %s", fn);
673 + if (ret == 0) {
674 + // simple check to avoid starting the attach mechanism when
675 + // a bogus non-root user creates the file
676 + if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
677 + init();
678 + log_trace(attach)("Attach triggered by %s", fn);
679 + return true;
680 + } else {
681 + log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
684 + return false;
687 +// if VM aborts then remove listener
688 +void AttachListener::abort() {
689 + listener_cleanup();
692 +void AttachListener::pd_data_dump() {
693 + os::signal_notify(SIGQUIT);
696 +static jint enable_dprobes(AttachOperation* op, outputStream* out) {
697 + const char* probe = op->arg(0);
698 + if (probe == NULL || probe[0] == '\0') {
699 + out->print_cr("No probe specified");
700 + return JNI_ERR;
701 + } else {
702 + char *end;
703 + long val = strtol(probe, &end, 10);
704 + if (end == probe || val < 0 || val > INT_MAX) {
705 + out->print_cr("invalid probe type");
706 + return JNI_ERR;
707 + } else {
708 + int probe_typess = (int) val;
709 + DTrace::enable_dprobes(probe_typess);
710 + return JNI_OK;
715 +// platform specific operations table
716 +static AttachOperationFunctionInfo funcs[] = {
717 + { "enabledprobes", enable_dprobes },
718 + { NULL, NULL }
721 +void AttachListener::pd_detachall() {
722 + DTrace::detach_all_clients();
724 diff -urN /tmp/a/c1_globals_solaris.hpp b/src/hotspot/os/solaris/c1_globals_solaris.hpp
725 --- /tmp/a/c1_globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100
726 +++ b/src/hotspot/os/solaris/c1_globals_solaris.hpp 2024-09-16 14:41:33.965962792 +0100
727 @@ -0,0 +1,36 @@
729 + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
730 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
732 + * This code is free software; you can redistribute it and/or modify it
733 + * under the terms of the GNU General Public License version 2 only, as
734 + * published by the Free Software Foundation.
736 + * This code is distributed in the hope that it will be useful, but WITHOUT
737 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
738 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
739 + * version 2 for more details (a copy is included in the LICENSE file that
740 + * accompanied this code).
742 + * You should have received a copy of the GNU General Public License version
743 + * 2 along with this work; if not, write to the Free Software Foundation,
744 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
746 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
747 + * or visit www.oracle.com if you need additional information or have any
748 + * questions.
750 + */
752 +#ifndef OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
753 +#define OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
755 +#include "utilities/globalDefinitions.hpp"
756 +#include "utilities/macros.hpp"
759 +// Sets the default values for operating system dependent flags used by the
760 +// client compiler. (see c1_globals.hpp)
763 +#endif // OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
764 diff -urN /tmp/a/c2_globals_solaris.hpp b/src/hotspot/os/solaris/c2_globals_solaris.hpp
765 --- /tmp/a/c2_globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100
766 +++ b/src/hotspot/os/solaris/c2_globals_solaris.hpp 2024-09-16 14:41:33.966036351 +0100
767 @@ -0,0 +1,36 @@
769 + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
770 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
772 + * This code is free software; you can redistribute it and/or modify it
773 + * under the terms of the GNU General Public License version 2 only, as
774 + * published by the Free Software Foundation.
776 + * This code is distributed in the hope that it will be useful, but WITHOUT
777 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
778 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
779 + * version 2 for more details (a copy is included in the LICENSE file that
780 + * accompanied this code).
782 + * You should have received a copy of the GNU General Public License version
783 + * 2 along with this work; if not, write to the Free Software Foundation,
784 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
786 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
787 + * or visit www.oracle.com if you need additional information or have any
788 + * questions.
790 + */
792 +#ifndef OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
793 +#define OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
795 +#include "utilities/globalDefinitions.hpp"
796 +#include "utilities/macros.hpp"
799 +// Sets the default values for operating system dependent flags used by the
800 +// server compiler. (see c2_globals.hpp)
803 +#endif // OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
804 diff -urN /tmp/a/decoder_solaris.cpp b/src/hotspot/os/solaris/decoder_solaris.cpp
805 --- /tmp/a/decoder_solaris.cpp 1970-01-01 01:00:00.000000000 +0100
806 +++ b/src/hotspot/os/solaris/decoder_solaris.cpp 2024-09-16 14:41:33.989898931 +0100
807 @@ -0,0 +1,45 @@
809 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
810 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
812 + * This code is free software; you can redistribute it and/or modify it
813 + * under the terms of the GNU General Public License version 2 only, as
814 + * published by the Free Software Foundation.
816 + * This code is distributed in the hope that it will be useful, but WITHOUT
817 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
818 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
819 + * version 2 for more details (a copy is included in the LICENSE file that
820 + * accompanied this code).
822 + * You should have received a copy of the GNU General Public License version
823 + * 2 along with this work; if not, write to the Free Software Foundation,
824 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
826 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
827 + * or visit www.oracle.com if you need additional information or have any
828 + * questions.
830 + */
832 +#include "jvm.h"
833 +#include "utilities/decoder_elf.hpp"
835 +#include <cxxabi.h>
837 +bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) {
838 + int status;
839 + char* result;
840 + size_t size = (size_t)buflen;
841 + // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small,
842 + // __cxa_demangle will call system "realloc" for additional memory, which
843 + // may use different malloc/realloc mechanism that allocates 'buf'.
844 + if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) {
845 + jio_snprintf(buf, buflen, "%s", result);
846 + // call c library's free
847 + ::free(result);
848 + return true;
850 + return false;
853 diff -urN /tmp/a/dtrace/jhelper.d b/src/hotspot/os/solaris/dtrace/jhelper.d
854 --- /tmp/a/dtrace/jhelper.d 1970-01-01 01:00:00.000000000 +0100
855 +++ b/src/hotspot/os/solaris/dtrace/jhelper.d 2024-09-16 14:41:33.966540246 +0100
856 @@ -0,0 +1,540 @@
858 + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
859 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
861 + * This code is free software; you can redistribute it and/or modify it
862 + * under the terms of the GNU General Public License version 2 only, as
863 + * published by the Free Software Foundation.
865 + * This code is distributed in the hope that it will be useful, but WITHOUT
866 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
867 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
868 + * version 2 for more details (a copy is included in the LICENSE file that
869 + * accompanied this code).
871 + * You should have received a copy of the GNU General Public License version
872 + * 2 along with this work; if not, write to the Free Software Foundation,
873 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
875 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
876 + * or visit www.oracle.com if you need additional information or have any
877 + * questions.
879 + */
881 +/* This file is auto-generated */
882 +#include "JvmOffsetsIndex.h"
884 +#define DEBUG
886 +#ifdef DEBUG
887 +#define MARK_LINE this->line = __LINE__
888 +#else
889 +#define MARK_LINE
890 +#endif
892 +#ifdef _LP64
893 +#define STACK_BIAS 0x7ff
894 +#define pointer uint64_t
895 +#else
896 +#define STACK_BIAS 0
897 +#define pointer uint32_t
898 +#endif
900 +extern pointer __JvmOffsets;
902 +/* GrowableArray<CodeHeaps*>* */
903 +extern pointer __1cJCodeCacheG_heaps_;
905 +extern pointer __1cIUniverseO_collectedHeap_;
907 +extern pointer __1cHnmethodG__vtbl_;
908 +extern pointer __1cGMethodG__vtbl_;
909 +extern pointer __1cKBufferBlobG__vtbl_;
911 +#define copyin_ptr(ADDR) *(pointer*) copyin((pointer) (ADDR), sizeof(pointer))
912 +#define copyin_uchar(ADDR) *(uchar_t*) copyin((pointer) (ADDR), sizeof(uchar_t))
913 +#define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t))
914 +#define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t))
915 +#define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t))
916 +#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t))
918 +#define copyin_offset(JVM_CONST) JVM_CONST = \
919 + copyin_int32(JvmOffsetsPtr + IDX_##JVM_CONST * sizeof(int32_t))
921 +int init_done;
923 +dtrace:helper:ustack:
925 + MARK_LINE;
926 + this->done = 0;
927 + /*
928 + * TBD:
929 + * Here we initialize init_done, otherwise jhelper does not work.
930 + * Therefore, copyin_offset() statements work multiple times now.
931 + * There is a hope we could avoid it in the future, and so,
932 + * this initialization can be removed.
933 + */
934 + init_done = 0;
935 + this->error = (char *) NULL;
936 + this->result = (char *) NULL;
937 + this->isMethod = 0;
938 + this->codecache = 0;
939 + this->klass = (pointer) NULL;
940 + this->vtbl = (pointer) NULL;
941 + this->suffix = '\0';
944 +dtrace:helper:ustack:
946 + MARK_LINE;
947 + /* Initialization of JvmOffsets constants */
948 + JvmOffsetsPtr = (pointer) &``__JvmOffsets;
951 +dtrace:helper:ustack:
952 +/!init_done && !this->done/
954 + MARK_LINE;
956 + copyin_offset(POINTER_SIZE);
957 + copyin_offset(COMPILER);
958 + copyin_offset(OFFSET_CollectedHeap_reserved);
959 + copyin_offset(OFFSET_MemRegion_start);
960 + copyin_offset(OFFSET_MemRegion_word_size);
961 + copyin_offset(SIZE_HeapWord);
963 + copyin_offset(OFFSET_interpreter_frame_method);
964 + copyin_offset(OFFSET_Klass_name);
965 + copyin_offset(OFFSET_ConstantPool_pool_holder);
967 + copyin_offset(OFFSET_HeapBlockHeader_used);
968 + copyin_offset(OFFSET_oopDesc_metadata);
970 + copyin_offset(OFFSET_Symbol_length);
971 + copyin_offset(OFFSET_Symbol_body);
973 + copyin_offset(OFFSET_Method_constMethod);
974 + copyin_offset(OFFSET_ConstMethod_constants);
975 + copyin_offset(OFFSET_ConstMethod_name_index);
976 + copyin_offset(OFFSET_ConstMethod_signature_index);
978 + copyin_offset(OFFSET_CodeHeap_memory);
979 + copyin_offset(OFFSET_CodeHeap_segmap);
980 + copyin_offset(OFFSET_CodeHeap_log2_segment_size);
982 + copyin_offset(OFFSET_GrowableArray_CodeHeap_data);
983 + copyin_offset(OFFSET_GrowableArray_CodeHeap_len);
985 + copyin_offset(OFFSET_VirtualSpace_low);
986 + copyin_offset(OFFSET_VirtualSpace_high);
988 + copyin_offset(OFFSET_CodeBlob_name);
990 + copyin_offset(OFFSET_nmethod_method);
991 + copyin_offset(SIZE_HeapBlockHeader);
992 + copyin_offset(SIZE_oopDesc);
993 + copyin_offset(SIZE_ConstantPool);
995 + copyin_offset(OFFSET_NarrowPtrStruct_base);
996 + copyin_offset(OFFSET_NarrowPtrStruct_shift);
998 + /*
999 + * The PC to translate is in arg0.
1000 + */
1001 + this->pc = arg0;
1003 +#if defined(__i386) || defined(__amd64)
1004 + this->methodPtr = copyin_ptr(arg1 + OFFSET_interpreter_frame_method);
1005 +#else
1006 +#error "Don't know architecture"
1007 +#endif
1009 + /* Read address of GrowableArray<CodeHeaps*> */
1010 + // this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_);
1011 + this->code_heaps_address = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cJCodeCacheG_heaps_ ) , sizeof ( uint64_t ) );
1013 + /* Read address of _data array field in GrowableArray */
1014 + this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data);
1015 + this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len);
1017 + this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_;
1019 + /*
1020 + * Get Java heap bounds
1021 + */
1022 + // this->Universe_collectedHeap = copyin_ptr(&``__1cIUniverseO_collectedHeap_);
1023 + this->Universe_collectedHeap = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cIUniverseO_collectedHeap_ ) , sizeof ( uint64_t ) );
1025 + this->heap_start = copyin_ptr(this->Universe_collectedHeap +
1026 + OFFSET_CollectedHeap_reserved +
1027 + OFFSET_MemRegion_start);
1028 + this->heap_size = SIZE_HeapWord *
1029 + copyin_ptr(this->Universe_collectedHeap +
1030 + OFFSET_CollectedHeap_reserved +
1031 + OFFSET_MemRegion_word_size
1032 + );
1033 + this->heap_end = this->heap_start + this->heap_size;
1037 + * IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in
1038 + * the code cache. If more code heaps are added the following probes have to
1039 + * be extended. This is done by simply adding a probe to get the heap bounds
1040 + * and another probe to set the code heap address of the newly created heap.
1041 + */
1044 + * ----- BEGIN: Get bounds of code heaps -----
1045 + */
1046 +dtrace:helper:ustack:
1047 +/init_done < 1 && this->number_of_heaps >= 1 && !this->done/
1049 + MARK_LINE;
1050 + /* CodeHeap 1 */
1051 + init_done = 1;
1052 + this->code_heap1_address = copyin_ptr(this->code_heaps_array_address);
1053 + this->code_heap1_low = copyin_ptr(this->code_heap1_address +
1054 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
1055 + this->code_heap1_high = copyin_ptr(this->code_heap1_address +
1056 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
1059 +dtrace:helper:ustack:
1060 +/init_done < 2 && this->number_of_heaps >= 2 && !this->done/
1062 + MARK_LINE;
1063 + /* CodeHeap 2 */
1064 + init_done = 2;
1065 + this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
1066 + this->code_heap2_address = copyin_ptr(this->code_heaps_array_address);
1067 + this->code_heap2_low = copyin_ptr(this->code_heap2_address +
1068 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
1069 + this->code_heap2_high = copyin_ptr(this->code_heap2_address +
1070 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
1073 +dtrace:helper:ustack:
1074 +/init_done < 3 && this->number_of_heaps >= 3 && !this->done/
1076 + /* CodeHeap 3 */
1077 + init_done = 3;
1078 + this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
1079 + this->code_heap3_address = copyin_ptr(this->code_heaps_array_address);
1080 + this->code_heap3_low = copyin_ptr(this->code_heap3_address +
1081 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
1082 + this->code_heap3_high = copyin_ptr(this->code_heap3_address +
1083 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
1086 +dtrace:helper:ustack:
1087 +/init_done < 4 && this->number_of_heaps >= 4 && !this->done/
1089 + /* CodeHeap 4 */
1090 + init_done = 4;
1091 + this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
1092 + this->code_heap4_address = copyin_ptr(this->code_heaps_array_address);
1093 + this->code_heap4_low = copyin_ptr(this->code_heap4_address +
1094 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
1095 + this->code_heap4_high = copyin_ptr(this->code_heap4_address +
1096 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
1099 +dtrace:helper:ustack:
1100 +/init_done < 5 && this->number_of_heaps >= 5 && !this->done/
1102 + /* CodeHeap 5 */
1103 + init_done = 5;
1104 + this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
1105 + this->code_heap5_address = copyin_ptr(this->code_heaps_array_address);
1106 + this->code_heap5_low = copyin_ptr(this->code_heap5_address +
1107 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
1108 + this->code_heap5_high = copyin_ptr(this->code_heap5_address +
1109 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
1112 + * ----- END: Get bounds of code heaps -----
1113 + */
1116 + * ----- BEGIN: Get address of the code heap pc points to -----
1117 + */
1118 +dtrace:helper:ustack:
1119 +/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/
1121 + MARK_LINE;
1122 + this->codecache = 1;
1123 + this->code_heap_address = this->code_heap1_address;
1126 +dtrace:helper:ustack:
1127 +/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/
1129 + MARK_LINE;
1130 + this->codecache = 1;
1131 + this->code_heap_address = this->code_heap2_address;
1134 +dtrace:helper:ustack:
1135 +/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/
1137 + MARK_LINE;
1138 + this->codecache = 1;
1139 + this->code_heap_address = this->code_heap3_address;
1142 +dtrace:helper:ustack:
1143 +/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/
1145 + MARK_LINE;
1146 + this->codecache = 1;
1147 + this->code_heap_address = this->code_heap4_address;
1150 +dtrace:helper:ustack:
1151 +/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/
1153 + MARK_LINE;
1154 + this->codecache = 1;
1155 + this->code_heap_address = this->code_heap5_address;
1158 + * ----- END: Get address of the code heap pc points to -----
1159 + */
1161 +dtrace:helper:ustack:
1162 +/!this->done && this->codecache/
1164 + MARK_LINE;
1165 + /*
1166 + * Get code heap configuration
1167 + */
1168 + this->code_heap_low = copyin_ptr(this->code_heap_address +
1169 + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
1170 + this->code_heap_segmap_low = copyin_ptr(this->code_heap_address +
1171 + OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
1172 + this->code_heap_log2_segment_size = copyin_uint32(
1173 + this->code_heap_address + OFFSET_CodeHeap_log2_segment_size);
1175 + /*
1176 + * Find start
1177 + */
1178 + this->segment = (this->pc - this->code_heap_low) >>
1179 + this->code_heap_log2_segment_size;
1180 + this->block = this->code_heap_segmap_low;
1181 + this->tag = copyin_uchar(this->block + this->segment);
1184 +dtrace:helper:ustack:
1185 +/!this->done && this->codecache && this->tag > 0/
1187 + MARK_LINE;
1188 + this->tag = copyin_uchar(this->block + this->segment);
1189 + this->segment = this->segment - this->tag;
1192 +dtrace:helper:ustack:
1193 +/!this->done && this->codecache && this->tag > 0/
1195 + MARK_LINE;
1196 + this->tag = copyin_uchar(this->block + this->segment);
1197 + this->segment = this->segment - this->tag;
1200 +dtrace:helper:ustack:
1201 +/!this->done && this->codecache && this->tag > 0/
1203 + MARK_LINE;
1204 + this->tag = copyin_uchar(this->block + this->segment);
1205 + this->segment = this->segment - this->tag;
1208 +dtrace:helper:ustack:
1209 +/!this->done && this->codecache && this->tag > 0/
1211 + MARK_LINE;
1212 + this->tag = copyin_uchar(this->block + this->segment);
1213 + this->segment = this->segment - this->tag;
1216 +dtrace:helper:ustack:
1217 +/!this->done && this->codecache && this->tag > 0/
1219 + MARK_LINE;
1220 + this->tag = copyin_uchar(this->block + this->segment);
1221 + this->segment = this->segment - this->tag;
1224 +dtrace:helper:ustack:
1225 +/!this->done && this->codecache && this->tag > 0/
1227 + MARK_LINE;
1228 + this->error = "<couldn't find start>";
1229 + this->done = 1;
1232 +dtrace:helper:ustack:
1233 +/!this->done && this->codecache/
1235 + MARK_LINE;
1236 + this->block = this->code_heap_low +
1237 + (this->segment << this->code_heap_log2_segment_size);
1238 + this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
1241 +dtrace:helper:ustack:
1242 +/!this->done && this->codecache && !this->used/
1244 + MARK_LINE;
1245 + this->error = "<block not in use>";
1246 + this->done = 1;
1249 +dtrace:helper:ustack:
1250 +/!this->done && this->codecache/
1252 + MARK_LINE;
1253 + this->start = this->block + SIZE_HeapBlockHeader;
1254 + this->vtbl = copyin_ptr(this->start);
1256 + this->nmethod_vtbl = (pointer) &``__1cHnmethodG__vtbl_;
1257 + this->BufferBlob_vtbl = (pointer) &``__1cKBufferBlobG__vtbl_;
1260 +dtrace:helper:ustack:
1261 +/!this->done && this->vtbl == this->nmethod_vtbl/
1263 + MARK_LINE;
1264 + this->methodPtr = copyin_ptr(this->start + OFFSET_nmethod_method);
1265 + this->suffix = '*';
1266 + this->isMethod = 1;
1269 +dtrace:helper:ustack:
1270 +/!this->done && this->vtbl == this->BufferBlob_vtbl/
1272 + MARK_LINE;
1273 + this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name);
1277 +dtrace:helper:ustack:
1278 +/!this->done && this->vtbl == this->BufferBlob_vtbl && this->methodPtr != 0/
1280 + MARK_LINE;
1281 + this->klass = copyin_ptr(this->methodPtr);
1282 + this->isMethod = this->klass == this->Method_vtbl;
1283 + this->done = !this->isMethod;
1286 +dtrace:helper:ustack:
1287 +/!this->done && !this->isMethod/
1289 + MARK_LINE;
1290 + this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name);
1291 + this->result = this->name != 0 ? copyinstr(this->name) : "<CodeBlob>";
1292 + this->done = 1;
1295 +dtrace:helper:ustack:
1296 +/!this->done && this->isMethod/
1298 + MARK_LINE;
1299 + this->constMethod = copyin_ptr(this->methodPtr +
1300 + OFFSET_Method_constMethod);
1302 + this->nameIndex = copyin_uint16(this->constMethod +
1303 + OFFSET_ConstMethod_name_index);
1305 + this->signatureIndex = copyin_uint16(this->constMethod +
1306 + OFFSET_ConstMethod_signature_index);
1308 + this->constantPool = copyin_ptr(this->constMethod +
1309 + OFFSET_ConstMethod_constants);
1311 + this->nameSymbol = copyin_ptr(this->constantPool +
1312 + this->nameIndex * sizeof (pointer) + SIZE_ConstantPool);
1313 + /* The symbol is a CPSlot and has lower bit set to indicate metadata */
1314 + this->nameSymbol &= (~1); /* remove metadata lsb */
1316 + this->nameSymbolLength = copyin_uint16(this->nameSymbol +
1317 + OFFSET_Symbol_length);
1319 + this->signatureSymbol = copyin_ptr(this->constantPool +
1320 + this->signatureIndex * sizeof (pointer) + SIZE_ConstantPool);
1321 + this->signatureSymbol &= (~1); /* remove metadata lsb */
1323 + this->signatureSymbolLength = copyin_uint16(this->signatureSymbol +
1324 + OFFSET_Symbol_length);
1326 + this->klassPtr = copyin_ptr(this->constantPool +
1327 + OFFSET_ConstantPool_pool_holder);
1329 + this->klassSymbol = copyin_ptr(this->klassPtr +
1330 + OFFSET_Klass_name);
1332 + this->klassSymbolLength = copyin_uint16(this->klassSymbol +
1333 + OFFSET_Symbol_length);
1335 + /*
1336 + * Enough for three strings, plus the '.', plus the trailing '\0'.
1337 + */
1338 + this->result = (char *) alloca(this->klassSymbolLength +
1339 + this->nameSymbolLength +
1340 + this->signatureSymbolLength + 2 + 1);
1342 + copyinto(this->klassSymbol + OFFSET_Symbol_body,
1343 + this->klassSymbolLength, this->result);
1345 + /*
1346 + * Add the '.' between the class and the name.
1347 + */
1348 + this->result[this->klassSymbolLength] = '.';
1350 + copyinto(this->nameSymbol + OFFSET_Symbol_body,
1351 + this->nameSymbolLength,
1352 + this->result + this->klassSymbolLength + 1);
1354 + copyinto(this->signatureSymbol + OFFSET_Symbol_body,
1355 + this->signatureSymbolLength,
1356 + this->result + this->klassSymbolLength +
1357 + this->nameSymbolLength + 1);
1359 + /*
1360 + * Now we need to add a trailing '\0' and possibly a tag character.
1361 + */
1362 + this->result[this->klassSymbolLength + 1 +
1363 + this->nameSymbolLength +
1364 + this->signatureSymbolLength] = this->suffix;
1365 + this->result[this->klassSymbolLength + 2 +
1366 + this->nameSymbolLength +
1367 + this->signatureSymbolLength] = '\0';
1369 + this->done = 1;
1372 +dtrace:helper:ustack:
1373 +/this->done && this->error == (char *) NULL/
1375 + this->result;
1378 +dtrace:helper:ustack:
1379 +/this->done && this->error != (char *) NULL/
1381 + this->error;
1384 +dtrace:helper:ustack:
1385 +/!this->done && this->codecache/
1387 + this->done = 1;
1388 + "error";
1392 +dtrace:helper:ustack:
1393 +/!this->done/
1395 + NULL;
1397 diff -urN /tmp/a/globals_solaris.hpp b/src/hotspot/os/solaris/globals_solaris.hpp
1398 --- /tmp/a/globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100
1399 +++ b/src/hotspot/os/solaris/globals_solaris.hpp 2024-09-16 14:41:33.966625738 +0100
1400 @@ -0,0 +1,48 @@
1402 + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
1403 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1405 + * This code is free software; you can redistribute it and/or modify it
1406 + * under the terms of the GNU General Public License version 2 only, as
1407 + * published by the Free Software Foundation.
1409 + * This code is distributed in the hope that it will be useful, but WITHOUT
1410 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1411 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1412 + * version 2 for more details (a copy is included in the LICENSE file that
1413 + * accompanied this code).
1415 + * You should have received a copy of the GNU General Public License version
1416 + * 2 along with this work; if not, write to the Free Software Foundation,
1417 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1419 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1420 + * or visit www.oracle.com if you need additional information or have any
1421 + * questions.
1423 + */
1425 +#ifndef OS_SOLARIS_GLOBALS_SOLARIS_HPP
1426 +#define OS_SOLARIS_GLOBALS_SOLARIS_HPP
1429 +// Defines Solaris specific flags. They are not available on other platforms.
1431 +#define RUNTIME_OS_FLAGS(develop, \
1432 + develop_pd, \
1433 + product, \
1434 + product_pd, \
1435 + range, \
1436 + constraint)
1439 +// Defines Solaris-specific default values. The flags are available on all
1440 +// platforms, but they may have different default values on other platforms.
1442 +define_pd_global(size_t, PreTouchParallelChunkSize, 1 * G);
1443 +define_pd_global(bool, UseLargePages, true);
1444 +define_pd_global(bool, UseLargePagesIndividualAllocation, false);
1445 +define_pd_global(bool, UseOSErrorReporting, false);
1446 +define_pd_global(bool, UseThreadPriorities, false);
1448 +#endif // OS_SOLARIS_GLOBALS_SOLARIS_HPP
1449 diff -urN /tmp/a/osThread_solaris.cpp b/src/hotspot/os/solaris/osThread_solaris.cpp
1450 --- /tmp/a/osThread_solaris.cpp 1970-01-01 01:00:00.000000000 +0100
1451 +++ b/src/hotspot/os/solaris/osThread_solaris.cpp 2024-09-16 14:41:33.966705744 +0100
1452 @@ -0,0 +1,46 @@
1454 + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
1455 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1457 + * This code is free software; you can redistribute it and/or modify it
1458 + * under the terms of the GNU General Public License version 2 only, as
1459 + * published by the Free Software Foundation.
1461 + * This code is distributed in the hope that it will be useful, but WITHOUT
1462 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1463 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1464 + * version 2 for more details (a copy is included in the LICENSE file that
1465 + * accompanied this code).
1467 + * You should have received a copy of the GNU General Public License version
1468 + * 2 along with this work; if not, write to the Free Software Foundation,
1469 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1471 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472 + * or visit www.oracle.com if you need additional information or have any
1473 + * questions.
1475 + */
1477 +#include "precompiled.hpp"
1478 +#include "memory/allocation.hpp"
1479 +#include "runtime/mutex.hpp"
1480 +#include "runtime/osThread.hpp"
1482 +#include <signal.h>
1484 + // ***************************************************************
1485 + // Platform dependent initialization and cleanup
1486 + // ***************************************************************
1488 +OSThread::OSThread()
1489 + : _thread_id(0),
1490 + _caller_sigmask(),
1491 + _vm_created_thread(false),
1492 + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) {
1493 + sigemptyset(&_caller_sigmask);
1496 +OSThread::~OSThread() {
1497 + delete _startThread_lock;
1499 diff -urN /tmp/a/osThread_solaris.hpp b/src/hotspot/os/solaris/osThread_solaris.hpp
1500 --- /tmp/a/osThread_solaris.hpp 1970-01-01 01:00:00.000000000 +0100
1501 +++ b/src/hotspot/os/solaris/osThread_solaris.hpp 2024-09-16 14:41:33.966795992 +0100
1502 @@ -0,0 +1,98 @@
1504 + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
1505 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1507 + * This code is free software; you can redistribute it and/or modify it
1508 + * under the terms of the GNU General Public License version 2 only, as
1509 + * published by the Free Software Foundation.
1511 + * This code is distributed in the hope that it will be useful, but WITHOUT
1512 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1513 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1514 + * version 2 for more details (a copy is included in the LICENSE file that
1515 + * accompanied this code).
1517 + * You should have received a copy of the GNU General Public License version
1518 + * 2 along with this work; if not, write to the Free Software Foundation,
1519 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1521 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1522 + * or visit www.oracle.com if you need additional information or have any
1523 + * questions.
1525 + */
1527 +#ifndef OS_SOLARIS_OSTHREAD_SOLARIS_HPP
1528 +#define OS_SOLARIS_OSTHREAD_SOLARIS_HPP
1530 +#include "runtime/osThreadBase.hpp"
1531 +#include "suspendResume_posix.hpp"
1532 +#include "utilities/globalDefinitions.hpp"
1534 +class OSThread : public OSThreadBase {
1535 + friend class VMStructs;
1537 + typedef thread_t thread_id_t;
1538 + thread_id_t _thread_id;
1540 + uint _lwp_id; // lwp ID, only used with bound threads
1541 + int _native_priority; // Saved native priority when starting
1542 + // a bound thread
1543 + sigset_t _caller_sigmask; // Caller's signal mask
1544 + bool _vm_created_thread; // true if the VM created this thread,
1545 + // false if primary thread or attached thread
1546 + public:
1547 + OSThread();
1548 + ~OSThread();
1550 + uint lwp_id() const { return _lwp_id; }
1551 + int native_priority() const { return _native_priority; }
1553 + // Set and get state of _vm_created_thread flag
1554 + void set_vm_created() { _vm_created_thread = true; }
1555 + bool is_vm_created() { return _vm_created_thread; }
1557 + // Methods to save/restore caller's signal mask
1558 + sigset_t caller_sigmask() const { return _caller_sigmask; }
1559 + void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; }
1561 + void set_lwp_id(uint id) { _lwp_id = id; }
1562 + void set_native_priority(int prio) { _native_priority = prio; }
1564 + thread_id_t thread_id() const {
1565 + return _thread_id;
1567 + void set_thread_id(thread_id_t id) {
1568 + _thread_id = id;
1571 + pthread_t pthread_id() const {
1572 + // Here: same as OSThread::thread_id()
1573 + return _thread_id;
1575 + SuspendResume sr;
1577 + private:
1578 + void* _siginfo;
1579 + ucontext_t* _ucontext;
1581 + public:
1582 + void set_siginfo(void* ptr) { _siginfo = ptr; }
1583 + ucontext_t* ucontext() const { return _ucontext; }
1584 + void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; }
1586 + private:
1587 + Monitor* _startThread_lock; // sync parent and child in thread creation
1589 + public:
1591 + Monitor* startThread_lock() const {
1592 + return _startThread_lock;
1595 + // Printing
1596 + uintx thread_id_for_printing() const override {
1597 + return (uintx)_thread_id;
1600 +#endif // OS_SOLARIS_OSTHREAD_SOLARIS_HPP
1601 diff -urN /tmp/a/os_perf_solaris.cpp b/src/hotspot/os/solaris/os_perf_solaris.cpp
1602 --- /tmp/a/os_perf_solaris.cpp 1970-01-01 01:00:00.000000000 +0100
1603 +++ b/src/hotspot/os/solaris/os_perf_solaris.cpp 2024-09-16 14:41:33.967040032 +0100
1604 @@ -0,0 +1,808 @@
1606 + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
1607 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1609 + * This code is free software; you can redistribute it and/or modify it
1610 + * under the terms of the GNU General Public License version 2 only, as
1611 + * published by the Free Software Foundation.
1613 + * This code is distributed in the hope that it will be useful, but WITHOUT
1614 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1615 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1616 + * version 2 for more details (a copy is included in the LICENSE file that
1617 + * accompanied this code).
1619 + * You should have received a copy of the GNU General Public License version
1620 + * 2 along with this work; if not, write to the Free Software Foundation,
1621 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1623 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1624 + * or visit www.oracle.com if you need additional information or have any
1625 + * questions.
1627 + */
1629 +#include "precompiled.hpp"
1630 +#include "jvm.h"
1631 +#include "memory/allocation.inline.hpp"
1632 +#include "runtime/os.hpp"
1633 +#include "runtime/os_perf.hpp"
1634 +#include "runtime/vm_version.hpp"
1635 +#include "os_solaris.inline.hpp"
1636 +#include "utilities/globalDefinitions.hpp"
1637 +#include "utilities/macros.hpp"
1639 +#include <sys/types.h>
1640 +#include <procfs.h>
1641 +#include <dirent.h>
1642 +#include <errno.h>
1643 +#include <stdio.h>
1644 +#include <stdlib.h>
1645 +#include <strings.h>
1646 +#include <unistd.h>
1647 +#include <fcntl.h>
1648 +#include <kstat.h>
1649 +#include <unistd.h>
1650 +#include <string.h>
1651 +#include <sys/sysinfo.h>
1652 +#include <sys/lwp.h>
1653 +#include <pthread.h>
1654 +#include <time.h>
1655 +#include <utmpx.h>
1656 +#include <dlfcn.h>
1657 +#include <sys/loadavg.h>
1658 +#include <limits.h>
1660 +static const double NANOS_PER_SEC = 1000000000.0;
1662 +struct CPUPerfTicks {
1663 + kstat_t* kstat;
1664 + uint64_t last_idle;
1665 + uint64_t last_total;
1666 + double last_ratio;
1669 +struct CPUPerfCounters {
1670 + int nProcs;
1671 + CPUPerfTicks* jvmTicks;
1672 + kstat_ctl_t* kstat_ctrl;
1675 +static int get_info(const char* path, void* info, size_t s, off_t o) {
1676 + assert(path != NULL, "path is NULL!");
1677 + assert(info != NULL, "info is NULL!");
1679 + int fd = -1;
1681 + if ((fd = os::open(path, O_RDONLY, 0)) < 0) {
1682 + return OS_ERR;
1684 + if (pread(fd, info, s, o) != s) {
1685 + close(fd);
1686 + return OS_ERR;
1688 + close(fd);
1689 + return OS_OK;
1692 +static int get_psinfo2(void* info, size_t s, off_t o) {
1693 + return get_info("/proc/self/psinfo", info, s, o);
1696 +static int get_psinfo(psinfo_t* info) {
1697 + return get_psinfo2(info, sizeof(*info), 0);
1700 +static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) {
1701 + assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!");
1702 + assert(load != NULL, "load pointer is NULL!");
1703 + assert(cpu_stat != NULL, "cpu_stat pointer is NULL!");
1705 + if (load->kstat == NULL) {
1706 + // no handle.
1707 + return OS_ERR;
1709 + if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) {
1710 + // disable handle for this CPU
1711 + load->kstat = NULL;
1712 + return OS_ERR;
1714 + return OS_OK;
1717 +static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) {
1718 + assert(counters != NULL, "counters pointer is NULL!");
1720 + cpu_stat_t cpu_stat = {0};
1722 + if (which_logical_cpu >= counters->nProcs) {
1723 + return .0;
1726 + CPUPerfTicks load = counters->jvmTicks[which_logical_cpu];
1727 + if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) {
1728 + return .0;
1731 + uint_t* usage = cpu_stat.cpu_sysinfo.cpu;
1732 + if (usage == NULL) {
1733 + return .0;
1736 + uint64_t c_idle = usage[CPU_IDLE];
1737 + uint64_t c_total = 0;
1739 + for (int i = 0; i < CPU_STATES; i++) {
1740 + c_total += usage[i];
1743 + // Calculate diff against previous snapshot
1744 + uint64_t d_idle = c_idle - load.last_idle;
1745 + uint64_t d_total = c_total - load.last_total;
1747 + /** update if weve moved */
1748 + if (d_total > 0) {
1749 + // Save current values for next time around
1750 + load.last_idle = c_idle;
1751 + load.last_total = c_total;
1752 + load.last_ratio = (double) (d_total - d_idle) / d_total;
1755 + return load.last_ratio;
1758 +static int get_boot_time(uint64_t* time) {
1759 + assert(time != NULL, "time pointer is NULL!");
1760 + setutxent();
1761 + for(;;) {
1762 + struct utmpx* u;
1763 + if ((u = getutxent()) == NULL) {
1764 + break;
1766 + if (u->ut_type == BOOT_TIME) {
1767 + *time = u->ut_xtime;
1768 + endutxent();
1769 + return OS_OK;
1772 + endutxent();
1773 + return OS_ERR;
1776 +static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) {
1777 + assert(switches != NULL, "switches pointer is NULL!");
1778 + assert(counters != NULL, "counter pointer is NULL!");
1779 + *switches = 0;
1780 + uint64_t s = 0;
1782 + // Collect data from all CPUs
1783 + for (int i = 0; i < counters->nProcs; i++) {
1784 + cpu_stat_t cpu_stat = {0};
1785 + CPUPerfTicks load = counters->jvmTicks[i];
1787 + if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) {
1788 + s += cpu_stat.cpu_sysinfo.pswitch;
1789 + } else {
1790 + //fail fast...
1791 + return OS_ERR;
1794 + *switches = s;
1795 + return OS_OK;
1798 +static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) {
1799 + assert(counters != NULL, "counters is NULL!");
1800 + assert(rate != NULL, "rate pointer is NULL!");
1801 + static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
1802 + static uint64_t lastTime = 0;
1803 + static uint64_t lastSwitches = 0;
1804 + static double lastRate = 0.0;
1806 + uint64_t lt = 0;
1807 + int res = 0;
1809 + if (lastTime == 0) {
1810 + uint64_t tmp;
1811 + if (get_boot_time(&tmp) < 0) {
1812 + return OS_ERR;
1814 + lt = tmp * 1000;
1817 + res = OS_OK;
1819 + pthread_mutex_lock(&contextSwitchLock);
1822 + uint64_t sw = 0;
1823 + clock_t t, d;
1825 + if (lastTime == 0) {
1826 + lastTime = lt;
1829 + t = clock();
1830 + d = t - lastTime;
1832 + if (d == 0) {
1833 + *rate = lastRate;
1834 + } else if (get_noof_context_switches(counters, &sw)== OS_OK) {
1835 + *rate = ((double)(sw - lastSwitches) / d) * 1000;
1836 + lastRate = *rate;
1837 + lastSwitches = sw;
1838 + lastTime = t;
1839 + } else {
1840 + *rate = 0.0;
1841 + res = OS_ERR;
1843 + if (*rate < 0.0) {
1844 + *rate = 0.0;
1845 + lastRate = 0.0;
1848 + pthread_mutex_unlock(&contextSwitchLock);
1849 + return res;
1854 +class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
1855 + friend class CPUPerformanceInterface;
1856 + private:
1857 + CPUPerfCounters _counters;
1858 + int cpu_load(int which_logical_cpu, double* cpu_load);
1859 + int context_switch_rate(double* rate);
1860 + int cpu_load_total_process(double* cpu_load);
1861 + int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
1863 + CPUPerformance();
1864 + ~CPUPerformance();
1865 + bool initialize();
1868 +CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
1869 + _counters.nProcs = 0;
1870 + _counters.jvmTicks = NULL;
1871 + _counters.kstat_ctrl = NULL;
1874 +bool CPUPerformanceInterface::CPUPerformance::initialize() {
1875 + // initialize kstat control structure,
1876 + _counters.kstat_ctrl = kstat_open();
1877 + assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!");
1879 + if (NULL == _counters.kstat_ctrl) {
1880 + return false;
1883 + // Get number of CPU(s)
1884 + if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) {
1885 + // ignore error?
1886 + _counters.nProcs = 1;
1889 + assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!");
1890 + if (_counters.nProcs == 0) {
1891 + return false;
1894 + // Data structure(s) for saving CPU load (one per CPU)
1895 + size_t array_entry_count = _counters.nProcs;
1896 + _counters.jvmTicks = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal);
1897 + memset(_counters.jvmTicks, 0, array_entry_count * sizeof(*_counters.jvmTicks));
1899 + // Get kstat cpu_stat counters for every CPU
1900 + // loop over kstat to find our cpu_stat(s)
1901 + int i = 0;
1902 + for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
1903 + if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
1904 + if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) {
1905 + continue;
1907 + if (i == _counters.nProcs) {
1908 + // more cpu_stats than reported CPUs
1909 + break;
1911 + _counters.jvmTicks[i++].kstat = kstat;
1914 + return true;
1917 +CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
1918 + FREE_C_HEAP_ARRAY(char, _counters.jvmTicks);
1919 + if (_counters.kstat_ctrl != NULL) {
1920 + kstat_close(_counters.kstat_ctrl);
1924 +int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
1925 + assert(cpu_load != NULL, "cpu_load pointer is NULL!");
1926 + double t = .0;
1927 + if (-1 == which_logical_cpu) {
1928 + for (int i = 0; i < _counters.nProcs; i++) {
1929 + t += get_cpu_load(i, &_counters);
1931 + // Cap total systemload to 1.0
1932 + t = MIN2<double>((t / _counters.nProcs), 1.0);
1933 + } else {
1934 + t = MIN2<double>(get_cpu_load(which_logical_cpu, &_counters), 1.0);
1937 + *cpu_load = t;
1938 + return OS_OK;
1941 +int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
1942 + assert(cpu_load != NULL, "cpu_load pointer is NULL!");
1944 + psinfo_t info;
1946 + // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
1947 + // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
1948 + if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) {
1949 + *cpu_load = 0.0;
1950 + return OS_ERR;
1952 + *cpu_load = (double) info.pr_pctcpu / 0x8000;
1953 + return OS_OK;
1956 +int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
1957 + assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
1958 + assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
1959 + assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
1961 + static uint64_t lastTime;
1962 + static uint64_t lastUser, lastKernel;
1963 + static double lastUserRes, lastKernelRes;
1965 + pstatus_t pss;
1966 + psinfo_t info;
1968 + *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0;
1969 + if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) {
1970 + return OS_ERR;
1973 + if (get_psinfo(&info) != 0) {
1974 + return OS_ERR;
1977 + // get the total time in user, kernel and total time
1978 + // check ratios for 'lately' and multiply the 'recent load'.
1979 + uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec;
1980 + uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec;
1981 + uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec;
1982 + uint64_t diff = time - lastTime;
1983 + double load = (double) info.pr_pctcpu / 0x8000;
1985 + if (diff > 0) {
1986 + lastUserRes = (load * (user - lastUser)) / diff;
1987 + lastKernelRes = (load * (kernel - lastKernel)) / diff;
1989 + // BUG9182835 - patch for clamping these values to sane ones.
1990 + lastUserRes = MIN2<double>(1, lastUserRes);
1991 + lastUserRes = MAX2<double>(0, lastUserRes);
1992 + lastKernelRes = MIN2<double>(1, lastKernelRes);
1993 + lastKernelRes = MAX2<double>(0, lastKernelRes);
1996 + double t = .0;
1997 + cpu_load(-1, &t);
1998 + // clamp at user+system and 1.0
1999 + if (lastUserRes + lastKernelRes > t) {
2000 + t = MIN2<double>(lastUserRes + lastKernelRes, 1.0);
2003 + *pjvmUserLoad = lastUserRes;
2004 + *pjvmKernelLoad = lastKernelRes;
2005 + *psystemTotalLoad = t;
2007 + lastTime = time;
2008 + lastUser = user;
2009 + lastKernel = kernel;
2011 + return OS_OK;
2014 +int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
2015 + return perf_context_switch_rate(&_counters, rate);
2018 +CPUPerformanceInterface::CPUPerformanceInterface() {
2019 + _impl = NULL;
2022 +bool CPUPerformanceInterface::initialize() {
2023 + _impl = new CPUPerformanceInterface::CPUPerformance();
2024 + return _impl->initialize();
2027 +CPUPerformanceInterface::~CPUPerformanceInterface(void) {
2028 + if (_impl != NULL) {
2029 + delete _impl;
2033 +int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
2034 + return _impl->cpu_load(which_logical_cpu, cpu_load);
2037 +int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
2038 + return _impl->cpu_load_total_process(cpu_load);
2041 +int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
2042 + return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
2045 +int CPUPerformanceInterface::context_switch_rate(double* rate) const {
2046 + return _impl->context_switch_rate(rate);
2049 +class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
2050 + friend class SystemProcessInterface;
2051 + private:
2052 + class ProcessIterator : public CHeapObj<mtInternal> {
2053 + friend class SystemProcessInterface::SystemProcesses;
2054 + private:
2055 + DIR* _dir;
2056 + struct dirent* _entry;
2057 + bool _valid;
2059 + ProcessIterator();
2060 + ~ProcessIterator();
2061 + bool initialize();
2063 + bool is_valid() const { return _valid; }
2064 + bool is_valid_entry(struct dirent* const entry) const;
2065 + bool is_dir(const char* const name) const;
2066 + char* allocate_string(const char* const str) const;
2067 + int current(SystemProcess* const process_info);
2068 + int next_process();
2069 + };
2071 + ProcessIterator* _iterator;
2072 + SystemProcesses();
2073 + bool initialize();
2074 + ~SystemProcesses();
2076 + //information about system processes
2077 + int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
2080 +bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
2081 + struct stat64 mystat;
2082 + int ret_val = 0;
2084 + ret_val = ::stat64(name, &mystat);
2086 + if (ret_val < 0) {
2087 + return false;
2089 + ret_val = S_ISDIR(mystat.st_mode);
2090 + return ret_val > 0;
2093 +// if it has a numeric name, is a directory and has a 'psinfo' file in it
2094 +bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
2095 + // ignore the "." and ".." directories
2096 + if ((strcmp(entry->d_name, ".") == 0) ||
2097 + (strcmp(entry->d_name, "..") == 0)) {
2098 + return false;
2101 + char buffer[PATH_MAX] = {0};
2102 + uint64_t size = 0;
2103 + bool result = false;
2104 + FILE *fp = NULL;
2106 + if (atoi(entry->d_name) != 0) {
2107 + jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
2109 + if (is_dir(buffer)) {
2110 + memset(buffer, 0, PATH_MAX);
2111 + jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name);
2112 + if ((fp = fopen(buffer, "r")) != NULL) {
2113 + int nread = 0;
2114 + psinfo_t psinfo_data;
2115 + if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) {
2116 + // only considering system process owned by root
2117 + if (psinfo_data.pr_uid == 0) {
2118 + result = true;
2125 + if (fp != NULL) {
2126 + fclose(fp);
2129 + return result;
2132 +char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
2133 + if (str != NULL) {
2134 + return os::strdup_check_oom(str, mtInternal);
2136 + return NULL;
2139 +int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
2140 + if (!is_valid()) {
2141 + return OS_ERR;
2144 + char psinfo_path[PATH_MAX] = {0};
2145 + jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name);
2147 + FILE *fp = NULL;
2148 + if ((fp = fopen(psinfo_path, "r")) == NULL) {
2149 + return OS_ERR;
2152 + int nread = 0;
2153 + psinfo_t psinfo_data;
2154 + if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) {
2155 + fclose(fp);
2156 + return OS_ERR;
2159 + char *exe_path = NULL;
2160 + if ((psinfo_data.pr_fname != NULL) &&
2161 + (psinfo_data.pr_psargs != NULL)) {
2162 + char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname);
2163 + if (path_substring != NULL) {
2164 + int len = path_substring - psinfo_data.pr_psargs;
2165 + exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
2166 + jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs);
2167 + exe_path[len] = '\0';
2171 + process_info->set_pid(atoi(_entry->d_name));
2172 + process_info->set_name(allocate_string(psinfo_data.pr_fname));
2173 + process_info->set_path(allocate_string(exe_path));
2174 + process_info->set_command_line(allocate_string(psinfo_data.pr_psargs));
2176 + if (exe_path != NULL) {
2177 + FREE_C_HEAP_ARRAY(char, exe_path);
2180 + if (fp != NULL) {
2181 + fclose(fp);
2184 + return OS_OK;
2187 +int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
2188 + if (!is_valid()) {
2189 + return OS_ERR;
2192 + do {
2193 + _entry = os::readdir(_dir);
2194 + if (_entry == NULL) {
2195 + // Error or reached end. Could use errno to distinguish those cases.
2196 + _valid = false;
2197 + return OS_ERR;
2199 + } while(!is_valid_entry(_entry));
2201 + _valid = true;
2202 + return OS_OK;
2205 +SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
2206 + _dir = NULL;
2207 + _entry = NULL;
2208 + _valid = false;
2211 +bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
2212 + _dir = os::opendir("/proc");
2213 + _entry = NULL;
2214 + _valid = true;
2215 + next_process();
2217 + return true;
2220 +SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
2221 + if (_dir != NULL) {
2222 + os::closedir(_dir);
2226 +SystemProcessInterface::SystemProcesses::SystemProcesses() {
2227 + _iterator = NULL;
2230 +bool SystemProcessInterface::SystemProcesses::initialize() {
2231 + _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
2232 + return _iterator->initialize();
2235 +SystemProcessInterface::SystemProcesses::~SystemProcesses() {
2236 + if (_iterator != NULL) {
2237 + delete _iterator;
2241 +int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
2242 + assert(system_processes != NULL, "system_processes pointer is NULL!");
2243 + assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
2244 + assert(_iterator != NULL, "iterator is NULL!");
2246 + // initialize pointers
2247 + *no_of_sys_processes = 0;
2248 + *system_processes = NULL;
2250 + while (_iterator->is_valid()) {
2251 + SystemProcess* tmp = new SystemProcess();
2252 + _iterator->current(tmp);
2254 + //if already existing head
2255 + if (*system_processes != NULL) {
2256 + //move "first to second"
2257 + tmp->set_next(*system_processes);
2259 + // new head
2260 + *system_processes = tmp;
2261 + // increment
2262 + (*no_of_sys_processes)++;
2263 + // step forward
2264 + _iterator->next_process();
2266 + return OS_OK;
2269 +int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
2270 + return _impl->system_processes(system_procs, no_of_sys_processes);
2273 +SystemProcessInterface::SystemProcessInterface() {
2274 + _impl = NULL;
2277 +bool SystemProcessInterface::initialize() {
2278 + _impl = new SystemProcessInterface::SystemProcesses();
2279 + return _impl->initialize();
2283 +SystemProcessInterface::~SystemProcessInterface() {
2284 + if (_impl != NULL) {
2285 + delete _impl;
2289 +CPUInformationInterface::CPUInformationInterface() {
2290 + _cpu_info = NULL;
2293 +bool CPUInformationInterface::initialize() {
2294 + _cpu_info = new CPUInformation();
2295 + VM_Version::initialize_cpu_information();
2296 + _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads());
2297 + _cpu_info->set_number_of_cores(VM_Version::number_of_cores());
2298 + _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets());
2299 + _cpu_info->set_cpu_name(VM_Version::cpu_name());
2300 + _cpu_info->set_cpu_description(VM_Version::cpu_description());
2301 + return true;
2304 +CPUInformationInterface::~CPUInformationInterface() {
2305 + if (_cpu_info != NULL) {
2306 + if (_cpu_info->cpu_name() != NULL) {
2307 + const char* cpu_name = _cpu_info->cpu_name();
2308 + FREE_C_HEAP_ARRAY(char, cpu_name);
2309 + _cpu_info->set_cpu_name(NULL);
2311 + if (_cpu_info->cpu_description() != NULL) {
2312 + const char* cpu_desc = _cpu_info->cpu_description();
2313 + FREE_C_HEAP_ARRAY(char, cpu_desc);
2314 + _cpu_info->set_cpu_description(NULL);
2316 + delete _cpu_info;
2320 +int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
2321 + if (_cpu_info == NULL) {
2322 + return OS_ERR;
2325 + cpu_info = *_cpu_info; // shallow copy assignment
2326 + return OS_OK;
2329 +class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
2330 + friend class NetworkPerformanceInterface;
2331 + private:
2332 + NetworkPerformance();
2333 + NONCOPYABLE(NetworkPerformance);
2334 + bool initialize();
2335 + ~NetworkPerformance();
2336 + int network_utilization(NetworkInterface** network_interfaces) const;
2339 +NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
2343 +bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
2344 + return true;
2347 +NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
2351 +int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
2353 + kstat_ctl_t* ctl = kstat_open();
2354 + if (ctl == NULL) {
2355 + return OS_ERR;
2358 + NetworkInterface* ret = NULL;
2359 + for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) {
2360 + if (strcmp(k->ks_class, "net") != 0) {
2361 + continue;
2363 + if (strcmp(k->ks_module, "link") != 0) {
2364 + continue;
2367 + if (kstat_read(ctl, k, NULL) == -1) {
2368 + return OS_ERR;
2371 + uint64_t bytes_in = UINT64_MAX;
2372 + uint64_t bytes_out = UINT64_MAX;
2373 + for (unsigned int i = 0; i < k->ks_ndata; ++i) {
2374 + kstat_named_t* data = &reinterpret_cast<kstat_named_t*>(k->ks_data)[i];
2375 + if (strcmp(data->name, "rbytes64") == 0) {
2376 + bytes_in = data->value.ui64;
2378 + else if (strcmp(data->name, "obytes64") == 0) {
2379 + bytes_out = data->value.ui64;
2383 + if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) {
2384 + NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret);
2385 + ret = cur;
2389 + kstat_close(ctl);
2390 + *network_interfaces = ret;
2392 + return OS_OK;
2395 +NetworkPerformanceInterface::NetworkPerformanceInterface() {
2396 + _impl = NULL;
2399 +NetworkPerformanceInterface::~NetworkPerformanceInterface() {
2400 + if (_impl != NULL) {
2401 + delete _impl;
2405 +bool NetworkPerformanceInterface::initialize() {
2406 + _impl = new NetworkPerformanceInterface::NetworkPerformance();
2407 + return _impl->initialize();
2410 +int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
2411 + return _impl->network_utilization(network_interfaces);
2413 diff -urN /tmp/a/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp
2414 --- /tmp/a/os_solaris.cpp 1970-01-01 01:00:00.000000000 +0100
2415 +++ b/src/hotspot/os/solaris/os_solaris.cpp 2024-09-16 14:41:33.968071187 +0100
2416 @@ -0,0 +1,2937 @@
2418 + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
2419 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2421 + * This code is free software; you can redistribute it and/or modify it
2422 + * under the terms of the GNU General Public License version 2 only, as
2423 + * published by the Free Software Foundation.
2425 + * This code is distributed in the hope that it will be useful, but WITHOUT
2426 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2427 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2428 + * version 2 for more details (a copy is included in the LICENSE file that
2429 + * accompanied this code).
2431 + * You should have received a copy of the GNU General Public License version
2432 + * 2 along with this work; if not, write to the Free Software Foundation,
2433 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2435 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2436 + * or visit www.oracle.com if you need additional information or have any
2437 + * questions.
2439 + */
2441 +// no precompiled headers
2442 +#include "jvm.h"
2443 +#include "classfile/classLoader.hpp"
2444 +#include "classfile/systemDictionary.hpp"
2445 +#include "classfile/vmSymbols.hpp"
2446 +#include "code/vtableStubs.hpp"
2447 +#include "compiler/compileBroker.hpp"
2448 +#include "compiler/disassembler.hpp"
2449 +#include "interpreter/interpreter.hpp"
2450 +#include "jvmtifiles/jvmti.h"
2451 +#include "logging/log.hpp"
2452 +#include "logging/logStream.hpp"
2453 +#include "memory/allocation.inline.hpp"
2454 +#include "memory/universe.hpp"
2455 +#include "oops/oop.inline.hpp"
2456 +#include "os_solaris.inline.hpp"
2457 +#include "prims/jniFastGetField.hpp"
2458 +#include "prims/jvm_misc.hpp"
2459 +#include "runtime/arguments.hpp"
2460 +#include "runtime/atomic.hpp"
2461 +#include "runtime/globals.hpp"
2462 +#include "runtime/globals_extension.hpp"
2463 +#include "runtime/interfaceSupport.inline.hpp"
2464 +#include "runtime/java.hpp"
2465 +#include "runtime/javaCalls.hpp"
2466 +#include "runtime/javaThread.hpp"
2467 +#include "runtime/mutexLocker.hpp"
2468 +#include "runtime/objectMonitor.hpp"
2469 +#include "runtime/osInfo.hpp"
2470 +#include "runtime/orderAccess.hpp"
2471 +#include "runtime/osThread.hpp"
2472 +#include "runtime/park.hpp"
2473 +#include "runtime/perfMemory.hpp"
2474 +#include "runtime/sharedRuntime.hpp"
2475 +#include "runtime/statSampler.hpp"
2476 +#include "runtime/stubRoutines.hpp"
2477 +#include "runtime/threadCritical.hpp"
2478 +#include "runtime/threads.hpp"
2479 +#include "runtime/timer.hpp"
2480 +#include "runtime/vm_version.hpp"
2481 +#include "semaphore_posix.hpp"
2482 +#include "services/attachListener.hpp"
2483 +#include "nmt/memTracker.hpp"
2484 +#include "services/runtimeService.hpp"
2485 +#include "signals_posix.hpp"
2486 +#include "utilities/align.hpp"
2487 +#include "utilities/checkedCast.hpp"
2488 +#include "utilities/decoder.hpp"
2489 +#include "utilities/defaultStream.hpp"
2490 +#include "utilities/events.hpp"
2491 +#include "utilities/growableArray.hpp"
2492 +#include "utilities/macros.hpp"
2493 +#include "utilities/vmError.hpp"
2495 +// put OS-includes here
2496 +# include <dlfcn.h>
2497 +# include <errno.h>
2498 +# include <exception>
2499 +# include <link.h>
2500 +# include <poll.h>
2501 +# include <pthread.h>
2502 +# include <setjmp.h>
2503 +# include <signal.h>
2504 +# include <stdio.h>
2505 +# include <alloca.h>
2506 +# include <sys/filio.h>
2507 +# include <sys/ipc.h>
2508 +# include <sys/lwp.h>
2509 +# include <sys/machelf.h> // for elf Sym structure used by dladdr1
2510 +# include <sys/mman.h>
2511 +# include <sys/processor.h>
2512 +# include <sys/procset.h>
2513 +# include <sys/pset.h>
2514 +# include <sys/resource.h>
2515 +# include <sys/shm.h>
2516 +# include <sys/socket.h>
2517 +# include <sys/stat.h>
2518 +# include <sys/swap.h> // for swapctl
2519 +# include <sys/systeminfo.h>
2520 +# include <sys/time.h>
2521 +# include <sys/times.h>
2522 +# include <sys/types.h>
2523 +# include <sys/wait.h>
2524 +# include <sys/utsname.h>
2525 +# include <thread.h>
2526 +# include <unistd.h>
2527 +# include <sys/priocntl.h>
2528 +# include <sys/rtpriocntl.h>
2529 +# include <sys/tspriocntl.h>
2530 +# include <sys/iapriocntl.h>
2531 +# include <sys/fxpriocntl.h>
2532 +# include <sys/loadavg.h>
2533 +# include <string.h>
2534 +# include <stdio.h>
2535 +# include <vm/anon.h> // for swap anoninfo
2537 +# include <procfs.h>
2539 +#define MAX_PATH (2 * K)
2541 +// for timer info max values which include all bits
2542 +#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
2544 +// Here are some liblgrp types from sys/lgrp_user.h to be able to
2545 +// compile on older systems without this header file.
2547 +#ifndef MADV_ACCESS_LWP
2548 + #define MADV_ACCESS_LWP 7 /* next LWP to access heavily */
2549 +#endif
2550 +#ifndef MADV_ACCESS_MANY
2551 + #define MADV_ACCESS_MANY 8 /* many processes to access heavily */
2552 +#endif
2554 +#ifndef LGRP_RSRC_CPU
2555 + #define LGRP_RSRC_CPU 0 /* CPU resources */
2556 +#endif
2557 +#ifndef LGRP_RSRC_MEM
2558 + #define LGRP_RSRC_MEM 1 /* memory resources */
2559 +#endif
2561 +// guarded in sys/mman.h
2562 +extern "C" {
2563 +extern int getpagesizes(size_t[], int);
2566 +// Values for ThreadPriorityPolicy == 1
2567 +int prio_policy1[CriticalPriority+1] = {
2568 + -99999, 0, 16, 32, 48, 64,
2569 + 80, 96, 112, 124, 127, 127 };
2571 +// System parameters used internally
2572 +static clock_t clock_tics_per_sec = 100;
2574 +// For diagnostics to print a message once. see run_periodic_checks
2575 +static bool check_addr0_done = false;
2577 +address os::Solaris::handler_start; // start pc of thr_sighndlrinfo
2578 +address os::Solaris::handler_end; // end pc of thr_sighndlrinfo
2580 +address os::Solaris::_main_stack_base = NULL; // 4352906 workaround
2582 +os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL;
2584 +// "default" initializers for missing libc APIs
2585 +extern "C" {
2586 + int memcntl(void *, size_t, int, void *, int, int);
2587 + int meminfo(const uint64_t *, int, const uint_t *, int, uint64_t *, uint_t *);
2590 +static inline size_t adjust_stack_size(address base, size_t size) {
2591 + if ((ssize_t)size < 0) {
2592 + // 4759953: Compensate for ridiculous stack size.
2593 + size = max_intx;
2595 + if (size > (size_t)base) {
2596 + // 4812466: Make sure size doesn't allow the stack to wrap the address space.
2597 + size = (size_t)base;
2599 + return size;
2602 +static inline stack_t get_stack_info() {
2603 + stack_t st;
2604 + int retval = thr_stksegment(&st);
2605 + st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size);
2606 + assert(retval == 0, "incorrect return value from thr_stksegment");
2607 + assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
2608 + assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
2609 + return st;
2612 +bool os::is_primordial_thread(void) {
2613 + int r = thr_main();
2614 + guarantee(r == 0 || r == 1, "CR6501650 or CR6493689");
2615 + return r == 1;
2618 +address os::Solaris::current_stack_base() {
2619 + bool _is_primordial_thread = os::is_primordial_thread();
2621 + // Workaround 4352906, avoid calls to thr_stksegment by
2622 + // thr_main after the first one (it looks like we trash
2623 + // some data, causing the value for ss_sp to be incorrect).
2624 + if (!_is_primordial_thread || os::Solaris::_main_stack_base == NULL) {
2625 + stack_t st = get_stack_info();
2626 + if (_is_primordial_thread) {
2627 + // cache initial value of stack base
2628 + os::Solaris::_main_stack_base = (address)st.ss_sp;
2630 + return (address)st.ss_sp;
2631 + } else {
2632 + guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base");
2633 + return os::Solaris::_main_stack_base;
2637 +size_t os::Solaris::current_stack_size() {
2638 + size_t size;
2640 + if (!os::is_primordial_thread()) {
2641 + size = get_stack_info().ss_size;
2642 + } else {
2643 + struct rlimit limits;
2644 + getrlimit(RLIMIT_STACK, &limits);
2645 + size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur);
2647 + // base may not be page aligned
2648 + address base = current_stack_base();
2649 + address bottom = align_up(base - size, os::vm_page_size());;
2650 + return (size_t)(base - bottom);
2653 +void os::current_stack_base_and_size(address* stack_base, size_t* stack_size) {
2654 + *stack_base = os::Solaris::current_stack_base();
2655 + *stack_size = os::Solaris::current_stack_size();
2658 +jint os::Solaris::_os_thread_limit = 0;
2659 +volatile jint os::Solaris::_os_thread_count = 0;
2661 +julong os::available_memory() {
2662 + return Solaris::available_memory();
2665 +julong os::free_memory() {
2666 + return Solaris::available_memory();
2669 +julong os::Solaris::available_memory() {
2670 + return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size();
2673 +julong os::Solaris::_physical_memory = 0;
2675 +jlong os::total_swap_space() {
2676 + struct anoninfo ai;
2677 + pgcnt_t allocated, reserved, available;
2678 + int ret = swapctl(SC_AINFO, &ai);
2679 + if (ret == -1) {
2680 + return -1;
2682 + return (jlong)(ai.ani_max * sysconf(_SC_PAGESIZE));
2685 +jlong os::free_swap_space() {
2686 + struct anoninfo ai;
2687 + int ret = swapctl(SC_AINFO, &ai);
2688 + if (ret == -1) {
2689 + return -1;
2691 + return (jlong)(ai.ani_free * sysconf(_SC_PAGESIZE));
2694 +julong os::physical_memory() {
2695 + return Solaris::physical_memory();
2698 +size_t os::rss() { return (size_t)0; }
2700 +static hrtime_t first_hrtime = 0;
2701 +static const hrtime_t hrtime_hz = 1000*1000*1000;
2702 +static volatile hrtime_t max_hrtime = 0;
2705 +void os::Solaris::initialize_system_info() {
2706 + set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
2707 + _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) *
2708 + (julong)sysconf(_SC_PAGESIZE);
2711 +uint os::processor_id() {
2712 + const processorid_t id = ::getcpuid();
2713 + assert(id >= 0 && id < _processor_count, "Invalid processor id");
2714 + return (uint)id;
2717 +int os::active_processor_count() {
2718 + // User has overridden the number of active processors
2719 + if (ActiveProcessorCount > 0) {
2720 + log_trace(os)("active_processor_count: "
2721 + "active processor count set by user : %d",
2722 + ActiveProcessorCount);
2723 + return ActiveProcessorCount;
2726 + int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
2727 + pid_t pid = getpid();
2728 + psetid_t pset = PS_NONE;
2729 + // Are we running in a processor set or is there any processor set around?
2730 + if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) {
2731 + uint_t pset_cpus;
2732 + // Query the number of cpus available to us.
2733 + if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) {
2734 + assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check");
2735 + return pset_cpus;
2738 + // Otherwise return number of online cpus
2739 + return online_cpus;
2742 +void os::set_native_thread_name(const char *name) {
2743 + if (Solaris::_pthread_setname_np != NULL) {
2744 + // Only the first 31 bytes of 'name' are processed by pthread_setname_np
2745 + // but we explicitly copy into a size-limited buffer to avoid any
2746 + // possible overflow.
2747 + char buf[32];
2748 + snprintf(buf, sizeof(buf), "%s", name);
2749 + buf[sizeof(buf) - 1] = '\0';
2750 + Solaris::_pthread_setname_np(pthread_self(), buf);
2754 +void os::init_system_properties_values() {
2755 + // The next steps are taken in the product version:
2756 + //
2757 + // Obtain the JAVA_HOME value from the location of libjvm.so.
2758 + // This library should be located at:
2759 + // <JAVA_HOME>/jre/lib/<arch>/{client|server}/libjvm.so.
2760 + //
2761 + // If "/jre/lib/" appears at the right place in the path, then we
2762 + // assume libjvm.so is installed in a JDK and we use this path.
2763 + //
2764 + // Otherwise exit with message: "Could not create the Java virtual machine."
2765 + //
2766 + // The following extra steps are taken in the debugging version:
2767 + //
2768 + // If "/jre/lib/" does NOT appear at the right place in the path
2769 + // instead of exit check for $JAVA_HOME environment variable.
2770 + //
2771 + // If it is defined and we are able to locate $JAVA_HOME/jre/lib/<arch>,
2772 + // then we append a fake suffix "hotspot/libjvm.so" to this path so
2773 + // it looks like libjvm.so is installed there
2774 + // <JAVA_HOME>/jre/lib/<arch>/hotspot/libjvm.so.
2775 + //
2776 + // Otherwise exit.
2777 + //
2778 + // Important note: if the location of libjvm.so changes this
2779 + // code needs to be changed accordingly.
2781 +// Base path of extensions installed on the system.
2782 +#define SYS_EXT_DIR "/usr/jdk/packages"
2783 +#define EXTENSIONS_DIR "/lib/ext"
2785 + // Buffer that fits several sprintfs.
2786 + // Note that the space for the colon and the trailing null are provided
2787 + // by the nulls included by the sizeof operator.
2788 + const size_t bufsize =
2789 + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends.
2790 + sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path
2791 + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir
2792 + char *buf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
2794 + // sysclasspath, java_home, dll_dir
2796 + char *pslash;
2797 + os::jvm_path(buf, bufsize);
2799 + // Found the full path to libjvm.so.
2800 + // Now cut the path to <java_home>/jre if we can.
2801 + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
2802 + pslash = strrchr(buf, '/');
2803 + if (pslash != NULL) {
2804 + *pslash = '\0'; // Get rid of /{client|server|hotspot}.
2806 + Arguments::set_dll_dir(buf);
2808 + if (pslash != NULL) {
2809 + pslash = strrchr(buf, '/');
2810 + if (pslash != NULL) {
2811 + *pslash = '\0'; // Get rid of /lib.
2814 + Arguments::set_java_home(buf);
2815 + if (!set_boot_path('/', ':')) {
2816 + vm_exit_during_initialization("Failed setting boot class path.", NULL);
2820 + // Where to look for native libraries.
2822 + // Use dlinfo() to determine the correct java.library.path.
2823 + //
2824 + // If we're launched by the Java launcher, and the user
2825 + // does not set java.library.path explicitly on the commandline,
2826 + // the Java launcher sets LD_LIBRARY_PATH for us and unsets
2827 + // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case
2828 + // dlinfo returns LD_LIBRARY_PATH + crle settings (including
2829 + // /usr/lib), which is exactly what we want.
2830 + //
2831 + // If the user does set java.library.path, it completely
2832 + // overwrites this setting, and always has.
2833 + //
2834 + // If we're not launched by the Java launcher, we may
2835 + // get here with any/all of the LD_LIBRARY_PATH[_32|64]
2836 + // settings. Again, dlinfo does exactly what we want.
2838 + Dl_serinfo info_sz, *info = &info_sz;
2839 + Dl_serpath *path;
2840 + char *library_path;
2841 + char *common_path = buf;
2843 + // Determine search path count and required buffer size.
2844 + if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) {
2845 + FREE_C_HEAP_ARRAY(char, buf);
2846 + vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror());
2849 + // Allocate new buffer and initialize.
2850 + info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal);
2851 + info->dls_size = info_sz.dls_size;
2852 + info->dls_cnt = info_sz.dls_cnt;
2854 + // Obtain search path information.
2855 + if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) {
2856 + FREE_C_HEAP_ARRAY(char, buf);
2857 + FREE_C_HEAP_ARRAY(char, info);
2858 + vm_exit_during_initialization("dlinfo SERINFO request", dlerror());
2861 + path = &info->dls_serpath[0];
2863 + // Note: Due to a legacy implementation, most of the library path
2864 + // is set in the launcher. This was to accommodate linking restrictions
2865 + // on legacy Solaris implementations (which are no longer supported).
2866 + // Eventually, all the library path setting will be done here.
2867 + //
2868 + // However, to prevent the proliferation of improperly built native
2869 + // libraries, the new path component /usr/jdk/packages is added here.
2871 + // Construct the invariant part of ld_library_path.
2872 + sprintf(common_path, SYS_EXT_DIR "/lib");
2874 + // Struct size is more than sufficient for the path components obtained
2875 + // through the dlinfo() call, so only add additional space for the path
2876 + // components explicitly added here.
2877 + size_t library_path_size = info->dls_size + strlen(common_path);
2878 + library_path = NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal);
2879 + library_path[0] = '\0';
2881 + // Construct the desired Java library path from the linker's library
2882 + // search path.
2883 + //
2884 + // For compatibility, it is optimal that we insert the additional path
2885 + // components specific to the Java VM after those components specified
2886 + // in LD_LIBRARY_PATH (if any) but before those added by the ld.so
2887 + // infrastructure.
2888 + if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it.
2889 + strcpy(library_path, common_path);
2890 + } else {
2891 + int inserted = 0;
2892 + uint_t i;
2893 + for (i = 0; i < info->dls_cnt; i++, path++) {
2894 + uint_t flags = path->dls_flags & LA_SER_MASK;
2895 + if (((flags & LA_SER_LIBPATH) == 0) && !inserted) {
2896 + strcat(library_path, common_path);
2897 + strcat(library_path, os::path_separator());
2898 + inserted = 1;
2900 + strcat(library_path, path->dls_name);
2901 + strcat(library_path, os::path_separator());
2903 + // Eliminate trailing path separator.
2904 + library_path[strlen(library_path)-1] = '\0';
2907 + // happens before argument parsing - can't use a trace flag
2908 + // tty->print_raw("init_system_properties_values: native lib path: ");
2909 + // tty->print_raw_cr(library_path);
2911 + // Callee copies into its own buffer.
2912 + Arguments::set_library_path(library_path);
2914 + FREE_C_HEAP_ARRAY(char, library_path);
2915 + FREE_C_HEAP_ARRAY(char, info);
2918 + // Extensions directories.
2919 + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
2920 + Arguments::set_ext_dirs(buf);
2922 + FREE_C_HEAP_ARRAY(char, buf);
2924 +#undef SYS_EXT_DIR
2925 +#undef EXTENSIONS_DIR
2928 +static thread_t main_thread;
2930 +// Thread start routine for all newly created threads
2931 +extern "C" void* thread_native_entry(void* thread_addr) {
2933 + Thread* thread = (Thread*)thread_addr;
2935 + thread->record_stack_base_and_size();
2937 + // Try to randomize the cache line index of hot stack frames.
2938 + // This helps when threads of the same stack traces evict each other's
2939 + // cache lines. The threads can be either from the same JVM instance, or
2940 + // from different JVM instances. The benefit is especially true for
2941 + // processors with hyperthreading technology.
2942 + static int counter = 0;
2943 + int pid = os::current_process_id();
2944 + alloca(((pid ^ counter++) & 7) * 128);
2946 + int prio;
2948 + thread->initialize_thread_current();
2950 + OSThread* osthr = thread->osthread();
2952 + osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound
2954 + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").",
2955 + os::current_thread_id());
2957 + if (UseNUMA) {
2958 + int lgrp_id = os::numa_get_group_id();
2959 + if (lgrp_id != -1) {
2960 + thread->set_lgrp_id(lgrp_id);
2964 + // Our priority was set when we were created, and stored in the
2965 + // osthread, but couldn't be passed through to our LWP until now.
2966 + // So read back the priority and set it again.
2968 + if (osthr->thread_id() != -1) {
2969 + if (UseThreadPriorities) {
2970 + int prio = osthr->native_priority();
2971 + os::set_native_priority(thread, prio);
2975 + assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
2977 + // initialize signal mask for this thread
2978 + PosixSignals::hotspot_sigmask(thread);
2980 + os::Solaris::init_thread_fpu_state();
2982 + thread->call_run();
2984 + // Note: at this point the thread object may already have deleted itself.
2985 + // Do not dereference it from here on out.
2987 + // One less thread is executing
2988 + // When the VMThread gets here, the main thread may have already exited
2989 + // which frees the CodeHeap containing the Atomic::dec code
2990 + if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) {
2991 + Atomic::dec(&os::Solaris::_os_thread_count);
2994 + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id());
2996 + thr_exit(NULL);
2997 + ShouldNotReachHere();
2999 + return NULL;
3002 +static OSThread* create_os_thread(Thread* thread, thread_t thread_id) {
3003 + // Allocate the OSThread object
3004 + OSThread* osthread = new OSThread();
3005 + if (osthread == NULL) return NULL;
3007 + // Store info on the Solaris thread into the OSThread
3008 + osthread->set_thread_id(thread_id);
3009 + osthread->set_lwp_id(_lwp_self());
3011 + if (UseNUMA) {
3012 + int lgrp_id = os::numa_get_group_id();
3013 + if (lgrp_id != -1) {
3014 + thread->set_lgrp_id(lgrp_id);
3018 + // Initial thread state is INITIALIZED, not SUSPENDED
3019 + osthread->set_state(INITIALIZED);
3021 + return osthread;
3024 +bool os::create_attached_thread(JavaThread* thread) {
3025 +#ifdef ASSERT
3026 + thread->verify_not_published();
3027 +#endif
3028 + OSThread* osthread = create_os_thread(thread, thr_self());
3029 + if (osthread == NULL) {
3030 + return false;
3033 + // Initial thread state is RUNNABLE
3034 + osthread->set_state(RUNNABLE);
3035 + thread->set_osthread(osthread);
3037 + if (os::is_primordial_thread()) {
3038 + os::Solaris::correct_stack_boundaries_for_primordial_thread(thread);
3041 + // initialize signal mask for this thread
3042 + // and save the caller's signal mask
3043 + PosixSignals::hotspot_sigmask(thread);
3045 + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").",
3046 + os::current_thread_id());
3048 + return true;
3051 +bool os::create_main_thread(JavaThread* thread) {
3052 +#ifdef ASSERT
3053 + thread->verify_not_published();
3054 +#endif
3055 + if (_starting_thread == NULL) {
3056 + _starting_thread = create_os_thread(thread, main_thread);
3057 + if (_starting_thread == NULL) {
3058 + return false;
3062 + // The primodial thread is runnable from the start
3063 + _starting_thread->set_state(RUNNABLE);
3065 + thread->set_osthread(_starting_thread);
3067 + // initialize signal mask for this thread
3068 + // and save the caller's signal mask
3069 + PosixSignals::hotspot_sigmask(thread);
3071 + return true;
3074 +// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr()
3075 +static char* describe_thr_create_attributes(char* buf, size_t buflen,
3076 + size_t stacksize, long flags) {
3077 + stringStream ss(buf, buflen);
3078 + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024);
3079 + ss.print("flags: ");
3080 + #define PRINT_FLAG(f) if (flags & f) ss.print( #f " ");
3081 + #define ALL(X) \
3082 + X(THR_SUSPENDED) \
3083 + X(THR_DETACHED) \
3084 + X(THR_BOUND) \
3085 + X(THR_NEW_LWP) \
3086 + X(THR_DAEMON)
3087 + ALL(PRINT_FLAG)
3088 + #undef ALL
3089 + #undef PRINT_FLAG
3090 + return buf;
3093 +// return default stack size for thr_type
3094 +size_t os::Posix::default_stack_size(os::ThreadType thr_type) {
3095 + // default stack size when not specified by caller is 1M (2M for LP64)
3096 + size_t s = (BytesPerWord >> 2) * K * K;
3097 + return s;
3100 +bool os::create_thread(Thread* thread, ThreadType thr_type,
3101 + size_t req_stack_size) {
3102 + // Allocate the OSThread object
3103 + OSThread* osthread = new OSThread();
3104 + if (osthread == NULL) {
3105 + return false;
3108 + // calculate stack size if it's not specified by caller
3109 + size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
3111 + // Initial state is ALLOCATED but not INITIALIZED
3112 + osthread->set_state(ALLOCATED);
3114 + if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) {
3115 + // We got lots of threads. Check if we still have some address space left.
3116 + // Need to be at least 5Mb of unreserved address space. We do check by
3117 + // trying to reserve some.
3118 + const size_t VirtualMemoryBangSize = 20*K*K;
3119 + char* mem = os::reserve_memory(VirtualMemoryBangSize);
3120 + if (mem == NULL) {
3121 + delete osthread;
3122 + return false;
3123 + } else {
3124 + // Release the memory again
3125 + os::release_memory(mem, VirtualMemoryBangSize);
3129 + // Setup osthread because the child thread may need it.
3130 + thread->set_osthread(osthread);
3132 + // Create the Solaris thread
3133 + thread_t tid = 0;
3134 + long flags = THR_DETACHED | THR_SUSPENDED;
3135 + int status;
3137 + // Mark that we don't have an lwp or thread id yet.
3138 + // In case we attempt to set the priority before the thread starts.
3139 + osthread->set_lwp_id(-1);
3140 + osthread->set_thread_id(-1);
3142 + status = thr_create(NULL, stack_size, thread_native_entry, thread, flags, &tid);
3144 + char buf[64];
3145 + if (status == 0) {
3146 + log_info(os, thread)("Thread \"%s\" started (tid: " UINTX_FORMAT ", attributes: %s). ",
3147 + thread->name(), (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
3148 + } else {
3149 + log_warning(os, thread)("Failed to start thread \"%s\" - thr_create failed (%s) for attributes: %s.",
3150 + thread->name(), os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
3151 + // Log some OS information which might explain why creating the thread failed.
3152 + log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
3153 + LogStream st(Log(os, thread)::info());
3154 + os::Posix::print_rlimit_info(&st);
3155 + os::print_memory_info(&st);
3158 + if (status != 0) {
3159 + thread->set_osthread(NULL);
3160 + // Need to clean up stuff we've allocated so far
3161 + delete osthread;
3162 + return false;
3165 + Atomic::inc(&os::Solaris::_os_thread_count);
3167 + // Store info on the Solaris thread into the OSThread
3168 + osthread->set_thread_id(tid);
3170 + // Remember that we created this thread so we can set priority on it
3171 + osthread->set_vm_created();
3173 + // Most thread types will set an explicit priority before starting the thread,
3174 + // but for those that don't we need a valid value to read back in thread_native_entry.
3175 + osthread->set_native_priority(NormPriority);
3177 + // Initial thread state is INITIALIZED, not SUSPENDED
3178 + osthread->set_state(INITIALIZED);
3180 + // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
3181 + return true;
3184 +// CR 7190089: on Solaris, primordial thread's stack needs adjusting.
3185 +// Without the adjustment, stack size is incorrect if stack is set to unlimited (ulimit -s unlimited).
3186 +void os::Solaris::correct_stack_boundaries_for_primordial_thread(Thread* thr) {
3187 + assert(is_primordial_thread(), "Call only for primordial thread");
3189 + JavaThread* jt = (JavaThread *)thr;
3190 + assert(jt != NULL, "Sanity check");
3191 + size_t stack_size;
3192 + address base = jt->stack_base();
3193 + if (Arguments::created_by_java_launcher()) {
3194 + // Use 2MB to allow for Solaris 7 64 bit mode.
3195 + stack_size = JavaThread::stack_size_at_create() == 0
3196 + ? 2048*K : JavaThread::stack_size_at_create();
3198 + // There are rare cases when we may have already used more than
3199 + // the basic stack size allotment before this method is invoked.
3200 + // Attempt to allow for a normally sized java_stack.
3201 + size_t current_stack_offset = (size_t)(base - (address)&stack_size);
3202 + stack_size += ReservedSpace::page_align_size_down(current_stack_offset);
3203 + } else {
3204 + // 6269555: If we were not created by a Java launcher, i.e. if we are
3205 + // running embedded in a native application, treat the primordial thread
3206 + // as much like a native attached thread as possible. This means using
3207 + // the current stack size from thr_stksegment(), unless it is too large
3208 + // to reliably setup guard pages. A reasonable max size is 8MB.
3209 + size_t current_size = current_stack_size();
3210 + // This should never happen, but just in case....
3211 + if (current_size == 0) current_size = 2 * K * K;
3212 + stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size;
3214 + address bottom = align_up(base - stack_size, os::vm_page_size());;
3215 + stack_size = (size_t)(base - bottom);
3217 + assert(stack_size > 0, "Stack size calculation problem");
3219 + if (stack_size > jt->stack_size()) {
3220 +#ifndef PRODUCT
3221 + struct rlimit limits;
3222 + getrlimit(RLIMIT_STACK, &limits);
3223 + size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur);
3224 + assert(size >= jt->stack_size(), "Stack size problem in main thread");
3225 +#endif
3226 + tty->print_cr("Stack size of " SIZE_FORMAT " Kb exceeds current limit of " SIZE_FORMAT " Kb.\n"
3227 + "(Stack sizes are rounded up to a multiple of the system page size.)\n"
3228 + "See limit(1) to increase the stack size limit.",
3229 + stack_size / K, jt->stack_size() / K);
3230 + vm_exit(1);
3232 + assert(jt->stack_size() >= stack_size,
3233 + "Attempt to map more stack than was allocated");
3234 + jt->set_stack_size(stack_size);
3240 +// Free Solaris resources related to the OSThread
3241 +void os::free_thread(OSThread* osthread) {
3242 + assert(osthread != NULL, "os::free_thread but osthread not set");
3244 + // We are told to free resources of the argument thread,
3245 + // but we can only really operate on the current thread.
3246 + assert(Thread::current()->osthread() == osthread,
3247 + "os::free_thread but not current thread");
3249 + // Restore caller's signal mask
3250 + sigset_t sigmask = osthread->caller_sigmask();
3251 + pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
3253 + delete osthread;
3256 +void os::pd_start_thread(Thread* thread) {
3257 + int status = thr_continue(thread->osthread()->thread_id());
3258 + assert_status(status == 0, status, "thr_continue failed");
3262 +intx os::current_thread_id() {
3263 + return (intx)thr_self();
3266 +static pid_t _initial_pid = 0;
3268 +int os::current_process_id() {
3269 + return (int)(_initial_pid ? _initial_pid : getpid());
3272 +// gethrtime() should be monotonic according to the documentation,
3273 +// but some virtualized platforms are known to break this guarantee.
3274 +// getTimeNanos() must be guaranteed not to move backwards, so we
3275 +// are forced to add a check here.
3276 +inline hrtime_t getTimeNanos() {
3277 + const hrtime_t now = gethrtime();
3278 + const hrtime_t prev = max_hrtime;
3279 + if (now <= prev) {
3280 + return prev; // same or retrograde time;
3282 + const hrtime_t obsv = Atomic::cmpxchg(&max_hrtime, prev, now);
3283 + assert(obsv >= prev, "invariant"); // Monotonicity
3284 + // If the CAS succeeded then we're done and return "now".
3285 + // If the CAS failed and the observed value "obsv" is >= now then
3286 + // we should return "obsv". If the CAS failed and now > obsv > prv then
3287 + // some other thread raced this thread and installed a new value, in which case
3288 + // we could either (a) retry the entire operation, (b) retry trying to install now
3289 + // or (c) just return obsv. We use (c). No loop is required although in some cases
3290 + // we might discard a higher "now" value in deference to a slightly lower but freshly
3291 + // installed obsv value. That's entirely benign -- it admits no new orderings compared
3292 + // to (a) or (b) -- and greatly reduces coherence traffic.
3293 + // We might also condition (c) on the magnitude of the delta between obsv and now.
3294 + // Avoiding excessive CAS operations to hot RW locations is critical.
3295 + // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
3296 + return (prev == obsv) ? now : obsv;
3299 +double os::elapsedVTime() {
3300 + return (double)gethrvtime() / (double)hrtime_hz;
3303 +// DLL functions
3305 +// This must be hard coded because it's the system's temporary
3306 +// directory not the java application's temp directory, ala java.io.tmpdir.
3307 +const char* os::get_temp_directory() { return "/tmp"; }
3309 +// check if addr is inside libjvm.so
3310 +bool os::address_is_in_vm(address addr) {
3311 + static address libjvm_base_addr;
3312 + Dl_info dlinfo;
3314 + if (libjvm_base_addr == NULL) {
3315 + if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) {
3316 + libjvm_base_addr = (address)dlinfo.dli_fbase;
3318 + assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
3321 + if (dladdr((void *)addr, &dlinfo) != 0) {
3322 + if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
3325 + return false;
3328 +void os::prepare_native_symbols() {
3331 +bool os::dll_address_to_function_name(address addr, char *buf,
3332 + int buflen, int * offset,
3333 + bool demangle) {
3334 + // buf is not optional, but offset is optional
3335 + assert(buf != NULL, "sanity check");
3337 + Dl_info dlinfo;
3339 +#ifdef _LP64
3340 + Elf64_Sym * info;
3341 +#else
3342 + Elf32_Sym * info;
3343 +#endif
3344 + if (dladdr1((void *)addr, &dlinfo, (void **)&info,
3345 + RTLD_DL_SYMENT) != 0) {
3346 + // see if we have a matching symbol that covers our address
3347 + if (dlinfo.dli_saddr != NULL &&
3348 + (char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
3349 + if (dlinfo.dli_sname != NULL) {
3350 + if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
3351 + jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
3353 + if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
3354 + return true;
3357 + // no matching symbol so try for just file info
3358 + if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
3359 + if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
3360 + buf, buflen, offset, dlinfo.dli_fname, demangle)) {
3361 + return true;
3365 + buf[0] = '\0';
3366 + if (offset != NULL) *offset = -1;
3367 + return false;
3370 +bool os::dll_address_to_library_name(address addr, char* buf,
3371 + int buflen, int* offset) {
3372 + // buf is not optional, but offset is optional
3373 + assert(buf != NULL, "sanity check");
3375 + Dl_info dlinfo;
3377 + if (dladdr((void*)addr, &dlinfo) != 0) {
3378 + if (dlinfo.dli_fname != NULL) {
3379 + jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
3381 + if (dlinfo.dli_fbase != NULL && offset != NULL) {
3382 + *offset = addr - (address)dlinfo.dli_fbase;
3384 + return true;
3387 + buf[0] = '\0';
3388 + if (offset) *offset = -1;
3389 + return false;
3392 +int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
3393 + Dl_info dli;
3394 + // Sanity check?
3395 + if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 ||
3396 + dli.dli_fname == NULL) {
3397 + return 1;
3400 + void * handle = dlopen(dli.dli_fname, RTLD_LAZY);
3401 + if (handle == NULL) {
3402 + return 1;
3405 + Link_map *map;
3406 + dlinfo(handle, RTLD_DI_LINKMAP, &map);
3407 + if (map == NULL) {
3408 + dlclose(handle);
3409 + return 1;
3412 + while (map->l_prev != NULL) {
3413 + map = map->l_prev;
3416 + while (map != NULL) {
3417 + // Iterate through all map entries and call callback with fields of interest
3418 + if(callback(map->l_name, (address)map->l_addr, (address)0, param)) {
3419 + dlclose(handle);
3420 + return 1;
3422 + map = map->l_next;
3425 + dlclose(handle);
3426 + return 0;
3429 +int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) {
3430 + outputStream * out = (outputStream *) param;
3431 + out->print_cr(INTPTR_FORMAT " \t%s", (intptr_t)base_address, name);
3432 + return 0;
3435 +void os::print_dll_info(outputStream * st) {
3436 + st->print_cr("Dynamic libraries:"); st->flush();
3437 + if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) {
3438 + st->print_cr("Error: Cannot print dynamic libraries.");
3442 +static void change_endianness(Elf32_Half& val) {
3443 + unsigned char *ptr = (unsigned char *)&val;
3444 + unsigned char swp = ptr[0];
3445 + ptr[0] = ptr[1];
3446 + ptr[1] = swp;
3449 +// Loads .dll/.so and
3450 +// in case of error it checks if .dll/.so was built for the
3451 +// same architecture as Hotspot is running on
3453 +void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
3454 + log_info(os)("attempting shared library load of %s", filename);
3456 + void * result= ::dlopen(filename, RTLD_LAZY);
3457 + if (result != NULL) {
3458 + // Successful loading
3459 + Events::log(NULL, "Loaded shared library %s", filename);
3460 + log_info(os)("shared library load of %s was successful", filename);
3461 + return result;
3464 + Elf32_Ehdr elf_head;
3465 + const char* error_report = ::dlerror();
3466 + if (error_report == NULL) {
3467 + error_report = "dlerror returned no error description";
3469 + if (ebuf != NULL && ebuflen > 0) {
3470 + ::strncpy(ebuf, error_report, ebuflen-1);
3471 + ebuf[ebuflen-1]='\0';
3474 + Events::log(NULL, "Loading shared library %s failed, %s", filename, error_report);
3475 + log_info(os)("shared library load of %s failed, %s", filename, error_report);
3477 + int diag_msg_max_length=ebuflen-strlen(ebuf);
3478 + char* diag_msg_buf=ebuf+strlen(ebuf);
3480 + if (diag_msg_max_length==0) {
3481 + // No more space in ebuf for additional diagnostics message
3482 + return NULL;
3486 + int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK);
3488 + if (file_descriptor < 0) {
3489 + // Can't open library, report dlerror() message
3490 + return NULL;
3493 + bool failed_to_read_elf_head=
3494 + (sizeof(elf_head)!=
3495 + (::read(file_descriptor, &elf_head,sizeof(elf_head))));
3497 + ::close(file_descriptor);
3498 + if (failed_to_read_elf_head) {
3499 + // file i/o error - report dlerror() msg
3500 + return NULL;
3503 + if (elf_head.e_ident[EI_DATA] != LITTLE_ENDIAN_ONLY(ELFDATA2LSB) BIG_ENDIAN_ONLY(ELFDATA2MSB)) {
3504 + // handle invalid/out of range endianness values
3505 + if (elf_head.e_ident[EI_DATA] == 0 || elf_head.e_ident[EI_DATA] > 2) {
3506 + return NULL;
3508 + change_endianness(elf_head.e_machine);
3511 + typedef struct {
3512 + Elf32_Half code; // Actual value as defined in elf.h
3513 + Elf32_Half compat_class; // Compatibility of archs at VM's sense
3514 + unsigned char elf_class; // 32 or 64 bit
3515 + unsigned char endianess; // MSB or LSB
3516 + char* name; // String representation
3517 + } arch_t;
3519 + static const arch_t arch_array[]={
3520 + {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
3521 + {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
3522 + {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"},
3523 + {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"},
3524 + {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
3525 + {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
3526 + {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
3527 + {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
3528 + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
3529 + {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
3530 + // we only support 64 bit z architecture
3531 + {EM_S390, EM_S390, ELFCLASS64, ELFDATA2MSB, (char*)"IBM System/390"},
3532 + {EM_AARCH64, EM_AARCH64, ELFCLASS64, ELFDATA2LSB, (char*)"AARCH64"}
3533 + };
3535 +#if (defined IA32)
3536 + static Elf32_Half running_arch_code=EM_386;
3537 +#elif (defined AMD64)
3538 + static Elf32_Half running_arch_code=EM_X86_64;
3539 +#elif (defined IA64)
3540 + static Elf32_Half running_arch_code=EM_IA_64;
3541 +#elif (defined __sparc) && (defined _LP64)
3542 + static Elf32_Half running_arch_code=EM_SPARCV9;
3543 +#elif (defined __sparc) && (!defined _LP64)
3544 + static Elf32_Half running_arch_code=EM_SPARC;
3545 +#elif (defined __powerpc64__)
3546 + static Elf32_Half running_arch_code=EM_PPC64;
3547 +#elif (defined __powerpc__)
3548 + static Elf32_Half running_arch_code=EM_PPC;
3549 +#elif (defined ARM)
3550 + static Elf32_Half running_arch_code=EM_ARM;
3551 +#else
3552 + #error Method os::dll_load requires that one of following is defined:\
3553 + IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM
3554 +#endif
3556 + // Identify compatibility class for VM's architecture and library's architecture
3557 + // Obtain string descriptions for architectures
3559 + arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL};
3560 + int running_arch_index=-1;
3562 + for (unsigned int i=0; i < ARRAY_SIZE(arch_array); i++) {
3563 + if (running_arch_code == arch_array[i].code) {
3564 + running_arch_index = i;
3566 + if (lib_arch.code == arch_array[i].code) {
3567 + lib_arch.compat_class = arch_array[i].compat_class;
3568 + lib_arch.name = arch_array[i].name;
3572 + assert(running_arch_index != -1,
3573 + "Didn't find running architecture code (running_arch_code) in arch_array");
3574 + if (running_arch_index == -1) {
3575 + // Even though running architecture detection failed
3576 + // we may still continue with reporting dlerror() message
3577 + return NULL;
3580 + if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) {
3581 + if (lib_arch.name != NULL) {
3582 + ::snprintf(diag_msg_buf, diag_msg_max_length-1,
3583 + " (Possible cause: can't load %s .so on a %s platform)",
3584 + lib_arch.name, arch_array[running_arch_index].name);
3585 + } else {
3586 + ::snprintf(diag_msg_buf, diag_msg_max_length-1,
3587 + " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)",
3588 + lib_arch.code, arch_array[running_arch_index].name);
3590 + return NULL;
3593 + if (lib_arch.endianess != arch_array[running_arch_index].endianess) {
3594 + ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)");
3595 + return NULL;
3598 + // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit
3599 + if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) {
3600 + ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)");
3601 + return NULL;
3604 + if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) {
3605 + ::snprintf(diag_msg_buf, diag_msg_max_length-1,
3606 + " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)",
3607 + (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32);
3608 + return NULL;
3611 + return NULL;
3614 +static inline time_t get_mtime(const char* filename) {
3615 + struct stat st;
3616 + int ret = os::stat(filename, &st);
3617 + assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno));
3618 + return st.st_mtime;
3621 +int os::compare_file_modified_times(const char* file1, const char* file2) {
3622 + time_t t1 = get_mtime(file1);
3623 + time_t t2 = get_mtime(file2);
3624 + return t1 - t2;
3627 +static bool _print_ascii_file(const char* filename, outputStream* st) {
3628 + int fd = ::open(filename, O_RDONLY);
3629 + if (fd == -1) {
3630 + return false;
3633 + char buf[32];
3634 + int bytes;
3635 + while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) {
3636 + st->print_raw(buf, bytes);
3639 + ::close(fd);
3641 + return true;
3644 +void os::print_os_info_brief(outputStream* st) {
3645 + os::Solaris::print_distro_info(st);
3647 + os::Posix::print_uname_info(st);
3649 + os::Solaris::print_libversion_info(st);
3652 +void os::print_os_info(outputStream* st) {
3653 + st->print("OS:");
3655 + os::Solaris::print_distro_info(st);
3657 + os::Posix::print_uname_info(st);
3659 + os::Posix::print_uptime_info(st);
3661 + os::Solaris::print_libversion_info(st);
3663 + os::Posix::print_rlimit_info(st);
3665 + os::Posix::print_load_average(st);
3668 +void os::Solaris::print_distro_info(outputStream* st) {
3669 + if (!_print_ascii_file("/etc/release", st)) {
3670 + st->print("Solaris");
3672 + st->cr();
3675 +void os::get_summary_os_info(char* buf, size_t buflen) {
3676 + strncpy(buf, "Solaris", buflen); // default to plain solaris
3677 + FILE* fp = fopen("/etc/release", "r");
3678 + if (fp != NULL) {
3679 + char tmp[256];
3680 + // Only get the first line and chop out everything but the os name.
3681 + if (fgets(tmp, sizeof(tmp), fp)) {
3682 + char* ptr = tmp;
3683 + // skip past whitespace characters
3684 + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++;
3685 + if (*ptr != '\0') {
3686 + char* nl = strchr(ptr, '\n');
3687 + if (nl != NULL) *nl = '\0';
3688 + strncpy(buf, ptr, buflen);
3691 + fclose(fp);
3695 +void os::Solaris::print_libversion_info(outputStream* st) {
3696 + st->print(" (T2 libthread)");
3697 + st->cr();
3700 +static bool check_addr0(outputStream* st) {
3701 + jboolean status = false;
3702 + const int read_chunk = 200;
3703 + int ret = 0;
3704 + int nmap = 0;
3705 + int fd = ::open("/proc/self/map",O_RDONLY);
3706 + if (fd >= 0) {
3707 + prmap_t *p = NULL;
3708 + char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t));
3709 + if (NULL == mbuff) {
3710 + ::close(fd);
3711 + return status;
3713 + while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) {
3714 + //check if read() has not read partial data
3715 + if( 0 != ret % sizeof(prmap_t)){
3716 + break;
3718 + nmap = ret / sizeof(prmap_t);
3719 + p = (prmap_t *)mbuff;
3720 + for(int i = 0; i < nmap; i++){
3721 + if (p->pr_vaddr == 0x0) {
3722 + st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024);
3723 + st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname);
3724 + st->print("Access: ");
3725 + st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-");
3726 + st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-");
3727 + st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-");
3728 + st->cr();
3729 + status = true;
3731 + p++;
3734 + free(mbuff);
3735 + ::close(fd);
3737 + return status;
3740 +void os::get_summary_cpu_info(char* buf, size_t buflen) {
3741 + // Get MHz with system call. We don't seem to already have this.
3742 + processor_info_t stats;
3743 + processorid_t id = getcpuid();
3744 + int clock = 0;
3745 + if (processor_info(id, &stats) != -1) {
3746 + clock = stats.pi_clock; // pi_processor_type isn't more informative than below
3748 + snprintf(buf, buflen, "64 bit %d MHz", clock);
3751 +void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
3752 + // Nothing to do for now.
3755 +void os::print_memory_info(outputStream* st) {
3756 + st->print("Memory:");
3757 + st->print(" " SIZE_FORMAT "k page", os::vm_page_size()>>10);
3758 + st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10);
3759 + st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10);
3760 + st->cr();
3761 + (void) check_addr0(st);
3764 +static int Maxsignum = 0;
3766 +static char saved_jvm_path[MAXPATHLEN] = { 0 };
3768 +// Find the full path to the current module, libjvm.so
3769 +void os::jvm_path(char *buf, jint buflen) {
3770 + // Error checking.
3771 + if (buflen < MAXPATHLEN) {
3772 + assert(false, "must use a large-enough buffer");
3773 + buf[0] = '\0';
3774 + return;
3776 + // Lazy resolve the path to current module.
3777 + if (saved_jvm_path[0] != 0) {
3778 + strcpy(buf, saved_jvm_path);
3779 + return;
3782 + Dl_info dlinfo;
3783 + int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
3784 + assert(ret != 0, "cannot locate libjvm");
3785 + if (ret != 0 && dlinfo.dli_fname != NULL) {
3786 + if (os::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) {
3787 + return;
3789 + } else {
3790 + buf[0] = '\0';
3791 + return;
3794 + if (Arguments::sun_java_launcher_is_altjvm()) {
3795 + // Support for the java launcher's '-XXaltjvm=<path>' option. Typical
3796 + // value for buf is "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so".
3797 + // If "/jre/lib/" appears at the right place in the string, then
3798 + // assume we are installed in a JDK and we're done. Otherwise, check
3799 + // for a JAVA_HOME environment variable and fix up the path so it
3800 + // looks like libjvm.so is installed there (append a fake suffix
3801 + // hotspot/libjvm.so).
3802 + const char *p = buf + strlen(buf) - 1;
3803 + for (int count = 0; p > buf && count < 5; ++count) {
3804 + for (--p; p > buf && *p != '/'; --p)
3805 + /* empty */ ;
3808 + if (strncmp(p, "/jre/lib/", 9) != 0) {
3809 + // Look for JAVA_HOME in the environment.
3810 + char* java_home_var = ::getenv("JAVA_HOME");
3811 + if (java_home_var != NULL && java_home_var[0] != 0) {
3812 + char* jrelib_p;
3813 + int len;
3815 + // Check the current module name "libjvm.so".
3816 + p = strrchr(buf, '/');
3817 + assert(strstr(p, "/libjvm") == p, "invalid library name");
3819 + if (os::realpath(java_home_var, buf, buflen) == NULL) {
3820 + return;
3822 + // determine if this is a legacy image or modules image
3823 + // modules image doesn't have "jre" subdirectory
3824 + len = strlen(buf);
3825 + assert(len < buflen, "Ran out of buffer space");
3826 + jrelib_p = buf + len;
3827 + snprintf(jrelib_p, buflen-len, "/jre/lib");
3828 + if (0 != access(buf, F_OK)) {
3829 + snprintf(jrelib_p, buflen-len, "/lib");
3832 + if (0 == access(buf, F_OK)) {
3833 + // Use current module name "libjvm.so"
3834 + len = strlen(buf);
3835 + snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
3836 + } else {
3837 + // Go back to path of .so
3838 + if (os::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) {
3839 + return;
3846 + strncpy(saved_jvm_path, buf, MAXPATHLEN);
3847 + saved_jvm_path[MAXPATHLEN - 1] = '\0';
3850 +////////////////////////////////////////////////////////////////////////////////
3851 +// Virtual Memory
3853 +static bool recoverable_mmap_error(int err) {
3854 + // See if the error is one we can let the caller handle. This
3855 + // list of errno values comes from the Solaris mmap(2) man page.
3856 + switch (err) {
3857 + case EBADF:
3858 + case EINVAL:
3859 + case ENOTSUP:
3860 + // let the caller deal with these errors
3861 + return true;
3863 + default:
3864 + // Any remaining errors on this OS can cause our reserved mapping
3865 + // to be lost. That can cause confusion where different data
3866 + // structures think they have the same memory mapped. The worst
3867 + // scenario is if both the VM and a library think they have the
3868 + // same memory mapped.
3869 + return false;
3873 +static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec,
3874 + int err) {
3875 + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
3876 + ", %d) failed; error='%s' (errno=%d)", p2i(addr), bytes, exec,
3877 + os::strerror(err), err);
3880 +static void warn_fail_commit_memory(char* addr, size_t bytes,
3881 + size_t alignment_hint, bool exec,
3882 + int err) {
3883 + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
3884 + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr),
3885 + bytes, alignment_hint, exec, os::strerror(err), err);
3888 +int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) {
3889 + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
3890 + size_t size = bytes;
3891 + char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot);
3892 + if (res != NULL) {
3893 + if (UseNUMAInterleaving) {
3894 + numa_make_global(addr, bytes);
3896 + return 0;
3897 + } else {
3898 + ErrnoPreserver ep;
3899 + log_trace(os, map)("mmap failed: " RANGEFMT " errno=(%s)",
3900 + RANGEFMTARGS(addr, size),
3901 + os::strerror(ep.saved_errno()));
3904 + int err = errno; // save errno from mmap() call in mmap_chunk()
3906 + if (!recoverable_mmap_error(err)) {
3907 + ErrnoPreserver ep;
3908 + log_trace(os, map)("mmap failed: " RANGEFMT " errno=(%s)",
3909 + RANGEFMTARGS(addr, size),
3910 + os::strerror(ep.saved_errno()));
3911 + warn_fail_commit_memory(addr, bytes, exec, err);
3912 + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory.");
3915 + return err;
3918 +bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) {
3919 + return Solaris::commit_memory_impl(addr, bytes, exec) == 0;
3922 +void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec,
3923 + const char* mesg) {
3924 + assert(mesg != NULL, "mesg must be specified");
3925 + int err = os::Solaris::commit_memory_impl(addr, bytes, exec);
3926 + if (err != 0) {
3927 + // the caller wants all commit errors to exit with the specified mesg:
3928 + warn_fail_commit_memory(addr, bytes, exec, err);
3929 + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg);
3933 +size_t os::Solaris::page_size_for_alignment(size_t alignment) {
3934 + assert(is_aligned(alignment, (size_t) os::vm_page_size()),
3935 + SIZE_FORMAT " is not aligned to " SIZE_FORMAT,
3936 + alignment, (size_t) os::vm_page_size());
3938 + const int page_sizes_max = 9;
3939 + size_t _illumos_page_sizes[page_sizes_max];
3940 + int n = getpagesizes(_illumos_page_sizes, page_sizes_max);
3941 + for (int i = 0; _illumos_page_sizes[i] != 0; i++) {
3942 + if (is_aligned(alignment, _illumos_page_sizes[i])) {
3943 + return _illumos_page_sizes[i];
3947 + return (size_t) os::vm_page_size();
3950 +int os::Solaris::commit_memory_impl(char* addr, size_t bytes,
3951 + size_t alignment_hint, bool exec) {
3952 + int err = Solaris::commit_memory_impl(addr, bytes, exec);
3953 + if (err == 0 && UseLargePages && alignment_hint > 0) {
3954 + assert(is_aligned(bytes, alignment_hint),
3955 + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint);
3957 + // The syscall memcntl requires an exact page size (see man memcntl for details).
3958 + size_t page_size = page_size_for_alignment(alignment_hint);
3959 + if (page_size > (size_t) os::vm_page_size()) {
3960 + (void)Solaris::setup_large_pages(addr, bytes, page_size);
3963 + return err;
3966 +bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint,
3967 + bool exec) {
3968 + return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0;
3971 +void os::pd_commit_memory_or_exit(char* addr, size_t bytes,
3972 + size_t alignment_hint, bool exec,
3973 + const char* mesg) {
3974 + assert(mesg != NULL, "mesg must be specified");
3975 + int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec);
3976 + if (err != 0) {
3977 + // the caller wants all commit errors to exit with the specified mesg:
3978 + warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err);
3979 + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg);
3983 +// Uncommit the pages in a specified region.
3984 +void os::pd_disclaim_memory(char* addr, size_t bytes) {
3985 + if (posix_madvise(addr, bytes, MADV_FREE) < 0) {
3986 + debug_only(warning("MADV_FREE failed."));
3987 + return;
3991 +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) {
3992 + return page_size;
3995 +bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
3996 + return os::commit_memory(addr, size, !ExecMem);
3999 +bool os::remove_stack_guard_pages(char* addr, size_t size) {
4000 + return os::uncommit_memory(addr, size);
4003 +// Change the page size in a given range.
4004 +void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
4005 + assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned.");
4006 + assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned.");
4007 + if (UseLargePages) {
4008 + size_t page_size = Solaris::page_size_for_alignment(alignment_hint);
4009 + if (page_size > (size_t) os::vm_page_size()) {
4010 + Solaris::setup_large_pages(addr, bytes, page_size);
4015 +// Tell the OS to make the range local to the first-touching LWP
4016 +void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
4017 + assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
4018 + if (posix_madvise(addr, bytes, MADV_ACCESS_LWP) < 0) {
4019 + debug_only(warning("MADV_ACCESS_LWP failed."));
4023 +// Tell the OS that this range would be accessed from different LWPs.
4024 +void os::numa_make_global(char *addr, size_t bytes) {
4025 + assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
4026 + if (posix_madvise(addr, bytes, MADV_ACCESS_MANY) < 0) {
4027 + debug_only(warning("MADV_ACCESS_MANY failed."));
4031 +// Get the number of the locality groups.
4032 +size_t os::numa_get_groups_num() {
4033 + size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie());
4034 + return n != -1 ? n : 1;
4037 +// Get a list of leaf locality groups. A leaf lgroup is group that
4038 +// doesn't have any children. Typical leaf group is a CPU or a CPU/memory
4039 +// board. An LWP is assigned to one of these groups upon creation.
4040 +size_t os::numa_get_leaf_groups(uint *ids, size_t size) {
4041 + if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) {
4042 + ids[0] = 0;
4043 + return 1;
4045 + int result_size = 0, top = 1, bottom = 0, cur = 0;
4046 + for (unsigned int k = 0; k < size; k++) {
4047 + int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur],
4048 + (Solaris::lgrp_id_t*)&ids[top], size - top);
4049 + if (r == -1) {
4050 + ids[0] = 0;
4051 + return 1;
4053 + if (!r) {
4054 + // That's a leaf node.
4055 + assert(bottom <= cur, "Sanity check");
4056 + // Check if the node has memory
4057 + if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur],
4058 + NULL, 0, LGRP_RSRC_MEM) > 0) {
4059 + ids[bottom++] = ids[cur];
4062 + top += r;
4063 + cur++;
4065 + if (bottom == 0) {
4066 + // Handle a situation, when the OS reports no memory available.
4067 + // Assume UMA architecture.
4068 + ids[0] = 0;
4069 + return 1;
4071 + return bottom;
4074 +// Detect the topology change. Typically happens during CPU plugging-unplugging.
4075 +bool os::numa_topology_changed() {
4076 + int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie());
4077 + if (is_stale != -1 && is_stale) {
4078 + Solaris::lgrp_fini(Solaris::lgrp_cookie());
4079 + Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER);
4080 + assert(c != 0, "Failure to initialize LGRP API");
4081 + Solaris::set_lgrp_cookie(c);
4082 + return true;
4084 + return false;
4087 +// Get the group id of the current LWP.
4088 +int os::numa_get_group_id() {
4089 + int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID);
4090 + if (lgrp_id == -1) {
4091 + return 0;
4093 + const int size = os::numa_get_groups_num();
4094 + int *ids = (int*)alloca(size * sizeof(int));
4096 + // Get the ids of all lgroups with memory; r is the count.
4097 + int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id,
4098 + (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM);
4099 + if (r <= 0) {
4100 + return 0;
4102 + return ids[os::random() % r];
4105 +int os::numa_get_group_id_for_address(const void* address) {
4106 + return 0;
4109 +bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) {
4110 + return false;
4113 +bool os::pd_uncommit_memory(char* addr, size_t bytes, bool exec) {
4114 + size_t size = bytes;
4115 + // Map uncommitted pages PROT_NONE so we fail early if we touch an
4116 + // uncommitted page. Otherwise, the read/write might succeed if we
4117 + // have enough swap space to back the physical page.
4118 + char *res = Solaris::mmap_chunk(addr, size,
4119 + MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE,
4120 + PROT_NONE);
4121 + if (res == NULL) {
4122 + ErrnoPreserver ep;
4123 + log_trace(os, map)("mmap failed: " RANGEFMT " errno=(%s)",
4124 + RANGEFMTARGS(addr, size),
4125 + os::strerror(ep.saved_errno()));
4126 + return false;
4128 + return true;
4131 +char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) {
4132 + char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0);
4134 + if (b == MAP_FAILED) {
4135 + return NULL;
4137 + return b;
4140 +char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes) {
4141 + char* addr = requested_addr;
4142 + int flags = MAP_PRIVATE | MAP_NORESERVE;
4144 + // Map uncommitted pages PROT_NONE so we fail early if we touch an
4145 + // uncommitted page. Otherwise, the read/write might succeed if we
4146 + // have enough swap space to back the physical page.
4147 + return mmap_chunk(addr, bytes, flags, PROT_NONE);
4150 +char* os::pd_reserve_memory(size_t bytes, bool exec) {
4151 + char* addr = Solaris::anon_mmap(NULL, bytes);
4153 + return addr;
4156 +char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
4157 + assert(file_desc >= 0, "file_desc is not valid");
4158 + char* result = pd_attempt_reserve_memory_at(requested_addr, bytes, !ExecMem);
4159 + if (result != NULL) {
4160 + if (replace_existing_mapping_with_file_mapping(result, bytes, file_desc) == NULL) {
4161 + vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory"));
4164 + return result;
4167 +// Reserve memory at an arbitrary address, only if that area is
4168 +// available (and not reserved for something else).
4170 +char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool exec) {
4171 + // Assert only that the size is a multiple of the page size, since
4172 + // that's all that mmap requires, and since that's all we really know
4173 + // about at this low abstraction level. If we need higher alignment,
4174 + // we can either pass an alignment to this method or verify alignment
4175 + // in one of the methods further up the call chain. See bug 5044738.
4176 + assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
4178 + // Since snv_84, Solaris attempts to honor the address hint - see 5003415.
4179 + char* addr = Solaris::anon_mmap(requested_addr, bytes);
4181 + volatile int err = errno;
4182 + if (addr == requested_addr) {
4183 + return addr;
4186 + if (addr != NULL) {
4187 + pd_unmap_memory(addr, bytes);
4190 + return NULL;
4193 +static int anon_munmap(char * addr, size_t size) {
4194 + if (::munmap(addr, size) != 0) {
4195 + ErrnoPreserver ep;
4196 + log_trace(os, map)("munmap failed: " RANGEFMT " errno=(%s)",
4197 + RANGEFMTARGS(addr, size),
4198 + os::strerror(ep.saved_errno()));
4199 + return 0;
4201 + return 1;
4204 +bool os::pd_release_memory(char* addr, size_t bytes) {
4205 + size_t size = bytes;
4206 + return anon_munmap(addr, size);
4209 +static bool solaris_mprotect(char* addr, size_t bytes, int prot) {
4210 + assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()),
4211 + "addr must be page aligned");
4212 + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot);
4213 + int retVal = mprotect(addr, bytes, prot);
4214 + return retVal == 0;
4217 +// Protect memory (Used to pass readonly pages through
4218 +// JNI GetArray<type>Elements with empty arrays.)
4219 +// Also, used for serialization page and for compressed oops null pointer
4220 +// checking.
4221 +bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
4222 + bool is_committed) {
4223 + unsigned int p = 0;
4224 + switch (prot) {
4225 + case MEM_PROT_NONE: p = PROT_NONE; break;
4226 + case MEM_PROT_READ: p = PROT_READ; break;
4227 + case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break;
4228 + case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
4229 + default:
4230 + ShouldNotReachHere();
4232 + // is_committed is unused.
4233 + return solaris_mprotect(addr, bytes, p);
4236 +// guard_memory and unguard_memory only happens within stack guard pages.
4237 +// Since ISM pertains only to the heap, guard and unguard memory should not
4238 +/// happen with an ISM region.
4239 +bool os::guard_memory(char* addr, size_t bytes) {
4240 + return solaris_mprotect(addr, bytes, PROT_NONE);
4243 +bool os::unguard_memory(char* addr, size_t bytes) {
4244 + return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE);
4247 +// Large page support
4248 +static size_t _large_page_size = 0;
4250 +bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) {
4251 + // Find the page sizes supported by the system
4252 + const int page_sizes_max = 9;
4253 + size_t _illumos_page_sizes[page_sizes_max];
4254 + int n = getpagesizes(_illumos_page_sizes, page_sizes_max);
4255 + assert(n > 0, "illumos bug?");
4257 + if (n == 1) return false; // Only one page size available.
4259 + // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set)
4260 + const size_t size_limit =
4261 + FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes;
4262 + int beg;
4263 + for (beg = 0; beg < n; ++beg) {
4264 + if (_illumos_page_sizes[beg] <= size_limit) {
4265 + _page_sizes.add(_illumos_page_sizes[beg]);
4266 + if (_illumos_page_sizes[beg] > *page_size) {
4267 + *page_size = _illumos_page_sizes[beg];
4271 + // make sure we add the default
4272 + _page_sizes.add(os::vm_page_size());
4273 + return true;
4276 +void os::large_page_init() {
4277 + if (UseLargePages) {
4278 + // print a warning if any large page related flag is specified on command line
4279 + bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
4280 + !FLAG_IS_DEFAULT(LargePageSizeInBytes);
4282 + UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size);
4286 +bool os::Solaris::is_valid_page_size(size_t bytes) {
4287 + return _page_sizes.contains(bytes);
4290 +bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
4291 + assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align);
4292 + assert(is_aligned((void*) start, align),
4293 + PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align);
4294 + assert(is_aligned(bytes, align),
4295 + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align);
4297 + // Signal to OS that we want large pages for addresses
4298 + // from addr, addr + bytes
4299 + struct memcntl_mha mpss_struct;
4300 + mpss_struct.mha_cmd = MHA_MAPSIZE_VA;
4301 + mpss_struct.mha_pagesize = align;
4302 + mpss_struct.mha_flags = 0;
4303 + // Upon successful completion, memcntl() returns 0
4304 + if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) {
4305 + debug_only(warning("Attempt to use MPSS failed."));
4306 + return false;
4308 + return true;
4311 +char* os::pd_reserve_memory_special(size_t size, size_t alignment, size_t page_size, char* addr, bool exec) {
4312 + fatal("os::reserve_memory_special should not be called on Solaris.");
4313 + return NULL;
4316 +bool os::pd_release_memory_special(char* base, size_t bytes) {
4317 + fatal("os::release_memory_special should not be called on Solaris.");
4318 + return false;
4321 +size_t os::large_page_size() {
4322 + return _large_page_size;
4325 +// MPSS allows application to commit large page memory on demand; with ISM
4326 +// the entire memory region must be allocated as shared memory.
4327 +bool os::can_commit_large_page_memory() {
4328 + return true;
4331 +size_t os::vm_min_address() {
4332 + return _vm_min_address_default;
4335 +// Interface for setting lwp priorities. We are using T2 libthread,
4336 +// which forces the use of bound threads, so all of our threads will
4337 +// be assigned to real lwp's. Using the thr_setprio function is
4338 +// meaningless in this mode so we must adjust the real lwp's priority.
4339 +// The routines below implement the getting and setting of lwp priorities.
4341 +// Note: There are three priority scales used on Solaris. Java priorities
4342 +// which range from 1 to 10, libthread "thr_setprio" scale which range
4343 +// from 0 to 127, and the current scheduling class of the process we
4344 +// are running in. This is typically from -60 to +60.
4345 +// The setting of the lwp priorities is done after a call to thr_setprio
4346 +// so Java priorities are mapped to libthread priorities and we map from
4347 +// the latter to lwp priorities. We don't keep priorities stored in
4348 +// Java priorities since some of our worker threads want to set priorities
4349 +// higher than all Java threads.
4351 +// For related information:
4352 +// (1) man -s 2 priocntl
4353 +// (2) man -s 4 priocntl
4354 +// (3) man dispadmin
4355 +// = librt.so
4356 +// = libthread/common/rtsched.c - thrp_setlwpprio().
4357 +// = ps -cL <pid> ... to validate priority.
4358 +// = sched_get_priority_min and _max
4359 +// pthread_create
4360 +// sched_setparam
4361 +// pthread_setschedparam
4363 +// Assumptions:
4364 +// + We assume that all threads in the process belong to the same
4365 +// scheduling class. IE. a homogeneous process.
4366 +// + Must be root or in IA group to change change "interactive" attribute.
4367 +// Priocntl() will fail silently. The only indication of failure is when
4368 +// we read-back the value and notice that it hasn't changed.
4369 +// + Interactive threads enter the runq at the head, non-interactive at the tail.
4370 +// + For RT, change timeslice as well. Invariant:
4371 +// constant "priority integral"
4372 +// Konst == TimeSlice * (60-Priority)
4373 +// Given a priority, compute appropriate timeslice.
4374 +// + Higher numerical values have higher priority.
4376 +// sched class attributes
4377 +typedef struct {
4378 + int schedPolicy; // classID
4379 + int maxPrio;
4380 + int minPrio;
4381 +} SchedInfo;
4384 +static SchedInfo tsLimits, iaLimits, rtLimits, fxLimits;
4386 +#ifdef ASSERT
4387 +static int ReadBackValidate = 1;
4388 +#endif
4389 +static int myClass = 0;
4390 +static int myMin = 0;
4391 +static int myMax = 0;
4392 +static int myCur = 0;
4393 +static bool priocntl_enable = false;
4395 +static const int criticalPrio = FXCriticalPriority;
4396 +static int java_MaxPriority_to_os_priority = 0; // Saved mapping
4399 +// lwp_priocntl_init
4401 +// Try to determine the priority scale for our process.
4403 +// Return errno or 0 if OK.
4405 +static int lwp_priocntl_init() {
4406 + int rslt;
4407 + pcinfo_t ClassInfo;
4408 + pcparms_t ParmInfo;
4409 + int i;
4411 + if (!UseThreadPriorities) return 0;
4413 + // If ThreadPriorityPolicy is 1, switch tables
4414 + if (ThreadPriorityPolicy == 1) {
4415 + for (i = 0; i < CriticalPriority+1; i++)
4416 + os::java_to_os_priority[i] = prio_policy1[i];
4418 + if (UseCriticalJavaThreadPriority) {
4419 + // MaxPriority always maps to the FX scheduling class and criticalPrio.
4420 + // See set_native_priority() and set_lwp_class_and_priority().
4421 + // Save original MaxPriority mapping in case attempt to
4422 + // use critical priority fails.
4423 + java_MaxPriority_to_os_priority = os::java_to_os_priority[MaxPriority];
4424 + // Set negative to distinguish from other priorities
4425 + os::java_to_os_priority[MaxPriority] = -criticalPrio;
4428 + // Get IDs for a set of well-known scheduling classes.
4429 + // TODO-FIXME: GETCLINFO returns the current # of classes in the
4430 + // the system. We should have a loop that iterates over the
4431 + // classID values, which are known to be "small" integers.
4433 + strcpy(ClassInfo.pc_clname, "TS");
4434 + ClassInfo.pc_cid = -1;
4435 + rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
4436 + if (rslt < 0) return errno;
4437 + assert(ClassInfo.pc_cid != -1, "cid for TS class is -1");
4438 + tsLimits.schedPolicy = ClassInfo.pc_cid;
4439 + tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri;
4440 + tsLimits.minPrio = -tsLimits.maxPrio;
4442 + strcpy(ClassInfo.pc_clname, "IA");
4443 + ClassInfo.pc_cid = -1;
4444 + rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
4445 + if (rslt < 0) return errno;
4446 + assert(ClassInfo.pc_cid != -1, "cid for IA class is -1");
4447 + iaLimits.schedPolicy = ClassInfo.pc_cid;
4448 + iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri;
4449 + iaLimits.minPrio = -iaLimits.maxPrio;
4451 + strcpy(ClassInfo.pc_clname, "RT");
4452 + ClassInfo.pc_cid = -1;
4453 + rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
4454 + if (rslt < 0) return errno;
4455 + assert(ClassInfo.pc_cid != -1, "cid for RT class is -1");
4456 + rtLimits.schedPolicy = ClassInfo.pc_cid;
4457 + rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri;
4458 + rtLimits.minPrio = 0;
4460 + strcpy(ClassInfo.pc_clname, "FX");
4461 + ClassInfo.pc_cid = -1;
4462 + rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
4463 + if (rslt < 0) return errno;
4464 + assert(ClassInfo.pc_cid != -1, "cid for FX class is -1");
4465 + fxLimits.schedPolicy = ClassInfo.pc_cid;
4466 + fxLimits.maxPrio = ((fxinfo_t*)ClassInfo.pc_clinfo)->fx_maxupri;
4467 + fxLimits.minPrio = 0;
4469 + // Query our "current" scheduling class.
4470 + // This will normally be IA, TS or, rarely, FX or RT.
4471 + memset(&ParmInfo, 0, sizeof(ParmInfo));
4472 + ParmInfo.pc_cid = PC_CLNULL;
4473 + rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
4474 + if (rslt < 0) return errno;
4475 + myClass = ParmInfo.pc_cid;
4477 + // We now know our scheduling classId, get specific information
4478 + // about the class.
4479 + ClassInfo.pc_cid = myClass;
4480 + ClassInfo.pc_clname[0] = 0;
4481 + rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo);
4482 + if (rslt < 0) return errno;
4484 + memset(&ParmInfo, 0, sizeof(pcparms_t));
4485 + ParmInfo.pc_cid = PC_CLNULL;
4486 + rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
4487 + if (rslt < 0) return errno;
4489 + if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
4490 + myMin = rtLimits.minPrio;
4491 + myMax = rtLimits.maxPrio;
4492 + } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
4493 + iaparms_t *iaInfo = (iaparms_t*)ParmInfo.pc_clparms;
4494 + myMin = iaLimits.minPrio;
4495 + myMax = iaLimits.maxPrio;
4496 + myMax = MIN2(myMax, (int)iaInfo->ia_uprilim); // clamp - restrict
4497 + } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
4498 + tsparms_t *tsInfo = (tsparms_t*)ParmInfo.pc_clparms;
4499 + myMin = tsLimits.minPrio;
4500 + myMax = tsLimits.maxPrio;
4501 + myMax = MIN2(myMax, (int)tsInfo->ts_uprilim); // clamp - restrict
4502 + } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) {
4503 + fxparms_t *fxInfo = (fxparms_t*)ParmInfo.pc_clparms;
4504 + myMin = fxLimits.minPrio;
4505 + myMax = fxLimits.maxPrio;
4506 + myMax = MIN2(myMax, (int)fxInfo->fx_uprilim); // clamp - restrict
4507 + } else {
4508 + return EINVAL; // no clue, punt
4511 + priocntl_enable = true; // Enable changing priorities
4512 + return 0;
4515 +#define IAPRI(x) ((iaparms_t *)((x).pc_clparms))
4516 +#define RTPRI(x) ((rtparms_t *)((x).pc_clparms))
4517 +#define TSPRI(x) ((tsparms_t *)((x).pc_clparms))
4518 +#define FXPRI(x) ((fxparms_t *)((x).pc_clparms))
4521 +// scale_to_lwp_priority
4523 +// Convert from the libthread "thr_setprio" scale to our current
4524 +// lwp scheduling class scale.
4526 +static int scale_to_lwp_priority(int rMin, int rMax, int x) {
4527 + int v;
4529 + if (x == 127) return rMax; // avoid round-down
4530 + v = (((x*(rMax-rMin)))/128)+rMin;
4531 + return v;
4535 +// set_lwp_class_and_priority
4536 +int set_lwp_class_and_priority(int ThreadID, int lwpid,
4537 + int newPrio, int new_class, bool scale) {
4538 + int rslt;
4539 + int Actual, Expected, prv;
4540 + pcparms_t ParmInfo; // for GET-SET
4541 +#ifdef ASSERT
4542 + pcparms_t ReadBack; // for readback
4543 +#endif
4545 + // Set priority via PC_GETPARMS, update, PC_SETPARMS
4546 + // Query current values.
4547 + // TODO: accelerate this by eliminating the PC_GETPARMS call.
4548 + // Cache "pcparms_t" in global ParmCache.
4549 + // TODO: elide set-to-same-value
4551 + // If something went wrong on init, don't change priorities.
4552 + if (!priocntl_enable) {
4553 + return EINVAL;
4556 + // If lwp hasn't started yet, just return
4557 + // the _start routine will call us again.
4558 + if (lwpid <= 0) {
4559 + return 0;
4562 + memset(&ParmInfo, 0, sizeof(pcparms_t));
4563 + ParmInfo.pc_cid = PC_CLNULL;
4564 + rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo);
4565 + if (rslt < 0) return errno;
4567 + int cur_class = ParmInfo.pc_cid;
4568 + ParmInfo.pc_cid = (id_t)new_class;
4570 + if (new_class == rtLimits.schedPolicy) {
4571 + rtparms_t *rtInfo = (rtparms_t*)ParmInfo.pc_clparms;
4572 + rtInfo->rt_pri = scale ? scale_to_lwp_priority(rtLimits.minPrio,
4573 + rtLimits.maxPrio, newPrio)
4574 + : newPrio;
4575 + rtInfo->rt_tqsecs = RT_NOCHANGE;
4576 + rtInfo->rt_tqnsecs = RT_NOCHANGE;
4577 + } else if (new_class == iaLimits.schedPolicy) {
4578 + iaparms_t* iaInfo = (iaparms_t*)ParmInfo.pc_clparms;
4579 + int maxClamped = MIN2(iaLimits.maxPrio,
4580 + cur_class == new_class
4581 + ? (int)iaInfo->ia_uprilim : iaLimits.maxPrio);
4582 + iaInfo->ia_upri = scale ? scale_to_lwp_priority(iaLimits.minPrio,
4583 + maxClamped, newPrio)
4584 + : newPrio;
4585 + iaInfo->ia_uprilim = cur_class == new_class
4586 + ? IA_NOCHANGE : (pri_t)iaLimits.maxPrio;
4587 + iaInfo->ia_mode = IA_NOCHANGE;
4588 + } else if (new_class == tsLimits.schedPolicy) {
4589 + tsparms_t* tsInfo = (tsparms_t*)ParmInfo.pc_clparms;
4590 + int maxClamped = MIN2(tsLimits.maxPrio,
4591 + cur_class == new_class
4592 + ? (int)tsInfo->ts_uprilim : tsLimits.maxPrio);
4593 + tsInfo->ts_upri = scale ? scale_to_lwp_priority(tsLimits.minPrio,
4594 + maxClamped, newPrio)
4595 + : newPrio;
4596 + tsInfo->ts_uprilim = cur_class == new_class
4597 + ? TS_NOCHANGE : (pri_t)tsLimits.maxPrio;
4598 + } else if (new_class == fxLimits.schedPolicy) {
4599 + fxparms_t* fxInfo = (fxparms_t*)ParmInfo.pc_clparms;
4600 + int maxClamped = MIN2(fxLimits.maxPrio,
4601 + cur_class == new_class
4602 + ? (int)fxInfo->fx_uprilim : fxLimits.maxPrio);
4603 + fxInfo->fx_upri = scale ? scale_to_lwp_priority(fxLimits.minPrio,
4604 + maxClamped, newPrio)
4605 + : newPrio;
4606 + fxInfo->fx_uprilim = cur_class == new_class
4607 + ? FX_NOCHANGE : (pri_t)fxLimits.maxPrio;
4608 + fxInfo->fx_tqsecs = FX_NOCHANGE;
4609 + fxInfo->fx_tqnsecs = FX_NOCHANGE;
4610 + } else {
4611 + return EINVAL; // no clue, punt
4614 + rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo);
4615 + if (rslt < 0) return errno;
4617 +#ifdef ASSERT
4618 + // Sanity check: read back what we just attempted to set.
4619 + // In theory it could have changed in the interim ...
4620 + //
4621 + // The priocntl system call is tricky.
4622 + // Sometimes it'll validate the priority value argument and
4623 + // return EINVAL if unhappy. At other times it fails silently.
4624 + // Readbacks are prudent.
4626 + if (!ReadBackValidate) return 0;
4628 + memset(&ReadBack, 0, sizeof(pcparms_t));
4629 + ReadBack.pc_cid = PC_CLNULL;
4630 + rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack);
4631 + assert(rslt >= 0, "priocntl failed");
4632 + Actual = Expected = 0xBAD;
4633 + assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match");
4634 + if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
4635 + Actual = RTPRI(ReadBack)->rt_pri;
4636 + Expected = RTPRI(ParmInfo)->rt_pri;
4637 + } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
4638 + Actual = IAPRI(ReadBack)->ia_upri;
4639 + Expected = IAPRI(ParmInfo)->ia_upri;
4640 + } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
4641 + Actual = TSPRI(ReadBack)->ts_upri;
4642 + Expected = TSPRI(ParmInfo)->ts_upri;
4643 + } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) {
4644 + Actual = FXPRI(ReadBack)->fx_upri;
4645 + Expected = FXPRI(ParmInfo)->fx_upri;
4647 +#endif
4649 + return 0;
4652 +// Solaris only gives access to 128 real priorities at a time,
4653 +// so we expand Java's ten to fill this range. This would be better
4654 +// if we dynamically adjusted relative priorities.
4656 +// The ThreadPriorityPolicy option allows us to select 2 different
4657 +// priority scales.
4659 +// ThreadPriorityPolicy=0
4660 +// Since the Solaris' default priority is MaximumPriority, we do not
4661 +// set a priority lower than Max unless a priority lower than
4662 +// NormPriority is requested.
4664 +// ThreadPriorityPolicy=1
4665 +// This mode causes the priority table to get filled with
4666 +// linear values. NormPriority gets mapped to 50% of the
4667 +// Maximum priority and so on. This will cause VM threads
4668 +// to get unfair treatment against other Solaris processes
4669 +// which do not explicitly alter their thread priorities.
4671 +int os::java_to_os_priority[CriticalPriority + 1] = {
4672 + -99999, // 0 Entry should never be used
4674 + 0, // 1 MinPriority
4675 + 32, // 2
4676 + 64, // 3
4678 + 96, // 4
4679 + 127, // 5 NormPriority
4680 + 127, // 6
4682 + 127, // 7
4683 + 127, // 8
4684 + 127, // 9 NearMaxPriority
4686 + 127, // 10 MaxPriority
4688 + -criticalPrio // 11 CriticalPriority
4691 +OSReturn os::set_native_priority(Thread* thread, int newpri) {
4692 + OSThread* osthread = thread->osthread();
4694 + // Save requested priority in case the thread hasn't been started
4695 + osthread->set_native_priority(newpri);
4697 + // Check for critical priority request
4698 + bool fxcritical = false;
4699 + if (newpri == -criticalPrio) {
4700 + fxcritical = true;
4701 + newpri = criticalPrio;
4704 + assert(newpri >= MinimumPriority && newpri <= MaximumPriority, "bad priority mapping");
4705 + if (!UseThreadPriorities) return OS_OK;
4707 + int status = 0;
4709 + if (!fxcritical) {
4710 + // Use thr_setprio only if we have a priority that thr_setprio understands
4711 + status = thr_setprio(thread->osthread()->thread_id(), newpri);
4714 + int lwp_status =
4715 + set_lwp_class_and_priority(osthread->thread_id(),
4716 + osthread->lwp_id(),
4717 + newpri,
4718 + fxcritical ? fxLimits.schedPolicy : myClass,
4719 + !fxcritical);
4720 + if (lwp_status != 0 && fxcritical) {
4721 + // Try again, this time without changing the scheduling class
4722 + newpri = java_MaxPriority_to_os_priority;
4723 + lwp_status = set_lwp_class_and_priority(osthread->thread_id(),
4724 + osthread->lwp_id(),
4725 + newpri, myClass, false);
4727 + status |= lwp_status;
4728 + return (status == 0) ? OS_OK : OS_ERR;
4732 +OSReturn os::get_native_priority(const Thread* const thread,
4733 + int *priority_ptr) {
4734 + int p;
4735 + if (!UseThreadPriorities) {
4736 + *priority_ptr = NormalPriority;
4737 + return OS_OK;
4739 + int status = thr_getprio(thread->osthread()->thread_id(), &p);
4740 + if (status != 0) {
4741 + return OS_ERR;
4743 + *priority_ptr = p;
4744 + return OS_OK;
4747 +////////////////////////////////////////////////////////////////////////////////
4749 +// This does not do anything on Solaris. This is basically a hook for being
4750 +// able to use structured exception handling (thread-local exception filters) on, e.g., Win32.
4751 +void os::os_exception_wrapper(java_call_t f, JavaValue* value,
4752 + const methodHandle& method, JavaCallArguments* args,
4753 + JavaThread* thread) {
4754 + f(value, method, args, thread);
4757 +void report_error(const char* file_name, int line_no, const char* title,
4758 + const char* format, ...);
4760 +// (Static) wrappers for the liblgrp API
4761 +os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home;
4762 +os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init;
4763 +os::Solaris::lgrp_fini_func_t os::Solaris::_lgrp_fini;
4764 +os::Solaris::lgrp_root_func_t os::Solaris::_lgrp_root;
4765 +os::Solaris::lgrp_children_func_t os::Solaris::_lgrp_children;
4766 +os::Solaris::lgrp_resources_func_t os::Solaris::_lgrp_resources;
4767 +os::Solaris::lgrp_nlgrps_func_t os::Solaris::_lgrp_nlgrps;
4768 +os::Solaris::lgrp_cookie_stale_func_t os::Solaris::_lgrp_cookie_stale;
4769 +os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0;
4771 +static address resolve_symbol_lazy(const char* name) {
4772 + address addr = (address) dlsym(RTLD_DEFAULT, name);
4773 + if (addr == NULL) {
4774 + // RTLD_DEFAULT was not defined on some early versions of 2.5.1
4775 + addr = (address) dlsym(RTLD_NEXT, name);
4777 + return addr;
4780 +static address resolve_symbol(const char* name) {
4781 + address addr = resolve_symbol_lazy(name);
4782 + if (addr == NULL) {
4783 + fatal("resolve_symbol failed (%s)", dlerror());
4785 + return addr;
4788 +void os::Solaris::libthread_init() {
4789 + address func = (address)dlsym(RTLD_DEFAULT, "_thr_suspend_allmutators");
4791 + lwp_priocntl_init();
4793 + // RTLD_DEFAULT was not defined on some early versions of 5.5.1
4794 + if (func == NULL) {
4795 + func = (address) dlsym(RTLD_NEXT, "_thr_suspend_allmutators");
4796 + // Guarantee that this VM is running on an new enough OS (5.6 or
4797 + // later) that it will have a new enough libthread.so.
4798 + guarantee(func != NULL, "libthread.so is too old.");
4801 + int size;
4802 + void (*handler_info_func)(address *, int *);
4803 + handler_info_func = CAST_TO_FN_PTR(void (*)(address *, int *), resolve_symbol("thr_sighndlrinfo"));
4804 + handler_info_func(&handler_start, &size);
4805 + handler_end = handler_start + size;
4809 +bool os::Solaris::_synchronization_initialized;
4811 +void os::Solaris::synchronization_init() {
4812 + _synchronization_initialized = true;
4815 +bool os::Solaris::liblgrp_init() {
4816 + void *handle = dlopen("liblgrp.so.1", RTLD_LAZY);
4817 + if (handle != NULL) {
4818 + os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home")));
4819 + os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init")));
4820 + os::Solaris::set_lgrp_fini(CAST_TO_FN_PTR(lgrp_fini_func_t, dlsym(handle, "lgrp_fini")));
4821 + os::Solaris::set_lgrp_root(CAST_TO_FN_PTR(lgrp_root_func_t, dlsym(handle, "lgrp_root")));
4822 + os::Solaris::set_lgrp_children(CAST_TO_FN_PTR(lgrp_children_func_t, dlsym(handle, "lgrp_children")));
4823 + os::Solaris::set_lgrp_resources(CAST_TO_FN_PTR(lgrp_resources_func_t, dlsym(handle, "lgrp_resources")));
4824 + os::Solaris::set_lgrp_nlgrps(CAST_TO_FN_PTR(lgrp_nlgrps_func_t, dlsym(handle, "lgrp_nlgrps")));
4825 + os::Solaris::set_lgrp_cookie_stale(CAST_TO_FN_PTR(lgrp_cookie_stale_func_t,
4826 + dlsym(handle, "lgrp_cookie_stale")));
4828 + lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER);
4829 + set_lgrp_cookie(c);
4830 + return true;
4832 + return false;
4835 +int os::Solaris::_dev_zero_fd = -1;
4837 +// this is called _before_ the global arguments have been parsed
4838 +void os::init(void) {
4839 + _initial_pid = getpid();
4841 + max_hrtime = first_hrtime = gethrtime();
4843 + init_random(1234567);
4845 + int page_size = sysconf(_SC_PAGESIZE);
4846 + OSInfo::set_vm_page_size(page_size);
4847 + OSInfo::set_vm_allocation_granularity(page_size);
4848 + if (os::vm_page_size() <= 0) {
4849 + fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno));
4851 + _page_sizes.add(os::vm_page_size());
4853 + Solaris::initialize_system_info();
4855 + int fd = ::open("/dev/zero", O_RDWR);
4856 + if (fd < 0) {
4857 + fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno));
4858 + } else {
4859 + Solaris::set_dev_zero_fd(fd);
4861 + // Close on exec, child won't inherit.
4862 + fcntl(fd, F_SETFD, FD_CLOEXEC);
4865 + clock_tics_per_sec = CLK_TCK;
4867 + // main_thread points to the thread that created/loaded the JVM.
4868 + main_thread = thr_self();
4870 + // dynamic lookup of functions that may not be available in our lowest
4871 + // supported Solaris release
4872 + void * handle = dlopen("libc.so.1", RTLD_LAZY);
4873 + if (handle != NULL) {
4874 + Solaris::_pthread_setname_np = // from 11.3
4875 + (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np");
4878 + // Shared Posix initialization
4879 + os::Posix::init();
4882 +// To install functions for atexit system call
4883 +extern "C" {
4884 + static void perfMemory_exit_helper() {
4885 + perfMemory_exit();
4889 +// this is called _after_ the global arguments have been parsed
4890 +jint os::init_2(void) {
4891 + Solaris::libthread_init();
4893 + if (UseNUMA) {
4894 + if (!Solaris::liblgrp_init()) {
4895 + FLAG_SET_ERGO(UseNUMA, false);
4896 + } else {
4897 + size_t lgrp_limit = os::numa_get_groups_num();
4898 + uint *lgrp_ids = NEW_C_HEAP_ARRAY(uint, lgrp_limit, mtInternal);
4899 + size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);
4900 + FREE_C_HEAP_ARRAY(uint, lgrp_ids);
4901 + if (lgrp_num < 2) {
4902 + // There's only one locality group, disable NUMA
4903 + UseNUMA = false;
4908 + // When NUMA requested, not-NUMA-aware allocations default to interleaving.
4909 + if (UseNUMA && !UseNUMAInterleaving) {
4910 + FLAG_SET_ERGO_IF_DEFAULT(UseNUMAInterleaving, true);
4913 + if (PosixSignals::init() == JNI_ERR) {
4914 + return JNI_ERR;
4917 + // initialize synchronization primitives
4918 + Solaris::synchronization_init();
4919 + DEBUG_ONLY(os::set_mutex_init_done();)
4921 + if (MaxFDLimit) {
4922 + // set the number of file descriptors to max. print out error
4923 + // if getrlimit/setrlimit fails but continue regardless.
4924 + struct rlimit nbr_files;
4925 + int status = getrlimit(RLIMIT_NOFILE, &nbr_files);
4926 + if (status != 0) {
4927 + log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno));
4928 + } else {
4929 + nbr_files.rlim_cur = nbr_files.rlim_max;
4930 + status = setrlimit(RLIMIT_NOFILE, &nbr_files);
4931 + if (status != 0) {
4932 + log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno));
4937 + // Calculate theoretical max. size of Threads to guard gainst
4938 + // artificial out-of-memory situations, where all available address-
4939 + // space has been reserved by thread stacks. Default stack size is 1Mb.
4940 + size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ?
4941 + JavaThread::stack_size_at_create() : (1*K*K);
4942 + assert(pre_thread_stack_size != 0, "Must have a stack");
4943 + // Solaris has a maximum of 4Gb of user programs. Calculate the thread limit when
4944 + // we should start doing Virtual Memory banging. Currently when the threads will
4945 + // have used all but 200Mb of space.
4946 + size_t max_address_space = ((unsigned int)4 * K * K * K) - (200 * K * K);
4947 + Solaris::_os_thread_limit = max_address_space / pre_thread_stack_size;
4949 + // at-exit methods are called in the reverse order of their registration.
4950 + // In Solaris 7 and earlier, atexit functions are called on return from
4951 + // main or as a result of a call to exit(3C). There can be only 32 of
4952 + // these functions registered and atexit() does not set errno. In Solaris
4953 + // 8 and later, there is no limit to the number of functions registered
4954 + // and atexit() sets errno. In addition, in Solaris 8 and later, atexit
4955 + // functions are called upon dlclose(3DL) in addition to return from main
4956 + // and exit(3C).
4958 + if (PerfAllowAtExitRegistration) {
4959 + // only register atexit functions if PerfAllowAtExitRegistration is set.
4960 + // atexit functions can be delayed until process exit time, which
4961 + // can be problematic for embedded VM situations. Embedded VMs should
4962 + // call DestroyJavaVM() to assure that VM resources are released.
4964 + // note: perfMemory_exit_helper atexit function may be removed in
4965 + // the future if the appropriate cleanup code can be added to the
4966 + // VM_Exit VMOperation's doit method.
4967 + if (atexit(perfMemory_exit_helper) != 0) {
4968 + warning("os::init2 atexit(perfMemory_exit_helper) failed");
4972 + // Shared Posix initialization
4973 + os::Posix::init_2();
4975 + return JNI_OK;
4978 +// This code originates from JDK's sysOpen and open64_w
4979 +// from src/solaris/hpi/src/system_md.c
4981 +int os::open(const char *path, int oflag, int mode) {
4982 + if (strlen(path) > MAX_PATH - 1) {
4983 + errno = ENAMETOOLONG;
4984 + return -1;
4986 + int fd;
4988 + fd = ::open64(path, oflag, mode);
4989 + if (fd == -1) return -1;
4991 + // If the open succeeded, the file might still be a directory
4993 + struct stat64 buf64;
4994 + int ret = ::fstat64(fd, &buf64);
4995 + int st_mode = buf64.st_mode;
4997 + if (ret != -1) {
4998 + if ((st_mode & S_IFMT) == S_IFDIR) {
4999 + errno = EISDIR;
5000 + ::close(fd);
5001 + return -1;
5003 + } else {
5004 + ::close(fd);
5005 + return -1;
5009 + // All file descriptors that are opened in the JVM and not
5010 + // specifically destined for a subprocess should have the
5011 + // close-on-exec flag set. If we don't set it, then careless 3rd
5012 + // party native code might fork and exec without closing all
5013 + // appropriate file descriptors (e.g. as we do in closeDescriptors in
5014 + // UNIXProcess.c), and this in turn might:
5015 + //
5016 + // - cause end-of-file to fail to be detected on some file
5017 + // descriptors, resulting in mysterious hangs, or
5018 + //
5019 + // - might cause an fopen in the subprocess to fail on a system
5020 + // suffering from bug 1085341.
5021 + //
5022 + // (Yes, the default setting of the close-on-exec flag is a Unix
5023 + // design flaw)
5024 + //
5025 + // See:
5026 + // 1085341: 32-bit stdio routines should support file descriptors >255
5027 + // 4843136: (process) pipe file descriptor from Runtime.exec not being closed
5028 + // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9
5029 + //
5030 +#ifdef FD_CLOEXEC
5032 + int flags = ::fcntl(fd, F_GETFD);
5033 + if (flags != -1) {
5034 + ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
5037 +#endif
5039 + return fd;
5042 +const intptr_t thr_time_off = (intptr_t)(&((prusage_t *)(NULL))->pr_utime);
5043 +const intptr_t thr_time_size = (intptr_t)(&((prusage_t *)(NULL))->pr_ttime) -
5044 + (intptr_t)(&((prusage_t *)(NULL))->pr_utime);
5047 +// JVMTI & JVM monitoring and management support
5048 +// The thread_cpu_time() and current_thread_cpu_time() are only
5049 +// supported if is_thread_cpu_time_supported() returns true.
5050 +// They are not supported on Solaris T1.
5052 +// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
5053 +// are used by JVM M&M and JVMTI to get user+sys or user CPU time
5054 +// of a thread.
5056 +// current_thread_cpu_time() and thread_cpu_time(Thread *)
5057 +// returns the fast estimate available on the platform.
5059 +// hrtime_t gethrvtime() return value includes
5060 +// user time but does not include system time
5061 +jlong os::current_thread_cpu_time() {
5062 + return (jlong) gethrvtime();
5065 +jlong os::thread_cpu_time(Thread *thread) {
5066 + // return user level CPU time only to be consistent with
5067 + // what current_thread_cpu_time returns.
5068 + // thread_cpu_time_info() must be changed if this changes
5069 + return os::thread_cpu_time(thread, false /* user time only */);
5072 +jlong os::current_thread_cpu_time(bool user_sys_cpu_time) {
5073 + if (user_sys_cpu_time) {
5074 + return os::thread_cpu_time(Thread::current(), user_sys_cpu_time);
5075 + } else {
5076 + return os::current_thread_cpu_time();
5080 +jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
5081 + char proc_name[64];
5082 + int count;
5083 + prusage_t prusage;
5084 + jlong lwp_time;
5085 + int fd;
5087 + sprintf(proc_name, "/proc/%d/lwp/%d/lwpusage",
5088 + getpid(),
5089 + thread->osthread()->lwp_id());
5090 + fd = ::open(proc_name, O_RDONLY);
5091 + if (fd == -1) return -1;
5093 + do {
5094 + count = ::pread(fd,
5095 + (void *)&prusage.pr_utime,
5096 + thr_time_size,
5097 + thr_time_off);
5098 + } while (count < 0 && errno == EINTR);
5099 + ::close(fd);
5100 + if (count < 0) return -1;
5102 + if (user_sys_cpu_time) {
5103 + // user + system CPU time
5104 + lwp_time = (((jlong)prusage.pr_stime.tv_sec +
5105 + (jlong)prusage.pr_utime.tv_sec) * (jlong)1000000000) +
5106 + (jlong)prusage.pr_stime.tv_nsec +
5107 + (jlong)prusage.pr_utime.tv_nsec;
5108 + } else {
5109 + // user level CPU time only
5110 + lwp_time = ((jlong)prusage.pr_utime.tv_sec * (jlong)1000000000) +
5111 + (jlong)prusage.pr_utime.tv_nsec;
5114 + return (lwp_time);
5117 +void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
5118 + info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
5119 + info_ptr->may_skip_backward = false; // elapsed time not wall time
5120 + info_ptr->may_skip_forward = false; // elapsed time not wall time
5121 + info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned
5124 +void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
5125 + info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
5126 + info_ptr->may_skip_backward = false; // elapsed time not wall time
5127 + info_ptr->may_skip_forward = false; // elapsed time not wall time
5128 + info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned
5131 +bool os::is_thread_cpu_time_supported() {
5132 + return true;
5135 +// System loadavg support. Returns -1 if load average cannot be obtained.
5136 +// Return the load average for our processor set.
5137 +int os::loadavg(double loadavg[], int nelem) {
5138 + return pset_getloadavg(PS_MYID, loadavg, nelem);
5141 +//---------------------------------------------------------------------------------
5143 +bool os::find(address addr, outputStream* st) {
5144 + Dl_info dlinfo;
5145 + memset(&dlinfo, 0, sizeof(dlinfo));
5146 + if (dladdr(addr, &dlinfo) != 0) {
5147 + st->print(PTR_FORMAT ": ", p2i(addr));
5148 + if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) {
5149 + st->print("%s+" PTR_FORMAT, dlinfo.dli_sname,
5150 + p2i(addr) - p2i(dlinfo.dli_saddr));
5151 + } else if (dlinfo.dli_fbase != NULL) {
5152 + st->print("<offset " PTR_FORMAT ">", p2i(addr) - p2i(dlinfo.dli_fbase));
5153 + } else {
5154 + st->print("<absolute address>");
5156 + if (dlinfo.dli_fname != NULL) {
5157 + st->print(" in %s", dlinfo.dli_fname);
5159 + if (dlinfo.dli_fbase != NULL) {
5160 + st->print(" at " PTR_FORMAT, p2i(dlinfo.dli_fbase));
5162 + st->cr();
5164 + if (Verbose) {
5165 + // decode some bytes around the PC
5166 + address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size());
5167 + address end = clamp_address_in_page(addr+40, addr, os::vm_page_size());
5168 + address lowest = (address) dlinfo.dli_sname;
5169 + if (!lowest) lowest = (address) dlinfo.dli_fbase;
5170 + if (begin < lowest) begin = lowest;
5171 + Dl_info dlinfo2;
5172 + if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr
5173 + && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) {
5174 + end = (address) dlinfo2.dli_saddr;
5176 + Disassembler::decode(begin, end, st);
5178 + return true;
5180 + return false;
5183 +// Following function has been added to support HotSparc's libjvm.so running
5184 +// under Solaris production JDK 1.2.2 / 1.3.0. These came from
5185 +// src/solaris/hpi/native_threads in the EVM codebase.
5187 +// NOTE: This is no longer needed in the 1.3.1 and 1.4 production release
5188 +// libraries and should thus be removed. We will leave it behind for a while
5189 +// until we no longer want to able to run on top of 1.3.0 Solaris production
5190 +// JDK. See 4341971.
5192 +#define STACK_SLACK 0x800
5194 +extern "C" {
5195 + intptr_t sysThreadAvailableStackWithSlack() {
5196 + stack_t st;
5197 + intptr_t retval, stack_top;
5198 + retval = thr_stksegment(&st);
5199 + assert(retval == 0, "incorrect return value from thr_stksegment");
5200 + assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
5201 + assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
5202 + stack_top=(intptr_t)st.ss_sp-st.ss_size;
5203 + return ((intptr_t)&stack_top - stack_top - STACK_SLACK);
5207 +// ObjectMonitor park-unpark infrastructure ...
5209 +// We implement Solaris and Linux PlatformEvents with the
5210 +// obvious condvar-mutex-flag triple.
5211 +// Another alternative that works quite well is pipes:
5212 +// Each PlatformEvent consists of a pipe-pair.
5213 +// The thread associated with the PlatformEvent
5214 +// calls park(), which reads from the input end of the pipe.
5215 +// Unpark() writes into the other end of the pipe.
5216 +// The write-side of the pipe must be set NDELAY.
5217 +// Unfortunately pipes consume a large # of handles.
5218 +// Native solaris lwp_park() and lwp_unpark() work nicely, too.
5219 +// Using pipes for the 1st few threads might be workable, however.
5221 +// park() is permitted to return spuriously.
5222 +// Callers of park() should wrap the call to park() in
5223 +// an appropriate loop. A litmus test for the correct
5224 +// usage of park is the following: if park() were modified
5225 +// to immediately return 0 your code should still work,
5226 +// albeit degenerating to a spin loop.
5228 +// In a sense, park()-unpark() just provides more polite spinning
5229 +// and polling with the key difference over naive spinning being
5230 +// that a parked thread needs to be explicitly unparked() in order
5231 +// to wake up and to poll the underlying condition.
5233 +// Assumption:
5234 +// Only one parker can exist on an event, which is why we allocate
5235 +// them per-thread. Multiple unparkers can coexist.
5237 +// _event transitions in park()
5238 +// -1 => -1 : illegal
5239 +// 1 => 0 : pass - return immediately
5240 +// 0 => -1 : block; then set _event to 0 before returning
5242 +// _event transitions in unpark()
5243 +// 0 => 1 : just return
5244 +// 1 => 1 : just return
5245 +// -1 => either 0 or 1; must signal target thread
5246 +// That is, we can safely transition _event from -1 to either
5247 +// 0 or 1.
5249 +// _event serves as a restricted-range semaphore.
5250 +// -1 : thread is blocked, i.e. there is a waiter
5251 +// 0 : neutral: thread is running or ready,
5252 +// could have been signaled after a wait started
5253 +// 1 : signaled - thread is running or ready
5255 +// Another possible encoding of _event would be with
5256 +// explicit "PARKED" == 01b and "SIGNALED" == 10b bits.
5258 +// TODO-FIXME: add DTRACE probes for:
5259 +// 1. Tx parks
5260 +// 2. Ty unparks Tx
5261 +// 3. Tx resumes from park
5263 +// JSR166
5264 +// -------------------------------------------------------
5266 +// The solaris and linux implementations of park/unpark are fairly
5267 +// conservative for now, but can be improved. They currently use a
5268 +// mutex/condvar pair, plus _counter.
5269 +// Park decrements _counter if > 0, else does a condvar wait. Unpark
5270 +// sets count to 1 and signals condvar. Only one thread ever waits
5271 +// on the condvar. Contention seen when trying to park implies that someone
5272 +// is unparking you, so don't wait. And spurious returns are fine, so there
5273 +// is no need to track notifications.
5275 +// Get the default path to the core file
5276 +// Returns the length of the string
5277 +int os::get_core_path(char* buffer, size_t bufferSize) {
5278 + const char* p = get_current_directory(buffer, bufferSize);
5280 + if (p == NULL) {
5281 + assert(p != NULL, "failed to get current directory");
5282 + return 0;
5285 + jio_snprintf(buffer, bufferSize, "%s/core or core.%d",
5286 + p, current_process_id());
5288 + return strlen(buffer);
5291 +bool os::supports_map_sync() {
5292 + return false;
5295 +#ifndef PRODUCT
5296 +void TestReserveMemorySpecial_test() {
5297 + // No tests available for this platform
5299 +#endif
5301 +bool os::start_debugging(char *buf, int buflen) {
5302 + int len = (int)strlen(buf);
5303 + char *p = &buf[len];
5305 + jio_snprintf(p, buflen-len,
5306 + "\n\n"
5307 + "Do you want to debug the problem?\n\n"
5308 + "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n"
5309 + "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n"
5310 + "Otherwise, press RETURN to abort...",
5311 + os::current_process_id(), os::current_thread_id());
5313 + bool yes = os::message_box("Unexpected Error", buf);
5315 + if (yes) {
5316 + // yes, user asked VM to launch debugger
5317 + jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id());
5319 + os::fork_and_exec(buf);
5320 + yes = false;
5322 + return yes;
5325 +void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
5327 +#if INCLUDE_JFR
5329 +void os::jfr_report_memory_info() {}
5331 +#endif // INCLUDE_JFR
5333 +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
5335 + if (ebuf && ebuflen > 0) {
5336 + ebuf[0] = '\0';
5337 + ebuf[ebuflen - 1] = '\0';
5340 + bool res = (0 == ::dlclose(libhandle));
5341 + if (!res) {
5342 + // error analysis when dlopen fails
5343 + const char* error_report = ::dlerror();
5344 + if (error_report == nullptr) {
5345 + error_report = "dlerror returned no error description";
5347 + if (ebuf != nullptr && ebuflen > 0) {
5348 + snprintf(ebuf, ebuflen - 1, "%s", error_report);
5352 + return res;
5353 +} // end: os::pd_dll_unload()
5354 diff -urN /tmp/a/os_solaris.hpp b/src/hotspot/os/solaris/os_solaris.hpp
5355 --- /tmp/a/os_solaris.hpp 1970-01-01 01:00:00.000000000 +0100
5356 +++ b/src/hotspot/os/solaris/os_solaris.hpp 2024-09-16 14:41:33.968210379 +0100
5357 @@ -0,0 +1,201 @@
5359 + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
5360 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5362 + * This code is free software; you can redistribute it and/or modify it
5363 + * under the terms of the GNU General Public License version 2 only, as
5364 + * published by the Free Software Foundation.
5366 + * This code is distributed in the hope that it will be useful, but WITHOUT
5367 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5368 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5369 + * version 2 for more details (a copy is included in the LICENSE file that
5370 + * accompanied this code).
5372 + * You should have received a copy of the GNU General Public License version
5373 + * 2 along with this work; if not, write to the Free Software Foundation,
5374 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5376 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5377 + * or visit www.oracle.com if you need additional information or have any
5378 + * questions.
5380 + */
5382 +#ifndef OS_SOLARIS_OS_SOLARIS_HPP
5383 +#define OS_SOLARIS_OS_SOLARIS_HPP
5385 +#include "runtime/os.hpp"
5387 +// Solaris_OS defines the interface to Solaris operating systems
5389 +// see thr_setprio(3T) for the basis of these numbers
5390 +#define MinimumPriority 0
5391 +#define NormalPriority 64
5392 +#define MaximumPriority 127
5394 +// FX/60 is critical thread class/priority on T4
5395 +#define FXCriticalPriority 60
5397 +class os::Solaris {
5398 + friend class os;
5400 + private:
5402 + static bool _synchronization_initialized;
5404 + typedef uintptr_t lgrp_cookie_t;
5405 + typedef id_t lgrp_id_t;
5406 + typedef int lgrp_rsrc_t;
5407 + typedef enum lgrp_view {
5408 + LGRP_VIEW_CALLER, // what's available to the caller
5409 + LGRP_VIEW_OS // what's available to operating system
5410 + } lgrp_view_t;
5412 + typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id);
5413 + typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view);
5414 + typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie);
5415 + typedef lgrp_id_t (*lgrp_root_func_t)(lgrp_cookie_t cookie);
5416 + typedef int (*lgrp_children_func_t)(lgrp_cookie_t cookie, lgrp_id_t parent,
5417 + lgrp_id_t *lgrp_array, uint_t lgrp_array_size);
5418 + typedef int (*lgrp_resources_func_t)(lgrp_cookie_t cookie, lgrp_id_t lgrp,
5419 + lgrp_id_t *lgrp_array, uint_t lgrp_array_size,
5420 + lgrp_rsrc_t type);
5421 + typedef int (*lgrp_nlgrps_func_t)(lgrp_cookie_t cookie);
5422 + typedef int (*lgrp_cookie_stale_func_t)(lgrp_cookie_t cookie);
5424 + static lgrp_home_func_t _lgrp_home;
5425 + static lgrp_init_func_t _lgrp_init;
5426 + static lgrp_fini_func_t _lgrp_fini;
5427 + static lgrp_root_func_t _lgrp_root;
5428 + static lgrp_children_func_t _lgrp_children;
5429 + static lgrp_resources_func_t _lgrp_resources;
5430 + static lgrp_nlgrps_func_t _lgrp_nlgrps;
5431 + static lgrp_cookie_stale_func_t _lgrp_cookie_stale;
5432 + static lgrp_cookie_t _lgrp_cookie;
5434 + // Large Page Support
5435 + static bool is_valid_page_size(size_t bytes);
5436 + static size_t page_size_for_alignment(size_t alignment);
5437 + static bool setup_large_pages(caddr_t start, size_t bytes, size_t align);
5439 + typedef int (*pthread_setname_np_func_t)(pthread_t, const char*);
5440 + static pthread_setname_np_func_t _pthread_setname_np;
5442 + public:
5443 + // Large Page Support--ISM.
5444 + static bool largepage_range(char* addr, size_t size);
5446 + static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo
5448 + static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect);
5449 + static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread,
5450 + const ucontext_t* uc);
5452 + static intptr_t* ucontext_get_sp(const ucontext_t* uc);
5453 + // ucontext_get_fp() is only used by Solaris X86 (see note below)
5454 + static intptr_t* ucontext_get_fp(const ucontext_t* uc);
5456 + static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
5458 + static void init_thread_fpu_state(void);
5460 + protected:
5461 + // Solaris-specific interface goes here
5462 + static julong available_memory();
5463 + static julong free_memory();
5464 + static julong physical_memory() { return _physical_memory; }
5465 + static julong _physical_memory;
5466 + static void initialize_system_info();
5467 + static int _dev_zero_fd;
5468 + static int get_dev_zero_fd() { return _dev_zero_fd; }
5469 + static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; }
5470 + static int commit_memory_impl(char* addr, size_t bytes, bool exec);
5471 + static int commit_memory_impl(char* addr, size_t bytes,
5472 + size_t alignment_hint, bool exec);
5473 + static char* mmap_chunk(char *addr, size_t size, int flags, int prot);
5474 + static char* anon_mmap(char* requested_addr, size_t bytes);
5475 + static bool mpss_sanity_check(bool warn, size_t * page_size);
5477 + static address current_stack_base();
5478 + static size_t current_stack_size();
5480 + // Workaround for 4352906. thr_stksegment sometimes returns
5481 + // a bad value for the primordial thread's stack base when
5482 + // it is called more than one time.
5483 + // Workaround is to cache the initial value to avoid further
5484 + // calls to thr_stksegment.
5485 + // It appears that someone (Hotspot?) is trashing the user's
5486 + // proc_t structure (note that this is a system struct).
5487 + static address _main_stack_base;
5489 + static void print_distro_info(outputStream* st);
5490 + static void print_libversion_info(outputStream* st);
5492 + public:
5493 + static void libthread_init();
5494 + static void synchronization_init();
5495 + static bool liblgrp_init();
5497 + // alignment with os_posix means we use pthreads
5498 + static int mutex_lock(pthread_mutex_t *mx) { return pthread_mutex_lock(mx); }
5499 + static int mutex_trylock(pthread_mutex_t *mx) { return pthread_mutex_trylock(mx); }
5500 + static int mutex_unlock(pthread_mutex_t *mx) { return pthread_mutex_unlock(mx); }
5501 + static int mutex_init(pthread_mutex_t *mx) { return pthread_mutex_init(mx, NULL); }
5502 + static int mutex_destroy(pthread_mutex_t *mx) { return pthread_mutex_destroy(mx); }
5504 + static int cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mx, timestruc_t *abst) { return pthread_cond_timedwait(cv, mx, abst); }
5505 + static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mx) { return pthread_cond_wait(cv, mx); }
5506 + static int cond_signal(pthread_cond_t *cv) { return pthread_cond_signal(cv); }
5507 + static int cond_broadcast(pthread_cond_t *cv) { return pthread_cond_broadcast(cv); }
5508 + static int cond_init(pthread_cond_t *cv) { return pthread_cond_init(cv, NULL); }
5509 + static int cond_destroy(pthread_cond_t *cv) { return pthread_cond_destroy(cv); }
5511 + static bool synchronization_initialized() { return _synchronization_initialized; }
5513 + static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; }
5514 + static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; }
5515 + static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; }
5516 + static void set_lgrp_root(lgrp_root_func_t func) { _lgrp_root = func; }
5517 + static void set_lgrp_children(lgrp_children_func_t func) { _lgrp_children = func; }
5518 + static void set_lgrp_resources(lgrp_resources_func_t func) { _lgrp_resources = func; }
5519 + static void set_lgrp_nlgrps(lgrp_nlgrps_func_t func) { _lgrp_nlgrps = func; }
5520 + static void set_lgrp_cookie_stale(lgrp_cookie_stale_func_t func) { _lgrp_cookie_stale = func; }
5521 + static void set_lgrp_cookie(lgrp_cookie_t cookie) { _lgrp_cookie = cookie; }
5523 + static id_t lgrp_home(idtype_t type, id_t id) { return _lgrp_home != NULL ? _lgrp_home(type, id) : -1; }
5524 + static lgrp_cookie_t lgrp_init(lgrp_view_t view) { return _lgrp_init != NULL ? _lgrp_init(view) : 0; }
5525 + static int lgrp_fini(lgrp_cookie_t cookie) { return _lgrp_fini != NULL ? _lgrp_fini(cookie) : -1; }
5526 + static lgrp_id_t lgrp_root(lgrp_cookie_t cookie) { return _lgrp_root != NULL ? _lgrp_root(cookie) : -1; }
5527 + static int lgrp_children(lgrp_cookie_t cookie, lgrp_id_t parent,
5528 + lgrp_id_t *lgrp_array, uint_t lgrp_array_size) {
5529 + return _lgrp_children != NULL ? _lgrp_children(cookie, parent, lgrp_array, lgrp_array_size) : -1;
5531 + static int lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp,
5532 + lgrp_id_t *lgrp_array, uint_t lgrp_array_size,
5533 + lgrp_rsrc_t type) {
5534 + return _lgrp_resources != NULL ? _lgrp_resources(cookie, lgrp, lgrp_array, lgrp_array_size, type) : -1;
5537 + static int lgrp_nlgrps(lgrp_cookie_t cookie) { return _lgrp_nlgrps != NULL ? _lgrp_nlgrps(cookie) : -1; }
5538 + static int lgrp_cookie_stale(lgrp_cookie_t cookie) {
5539 + return _lgrp_cookie_stale != NULL ? _lgrp_cookie_stale(cookie) : -1;
5541 + static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; }
5543 + static sigset_t* unblocked_signals();
5544 + static sigset_t* vm_signals();
5546 + // %%% Following should be promoted to os.hpp:
5547 + // Trace number of created threads
5548 + static jint _os_thread_limit;
5549 + static volatile jint _os_thread_count;
5551 + static void correct_stack_boundaries_for_primordial_thread(Thread* thr);
5553 + // Stack repair handling
5555 + // none present
5558 +#endif // OS_SOLARIS_OS_SOLARIS_HPP
5559 diff -urN /tmp/a/os_solaris.inline.hpp b/src/hotspot/os/solaris/os_solaris.inline.hpp
5560 --- /tmp/a/os_solaris.inline.hpp 1970-01-01 01:00:00.000000000 +0100
5561 +++ b/src/hotspot/os/solaris/os_solaris.inline.hpp 2024-09-16 14:41:33.968292953 +0100
5562 @@ -0,0 +1,72 @@
5564 + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
5565 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5567 + * This code is free software; you can redistribute it and/or modify it
5568 + * under the terms of the GNU General Public License version 2 only, as
5569 + * published by the Free Software Foundation.
5571 + * This code is distributed in the hope that it will be useful, but WITHOUT
5572 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5573 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5574 + * version 2 for more details (a copy is included in the LICENSE file that
5575 + * accompanied this code).
5577 + * You should have received a copy of the GNU General Public License version
5578 + * 2 along with this work; if not, write to the Free Software Foundation,
5579 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5581 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5582 + * or visit www.oracle.com if you need additional information or have any
5583 + * questions.
5585 + */
5587 +#ifndef OS_SOLARIS_OS_SOLARIS_INLINE_HPP
5588 +#define OS_SOLARIS_OS_SOLARIS_INLINE_HPP
5590 +#include "os_solaris.hpp"
5592 +#include "runtime/os.hpp"
5593 +#include "os_posix.inline.hpp"
5595 +// System includes
5596 +#include <sys/param.h>
5597 +#include <dlfcn.h>
5598 +#include <sys/socket.h>
5599 +#include <poll.h>
5600 +#include <sys/filio.h>
5601 +#include <unistd.h>
5602 +#include <netdb.h>
5603 +#include <setjmp.h>
5605 +inline bool os::zero_page_read_protected() {
5606 + return true;
5609 +inline bool os::uses_stack_guard_pages() {
5610 + return true;
5613 +inline bool os::must_commit_stack_guard_pages() {
5614 + assert(uses_stack_guard_pages(), "sanity check");
5615 + int r = thr_main() ;
5616 + guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ;
5617 + return r;
5621 +// Bang the shadow pages if they need to be touched to be mapped.
5622 +inline void os::map_stack_shadow_pages(address sp) {
5625 +// stubbed-out trim-native support
5626 +inline bool os::can_trim_native_heap() { return false; }
5627 +inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
5629 +//////////////////////////////////////////////////////////////////////////////
5630 +////////////////////////////////////////////////////////////////////////////////
5632 +inline bool os::numa_has_group_homing() { return true; }
5634 +#endif // OS_SOLARIS_OS_SOLARIS_INLINE_HPP
5635 diff -urN /tmp/a/vmStructs_solaris.hpp b/src/hotspot/os/solaris/vmStructs_solaris.hpp
5636 --- /tmp/a/vmStructs_solaris.hpp 1970-01-01 01:00:00.000000000 +0100
5637 +++ b/src/hotspot/os/solaris/vmStructs_solaris.hpp 2024-09-16 14:41:33.968376996 +0100
5638 @@ -0,0 +1,44 @@
5640 + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
5641 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5643 + * This code is free software; you can redistribute it and/or modify it
5644 + * under the terms of the GNU General Public License version 2 only, as
5645 + * published by the Free Software Foundation.
5647 + * This code is distributed in the hope that it will be useful, but WITHOUT
5648 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5649 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5650 + * version 2 for more details (a copy is included in the LICENSE file that
5651 + * accompanied this code).
5653 + * You should have received a copy of the GNU General Public License version
5654 + * 2 along with this work; if not, write to the Free Software Foundation,
5655 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5657 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5658 + * or visit www.oracle.com if you need additional information or have any
5659 + * questions.
5661 + */
5663 +#ifndef OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
5664 +#define OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
5666 +// These are the OS-specific fields, types and integer
5667 +// constants required by the Serviceability Agent. This file is
5668 +// referenced by vmStructs.cpp.
5670 +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
5671 + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t)
5673 +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
5674 + declare_unsigned_integer_type(OSThread::thread_id_t)
5676 +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
5678 +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
5680 +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function)
5682 +#endif // OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP