1.1 --- a/src/share/vm/services/heapDumper.cpp Mon Mar 09 13:34:00 2009 -0700 1.2 +++ b/src/share/vm/services/heapDumper.cpp Thu Mar 12 18:16:36 2009 -0700 1.3 @@ -347,7 +347,6 @@ 1.4 INITIAL_CLASS_COUNT = 200 1.5 }; 1.6 1.7 - 1.8 // Supports I/O operations on a dump file 1.9 1.10 class DumpWriter : public StackObj { 1.11 @@ -1303,7 +1302,9 @@ 1.12 // The VM operation that performs the heap dump 1.13 class VM_HeapDumper : public VM_GC_Operation { 1.14 private: 1.15 - DumpWriter* _writer; 1.16 + static VM_HeapDumper* _global_dumper; 1.17 + static DumpWriter* _global_writer; 1.18 + DumpWriter* _local_writer; 1.19 bool _gc_before_heap_dump; 1.20 bool _is_segmented_dump; 1.21 jlong _dump_start; 1.22 @@ -1311,8 +1312,20 @@ 1.23 ThreadStackTrace** _stack_traces; 1.24 int _num_threads; 1.25 1.26 - // accessors 1.27 - DumpWriter* writer() const { return _writer; } 1.28 + // accessors and setters 1.29 + static VM_HeapDumper* dumper() { assert(_global_dumper != NULL, "Error"); return _global_dumper; } 1.30 + static DumpWriter* writer() { assert(_global_writer != NULL, "Error"); return _global_writer; } 1.31 + void set_global_dumper() { 1.32 + assert(_global_dumper == NULL, "Error"); 1.33 + _global_dumper = this; 1.34 + } 1.35 + void set_global_writer() { 1.36 + assert(_global_writer == NULL, "Error"); 1.37 + _global_writer = _local_writer; 1.38 + } 1.39 + void clear_global_dumper() { _global_dumper = NULL; } 1.40 + void clear_global_writer() { _global_writer = NULL; } 1.41 + 1.42 bool is_segmented_dump() const { return _is_segmented_dump; } 1.43 void set_segmented_dump() { _is_segmented_dump = true; } 1.44 jlong dump_start() const { return _dump_start; } 1.45 @@ -1357,7 +1370,7 @@ 1.46 VM_GC_Operation(0 /* total collections, dummy, ignored */, 1.47 0 /* total full collections, dummy, ignored */, 1.48 gc_before_heap_dump) { 1.49 - _writer = writer; 1.50 + _local_writer = writer; 1.51 _gc_before_heap_dump = gc_before_heap_dump; 1.52 _is_segmented_dump = false; 1.53 _dump_start = (jlong)-1; 1.54 @@ -1381,6 +1394,9 @@ 1.55 void doit(); 1.56 }; 1.57 1.58 +VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL; 1.59 +DumpWriter* VM_HeapDumper::_global_writer = NULL; 1.60 + 1.61 bool VM_HeapDumper::skip_operation() const { 1.62 return false; 1.63 } 1.64 @@ -1479,31 +1495,28 @@ 1.65 void VM_HeapDumper::do_load_class(klassOop k) { 1.66 static u4 class_serial_num = 0; 1.67 1.68 - VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); 1.69 - DumpWriter* writer = dumper->writer(); 1.70 - 1.71 // len of HPROF_LOAD_CLASS record 1.72 u4 remaining = 2*oopSize + 2*sizeof(u4); 1.73 1.74 // write a HPROF_LOAD_CLASS for the class and each array class 1.75 do { 1.76 - DumperSupport::write_header(writer, HPROF_LOAD_CLASS, remaining); 1.77 + DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); 1.78 1.79 // class serial number is just a number 1.80 - writer->write_u4(++class_serial_num); 1.81 + writer()->write_u4(++class_serial_num); 1.82 1.83 // class ID 1.84 Klass* klass = Klass::cast(k); 1.85 - writer->write_classID(klass); 1.86 + writer()->write_classID(klass); 1.87 1.88 // add the klassOop and class serial number pair 1.89 - dumper->add_class_serial_number(klass, class_serial_num); 1.90 + dumper()->add_class_serial_number(klass, class_serial_num); 1.91 1.92 - writer->write_u4(STACK_TRACE_ID); 1.93 + writer()->write_u4(STACK_TRACE_ID); 1.94 1.95 // class name ID 1.96 symbolOop name = klass->name(); 1.97 - writer->write_objectID(name); 1.98 + writer()->write_objectID(name); 1.99 1.100 // write a LOAD_CLASS record for the array type (if it exists) 1.101 k = klass->array_klass_or_null(); 1.102 @@ -1512,17 +1525,13 @@ 1.103 1.104 // writes a HPROF_GC_CLASS_DUMP record for the given class 1.105 void VM_HeapDumper::do_class_dump(klassOop k) { 1.106 - VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); 1.107 - DumpWriter* writer = dumper->writer(); 1.108 - DumperSupport::dump_class_and_array_classes(writer, k); 1.109 + DumperSupport::dump_class_and_array_classes(writer(), k); 1.110 } 1.111 1.112 // writes a HPROF_GC_CLASS_DUMP records for a given basic type 1.113 // array (and each multi-dimensional array too) 1.114 void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) { 1.115 - VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); 1.116 - DumpWriter* writer = dumper->writer(); 1.117 - DumperSupport::dump_basic_type_array_class(writer, k); 1.118 + DumperSupport::dump_basic_type_array_class(writer(), k); 1.119 } 1.120 1.121 // Walk the stack of the given thread. 1.122 @@ -1658,6 +1667,11 @@ 1.123 ch->ensure_parsability(false); 1.124 } 1.125 1.126 + // At this point we should be the only dumper active, so 1.127 + // the following should be safe. 1.128 + set_global_dumper(); 1.129 + set_global_writer(); 1.130 + 1.131 // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 1.132 size_t used = ch->used(); 1.133 const char* header; 1.134 @@ -1667,6 +1681,7 @@ 1.135 } else { 1.136 header = "JAVA PROFILE 1.0.1"; 1.137 } 1.138 + 1.139 // header is few bytes long - no chance to overflow int 1.140 writer()->write_raw((void*)header, (int)strlen(header)); 1.141 writer()->write_u1(0); // terminator 1.142 @@ -1723,6 +1738,10 @@ 1.143 // fixes up the length of the dump record. In the case of a segmented 1.144 // heap then the HPROF_HEAP_DUMP_END record is also written. 1.145 end_of_dump(); 1.146 + 1.147 + // Now we clear the global variables, so that a future dumper might run. 1.148 + clear_global_dumper(); 1.149 + clear_global_writer(); 1.150 } 1.151 1.152 void VM_HeapDumper::dump_stack_traces() { 1.153 @@ -1790,7 +1809,12 @@ 1.154 1.155 // generate the dump 1.156 VM_HeapDumper dumper(&writer, _gc_before_heap_dump); 1.157 - VMThread::execute(&dumper); 1.158 + if (Thread::current()->is_VM_thread()) { 1.159 + assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint"); 1.160 + dumper.doit(); 1.161 + } else { 1.162 + VMThread::execute(&dumper); 1.163 + } 1.164 1.165 // close dump file and record any error that the writer may have encountered 1.166 writer.close(); 1.167 @@ -1845,49 +1869,68 @@ 1.168 } 1.169 } 1.170 1.171 - 1.172 -// Called by error reporting 1.173 +// Called by error reporting by a single Java thread outside of a JVM safepoint, 1.174 +// or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various 1.175 +// callers are strictly serialized and guaranteed not to interfere below. For more 1.176 +// general use, however, this method will need modification to prevent 1.177 +// inteference when updating the static variables base_path and dump_file_seq below. 1.178 void HeapDumper::dump_heap() { 1.179 - static char path[JVM_MAXPATHLEN]; 1.180 + static char base_path[JVM_MAXPATHLEN] = {'\0'}; 1.181 + static uint dump_file_seq = 0; 1.182 + char my_path[JVM_MAXPATHLEN] = {'\0'}; 1.183 1.184 // The dump file defaults to java_pid<pid>.hprof in the current working 1.185 // directory. HeapDumpPath=<file> can be used to specify an alternative 1.186 // dump file name or a directory where dump file is created. 1.187 - bool use_default_filename = true; 1.188 - if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { 1.189 - path[0] = '\0'; // HeapDumpPath=<file> not specified 1.190 - } else { 1.191 - assert(strlen(HeapDumpPath) < sizeof(path), "HeapDumpPath too long"); 1.192 - strcpy(path, HeapDumpPath); 1.193 - // check if the path is a directory (must exist) 1.194 - DIR* dir = os::opendir(path); 1.195 - if (dir == NULL) { 1.196 - use_default_filename = false; 1.197 + if (dump_file_seq == 0) { // first time in, we initialize base_path 1.198 + bool use_default_filename = true; 1.199 + if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { 1.200 + // HeapDumpPath=<file> not specified 1.201 } else { 1.202 - // HeapDumpPath specified a directory. We append a file separator 1.203 - // (if needed). 1.204 - os::closedir(dir); 1.205 - size_t fs_len = strlen(os::file_separator()); 1.206 - if (strlen(path) >= fs_len) { 1.207 - char* end = path; 1.208 - end += (strlen(path) - fs_len); 1.209 - if (strcmp(end, os::file_separator()) != 0) { 1.210 - assert(strlen(path) + strlen(os::file_separator()) < sizeof(path), 1.211 - "HeapDumpPath too long"); 1.212 - strcat(path, os::file_separator()); 1.213 + assert(strlen(HeapDumpPath) < sizeof(base_path), "HeapDumpPath too long"); 1.214 + strcpy(base_path, HeapDumpPath); 1.215 + // check if the path is a directory (must exist) 1.216 + DIR* dir = os::opendir(base_path); 1.217 + if (dir == NULL) { 1.218 + use_default_filename = false; 1.219 + } else { 1.220 + // HeapDumpPath specified a directory. We append a file separator 1.221 + // (if needed). 1.222 + os::closedir(dir); 1.223 + size_t fs_len = strlen(os::file_separator()); 1.224 + if (strlen(base_path) >= fs_len) { 1.225 + char* end = base_path; 1.226 + end += (strlen(base_path) - fs_len); 1.227 + if (strcmp(end, os::file_separator()) != 0) { 1.228 + assert(strlen(base_path) + strlen(os::file_separator()) < sizeof(base_path), 1.229 + "HeapDumpPath too long"); 1.230 + strcat(base_path, os::file_separator()); 1.231 + } 1.232 } 1.233 } 1.234 } 1.235 + // If HeapDumpPath wasn't a file name then we append the default name 1.236 + if (use_default_filename) { 1.237 + char fn[32]; 1.238 + sprintf(fn, "java_pid%d", os::current_process_id()); 1.239 + assert(strlen(base_path) + strlen(fn) < sizeof(base_path), "HeapDumpPath too long"); 1.240 + strcat(base_path, fn); 1.241 + } 1.242 + assert(strlen(base_path) < sizeof(my_path), "Buffer too small"); 1.243 + strcpy(my_path, base_path); 1.244 + } else { 1.245 + // Append a sequence number id for dumps following the first 1.246 + char fn[33]; 1.247 + sprintf(fn, ".%d", dump_file_seq); 1.248 + assert(strlen(base_path) + strlen(fn) < sizeof(my_path), "HeapDumpPath too long"); 1.249 + strcpy(my_path, base_path); 1.250 + strcat(my_path, fn); 1.251 } 1.252 - // If HeapDumpPath wasn't a file name then we append the default name 1.253 - if (use_default_filename) { 1.254 - char fn[32]; 1.255 - sprintf(fn, "java_pid%d.hprof", os::current_process_id()); 1.256 - assert(strlen(path) + strlen(fn) < sizeof(path), "HeapDumpPath too long"); 1.257 - strcat(path, fn); 1.258 - } 1.259 + dump_file_seq++; // increment seq number for next time we dump 1.260 + assert(strlen(".hprof") + strlen(my_path) < sizeof(my_path), "HeapDumpPath too long"); 1.261 + strcat(my_path, ".hprof"); 1.262 1.263 HeapDumper dumper(false /* no GC before heap dump */, 1.264 true /* send to tty */); 1.265 - dumper.dump(path); 1.266 + dumper.dump(my_path); 1.267 }