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