Signed-off-by: Chip Davis cdavis@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 */ +@REQ(get_system_execution_state) +@REPLY + unsigned int exec_state; /* current execution state */ +@END + +/* Set the current thread's execution state */ +@REQ(set_thread_execution_state) + unsigned int new_state; /* thread's new execution state */ +@REPLY + unsigned int old_state; /* thread's old execution state */ +@END + +/* Create a power request object */ +@REQ(create_power_request) + VARARG(reason,unicode_str); /* reason for the request */ +@REPLY + obj_handle_t handle; /* power request handle */ +@END + +/* Enable a request on a power request object */ +@REQ(set_power_request) + obj_handle_t handle; /* power request handle */ + unsigned int request; /* the request to enable */ +@END + +/* Disable a request on a power request object */ +@REQ(clear_power_request) + obj_handle_t handle; /* power request handle */ + unsigned int request; /* the request to disable */ +@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 */