From: Billy Laws blaws05@gmail.com
--- dlls/ntdll/tests/thread.c | 2 +- dlls/ntdll/unix/thread.c | 3 ++- server/process.c | 8 ++++---- server/thread.c | 21 ++++++++++++++------- server/thread.h | 1 + 5 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/tests/thread.c b/dlls/ntdll/tests/thread.c index 0a8facc45ed..30b24007c7a 100644 --- a/dlls/ntdll/tests/thread.c +++ b/dlls/ntdll/tests/thread.c @@ -267,7 +267,7 @@ static void test_thread_bypass_process_freeze(void)
status = pNtCreateThreadEx( &thread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), test_thread_bypass_process_freeze_proc, NULL, THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE, 0, 0, 0, NULL ); - todo_wine ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status ); + ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status );
WaitForSingleObject( thread, INFINITE ); CloseHandle( thread ); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index ce6683e075f..02d96c1a6fc 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1315,7 +1315,8 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT ULONG flags, ULONG_PTR zero_bits, SIZE_T stack_commit, SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list ) { - static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER; + static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER | + THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE; sigset_t sigset; pthread_t pthread_id; pthread_attr_t pthread_attr; diff --git a/server/process.c b/server/process.c index 9b3b0b8fc6c..fc4850b36f9 100644 --- a/server/process.c +++ b/server/process.c @@ -1053,7 +1053,7 @@ void suspend_process( struct process *process ) LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list ) { struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry ); - if (!thread->suspend) stop_thread( thread ); + if (!thread->bypass_proc_suspend && !thread->suspend) stop_thread( thread ); } } } @@ -1069,7 +1069,7 @@ void resume_process( struct process *process ) LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list ) { struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry ); - if (!thread->suspend) wake_thread( thread ); + if (!thread->bypass_proc_suspend && !thread->suspend) wake_thread( thread ); } } } @@ -2005,7 +2005,7 @@ DECL_HANDLER(suspend_process) LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list ) { struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry ); - suspend_thread( thread ); + if (!thread->bypass_proc_suspend) suspend_thread( thread ); }
release_object( process ); @@ -2024,7 +2024,7 @@ DECL_HANDLER(resume_process) LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list ) { struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry ); - resume_thread( thread ); + if (!thread->bypass_proc_suspend) resume_thread( thread ); }
release_object( process ); diff --git a/server/thread.c b/server/thread.c index 05ec6a4ec00..46b126c0a5b 100644 --- a/server/thread.c +++ b/server/thread.c @@ -418,6 +418,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->base_priority = 0; thread->suspend = 0; thread->dbg_hidden = 0; + thread->bypass_proc_suspend = 0; thread->desktop_users = 0; thread->token = NULL; thread->desc = NULL; @@ -436,6 +437,11 @@ static inline void init_thread_structure( struct thread *thread ) thread->inflight[i].server = thread->inflight[i].client = -1; }
+static int get_effective_proc_suspend( struct thread *thread ) +{ + return thread->bypass_proc_suspend ? 0 : thread->process->suspend; +} + /* check if address looks valid for a client-side data structure (TEB etc.) */ static inline int is_valid_address( client_ptr_t addr ) { @@ -927,7 +933,7 @@ int suspend_thread( struct thread *thread ) int old_count = thread->suspend; if (thread->suspend < MAXIMUM_SUSPEND_COUNT) { - if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread ); + if (!(get_effective_proc_suspend( thread ) + thread->suspend++)) stop_thread( thread ); } else set_error( STATUS_SUSPEND_COUNT_EXCEEDED ); return old_count; @@ -940,7 +946,7 @@ int resume_thread( struct thread *thread ) if (thread->suspend > 0) { if (!(--thread->suspend)) resume_delayed_debug_events( thread ); - if (!(thread->suspend + thread->process->suspend)) wake_thread( thread ); + if (!(thread->suspend + get_effective_proc_suspend( thread ))) wake_thread( thread ); } return old_count; } @@ -1121,7 +1127,7 @@ static int check_wait( struct thread *thread ) return STATUS_KERNEL_APC;
/* Suspended threads may not acquire locks, but they can run system APCs */ - if (thread->process->suspend + thread->suspend > 0) return -1; + if (get_effective_proc_suspend( thread ) + thread->suspend > 0) return -1;
if (wait->select == SELECT_WAIT_ALL) { @@ -1208,7 +1214,7 @@ int wake_thread_queue_entry( struct wait_queue_entry *entry ) client_ptr_t cookie;
if (thread->wait != wait) return 0; /* not the current wait */ - if (thread->process->suspend + thread->suspend > 0) return 0; /* cannot acquire locks */ + if (get_effective_proc_suspend( thread ) + thread->suspend > 0) return 0; /* cannot acquire locks */
assert( wait->select != SELECT_WAIT_ALL );
@@ -1231,7 +1237,7 @@ static void thread_timeout( void *ptr )
wait->user = NULL; if (thread->wait != wait) return; /* not the top-level wait, ignore it */ - if (thread->suspend + thread->process->suspend > 0) return; /* suspended, ignore it */ + if (thread->suspend + get_effective_proc_suspend( thread ) > 0) return; /* suspended, ignore it */
if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=TIMEOUT\n", thread->id ); end_wait( thread, STATUS_TIMEOUT ); @@ -1369,7 +1375,7 @@ static inline struct list *get_apc_queue( struct thread *thread, enum apc_type t /* check if thread is currently waiting for a (system) apc */ static inline int is_in_apc_wait( struct thread *thread ) { - return (thread->process->suspend || thread->suspend || + return (get_effective_proc_suspend( thread ) || thread->suspend || (thread->wait && (thread->wait->flags & SELECT_INTERRUPTIBLE))); }
@@ -1646,6 +1652,7 @@ DECL_HANDLER(new_thread) thread->system_regs = current->system_regs; if (req->flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED) thread->suspend++; thread->dbg_hidden = !!(req->flags & THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER); + thread->bypass_proc_suspend = !!(req->flags & THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE); reply->tid = get_thread_id( thread ); if ((reply->handle = alloc_handle_no_access_check( current->process, thread, req->access, objattr->attributes ))) @@ -1739,7 +1746,7 @@ DECL_HANDLER(init_thread) set_thread_base_priority( current, current->base_priority ); set_thread_affinity( current, current->affinity );
- reply->suspend = (current->suspend || current->process->suspend || current->context != NULL); + reply->suspend = (current->suspend || get_effective_proc_suspend( current ) || current->context != NULL); }
/* terminate a thread */ diff --git a/server/thread.h b/server/thread.h index 58081be7481..2a144c2b248 100644 --- a/server/thread.h +++ b/server/thread.h @@ -86,6 +86,7 @@ struct thread int base_priority; /* base priority level (relative to process base priority class) */ int suspend; /* suspend count */ int dbg_hidden; /* hidden from debugger */ + int bypass_proc_suspend; /* will still run if the process is suspended */ obj_handle_t desktop; /* desktop handle */ int desktop_users; /* number of objects using the thread desktop */ timeout_t creation_time; /* Thread creation time */