src/share/vm/utilities/ostream.cpp

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/utilities/ostream.cpp	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,1326 @@
     1.4 +/*
     1.5 + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "precompiled.hpp"
    1.29 +#include "compiler/compileLog.hpp"
    1.30 +#include "oops/oop.inline.hpp"
    1.31 +#include "runtime/arguments.hpp"
    1.32 +#include "utilities/defaultStream.hpp"
    1.33 +#include "utilities/ostream.hpp"
    1.34 +#include "utilities/top.hpp"
    1.35 +#include "utilities/xmlstream.hpp"
    1.36 +#ifdef TARGET_OS_FAMILY_linux
    1.37 +# include "os_linux.inline.hpp"
    1.38 +#endif
    1.39 +#ifdef TARGET_OS_FAMILY_solaris
    1.40 +# include "os_solaris.inline.hpp"
    1.41 +#endif
    1.42 +#ifdef TARGET_OS_FAMILY_windows
    1.43 +# include "os_windows.inline.hpp"
    1.44 +#endif
    1.45 +#ifdef TARGET_OS_FAMILY_aix
    1.46 +# include "os_aix.inline.hpp"
    1.47 +#endif
    1.48 +#ifdef TARGET_OS_FAMILY_bsd
    1.49 +# include "os_bsd.inline.hpp"
    1.50 +#endif
    1.51 +
    1.52 +extern "C" void jio_print(const char* s); // Declarationtion of jvm method
    1.53 +
    1.54 +outputStream::outputStream(int width) {
    1.55 +  _width       = width;
    1.56 +  _position    = 0;
    1.57 +  _newlines    = 0;
    1.58 +  _precount    = 0;
    1.59 +  _indentation = 0;
    1.60 +}
    1.61 +
    1.62 +outputStream::outputStream(int width, bool has_time_stamps) {
    1.63 +  _width       = width;
    1.64 +  _position    = 0;
    1.65 +  _newlines    = 0;
    1.66 +  _precount    = 0;
    1.67 +  _indentation = 0;
    1.68 +  if (has_time_stamps)  _stamp.update();
    1.69 +}
    1.70 +
    1.71 +void outputStream::update_position(const char* s, size_t len) {
    1.72 +  for (size_t i = 0; i < len; i++) {
    1.73 +    char ch = s[i];
    1.74 +    if (ch == '\n') {
    1.75 +      _newlines += 1;
    1.76 +      _precount += _position + 1;
    1.77 +      _position = 0;
    1.78 +    } else if (ch == '\t') {
    1.79 +      int tw = 8 - (_position & 7);
    1.80 +      _position += tw;
    1.81 +      _precount -= tw-1;  // invariant:  _precount + _position == total count
    1.82 +    } else {
    1.83 +      _position += 1;
    1.84 +    }
    1.85 +  }
    1.86 +}
    1.87 +
    1.88 +// Execute a vsprintf, using the given buffer if necessary.
    1.89 +// Return a pointer to the formatted string.
    1.90 +const char* outputStream::do_vsnprintf(char* buffer, size_t buflen,
    1.91 +                                       const char* format, va_list ap,
    1.92 +                                       bool add_cr,
    1.93 +                                       size_t& result_len) {
    1.94 +  const char* result;
    1.95 +  if (add_cr)  buflen--;
    1.96 +  if (!strchr(format, '%')) {
    1.97 +    // constant format string
    1.98 +    result = format;
    1.99 +    result_len = strlen(result);
   1.100 +    if (add_cr && result_len >= buflen)  result_len = buflen-1;  // truncate
   1.101 +  } else if (format[0] == '%' && format[1] == 's' && format[2] == '\0') {
   1.102 +    // trivial copy-through format string
   1.103 +    result = va_arg(ap, const char*);
   1.104 +    result_len = strlen(result);
   1.105 +    if (add_cr && result_len >= buflen)  result_len = buflen-1;  // truncate
   1.106 +  } else if (vsnprintf(buffer, buflen, format, ap) >= 0) {
   1.107 +    result = buffer;
   1.108 +    result_len = strlen(result);
   1.109 +  } else {
   1.110 +    DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");)
   1.111 +    result = buffer;
   1.112 +    result_len = buflen - 1;
   1.113 +    buffer[result_len] = 0;
   1.114 +  }
   1.115 +  if (add_cr) {
   1.116 +    if (result != buffer) {
   1.117 +      strncpy(buffer, result, buflen);
   1.118 +      result = buffer;
   1.119 +    }
   1.120 +    buffer[result_len++] = '\n';
   1.121 +    buffer[result_len] = 0;
   1.122 +  }
   1.123 +  return result;
   1.124 +}
   1.125 +
   1.126 +void outputStream::print(const char* format, ...) {
   1.127 +  char buffer[O_BUFLEN];
   1.128 +  va_list ap;
   1.129 +  va_start(ap, format);
   1.130 +  size_t len;
   1.131 +  const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, false, len);
   1.132 +  write(str, len);
   1.133 +  va_end(ap);
   1.134 +}
   1.135 +
   1.136 +void outputStream::print_cr(const char* format, ...) {
   1.137 +  char buffer[O_BUFLEN];
   1.138 +  va_list ap;
   1.139 +  va_start(ap, format);
   1.140 +  size_t len;
   1.141 +  const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, true, len);
   1.142 +  write(str, len);
   1.143 +  va_end(ap);
   1.144 +}
   1.145 +
   1.146 +void outputStream::vprint(const char *format, va_list argptr) {
   1.147 +  char buffer[O_BUFLEN];
   1.148 +  size_t len;
   1.149 +  const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, false, len);
   1.150 +  write(str, len);
   1.151 +}
   1.152 +
   1.153 +void outputStream::vprint_cr(const char* format, va_list argptr) {
   1.154 +  char buffer[O_BUFLEN];
   1.155 +  size_t len;
   1.156 +  const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, true, len);
   1.157 +  write(str, len);
   1.158 +}
   1.159 +
   1.160 +void outputStream::fill_to(int col) {
   1.161 +  int need_fill = col - position();
   1.162 +  sp(need_fill);
   1.163 +}
   1.164 +
   1.165 +void outputStream::move_to(int col, int slop, int min_space) {
   1.166 +  if (position() >= col + slop)
   1.167 +    cr();
   1.168 +  int need_fill = col - position();
   1.169 +  if (need_fill < min_space)
   1.170 +    need_fill = min_space;
   1.171 +  sp(need_fill);
   1.172 +}
   1.173 +
   1.174 +void outputStream::put(char ch) {
   1.175 +  assert(ch != 0, "please fix call site");
   1.176 +  char buf[] = { ch, '\0' };
   1.177 +  write(buf, 1);
   1.178 +}
   1.179 +
   1.180 +#define SP_USE_TABS false
   1.181 +
   1.182 +void outputStream::sp(int count) {
   1.183 +  if (count < 0)  return;
   1.184 +  if (SP_USE_TABS && count >= 8) {
   1.185 +    int target = position() + count;
   1.186 +    while (count >= 8) {
   1.187 +      this->write("\t", 1);
   1.188 +      count -= 8;
   1.189 +    }
   1.190 +    count = target - position();
   1.191 +  }
   1.192 +  while (count > 0) {
   1.193 +    int nw = (count > 8) ? 8 : count;
   1.194 +    this->write("        ", nw);
   1.195 +    count -= nw;
   1.196 +  }
   1.197 +}
   1.198 +
   1.199 +void outputStream::cr() {
   1.200 +  this->write("\n", 1);
   1.201 +}
   1.202 +
   1.203 +void outputStream::stamp() {
   1.204 +  if (! _stamp.is_updated()) {
   1.205 +    _stamp.update(); // start at 0 on first call to stamp()
   1.206 +  }
   1.207 +
   1.208 +  // outputStream::stamp() may get called by ostream_abort(), use snprintf
   1.209 +  // to avoid allocating large stack buffer in print().
   1.210 +  char buf[40];
   1.211 +  jio_snprintf(buf, sizeof(buf), "%.3f", _stamp.seconds());
   1.212 +  print_raw(buf);
   1.213 +}
   1.214 +
   1.215 +void outputStream::stamp(bool guard,
   1.216 +                         const char* prefix,
   1.217 +                         const char* suffix) {
   1.218 +  if (!guard) {
   1.219 +    return;
   1.220 +  }
   1.221 +  print_raw(prefix);
   1.222 +  stamp();
   1.223 +  print_raw(suffix);
   1.224 +}
   1.225 +
   1.226 +void outputStream::date_stamp(bool guard,
   1.227 +                              const char* prefix,
   1.228 +                              const char* suffix) {
   1.229 +  if (!guard) {
   1.230 +    return;
   1.231 +  }
   1.232 +  print_raw(prefix);
   1.233 +  static const char error_time[] = "yyyy-mm-ddThh:mm:ss.mmm+zzzz";
   1.234 +  static const int buffer_length = 32;
   1.235 +  char buffer[buffer_length];
   1.236 +  const char* iso8601_result = os::iso8601_time(buffer, buffer_length);
   1.237 +  if (iso8601_result != NULL) {
   1.238 +    print_raw(buffer);
   1.239 +  } else {
   1.240 +    print_raw(error_time);
   1.241 +  }
   1.242 +  print_raw(suffix);
   1.243 +  return;
   1.244 +}
   1.245 +
   1.246 +outputStream& outputStream::indent() {
   1.247 +  while (_position < _indentation) sp();
   1.248 +  return *this;
   1.249 +}
   1.250 +
   1.251 +void outputStream::print_jlong(jlong value) {
   1.252 +  print(JLONG_FORMAT, value);
   1.253 +}
   1.254 +
   1.255 +void outputStream::print_julong(julong value) {
   1.256 +  print(JULONG_FORMAT, value);
   1.257 +}
   1.258 +
   1.259 +/**
   1.260 + * This prints out hex data in a 'windbg' or 'xxd' form, where each line is:
   1.261 + *   <hex-address>: 8 * <hex-halfword> <ascii translation (optional)>
   1.262 + * example:
   1.263 + * 0000000: 7f44 4f46 0102 0102 0000 0000 0000 0000  .DOF............
   1.264 + * 0000010: 0000 0000 0000 0040 0000 0020 0000 0005  .......@... ....
   1.265 + * 0000020: 0000 0000 0000 0040 0000 0000 0000 015d  .......@.......]
   1.266 + * ...
   1.267 + *
   1.268 + * indent is applied to each line.  Ends with a CR.
   1.269 + */
   1.270 +void outputStream::print_data(void* data, size_t len, bool with_ascii) {
   1.271 +  size_t limit = (len + 16) / 16 * 16;
   1.272 +  for (size_t i = 0; i < limit; ++i) {
   1.273 +    if (i % 16 == 0) {
   1.274 +      indent().print(SIZE_FORMAT_HEX_W(07)":", i);
   1.275 +    }
   1.276 +    if (i % 2 == 0) {
   1.277 +      print(" ");
   1.278 +    }
   1.279 +    if (i < len) {
   1.280 +      print("%02x", ((unsigned char*)data)[i]);
   1.281 +    } else {
   1.282 +      print("  ");
   1.283 +    }
   1.284 +    if ((i + 1) % 16 == 0) {
   1.285 +      if (with_ascii) {
   1.286 +        print("  ");
   1.287 +        for (size_t j = 0; j < 16; ++j) {
   1.288 +          size_t idx = i + j - 15;
   1.289 +          if (idx < len) {
   1.290 +            char c = ((char*)data)[idx];
   1.291 +            print("%c", c >= 32 && c <= 126 ? c : '.');
   1.292 +          }
   1.293 +        }
   1.294 +      }
   1.295 +      cr();
   1.296 +    }
   1.297 +  }
   1.298 +}
   1.299 +
   1.300 +stringStream::stringStream(size_t initial_size) : outputStream() {
   1.301 +  buffer_length = initial_size;
   1.302 +  buffer        = NEW_RESOURCE_ARRAY(char, buffer_length);
   1.303 +  buffer_pos    = 0;
   1.304 +  buffer_fixed  = false;
   1.305 +  DEBUG_ONLY(rm = Thread::current()->current_resource_mark();)
   1.306 +}
   1.307 +
   1.308 +// useful for output to fixed chunks of memory, such as performance counters
   1.309 +stringStream::stringStream(char* fixed_buffer, size_t fixed_buffer_size) : outputStream() {
   1.310 +  buffer_length = fixed_buffer_size;
   1.311 +  buffer        = fixed_buffer;
   1.312 +  buffer_pos    = 0;
   1.313 +  buffer_fixed  = true;
   1.314 +}
   1.315 +
   1.316 +void stringStream::write(const char* s, size_t len) {
   1.317 +  size_t write_len = len;               // number of non-null bytes to write
   1.318 +  size_t end = buffer_pos + len + 1;    // position after write and final '\0'
   1.319 +  if (end > buffer_length) {
   1.320 +    if (buffer_fixed) {
   1.321 +      // if buffer cannot resize, silently truncate
   1.322 +      end = buffer_length;
   1.323 +      write_len = end - buffer_pos - 1; // leave room for the final '\0'
   1.324 +    } else {
   1.325 +      // For small overruns, double the buffer.  For larger ones,
   1.326 +      // increase to the requested size.
   1.327 +      if (end < buffer_length * 2) {
   1.328 +        end = buffer_length * 2;
   1.329 +      }
   1.330 +      char* oldbuf = buffer;
   1.331 +      assert(rm == NULL || Thread::current()->current_resource_mark() == rm,
   1.332 +             "stringStream is re-allocated with a different ResourceMark");
   1.333 +      buffer = NEW_RESOURCE_ARRAY(char, end);
   1.334 +      strncpy(buffer, oldbuf, buffer_pos);
   1.335 +      buffer_length = end;
   1.336 +    }
   1.337 +  }
   1.338 +  // invariant: buffer is always null-terminated
   1.339 +  guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
   1.340 +  buffer[buffer_pos + write_len] = 0;
   1.341 +  strncpy(buffer + buffer_pos, s, write_len);
   1.342 +  buffer_pos += write_len;
   1.343 +
   1.344 +  // Note that the following does not depend on write_len.
   1.345 +  // This means that position and count get updated
   1.346 +  // even when overflow occurs.
   1.347 +  update_position(s, len);
   1.348 +}
   1.349 +
   1.350 +char* stringStream::as_string() {
   1.351 +  char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
   1.352 +  strncpy(copy, buffer, buffer_pos);
   1.353 +  copy[buffer_pos] = 0;  // terminating null
   1.354 +  return copy;
   1.355 +}
   1.356 +
   1.357 +stringStream::~stringStream() {}
   1.358 +
   1.359 +xmlStream*   xtty;
   1.360 +outputStream* tty;
   1.361 +outputStream* gclog_or_tty;
   1.362 +extern Mutex* tty_lock;
   1.363 +
   1.364 +#define EXTRACHARLEN   32
   1.365 +#define CURRENTAPPX    ".current"
   1.366 +#define FILENAMEBUFLEN  1024
   1.367 +// convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
   1.368 +char* get_datetime_string(char *buf, size_t len) {
   1.369 +  os::local_time_string(buf, len);
   1.370 +  int i = (int)strlen(buf);
   1.371 +  while (i-- >= 0) {
   1.372 +    if (buf[i] == ' ') buf[i] = '_';
   1.373 +    else if (buf[i] == ':') buf[i] = '-';
   1.374 +  }
   1.375 +  return buf;
   1.376 +}
   1.377 +
   1.378 +static const char* make_log_name_internal(const char* log_name, const char* force_directory,
   1.379 +                                                int pid, const char* tms) {
   1.380 +  const char* basename = log_name;
   1.381 +  char file_sep = os::file_separator()[0];
   1.382 +  const char* cp;
   1.383 +  char  pid_text[32];
   1.384 +
   1.385 +  for (cp = log_name; *cp != '\0'; cp++) {
   1.386 +    if (*cp == '/' || *cp == file_sep) {
   1.387 +      basename = cp + 1;
   1.388 +    }
   1.389 +  }
   1.390 +  const char* nametail = log_name;
   1.391 +  // Compute buffer length
   1.392 +  size_t buffer_length;
   1.393 +  if (force_directory != NULL) {
   1.394 +    buffer_length = strlen(force_directory) + strlen(os::file_separator()) +
   1.395 +                    strlen(basename) + 1;
   1.396 +  } else {
   1.397 +    buffer_length = strlen(log_name) + 1;
   1.398 +  }
   1.399 +
   1.400 +  // const char* star = strchr(basename, '*');
   1.401 +  const char* pts = strstr(basename, "%p");
   1.402 +  int pid_pos = (pts == NULL) ? -1 : (pts - nametail);
   1.403 +
   1.404 +  if (pid_pos >= 0) {
   1.405 +    jio_snprintf(pid_text, sizeof(pid_text), "pid%u", pid);
   1.406 +    buffer_length += strlen(pid_text);
   1.407 +  }
   1.408 +
   1.409 +  pts = strstr(basename, "%t");
   1.410 +  int tms_pos = (pts == NULL) ? -1 : (pts - nametail);
   1.411 +  if (tms_pos >= 0) {
   1.412 +    buffer_length += strlen(tms);
   1.413 +  }
   1.414 +
   1.415 +  // Create big enough buffer.
   1.416 +  char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
   1.417 +
   1.418 +  strcpy(buf, "");
   1.419 +  if (force_directory != NULL) {
   1.420 +    strcat(buf, force_directory);
   1.421 +    strcat(buf, os::file_separator());
   1.422 +    nametail = basename;       // completely skip directory prefix
   1.423 +  }
   1.424 +
   1.425 +  // who is first, %p or %t?
   1.426 +  int first = -1, second = -1;
   1.427 +  const char *p1st = NULL;
   1.428 +  const char *p2nd = NULL;
   1.429 +
   1.430 +  if (pid_pos >= 0 && tms_pos >= 0) {
   1.431 +    // contains both %p and %t
   1.432 +    if (pid_pos < tms_pos) {
   1.433 +      // case foo%pbar%tmonkey.log
   1.434 +      first  = pid_pos;
   1.435 +      p1st   = pid_text;
   1.436 +      second = tms_pos;
   1.437 +      p2nd   = tms;
   1.438 +    } else {
   1.439 +      // case foo%tbar%pmonkey.log
   1.440 +      first  = tms_pos;
   1.441 +      p1st   = tms;
   1.442 +      second = pid_pos;
   1.443 +      p2nd   = pid_text;
   1.444 +    }
   1.445 +  } else if (pid_pos >= 0) {
   1.446 +    // contains %p only
   1.447 +    first  = pid_pos;
   1.448 +    p1st   = pid_text;
   1.449 +  } else if (tms_pos >= 0) {
   1.450 +    // contains %t only
   1.451 +    first  = tms_pos;
   1.452 +    p1st   = tms;
   1.453 +  }
   1.454 +
   1.455 +  int buf_pos = (int)strlen(buf);
   1.456 +  const char* tail = nametail;
   1.457 +
   1.458 +  if (first >= 0) {
   1.459 +    tail = nametail + first + 2;
   1.460 +    strncpy(&buf[buf_pos], nametail, first);
   1.461 +    strcpy(&buf[buf_pos + first], p1st);
   1.462 +    buf_pos = (int)strlen(buf);
   1.463 +    if (second >= 0) {
   1.464 +      strncpy(&buf[buf_pos], tail, second - first - 2);
   1.465 +      strcpy(&buf[buf_pos + second - first - 2], p2nd);
   1.466 +      tail = nametail + second + 2;
   1.467 +    }
   1.468 +  }
   1.469 +  strcat(buf, tail);      // append rest of name, or all of name
   1.470 +  return buf;
   1.471 +}
   1.472 +
   1.473 +// log_name comes from -XX:LogFile=log_name or -Xloggc:log_name
   1.474 +// in log_name, %p => pid1234 and
   1.475 +//              %t => YYYY-MM-DD_HH-MM-SS
   1.476 +static const char* make_log_name(const char* log_name, const char* force_directory) {
   1.477 +  char timestr[32];
   1.478 +  get_datetime_string(timestr, sizeof(timestr));
   1.479 +  return make_log_name_internal(log_name, force_directory, os::current_process_id(),
   1.480 +                                timestr);
   1.481 +}
   1.482 +
   1.483 +#ifndef PRODUCT
   1.484 +void test_loggc_filename() {
   1.485 +  int pid;
   1.486 +  char  tms[32];
   1.487 +  char  i_result[FILENAMEBUFLEN];
   1.488 +  const char* o_result;
   1.489 +  get_datetime_string(tms, sizeof(tms));
   1.490 +  pid = os::current_process_id();
   1.491 +
   1.492 +  // test.log
   1.493 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms);
   1.494 +  o_result = make_log_name_internal("test.log", NULL, pid, tms);
   1.495 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)");
   1.496 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   1.497 +
   1.498 +  // test-%t-%p.log
   1.499 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid);
   1.500 +  o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms);
   1.501 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)");
   1.502 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   1.503 +
   1.504 +  // test-%t%p.log
   1.505 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid);
   1.506 +  o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms);
   1.507 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)");
   1.508 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   1.509 +
   1.510 +  // %p%t.log
   1.511 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms);
   1.512 +  o_result = make_log_name_internal("%p%t.log", NULL, pid, tms);
   1.513 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)");
   1.514 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   1.515 +
   1.516 +  // %p-test.log
   1.517 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid);
   1.518 +  o_result = make_log_name_internal("%p-test.log", NULL, pid, tms);
   1.519 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)");
   1.520 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   1.521 +
   1.522 +  // %t.log
   1.523 +  jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms);
   1.524 +  o_result = make_log_name_internal("%t.log", NULL, pid, tms);
   1.525 +  assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)");
   1.526 +  FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
   1.527 +}
   1.528 +#endif // PRODUCT
   1.529 +
   1.530 +fileStream::fileStream(const char* file_name) {
   1.531 +  _file = fopen(file_name, "w");
   1.532 +  if (_file != NULL) {
   1.533 +    _need_close = true;
   1.534 +  } else {
   1.535 +    warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
   1.536 +    _need_close = false;
   1.537 +  }
   1.538 +}
   1.539 +
   1.540 +fileStream::fileStream(const char* file_name, const char* opentype) {
   1.541 +  _file = fopen(file_name, opentype);
   1.542 +  if (_file != NULL) {
   1.543 +    _need_close = true;
   1.544 +  } else {
   1.545 +    warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
   1.546 +    _need_close = false;
   1.547 +  }
   1.548 +}
   1.549 +
   1.550 +void fileStream::write(const char* s, size_t len) {
   1.551 +  if (_file != NULL)  {
   1.552 +    // Make an unused local variable to avoid warning from gcc 4.x compiler.
   1.553 +    size_t count = fwrite(s, 1, len, _file);
   1.554 +  }
   1.555 +  update_position(s, len);
   1.556 +}
   1.557 +
   1.558 +long fileStream::fileSize() {
   1.559 +  long size = -1;
   1.560 +  if (_file != NULL) {
   1.561 +    long pos  = ::ftell(_file);
   1.562 +    if (::fseek(_file, 0, SEEK_END) == 0) {
   1.563 +      size = ::ftell(_file);
   1.564 +    }
   1.565 +    ::fseek(_file, pos, SEEK_SET);
   1.566 +  }
   1.567 +  return size;
   1.568 +}
   1.569 +
   1.570 +char* fileStream::readln(char *data, int count ) {
   1.571 +  char * ret = ::fgets(data, count, _file);
   1.572 +  //Get rid of annoying \n char
   1.573 +  data[::strlen(data)-1] = '\0';
   1.574 +  return ret;
   1.575 +}
   1.576 +
   1.577 +fileStream::~fileStream() {
   1.578 +  if (_file != NULL) {
   1.579 +    if (_need_close) fclose(_file);
   1.580 +    _file      = NULL;
   1.581 +  }
   1.582 +}
   1.583 +
   1.584 +void fileStream::flush() {
   1.585 +  fflush(_file);
   1.586 +}
   1.587 +
   1.588 +fdStream::fdStream(const char* file_name) {
   1.589 +  _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
   1.590 +  _need_close = true;
   1.591 +}
   1.592 +
   1.593 +fdStream::~fdStream() {
   1.594 +  if (_fd != -1) {
   1.595 +    if (_need_close) close(_fd);
   1.596 +    _fd = -1;
   1.597 +  }
   1.598 +}
   1.599 +
   1.600 +void fdStream::write(const char* s, size_t len) {
   1.601 +  if (_fd != -1) {
   1.602 +    // Make an unused local variable to avoid warning from gcc 4.x compiler.
   1.603 +    size_t count = ::write(_fd, s, (int)len);
   1.604 +  }
   1.605 +  update_position(s, len);
   1.606 +}
   1.607 +
   1.608 +// dump vm version, os version, platform info, build id,
   1.609 +// memory usage and command line flags into header
   1.610 +void gcLogFileStream::dump_loggc_header() {
   1.611 +  if (is_open()) {
   1.612 +    print_cr("%s", Abstract_VM_Version::internal_vm_info_string());
   1.613 +    os::print_memory_info(this);
   1.614 +    print("CommandLine flags: ");
   1.615 +    CommandLineFlags::printSetFlags(this);
   1.616 +  }
   1.617 +}
   1.618 +
   1.619 +gcLogFileStream::~gcLogFileStream() {
   1.620 +  if (_file != NULL) {
   1.621 +    if (_need_close) fclose(_file);
   1.622 +    _file = NULL;
   1.623 +  }
   1.624 +  if (_file_name != NULL) {
   1.625 +    FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
   1.626 +    _file_name = NULL;
   1.627 +  }
   1.628 +}
   1.629 +
   1.630 +gcLogFileStream::gcLogFileStream(const char* file_name) {
   1.631 +  _cur_file_num = 0;
   1.632 +  _bytes_written = 0L;
   1.633 +  _file_name = make_log_name(file_name, NULL);
   1.634 +
   1.635 +  // gc log file rotation
   1.636 +  if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) {
   1.637 +    char tempbuf[FILENAMEBUFLEN];
   1.638 +    jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
   1.639 +    _file = fopen(tempbuf, "w");
   1.640 +  } else {
   1.641 +    _file = fopen(_file_name, "w");
   1.642 +  }
   1.643 +  if (_file != NULL) {
   1.644 +    _need_close = true;
   1.645 +    dump_loggc_header();
   1.646 +  } else {
   1.647 +    warning("Cannot open file %s due to %s\n", _file_name, strerror(errno));
   1.648 +    _need_close = false;
   1.649 +  }
   1.650 +}
   1.651 +
   1.652 +void gcLogFileStream::write(const char* s, size_t len) {
   1.653 +  if (_file != NULL) {
   1.654 +    size_t count = fwrite(s, 1, len, _file);
   1.655 +    _bytes_written += count;
   1.656 +  }
   1.657 +  update_position(s, len);
   1.658 +}
   1.659 +
   1.660 +// rotate_log must be called from VMThread at safepoint. In case need change parameters
   1.661 +// for gc log rotation from thread other than VMThread, a sub type of VM_Operation
   1.662 +// should be created and be submitted to VMThread's operation queue. DO NOT call this
   1.663 +// function directly. Currently, it is safe to rotate log at safepoint through VMThread.
   1.664 +// That is, no mutator threads and concurrent GC threads run parallel with VMThread to
   1.665 +// write to gc log file at safepoint. If in future, changes made for mutator threads or
   1.666 +// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
   1.667 +// must be synchronized.
   1.668 +void gcLogFileStream::rotate_log(bool force, outputStream* out) {
   1.669 +  char time_msg[FILENAMEBUFLEN];
   1.670 +  char time_str[EXTRACHARLEN];
   1.671 +  char current_file_name[FILENAMEBUFLEN];
   1.672 +  char renamed_file_name[FILENAMEBUFLEN];
   1.673 +
   1.674 +  if (!should_rotate(force)) {
   1.675 +    return;
   1.676 +  }
   1.677 +
   1.678 +#ifdef ASSERT
   1.679 +  Thread *thread = Thread::current();
   1.680 +  assert(thread == NULL ||
   1.681 +         (thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()),
   1.682 +         "Must be VMThread at safepoint");
   1.683 +#endif
   1.684 +  if (NumberOfGCLogFiles == 1) {
   1.685 +    // rotate in same file
   1.686 +    rewind();
   1.687 +    _bytes_written = 0L;
   1.688 +    jio_snprintf(time_msg, sizeof(time_msg), "File  %s rotated at %s\n",
   1.689 +                 _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
   1.690 +    write(time_msg, strlen(time_msg));
   1.691 +
   1.692 +    if (out != NULL) {
   1.693 +      out->print("%s", time_msg);
   1.694 +    }
   1.695 +
   1.696 +    dump_loggc_header();
   1.697 +    return;
   1.698 +  }
   1.699 +
   1.700 +#if defined(_WINDOWS)
   1.701 +#ifndef F_OK
   1.702 +#define F_OK 0
   1.703 +#endif
   1.704 +#endif // _WINDOWS
   1.705 +
   1.706 +  // rotate file in names extended_filename.0, extended_filename.1, ...,
   1.707 +  // extended_filename.<NumberOfGCLogFiles - 1>. Current rotation file name will
   1.708 +  // have a form of extended_filename.<i>.current where i is the current rotation
   1.709 +  // file number. After it reaches max file size, the file will be saved and renamed
   1.710 +  // with .current removed from its tail.
   1.711 +  size_t filename_len = strlen(_file_name);
   1.712 +  if (_file != NULL) {
   1.713 +    jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d",
   1.714 +                 _file_name, _cur_file_num);
   1.715 +    jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
   1.716 +                 _file_name, _cur_file_num);
   1.717 +
   1.718 +    const char* msg = force ? "GC log rotation request has been received."
   1.719 +                            : "GC log file has reached the maximum size.";
   1.720 +    jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n",
   1.721 +                     os::local_time_string((char *)time_str, sizeof(time_str)),
   1.722 +                                                         msg, renamed_file_name);
   1.723 +    write(time_msg, strlen(time_msg));
   1.724 +
   1.725 +    if (out != NULL) {
   1.726 +      out->print("%s", time_msg);
   1.727 +    }
   1.728 +
   1.729 +    fclose(_file);
   1.730 +    _file = NULL;
   1.731 +
   1.732 +    bool can_rename = true;
   1.733 +    if (access(current_file_name, F_OK) != 0) {
   1.734 +      // current file does not exist?
   1.735 +      warning("No source file exists, cannot rename\n");
   1.736 +      can_rename = false;
   1.737 +    }
   1.738 +    if (can_rename) {
   1.739 +      if (access(renamed_file_name, F_OK) == 0) {
   1.740 +        if (remove(renamed_file_name) != 0) {
   1.741 +          warning("Could not delete existing file %s\n", renamed_file_name);
   1.742 +          can_rename = false;
   1.743 +        }
   1.744 +      } else {
   1.745 +        // file does not exist, ok to rename
   1.746 +      }
   1.747 +    }
   1.748 +    if (can_rename && rename(current_file_name, renamed_file_name) != 0) {
   1.749 +      warning("Could not rename %s to %s\n", _file_name, renamed_file_name);
   1.750 +    }
   1.751 +  }
   1.752 +
   1.753 +  _cur_file_num++;
   1.754 +  if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
   1.755 +  jio_snprintf(current_file_name,  filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
   1.756 +               _file_name, _cur_file_num);
   1.757 +  _file = fopen(current_file_name, "w");
   1.758 +
   1.759 +  if (_file != NULL) {
   1.760 +    _bytes_written = 0L;
   1.761 +    _need_close = true;
   1.762 +    // reuse current_file_name for time_msg
   1.763 +    jio_snprintf(current_file_name, filename_len + EXTRACHARLEN,
   1.764 +                 "%s.%d", _file_name, _cur_file_num);
   1.765 +    jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
   1.766 +                           os::local_time_string((char *)time_str, sizeof(time_str)),
   1.767 +                           current_file_name);
   1.768 +    write(time_msg, strlen(time_msg));
   1.769 +
   1.770 +    if (out != NULL) {
   1.771 +      out->print("%s", time_msg);
   1.772 +    }
   1.773 +
   1.774 +    dump_loggc_header();
   1.775 +    // remove the existing file
   1.776 +    if (access(current_file_name, F_OK) == 0) {
   1.777 +      if (remove(current_file_name) != 0) {
   1.778 +        warning("Could not delete existing file %s\n", current_file_name);
   1.779 +      }
   1.780 +    }
   1.781 +  } else {
   1.782 +    warning("failed to open rotation log file %s due to %s\n"
   1.783 +            "Turned off GC log file rotation\n",
   1.784 +                  _file_name, strerror(errno));
   1.785 +    _need_close = false;
   1.786 +    FLAG_SET_DEFAULT(UseGCLogFileRotation, false);
   1.787 +  }
   1.788 +}
   1.789 +
   1.790 +defaultStream* defaultStream::instance = NULL;
   1.791 +int defaultStream::_output_fd = 1;
   1.792 +int defaultStream::_error_fd  = 2;
   1.793 +FILE* defaultStream::_output_stream = stdout;
   1.794 +FILE* defaultStream::_error_stream  = stderr;
   1.795 +
   1.796 +#define LOG_MAJOR_VERSION 160
   1.797 +#define LOG_MINOR_VERSION 1
   1.798 +
   1.799 +void defaultStream::init() {
   1.800 +  _inited = true;
   1.801 +  if (LogVMOutput || LogCompilation) {
   1.802 +    init_log();
   1.803 +  }
   1.804 +}
   1.805 +
   1.806 +bool defaultStream::has_log_file() {
   1.807 +  // lazily create log file (at startup, LogVMOutput is false even
   1.808 +  // if +LogVMOutput is used, because the flags haven't been parsed yet)
   1.809 +  // For safer printing during fatal error handling, do not init logfile
   1.810 +  // if a VM error has been reported.
   1.811 +  if (!_inited && !is_error_reported())  init();
   1.812 +  return _log_file != NULL;
   1.813 +}
   1.814 +
   1.815 +void defaultStream::init_log() {
   1.816 +  // %%% Need a MutexLocker?
   1.817 +  const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log";
   1.818 +  const char* try_name = make_log_name(log_name, NULL);
   1.819 +  fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
   1.820 +  if (!file->is_open()) {
   1.821 +    // Try again to open the file.
   1.822 +    char warnbuf[O_BUFLEN*2];
   1.823 +    jio_snprintf(warnbuf, sizeof(warnbuf),
   1.824 +                 "Warning:  Cannot open log file: %s\n", try_name);
   1.825 +    // Note:  This feature is for maintainer use only.  No need for L10N.
   1.826 +    jio_print(warnbuf);
   1.827 +    FREE_C_HEAP_ARRAY(char, try_name, mtInternal);
   1.828 +    try_name = make_log_name(log_name, os::get_temp_directory());
   1.829 +    jio_snprintf(warnbuf, sizeof(warnbuf),
   1.830 +                 "Warning:  Forcing option -XX:LogFile=%s\n", try_name);
   1.831 +    jio_print(warnbuf);
   1.832 +    delete file;
   1.833 +    file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
   1.834 +  }
   1.835 +  FREE_C_HEAP_ARRAY(char, try_name, mtInternal);
   1.836 +
   1.837 +  if (file->is_open()) {
   1.838 +    _log_file = file;
   1.839 +    xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file);
   1.840 +    _outer_xmlStream = xs;
   1.841 +    if (this == tty)  xtty = xs;
   1.842 +    // Write XML header.
   1.843 +    xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>");
   1.844 +    // (For now, don't bother to issue a DTD for this private format.)
   1.845 +    jlong time_ms = os::javaTimeMillis() - tty->time_stamp().milliseconds();
   1.846 +    // %%% Should be: jlong time_ms = os::start_time_milliseconds(), if
   1.847 +    // we ever get round to introduce that method on the os class
   1.848 +    xs->head("hotspot_log version='%d %d'"
   1.849 +             " process='%d' time_ms='"INT64_FORMAT"'",
   1.850 +             LOG_MAJOR_VERSION, LOG_MINOR_VERSION,
   1.851 +             os::current_process_id(), (int64_t)time_ms);
   1.852 +    // Write VM version header immediately.
   1.853 +    xs->head("vm_version");
   1.854 +    xs->head("name"); xs->text("%s", VM_Version::vm_name()); xs->cr();
   1.855 +    xs->tail("name");
   1.856 +    xs->head("release"); xs->text("%s", VM_Version::vm_release()); xs->cr();
   1.857 +    xs->tail("release");
   1.858 +    xs->head("info"); xs->text("%s", VM_Version::internal_vm_info_string()); xs->cr();
   1.859 +    xs->tail("info");
   1.860 +    xs->tail("vm_version");
   1.861 +    // Record information about the command-line invocation.
   1.862 +    xs->head("vm_arguments");  // Cf. Arguments::print_on()
   1.863 +    if (Arguments::num_jvm_flags() > 0) {
   1.864 +      xs->head("flags");
   1.865 +      Arguments::print_jvm_flags_on(xs->text());
   1.866 +      xs->tail("flags");
   1.867 +    }
   1.868 +    if (Arguments::num_jvm_args() > 0) {
   1.869 +      xs->head("args");
   1.870 +      Arguments::print_jvm_args_on(xs->text());
   1.871 +      xs->tail("args");
   1.872 +    }
   1.873 +    if (Arguments::java_command() != NULL) {
   1.874 +      xs->head("command"); xs->text()->print_cr("%s", Arguments::java_command());
   1.875 +      xs->tail("command");
   1.876 +    }
   1.877 +    if (Arguments::sun_java_launcher() != NULL) {
   1.878 +      xs->head("launcher"); xs->text()->print_cr("%s", Arguments::sun_java_launcher());
   1.879 +      xs->tail("launcher");
   1.880 +    }
   1.881 +    if (Arguments::system_properties() !=  NULL) {
   1.882 +      xs->head("properties");
   1.883 +      // Print it as a java-style property list.
   1.884 +      // System properties don't generally contain newlines, so don't bother with unparsing.
   1.885 +      for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) {
   1.886 +        xs->text()->print_cr("%s=%s", p->key(), p->value());
   1.887 +      }
   1.888 +      xs->tail("properties");
   1.889 +    }
   1.890 +    xs->tail("vm_arguments");
   1.891 +    // tty output per se is grouped under the <tty>...</tty> element.
   1.892 +    xs->head("tty");
   1.893 +    // All further non-markup text gets copied to the tty:
   1.894 +    xs->_text = this;  // requires friend declaration!
   1.895 +  } else {
   1.896 +    delete(file);
   1.897 +    // and leave xtty as NULL
   1.898 +    LogVMOutput = false;
   1.899 +    DisplayVMOutput = true;
   1.900 +    LogCompilation = false;
   1.901 +  }
   1.902 +}
   1.903 +
   1.904 +// finish_log() is called during normal VM shutdown. finish_log_on_error() is
   1.905 +// called by ostream_abort() after a fatal error.
   1.906 +//
   1.907 +void defaultStream::finish_log() {
   1.908 +  xmlStream* xs = _outer_xmlStream;
   1.909 +  xs->done("tty");
   1.910 +
   1.911 +  // Other log forks are appended here, at the End of Time:
   1.912 +  CompileLog::finish_log(xs->out());  // write compile logging, if any, now
   1.913 +
   1.914 +  xs->done("hotspot_log");
   1.915 +  xs->flush();
   1.916 +
   1.917 +  fileStream* file = _log_file;
   1.918 +  _log_file = NULL;
   1.919 +
   1.920 +  delete _outer_xmlStream;
   1.921 +  _outer_xmlStream = NULL;
   1.922 +
   1.923 +  file->flush();
   1.924 +  delete file;
   1.925 +}
   1.926 +
   1.927 +void defaultStream::finish_log_on_error(char *buf, int buflen) {
   1.928 +  xmlStream* xs = _outer_xmlStream;
   1.929 +
   1.930 +  if (xs && xs->out()) {
   1.931 +
   1.932 +    xs->done_raw("tty");
   1.933 +
   1.934 +    // Other log forks are appended here, at the End of Time:
   1.935 +    CompileLog::finish_log_on_error(xs->out(), buf, buflen);  // write compile logging, if any, now
   1.936 +
   1.937 +    xs->done_raw("hotspot_log");
   1.938 +    xs->flush();
   1.939 +
   1.940 +    fileStream* file = _log_file;
   1.941 +    _log_file = NULL;
   1.942 +    _outer_xmlStream = NULL;
   1.943 +
   1.944 +    if (file) {
   1.945 +      file->flush();
   1.946 +
   1.947 +      // Can't delete or close the file because delete and fclose aren't
   1.948 +      // async-safe. We are about to die, so leave it to the kernel.
   1.949 +      // delete file;
   1.950 +    }
   1.951 +  }
   1.952 +}
   1.953 +
   1.954 +intx defaultStream::hold(intx writer_id) {
   1.955 +  bool has_log = has_log_file();  // check before locking
   1.956 +  if (// impossible, but who knows?
   1.957 +      writer_id == NO_WRITER ||
   1.958 +
   1.959 +      // bootstrap problem
   1.960 +      tty_lock == NULL ||
   1.961 +
   1.962 +      // can't grab a lock or call Thread::current() if TLS isn't initialized
   1.963 +      ThreadLocalStorage::thread() == NULL ||
   1.964 +
   1.965 +      // developer hook
   1.966 +      !SerializeVMOutput ||
   1.967 +
   1.968 +      // VM already unhealthy
   1.969 +      is_error_reported() ||
   1.970 +
   1.971 +      // safepoint == global lock (for VM only)
   1.972 +      (SafepointSynchronize::is_synchronizing() &&
   1.973 +       Thread::current()->is_VM_thread())
   1.974 +      ) {
   1.975 +    // do not attempt to lock unless we know the thread and the VM is healthy
   1.976 +    return NO_WRITER;
   1.977 +  }
   1.978 +  if (_writer == writer_id) {
   1.979 +    // already held, no need to re-grab the lock
   1.980 +    return NO_WRITER;
   1.981 +  }
   1.982 +  tty_lock->lock_without_safepoint_check();
   1.983 +  // got the lock
   1.984 +  if (writer_id != _last_writer) {
   1.985 +    if (has_log) {
   1.986 +      _log_file->bol();
   1.987 +      // output a hint where this output is coming from:
   1.988 +      _log_file->print_cr("<writer thread='" UINTX_FORMAT "'/>", writer_id);
   1.989 +    }
   1.990 +    _last_writer = writer_id;
   1.991 +  }
   1.992 +  _writer = writer_id;
   1.993 +  return writer_id;
   1.994 +}
   1.995 +
   1.996 +void defaultStream::release(intx holder) {
   1.997 +  if (holder == NO_WRITER) {
   1.998 +    // nothing to release:  either a recursive lock, or we scribbled (too bad)
   1.999 +    return;
  1.1000 +  }
  1.1001 +  if (_writer != holder) {
  1.1002 +    return;  // already unlocked, perhaps via break_tty_lock_for_safepoint
  1.1003 +  }
  1.1004 +  _writer = NO_WRITER;
  1.1005 +  tty_lock->unlock();
  1.1006 +}
  1.1007 +
  1.1008 +
  1.1009 +// Yuck:  jio_print does not accept char*/len.
  1.1010 +static void call_jio_print(const char* s, size_t len) {
  1.1011 +  char buffer[O_BUFLEN+100];
  1.1012 +  if (len > sizeof(buffer)-1) {
  1.1013 +    warning("increase O_BUFLEN in ostream.cpp -- output truncated");
  1.1014 +    len = sizeof(buffer)-1;
  1.1015 +  }
  1.1016 +  strncpy(buffer, s, len);
  1.1017 +  buffer[len] = '\0';
  1.1018 +  jio_print(buffer);
  1.1019 +}
  1.1020 +
  1.1021 +
  1.1022 +void defaultStream::write(const char* s, size_t len) {
  1.1023 +  intx thread_id = os::current_thread_id();
  1.1024 +  intx holder = hold(thread_id);
  1.1025 +
  1.1026 +  if (DisplayVMOutput &&
  1.1027 +      (_outer_xmlStream == NULL || !_outer_xmlStream->inside_attrs())) {
  1.1028 +    // print to output stream. It can be redirected by a vfprintf hook
  1.1029 +    if (s[len] == '\0') {
  1.1030 +      jio_print(s);
  1.1031 +    } else {
  1.1032 +      call_jio_print(s, len);
  1.1033 +    }
  1.1034 +  }
  1.1035 +
  1.1036 +  // print to log file
  1.1037 +  if (has_log_file()) {
  1.1038 +    int nl0 = _newlines;
  1.1039 +    xmlTextStream::write(s, len);
  1.1040 +    // flush the log file too, if there were any newlines
  1.1041 +    if (nl0 != _newlines){
  1.1042 +      flush();
  1.1043 +    }
  1.1044 +  } else {
  1.1045 +    update_position(s, len);
  1.1046 +  }
  1.1047 +
  1.1048 +  release(holder);
  1.1049 +}
  1.1050 +
  1.1051 +intx ttyLocker::hold_tty() {
  1.1052 +  if (defaultStream::instance == NULL)  return defaultStream::NO_WRITER;
  1.1053 +  intx thread_id = os::current_thread_id();
  1.1054 +  return defaultStream::instance->hold(thread_id);
  1.1055 +}
  1.1056 +
  1.1057 +void ttyLocker::release_tty(intx holder) {
  1.1058 +  if (holder == defaultStream::NO_WRITER)  return;
  1.1059 +  defaultStream::instance->release(holder);
  1.1060 +}
  1.1061 +
  1.1062 +bool ttyLocker::release_tty_if_locked() {
  1.1063 +  intx thread_id = os::current_thread_id();
  1.1064 +  if (defaultStream::instance->writer() == thread_id) {
  1.1065 +    // release the lock and return true so callers know if was
  1.1066 +    // previously held.
  1.1067 +    release_tty(thread_id);
  1.1068 +    return true;
  1.1069 +  }
  1.1070 +  return false;
  1.1071 +}
  1.1072 +
  1.1073 +void ttyLocker::break_tty_lock_for_safepoint(intx holder) {
  1.1074 +  if (defaultStream::instance != NULL &&
  1.1075 +      defaultStream::instance->writer() == holder) {
  1.1076 +    if (xtty != NULL) {
  1.1077 +      xtty->print_cr("<!-- safepoint while printing -->");
  1.1078 +    }
  1.1079 +    defaultStream::instance->release(holder);
  1.1080 +  }
  1.1081 +  // (else there was no lock to break)
  1.1082 +}
  1.1083 +
  1.1084 +void ostream_init() {
  1.1085 +  if (defaultStream::instance == NULL) {
  1.1086 +    defaultStream::instance = new(ResourceObj::C_HEAP, mtInternal) defaultStream();
  1.1087 +    tty = defaultStream::instance;
  1.1088 +
  1.1089 +    // We want to ensure that time stamps in GC logs consider time 0
  1.1090 +    // the time when the JVM is initialized, not the first time we ask
  1.1091 +    // for a time stamp. So, here, we explicitly update the time stamp
  1.1092 +    // of tty.
  1.1093 +    tty->time_stamp().update_to(1);
  1.1094 +  }
  1.1095 +}
  1.1096 +
  1.1097 +void ostream_init_log() {
  1.1098 +  // For -Xloggc:<file> option - called in runtime/thread.cpp
  1.1099 +  // Note : this must be called AFTER ostream_init()
  1.1100 +
  1.1101 +  gclog_or_tty = tty; // default to tty
  1.1102 +  if (Arguments::gc_log_filename() != NULL) {
  1.1103 +    fileStream * gclog  = new(ResourceObj::C_HEAP, mtInternal)
  1.1104 +                             gcLogFileStream(Arguments::gc_log_filename());
  1.1105 +    if (gclog->is_open()) {
  1.1106 +      // now we update the time stamp of the GC log to be synced up
  1.1107 +      // with tty.
  1.1108 +      gclog->time_stamp().update_to(tty->time_stamp().ticks());
  1.1109 +    }
  1.1110 +    gclog_or_tty = gclog;
  1.1111 +  }
  1.1112 +
  1.1113 +  // If we haven't lazily initialized the logfile yet, do it now,
  1.1114 +  // to avoid the possibility of lazy initialization during a VM
  1.1115 +  // crash, which can affect the stability of the fatal error handler.
  1.1116 +  defaultStream::instance->has_log_file();
  1.1117 +}
  1.1118 +
  1.1119 +// ostream_exit() is called during normal VM exit to finish log files, flush
  1.1120 +// output and free resource.
  1.1121 +void ostream_exit() {
  1.1122 +  static bool ostream_exit_called = false;
  1.1123 +  if (ostream_exit_called)  return;
  1.1124 +  ostream_exit_called = true;
  1.1125 +  if (gclog_or_tty != tty) {
  1.1126 +      delete gclog_or_tty;
  1.1127 +  }
  1.1128 +  {
  1.1129 +      // we temporaly disable PrintMallocFree here
  1.1130 +      // as otherwise it'll lead to using of almost deleted
  1.1131 +      // tty or defaultStream::instance in logging facility
  1.1132 +      // of HeapFree(), see 6391258
  1.1133 +      DEBUG_ONLY(FlagSetting fs(PrintMallocFree, false);)
  1.1134 +      if (tty != defaultStream::instance) {
  1.1135 +          delete tty;
  1.1136 +      }
  1.1137 +      if (defaultStream::instance != NULL) {
  1.1138 +          delete defaultStream::instance;
  1.1139 +      }
  1.1140 +  }
  1.1141 +  tty = NULL;
  1.1142 +  xtty = NULL;
  1.1143 +  gclog_or_tty = NULL;
  1.1144 +  defaultStream::instance = NULL;
  1.1145 +}
  1.1146 +
  1.1147 +// ostream_abort() is called by os::abort() when VM is about to die.
  1.1148 +void ostream_abort() {
  1.1149 +  // Here we can't delete gclog_or_tty and tty, just flush their output
  1.1150 +  if (gclog_or_tty) gclog_or_tty->flush();
  1.1151 +  if (tty) tty->flush();
  1.1152 +
  1.1153 +  if (defaultStream::instance != NULL) {
  1.1154 +    static char buf[4096];
  1.1155 +    defaultStream::instance->finish_log_on_error(buf, sizeof(buf));
  1.1156 +  }
  1.1157 +}
  1.1158 +
  1.1159 +staticBufferStream::staticBufferStream(char* buffer, size_t buflen,
  1.1160 +                                       outputStream *outer_stream) {
  1.1161 +  _buffer = buffer;
  1.1162 +  _buflen = buflen;
  1.1163 +  _outer_stream = outer_stream;
  1.1164 +  // compile task prints time stamp relative to VM start
  1.1165 +  _stamp.update_to(1);
  1.1166 +}
  1.1167 +
  1.1168 +void staticBufferStream::write(const char* c, size_t len) {
  1.1169 +  _outer_stream->print_raw(c, (int)len);
  1.1170 +}
  1.1171 +
  1.1172 +void staticBufferStream::flush() {
  1.1173 +  _outer_stream->flush();
  1.1174 +}
  1.1175 +
  1.1176 +void staticBufferStream::print(const char* format, ...) {
  1.1177 +  va_list ap;
  1.1178 +  va_start(ap, format);
  1.1179 +  size_t len;
  1.1180 +  const char* str = do_vsnprintf(_buffer, _buflen, format, ap, false, len);
  1.1181 +  write(str, len);
  1.1182 +  va_end(ap);
  1.1183 +}
  1.1184 +
  1.1185 +void staticBufferStream::print_cr(const char* format, ...) {
  1.1186 +  va_list ap;
  1.1187 +  va_start(ap, format);
  1.1188 +  size_t len;
  1.1189 +  const char* str = do_vsnprintf(_buffer, _buflen, format, ap, true, len);
  1.1190 +  write(str, len);
  1.1191 +  va_end(ap);
  1.1192 +}
  1.1193 +
  1.1194 +void staticBufferStream::vprint(const char *format, va_list argptr) {
  1.1195 +  size_t len;
  1.1196 +  const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, false, len);
  1.1197 +  write(str, len);
  1.1198 +}
  1.1199 +
  1.1200 +void staticBufferStream::vprint_cr(const char* format, va_list argptr) {
  1.1201 +  size_t len;
  1.1202 +  const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, true, len);
  1.1203 +  write(str, len);
  1.1204 +}
  1.1205 +
  1.1206 +bufferedStream::bufferedStream(size_t initial_size, size_t bufmax) : outputStream() {
  1.1207 +  buffer_length = initial_size;
  1.1208 +  buffer        = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
  1.1209 +  buffer_pos    = 0;
  1.1210 +  buffer_fixed  = false;
  1.1211 +  buffer_max    = bufmax;
  1.1212 +}
  1.1213 +
  1.1214 +bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax) : outputStream() {
  1.1215 +  buffer_length = fixed_buffer_size;
  1.1216 +  buffer        = fixed_buffer;
  1.1217 +  buffer_pos    = 0;
  1.1218 +  buffer_fixed  = true;
  1.1219 +  buffer_max    = bufmax;
  1.1220 +}
  1.1221 +
  1.1222 +void bufferedStream::write(const char* s, size_t len) {
  1.1223 +
  1.1224 +  if(buffer_pos + len > buffer_max) {
  1.1225 +    flush();
  1.1226 +  }
  1.1227 +
  1.1228 +  size_t end = buffer_pos + len;
  1.1229 +  if (end >= buffer_length) {
  1.1230 +    if (buffer_fixed) {
  1.1231 +      // if buffer cannot resize, silently truncate
  1.1232 +      len = buffer_length - buffer_pos - 1;
  1.1233 +    } else {
  1.1234 +      // For small overruns, double the buffer.  For larger ones,
  1.1235 +      // increase to the requested size.
  1.1236 +      if (end < buffer_length * 2) {
  1.1237 +        end = buffer_length * 2;
  1.1238 +      }
  1.1239 +      buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal);
  1.1240 +      buffer_length = end;
  1.1241 +    }
  1.1242 +  }
  1.1243 +  memcpy(buffer + buffer_pos, s, len);
  1.1244 +  buffer_pos += len;
  1.1245 +  update_position(s, len);
  1.1246 +}
  1.1247 +
  1.1248 +char* bufferedStream::as_string() {
  1.1249 +  char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
  1.1250 +  strncpy(copy, buffer, buffer_pos);
  1.1251 +  copy[buffer_pos] = 0;  // terminating null
  1.1252 +  return copy;
  1.1253 +}
  1.1254 +
  1.1255 +bufferedStream::~bufferedStream() {
  1.1256 +  if (!buffer_fixed) {
  1.1257 +    FREE_C_HEAP_ARRAY(char, buffer, mtInternal);
  1.1258 +  }
  1.1259 +}
  1.1260 +
  1.1261 +#ifndef PRODUCT
  1.1262 +
  1.1263 +#if defined(SOLARIS) || defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE)
  1.1264 +#include <sys/types.h>
  1.1265 +#include <sys/socket.h>
  1.1266 +#include <netinet/in.h>
  1.1267 +#include <arpa/inet.h>
  1.1268 +#endif
  1.1269 +
  1.1270 +// Network access
  1.1271 +networkStream::networkStream() : bufferedStream(1024*10, 1024*10) {
  1.1272 +
  1.1273 +  _socket = -1;
  1.1274 +
  1.1275 +  int result = os::socket(AF_INET, SOCK_STREAM, 0);
  1.1276 +  if (result <= 0) {
  1.1277 +    assert(false, "Socket could not be created!");
  1.1278 +  } else {
  1.1279 +    _socket = result;
  1.1280 +  }
  1.1281 +}
  1.1282 +
  1.1283 +int networkStream::read(char *buf, size_t len) {
  1.1284 +  return os::recv(_socket, buf, (int)len, 0);
  1.1285 +}
  1.1286 +
  1.1287 +void networkStream::flush() {
  1.1288 +  if (size() != 0) {
  1.1289 +    int result = os::raw_send(_socket, (char *)base(), size(), 0);
  1.1290 +    assert(result != -1, "connection error");
  1.1291 +    assert(result == (int)size(), "didn't send enough data");
  1.1292 +  }
  1.1293 +  reset();
  1.1294 +}
  1.1295 +
  1.1296 +networkStream::~networkStream() {
  1.1297 +  close();
  1.1298 +}
  1.1299 +
  1.1300 +void networkStream::close() {
  1.1301 +  if (_socket != -1) {
  1.1302 +    flush();
  1.1303 +    os::socket_close(_socket);
  1.1304 +    _socket = -1;
  1.1305 +  }
  1.1306 +}
  1.1307 +
  1.1308 +bool networkStream::connect(const char *ip, short port) {
  1.1309 +
  1.1310 +  struct sockaddr_in server;
  1.1311 +  server.sin_family = AF_INET;
  1.1312 +  server.sin_port = htons(port);
  1.1313 +
  1.1314 +  server.sin_addr.s_addr = inet_addr(ip);
  1.1315 +  if (server.sin_addr.s_addr == (uint32_t)-1) {
  1.1316 +    struct hostent* host = os::get_host_by_name((char*)ip);
  1.1317 +    if (host != NULL) {
  1.1318 +      memcpy(&server.sin_addr, host->h_addr_list[0], host->h_length);
  1.1319 +    } else {
  1.1320 +      return false;
  1.1321 +    }
  1.1322 +  }
  1.1323 +
  1.1324 +
  1.1325 +  int result = os::connect(_socket, (struct sockaddr*)&server, sizeof(struct sockaddr_in));
  1.1326 +  return (result >= 0);
  1.1327 +}
  1.1328 +
  1.1329 +#endif

mercurial