src/share/vm/jfr/recorder/jfrRecorder.cpp

Fri, 27 Sep 2019 13:23:32 +0800

author
mgronlun
date
Fri, 27 Sep 2019 13:23:32 +0800
changeset 9884
1258121876f8
parent 9879
d2b51a10084d
child 9925
30fb8c8cceb9
permissions
-rw-r--r--

8227011: Starting a JFR recording in response to JVMTI VMInit and / or Java agent premain corrupts memory
Reviewed-by: egahlin, rwestberg

     1 /*
     2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #include "precompiled.hpp"
    26 #include "jfr/dcmd/jfrDcmds.hpp"
    27 #include "jfr/instrumentation/jfrJvmtiAgent.hpp"
    28 #include "jfr/jni/jfrJavaSupport.hpp"
    29 #include "jfr/periodic/jfrOSInterface.hpp"
    30 #include "jfr/periodic/sampling/jfrThreadSampler.hpp"
    31 #include "jfr/recorder/jfrRecorder.hpp"
    32 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
    33 #include "jfr/recorder/repository/jfrRepository.hpp"
    34 #include "jfr/recorder/service/jfrOptionSet.hpp"
    35 #include "jfr/recorder/service/jfrPostBox.hpp"
    36 #include "jfr/recorder/service/jfrRecorderService.hpp"
    37 #include "jfr/recorder/service/jfrRecorderThread.hpp"
    38 #include "jfr/recorder/storage/jfrStorage.hpp"
    39 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
    40 #include "jfr/recorder/stringpool/jfrStringPool.hpp"
    41 #include "jfr/utilities/jfrTime.hpp"
    42 #include "jfr/writers/jfrJavaEventWriter.hpp"
    43 #include "memory/resourceArea.hpp"
    44 #include "runtime/handles.inline.hpp"
    45 #include "runtime/globals_extension.hpp"
    46 #include "utilities/growableArray.hpp"
    48 bool JfrRecorder::_shutting_down = false;
    50 bool JfrRecorder::is_disabled() {
    51   // True if -XX:-FlightRecorder has been explicitly set on the
    52   // command line
    53   return FLAG_IS_CMDLINE(FlightRecorder) ? !FlightRecorder : false;
    54 }
    56 static bool _enabled = false;
    58 static bool enable() {
    59   assert(!_enabled, "invariant");
    60   FLAG_SET_MGMT(bool, FlightRecorder, true);
    61   _enabled = FlightRecorder;
    62   assert(_enabled, "invariant");
    63   return _enabled;
    64 }
    66 bool JfrRecorder::is_enabled() {
    67   return _enabled;
    68 }
    70 bool JfrRecorder::on_vm_init() {
    71   if (!is_disabled()) {
    72     if (FlightRecorder || StartFlightRecording != NULL) {
    73       enable();
    74     }
    75   }
    76   // fast time initialization
    77   return JfrTime::initialize();
    78 }
    80 static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL;
    82 static void release_recordings() {
    83   if (dcmd_recordings_array != NULL) {
    84     const int length = dcmd_recordings_array->length();
    85     for (int i = 0; i < length; ++i) {
    86       delete dcmd_recordings_array->at(i);
    87     }
    88     delete dcmd_recordings_array;
    89     dcmd_recordings_array = NULL;
    90   }
    91 }
    93 static void teardown_startup_support() {
    94   release_recordings();
    95   JfrOptionSet::release_startup_recording_options();
    96 }
    98 // Parsing options here to detect errors as soon as possible
    99 static bool parse_recording_options(const char* options, JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
   100   assert(options != NULL, "invariant");
   101   assert(dcmd_recording != NULL, "invariant");
   102   CmdLine cmdline(options, strlen(options), true);
   103   dcmd_recording->parse(&cmdline, ',', THREAD);
   104   if (HAS_PENDING_EXCEPTION) {
   105     java_lang_Throwable::print(PENDING_EXCEPTION, tty);
   106     CLEAR_PENDING_EXCEPTION;
   107     return false;
   108   }
   109   return true;
   110 }
   112 static bool validate_recording_options(TRAPS) {
   113   const GrowableArray<const char*>* options = JfrOptionSet::startup_recording_options();
   114   if (options == NULL) {
   115     return true;
   116   }
   117   const int length = options->length();
   118   assert(length >= 1, "invariant");
   119   assert(dcmd_recordings_array == NULL, "invariant");
   120   dcmd_recordings_array = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<JfrStartFlightRecordingDCmd*>(length, true, mtTracing);
   121   assert(dcmd_recordings_array != NULL, "invariant");
   122   for (int i = 0; i < length; ++i) {
   123     JfrStartFlightRecordingDCmd* const dcmd_recording = new(ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true);
   124     assert(dcmd_recording != NULL, "invariant");
   125     dcmd_recordings_array->append(dcmd_recording);
   126     if (!parse_recording_options(options->at(i), dcmd_recording, THREAD)) {
   127       return false;
   128     }
   129   }
   130   return true;
   131 }
   133 static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
   134   assert(dcmd_recording != NULL, "invariant");
   135   if (LogJFR && Verbose) tty->print_cr("Starting a recording");
   136   dcmd_recording->execute(DCmd_Source_Internal, THREAD);
   137   if (HAS_PENDING_EXCEPTION) {
   138     if (LogJFR) tty->print_cr("Exception while starting a recording");
   139     CLEAR_PENDING_EXCEPTION;
   140     return false;
   141   }
   142   if (LogJFR && Verbose) tty->print_cr("Finished starting a recording");
   143   return true;
   144 }
   146 static bool launch_recordings(TRAPS) {
   147   bool result = true;
   148   if (dcmd_recordings_array != NULL) {
   149     const int length = dcmd_recordings_array->length();
   150     assert(length >= 1, "invariant");
   151     for (int i = 0; i < length; ++i) {
   152       if (!launch_recording(dcmd_recordings_array->at(i), THREAD)) {
   153         result = false;
   154         break;
   155       }
   156     }
   157   }
   158   teardown_startup_support();
   159   return result;
   160 }
   162 static bool is_cds_dump_requested() {
   163   // we will not be able to launch recordings if a cds dump is being requested
   164   if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) {
   165     warning("JFR will be disabled during CDS dumping");
   166     teardown_startup_support();
   167     return true;
   168   }
   169   return false;
   170 }
   172 bool JfrRecorder::on_vm_start() {
   173   if (is_cds_dump_requested()) {
   174     return true;
   175   }
   176   Thread* const thread = Thread::current();
   177   if (!JfrJavaEventWriter::has_required_classes(thread)) {
   178     // assume it is compact profile of jfr.jar is missed for some reasons
   179     // skip further initialization.
   180     return true;
   181   }
   182   if (!JfrOptionSet::initialize(thread)) {
   183     return false;
   184   }
   185   if (!register_jfr_dcmds()) {
   186     return false;
   187   }
   189   if (!validate_recording_options(thread)) {
   190     return false;
   191   }
   192   if (!JfrOptionSet::configure(thread)) {
   193     return false;
   194   }
   196   if (!is_enabled()) {
   197     return true;
   198   }
   200   return launch_recordings(thread);
   201 }
   203 static bool _created = false;
   205 //
   206 // Main entry point for starting Jfr functionality.
   207 // Non-protected initializations assume single-threaded setup.
   208 //
   209 bool JfrRecorder::create(bool simulate_failure) {
   210   assert(!is_disabled(), "invariant");
   211   assert(!is_created(), "invariant");
   212   if (!is_enabled()) {
   213     enable();
   214   }
   215   if (!create_components() || simulate_failure) {
   216     destroy_components();
   217     return false;
   218   }
   219   if (!create_recorder_thread()) {
   220     destroy_components();
   221     return false;
   222   }
   223   _created = true;
   224   return true;
   225 }
   227 bool JfrRecorder::is_created() {
   228   return _created;
   229 }
   231 bool JfrRecorder::create_components() {
   232   ResourceMark rm;
   233   HandleMark hm;
   235   if (!create_java_event_writer()) {
   236     return false;
   237   }
   238   if (!create_jvmti_agent()) {
   239     return false;
   240   }
   241   if (!create_post_box()) {
   242     return false;
   243   }
   244   if (!create_chunk_repository()) {
   245     return false;
   246   }
   247   if (!create_storage()) {
   248     return false;
   249   }
   250   if (!create_checkpoint_manager()) {
   251     return false;
   252   }
   253   if (!create_stacktrace_repository()) {
   254     return false;
   255   }
   256   if (!create_os_interface()) {
   257     return false;
   258   }
   259   if (!create_stringpool()) {
   260     return false;
   261   }
   262   if (!create_thread_sampling()) {
   263     return false;
   264   }
   265   return true;
   266 }
   268 // subsystems
   269 static JfrJvmtiAgent* _jvmti_agent = NULL;
   270 static JfrPostBox* _post_box = NULL;
   271 static JfrStorage* _storage = NULL;
   272 static JfrCheckpointManager* _checkpoint_manager = NULL;
   273 static JfrRepository* _repository = NULL;
   274 static JfrStackTraceRepository* _stack_trace_repository;
   275 static JfrStringPool* _stringpool = NULL;
   276 static JfrOSInterface* _os_interface = NULL;
   277 static JfrThreadSampling* _thread_sampling = NULL;
   279 bool JfrRecorder::create_java_event_writer() {
   280   return JfrJavaEventWriter::initialize();
   281 }
   283 bool JfrRecorder::create_jvmti_agent() {
   284   return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true;
   285 }
   287 bool JfrRecorder::create_post_box() {
   288   assert(_post_box == NULL, "invariant");
   289   _post_box = JfrPostBox::create();
   290   return _post_box != NULL;
   291 }
   293 bool JfrRecorder::create_chunk_repository() {
   294   assert(_repository == NULL, "invariant");
   295   assert(_post_box != NULL, "invariant");
   296   _repository = JfrRepository::create(*_post_box);
   297   return _repository != NULL && _repository->initialize();
   298 }
   300 bool JfrRecorder::create_os_interface() {
   301   assert(_os_interface == NULL, "invariant");
   302   _os_interface = JfrOSInterface::create();
   303   return _os_interface != NULL && _os_interface->initialize();
   304 }
   306 bool JfrRecorder::create_storage() {
   307   assert(_repository != NULL, "invariant");
   308   assert(_post_box != NULL, "invariant");
   309   _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box);
   310   return _storage != NULL && _storage->initialize();
   311 }
   313 bool JfrRecorder::create_checkpoint_manager() {
   314   assert(_checkpoint_manager == NULL, "invariant");
   315   assert(_repository != NULL, "invariant");
   316   _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter());
   317   return _checkpoint_manager != NULL && _checkpoint_manager->initialize();
   318 }
   320 bool JfrRecorder::create_stacktrace_repository() {
   321   assert(_stack_trace_repository == NULL, "invariant");
   322   _stack_trace_repository = JfrStackTraceRepository::create();
   323   return _stack_trace_repository != NULL && _stack_trace_repository->initialize();
   324 }
   326 bool JfrRecorder::create_stringpool() {
   327   assert(_stringpool == NULL, "invariant");
   328   assert(_repository != NULL, "invariant");
   329   _stringpool = JfrStringPool::create(_repository->chunkwriter());
   330   return _stringpool != NULL && _stringpool->initialize();
   331 }
   333 bool JfrRecorder::create_thread_sampling() {
   334   assert(_thread_sampling == NULL, "invariant");
   335   _thread_sampling = JfrThreadSampling::create();
   336   return _thread_sampling != NULL;
   337 }
   339 void JfrRecorder::destroy_components() {
   340   JfrJvmtiAgent::destroy();
   341   if (_post_box != NULL) {
   342     JfrPostBox::destroy();
   343     _post_box = NULL;
   344   }
   345   if (_repository != NULL) {
   346     JfrRepository::destroy();
   347     _repository = NULL;
   348   }
   349   if (_storage != NULL) {
   350     JfrStorage::destroy();
   351     _storage = NULL;
   352   }
   353   if (_checkpoint_manager != NULL) {
   354     JfrCheckpointManager::destroy();
   355     _checkpoint_manager = NULL;
   356   }
   357   if (_stack_trace_repository != NULL) {
   358     JfrStackTraceRepository::destroy();
   359     _stack_trace_repository = NULL;
   360   }
   361   if (_stringpool != NULL) {
   362     JfrStringPool::destroy();
   363     _stringpool = NULL;
   364   }
   365   if (_os_interface != NULL) {
   366     JfrOSInterface::destroy();
   367     _os_interface = NULL;
   368   }
   369   if (_thread_sampling != NULL) {
   370     JfrThreadSampling::destroy();
   371     _thread_sampling = NULL;
   372   }
   373 }
   375 bool JfrRecorder::create_recorder_thread() {
   376   return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current());
   377 }
   379 void JfrRecorder::destroy() {
   380   assert(is_created(), "invariant");
   381   _post_box->post(MSG_SHUTDOWN);
   382   JfrJvmtiAgent::destroy();
   383 }
   385 void JfrRecorder::on_recorder_thread_exit() {
   386   assert(!is_recording(), "invariant");
   387   // intent is to destroy the recorder instance and components,
   388   // but need sensitive coordination not yet in place
   389   //
   390   // destroy_components();
   391   //
   392   if (LogJFR) tty->print_cr("Recorder thread STOPPED");
   393 }
   395 void JfrRecorder::start_recording() {
   396   _post_box->post(MSG_START);
   397 }
   399 bool JfrRecorder::is_recording() {
   400   return JfrRecorderService::is_recording();
   401 }
   403 void JfrRecorder::stop_recording() {
   404   _post_box->post(MSG_STOP);
   405 }

mercurial