From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcp140/tests/msvcp140.c | 2 +- dlls/msvcp90/msvcp90.h | 2 +- dlls/msvcr120/tests/msvcr120.c | 2 +- dlls/msvcrt/concurrency.c | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c index 640e44e5b7c..6affa2f9c29 100644 --- a/dlls/msvcp140/tests/msvcp140.c +++ b/dlls/msvcp140/tests/msvcp140.c @@ -150,6 +150,7 @@ typedef struct
typedef struct cs_queue { + void *ctx; struct cs_queue *next; BOOL free; int unknown; @@ -157,7 +158,6 @@ typedef struct cs_queue
typedef struct { - ULONG_PTR unk_thread_id; cs_queue unk_active; void *unknown[2]; cs_queue *head; diff --git a/dlls/msvcp90/msvcp90.h b/dlls/msvcp90/msvcp90.h index b996ae84a46..cfeb03fa235 100644 --- a/dlls/msvcp90/msvcp90.h +++ b/dlls/msvcp90/msvcp90.h @@ -45,6 +45,7 @@ extern void* (__cdecl *MSVCRT_set_new_handler)(void*); /* keep in sync with msvcrt/lock.c */ typedef struct cs_queue { + void *ctx; struct cs_queue *next; BOOL free; int unknown; @@ -52,7 +53,6 @@ typedef struct cs_queue
typedef struct { - ULONG_PTR unk_thread_id; cs_queue unk_active; void *unknown[2]; cs_queue *head; diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index fd8e42fd35d..e5a5ff0435d 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -90,6 +90,7 @@ typedef unsigned char MSVCRT_bool;
typedef struct cs_queue { + void *ctx; struct cs_queue *next; BOOL free; int unknown; @@ -97,7 +98,6 @@ typedef struct cs_queue
typedef struct { - ULONG_PTR unk_thread_id; cs_queue unk_active; void *unknown[2]; cs_queue *head; diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 84ee0f1817a..598444f3a53 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -216,6 +216,7 @@ struct scheduled_chore { /* keep in sync with msvcp90/msvcp90.h */ typedef struct cs_queue { + Context *ctx; struct cs_queue *next; #if _MSVCR_VER >= 110 LONG free; @@ -225,7 +226,6 @@ typedef struct cs_queue
typedef struct { - ULONG_PTR unk_thread_id; cs_queue unk_active; #if _MSVCR_VER >= 110 void *unknown[2]; @@ -2425,7 +2425,7 @@ critical_section* __thiscall critical_section_ctor(critical_section *this) NtClose(event); }
- this->unk_thread_id = 0; + this->unk_active.ctx = NULL; this->head = this->tail = NULL; return this; } @@ -2458,7 +2458,7 @@ static inline void spin_wait_for_next_cs(cs_queue *q)
static inline void cs_set_head(critical_section *cs, cs_queue *q) { - cs->unk_thread_id = GetCurrentThreadId(); + cs->unk_active.ctx = get_current_context(); cs->unk_active.next = q->next; cs->head = &cs->unk_active; } @@ -2467,7 +2467,7 @@ static inline void cs_lock(critical_section *cs, cs_queue *q) { cs_queue *last;
- if(cs->unk_thread_id == GetCurrentThreadId()) { + if(cs->unk_active.ctx == get_current_context()) { improper_lock e; improper_lock_ctor_str(&e, "Already locked"); _CxxThrowException(&e, &improper_lock_exception_type); @@ -2507,7 +2507,7 @@ bool __thiscall critical_section_try_lock(critical_section *this)
TRACE("(%p)\n", this);
- if(this->unk_thread_id == GetCurrentThreadId()) + if(this->unk_active.ctx == get_current_context()) return FALSE;
memset(&q, 0, sizeof(q)); @@ -2529,7 +2529,7 @@ void __thiscall critical_section_unlock(critical_section *this) { TRACE("(%p)\n", this);
- this->unk_thread_id = 0; + this->unk_active.ctx = NULL; this->head = NULL; if(InterlockedCompareExchangePointer(&this->tail, NULL, &this->unk_active) == &this->unk_active) return; @@ -2577,7 +2577,7 @@ bool __thiscall critical_section_try_lock_for(
TRACE("(%p %d)\n", this, timeout);
- if(this->unk_thread_id == GetCurrentThreadId()) { + if(this->unk_active.ctx == get_current_context()) { improper_lock e; improper_lock_ctor_str(&e, "Already locked"); _CxxThrowException(&e, &improper_lock_exception_type);
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcp90/msvcp90.h | 2 +- dlls/msvcrt/concurrency.c | 65 ++++++++++++++++++++++++++------------- 2 files changed, 45 insertions(+), 22 deletions(-)
diff --git a/dlls/msvcp90/msvcp90.h b/dlls/msvcp90/msvcp90.h index cfeb03fa235..5b77a8164e8 100644 --- a/dlls/msvcp90/msvcp90.h +++ b/dlls/msvcp90/msvcp90.h @@ -47,7 +47,7 @@ typedef struct cs_queue { void *ctx; struct cs_queue *next; - BOOL free; + LONG status; int unknown; } cs_queue;
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 598444f3a53..d41832f6763 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -214,12 +214,14 @@ struct scheduled_chore { };
/* keep in sync with msvcp90/msvcp90.h */ +#define CS_UNLOCK 1 +#define CS_TIMEOUT 2 typedef struct cs_queue { Context *ctx; struct cs_queue *next; #if _MSVCR_VER >= 110 - LONG free; + LONG status; int unknown; #endif } cs_queue; @@ -2417,14 +2419,6 @@ critical_section* __thiscall critical_section_ctor(critical_section *this) { TRACE("(%p)\n", this);
- if(!keyed_event) { - HANDLE event; - - NtCreateKeyedEvent(&event, GENERIC_READ|GENERIC_WRITE, NULL, 0); - if(InterlockedCompareExchangePointer(&keyed_event, event, NULL) != NULL) - NtClose(event); - } - this->unk_active.ctx = NULL; this->head = this->tail = NULL; return this; @@ -2474,10 +2468,11 @@ static inline void cs_lock(critical_section *cs, cs_queue *q) }
memset(q, 0, sizeof(*q)); + q->ctx = get_current_context(); last = InterlockedExchangePointer(&cs->tail, q); if(last) { last->next = q; - NtWaitForKeyedEvent(keyed_event, q, 0, NULL); + call_Context_Block(q->ctx); }
cs_set_head(cs, q); @@ -2539,7 +2534,7 @@ void __thiscall critical_section_unlock(critical_section *this) while(1) { cs_queue *next;
- if(!InterlockedExchange(&this->unk_active.next->free, TRUE)) + if(!InterlockedCompareExchange(&this->unk_active.next->status, CS_UNLOCK, 0)) break;
next = this->unk_active.next; @@ -2554,7 +2549,7 @@ void __thiscall critical_section_unlock(critical_section *this) } #endif
- NtReleaseKeyedEvent(keyed_event, this->unk_active.next, 0, NULL); + call_Context_Unblock(this->unk_active.next->ctx); }
/* ?native_handle@critical_section@Concurrency@@QAEAAV12@XZ */ @@ -2567,17 +2562,26 @@ critical_section* __thiscall critical_section_native_handle(critical_section *th }
#if _MSVCR_VER >= 110 +static void WINAPI timeout_unlock(TP_CALLBACK_INSTANCE *instance, void *ctx, TP_TIMER *timer) +{ + cs_queue *q = ctx; + + if(!InterlockedCompareExchange(&q->status, CS_TIMEOUT, 0)) + call_Context_Unblock(q->ctx); +} + /* ?try_lock_for@critical_section@Concurrency@@QAE_NI@Z */ /* ?try_lock_for@critical_section@Concurrency@@QEAA_NI@Z */ DEFINE_THISCALL_WRAPPER(critical_section_try_lock_for, 8) bool __thiscall critical_section_try_lock_for( critical_section *this, unsigned int timeout) { + Context *ctx = get_current_context(); cs_queue *q, *last;
TRACE("(%p %d)\n", this, timeout);
- if(this->unk_active.ctx == get_current_context()) { + if(this->unk_active.ctx == ctx) { improper_lock e; improper_lock_ctor_str(&e, "Already locked"); _CxxThrowException(&e, &improper_lock_exception_type); @@ -2585,25 +2589,36 @@ bool __thiscall critical_section_try_lock_for(
if(!(q = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*q)))) return critical_section_try_lock(this); + q->ctx = ctx;
last = InterlockedExchangePointer(&this->tail, q); if(last) { + TP_TIMER *tp_timer; LARGE_INTEGER to; - NTSTATUS status; FILETIME ft;
last->next = q; GetSystemTimeAsFileTime(&ft); to.QuadPart = ((LONGLONG)ft.dwHighDateTime << 32) + ft.dwLowDateTime + (LONGLONG)timeout * TICKSPERMSEC; - status = NtWaitForKeyedEvent(keyed_event, q, 0, &to); - if(status == STATUS_TIMEOUT) { - if(!InterlockedExchange(&q->free, TRUE)) - return FALSE; - /* A thread has signaled the event and is block waiting. */ - /* We need to catch the event to wake the thread. */ - NtWaitForKeyedEvent(keyed_event, q, 0, NULL); + ft.dwHighDateTime = to.QuadPart >> 32; + ft.dwLowDateTime = to.QuadPart; + + tp_timer = CreateThreadpoolTimer(timeout_unlock, q, NULL); + if(!tp_timer) { + FIXME("throw exception?\n"); + return FALSE; } + SetThreadpoolTimer(tp_timer, &ft, 0, 0); + + call_Context_Block(q->ctx); + + SetThreadpoolTimer(tp_timer, NULL, 0, 0); + WaitForThreadpoolTimerCallbacks(tp_timer, TRUE); + CloseThreadpoolTimer(tp_timer); + + if(q->status == CS_TIMEOUT) + return FALSE; }
cs_set_head(this, q); @@ -2863,6 +2878,14 @@ event* __thiscall event_ctor(event *this) { TRACE("(%p)\n", this);
+ if(!keyed_event) { + HANDLE event; + + NtCreateKeyedEvent(&event, GENERIC_READ|GENERIC_WRITE, NULL, 0); + if(InterlockedCompareExchangePointer(&keyed_event, event, NULL) != NULL) + NtClose(event); + } + this->waiters = NULL; this->signaled = FALSE; critical_section_ctor(&this->cs);