1 /* 2 * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved. 3 * 4 * This file is part of the Lock Contention Tracing Subsystem for the HotSpot 5 * Virtual Machine, which is developed at Christian Doppler Laboratory on 6 * Monitoring and Evolution of Very-Large-Scale Software Systems. Please 7 * contact us at <http://mevss.jku.at/> if you need additional information 8 * or have any questions. 9 * 10 * This code is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 only, as 12 * published by the Free Software Foundation. 13 * 14 * This code is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 * version 2 for more details (a copy is included in the LICENSE file that 18 * accompanied this code). 19 * 20 * You should have received a copy of the GNU General Public License version 21 * 2 along with this work. If not, see <http://www.gnu.org/licenses/>. 22 * 23 */ 24 25 #ifndef SHARE_VM_EVTRACE_TRACEWRITER_INLINE_HPP 26 #define SHARE_VM_EVTRACE_TRACEWRITER_INLINE_HPP 27 28 #include "evtrace/traceBuffer.hpp" 29 #include "evtrace/traceManager.hpp" 30 31 // 32 // TraceWriterBase 33 // 34 35 inline TraceWriterBase::TraceWriterBase(size_t nbytes) 36 : _writer_top(NULL), 37 _nsv(true, false) 38 { 39 assert(!SafepointSynchronize::is_at_safepoint() || Thread::current()->is_VM_thread(), 40 "only the VM thread may write events during a safepoint"); 41 assert(!Thread::current()->trace_active(), "tracing already in use"); 42 debug_only(Thread::current()->toggle_trace_active();) 43 reserve(nbytes); 44 } 45 46 inline TraceWriterBase::~TraceWriterBase() { 47 assert(_writer_top == NULL || Thread::current()->trace_buffer() == NULL 48 || _writer_top == Thread::current()->trace_buffer()->top, 49 "must have used up reserved space"); 50 assert(Thread::current()->trace_active(), "tracing must be active"); 51 debug_only(Thread::current()->toggle_trace_active();) 52 } 53 54 inline void TraceWriterBase::assert_reserved(size_t nbytes) { 55 assert(_writer_top != NULL, "no space reserved"); 56 assert(Thread::current()->trace_buffer() != NULL, "thread has no trace buffer"); 57 assert(_writer_top + nbytes <= Thread::current()->trace_buffer()->top, "not enough space reserved"); 58 } 59 60 inline void TraceWriterBase::reserve(size_t nbytes) { 61 if (!TraceManager::is_initialized()) { 62 assert(_writer_top == NULL, "have pointer into buffer, but tracing is not initialized"); 63 return; 64 } 65 66 assert(_writer_top == NULL || Thread::current()->trace_buffer() == NULL 67 || _writer_top == Thread::current()->trace_buffer()->top, 68 "must finish writing before reserving more space"); 69 70 // NOTE: our No_Safepoint_Verifier ensures that no safepoint can happen 71 // between submitting/requesting a buffer and setting it as the thread's 72 // trace buffer 73 74 TraceBuffer *buf = Thread::current()->trace_buffer(); 75 if (buf != NULL) { 76 _writer_top = buf->top; 77 if (!buf->reserve(nbytes)) { 78 // does not fit 79 _writer_top = NULL; 80 TraceManager::submit_buffer(Thread::current()->trace_buffer()); 81 Thread::current()->set_trace_buffer(NULL); 82 buf = NULL; 83 } 84 } 85 if (buf == NULL && TraceManager::is_initialized()) { 86 buf = TraceManager::request_buffer(); 87 buf->owner = Thread::current(); 88 _writer_top = buf->top; 89 guarantee(buf->reserve(nbytes), "newly requested buffer does not fit the event"); 90 Thread::current()->set_trace_buffer(buf); 91 } 92 } 93 94 inline void TraceWriterBase::put_u1(u1 v) { 95 assert_reserved(1); 96 *_writer_top++ = v; 97 } 98 99 inline void TraceWriterBase::put_u2(u2 v) { 100 assert_reserved(2); 101 *(u2 *) _writer_top = v; 102 _writer_top += 2; 103 } 104 105 inline void TraceWriterBase::put_u4(u4 v) { 106 assert_reserved(4); 107 *(u4 *) _writer_top = v; 108 _writer_top += 4; 109 } 110 111 inline void TraceWriterBase::put_u8(u8 v) { 112 assert_reserved(8); 113 *(u8 *) _writer_top = v; 114 _writer_top += 8; 115 } 116 117 inline void TraceWriterBase::put_s4(s4 v) { 118 assert_reserved(4); 119 *(s4 *) _writer_top = v; 120 _writer_top += 4; 121 } 122 123 inline void TraceWriterBase::put_s8(s8 v) { 124 assert_reserved(8); 125 *(s8 *) _writer_top = v; 126 _writer_top += 8; 127 } 128 129 inline void TraceWriterBase::put_data(void *data, size_t length) { 130 assert_reserved(length); 131 memcpy(_writer_top, data, length); 132 _writer_top += length; 133 } 134 135 inline void TraceWriterBase::put_utf8str(const char *s, size_t bytes) { 136 assert_reserved(bytes); 137 138 assert(bytes > 2, "invalid length"); 139 bytes -= 2; 140 assert(bytes == (size_t) ((s2) bytes), "string length must fit in u2"); 141 *(s2 *) _writer_top = (s2) bytes; 142 _writer_top += 2; 143 if (s != NULL) { 144 memcpy(_writer_top, s, bytes); 145 _writer_top += bytes; 146 } 147 } 148 149 inline size_t TraceWriterBase::nbytes_for_utf8str(const char* s, size_t maxbytes) { 150 assert(s != NULL, "null string"); 151 152 size_t nbytes = 0; 153 if (s != NULL) { 154 jchar c; 155 const char *end = s + maxbytes; 156 for (;;) { 157 const char *q = s; 158 s = UTF8::next(s, &c); 159 if (c == 0 || s >= end) { 160 break; 161 } 162 nbytes += (size_t) (s - q); 163 } 164 assert(nbytes == (u2) nbytes, "string length must fit in u2"); 165 } 166 nbytes += 2; // for u2 with length 167 return nbytes; 168 } 169 170 #endif /* SHARE_VM_EVTRACE_TRACEWRITER_INLINE_HPP */