Piotr Caban : msvcr100: Add critical_section class implementation.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue Jun 24 14:28:33 CDT 2014
Module: wine
Branch: master
Commit: 7f23c57d09746ee8d14893f982052b08a2c675ca
URL: http://source.winehq.org/git/wine.git/?a=commit;h=7f23c57d09746ee8d14893f982052b08a2c675ca
Author: Piotr Caban <piotr at codeweavers.com>
Date: Tue Jun 24 11:57:47 2014 +0200
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 09ff1af..94599d1 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 at 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 at 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 at critical_section@Concurrency@@QAEAAV12 at 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 5a3bba7..1deb080 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 9069b79..22ba0d4 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;
More information about the wine-cvs
mailing list