hotspot/src/os/windows/vm/os_windows.cpp
changeset 7405 e6fc8d3926f8
parent 7397 5b173b4ca846
child 7410 f5b282e7a7a6
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Tue Nov 23 13:22:55 2010 -0800
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Wed Dec 01 18:26:32 2010 -0500
@@ -47,7 +47,6 @@
 #include "runtime/arguments.hpp"
 #include "runtime/extendedPC.hpp"
 #include "runtime/globals.hpp"
-#include "runtime/hpi.hpp"
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/java.hpp"
 #include "runtime/javaCalls.hpp"
@@ -1044,8 +1043,6 @@
     return 0;
 }
 
-const char* os::dll_file_extension() { return ".dll"; }
-
 const char* os::get_temp_directory() {
   const char *prop = Arguments::get_property("java.io.tmpdir");
   if (prop != 0) return prop;
@@ -1067,7 +1064,6 @@
 
 void os::dll_build_name(char *buffer, size_t buflen,
                         const char* pname, const char* fname) {
-  // Copied from libhpi
   const size_t pnamelen = pname ? strlen(pname) : 0;
   const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
 
@@ -1378,10 +1374,6 @@
   return false;
 }
 
-void* os::dll_lookup(void* handle, const char* name) {
-  return GetProcAddress((HMODULE)handle, name);
-}
-
 // save the start and end address of jvm.dll into param[0] and param[1]
 static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr,
                     unsigned size, void * param) {
@@ -1734,6 +1726,44 @@
 #endif
 }
 
+// This method is a copy of JDK's sysGetLastErrorString
+// from src/windows/hpi/src/system_md.c
+
+size_t os::lasterror(char *buf, size_t len) {
+  long errval;
+
+  if ((errval = GetLastError()) != 0) {
+      /* DOS error */
+    int n = (int)FormatMessage(
+          FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+          NULL,
+          errval,
+          0,
+          buf,
+          (DWORD)len,
+          NULL);
+    if (n > 3) {
+      /* Drop final '.', CR, LF */
+      if (buf[n - 1] == '\n') n--;
+      if (buf[n - 1] == '\r') n--;
+      if (buf[n - 1] == '.') n--;
+      buf[n] = '\0';
+    }
+    return n;
+  }
+
+  if (errno != 0) {
+    /* C runtime error that has no corresponding DOS error code */
+    const char *s = strerror(errno);
+    size_t n = strlen(s);
+    if (n >= len) n = len - 1;
+    strncpy(buf, s, n);
+    buf[n] = '\0';
+    return n;
+  }
+  return 0;
+}
+
 // sun.misc.Signal
 // NOTE that this is a workaround for an apparent kernel bug where if
 // a signal handler for SIGBREAK is installed then that signal handler
@@ -2941,10 +2971,6 @@
   assert(ret != SYS_THREAD_ERROR, "StartThread failed"); // should propagate back
 }
 
-size_t os::read(int fd, void *buf, unsigned int nBytes) {
-  return ::read(fd, buf, nBytes);
-}
-
 class HighResolutionInterval {
   // The default timer resolution seems to be 10 milliseconds.
   // (Where is this written down?)
@@ -3423,10 +3449,6 @@
 #endif
   }
 
-  // Initialize HPI.
-  jint hpi_result = hpi::initialize();
-  if (hpi_result != JNI_OK) { return hpi_result; }
-
   // If stack_commit_size is 0, windows will reserve the default size,
   // but only commit a small portion of it.
   size_t stack_commit_size = round_to(ThreadStackSize*K, os::vm_page_size());
@@ -3531,7 +3553,7 @@
     errno = ENAMETOOLONG;
     return -1;
   }
-  hpi::native_path(strcpy(pathbuf, path));
+  os::native_path(strcpy(pathbuf, path));
   int ret = ::stat(pathbuf, sbuf);
   if (sbuf != NULL && UseUTCFileTimestamp) {
     // Fix for 6539723.  st_mtime returned from stat() is dependent on
@@ -3675,6 +3697,20 @@
   return DontYieldALot;
 }
 
+// This method is a slightly reworked copy of JDK's sysOpen
+// from src/windows/hpi/src/sys_api_md.c
+
+int os::open(const char *path, int oflag, int mode) {
+  char pathbuf[MAX_PATH];
+
+  if (strlen(path) > MAX_PATH - 1) {
+    errno = ENAMETOOLONG;
+          return -1;
+  }
+  os::native_path(strcpy(pathbuf, path));
+  return ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode);
+}
+
 // Is a (classpath) directory empty?
 bool os::dir_is_empty(const char* path) {
   WIN32_FIND_DATA fd;
@@ -3706,6 +3742,297 @@
 }
 
 
+jlong os::lseek(int fd, jlong offset, int whence) {
+  return (jlong) ::_lseeki64(fd, offset, whence);
+}
+
+// This method is a slightly reworked copy of JDK's sysNativePath
+// from src/windows/hpi/src/path_md.c
+
+/* Convert a pathname to native format.  On win32, this involves forcing all
+   separators to be '\\' rather than '/' (both are legal inputs, but Win95
+   sometimes rejects '/') and removing redundant separators.  The input path is
+   assumed to have been converted into the character encoding used by the local
+   system.  Because this might be a double-byte encoding, care is taken to
+   treat double-byte lead characters correctly.
+
+   This procedure modifies the given path in place, as the result is never
+   longer than the original.  There is no error return; this operation always
+   succeeds. */
+char * os::native_path(char *path) {
+  char *src = path, *dst = path, *end = path;
+  char *colon = NULL;           /* If a drive specifier is found, this will
+                                        point to the colon following the drive
+                                        letter */
+
+  /* Assumption: '/', '\\', ':', and drive letters are never lead bytes */
+  assert(((!::IsDBCSLeadByte('/'))
+    && (!::IsDBCSLeadByte('\\'))
+    && (!::IsDBCSLeadByte(':'))),
+    "Illegal lead byte");
+
+  /* Check for leading separators */
+#define isfilesep(c) ((c) == '/' || (c) == '\\')
+  while (isfilesep(*src)) {
+    src++;
+  }
+
+  if (::isalpha(*src) && !::IsDBCSLeadByte(*src) && src[1] == ':') {
+    /* Remove leading separators if followed by drive specifier.  This
+      hack is necessary to support file URLs containing drive
+      specifiers (e.g., "file://c:/path").  As a side effect,
+      "/c:/path" can be used as an alternative to "c:/path". */
+    *dst++ = *src++;
+    colon = dst;
+    *dst++ = ':';
+    src++;
+  } else {
+    src = path;
+    if (isfilesep(src[0]) && isfilesep(src[1])) {
+      /* UNC pathname: Retain first separator; leave src pointed at
+         second separator so that further separators will be collapsed
+         into the second separator.  The result will be a pathname
+         beginning with "\\\\" followed (most likely) by a host name. */
+      src = dst = path + 1;
+      path[0] = '\\';     /* Force first separator to '\\' */
+    }
+  }
+
+  end = dst;
+
+  /* Remove redundant separators from remainder of path, forcing all
+      separators to be '\\' rather than '/'. Also, single byte space
+      characters are removed from the end of the path because those
+      are not legal ending characters on this operating system.
+  */
+  while (*src != '\0') {
+    if (isfilesep(*src)) {
+      *dst++ = '\\'; src++;
+      while (isfilesep(*src)) src++;
+      if (*src == '\0') {
+        /* Check for trailing separator */
+        end = dst;
+        if (colon == dst - 2) break;                      /* "z:\\" */
+        if (dst == path + 1) break;                       /* "\\" */
+        if (dst == path + 2 && isfilesep(path[0])) {
+          /* "\\\\" is not collapsed to "\\" because "\\\\" marks the
+            beginning of a UNC pathname.  Even though it is not, by
+            itself, a valid UNC pathname, we leave it as is in order
+            to be consistent with the path canonicalizer as well
+            as the win32 APIs, which treat this case as an invalid
+            UNC pathname rather than as an alias for the root
+            directory of the current drive. */
+          break;
+        }
+        end = --dst;  /* Path does not denote a root directory, so
+                                    remove trailing separator */
+        break;
+      }
+      end = dst;
+    } else {
+      if (::IsDBCSLeadByte(*src)) { /* Copy a double-byte character */
+        *dst++ = *src++;
+        if (*src) *dst++ = *src++;
+        end = dst;
+      } else {         /* Copy a single-byte character */
+        char c = *src++;
+        *dst++ = c;
+        /* Space is not a legal ending character */
+        if (c != ' ') end = dst;
+      }
+    }
+  }
+
+  *end = '\0';
+
+  /* For "z:", add "." to work around a bug in the C runtime library */
+  if (colon == dst - 1) {
+          path[2] = '.';
+          path[3] = '\0';
+  }
+
+  #ifdef DEBUG
+    jio_fprintf(stderr, "sysNativePath: %s\n", path);
+  #endif DEBUG
+  return path;
+}
+
+// This code is a copy of JDK's sysSetLength
+// from src/windows/hpi/src/sys_api_md.c
+
+int os::ftruncate(int fd, jlong length) {
+  HANDLE h = (HANDLE)::_get_osfhandle(fd);
+  long high = (long)(length >> 32);
+  DWORD ret;
+
+  if (h == (HANDLE)(-1)) {
+    return -1;
+  }
+
+  ret = ::SetFilePointer(h, (long)(length), &high, FILE_BEGIN);
+  if ((ret == 0xFFFFFFFF) && (::GetLastError() != NO_ERROR)) {
+      return -1;
+  }
+
+  if (::SetEndOfFile(h) == FALSE) {
+    return -1;
+  }
+
+  return 0;
+}
+
+
+// This code is a copy of JDK's sysSync
+// from src/windows/hpi/src/sys_api_md.c
+// except for the legacy workaround for a bug in Win 98
+
+int os::fsync(int fd) {
+  HANDLE handle = (HANDLE)::_get_osfhandle(fd);
+
+  if ( (!::FlushFileBuffers(handle)) &&
+         (GetLastError() != ERROR_ACCESS_DENIED) ) {
+    /* from winerror.h */
+    return -1;
+  }
+  return 0;
+}
+
+static int nonSeekAvailable(int, long *);
+static int stdinAvailable(int, long *);
+
+#define S_ISCHR(mode)   (((mode) & _S_IFCHR) == _S_IFCHR)
+#define S_ISFIFO(mode)  (((mode) & _S_IFIFO) == _S_IFIFO)
+
+// This code is a copy of JDK's sysAvailable
+// from src/windows/hpi/src/sys_api_md.c
+
+int os::available(int fd, jlong *bytes) {
+  jlong cur, end;
+  struct _stati64 stbuf64;
+
+  if (::_fstati64(fd, &stbuf64) >= 0) {
+    int mode = stbuf64.st_mode;
+    if (S_ISCHR(mode) || S_ISFIFO(mode)) {
+      int ret;
+      long lpbytes;
+      if (fd == 0) {
+        ret = stdinAvailable(fd, &lpbytes);
+      } else {
+        ret = nonSeekAvailable(fd, &lpbytes);
+      }
+      (*bytes) = (jlong)(lpbytes);
+      return ret;
+    }
+    if ((cur = ::_lseeki64(fd, 0L, SEEK_CUR)) == -1) {
+      return FALSE;
+    } else if ((end = ::_lseeki64(fd, 0L, SEEK_END)) == -1) {
+      return FALSE;
+    } else if (::_lseeki64(fd, cur, SEEK_SET) == -1) {
+      return FALSE;
+    }
+    *bytes = end - cur;
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+// This code is a copy of JDK's nonSeekAvailable
+// from src/windows/hpi/src/sys_api_md.c
+
+static int nonSeekAvailable(int fd, long *pbytes) {
+  /* This is used for available on non-seekable devices
+    * (like both named and anonymous pipes, such as pipes
+    *  connected to an exec'd process).
+    * Standard Input is a special case.
+    *
+    */
+  HANDLE han;
+
+  if ((han = (HANDLE) ::_get_osfhandle(fd)) == (HANDLE)(-1)) {
+    return FALSE;
+  }
+
+  if (! ::PeekNamedPipe(han, NULL, 0, NULL, (LPDWORD)pbytes, NULL)) {
+        /* PeekNamedPipe fails when at EOF.  In that case we
+         * simply make *pbytes = 0 which is consistent with the
+         * behavior we get on Solaris when an fd is at EOF.
+         * The only alternative is to raise an Exception,
+         * which isn't really warranted.
+         */
+    if (::GetLastError() != ERROR_BROKEN_PIPE) {
+      return FALSE;
+    }
+    *pbytes = 0;
+  }
+  return TRUE;
+}
+
+#define MAX_INPUT_EVENTS 2000
+
+// This code is a copy of JDK's stdinAvailable
+// from src/windows/hpi/src/sys_api_md.c
+
+static int stdinAvailable(int fd, long *pbytes) {
+  HANDLE han;
+  DWORD numEventsRead = 0;      /* Number of events read from buffer */
+  DWORD numEvents = 0;  /* Number of events in buffer */
+  DWORD i = 0;          /* Loop index */
+  DWORD curLength = 0;  /* Position marker */
+  DWORD actualLength = 0;       /* Number of bytes readable */
+  BOOL error = FALSE;         /* Error holder */
+  INPUT_RECORD *lpBuffer;     /* Pointer to records of input events */
+
+  if ((han = ::GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+        return FALSE;
+  }
+
+  /* Construct an array of input records in the console buffer */
+  error = ::GetNumberOfConsoleInputEvents(han, &numEvents);
+  if (error == 0) {
+    return nonSeekAvailable(fd, pbytes);
+  }
+
+  /* lpBuffer must fit into 64K or else PeekConsoleInput fails */
+  if (numEvents > MAX_INPUT_EVENTS) {
+    numEvents = MAX_INPUT_EVENTS;
+  }
+
+  lpBuffer = (INPUT_RECORD *)os::malloc(numEvents * sizeof(INPUT_RECORD));
+  if (lpBuffer == NULL) {
+    return FALSE;
+  }
+
+  error = ::PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);
+  if (error == 0) {
+    os::free(lpBuffer);
+    return FALSE;
+  }
+
+  /* Examine input records for the number of bytes available */
+  for(i=0; i<numEvents; i++) {
+    if (lpBuffer[i].EventType == KEY_EVENT) {
+
+      KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)
+                                      &(lpBuffer[i].Event);
+      if (keyRecord->bKeyDown == TRUE) {
+        CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);
+        curLength++;
+        if (*keyPressed == '\r') {
+          actualLength = curLength;
+        }
+      }
+    }
+  }
+
+  if(lpBuffer != NULL) {
+    os::free(lpBuffer);
+  }
+
+  *pbytes = (long) actualLength;
+  return TRUE;
+}
+
 // Map a block of memory.
 char* os::map_memory(int fd, const char* file_name, size_t file_offset,
                      char *addr, size_t bytes, bool read_only,
@@ -3871,7 +4198,7 @@
   int fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
   if (fd != -1) {
     struct stat buf;
-    close(fd);
+    ::close(fd);
     while (::stat(filename, &buf) == 0) {
       Sleep(100);
     }
@@ -4232,3 +4559,164 @@
 // We don't build a headless jre for Windows
 bool os::is_headless_jre() { return false; }
 
+// OS_SocketInterface
+// Not used on Windows
+
+// OS_SocketInterface
+typedef struct hostent * (PASCAL FAR *ws2_ifn_ptr_t)(...);
+ws2_ifn_ptr_t *get_host_by_name_fn = NULL;
+
+typedef CRITICAL_SECTION mutex_t;
+#define mutexInit(m)    InitializeCriticalSection(m)
+#define mutexDestroy(m) DeleteCriticalSection(m)
+#define mutexLock(m)    EnterCriticalSection(m)
+#define mutexUnlock(m)  LeaveCriticalSection(m)
+
+static bool sockfnptrs_initialized = FALSE;
+static mutex_t sockFnTableMutex;
+
+/* is Winsock2 loaded? better to be explicit than to rely on sockfnptrs */
+static bool winsock2Available = FALSE;
+
+
+static void initSockFnTable() {
+  int (PASCAL FAR* WSAStartupPtr)(WORD, LPWSADATA);
+  WSADATA wsadata;
+
+  ::mutexInit(&sockFnTableMutex);
+  ::mutexLock(&sockFnTableMutex);
+
+  if (sockfnptrs_initialized == FALSE) {
+        HMODULE hWinsock;
+
+          /* try to load Winsock2, and if that fails, load Winsock */
+    hWinsock = ::LoadLibrary("ws2_32.dll");
+
+    if (hWinsock == NULL) {
+      jio_fprintf(stderr, "Could not load Winsock 2 (error: %d)\n",
+      ::GetLastError());
+      return;
+    }
+
+    /* If we loaded a DLL, then we might as well initialize it.  */
+    WSAStartupPtr = (int (PASCAL FAR *)(WORD, LPWSADATA))
+    ::GetProcAddress(hWinsock, "WSAStartup");
+
+    if (WSAStartupPtr(MAKEWORD(1,1), &wsadata) != 0) {
+        jio_fprintf(stderr, "Could not initialize Winsock\n");
+    }
+
+    get_host_by_name_fn
+        = (ws2_ifn_ptr_t*) GetProcAddress(hWinsock, "gethostbyname");
+  }
+
+  assert(get_host_by_name_fn != NULL,
+    "gethostbyname function not found");
+  sockfnptrs_initialized = TRUE;
+  ::mutexUnlock(&sockFnTableMutex);
+}
+
+struct hostent*  os::get_host_by_name(char* name) {
+  if (!sockfnptrs_initialized) {
+    initSockFnTable();
+  }
+
+  assert(sockfnptrs_initialized == TRUE && get_host_by_name_fn != NULL,
+    "sockfnptrs is not initialized or pointer to gethostbyname function is NULL");
+  return (*get_host_by_name_fn)(name);
+}
+
+
+int os::socket_close(int fd) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::socket_available(int fd, jint *pbytes) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::socket(int domain, int type, int protocol) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::listen(int fd, int count) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::connect(int fd, struct sockaddr *him, int len) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::accept(int fd, struct sockaddr *him, int *len) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::sendto(int fd, char *buf, int len, int flags,
+                        struct sockaddr *to, int tolen) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::recvfrom(int fd, char *buf, int nBytes, int flags,
+                         sockaddr *from, int *fromlen) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::recv(int fd, char *buf, int nBytes, int flags) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::send(int fd, char *buf, int nBytes, int flags) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::raw_send(int fd, char *buf, int nBytes, int flags) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::timeout(int fd, long timeout) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::get_host_name(char* name, int namelen) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::socket_shutdown(int fd, int howto) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::bind(int fd, struct sockaddr *him, int len) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::get_sock_name(int fd, struct sockaddr *him, int *len) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::get_sock_opt(int fd, int level, int optname,
+                             char *optval, int* optlen) {
+  ShouldNotReachHere();
+  return 0;
+}
+
+int os::set_sock_opt(int fd, int level, int optname,
+                             const char *optval, int optlen) {
+  ShouldNotReachHere();
+  return 0;
+}