From: Torge Matthies tmatthies@codeweavers.com
Keep the one with the lowest id, which seems to be the behavior on native.
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/msvcrt/concurrency.c | 68 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index d0c9924c631..3ca8d748cad 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -97,6 +97,7 @@ typedef struct { } ExternalContextBase; extern const vtable_ptr ExternalContextBase_vtable; static void ExternalContextBase_ctor(ExternalContextBase*); +static void ExternalContextBase_dtor(ExternalContextBase*);
typedef struct Scheduler { const vtable_ptr *vtable; @@ -359,6 +360,16 @@ enum ConcRT_EventType CONCRT_EVENT_DETACH };
+static CRITICAL_SECTION cached_context_cs; +static CRITICAL_SECTION_DEBUG cached_context_cs_debug = +{ + 0, 0, &cached_context_cs, + { &cached_context_cs_debug.ProcessLocksList, &cached_context_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": cached_context_cs") } +}; +static CRITICAL_SECTION cached_context_cs = { &cached_context_cs_debug, -1, 0, 0, 0, 0 }; +static ExternalContextBase* cached_context; + static DWORD context_tls_index = TLS_OUT_OF_INDEXES;
static CRITICAL_SECTION default_scheduler_cs; @@ -674,6 +685,55 @@ static BOOL WINAPI init_context_tls_index(INIT_ONCE *once, void *param, void **c return context_tls_index != TLS_OUT_OF_INDEXES; }
+static Context* allocate_context(void) +{ + ExternalContextBase *context = NULL; + + EnterCriticalSection(&cached_context_cs); + if (cached_context) + { + context = cached_context; + cached_context = NULL; + } + LeaveCriticalSection(&cached_context_cs); + if (!context) + { + context = operator_new(sizeof(ExternalContextBase)); + ExternalContextBase_ctor(context); + } + return &context->context; +} + +static void free_context(Context* ctx) +{ + ExternalContextBase *context = (ExternalContextBase*)ctx; + + if (context->context.vtable != &ExternalContextBase_vtable) + { + call_Context_dtor(ctx, 1); + return; + } + + EnterCriticalSection(&cached_context_cs); + if (cached_context && context->id < cached_context->id) + { + ExternalContextBase_dtor(cached_context); + operator_delete(cached_context); + cached_context = NULL; + } + if (!cached_context) + { + cached_context = context; + context = NULL; + } + LeaveCriticalSection(&cached_context_cs); + if (context) + { + ExternalContextBase_dtor(context); + operator_delete(context); + } +} + static Context* get_current_context(void) { static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; @@ -689,10 +749,8 @@ static Context* get_current_context(void)
ret = TlsGetValue(context_tls_index); if (!ret) { - ExternalContextBase *context = operator_new(sizeof(ExternalContextBase)); - ExternalContextBase_ctor(context); - TlsSetValue(context_tls_index, context); - ret = &context->context; + ret = allocate_context(); + TlsSetValue(context_tls_index, ret); } return ret; } @@ -3122,7 +3180,7 @@ void msvcrt_free_scheduler_thread(void) { Context *context = try_get_current_context(); if (!context) return; - call_Context_dtor(context, 1); + free_context(context); }
#endif /* _MSVCR_VER >= 100 */