Thu, 20 Nov 2008 16:56:09 -0800
6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa
1 /*
2 * Copyright 1997-2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
25 # include "incls/_precompiled.incl"
26 # include "incls/_ostream.cpp.incl"
28 extern "C" void jio_print(const char* s); // Declarationtion of jvm method
30 outputStream::outputStream(int width) {
31 _width = width;
32 _position = 0;
33 _newlines = 0;
34 _precount = 0;
35 _indentation = 0;
36 }
38 outputStream::outputStream(int width, bool has_time_stamps) {
39 _width = width;
40 _position = 0;
41 _newlines = 0;
42 _precount = 0;
43 _indentation = 0;
44 if (has_time_stamps) _stamp.update();
45 }
47 void outputStream::update_position(const char* s, size_t len) {
48 for (size_t i = 0; i < len; i++) {
49 char ch = s[i];
50 if (ch == '\n') {
51 _newlines += 1;
52 _precount += _position + 1;
53 _position = 0;
54 } else if (ch == '\t') {
55 int tw = 8 - (_position & 7);
56 _position += tw;
57 _precount -= tw-1; // invariant: _precount + _position == total count
58 } else {
59 _position += 1;
60 }
61 }
62 }
64 // Execute a vsprintf, using the given buffer if necessary.
65 // Return a pointer to the formatted string.
66 const char* outputStream::do_vsnprintf(char* buffer, size_t buflen,
67 const char* format, va_list ap,
68 bool add_cr,
69 size_t& result_len) {
70 const char* result;
71 if (add_cr) buflen--;
72 if (!strchr(format, '%')) {
73 // constant format string
74 result = format;
75 result_len = strlen(result);
76 if (add_cr && result_len >= buflen) result_len = buflen-1; // truncate
77 } else if (format[0] == '%' && format[1] == 's' && format[2] == '\0') {
78 // trivial copy-through format string
79 result = va_arg(ap, const char*);
80 result_len = strlen(result);
81 if (add_cr && result_len >= buflen) result_len = buflen-1; // truncate
82 } else if (vsnprintf(buffer, buflen, format, ap) >= 0) {
83 result = buffer;
84 result_len = strlen(result);
85 } else {
86 DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");)
87 result = buffer;
88 result_len = buflen - 1;
89 buffer[result_len] = 0;
90 }
91 if (add_cr) {
92 if (result != buffer) {
93 strncpy(buffer, result, buflen);
94 result = buffer;
95 }
96 buffer[result_len++] = '\n';
97 buffer[result_len] = 0;
98 }
99 return result;
100 }
102 void outputStream::print(const char* format, ...) {
103 char buffer[O_BUFLEN];
104 va_list ap;
105 va_start(ap, format);
106 size_t len;
107 const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, false, len);
108 write(str, len);
109 va_end(ap);
110 }
112 void outputStream::print_cr(const char* format, ...) {
113 char buffer[O_BUFLEN];
114 va_list ap;
115 va_start(ap, format);
116 size_t len;
117 const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, true, len);
118 write(str, len);
119 va_end(ap);
120 }
122 void outputStream::vprint(const char *format, va_list argptr) {
123 char buffer[O_BUFLEN];
124 size_t len;
125 const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, false, len);
126 write(str, len);
127 }
129 void outputStream::vprint_cr(const char* format, va_list argptr) {
130 char buffer[O_BUFLEN];
131 size_t len;
132 const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, true, len);
133 write(str, len);
134 }
136 void outputStream::fill_to(int col) {
137 int need_fill = col - position();
138 sp(need_fill);
139 }
141 void outputStream::move_to(int col, int slop, int min_space) {
142 if (position() >= col + slop)
143 cr();
144 int need_fill = col - position();
145 if (need_fill < min_space)
146 need_fill = min_space;
147 sp(need_fill);
148 }
150 void outputStream::put(char ch) {
151 assert(ch != 0, "please fix call site");
152 char buf[] = { ch, '\0' };
153 write(buf, 1);
154 }
156 #define SP_USE_TABS false
158 void outputStream::sp(int count) {
159 if (count < 0) return;
160 if (SP_USE_TABS && count >= 8) {
161 int target = position() + count;
162 while (count >= 8) {
163 this->write("\t", 1);
164 count -= 8;
165 }
166 count = target - position();
167 }
168 while (count > 0) {
169 int nw = (count > 8) ? 8 : count;
170 this->write(" ", nw);
171 count -= nw;
172 }
173 }
175 void outputStream::cr() {
176 this->write("\n", 1);
177 }
179 void outputStream::stamp() {
180 if (! _stamp.is_updated()) {
181 _stamp.update(); // start at 0 on first call to stamp()
182 }
184 // outputStream::stamp() may get called by ostream_abort(), use snprintf
185 // to avoid allocating large stack buffer in print().
186 char buf[40];
187 jio_snprintf(buf, sizeof(buf), "%.3f", _stamp.seconds());
188 print_raw(buf);
189 }
191 void outputStream::stamp(bool guard,
192 const char* prefix,
193 const char* suffix) {
194 if (!guard) {
195 return;
196 }
197 print_raw(prefix);
198 stamp();
199 print_raw(suffix);
200 }
202 void outputStream::date_stamp(bool guard,
203 const char* prefix,
204 const char* suffix) {
205 if (!guard) {
206 return;
207 }
208 print_raw(prefix);
209 static const char error_time[] = "yyyy-mm-ddThh:mm:ss.mmm+zzzz";
210 static const int buffer_length = 32;
211 char buffer[buffer_length];
212 const char* iso8601_result = os::iso8601_time(buffer, buffer_length);
213 if (iso8601_result != NULL) {
214 print_raw(buffer);
215 } else {
216 print_raw(error_time);
217 }
218 print_raw(suffix);
219 return;
220 }
222 void outputStream::indent() {
223 while (_position < _indentation) sp();
224 }
226 void outputStream::print_jlong(jlong value) {
227 // N.B. Same as INT64_FORMAT
228 print(os::jlong_format_specifier(), value);
229 }
231 void outputStream::print_julong(julong value) {
232 // N.B. Same as UINT64_FORMAT
233 print(os::julong_format_specifier(), value);
234 }
236 stringStream::stringStream(size_t initial_size) : outputStream() {
237 buffer_length = initial_size;
238 buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
239 buffer_pos = 0;
240 buffer_fixed = false;
241 }
243 // useful for output to fixed chunks of memory, such as performance counters
244 stringStream::stringStream(char* fixed_buffer, size_t fixed_buffer_size) : outputStream() {
245 buffer_length = fixed_buffer_size;
246 buffer = fixed_buffer;
247 buffer_pos = 0;
248 buffer_fixed = true;
249 }
251 void stringStream::write(const char* s, size_t len) {
252 size_t write_len = len; // number of non-null bytes to write
253 size_t end = buffer_pos + len + 1; // position after write and final '\0'
254 if (end > buffer_length) {
255 if (buffer_fixed) {
256 // if buffer cannot resize, silently truncate
257 end = buffer_length;
258 write_len = end - buffer_pos - 1; // leave room for the final '\0'
259 } else {
260 // For small overruns, double the buffer. For larger ones,
261 // increase to the requested size.
262 if (end < buffer_length * 2) {
263 end = buffer_length * 2;
264 }
265 char* oldbuf = buffer;
266 buffer = NEW_RESOURCE_ARRAY(char, end);
267 strncpy(buffer, oldbuf, buffer_pos);
268 buffer_length = end;
269 }
270 }
271 // invariant: buffer is always null-terminated
272 guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
273 buffer[buffer_pos + write_len] = 0;
274 strncpy(buffer + buffer_pos, s, write_len);
275 buffer_pos += write_len;
277 // Note that the following does not depend on write_len.
278 // This means that position and count get updated
279 // even when overflow occurs.
280 update_position(s, len);
281 }
283 char* stringStream::as_string() {
284 char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
285 strncpy(copy, buffer, buffer_pos);
286 copy[buffer_pos] = 0; // terminating null
287 return copy;
288 }
290 stringStream::~stringStream() {}
292 xmlStream* xtty;
293 outputStream* tty;
294 outputStream* gclog_or_tty;
295 extern Mutex* tty_lock;
297 fileStream::fileStream(const char* file_name) {
298 _file = fopen(file_name, "w");
299 _need_close = true;
300 }
302 void fileStream::write(const char* s, size_t len) {
303 if (_file != NULL) fwrite(s, 1, len, _file);
304 update_position(s, len);
305 }
307 fileStream::~fileStream() {
308 if (_file != NULL) {
309 if (_need_close) fclose(_file);
310 _file = NULL;
311 }
312 }
314 void fileStream::flush() {
315 fflush(_file);
316 }
318 fdStream::fdStream(const char* file_name) {
319 _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
320 _need_close = true;
321 }
323 fdStream::~fdStream() {
324 if (_fd != -1) {
325 if (_need_close) close(_fd);
326 _fd = -1;
327 }
328 }
330 void fdStream::write(const char* s, size_t len) {
331 if (_fd != -1) ::write(_fd, s, (int)len);
332 update_position(s, len);
333 }
335 defaultStream* defaultStream::instance = NULL;
336 int defaultStream::_output_fd = 1;
337 int defaultStream::_error_fd = 2;
338 FILE* defaultStream::_output_stream = stdout;
339 FILE* defaultStream::_error_stream = stderr;
341 #define LOG_MAJOR_VERSION 160
342 #define LOG_MINOR_VERSION 1
344 void defaultStream::init() {
345 _inited = true;
346 if (LogVMOutput || LogCompilation) {
347 init_log();
348 }
349 }
351 bool defaultStream::has_log_file() {
352 // lazily create log file (at startup, LogVMOutput is false even
353 // if +LogVMOutput is used, because the flags haven't been parsed yet)
354 // For safer printing during fatal error handling, do not init logfile
355 // if a VM error has been reported.
356 if (!_inited && !is_error_reported()) init();
357 return _log_file != NULL;
358 }
360 static const char* make_log_name(const char* log_name, const char* force_directory, char* buf) {
361 const char* basename = log_name;
362 char file_sep = os::file_separator()[0];
363 const char* cp;
364 for (cp = log_name; *cp != '\0'; cp++) {
365 if (*cp == '/' || *cp == file_sep) {
366 basename = cp+1;
367 }
368 }
369 const char* nametail = log_name;
371 strcpy(buf, "");
372 if (force_directory != NULL) {
373 strcat(buf, force_directory);
374 strcat(buf, os::file_separator());
375 nametail = basename; // completely skip directory prefix
376 }
378 const char* star = strchr(basename, '*');
379 int star_pos = (star == NULL) ? -1 : (star - nametail);
381 if (star_pos >= 0) {
382 // convert foo*bar.log to foo123bar.log
383 int buf_pos = (int) strlen(buf);
384 strncpy(&buf[buf_pos], nametail, star_pos);
385 sprintf(&buf[buf_pos + star_pos], "%u", os::current_process_id());
386 nametail += star_pos + 1; // skip prefix and star
387 }
389 strcat(buf, nametail); // append rest of name, or all of name
390 return buf;
391 }
393 void defaultStream::init_log() {
394 // %%% Need a MutexLocker?
395 const char* log_name = LogFile != NULL ? LogFile : "hotspot.log";
396 char buf[O_BUFLEN*2];
397 const char* try_name = make_log_name(log_name, NULL, buf);
398 fileStream* file = new(ResourceObj::C_HEAP) fileStream(try_name);
399 if (!file->is_open()) {
400 // Try again to open the file.
401 char warnbuf[O_BUFLEN*2];
402 sprintf(warnbuf, "Warning: Cannot open log file: %s\n", try_name);
403 // Note: This feature is for maintainer use only. No need for L10N.
404 jio_print(warnbuf);
405 try_name = make_log_name("hs_pid*.log", os::get_temp_directory(), buf);
406 sprintf(warnbuf, "Warning: Forcing option -XX:LogFile=%s\n", try_name);
407 jio_print(warnbuf);
408 delete file;
409 file = new(ResourceObj::C_HEAP) fileStream(try_name);
410 }
411 if (file->is_open()) {
412 _log_file = file;
413 xmlStream* xs = new(ResourceObj::C_HEAP) xmlStream(file);
414 _outer_xmlStream = xs;
415 if (this == tty) xtty = xs;
416 // Write XML header.
417 xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>");
418 // (For now, don't bother to issue a DTD for this private format.)
419 jlong time_ms = os::javaTimeMillis() - tty->time_stamp().milliseconds();
420 // %%% Should be: jlong time_ms = os::start_time_milliseconds(), if
421 // we ever get round to introduce that method on the os class
422 xs->head("hotspot_log version='%d %d'"
423 " process='%d' time_ms='"INT64_FORMAT"'",
424 LOG_MAJOR_VERSION, LOG_MINOR_VERSION,
425 os::current_process_id(), time_ms);
426 // Write VM version header immediately.
427 xs->head("vm_version");
428 xs->head("name"); xs->text("%s", VM_Version::vm_name()); xs->cr();
429 xs->tail("name");
430 xs->head("release"); xs->text("%s", VM_Version::vm_release()); xs->cr();
431 xs->tail("release");
432 xs->head("info"); xs->text("%s", VM_Version::internal_vm_info_string()); xs->cr();
433 xs->tail("info");
434 xs->tail("vm_version");
435 // Record information about the command-line invocation.
436 xs->head("vm_arguments"); // Cf. Arguments::print_on()
437 if (Arguments::num_jvm_flags() > 0) {
438 xs->head("flags");
439 Arguments::print_jvm_flags_on(xs->text());
440 xs->tail("flags");
441 }
442 if (Arguments::num_jvm_args() > 0) {
443 xs->head("args");
444 Arguments::print_jvm_args_on(xs->text());
445 xs->tail("args");
446 }
447 if (Arguments::java_command() != NULL) {
448 xs->head("command"); xs->text()->print_cr("%s", Arguments::java_command());
449 xs->tail("command");
450 }
451 if (Arguments::sun_java_launcher() != NULL) {
452 xs->head("launcher"); xs->text()->print_cr("%s", Arguments::sun_java_launcher());
453 xs->tail("launcher");
454 }
455 if (Arguments::system_properties() != NULL) {
456 xs->head("properties");
457 // Print it as a java-style property list.
458 // System properties don't generally contain newlines, so don't bother with unparsing.
459 for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) {
460 xs->text()->print_cr("%s=%s", p->key(), p->value());
461 }
462 xs->tail("properties");
463 }
464 xs->tail("vm_arguments");
465 // tty output per se is grouped under the <tty>...</tty> element.
466 xs->head("tty");
467 // All further non-markup text gets copied to the tty:
468 xs->_text = this; // requires friend declaration!
469 } else {
470 delete(file);
471 // and leave xtty as NULL
472 LogVMOutput = false;
473 DisplayVMOutput = true;
474 LogCompilation = false;
475 }
476 }
478 // finish_log() is called during normal VM shutdown. finish_log_on_error() is
479 // called by ostream_abort() after a fatal error.
480 //
481 void defaultStream::finish_log() {
482 xmlStream* xs = _outer_xmlStream;
483 xs->done("tty");
485 // Other log forks are appended here, at the End of Time:
486 CompileLog::finish_log(xs->out()); // write compile logging, if any, now
488 xs->done("hotspot_log");
489 xs->flush();
491 fileStream* file = _log_file;
492 _log_file = NULL;
494 delete _outer_xmlStream;
495 _outer_xmlStream = NULL;
497 file->flush();
498 delete file;
499 }
501 void defaultStream::finish_log_on_error(char *buf, int buflen) {
502 xmlStream* xs = _outer_xmlStream;
504 if (xs && xs->out()) {
506 xs->done_raw("tty");
508 // Other log forks are appended here, at the End of Time:
509 CompileLog::finish_log_on_error(xs->out(), buf, buflen); // write compile logging, if any, now
511 xs->done_raw("hotspot_log");
512 xs->flush();
514 fileStream* file = _log_file;
515 _log_file = NULL;
516 _outer_xmlStream = NULL;
518 if (file) {
519 file->flush();
521 // Can't delete or close the file because delete and fclose aren't
522 // async-safe. We are about to die, so leave it to the kernel.
523 // delete file;
524 }
525 }
526 }
528 intx defaultStream::hold(intx writer_id) {
529 bool has_log = has_log_file(); // check before locking
530 if (// impossible, but who knows?
531 writer_id == NO_WRITER ||
533 // bootstrap problem
534 tty_lock == NULL ||
536 // can't grab a lock or call Thread::current() if TLS isn't initialized
537 ThreadLocalStorage::thread() == NULL ||
539 // developer hook
540 !SerializeVMOutput ||
542 // VM already unhealthy
543 is_error_reported() ||
545 // safepoint == global lock (for VM only)
546 (SafepointSynchronize::is_synchronizing() &&
547 Thread::current()->is_VM_thread())
548 ) {
549 // do not attempt to lock unless we know the thread and the VM is healthy
550 return NO_WRITER;
551 }
552 if (_writer == writer_id) {
553 // already held, no need to re-grab the lock
554 return NO_WRITER;
555 }
556 tty_lock->lock_without_safepoint_check();
557 // got the lock
558 if (writer_id != _last_writer) {
559 if (has_log) {
560 _log_file->bol();
561 // output a hint where this output is coming from:
562 _log_file->print_cr("<writer thread='"INTX_FORMAT"'/>", writer_id);
563 }
564 _last_writer = writer_id;
565 }
566 _writer = writer_id;
567 return writer_id;
568 }
570 void defaultStream::release(intx holder) {
571 if (holder == NO_WRITER) {
572 // nothing to release: either a recursive lock, or we scribbled (too bad)
573 return;
574 }
575 if (_writer != holder) {
576 return; // already unlocked, perhaps via break_tty_lock_for_safepoint
577 }
578 _writer = NO_WRITER;
579 tty_lock->unlock();
580 }
583 // Yuck: jio_print does not accept char*/len.
584 static void call_jio_print(const char* s, size_t len) {
585 char buffer[O_BUFLEN+100];
586 if (len > sizeof(buffer)-1) {
587 warning("increase O_BUFLEN in ostream.cpp -- output truncated");
588 len = sizeof(buffer)-1;
589 }
590 strncpy(buffer, s, len);
591 buffer[len] = '\0';
592 jio_print(buffer);
593 }
596 void defaultStream::write(const char* s, size_t len) {
597 intx thread_id = os::current_thread_id();
598 intx holder = hold(thread_id);
600 if (DisplayVMOutput &&
601 (_outer_xmlStream == NULL || !_outer_xmlStream->inside_attrs())) {
602 // print to output stream. It can be redirected by a vfprintf hook
603 if (s[len] == '\0') {
604 jio_print(s);
605 } else {
606 call_jio_print(s, len);
607 }
608 }
610 // print to log file
611 if (has_log_file()) {
612 int nl0 = _newlines;
613 xmlTextStream::write(s, len);
614 // flush the log file too, if there were any newlines
615 if (nl0 != _newlines){
616 flush();
617 }
618 } else {
619 update_position(s, len);
620 }
622 release(holder);
623 }
625 intx ttyLocker::hold_tty() {
626 if (defaultStream::instance == NULL) return defaultStream::NO_WRITER;
627 intx thread_id = os::current_thread_id();
628 return defaultStream::instance->hold(thread_id);
629 }
631 void ttyLocker::release_tty(intx holder) {
632 if (holder == defaultStream::NO_WRITER) return;
633 defaultStream::instance->release(holder);
634 }
636 void ttyLocker::break_tty_lock_for_safepoint(intx holder) {
637 if (defaultStream::instance != NULL &&
638 defaultStream::instance->writer() == holder) {
639 if (xtty != NULL) {
640 xtty->print_cr("<!-- safepoint while printing -->");
641 }
642 defaultStream::instance->release(holder);
643 }
644 // (else there was no lock to break)
645 }
647 void ostream_init() {
648 if (defaultStream::instance == NULL) {
649 defaultStream::instance = new(ResourceObj::C_HEAP) defaultStream();
650 tty = defaultStream::instance;
652 // We want to ensure that time stamps in GC logs consider time 0
653 // the time when the JVM is initialized, not the first time we ask
654 // for a time stamp. So, here, we explicitly update the time stamp
655 // of tty.
656 tty->time_stamp().update_to(1);
657 }
658 }
660 void ostream_init_log() {
661 // For -Xloggc:<file> option - called in runtime/thread.cpp
662 // Note : this must be called AFTER ostream_init()
664 gclog_or_tty = tty; // default to tty
665 if (Arguments::gc_log_filename() != NULL) {
666 fileStream * gclog = new(ResourceObj::C_HEAP)
667 fileStream(Arguments::gc_log_filename());
668 if (gclog->is_open()) {
669 // now we update the time stamp of the GC log to be synced up
670 // with tty.
671 gclog->time_stamp().update_to(tty->time_stamp().ticks());
672 gclog_or_tty = gclog;
673 }
674 }
676 // If we haven't lazily initialized the logfile yet, do it now,
677 // to avoid the possibility of lazy initialization during a VM
678 // crash, which can affect the stability of the fatal error handler.
679 defaultStream::instance->has_log_file();
680 }
682 // ostream_exit() is called during normal VM exit to finish log files, flush
683 // output and free resource.
684 void ostream_exit() {
685 static bool ostream_exit_called = false;
686 if (ostream_exit_called) return;
687 ostream_exit_called = true;
688 if (gclog_or_tty != tty) {
689 delete gclog_or_tty;
690 }
691 {
692 // we temporaly disable PrintMallocFree here
693 // as otherwise it'll lead to using of almost deleted
694 // tty or defaultStream::instance in logging facility
695 // of HeapFree(), see 6391258
696 DEBUG_ONLY(FlagSetting fs(PrintMallocFree, false);)
697 if (tty != defaultStream::instance) {
698 delete tty;
699 }
700 if (defaultStream::instance != NULL) {
701 delete defaultStream::instance;
702 }
703 }
704 tty = NULL;
705 xtty = NULL;
706 gclog_or_tty = NULL;
707 defaultStream::instance = NULL;
708 }
710 // ostream_abort() is called by os::abort() when VM is about to die.
711 void ostream_abort() {
712 // Here we can't delete gclog_or_tty and tty, just flush their output
713 if (gclog_or_tty) gclog_or_tty->flush();
714 if (tty) tty->flush();
716 if (defaultStream::instance != NULL) {
717 static char buf[4096];
718 defaultStream::instance->finish_log_on_error(buf, sizeof(buf));
719 }
720 }
722 staticBufferStream::staticBufferStream(char* buffer, size_t buflen,
723 outputStream *outer_stream) {
724 _buffer = buffer;
725 _buflen = buflen;
726 _outer_stream = outer_stream;
727 }
729 void staticBufferStream::write(const char* c, size_t len) {
730 _outer_stream->print_raw(c, (int)len);
731 }
733 void staticBufferStream::flush() {
734 _outer_stream->flush();
735 }
737 void staticBufferStream::print(const char* format, ...) {
738 va_list ap;
739 va_start(ap, format);
740 size_t len;
741 const char* str = do_vsnprintf(_buffer, _buflen, format, ap, false, len);
742 write(str, len);
743 va_end(ap);
744 }
746 void staticBufferStream::print_cr(const char* format, ...) {
747 va_list ap;
748 va_start(ap, format);
749 size_t len;
750 const char* str = do_vsnprintf(_buffer, _buflen, format, ap, true, len);
751 write(str, len);
752 va_end(ap);
753 }
755 void staticBufferStream::vprint(const char *format, va_list argptr) {
756 size_t len;
757 const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, false, len);
758 write(str, len);
759 }
761 void staticBufferStream::vprint_cr(const char* format, va_list argptr) {
762 size_t len;
763 const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, true, len);
764 write(str, len);
765 }
767 bufferedStream::bufferedStream(size_t initial_size, size_t bufmax) : outputStream() {
768 buffer_length = initial_size;
769 buffer = NEW_C_HEAP_ARRAY(char, buffer_length);
770 buffer_pos = 0;
771 buffer_fixed = false;
772 buffer_max = bufmax;
773 }
775 bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax) : outputStream() {
776 buffer_length = fixed_buffer_size;
777 buffer = fixed_buffer;
778 buffer_pos = 0;
779 buffer_fixed = true;
780 buffer_max = bufmax;
781 }
783 void bufferedStream::write(const char* s, size_t len) {
785 if(buffer_pos + len > buffer_max) {
786 flush();
787 }
789 size_t end = buffer_pos + len;
790 if (end >= buffer_length) {
791 if (buffer_fixed) {
792 // if buffer cannot resize, silently truncate
793 len = buffer_length - buffer_pos - 1;
794 } else {
795 // For small overruns, double the buffer. For larger ones,
796 // increase to the requested size.
797 if (end < buffer_length * 2) {
798 end = buffer_length * 2;
799 }
800 buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end);
801 buffer_length = end;
802 }
803 }
804 memcpy(buffer + buffer_pos, s, len);
805 buffer_pos += len;
806 update_position(s, len);
807 }
809 char* bufferedStream::as_string() {
810 char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
811 strncpy(copy, buffer, buffer_pos);
812 copy[buffer_pos] = 0; // terminating null
813 return copy;
814 }
816 bufferedStream::~bufferedStream() {
817 if (!buffer_fixed) {
818 FREE_C_HEAP_ARRAY(char, buffer);
819 }
820 }
822 #ifndef PRODUCT
824 #if defined(SOLARIS) || defined(LINUX)
825 #include <sys/types.h>
826 #include <sys/socket.h>
827 #include <netinet/in.h>
828 #include <arpa/inet.h>
829 #endif
831 // Network access
832 networkStream::networkStream() : bufferedStream(1024*10, 1024*10) {
834 _socket = -1;
836 hpi::initialize_socket_library();
838 int result = hpi::socket(AF_INET, SOCK_STREAM, 0);
839 if (result <= 0) {
840 assert(false, "Socket could not be created!");
841 } else {
842 _socket = result;
843 }
844 }
846 int networkStream::read(char *buf, size_t len) {
847 return hpi::recv(_socket, buf, (int)len, 0);
848 }
850 void networkStream::flush() {
851 if (size() != 0) {
852 int result = hpi::raw_send(_socket, (char *)base(), (int)size(), 0);
853 assert(result != -1, "connection error");
854 assert(result == (int)size(), "didn't send enough data");
855 }
856 reset();
857 }
859 networkStream::~networkStream() {
860 close();
861 }
863 void networkStream::close() {
864 if (_socket != -1) {
865 flush();
866 hpi::socket_close(_socket);
867 _socket = -1;
868 }
869 }
871 bool networkStream::connect(const char *ip, short port) {
873 struct sockaddr_in server;
874 server.sin_family = AF_INET;
875 server.sin_port = htons(port);
877 server.sin_addr.s_addr = inet_addr(ip);
878 if (server.sin_addr.s_addr == (uint32_t)-1) {
879 #ifdef _WINDOWS
880 struct hostent* host = hpi::get_host_by_name((char*)ip);
881 #else
882 struct hostent* host = gethostbyname(ip);
883 #endif
884 if (host != NULL) {
885 memcpy(&server.sin_addr, host->h_addr_list[0], host->h_length);
886 } else {
887 return false;
888 }
889 }
892 int result = hpi::connect(_socket, (struct sockaddr*)&server, sizeof(struct sockaddr_in));
893 return (result >= 0);
894 }
896 #endif