[PATCH v2 2/3] msvcrt: Implement Concurrency::event
Piotr Caban
piotr.caban at gmail.com
Wed Mar 15 07:25:38 CDT 2017
Hi Daniel,
I think it would be better to also avoid the static critical section.
Here are some hints how it can be achieved:
typedef struct
{
struct list *waiters;
INT_PTR signaled;
critical_section cs;
} event;
struct thread_wait;
typedef struct
{
struct thread_wait *wait;
struct list entry;
} thread_wait_entry;
typedef struct thread_wait
{
event *signaled;
int pending_waits;
thread_wait_entry entries[1];
} thread_wait;
(thread_wait structure will need to be accessed in a thread safe way)
With such structures event_set may be implemented in following way (this
describes the idea, it's not a fully correct code):
void __thiscall event_set(event *this)
{
critical_section_lock(&this->cs);
if (this->signaled) unlock and return;
this->signaled = TRUE;
LIST_FOR_EACH_ENTRY(cur, this->waiters) {
if (!InterlockedDecrement(&cur->wait->pending_waits)) {
if (!InterlockedCompareExchangePtr(&cur->wait->signaled,
this, 0))
NtReleaseKeyedEvent(keyed_event, cur->wait, 0, NULL);
}
}
critical_section_unlock(&this->cs);
}
void __thiscall event_reset(event *this)
{
critical_section_lock(&this->cs);
if (!this->signaled) unlock and return;
this->signaled = FALSE;
LIST_FOR_EACH_ENTRY(cur, this->waiters)
InterlockedIncrement(&cur->wait->pending_waits);
critical_section_unlock(&this->cs);
}
int __cdecl wait_for_multiple(event **events, MSVCRT_size_t count,
MSVCRT_bool wait_all, unsigned int timeout)
{
wait = allocate thread_wait struct;
initialize wait struct;
(wait->pending_waits = wait_all ? count : 1)
for(int i=0; i<count; i++) {
critical_section_lock(events[i]);
add wait to waiters queue
(decrease wait->pending_waits if necessary)
critical_section_unlock(events[i]);
}
status = NtWaitForKeyedEvent(keyed_event, wait, ...);
if(!status || InterlockedCompareExchangePtr(wait->signaled, 1, 0))
get ret from wait->signaled
else
ret = COOPERATIVE_WAIT_TIMEOUT;
for(int i=0; i<count; i++) {
critical_section_lock(events[i]);
remove wait from waiters queue
critical_section_unlock(events[i]);
}
}
Also I think it would be nice to avoid allocation in case of waiting for
only one handle (or just in event_wait function).
What do you think about it?
Thank you,
Piotr
More information about the wine-devel
mailing list