--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/os/win32/IOBuf.cpp Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include <stdio.h>
+
+// This file is currently used for os/solaris/agent too. At some point in time
+// the source will be reorganized to avoid these ifdefs.
+
+#ifdef __sun
+ #include <string.h>
+ #include <inttypes.h>
+ #include <sys/byteorder.h>
+#endif
+
+#include "IOBuf.hpp"
+
+// Formats for printing pointers
+#ifdef _LP64
+# define INTPTR_FORMAT "0x%016lx"
+#else /* ! _LP64 */
+# define INTPTR_FORMAT "0x%08lx"
+#endif /* _LP64 */
+
+// Uncomment the #define below to get messages on stderr
+// #define DEBUGGING
+
+IOBuf::IOBuf(int inLen, int outLen) {
+ inBuf = new Buffer(inLen);
+ outBuf = new Buffer(outLen);
+ fd = INVALID_SOCKET;
+ outHandle = NULL;
+ usingSocket = true;
+ reset();
+}
+
+IOBuf::~IOBuf() {
+ delete inBuf;
+ delete outBuf;
+}
+
+void
+IOBuf::setSocket(SOCKET sock) {
+ fd = sock;
+ usingSocket = true;
+}
+
+// Reading/writing files is only needed and used on windows.
+#ifdef WIN32
+void
+IOBuf::setOutputFileHandle(HANDLE handle) {
+ outHandle = handle;
+ usingSocket = false;
+}
+#endif
+
+void
+IOBuf::reset() {
+ gotDataLastTime = false;
+ state = TEXT_STATE;
+ binPos = 0;
+ binLength = 0;
+}
+
+IOBuf::ReadLineResult
+IOBuf::tryReadLine() {
+ return doReadLine(false);
+}
+
+char*
+IOBuf::readLine() {
+ ReadLineResult rr = doReadLine(true);
+ if (rr != RL_GOT_DATA) {
+ return NULL;
+ }
+ return getLine();
+}
+
+IOBuf::ReadLineResult
+IOBuf::doReadLine(bool shouldWait) {
+
+ if (!usingSocket) {
+ return IOBuf::RL_ERROR;
+ }
+
+ if (gotDataLastTime) {
+ curLine.clear();
+ }
+
+ int c;
+ do {
+ c = readChar(shouldWait);
+ if (c >= 0) {
+ Action act = processChar((char) c);
+ if (act == GOT_LINE) {
+ curLine.push_back('\0');
+ gotDataLastTime = true;
+ return IOBuf::RL_GOT_DATA;
+ } else if (act == SKIP_EOL_CHAR) {
+ // Do nothing
+ } else {
+ curLine.push_back((char) c);
+ }
+ }
+ } while (shouldWait || c >= 0);
+
+ gotDataLastTime = false;
+ return IOBuf::RL_NO_DATA;
+}
+
+bool
+IOBuf::flushImpl(bool moreDataToCome) {
+ int numWritten = 0;
+
+#ifdef WIN32
+ // When running on Windows and using IOBufs for inter-process
+ // communication, we need to write metadata into the stream
+ // indicating how many bytes are coming down. Five bytes are written
+ // per flush() call, four containing the integer number of bytes
+ // coming (not including the five-byte header) and one (a 0 or 1)
+ // indicating whether there is more data coming.
+ if (!usingSocket) {
+ int numToWrite = outBuf->drainRemaining();
+ char moreToCome = (moreDataToCome ? 1 : 0);
+ DWORD numBytesWritten;
+ if (!WriteFile(outHandle, &numToWrite, sizeof(int), &numBytesWritten, NULL)) {
+ return false;
+ }
+ if (numBytesWritten != sizeof(int)) {
+ return false;
+ }
+ if (!WriteFile(outHandle, &moreToCome, 1, &numBytesWritten, NULL)) {
+ return false;
+ }
+ if (numBytesWritten != 1) {
+ return false;
+ }
+ }
+#endif
+
+ while (outBuf->drainRemaining() != 0) {
+#ifdef DEBUGGING
+ fprintf(stderr, "Flushing %d bytes\n", outBuf->drainRemaining());
+#endif
+ if (usingSocket) {
+ numWritten = send(fd, outBuf->drainPos(), outBuf->drainRemaining(), 0);
+ } else {
+#ifdef WIN32
+ DWORD numBytesWritten;
+ if (!WriteFile(outHandle, outBuf->drainPos(), outBuf->drainRemaining(), &numBytesWritten, NULL)) {
+ numWritten = -1;
+ } else {
+ numWritten = numBytesWritten;
+ }
+#endif
+ }
+ if (numWritten != -1) {
+#ifdef DEBUGGING
+ fprintf(stderr, "Flushed %d bytes\n", numWritten);
+#endif
+ outBuf->incrDrainPos(numWritten);
+ } else {
+ return false;
+ }
+ }
+
+ outBuf->compact();
+
+ return true;
+}
+
+int
+IOBuf::readChar(bool block) {
+ do {
+ int c = inBuf->readByte();
+ if (c >= 0) {
+ return c;
+ }
+ // See whether we need to compact the input buffer
+ if (inBuf->remaining() < inBuf->size() / 2) {
+ inBuf->compact();
+ }
+ // See whether socket is ready
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (block || select(1 + fd, &fds, NULL, NULL, &timeout) > 0) {
+ if (block || FD_ISSET(fd, &fds)) {
+#ifdef DEBUGGING
+ int b = (block ? 1 : 0);
+ fprintf(stderr, "calling recv: block = %d\n", b);
+#endif
+ // Read data from socket
+ int numRead = recv(fd, inBuf->fillPos(), inBuf->remaining(), 0);
+ if (numRead < 0) {
+#ifdef DEBUGGING
+ fprintf(stderr, "recv failed\n");
+#endif
+ return -1;
+ }
+ inBuf->incrFillPos(numRead);
+ }
+ }
+ } while (block);
+
+ return inBuf->readByte();
+}
+
+char*
+IOBuf::getLine() {
+#ifdef DEBUGGING
+ fprintf(stderr, "Returning (first 10 chars) \"%.10s\"\n", curLine.begin());
+#endif
+ return curLine.begin();
+}
+
+bool
+IOBuf::flush() {
+ return flushImpl(false);
+}
+
+bool
+IOBuf::writeString(const char* str) {
+ int len = strlen(str);
+
+ if (len > outBuf->size()) {
+ return false;
+ }
+
+ if (len > outBuf->remaining()) {
+ if (!flushImpl(true)) {
+ return false;
+ }
+ }
+
+ // NOTE we do not copy the null terminator of the string.
+
+ strncpy(outBuf->fillPos(), str, len);
+ outBuf->incrFillPos(len);
+ return true;
+}
+
+bool
+IOBuf::writeInt(int val) {
+ char buf[128];
+ sprintf(buf, "%d", val);
+ return writeString(buf);
+}
+
+bool
+IOBuf::writeUnsignedInt(unsigned int val) {
+ char buf[128];
+ sprintf(buf, "%u", val);
+ return writeString(buf);
+}
+
+bool
+IOBuf::writeBoolAsInt(bool val) {
+ if (val) {
+ return writeString("1");
+ } else {
+ return writeString("0");
+ }
+}
+
+bool
+IOBuf::writeAddress(void* val) {
+ char buf[128];
+ sprintf(buf, INTPTR_FORMAT, val);
+ return writeString(buf);
+}
+
+bool
+IOBuf::writeSpace() {
+ return writeString(" ");
+}
+
+bool
+IOBuf::writeEOL() {
+ return writeString("\n\r");
+}
+
+bool
+IOBuf::writeBinChar(char c) {
+ return writeBinBuf((char*) &c, sizeof(c));
+}
+
+bool
+IOBuf::writeBinUnsignedShort(unsigned short i) {
+ i = htons(i);
+ return writeBinBuf((char*) &i, sizeof(i));
+}
+
+bool
+IOBuf::writeBinUnsignedInt(unsigned int i) {
+ i = htonl(i);
+ return writeBinBuf((char*) &i, sizeof(i));
+}
+
+bool
+IOBuf::writeBinBuf(char* buf, int size) {
+ while (size > 0) {
+ int spaceRemaining = outBuf->remaining();
+ if (spaceRemaining == 0) {
+ if (!flushImpl(true)) {
+ return false;
+ }
+ spaceRemaining = outBuf->remaining();
+ }
+ int toCopy = (size > spaceRemaining) ? spaceRemaining : size;
+ memcpy(outBuf->fillPos(), buf, toCopy);
+ outBuf->incrFillPos(toCopy);
+ buf += toCopy;
+ size -= toCopy;
+ if (size > 0) {
+ if (!flushImpl(true)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+#ifdef WIN32
+IOBuf::FillState
+IOBuf::fillFromFileHandle(HANDLE fh, DWORD* numBytesRead) {
+ int totalToRead;
+ char moreToCome;
+
+ outBuf->compact();
+
+ DWORD numRead;
+ if (!ReadFile(fh, &totalToRead, sizeof(int), &numRead, NULL)) {
+ return FAILED;
+ }
+ if (numRead != sizeof(int)) {
+ return FAILED;
+ }
+ if (!ReadFile(fh, &moreToCome, 1, &numRead, NULL)) {
+ return FAILED;
+ }
+ if (numRead != 1) {
+ return FAILED;
+ }
+ if (outBuf->remaining() < totalToRead) {
+ return FAILED;
+ }
+
+ int tmp = totalToRead;
+
+ while (totalToRead > 0) {
+ if (!ReadFile(fh, outBuf->fillPos(), totalToRead, &numRead, NULL)) {
+ return FAILED;
+ }
+ outBuf->incrFillPos((int) numRead);
+ totalToRead -= numRead;
+ }
+
+ *numBytesRead = tmp;
+ return ((moreToCome == 0) ? DONE : MORE_DATA_PENDING);
+}
+#endif
+
+bool
+IOBuf::isBinEscapeChar(char c) {
+ return (c == '|');
+}
+
+IOBuf::Action
+IOBuf::processChar(char c) {
+ Action action = NO_ACTION;
+ switch (state) {
+ case TEXT_STATE: {
+ // Looking for text char, bin escape char, or EOL
+ if (isBinEscapeChar(c)) {
+#ifdef DEBUGGING
+ fprintf(stderr, "[a: '%c'] ", inBuf[0]);
+#endif
+ binPos = 0;
+#ifdef DEBUGGING
+ fprintf(stderr, "[b: '%c'] ", inBuf[0]);
+#endif
+ binLength = 0;
+#ifdef DEBUGGING
+ fprintf(stderr, "[c: '%c'] ", inBuf[0]);
+#endif
+ state = BIN_STATE;
+#ifdef DEBUGGING
+ fprintf(stderr, "[d: '%c'] ", inBuf[0]);
+#endif
+#ifdef DEBUGGING
+ fprintf(stderr, "\nSwitching to BIN_STATE\n");
+#endif
+ } else if (isEOL(c)) {
+ state = EOL_STATE;
+ action = GOT_LINE;
+#ifdef DEBUGGING
+ fprintf(stderr, "\nSwitching to EOL_STATE (GOT_LINE)\n");
+#endif
+ }
+#ifdef DEBUGGING
+ else {
+ fprintf(stderr, "'%c' ", c);
+ fflush(stderr);
+ }
+#endif
+ break;
+ }
+
+ case BIN_STATE: {
+ // Seeking to finish read of input
+ if (binPos < 4) {
+ int cur = c & 0xFF;
+ binLength <<= 8;
+ binLength |= cur;
+ ++binPos;
+ } else {
+#ifdef DEBUGGING
+ fprintf(stderr, "Reading binary byte %d of %d\n",
+ binPos - 4, binLength);
+#endif
+ ++binPos;
+ if (binPos == 4 + binLength) {
+ state = TEXT_STATE;
+#ifdef DEBUGGING
+ fprintf(stderr, "Switching to TEXT_STATE\n");
+#endif
+ }
+ }
+ break;
+ }
+
+ case EOL_STATE: {
+ // More EOL characters just cause us to re-enter this state
+ if (isEOL(c)) {
+ action = SKIP_EOL_CHAR;
+ } else if (isBinEscapeChar(c)) {
+ binPos = 0;
+ binLength = 0;
+ state = BIN_STATE;
+ } else {
+ state = TEXT_STATE;
+#ifdef DEBUGGING
+ fprintf(stderr, "'%c' ", c);
+ fflush(stderr);
+#endif
+ }
+ break;
+ }
+
+ } // switch
+
+ return action;
+}
+
+
+bool
+IOBuf::isEOL(char c) {
+#ifdef WIN32
+ return ((c == '\n') || (c == '\r'));
+#elif defined(__sun)
+ return c == '\n';
+#else
+ #error Please port isEOL() to your platform
+ return false;
+#endif
+}