[PATCH v3 2/4] server: Add server requests for managing the system execution state.

Chip Davis cdavis at codeweavers.com
Sun Sep 1 22:43:11 CDT 2019


Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---

Notes:
    v3: Split this back out again.

 include/winnt.h     |   1 +
 server/Makefile.in  |   1 +
 server/power.c      | 263 ++++++++++++++++++++++++++++++++++++++++++++
 server/protocol.def |  32 ++++++
 server/thread.c     |   2 +
 server/thread.h     |   2 +
 6 files changed, 301 insertions(+)
 create mode 100644 server/power.c

diff --git a/include/winnt.h b/include/winnt.h
index 9c4174f310d6..f3847c5f073c 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -906,6 +906,7 @@ typedef enum _HEAP_INFORMATION_CLASS {
 #define ES_SYSTEM_REQUIRED    0x00000001
 #define ES_DISPLAY_REQUIRED   0x00000002
 #define ES_USER_PRESENT       0x00000004
+#define ES_AWAYMODE_REQUIRED  0x00000040
 #define ES_CONTINUOUS         0x80000000
 
 #include <excpt.h>
diff --git a/server/Makefile.in b/server/Makefile.in
index b39bd30305b5..e619d8223fb5 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -27,6 +27,7 @@ C_SRCS = \
 	procfs.c \
 	ptrace.c \
 	queue.c \
+	power.c \
 	region.c \
 	registry.c \
 	request.c \
diff --git a/server/power.c b/server/power.c
new file mode 100644
index 000000000000..5a8a576b2241
--- /dev/null
+++ b/server/power.c
@@ -0,0 +1,263 @@
+/*
+ * Power management support
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ * Copyright (C) 2003 Mike McCormack
+ * Copyright (C) 2005 Robert Shearman
+ * Copyright (C) 2019 Chip Davis for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+
+#include "handle.h"
+#include "request.h"
+#include "thread.h"
+#include "unicode.h"
+
+static unsigned int sys_count = 0;  /* number of holds on system sleep */
+static unsigned int disp_count = 0; /* number of holds on display sleep */
+static unsigned int away_count = 0; /* number of away mode requests */
+
+struct power_request
+{
+    struct object      obj;         /* object header */
+    struct unicode_str reason;      /* stated reason for the request */
+    unsigned           sys  : 1;    /* hold system sleep? */
+    unsigned           disp : 1;    /* hold display sleep? */
+    unsigned           away : 1;    /* request away mode? */
+};
+
+static void power_request_dump( struct object *obj, int verbose );
+static struct object_type *power_request_get_type( struct object *obj );
+static void power_request_destroy( struct object *obj );
+
+static const struct object_ops power_request_ops =
+{
+    sizeof(struct power_request),   /* size */
+    power_request_dump,             /* dump */
+    power_request_get_type,         /* get_type */
+    no_add_queue,                   /* add_queue */
+    NULL,                           /* remove_queue */
+    NULL,                           /* signaled */
+    NULL,                           /* satisfied */
+    no_signal,                      /* signal */
+    no_get_fd,                      /* get_fd */
+    no_map_access,                  /* map_access */
+    default_get_sd,                 /* get_sd */
+    default_set_sd,                 /* set_sd */
+    no_lookup_name,                 /* lookup_name */
+    no_link_name,                   /* link_name */
+    NULL,                           /* unlink_name */
+    no_open_file,                   /* open_file */
+    no_kernel_obj_list,             /* get_kernel_obj_list */
+    no_close_handle,                /* close_handle */
+    power_request_destroy           /* destroy */
+};
+
+static void power_request_dump( struct object *obj, int verbose )
+{
+    struct power_request *power_req = (struct power_request *)obj;
+    assert( obj->ops == &power_request_ops );
+    fprintf( stderr, "PowerRequest reason=" );
+    dump_strW( power_req->reason.str, power_req->reason.len, stderr, "\"\"" );
+    fprintf( stderr, " hold system=%s hold display=%s away mode=%s\n", power_req->sys ? "TRUE" : "FALSE",
+             power_req->disp ? "TRUE" : "FALSE", power_req->away ? "TRUE" : "FALSE" );
+}
+
+static struct object_type *power_request_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'P', 'o', 'w', 'e', 'r', 'R', 'e', 'q', 'u', 'e', 's', 't'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
+static void set_power_request( struct power_request *power_req, POWER_REQUEST_TYPE type )
+{
+    switch (type)
+    {
+    case PowerRequestDisplayRequired:
+        if (!power_req->disp)
+            ++disp_count;
+        power_req->disp = TRUE;
+        break;
+    case PowerRequestSystemRequired:
+        if (!power_req->sys)
+            ++sys_count;
+        power_req->sys = TRUE;
+        break;
+    case PowerRequestAwayModeRequired:
+        if (!power_req->away)
+            ++away_count;
+        power_req->away = TRUE;
+        break;
+    }
+}
+
+static void clear_power_request( struct power_request *power_req, POWER_REQUEST_TYPE type )
+{
+    switch (type)
+    {
+    case PowerRequestDisplayRequired:
+        if (power_req->disp)
+            --disp_count;
+        power_req->disp = FALSE;
+        break;
+    case PowerRequestSystemRequired:
+        if (power_req->sys)
+            --sys_count;
+        power_req->sys = FALSE;
+        break;
+    case PowerRequestAwayModeRequired:
+        if (power_req->away)
+            --away_count;
+        power_req->away = FALSE;
+        break;
+    }
+}
+
+static void power_request_destroy( struct object *obj )
+{
+    struct power_request *power_req;
+
+    assert( obj->ops == &power_request_ops );
+    power_req = (struct power_request *)obj;
+
+    clear_power_request( power_req, PowerRequestDisplayRequired );
+    clear_power_request( power_req, PowerRequestSystemRequired );
+    clear_power_request( power_req, PowerRequestAwayModeRequired );
+
+    free( (void *)power_req->reason.str );
+}
+
+/* creates a new power request */
+static struct power_request *create_power_request( struct unicode_str *reason )
+{
+    struct power_request *power_req = alloc_object( &power_request_ops );
+    if (power_req)
+    {
+        power_req->reason.str = memdup(reason->str, reason->len * sizeof(WCHAR));
+        power_req->reason.len = reason->len;
+        power_req->sys = 0;
+        power_req->disp = 0;
+        power_req->away = 0;
+    }
+    return power_req;
+}
+
+static struct power_request *get_power_request_obj( struct process *process, obj_handle_t handle )
+{
+    return (struct power_request *)get_handle_obj( process, handle, 0, &power_request_ops );
+}
+
+void release_thread_execution_state( struct thread *thread )
+{
+    if (thread->exec_state & ES_SYSTEM_REQUIRED)
+        --sys_count;
+    if (thread->exec_state & ES_DISPLAY_REQUIRED)
+        --disp_count;
+    if (thread->exec_state & ES_AWAYMODE_REQUIRED)
+        --away_count;
+}
+
+
+/* Get the current system execution state */
+DECL_HANDLER(get_system_execution_state)
+{
+    reply->exec_state = 0;
+    if (sys_count != 0)
+        reply->exec_state |= ES_SYSTEM_REQUIRED;
+    if (disp_count != 0)
+        reply->exec_state |= ES_DISPLAY_REQUIRED;
+    if (away_count != 0)
+        reply->exec_state |= ES_AWAYMODE_REQUIRED;
+}
+
+/* Set the current thread's execution state */
+DECL_HANDLER(set_thread_execution_state)
+{
+    reply->old_state = current->exec_state;
+
+    if (!(req->new_state & ES_CONTINUOUS))
+        return;
+
+    if ((current->exec_state & ES_SYSTEM_REQUIRED) && !(req->new_state & ES_SYSTEM_REQUIRED))
+        --sys_count;
+    else if (!(current->exec_state & ES_SYSTEM_REQUIRED) && (req->new_state & ES_SYSTEM_REQUIRED))
+        ++sys_count;
+
+    if ((current->exec_state & ES_DISPLAY_REQUIRED) && !(req->new_state & ES_DISPLAY_REQUIRED))
+        --disp_count;
+    else if (!(current->exec_state & ES_DISPLAY_REQUIRED) && (req->new_state & ES_DISPLAY_REQUIRED))
+        ++disp_count;
+
+    if ((current->exec_state & ES_AWAYMODE_REQUIRED) && !(req->new_state & ES_AWAYMODE_REQUIRED))
+        --away_count;
+    else if (!(current->exec_state & ES_AWAYMODE_REQUIRED) && (req->new_state & ES_AWAYMODE_REQUIRED))
+        ++away_count;
+    current->exec_state = req->new_state;
+}
+
+/* Create a power request object */
+DECL_HANDLER(create_power_request)
+{
+    struct unicode_str reason = get_req_unicode_str();
+
+    struct power_request *power_req = create_power_request( &reason );
+
+    if (power_req)
+    {
+        reply->handle = alloc_handle_no_access_check( current->process, power_req, 0, 0 );
+        release_object( power_req );
+    }
+    else
+    {
+        set_error( STATUS_NO_MEMORY );
+    }
+}
+
+/* Enable a request on a power request object */
+DECL_HANDLER(set_power_request)
+{
+    struct power_request *power_req = get_power_request_obj( current->process, req->handle );
+
+    if (power_req)
+    {
+        set_power_request( power_req, req->request );
+        release_object( power_req );
+    }
+}
+
+/* Disable a request on a power request object */
+DECL_HANDLER(clear_power_request)
+{
+    struct power_request *power_req = get_power_request_obj( current->process, req->handle );
+
+    if (power_req)
+    {
+        clear_power_request( power_req, req->request );
+        release_object( power_req );
+    }
+}
diff --git a/server/protocol.def b/server/protocol.def
index 6af0ae0cff89..191a8a810c58 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3944,3 +3944,35 @@ struct handle_info
 @REQ(resume_process)
     obj_handle_t handle;       /* process handle */
 @END
+
+/* Get the current system execution state */
+ at REQ(get_system_execution_state)
+ at REPLY
+    unsigned int exec_state;    /* current execution state */
+ at END
+
+/* Set the current thread's execution state */
+ at REQ(set_thread_execution_state)
+    unsigned int new_state;     /* thread's new execution state */
+ at REPLY
+    unsigned int old_state;     /* thread's old execution state */
+ at END
+
+/* Create a power request object */
+ at REQ(create_power_request)
+    VARARG(reason,unicode_str); /* reason for the request */
+ at REPLY
+    obj_handle_t handle;        /* power request handle */
+ at END
+
+/* Enable a request on a power request object */
+ at REQ(set_power_request)
+    obj_handle_t handle;        /* power request handle */
+    unsigned int request;       /* the request to enable */
+ at END
+
+/* Disable a request on a power request object */
+ at REQ(clear_power_request)
+    obj_handle_t handle;        /* power request handle */
+    unsigned int request;       /* the request to disable */
+ at END
diff --git a/server/thread.c b/server/thread.c
index dc327603daa4..d34d23aec6ab 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -205,6 +205,7 @@ static inline void init_thread_structure( struct thread *thread )
     thread->reply_fd        = NULL;
     thread->wait_fd         = NULL;
     thread->state           = RUNNING;
+    thread->exec_state      = ES_CONTINUOUS;
     thread->exit_code       = 0;
     thread->priority        = 0;
     thread->suspend         = 0;
@@ -1223,6 +1224,7 @@ void kill_thread( struct thread *thread, int violent_death )
     wake_up( &thread->obj, 0 );
     if (violent_death) send_thread_signal( thread, SIGQUIT );
     cleanup_thread( thread );
+    release_thread_execution_state( thread );
     remove_process_thread( thread->process, thread );
     release_object( thread );
 }
diff --git a/server/thread.h b/server/thread.h
index 9f7914803dec..8e29f9eda33e 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -72,6 +72,7 @@ struct thread
     struct fd             *reply_fd;      /* fd to send a reply to a client */
     struct fd             *wait_fd;       /* fd to use to wake a sleeping client */
     enum run_state         state;         /* running state */
+    unsigned int           exec_state;    /* power execution state */
     int                    exit_code;     /* thread exit code */
     int                    unix_pid;      /* Unix pid of client */
     int                    unix_tid;      /* Unix tid of client */
@@ -130,6 +131,7 @@ extern int is_cpu_supported( enum cpu_type cpu );
 extern unsigned int get_supported_cpu_mask(void);
 extern int suspend_thread( struct thread *thread );
 extern int resume_thread( struct thread *thread );
+extern void release_thread_execution_state( struct thread *thread );
 
 /* ptrace functions */
 
-- 
2.21.0




More information about the wine-devel mailing list