18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "runtime/atomic.hpp"
27 #include "runtime/thread.inline.hpp"
28 #include "runtime/threadCritical.hpp"
29
30 // OS-includes here
31 # include <windows.h>
32 # include <winbase.h>
33
34 //
35 // See threadCritical.hpp for details of this class.
36 //
37
38 static bool initialized = false;
39 static volatile int lock_count = -1;
40 static HANDLE lock_event;
41 static DWORD lock_owner = -1;
42
43 //
44 // Note that Microsoft's critical region code contains a race
45 // condition, and is not suitable for use. A thread holding the
46 // critical section cannot safely suspend a thread attempting
47 // to enter the critical region. The failure mode is that both
48 // threads are permanently suspended.
49 //
50 // I experiemented with the use of ordinary windows mutex objects
51 // and found them ~30 times slower than the critical region code.
52 //
53
54 ThreadCritical::ThreadCritical() {
55 DWORD current_thread = GetCurrentThreadId();
56
57 if (lock_owner != current_thread) {
58 // Grab the lock before doing anything.
59 while (Atomic::cmpxchg(&lock_count, -1, 0) != -1) {
60 if (initialized) {
61 DWORD ret = WaitForSingleObject(lock_event, INFINITE);
62 assert(ret == WAIT_OBJECT_0, "unexpected return value from WaitForSingleObject");
63 }
64 }
65
66 // Make sure the event object is allocated.
67 if (!initialized) {
68 // Locking will not work correctly unless this is autoreset.
69 lock_event = CreateEvent(NULL, false, false, NULL);
70 initialized = true;
71 }
72
73 assert(lock_owner == -1, "Lock acquired illegally.");
74 lock_owner = current_thread;
75 } else {
76 // Atomicity isn't required. Bump the recursion count.
77 lock_count++;
78 }
79
80 assert(lock_owner == GetCurrentThreadId(), "Lock acquired illegally.");
81 }
82
83 ThreadCritical::~ThreadCritical() {
84 assert(lock_owner == GetCurrentThreadId(), "unlock attempt by wrong thread");
85 assert(lock_count >= 0, "Attempt to unlock when already unlocked");
86
87 if (lock_count == 0) {
88 // We're going to unlock
89 lock_owner = -1;
90 lock_count = -1;
91 // No lost wakeups, lock_event stays signaled until reset.
92 DWORD ret = SetEvent(lock_event);
93 assert(ret != 0, "unexpected return value from SetEvent");
94 } else {
95 // Just unwinding a recursive lock;
96 lock_count--;
97 }
98 }
|
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "runtime/atomic.hpp"
27 #include "runtime/thread.inline.hpp"
28 #include "runtime/threadCritical.hpp"
29
30 // OS-includes here
31 # include <windows.h>
32 # include <winbase.h>
33
34 //
35 // See threadCritical.hpp for details of this class.
36 //
37
38 static INIT_ONCE initialized = INIT_ONCE_STATIC_INIT;
39 static int lock_count = 0;
40 static HANDLE lock_event;
41 static DWORD lock_owner = 0;
42
43 //
44 // Note that Microsoft's critical region code contains a race
45 // condition, and is not suitable for use. A thread holding the
46 // critical section cannot safely suspend a thread attempting
47 // to enter the critical region. The failure mode is that both
48 // threads are permanently suspended.
49 //
50 // I experiemented with the use of ordinary windows mutex objects
51 // and found them ~30 times slower than the critical region code.
52 //
53
54 static BOOL WINAPI initialize(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) {
55 lock_event = CreateEvent(NULL, false, true, NULL);
56 assert(lock_event != NULL, "unexpected return value from CreateEvent");
57 return true;
58 }
59
60 ThreadCritical::ThreadCritical() {
61 InitOnceExecuteOnce(&initialized, &initialize, NULL, NULL);
62
63 DWORD current_thread = GetCurrentThreadId();
64 if (lock_owner != current_thread) {
65 // Grab the lock before doing anything.
66 DWORD ret = WaitForSingleObject(lock_event, INFINITE);
67 assert(ret == WAIT_OBJECT_0, "unexpected return value from WaitForSingleObject");
68 lock_owner = current_thread;
69 }
70 // Atomicity isn't required. Bump the recursion count.
71 lock_count++;
72 }
73
74 ThreadCritical::~ThreadCritical() {
75 assert(lock_owner == GetCurrentThreadId(), "unlock attempt by wrong thread");
76 assert(lock_count >= 0, "Attempt to unlock when already unlocked");
77
78 lock_count--;
79 if (lock_count == 0) {
80 // We're going to unlock
81 lock_owner = 0;
82 // No lost wakeups, lock_event stays signaled until reset.
83 DWORD ret = SetEvent(lock_event);
84 assert(ret != 0, "unexpected return value from SetEvent");
85 }
86 }
|