[PATCH 4/4] schedsvc: Add support for executing tasks.

Dmitry Timoshkov dmitry at baikal.ru
Wed May 30 23:21:34 CDT 2018


Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/schedsvc/atsvc.c            | 182 ++++++++++++++++++++++++++++++++++++---
 dlls/schedsvc/schedsvc_private.h |   3 +
 dlls/schedsvc/svc_main.c         |  60 ++++++++++++-
 3 files changed, 230 insertions(+), 15 deletions(-)

diff --git a/dlls/schedsvc/atsvc.c b/dlls/schedsvc/atsvc.c
index 05335de3f3..9497c900a7 100644
--- a/dlls/schedsvc/atsvc.c
+++ b/dlls/schedsvc/atsvc.c
@@ -66,9 +66,19 @@ struct job_t
     USHORT instance_count;
 };
 
+struct running_job_t
+{
+    struct list entry;
+    UUID uuid;
+    HANDLE process;
+    DWORD pid;
+};
+
 static LONG current_jobid = 1;
 
 static struct list at_job_list = LIST_INIT(at_job_list);
+static struct list running_job_list = LIST_INIT(running_job_list);
+
 static CRITICAL_SECTION at_job_list_section;
 static CRITICAL_SECTION_DEBUG cs_debug =
 {
@@ -359,11 +369,6 @@ void add_job(const WCHAR *name)
         return;
     }
 
-    if (job->data.flags & 0x08000000)
-        FIXME("Terminate(%s): not implemented\n", debugstr_w(job->info.Command));
-    else if (job->data.flags & 0x04000000)
-        FIXME("Run(%s): not implemented\n", debugstr_w(job->info.Command));
-
     EnterCriticalSection(&at_job_list_section);
     job->name = heap_strdupW(name);
     job->info.JobId = current_jobid++;
@@ -545,25 +550,180 @@ failed:
     return ret;
 }
 
-static struct job_t *find_job(DWORD jobid, const WCHAR *name)
+static struct job_t *find_job(DWORD jobid, const WCHAR *name, const UUID *id)
 {
     struct job_t *job;
 
     LIST_FOR_EACH_ENTRY(job, &at_job_list, struct job_t, entry)
     {
-        if ((name && !lstrcmpiW(job->name, name)) || job->info.JobId == jobid)
+        if (job->info.JobId == jobid || (name && !lstrcmpiW(job->name, name)) || (id && IsEqualGUID(&job->data.uuid, id)))
             return job;
     }
 
     return NULL;
 }
 
+static void update_job_status(struct job_t *job)
+{
+    HANDLE hfile;
+    DWORD try, size;
+#include "pshpack2.h"
+    struct
+    {
+        UINT exit_code;
+        UINT status;
+        UINT flags;
+        SYSTEMTIME last_runtime;
+        WORD instance_count;
+    } state;
+#include "poppack.h"
+
+    try = 1;
+    for (;;)
+    {
+        hfile = CreateFileW(job->name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+        if (hfile != INVALID_HANDLE_VALUE) break;
+
+        if (try++ >= 3)
+        {
+            ERR("Failed to update %s, error %u\n", debugstr_w(job->name), GetLastError());
+            return;
+        }
+        Sleep(100);
+    }
+
+    if (SetFilePointer(hfile, FIELD_OFFSET(FIXDLEN_DATA, exit_code), NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER)
+    {
+        state.exit_code = job->data.exit_code;
+        state.status = job->data.status;
+        state.flags = job->data.flags;
+        state.last_runtime = job->data.last_runtime;
+        state.instance_count = job->instance_count;
+        WriteFile(hfile, &state, sizeof(state), &size, NULL);
+    }
+
+    CloseHandle(hfile);
+}
+
+void update_process_status(DWORD pid)
+{
+    struct running_job_t *runjob;
+
+    EnterCriticalSection(&at_job_list_section);
+
+    LIST_FOR_EACH_ENTRY(runjob, &running_job_list, struct running_job_t, entry)
+    {
+        if (runjob->pid == pid)
+        {
+            struct job_t *job = find_job(0, NULL, &runjob->uuid);
+            if (job)
+            {
+                DWORD exit_code = STILL_ACTIVE;
+
+                GetExitCodeProcess(runjob->process, &exit_code);
+
+                if (exit_code != STILL_ACTIVE)
+                {
+                    CloseHandle(runjob->process);
+                    list_remove(&runjob->entry);
+                    heap_free(runjob);
+
+                    job->data.exit_code = exit_code;
+                    job->data.status = SCHED_S_TASK_TERMINATED;
+                    job->data.flags &= ~0x0c000000;
+                    job->instance_count = 0;
+                    update_job_status(job);
+                }
+            }
+            break;
+        }
+    }
+
+    LeaveCriticalSection(&at_job_list_section);
+}
+
+void check_task_state(void)
+{
+    struct job_t *job;
+    struct running_job_t *runjob;
+
+    EnterCriticalSection(&at_job_list_section);
+
+    LIST_FOR_EACH_ENTRY(job, &at_job_list, struct job_t, entry)
+    {
+        if (job->data.flags & 0x08000000)
+        {
+            TRACE("terminating process %s\n", debugstr_w(job->info.Command));
+
+            LIST_FOR_EACH_ENTRY(runjob, &running_job_list, struct running_job_t, entry)
+            {
+                if (IsEqualGUID(&job->data.uuid, &runjob->uuid))
+                {
+                    TerminateProcess(runjob->process, 0);
+                    update_process_status(runjob->pid);
+                    break;
+                }
+            }
+        }
+        else if (job->data.flags & 0x04000000)
+        {
+            STARTUPINFOW si;
+            PROCESS_INFORMATION pi;
+
+            TRACE("running process %s\n", debugstr_w(job->info.Command));
+
+            if (job->instance_count)
+                FIXME("process %s is already running\n", debugstr_w(job->info.Command));
+
+            runjob = heap_alloc(sizeof(*runjob));
+            if (runjob)
+            {
+                static WCHAR winsta0[] = { 'W','i','n','S','t','a','0',0 };
+
+                memset(&si, 0, sizeof(si));
+                si.cb = sizeof(si);
+                /* FIXME: if (job->data.flags & TASK_FLAG_INTERACTIVE) */
+                si.lpDesktop = winsta0;
+                si.dwFlags = STARTF_USESHOWWINDOW;
+                si.wShowWindow = SW_SHOWNORMAL;
+                TRACE("executing %s %s at %s\n", debugstr_w(job->info.Command), debugstr_w(job->params), debugstr_w(job->curdir));
+                if (CreateProcessW(job->info.Command, job->params, NULL, NULL, FALSE, 0, NULL, job->curdir, &si, &pi))
+                {
+                    CloseHandle(pi.hThread);
+
+                    GetLocalTime(&job->data.last_runtime);
+                    job->data.exit_code = 0;
+                    job->data.status = SCHED_S_TASK_RUNNING;
+                    job->instance_count = 1;
+
+                    runjob->uuid = job->data.uuid;
+                    runjob->process = pi.hProcess;
+                    runjob->pid = pi.dwProcessId;
+                    list_add_tail(&running_job_list, &runjob->entry);
+                    add_process_to_queue(pi.hProcess);
+                }
+                else
+                {
+                    WARN("failed to execute %s\n", debugstr_w(job->info.Command));
+                    job->data.status = SCHED_S_TASK_HAS_NOT_RUN;
+                    job->instance_count = 0;
+                }
+            }
+
+            job->data.flags &= ~0x0c000000;
+            update_job_status(job);
+        }
+    }
+
+    LeaveCriticalSection(&at_job_list_section);
+}
+
 void remove_job(const WCHAR *name)
 {
     struct job_t *job;
 
     EnterCriticalSection(&at_job_list_section);
-    job = find_job(0, name);
+    job = find_job(0, name, NULL);
     if (job)
     {
         list_remove(&job->entry);
@@ -596,7 +756,7 @@ DWORD __cdecl NetrJobAdd(ATSVC_HANDLE server_name, AT_INFO *info, DWORD *jobid)
             for (i = 0; i < 5; i++)
             {
                 EnterCriticalSection(&at_job_list_section);
-                job = find_job(0, task_name);
+                job = find_job(0, task_name, NULL);
                 LeaveCriticalSection(&at_job_list_section);
 
                 if (job)
@@ -640,7 +800,7 @@ DWORD __cdecl NetrJobDel(ATSVC_HANDLE server_name, DWORD min_jobid, DWORD max_jo
 
     for (jobid = min_jobid; jobid <= max_jobid; jobid++)
     {
-        struct job_t *job = find_job(jobid, NULL);
+        struct job_t *job = find_job(jobid, NULL, NULL);
 
         if (!job)
         {
@@ -735,7 +895,7 @@ DWORD __cdecl NetrJobGetInfo(ATSVC_HANDLE server_name, DWORD jobid, AT_INFO **in
 
     EnterCriticalSection(&at_job_list_section);
 
-    job = find_job(jobid, NULL);
+    job = find_job(jobid, NULL, NULL);
     if (job)
     {
         AT_INFO *info_ret = heap_alloc(sizeof(*info_ret));
diff --git a/dlls/schedsvc/schedsvc_private.h b/dlls/schedsvc/schedsvc_private.h
index 215bba003e..f5cec2a7cb 100644
--- a/dlls/schedsvc/schedsvc_private.h
+++ b/dlls/schedsvc/schedsvc_private.h
@@ -25,6 +25,9 @@
 void schedsvc_auto_start(void) DECLSPEC_HIDDEN;
 void add_job(const WCHAR *name) DECLSPEC_HIDDEN;
 void remove_job(const WCHAR *name) DECLSPEC_HIDDEN;
+void check_task_state(void) DECLSPEC_HIDDEN;
+void add_process_to_queue(HANDLE hproc) DECLSPEC_HIDDEN;
+void update_process_status(DWORD pid) DECLSPEC_HIDDEN;
 
 static inline WCHAR *heap_strdupW(const WCHAR *src)
 {
diff --git a/dlls/schedsvc/svc_main.c b/dlls/schedsvc/svc_main.c
index f021d63b98..9342b50e4b 100644
--- a/dlls/schedsvc/svc_main.c
+++ b/dlls/schedsvc/svc_main.c
@@ -34,13 +34,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(schedsvc);
 
 static const WCHAR scheduleW[] = {'S','c','h','e','d','u','l','e',0};
 static SERVICE_STATUS_HANDLE schedsvc_handle;
-static HANDLE done_event;
+static HANDLE done_event, hjob_queue;
+
+void add_process_to_queue(HANDLE process)
+{
+    if (!AssignProcessToJobObject(hjob_queue, process))
+        ERR("AssignProcessToJobObject failed");
+}
 
 static DWORD WINAPI tasks_monitor_thread(void *arg)
 {
     static const WCHAR tasksW[] = { '\\','T','a','s','k','s','\\',0 };
     WCHAR path[MAX_PATH];
-    HANDLE htasks;
+    HANDLE htasks, hport;
+    JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
     OVERLAPPED ov;
 
     TRACE("Starting...\n");
@@ -59,6 +66,28 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
         return -1;
     }
 
+    hjob_queue = CreateJobObjectW(NULL, NULL);
+    if (!hjob_queue)
+    {
+        ERR("CreateJobObject failed");
+        return -1;
+    }
+
+    hport = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+    if (!hport)
+    {
+        ERR("CreateIoCompletionPort failed");
+        return -1;
+    }
+
+    info.CompletionKey = hjob_queue;
+    info.CompletionPort = hport;
+    if (!SetInformationJobObject(hjob_queue, JobObjectAssociateCompletionPortInformation, &info, sizeof(info)))
+    {
+        ERR("SetInformationJobObject failed");
+        return -1;
+    }
+
     memset(&ov, 0, sizeof(ov));
     ov.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
 
@@ -69,7 +98,7 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
             FILE_NOTIFY_INFORMATION data;
             WCHAR name_buffer[MAX_PATH];
         } info;
-        HANDLE events[2];
+        HANDLE events[3];
         DWORD ret;
 
         /* the buffer must be DWORD aligned */
@@ -87,10 +116,29 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
 
         events[0] = done_event;
         events[1] = ov.hEvent;
+        events[2] = hport;
 
-        ret = WaitForMultipleObjects(2, events, FALSE, INFINITE);
+        ret = WaitForMultipleObjects(3, events, FALSE, INFINITE);
         if (ret == WAIT_OBJECT_0) break;
 
+        if (ret == WAIT_OBJECT_0 + 2)
+        {
+            DWORD msg;
+            ULONG_PTR dummy, pid;
+
+            if (GetQueuedCompletionStatus(hport, &msg, &dummy, (OVERLAPPED **)&pid, 0))
+            {
+                if (msg == JOB_OBJECT_MSG_EXIT_PROCESS)
+                {
+                    TRACE("got message: process %#lx has terminated\n", pid);
+                    update_process_status(pid);
+                }
+                else
+                    FIXME("got message %#x from the job\n", msg);
+            }
+            continue;
+        }
+
         info.data.FileName[info.data.FileNameLength/sizeof(WCHAR)] = 0;
 
         switch (info.data.Action)
@@ -126,9 +174,13 @@ static DWORD WINAPI tasks_monitor_thread(void *arg)
             FIXME("%s: action %#x not handled\n", debugstr_w(info.data.FileName), info.data.Action);
             break;
         }
+
+        check_task_state();
     }
 
     CloseHandle(ov.hEvent);
+    CloseHandle(hport);
+    CloseHandle(hjob_queue);
     CloseHandle(htasks);
 
     TRACE("Finished.\n");
-- 
2.16.3




More information about the wine-devel mailing list