changeset 8656:289a2d2a8f97

8087322: Implement a Semaphore utility class Reviewed-by: kbarrett, dholmes
author stefank
date Mon, 19 Jan 2015 11:06:08 +0100
parents 1fa641488898
children 94d13c20fbf0 d76f3398c6eb
files make/solaris/makefiles/vm.make src/os/bsd/vm/os_bsd.cpp src/os/bsd/vm/semaphore_bsd.hpp src/os/linux/vm/os_linux.cpp src/os/posix/vm/os_posix.cpp src/os/posix/vm/semaphore_posix.hpp src/os/solaris/vm/os_solaris.cpp src/os/windows/vm/os_windows.cpp src/os/windows/vm/semaphore_windows.hpp src/share/vm/prims/jni.cpp src/share/vm/runtime/semaphore.cpp src/share/vm/runtime/semaphore.hpp
diffstat 12 files changed, 475 insertions(+), 138 deletions(-) [+]
line wrap: on
line diff
--- a/make/solaris/makefiles/vm.make	Thu Jun 25 20:47:46 2015 +0000
+++ b/make/solaris/makefiles/vm.make	Mon Jan 19 11:06:08 2015 +0100
@@ -143,7 +143,7 @@
 LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
 endif # sparcWorks
 
-LIBS += -lkstat
+LIBS += -lkstat -lrt
 
 # By default, link the *.o into the library, not the executable.
 LINK_INTO$(LINK_INTO) = LIBJVM
--- a/src/os/bsd/vm/os_bsd.cpp	Thu Jun 25 20:47:46 2015 +0000
+++ b/src/os/bsd/vm/os_bsd.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -59,6 +59,7 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
+#include "semaphore_bsd.hpp"
 #include "services/attachListener.hpp"
 #include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
@@ -1940,47 +1941,54 @@
   #define SEM_DESTROY(sem)        sem_destroy(&sem)
 #endif
 
-class Semaphore : public StackObj {
- public:
-  Semaphore();
-  ~Semaphore();
-  void signal();
-  void wait();
-  bool trywait();
-  bool timedwait(unsigned int sec, int nsec);
- private:
-  jlong currenttime() const;
-  os_semaphore_t _semaphore;
-};
-
-Semaphore::Semaphore() : _semaphore(0) {
-  SEM_INIT(_semaphore, 0);
+#ifdef __APPLE__
+// OS X doesn't support unamed POSIX semaphores, so the implementation in os_posix.cpp can't be used.
+
+static const char* sem_init_strerror(kern_return_t value) {
+  switch (value) {
+    case KERN_INVALID_ARGUMENT:  return "Invalid argument";
+    case KERN_RESOURCE_SHORTAGE: return "Resource shortage";
+    default:                     return "Unknown";
+  }
 }
 
-Semaphore::~Semaphore() {
+OSXSemaphore::OSXSemaphore(uint value) {
+  kern_return_t ret = SEM_INIT(_semaphore, value);
+
+  guarantee(ret == KERN_SUCCESS, err_msg("Failed to create semaphore: %s", sem_init_strerror(ret)));
+}
+
+OSXSemaphore::~OSXSemaphore() {
   SEM_DESTROY(_semaphore);
 }
 
-void Semaphore::signal() {
-  SEM_POST(_semaphore);
+void OSXSemaphore::signal(uint count) {
+  for (uint i = 0; i < count; i++) {
+    kern_return_t ret = SEM_POST(_semaphore);
+
+    assert(ret == KERN_SUCCESS, "Failed to signal semaphore");
+  }
 }
 
-void Semaphore::wait() {
-  SEM_WAIT(_semaphore);
+void OSXSemaphore::wait() {
+  kern_return_t ret;
+  while ((ret = SEM_WAIT(_semaphore)) == KERN_ABORTED) {
+    // Semaphore was interrupted. Retry.
+  }
+  assert(ret == KERN_SUCCESS, "Failed to wait on semaphore");
 }
 
-jlong Semaphore::currenttime() const {
+jlong OSXSemaphore::currenttime() {
   struct timeval tv;
   gettimeofday(&tv, NULL);
   return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000);
 }
 
-#ifdef __APPLE__
-bool Semaphore::trywait() {
+bool OSXSemaphore::trywait() {
   return timedwait(0, 0);
 }
 
-bool Semaphore::timedwait(unsigned int sec, int nsec) {
+bool OSXSemaphore::timedwait(unsigned int sec, int nsec) {
   kern_return_t kr = KERN_ABORTED;
   mach_timespec_t waitspec;
   waitspec.tv_sec = sec;
@@ -2011,33 +2019,24 @@
 }
 
 #else
-
-bool Semaphore::trywait() {
-  return sem_trywait(&_semaphore) == 0;
-}
-
-bool Semaphore::timedwait(unsigned int sec, int nsec) {
+// Use POSIX implementation of semaphores.
+
+struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
   struct timespec ts;
   unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
 
-  while (1) {
-    int result = sem_timedwait(&_semaphore, &ts);
-    if (result == 0) {
-      return true;
-    } else if (errno == EINTR) {
-      continue;
-    } else if (errno == ETIMEDOUT) {
-      return false;
-    } else {
-      return false;
-    }
-  }
+  return ts;
 }
 
 #endif // __APPLE__
 
 static os_semaphore_t sig_sem;
-static Semaphore sr_semaphore;
+
+#ifdef __APPLE__
+static OSXSemaphore sr_semaphore;
+#else
+static PosixSemaphore sr_semaphore;
+#endif
 
 void os::signal_init_pd() {
   // Initialize signal structures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/bsd/vm/semaphore_bsd.hpp	Mon Jan 19 11:06:08 2015 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_BSD_VM_SEMAPHORE_BSD_HPP
+#define OS_BSD_VM_SEMAPHORE_BSD_HPP
+
+#ifndef __APPLE__
+// Use POSIX semaphores.
+# include "semaphore_posix.hpp"
+
+#else
+// OS X doesn't support unamed POSIX semaphores, so the implementation in os_posix.cpp can't be used.
+# include "memory/allocation.hpp"
+# include <mach/semaphore.h>
+
+class OSXSemaphore : public CHeapObj<mtInternal>{
+  semaphore_t _semaphore;
+
+  // Prevent copying and assignment.
+  OSXSemaphore(const OSXSemaphore&);
+  OSXSemaphore& operator=(const OSXSemaphore&);
+
+ public:
+  OSXSemaphore(uint value = 0);
+  ~OSXSemaphore();
+
+  void signal(uint count = 1);
+
+  void wait();
+
+  bool trywait();
+  bool timedwait(unsigned int sec, int nsec);
+
+ private:
+  static jlong currenttime();
+};
+
+typedef OSXSemaphore SemaphoreImpl;
+
+#endif // __APPLE__
+
+#endif // OS_BSD_VM_SEMAPHORE_BSD_HPP
--- a/src/os/linux/vm/os_linux.cpp	Thu Jun 25 20:47:46 2015 +0000
+++ b/src/os/linux/vm/os_linux.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -60,6 +60,7 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
+#include "semaphore_posix.hpp"
 #include "services/attachListener.hpp"
 #include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
@@ -2315,40 +2316,7 @@
   return CAST_FROM_FN_PTR(void*, UserHandler);
 }
 
-class Semaphore : public StackObj {
- public:
-  Semaphore();
-  ~Semaphore();
-  void signal();
-  void wait();
-  bool trywait();
-  bool timedwait(unsigned int sec, int nsec);
- private:
-  sem_t _semaphore;
-};
-
-Semaphore::Semaphore() {
-  sem_init(&_semaphore, 0, 0);
-}
-
-Semaphore::~Semaphore() {
-  sem_destroy(&_semaphore);
-}
-
-void Semaphore::signal() {
-  sem_post(&_semaphore);
-}
-
-void Semaphore::wait() {
-  sem_wait(&_semaphore);
-}
-
-bool Semaphore::trywait() {
-  return sem_trywait(&_semaphore) == 0;
-}
-
-bool Semaphore::timedwait(unsigned int sec, int nsec) {
-
+struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
   struct timespec ts;
   // Semaphore's are always associated with CLOCK_REALTIME
   os::Linux::clock_gettime(CLOCK_REALTIME, &ts);
@@ -2365,18 +2333,7 @@
     }
   }
 
-  while (1) {
-    int result = sem_timedwait(&_semaphore, &ts);
-    if (result == 0) {
-      return true;
-    } else if (errno == EINTR) {
-      continue;
-    } else if (errno == ETIMEDOUT) {
-      return false;
-    } else {
-      return false;
-    }
-  }
+  return ts;
 }
 
 extern "C" {
@@ -2416,7 +2373,7 @@
 
 // Linux(POSIX) specific hand shaking semaphore.
 static sem_t sig_sem;
-static Semaphore sr_semaphore;
+static PosixSemaphore sr_semaphore;
 
 void os::signal_init_pd() {
   // Initialize signal structures
--- a/src/os/posix/vm/os_posix.cpp	Thu Jun 25 20:47:46 2015 +0000
+++ b/src/os/posix/vm/os_posix.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -24,6 +24,7 @@
 
 #include "utilities/globalDefinitions.hpp"
 #include "prims/jvm.h"
+#include "semaphore_posix.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/os.hpp"
@@ -34,6 +35,7 @@
 #include <sys/resource.h>
 #include <sys/utsname.h>
 #include <pthread.h>
+#include <semaphore.h>
 #include <signal.h>
 
 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
@@ -1015,3 +1017,73 @@
     }
   }
 }
+
+#define check_with_errno(check_type, cond, msg)                                      \
+  do {                                                                               \
+    int err = errno;                                                                 \
+    check_type(cond, err_msg("%s; error='%s' (errno=%d)", msg, strerror(err), err)); \
+} while (false)
+
+#define assert_with_errno(cond, msg)    check_with_errno(assert, cond, msg)
+#define guarantee_with_errno(cond, msg) check_with_errno(guarantee, cond, msg)
+
+// POSIX unamed semaphores are not supported on OS X.
+#ifndef __APPLE__
+
+PosixSemaphore::PosixSemaphore(uint value) {
+  int ret = sem_init(&_semaphore, 0, value);
+
+  guarantee_with_errno(ret == 0, "Failed to initialize semaphore");
+}
+
+PosixSemaphore::~PosixSemaphore() {
+  sem_destroy(&_semaphore);
+}
+
+void PosixSemaphore::signal(uint count) {
+  for (uint i = 0; i < count; i++) {
+    int ret = sem_post(&_semaphore);
+
+    assert_with_errno(ret == 0, "sem_post failed");
+  }
+}
+
+void PosixSemaphore::wait() {
+  int ret;
+
+  do {
+    ret = sem_wait(&_semaphore);
+  } while (ret != 0 && errno == EINTR);
+
+  assert_with_errno(ret == 0, "sem_wait failed");
+}
+
+bool PosixSemaphore::trywait() {
+  int ret;
+
+  do {
+    ret = sem_trywait(&_semaphore);
+  } while (ret != 0 && errno == EINTR);
+
+  assert_with_errno(ret == 0 || errno == EAGAIN, "trywait failed");
+
+  return ret == 0;
+}
+
+bool PosixSemaphore::timedwait(const struct timespec ts) {
+  while (true) {
+    int result = sem_timedwait(&_semaphore, &ts);
+    if (result == 0) {
+      return true;
+    } else if (errno == EINTR) {
+      continue;
+    } else if (errno == ETIMEDOUT) {
+      return false;
+    } else {
+      assert_with_errno(false, "timedwait failed");
+      return false;
+    }
+  }
+}
+
+#endif // __APPLE__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/posix/vm/semaphore_posix.hpp	Mon Jan 19 11:06:08 2015 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_POSIX_VM_SEMAPHORE_POSIX_HPP
+#define OS_POSIX_VM_SEMAPHORE_POSIX_HPP
+
+#include "memory/allocation.hpp"
+
+#include <semaphore.h>
+
+class PosixSemaphore : public CHeapObj<mtInternal> {
+  sem_t _semaphore;
+
+  // Prevent copying and assignment.
+  PosixSemaphore(const PosixSemaphore&);
+  PosixSemaphore& operator=(const PosixSemaphore&);
+
+ public:
+  PosixSemaphore(uint value = 0);
+  ~PosixSemaphore();
+
+  void signal(uint count = 1);
+
+  void wait();
+
+  bool trywait();
+  bool timedwait(unsigned int sec, int nsec) {
+    return timedwait(create_timespec(sec, nsec));
+  }
+
+ private:
+  bool timedwait(struct timespec ts);
+
+  // OS specific implementation to create a timespec suitable for semaphores.
+  struct timespec create_timespec(unsigned int set, int nsec);
+};
+
+typedef PosixSemaphore SemaphoreImpl;
+
+#endif // OS_POSIX_VM_SEMAPHORE_POSIX_HPP
--- a/src/os/solaris/vm/os_solaris.cpp	Thu Jun 25 20:47:46 2015 +0000
+++ b/src/os/solaris/vm/os_solaris.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -60,6 +60,7 @@
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
 #include "runtime/vm_version.hpp"
+#include "semaphore_posix.hpp"
 #include "services/attachListener.hpp"
 #include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
@@ -2263,55 +2264,11 @@
   return CAST_FROM_FN_PTR(void*, UserHandler);
 }
 
-class Semaphore : public StackObj {
- public:
-  Semaphore();
-  ~Semaphore();
-  void signal();
-  void wait();
-  bool trywait();
-  bool timedwait(unsigned int sec, int nsec);
- private:
-  sema_t _semaphore;
-};
-
-
-Semaphore::Semaphore() {
-  sema_init(&_semaphore, 0, NULL, NULL);
-}
-
-Semaphore::~Semaphore() {
-  sema_destroy(&_semaphore);
-}
-
-void Semaphore::signal() {
-  sema_post(&_semaphore);
-}
-
-void Semaphore::wait() {
-  sema_wait(&_semaphore);
-}
-
-bool Semaphore::trywait() {
-  return sema_trywait(&_semaphore) == 0;
-}
-
-bool Semaphore::timedwait(unsigned int sec, int nsec) {
+struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
   struct timespec ts;
   unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
 
-  while (1) {
-    int result = sema_timedwait(&_semaphore, &ts);
-    if (result == 0) {
-      return true;
-    } else if (errno == EINTR) {
-      continue;
-    } else if (errno == ETIME) {
-      return false;
-    } else {
-      return false;
-    }
-  }
+  return ts;
 }
 
 extern "C" {
@@ -3711,7 +3668,7 @@
   osthread->set_ucontext(context);
 }
 
-static Semaphore sr_semaphore;
+static PosixSemaphore sr_semaphore;
 
 void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
   // Save and restore errno to avoid confusing native code with EINTR
--- a/src/os/windows/vm/os_windows.cpp	Thu Jun 25 20:47:46 2015 +0000
+++ b/src/os/windows/vm/os_windows.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -63,6 +63,7 @@
 #include "runtime/threadCritical.hpp"
 #include "runtime/timer.hpp"
 #include "runtime/vm_version.hpp"
+#include "semaphore_windows.hpp"
 #include "services/attachListener.hpp"
 #include "services/memTracker.hpp"
 #include "services/runtimeService.hpp"
@@ -1901,6 +1902,30 @@
   return (int)error;
 }
 
+WindowsSemaphore::WindowsSemaphore(uint value) {
+  _semaphore = ::CreateSemaphore(NULL, value, LONG_MAX, NULL);
+
+  guarantee(_semaphore != NULL, err_msg("CreateSemaphore failed with error code: %lu", GetLastError()));
+}
+
+WindowsSemaphore::~WindowsSemaphore() {
+  ::CloseHandle(_semaphore);
+}
+
+void WindowsSemaphore::signal(uint count) {
+  if (count > 0) {
+    BOOL ret = ::ReleaseSemaphore(_semaphore, count, NULL);
+
+    assert(ret != 0, err_msg("ReleaseSemaphore failed with error code: %lu", GetLastError()));
+  }
+}
+
+void WindowsSemaphore::wait() {
+  DWORD ret = ::WaitForSingleObject(_semaphore, INFINITE);
+  assert(ret != WAIT_FAILED,   err_msg("WaitForSingleObject failed with error code: %lu", GetLastError()));
+  assert(ret == WAIT_OBJECT_0, err_msg("WaitForSingleObject failed with return value: %lu", ret));
+}
+
 // 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/windows/vm/semaphore_windows.hpp	Mon Jan 19 11:06:08 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_WINDOWS_VM_SEMAPHORE_WINDOWS_HPP
+#define OS_WINDOWS_VM_SEMAPHORE_WINDOWS_HPP
+
+#include "memory/allocation.hpp"
+
+#include <windef.h>
+
+class WindowsSemaphore : public CHeapObj<mtInternal> {
+  HANDLE _semaphore;
+
+  // Prevent copying and assignment.
+  WindowsSemaphore(const WindowsSemaphore&);
+  WindowsSemaphore& operator=(const WindowsSemaphore&);
+
+ public:
+  WindowsSemaphore(uint value = 0);
+  ~WindowsSemaphore();
+
+  void signal(uint count = 1);
+
+  void wait();
+};
+
+typedef WindowsSemaphore SemaphoreImpl;
+
+#endif // OS_WINDOWS_VM_SEMAPHORE_WINDOWS_HPP
--- a/src/share/vm/prims/jni.cpp	Thu Jun 25 20:47:46 2015 +0000
+++ b/src/share/vm/prims/jni.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -3848,6 +3848,7 @@
   unit_test_function_call
 
 // Forward declaration
+void test_semaphore();
 void TestOS_test();
 void TestReservedSpace_test();
 void TestReserveMemorySpecial_test();
@@ -3873,6 +3874,7 @@
 void execute_internal_vm_tests() {
   if (ExecuteInternalVMTests) {
     tty->print_cr("Running internal VM tests");
+    run_unit_test(test_semaphore());
     run_unit_test(TestOS_test());
     run_unit_test(TestReservedSpace_test());
     run_unit_test(TestReserveMemorySpecial_test());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/runtime/semaphore.cpp	Mon Jan 19 11:06:08 2015 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "utilities/debug.hpp"
+#include "runtime/semaphore.hpp"
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
+static void test_semaphore_single_separate(uint count) {
+  Semaphore sem(0);
+
+  for (uint i = 0; i < count; i++) {
+    sem.signal();
+  }
+
+  for (uint i = 0; i < count; i++) {
+    sem.wait();
+  }
+}
+
+static void test_semaphore_single_combined(uint count) {
+  Semaphore sem(0);
+
+  for (uint i = 0; i < count; i++) {
+    sem.signal();
+    sem.wait();
+  }
+}
+
+static void test_semaphore_many(uint value, uint max, uint increments) {
+  Semaphore sem(value);
+
+  uint total = value;
+
+  for (uint i = value; i + increments <= max; i += increments) {
+    sem.signal(increments);
+
+    total += increments;
+  }
+
+  for (uint i = 0; i < total; i++) {
+    sem.wait();
+  }
+}
+
+static void test_semaphore_many() {
+  for (uint max = 0; max < 10; max++) {
+    for (uint value = 0; value < max; value++) {
+      for (uint inc = 1; inc <= max - value; inc++) {
+        test_semaphore_many(value, max, inc);
+      }
+    }
+  }
+}
+
+void test_semaphore() {
+  for (uint i = 1; i < 10; i++) {
+    test_semaphore_single_separate(i);
+  }
+
+  for (uint i = 0; i < 10; i++) {
+    test_semaphore_single_combined(i);
+  }
+
+  test_semaphore_many();
+}
+
+#endif // PRODUCT
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/runtime/semaphore.hpp	Mon Jan 19 11:06:08 2015 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_SEMAPHORE_HPP
+#define SHARE_VM_RUNTIME_SEMAPHORE_HPP
+
+#include "memory/allocation.hpp"
+
+#if defined(TARGET_OS_FAMILY_linux) || defined(TARGET_OS_FAMILY_solaris) || defined(TARGET_OS_FAMILY_aix)
+# include "semaphore_posix.hpp"
+#elif defined(TARGET_OS_FAMILY_bsd)
+# include "semaphore_bsd.hpp"
+#elif defined(TARGET_OS_FAMILY_windows)
+# include "semaphore_windows.hpp"
+#else
+# error "No semaphore implementation provided for this OS"
+#endif
+
+// Implements the limited, platform independent Semaphore API.
+class Semaphore : public CHeapObj<mtInternal> {
+  SemaphoreImpl _impl;
+
+  // Prevent copying and assignment of Semaphore instances.
+  Semaphore(const Semaphore&);
+  Semaphore& operator=(const Semaphore&);
+
+ public:
+  Semaphore(uint value = 0) : _impl(value) {}
+  ~Semaphore() {}
+
+  void signal(uint count = 1) { _impl.signal(count); }
+
+  void wait()                 { _impl.wait(); }
+};
+
+
+#endif // SHARE_VM_RUNTIME_SEMAPHORE_HPP