Commit 3f97321c authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

msvcp110: Use _Condition_variable in _Cnd_t implementation.

parent e040e2c1
......@@ -821,22 +821,11 @@ void __cdecl _Mtx_reset_owner(_Mtx_arg_t mtx)
m->count++;
}
static inline LONG interlocked_dec_if_nonzero( LONG *dest )
{
LONG val, tmp;
for (val = *dest;; val = tmp)
{
if (!val || (tmp = InterlockedCompareExchange( dest, val - 1, val )) == val)
break;
}
return val;
}
#define CND_TIMEDOUT 2
typedef struct
{
CONDITION_VARIABLE cv;
_Condition_variable cv;
} *_Cnd_t;
#if _MSVCP_VER >= 140
......@@ -849,19 +838,9 @@ typedef _Cnd_t *_Cnd_arg_t;
#define CND_T_TO_ARG(c) (&(c))
#endif
static HANDLE keyed_event;
void __cdecl _Cnd_init_in_situ(_Cnd_t cnd)
{
InitializeConditionVariable(&cnd->cv);
if(!keyed_event) {
HANDLE event;
NtCreateKeyedEvent(&event, GENERIC_READ|GENERIC_WRITE, NULL, 0);
if(InterlockedCompareExchangePointer(&keyed_event, event, NULL) != NULL)
NtClose(event);
}
cv_init(&cnd->cv);
}
int __cdecl _Cnd_init(_Cnd_t *cnd)
......@@ -873,64 +852,50 @@ int __cdecl _Cnd_init(_Cnd_t *cnd)
int __cdecl _Cnd_wait(_Cnd_arg_t cnd, _Mtx_arg_t mtx)
{
CONDITION_VARIABLE *cv = &CND_T_FROM_ARG(cnd)->cv;
InterlockedExchangeAdd( (LONG *)&cv->Ptr, 1 );
_Mtx_unlock(mtx);
NtWaitForKeyedEvent(keyed_event, &cv->Ptr, FALSE, NULL);
_Condition_variable *cv = &CND_T_FROM_ARG(cnd)->cv;
_Mtx_t m = MTX_T_FROM_ARG(mtx);
_Mtx_lock(mtx);
_Mtx_clear_owner(mtx);
cv_wait(cv, &m->cs);
_Mtx_reset_owner(mtx);
return 0;
}
int __cdecl _Cnd_timedwait(_Cnd_arg_t cnd, _Mtx_arg_t mtx, const xtime *xt)
{
CONDITION_VARIABLE *cv = &CND_T_FROM_ARG(cnd)->cv;
LARGE_INTEGER timeout;
NTSTATUS status;
InterlockedExchangeAdd( (LONG *)&cv->Ptr, 1 );
_Mtx_unlock(mtx);
timeout.QuadPart = (ULONGLONG)(ULONG)_Xtime_diff_to_millis(xt) * -10000;
status = NtWaitForKeyedEvent(keyed_event, &cv->Ptr, FALSE, &timeout);
if (status)
{
if (!interlocked_dec_if_nonzero( (LONG *)&cv->Ptr ))
status = NtWaitForKeyedEvent( keyed_event, &cv->Ptr, FALSE, NULL );
}
_Condition_variable *cv = &CND_T_FROM_ARG(cnd)->cv;
_Mtx_t m = MTX_T_FROM_ARG(mtx);
bool r;
_Mtx_lock(mtx);
return status ? CND_TIMEDOUT : 0;
_Mtx_clear_owner(mtx);
r = cv_wait_for(cv, &m->cs, _Xtime_diff_to_millis(xt));
_Mtx_reset_owner(mtx);
return r ? 0 : CND_TIMEDOUT;
}
int __cdecl _Cnd_broadcast(_Cnd_arg_t cnd)
{
CONDITION_VARIABLE *cv = &CND_T_FROM_ARG(cnd)->cv;
LONG val = InterlockedExchange( (LONG *)&cv->Ptr, 0 );
while (val-- > 0)
NtReleaseKeyedEvent( keyed_event, &cv->Ptr, FALSE, NULL );
cv_notify_all(&CND_T_FROM_ARG(cnd)->cv);
return 0;
}
int __cdecl _Cnd_signal(_Cnd_arg_t cnd)
{
CONDITION_VARIABLE *cv = &CND_T_FROM_ARG(cnd)->cv;
if (interlocked_dec_if_nonzero( (LONG *)&cv->Ptr ))
NtReleaseKeyedEvent( keyed_event, &cv->Ptr, FALSE, NULL );
cv_notify_one(&CND_T_FROM_ARG(cnd)->cv);
return 0;
}
void __cdecl _Cnd_destroy_in_situ(_Cnd_t cnd)
{
_Cnd_broadcast(CND_T_TO_ARG(cnd));
cv_destroy(&cnd->cv);
}
void __cdecl _Cnd_destroy(_Cnd_arg_t cnd)
{
if(cnd) {
_Cnd_broadcast(cnd);
cv_destroy(&CND_T_FROM_ARG(cnd)->cv);
operator_delete(CND_T_FROM_ARG(cnd));
}
}
......@@ -1777,8 +1742,6 @@ void init_misc(void *base)
void free_misc(void)
{
#if _MSVCP_VER >= 110
if(keyed_event)
NtClose(keyed_event);
HeapFree(GetProcessHeap(), 0, broadcast_at_thread_exit.to_broadcast);
#endif
}
......
......@@ -58,11 +58,29 @@ typedef struct
void *tail;
} critical_section;
typedef struct cv_queue {
struct cv_queue *next;
LONG expired;
} cv_queue;
typedef struct {
/* cv_queue structure is not binary compatible */
cv_queue *queue;
critical_section lock;
} _Condition_variable;
extern void cs_init(critical_section*);
extern void cs_destroy(critical_section*);
extern void cs_lock(critical_section*);
extern void cs_unlock(critical_section*);
extern bool cs_trylock(critical_section*);
extern void cv_init(_Condition_variable*);
extern void cv_destroy(_Condition_variable*);
extern void cv_wait(_Condition_variable*, critical_section*);
extern bool cv_wait_for(_Condition_variable*, critical_section*, unsigned int);
extern void cv_notify_one(_Condition_variable*);
extern void cv_notify_all(_Condition_variable*);
#endif
#if _MSVCP_VER >= 100
......
......@@ -68,10 +68,14 @@ __ASM_GLOBAL_FUNC(call_thiscall_func,
"jmp *%edx\n\t")
#define call_func1(func,this) ((void* (WINAPI*)(void*,void*))&call_thiscall_func)(func,this)
#define call_func2(func,this,a) ((void* (WINAPI*)(void*,void*,void*))&call_thiscall_func)(func,this,a)
#define call_func3(func,this,a,b) ((void* (WINAPI*)(void*,void*,void*,unsigned int))&call_thiscall_func)(func,this,a,b)
#else /* __i386__ */
#define call_func1(func,this) func(this)
#define call_func2(func,this,a) func(this,a)
#define call_func3(func,this,a,b) func(this,a,b)
#endif /* __i386__ */
......@@ -81,6 +85,14 @@ static void (__thiscall *critical_section_lock)(critical_section*);
static void (__thiscall *critical_section_unlock)(critical_section*);
static bool (__thiscall *critical_section_trylock)(critical_section*);
static _Condition_variable* (__thiscall *_Condition_variable_ctor)(_Condition_variable*);
static void (__thiscall *_Condition_variable_dtor)(_Condition_variable*);
static void (__thiscall *_Condition_variable_wait)(_Condition_variable*, critical_section*);
bool (__thiscall *_Condition_variable_wait_for)(_Condition_variable*,
critical_section*, unsigned int);
void (__thiscall *_Condition_variable_notify_one)(_Condition_variable*);
void (__thiscall *_Condition_variable_notify_all)(_Condition_variable*);
void cs_init(critical_section *cs)
{
call_func1(critical_section_ctor, cs);
......@@ -105,6 +117,36 @@ bool cs_trylock(critical_section *cs)
{
return call_func1(critical_section_trylock, cs);
}
void cv_init(_Condition_variable *cv)
{
call_func1(_Condition_variable_ctor, cv);
}
void cv_destroy(_Condition_variable *cv)
{
call_func1(_Condition_variable_dtor, cv);
}
void cv_wait(_Condition_variable *cv, critical_section *cs)
{
call_func2(_Condition_variable_wait, cv, cs);
}
bool cv_wait_for(_Condition_variable *cv, critical_section *cs, unsigned int timeout)
{
return call_func3(_Condition_variable_wait_for, cv, cs, timeout);
}
void cv_notify_one(_Condition_variable *cv)
{
call_func1(_Condition_variable_notify_one, cv);
}
void cv_notify_all(_Condition_variable *cv)
{
call_func1(_Condition_variable_notify_all, cv);
}
#endif
#if _MSVCP_VER >= 100
......@@ -206,6 +248,16 @@ static void init_cxx_funcs(void)
critical_section_lock = (void*)GetProcAddress(hcon, "?lock@critical_section@Concurrency@@QEAAXXZ");
critical_section_unlock = (void*)GetProcAddress(hcon, "?unlock@critical_section@Concurrency@@QEAAXXZ");
critical_section_trylock = (void*)GetProcAddress(hcon, "?try_lock@critical_section@Concurrency@@QEAA_NXZ");
_Condition_variable_ctor = (void*)GetProcAddress(hcon, "??0_Condition_variable@details@Concurrency@@QEAA@XZ");
_Condition_variable_dtor = (void*)GetProcAddress(hcon, "??1_Condition_variable@details@Concurrency@@QEAA@XZ");
_Condition_variable_wait = (void*)GetProcAddress(hcon,
"?wait@_Condition_variable@details@Concurrency@@QEAAXAEAVcritical_section@3@@Z");
_Condition_variable_wait_for = (void*)GetProcAddress(hcon,
"?wait_for@_Condition_variable@details@Concurrency@@QEAA_NAEAVcritical_section@3@I@Z");
_Condition_variable_notify_one = (void*)GetProcAddress(hcon,
"?notify_one@_Condition_variable@details@Concurrency@@QEAAXXZ");
_Condition_variable_notify_all = (void*)GetProcAddress(hcon,
"?notify_all@_Condition_variable@details@Concurrency@@QEAAXXZ");
}
else
{
......@@ -215,12 +267,32 @@ static void init_cxx_funcs(void)
critical_section_lock = (void*)GetProcAddress(hcon, "?lock@critical_section@Concurrency@@QAAXXZ");
critical_section_unlock = (void*)GetProcAddress(hcon, "?unlock@critical_section@Concurrency@@QAAXXZ");
critical_section_trylock = (void*)GetProcAddress(hcon, "?try_lock@critical_section@Concurrency@@QAA_NXZ");
_Condition_variable_ctor = (void*)GetProcAddress(hcon, "??0_Condition_variable@details@Concurrency@@QAA@XZ");
_Condition_variable_dtor = (void*)GetProcAddress(hcon, "??1_Condition_variable@details@Concurrency@@QAA@XZ");
_Condition_variable_wait = (void*)GetProcAddress(hcon,
"?wait@_Condition_variable@details@Concurrency@@QAAXAAVcritical_section@3@@Z");
_Condition_variable_wait_for = (void*)GetProcAddress(hcon,
"?wait_for@_Condition_variable@details@Concurrency@@QAA_NAAVcritical_section@3@I@Z");
_Condition_variable_notify_one = (void*)GetProcAddress(hcon,
"?notify_one@_Condition_variable@details@Concurrency@@QAAXXZ");
_Condition_variable_notify_all = (void*)GetProcAddress(hcon,
"?notify_all@_Condition_variable@details@Concurrency@@QAAXXZ");
#else
critical_section_ctor = (void*)GetProcAddress(hcon, "??0critical_section@Concurrency@@QAE@XZ");
critical_section_dtor = (void*)GetProcAddress(hcon, "??1critical_section@Concurrency@@QAE@XZ");
critical_section_lock = (void*)GetProcAddress(hcon, "?lock@critical_section@Concurrency@@QAEXXZ");
critical_section_unlock = (void*)GetProcAddress(hcon, "?unlock@critical_section@Concurrency@@QAEXXZ");
critical_section_trylock = (void*)GetProcAddress(hcon, "?try_lock@critical_section@Concurrency@@QAE_NXZ");
_Condition_variable_ctor = (void*)GetProcAddress(hcon, "??0_Condition_variable@details@Concurrency@@QAE@XZ");
_Condition_variable_dtor = (void*)GetProcAddress(hcon, "??1_Condition_variable@details@Concurrency@@QAE@XZ");
_Condition_variable_wait = (void*)GetProcAddress(hcon,
"?wait@_Condition_variable@details@Concurrency@@QAEXAAVcritical_section@3@@Z");
_Condition_variable_wait_for = (void*)GetProcAddress(hcon,
"?wait_for@_Condition_variable@details@Concurrency@@QAE_NAAVcritical_section@3@I@Z");
_Condition_variable_notify_one = (void*)GetProcAddress(hcon,
"?notify_one@_Condition_variable@details@Concurrency@@QAEXXZ");
_Condition_variable_notify_all = (void*)GetProcAddress(hcon,
"?notify_all@_Condition_variable@details@Concurrency@@QAEXXZ");
#endif
}
#endif /* _MSVCP_VER >= 110 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment