4790 // 2. Consider wrapping the WaitForSingleObject(Ex) calls in SEH try/finally blocks |
4790 // 2. Consider wrapping the WaitForSingleObject(Ex) calls in SEH try/finally blocks |
4791 // to recover from (or at least detect) the dreaded Windows 841176 bug. |
4791 // to recover from (or at least detect) the dreaded Windows 841176 bug. |
4792 // 3. Collapse the interrupt_event, the JSR166 parker event, and the objectmonitor ParkEvent |
4792 // 3. Collapse the interrupt_event, the JSR166 parker event, and the objectmonitor ParkEvent |
4793 // into a single win32 CreateEvent() handle. |
4793 // into a single win32 CreateEvent() handle. |
4794 // |
4794 // |
|
4795 // Assumption: |
|
4796 // Only one parker can exist on an event, which is why we allocate |
|
4797 // them per-thread. Multiple unparkers can coexist. |
|
4798 // |
4795 // _Event transitions in park() |
4799 // _Event transitions in park() |
4796 // -1 => -1 : illegal |
4800 // -1 => -1 : illegal |
4797 // 1 => 0 : pass - return immediately |
4801 // 1 => 0 : pass - return immediately |
4798 // 0 => -1 : block |
4802 // 0 => -1 : block; then set _Event to 0 before returning |
4799 // |
4803 // |
4800 // _Event serves as a restricted-range semaphore : |
4804 // _Event transitions in unpark() |
4801 // -1 : thread is blocked |
4805 // 0 => 1 : just return |
4802 // 0 : neutral - thread is running or ready |
4806 // 1 => 1 : just return |
4803 // 1 : signaled - thread is running or ready |
4807 // -1 => either 0 or 1; must signal target thread |
|
4808 // That is, we can safely transition _Event from -1 to either |
|
4809 // 0 or 1. |
4804 // |
4810 // |
4805 // Another possible encoding of _Event would be |
4811 // _Event serves as a restricted-range semaphore. |
4806 // with explicit "PARKED" and "SIGNALED" bits. |
4812 // -1 : thread is blocked, i.e. there is a waiter |
|
4813 // 0 : neutral: thread is running or ready, |
|
4814 // could have been signaled after a wait started |
|
4815 // 1 : signaled - thread is running or ready |
|
4816 // |
|
4817 // Another possible encoding of _Event would be with |
|
4818 // explicit "PARKED" == 01b and "SIGNALED" == 10b bits. |
|
4819 // |
4807 |
4820 |
4808 int os::PlatformEvent::park(jlong Millis) { |
4821 int os::PlatformEvent::park(jlong Millis) { |
|
4822 // Transitions for _Event: |
|
4823 // -1 => -1 : illegal |
|
4824 // 1 => 0 : pass - return immediately |
|
4825 // 0 => -1 : block; then set _Event to 0 before returning |
|
4826 |
4809 guarantee(_ParkHandle != NULL , "Invariant"); |
4827 guarantee(_ParkHandle != NULL , "Invariant"); |
4810 guarantee(Millis > 0 , "Invariant"); |
4828 guarantee(Millis > 0 , "Invariant"); |
4811 int v; |
|
4812 |
4829 |
4813 // CONSIDER: defer assigning a CreateEvent() handle to the Event until |
4830 // CONSIDER: defer assigning a CreateEvent() handle to the Event until |
4814 // the initial park() operation. |
4831 // the initial park() operation. |
4815 |
4832 // Consider: use atomic decrement instead of CAS-loop |
|
4833 |
|
4834 int v; |
4816 for (;;) { |
4835 for (;;) { |
4817 v = _Event; |
4836 v = _Event; |
4818 if (Atomic::cmpxchg(v-1, &_Event, v) == v) break; |
4837 if (Atomic::cmpxchg(v-1, &_Event, v) == v) break; |
4819 } |
4838 } |
4820 guarantee((v == 0) || (v == 1), "invariant"); |
4839 guarantee((v == 0) || (v == 1), "invariant"); |
4858 // Implementor's license -- returning OS_TIMEOUT would be equally valid, however. |
4877 // Implementor's license -- returning OS_TIMEOUT would be equally valid, however. |
4859 return (v >= 0) ? OS_OK : OS_TIMEOUT; |
4878 return (v >= 0) ? OS_OK : OS_TIMEOUT; |
4860 } |
4879 } |
4861 |
4880 |
4862 void os::PlatformEvent::park() { |
4881 void os::PlatformEvent::park() { |
|
4882 // Transitions for _Event: |
|
4883 // -1 => -1 : illegal |
|
4884 // 1 => 0 : pass - return immediately |
|
4885 // 0 => -1 : block; then set _Event to 0 before returning |
|
4886 |
4863 guarantee(_ParkHandle != NULL, "Invariant"); |
4887 guarantee(_ParkHandle != NULL, "Invariant"); |
4864 // Invariant: Only the thread associated with the Event/PlatformEvent |
4888 // Invariant: Only the thread associated with the Event/PlatformEvent |
4865 // may call park(). |
4889 // may call park(). |
|
4890 // Consider: use atomic decrement instead of CAS-loop |
4866 int v; |
4891 int v; |
4867 for (;;) { |
4892 for (;;) { |
4868 v = _Event; |
4893 v = _Event; |
4869 if (Atomic::cmpxchg(v-1, &_Event, v) == v) break; |
4894 if (Atomic::cmpxchg(v-1, &_Event, v) == v) break; |
4870 } |
4895 } |
4889 |
4914 |
4890 void os::PlatformEvent::unpark() { |
4915 void os::PlatformEvent::unpark() { |
4891 guarantee(_ParkHandle != NULL, "Invariant"); |
4916 guarantee(_ParkHandle != NULL, "Invariant"); |
4892 |
4917 |
4893 // Transitions for _Event: |
4918 // Transitions for _Event: |
4894 // 0 :=> 1 |
4919 // 0 => 1 : just return |
4895 // 1 :=> 1 |
4920 // 1 => 1 : just return |
4896 // -1 :=> either 0 or 1; must signal target thread |
4921 // -1 => either 0 or 1; must signal target thread |
4897 // That is, we can safely transition _Event from -1 to either |
4922 // That is, we can safely transition _Event from -1 to either |
4898 // 0 or 1. |
4923 // 0 or 1. |
4899 // See also: "Semaphores in Plan 9" by Mullender & Cox |
4924 // See also: "Semaphores in Plan 9" by Mullender & Cox |
4900 // |
4925 // |
4901 // Note: Forcing a transition from "-1" to "1" on an unpark() means |
4926 // Note: Forcing a transition from "-1" to "1" on an unpark() means |
4902 // that it will take two back-to-back park() calls for the owning |
4927 // that it will take two back-to-back park() calls for the owning |
4903 // thread to block. This has the benefit of forcing a spurious return |
4928 // thread to block. This has the benefit of forcing a spurious return |