mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
msvcr100: Implement _StructuredTaskCollection::_Schedule and _Schedule_loc.
Signed-off-by: Torge Matthies <tmatthies@codeweavers.com>
This commit is contained in:
parent
e704c44542
commit
581a35d1bf
1 changed files with 183 additions and 7 deletions
|
@ -24,6 +24,8 @@
|
|||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/list.h"
|
||||
#include "msvcrt.h"
|
||||
#include "cxx.h"
|
||||
|
||||
|
@ -135,6 +137,7 @@ typedef struct {
|
|||
int shutdown_size;
|
||||
HANDLE *shutdown_events;
|
||||
CRITICAL_SECTION cs;
|
||||
struct list scheduled_chores;
|
||||
} ThreadScheduler;
|
||||
extern const vtable_ptr ThreadScheduler_vtable;
|
||||
|
||||
|
@ -164,15 +167,32 @@ typedef struct
|
|||
yield_func yield_func;
|
||||
} SpinWait;
|
||||
|
||||
#define FINISHED_INITIAL 0x80000000
|
||||
typedef struct
|
||||
{
|
||||
char dummy;
|
||||
void *unk1;
|
||||
unsigned int unk2;
|
||||
void *unk3;
|
||||
Context *context;
|
||||
volatile LONG count;
|
||||
volatile LONG finished;
|
||||
void *exception;
|
||||
void *event;
|
||||
} _StructuredTaskCollection;
|
||||
|
||||
typedef struct _UnrealizedChore
|
||||
{
|
||||
const vtable_ptr *vtable;
|
||||
void (__cdecl *chore_proc)(struct _UnrealizedChore*);
|
||||
_StructuredTaskCollection *task_collection;
|
||||
void (__cdecl *chore_wrapper)(struct _UnrealizedChore*);
|
||||
void *unk[6];
|
||||
} _UnrealizedChore;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char dummy;
|
||||
} _StructuredTaskCollection;
|
||||
struct scheduled_chore {
|
||||
struct list entry;
|
||||
_UnrealizedChore *chore;
|
||||
};
|
||||
|
||||
/* keep in sync with msvcp90/msvcp90.h */
|
||||
typedef struct cs_queue
|
||||
|
@ -629,6 +649,7 @@ DEFINE_RTTI_DATA1(scheduler_resource_allocation_error, 0, &cexception_rtti_base_
|
|||
DEFINE_CXX_DATA1(improper_lock, &cexception_cxx_type_info, cexception_dtor)
|
||||
DEFINE_CXX_DATA1(improper_scheduler_attach, &cexception_cxx_type_info, cexception_dtor)
|
||||
DEFINE_CXX_DATA1(improper_scheduler_detach, &cexception_cxx_type_info, cexception_dtor)
|
||||
DEFINE_CXX_DATA1(invalid_multiple_scheduling, &cexception_cxx_type_info, cexception_dtor)
|
||||
DEFINE_CXX_DATA1(invalid_scheduler_policy_key, &cexception_cxx_type_info, cexception_dtor)
|
||||
DEFINE_CXX_DATA1(invalid_scheduler_policy_thread_specification, &cexception_cxx_type_info, cexception_dtor)
|
||||
DEFINE_CXX_DATA1(invalid_scheduler_policy_value, &cexception_cxx_type_info, cexception_dtor)
|
||||
|
@ -839,6 +860,25 @@ bool __thiscall ExternalContextBase_IsSynchronouslyBlocked(const ExternalContext
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static void remove_scheduled_chores(Scheduler *scheduler, const ExternalContextBase *context)
|
||||
{
|
||||
ThreadScheduler *tscheduler = (ThreadScheduler*)scheduler;
|
||||
struct scheduled_chore *sc, *next;
|
||||
|
||||
if (tscheduler->scheduler.vtable != &ThreadScheduler_vtable)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&tscheduler->cs);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(sc, next, &tscheduler->scheduled_chores,
|
||||
struct scheduled_chore, entry) {
|
||||
if (sc->chore->task_collection->context == &context->context) {
|
||||
list_remove(&sc->entry);
|
||||
operator_delete(sc);
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&tscheduler->cs);
|
||||
}
|
||||
|
||||
static void ExternalContextBase_dtor(ExternalContextBase *this)
|
||||
{
|
||||
struct scheduler_list *scheduler_cur, *scheduler_next;
|
||||
|
@ -854,10 +894,12 @@ static void ExternalContextBase_dtor(ExternalContextBase *this)
|
|||
}
|
||||
|
||||
if (this->scheduler.scheduler) {
|
||||
remove_scheduled_chores(this->scheduler.scheduler, this);
|
||||
call_Scheduler_Release(this->scheduler.scheduler);
|
||||
|
||||
for(scheduler_cur=this->scheduler.next; scheduler_cur; scheduler_cur=scheduler_next) {
|
||||
scheduler_next = scheduler_cur->next;
|
||||
remove_scheduled_chores(scheduler_cur->scheduler, this);
|
||||
call_Scheduler_Release(scheduler_cur->scheduler);
|
||||
operator_delete(scheduler_cur);
|
||||
}
|
||||
|
@ -1157,6 +1199,7 @@ void __thiscall SchedulerPolicy_dtor(SchedulerPolicy *this)
|
|||
static void ThreadScheduler_dtor(ThreadScheduler *this)
|
||||
{
|
||||
int i;
|
||||
struct scheduled_chore *sc, *next;
|
||||
|
||||
if(this->ref != 0) WARN("ref = %ld\n", this->ref);
|
||||
SchedulerPolicy_dtor(&this->policy);
|
||||
|
@ -1167,6 +1210,12 @@ static void ThreadScheduler_dtor(ThreadScheduler *this)
|
|||
|
||||
this->cs.DebugInfo->Spare[0] = 0;
|
||||
DeleteCriticalSection(&this->cs);
|
||||
|
||||
if (!list_empty(&this->scheduled_chores))
|
||||
ERR("scheduled chore list is not empty\n");
|
||||
LIST_FOR_EACH_ENTRY_SAFE(sc, next, &this->scheduled_chores,
|
||||
struct scheduled_chore, entry)
|
||||
operator_delete(sc);
|
||||
}
|
||||
|
||||
DEFINE_THISCALL_WRAPPER(ThreadScheduler_Id, 4)
|
||||
|
@ -1375,6 +1424,8 @@ static ThreadScheduler* ThreadScheduler_ctor(ThreadScheduler *this,
|
|||
|
||||
InitializeCriticalSection(&this->cs);
|
||||
this->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ThreadScheduler");
|
||||
|
||||
list_init(&this->scheduled_chores);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1824,6 +1875,114 @@ void __thiscall _StructuredTaskCollection_dtor(_StructuredTaskCollection *this)
|
|||
|
||||
#endif /* _MSVCR_VER >= 120 */
|
||||
|
||||
static ThreadScheduler *get_thread_scheduler_from_context(Context *context)
|
||||
{
|
||||
Scheduler *scheduler = get_scheduler_from_context(context);
|
||||
if (scheduler && scheduler->vtable == &ThreadScheduler_vtable)
|
||||
return (ThreadScheduler*)scheduler;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void CALLBACK chore_wrapper_finally(BOOL normal, void *data)
|
||||
{
|
||||
_UnrealizedChore *chore = data;
|
||||
LONG prev_finished, new_finished;
|
||||
volatile LONG *ptr;
|
||||
|
||||
TRACE("(%u %p)\n", normal, data);
|
||||
|
||||
if (!chore->task_collection)
|
||||
return;
|
||||
ptr = &chore->task_collection->finished;
|
||||
chore->task_collection = NULL;
|
||||
|
||||
do {
|
||||
prev_finished = *ptr;
|
||||
if (prev_finished == FINISHED_INITIAL)
|
||||
new_finished = 1;
|
||||
else
|
||||
new_finished = prev_finished + 1;
|
||||
} while (InterlockedCompareExchange(ptr, new_finished, prev_finished)
|
||||
!= prev_finished);
|
||||
}
|
||||
|
||||
static void __cdecl chore_wrapper(_UnrealizedChore *chore)
|
||||
{
|
||||
TRACE("(%p)\n", chore);
|
||||
|
||||
__TRY
|
||||
{
|
||||
if (chore->chore_proc)
|
||||
chore->chore_proc(chore);
|
||||
}
|
||||
__FINALLY_CTX(chore_wrapper_finally, chore)
|
||||
}
|
||||
|
||||
static void __cdecl _StructuredTaskCollection_scheduler_cb(void *data)
|
||||
{
|
||||
ThreadScheduler *scheduler = (ThreadScheduler*)get_current_scheduler();
|
||||
struct list *entry;
|
||||
struct scheduled_chore *sc;
|
||||
_UnrealizedChore *chore;
|
||||
|
||||
TRACE("(%p)\n", scheduler);
|
||||
|
||||
if (scheduler->scheduler.vtable != &ThreadScheduler_vtable)
|
||||
{
|
||||
ERR("unknown scheduler set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&scheduler->cs);
|
||||
entry = list_head(&scheduler->scheduled_chores);
|
||||
if (entry)
|
||||
list_remove(entry);
|
||||
LeaveCriticalSection(&scheduler->cs);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
sc = LIST_ENTRY(entry, struct scheduled_chore, entry);
|
||||
chore = sc->chore;
|
||||
operator_delete(sc);
|
||||
|
||||
chore->chore_wrapper(chore);
|
||||
}
|
||||
|
||||
static bool schedule_chore(_StructuredTaskCollection *this,
|
||||
_UnrealizedChore *chore, Scheduler **pscheduler)
|
||||
{
|
||||
struct scheduled_chore *sc;
|
||||
ThreadScheduler *scheduler;
|
||||
|
||||
if (chore->task_collection) {
|
||||
invalid_multiple_scheduling e;
|
||||
invalid_multiple_scheduling_ctor_str(&e, "Chore scheduled multiple times");
|
||||
_CxxThrowException(&e, &invalid_multiple_scheduling_exception_type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!this->context)
|
||||
this->context = get_current_context();
|
||||
scheduler = get_thread_scheduler_from_context(this->context);
|
||||
if (!scheduler) {
|
||||
ERR("unknown context or scheduler set\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sc = operator_new(sizeof(*sc));
|
||||
sc->chore = chore;
|
||||
|
||||
chore->task_collection = this;
|
||||
chore->chore_wrapper = chore_wrapper;
|
||||
InterlockedIncrement(&this->count);
|
||||
|
||||
EnterCriticalSection(&scheduler->cs);
|
||||
list_add_head(&scheduler->scheduled_chores, &sc->entry);
|
||||
LeaveCriticalSection(&scheduler->cs);
|
||||
*pscheduler = &scheduler->scheduler;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER >= 110
|
||||
|
||||
/* ?_Schedule@_StructuredTaskCollection@details@Concurrency@@QAAXPAV_UnrealizedChore@23@PAVlocation@3@@Z */
|
||||
|
@ -1834,7 +1993,15 @@ void __thiscall _StructuredTaskCollection__Schedule_loc(
|
|||
_StructuredTaskCollection *this, _UnrealizedChore *chore,
|
||||
/*location*/void *placement)
|
||||
{
|
||||
FIXME("(%p %p %p): stub!\n", this, chore, placement);
|
||||
Scheduler *scheduler;
|
||||
|
||||
TRACE("(%p %p %p)\n", this, chore, placement);
|
||||
|
||||
if (schedule_chore(this, chore, &scheduler))
|
||||
{
|
||||
call_Scheduler_ScheduleTask_loc(scheduler,
|
||||
_StructuredTaskCollection_scheduler_cb, NULL, placement);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER >= 110 */
|
||||
|
@ -1846,7 +2013,15 @@ DEFINE_THISCALL_WRAPPER(_StructuredTaskCollection__Schedule, 8)
|
|||
void __thiscall _StructuredTaskCollection__Schedule(
|
||||
_StructuredTaskCollection *this, _UnrealizedChore *chore)
|
||||
{
|
||||
FIXME("(%p %p): stub!\n", this, chore);
|
||||
Scheduler *scheduler;
|
||||
|
||||
TRACE("(%p %p)\n", this, chore);
|
||||
|
||||
if (schedule_chore(this, chore, &scheduler))
|
||||
{
|
||||
call_Scheduler_ScheduleTask(scheduler,
|
||||
_StructuredTaskCollection_scheduler_cb, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* ?_RunAndWait@_StructuredTaskCollection@details@Concurrency@@QAA?AW4_TaskCollectionStatus@23@PAV_UnrealizedChore@23@@Z */
|
||||
|
@ -3105,6 +3280,7 @@ void msvcrt_init_concurrency(void *base)
|
|||
init_improper_lock_cxx(base);
|
||||
init_improper_scheduler_attach_cxx(base);
|
||||
init_improper_scheduler_detach_cxx(base);
|
||||
init_invalid_multiple_scheduling_cxx(base);
|
||||
init_invalid_scheduler_policy_key_cxx(base);
|
||||
init_invalid_scheduler_policy_thread_specification_cxx(base);
|
||||
init_invalid_scheduler_policy_value_cxx(base);
|
||||
|
|
Loading…
Reference in a new issue