diff --git a/dlls/qmgr/job.c b/dlls/qmgr/job.c index 6bc63f45947..2fbf1bc2a06 100644 --- a/dlls/qmgr/job.c +++ b/dlls/qmgr/job.c @@ -139,6 +139,7 @@ static HRESULT WINAPI BITS_IBackgroundCopyJob_Resume( && This->state != BG_JOB_STATE_TRANSFERRING) { This->state = BG_JOB_STATE_QUEUED; + SetEvent(globalMgr.jobEvent); } LeaveCriticalSection(&globalMgr.cs); diff --git a/dlls/qmgr/qmgr.c b/dlls/qmgr/qmgr.c index b0a6013ed30..608e01a3e2d 100644 --- a/dlls/qmgr/qmgr.c +++ b/dlls/qmgr/qmgr.c @@ -130,6 +130,7 @@ static const IBackgroundCopyManagerVtbl BITS_IBackgroundCopyManager_Vtbl = BackgroundCopyManagerImpl globalMgr = { &BITS_IBackgroundCopyManager_Vtbl, { NULL, -1, 0, 0, 0, 0 }, + NULL, LIST_INIT(globalMgr.jobs) }; @@ -140,3 +141,59 @@ HRESULT BackgroundCopyManagerConstructor(IUnknown *pUnkOuter, LPVOID *ppObj) *ppObj = (IBackgroundCopyManager *) &globalMgr; return S_OK; } + +DWORD WINAPI fileTransfer(void *param) +{ + BackgroundCopyManagerImpl *qmgr = &globalMgr; + HANDLE events[2]; + + events[0] = stop_event; + events[1] = qmgr->jobEvent; + + for (;;) + { + BackgroundCopyJobImpl *job, *jobCur; + BOOL haveJob = FALSE; + + /* Check if it's the stop_event */ + if (WaitForMultipleObjects(2, events, FALSE, INFINITE) == WAIT_OBJECT_0) + return 0; + + /* Note that other threads may add files to the job list, but only + this thread ever deletes them so we don't need to worry about jobs + magically disappearing from the list. */ + EnterCriticalSection(&qmgr->cs); + + LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr) + { + if (job->state == BG_JOB_STATE_ACKNOWLEDGED || job->state == BG_JOB_STATE_CANCELLED) + { + list_remove(&job->entryFromQmgr); + IBackgroundCopyJob_Release((IBackgroundCopyJob *) job); + } + else if (job->state == BG_JOB_STATE_QUEUED) + { + haveJob = TRUE; + break; + } + else if (job->state == BG_JOB_STATE_CONNECTING + || job->state == BG_JOB_STATE_TRANSFERRING) + { + ERR("Invalid state for job %p: %d\n", job, job->state); + } + } + + if (!haveJob) + ResetEvent(qmgr->jobEvent); + + LeaveCriticalSection(&qmgr->cs); + + if (haveJob) + { + FIXME("Actually process job %p; setting error state\n", job); + EnterCriticalSection(&qmgr->cs); + job->state = BG_JOB_STATE_ERROR; + LeaveCriticalSection(&qmgr->cs); + } + } +} diff --git a/dlls/qmgr/qmgr.h b/dlls/qmgr/qmgr.h index a58469405e9..fce84d942dd 100644 --- a/dlls/qmgr/qmgr.h +++ b/dlls/qmgr/qmgr.h @@ -81,8 +81,9 @@ typedef struct typedef struct { const IBackgroundCopyManagerVtbl *lpVtbl; - /* Protects job list and job states */ + /* Protects job list, job states, and jobEvent */ CRITICAL_SECTION cs; + HANDLE jobEvent; struct list jobs; } BackgroundCopyManagerImpl; @@ -91,6 +92,7 @@ typedef struct const IClassFactoryVtbl *lpVtbl; } ClassFactoryImpl; +extern HANDLE stop_event; extern ClassFactoryImpl BITS_ClassFactory; extern BackgroundCopyManagerImpl globalMgr; @@ -104,6 +106,7 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner, LPVOID *ppObj); HRESULT EnumBackgroundCopyFilesConstructor(LPVOID *ppObj, IBackgroundCopyJob* copyJob); +DWORD WINAPI fileTransfer(void *param); /* Little helper functions */ static inline char * diff --git a/dlls/qmgr/service.c b/dlls/qmgr/service.c index 5e31b8fde8f..50d515696a4 100644 --- a/dlls/qmgr/service.c +++ b/dlls/qmgr/service.c @@ -28,10 +28,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(qmgr); +HANDLE stop_event = NULL; + static WCHAR qmgr_nameW[] = {'B','I','T','S',0}; static SERVICE_STATUS_HANDLE status_handle; static SERVICE_STATUS status; -static HANDLE stop_event = NULL; static VOID UpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) @@ -108,6 +109,8 @@ StartCount(void) VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv) { + HANDLE fileTxThread; + DWORD threadId; TRACE("\n"); stop_event = CreateEventW(NULL, TRUE, FALSE, NULL); @@ -129,9 +132,24 @@ ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv) return; } + globalMgr.jobEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + if (!globalMgr.jobEvent) { + ERR("Couldn't create event: error %d\n", GetLastError()); + UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); + return; + } + + fileTxThread = CreateThread(NULL, 0, fileTransfer, NULL, 0, &threadId); + if (!fileTxThread) + { + ERR("Failed starting file transfer thread\n"); + UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); + return; + } + UpdateStatus(SERVICE_RUNNING, NO_ERROR, 0); - WaitForSingleObject(stop_event, INFINITE); + WaitForSingleObject(fileTxThread, INFINITE); UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); CloseHandle(stop_event); TRACE("service stoped\n");