From 7f23c57d09746ee8d14893f982052b08a2c675ca Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Tue, 24 Jun 2014 11:57:47 +0200 Subject: [PATCH] msvcr100: Add critical_section class implementation. --- dlls/msvcrt/lock.c | 160 +++++++++++++++++++++++++++++++++++++++++---------- dlls/msvcrt/main.c | 4 +- dlls/msvcrt/msvcrt.h | 2 +- 3 files changed, 132 insertions(+), 34 deletions(-) diff --git a/dlls/msvcrt/lock.c b/dlls/msvcrt/lock.c index 09ff1af4d53..94599d196c0 100644 --- a/dlls/msvcrt/lock.c +++ b/dlls/msvcrt/lock.c @@ -83,30 +83,6 @@ void msvcrt_init_mt_locks(void) } /********************************************************************** - * msvcrt_free_mt_locks (internal) - * - * Uninitialize all mt locks. Assume that neither _lock or _unlock will - * be called once we're calling this routine (ie _LOCKTAB_LOCK can be deleted) - * - */ -void msvcrt_free_mt_locks(void) -{ - int i; - - TRACE( ": uninitializing all mtlocks\n" ); - - /* Uninitialize the table */ - for( i=0; i < _TOTAL_LOCKS; i++ ) - { - if( lock_table[ i ].bInit ) - { - msvcrt_uninitialize_mlock( i ); - } - } -} - - -/********************************************************************** * _lock (MSVCRT.@) */ void CDECL _lock( int locknum ) @@ -309,10 +285,24 @@ MSVCRT_bool __thiscall SpinWait__SpinOnce(SpinWait *this) } } +static HANDLE keyed_event; + +typedef struct cs_queue +{ + struct cs_queue *next; +} cs_queue; + typedef struct { - void *unknown[3]; - void *head; + ULONG_PTR unk_thread_id; + cs_queue unk_active; +#if _MSVCR_VER >= 110 + void *unknown[2]; + int unknown2[2]; +#else + void *unknown[1]; +#endif + cs_queue *head; void *tail; } critical_section; @@ -321,7 +311,18 @@ typedef struct DEFINE_THISCALL_WRAPPER(critical_section_ctor, 4) critical_section* __thiscall critical_section_ctor(critical_section *this) { - FIXME("(%p) stub\n", 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_thread_id = 0; + this->head = this->tail = NULL; return this; } @@ -330,7 +331,32 @@ critical_section* __thiscall critical_section_ctor(critical_section *this) DEFINE_THISCALL_WRAPPER(critical_section_dtor, 4) void __thiscall critical_section_dtor(critical_section *this) { - FIXME("(%p) stub\n", this); + TRACE("(%p)\n", this); +} + +static void __cdecl spin_wait_yield(void) +{ + Sleep(0); +} + +static inline void spin_wait_for_next_cs(cs_queue *q) +{ + SpinWait sw; + + if(q->next) return; + + SpinWait_ctor(&sw, &spin_wait_yield); + SpinWait__Reset(&sw); + while(!q->next) + SpinWait__SpinOnce(&sw); + SpinWait_dtor(&sw); +} + +static inline void cs_set_head(critical_section *cs, cs_queue *q) +{ + cs->unk_thread_id = GetCurrentThreadId(); + cs->unk_active.next = q->next; + cs->head = &cs->unk_active; } /* ?lock@critical_section@Concurrency@@QAEXXZ */ @@ -338,7 +364,26 @@ void __thiscall critical_section_dtor(critical_section *this) DEFINE_THISCALL_WRAPPER(critical_section_lock, 4) void __thiscall critical_section_lock(critical_section *this) { - FIXME("(%p) stub\n", this); + cs_queue q, *last; + + TRACE("(%p)\n", this); + + if(this->unk_thread_id == GetCurrentThreadId()) { + FIXME("throw exception\n"); + return; + } + + q.next = NULL; + last = InterlockedExchangePointer(&this->tail, &q); + if(last) { + last->next = &q; + NtWaitForKeyedEvent(keyed_event, &q, 0, NULL); + } + + this->unk_active.next = NULL; + if(InterlockedCompareExchangePointer(&this->tail, &this->unk_active, &q) != &q) + spin_wait_for_next_cs(&q); + cs_set_head(this, &q); } /* ?try_lock@critical_section@Concurrency@@QAE_NXZ */ @@ -346,7 +391,24 @@ void __thiscall critical_section_lock(critical_section *this) DEFINE_THISCALL_WRAPPER(critical_section_try_lock, 4) MSVCRT_bool __thiscall critical_section_try_lock(critical_section *this) { - FIXME("(%p) stub\n", this); + cs_queue q; + + TRACE("(%p)\n", this); + + if(this->unk_thread_id == GetCurrentThreadId()) { + FIXME("throw exception\n"); + return FALSE; + } + + q.next = NULL; + if(!InterlockedCompareExchangePointer(&this->tail, &q, NULL)) { + this->unk_active.next = NULL; + if(InterlockedCompareExchangePointer(&this->tail, &this->unk_active, &q) != &q) + spin_wait_for_next_cs(&q); + + cs_set_head(this, &q); + return TRUE; + } return FALSE; } @@ -355,7 +417,15 @@ MSVCRT_bool __thiscall critical_section_try_lock(critical_section *this) DEFINE_THISCALL_WRAPPER(critical_section_unlock, 4) void __thiscall critical_section_unlock(critical_section *this) { - FIXME("(%p) stub\n", this); + TRACE("(%p)\n", this); + + this->unk_thread_id = 0; + this->head = NULL; + if(InterlockedCompareExchangePointer(&this->tail, NULL, &this->unk_active) + == &this->unk_active) return; + spin_wait_for_next_cs(&this->unk_active); + + NtReleaseKeyedEvent(keyed_event, this->unk_active.next, 0, NULL); } /* ?native_handle@critical_section@Concurrency@@QAEAAV12@XZ */ @@ -394,3 +464,31 @@ void __thiscall critical_section_scoped_lock_dtor(critical_section_scoped_lock * critical_section_unlock(this->cs); } #endif + +/********************************************************************** + * msvcrt_free_locks (internal) + * + * Uninitialize all mt locks. Assume that neither _lock or _unlock will + * be called once we're calling this routine (ie _LOCKTAB_LOCK can be deleted) + * + */ +void msvcrt_free_locks(void) +{ + int i; + + TRACE( ": uninitializing all mtlocks\n" ); + + /* Uninitialize the table */ + for( i=0; i < _TOTAL_LOCKS; i++ ) + { + if( lock_table[ i ].bInit ) + { + msvcrt_uninitialize_mlock( i ); + } + } + +#if _MSVCR_VER >= 100 + if(keyed_event) + NtClose(keyed_event); +#endif +} diff --git a/dlls/msvcrt/main.c b/dlls/msvcrt/main.c index 5a3bba762d0..1deb0804858 100644 --- a/dlls/msvcrt/main.c +++ b/dlls/msvcrt/main.c @@ -106,7 +106,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) } msvcrt_init_mt_locks(); if(!msvcrt_init_locale()) { - msvcrt_free_mt_locks(); + msvcrt_free_locks(); msvcrt_free_tls_mem(); msvcrt_destroy_heap(); return FALSE; @@ -130,7 +130,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) msvcrt_free_io(); if (lpvReserved) break; msvcrt_free_popen_data(); - msvcrt_free_mt_locks(); + msvcrt_free_locks(); msvcrt_free_console(); msvcrt_free_args(); msvcrt_free_signals(); diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 9069b797255..22ba0d40e4e 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -261,7 +261,7 @@ typedef void (__cdecl *free_func_t)(void*); /* Setup and teardown multi threaded locks */ extern void msvcrt_init_mt_locks(void) DECLSPEC_HIDDEN; -extern void msvcrt_free_mt_locks(void) DECLSPEC_HIDDEN; +extern void msvcrt_free_locks(void) DECLSPEC_HIDDEN; extern void msvcrt_init_exception(void*) DECLSPEC_HIDDEN; extern BOOL msvcrt_init_locale(void) DECLSPEC_HIDDEN; -- 2.11.4.GIT