blob: 1c00ce711061d5b713ed1c7faf4cb7b3efb9a108 [file] [log] [blame]
Alexandre Julliard642d3131998-07-12 19:29:36 +00001/*
2 * Server-side thread management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard642d3131998-07-12 19:29:36 +000019 */
20
Howard Abrams13277481999-07-10 13:16:29 +000021#include "config.h"
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000022#include "wine/port.h"
Howard Abrams13277481999-07-10 13:16:29 +000023
Alexandre Julliard642d3131998-07-12 19:29:36 +000024#include <assert.h>
Alexandre Julliarde5dedb12001-03-08 01:16:41 +000025#include <errno.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000026#include <fcntl.h>
Alexandre Julliard767e6f61998-08-09 12:47:43 +000027#include <signal.h>
Alexandre Julliardea1afce2000-08-22 20:08:37 +000028#include <stdarg.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000029#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000032#include <sys/types.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000033#include <unistd.h>
Ryan Cumming24f4ece2002-11-25 01:33:38 +000034#include <time.h>
Steven Edwards57279182005-03-04 12:38:36 +000035#ifdef HAVE_POLL_H
36#include <poll.h>
37#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +000038
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010039#include "ntstatus.h"
40#define WIN32_NO_STATUS
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000041#include "windef.h"
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010042#include "winternl.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000043
Alexandre Julliard863637b2003-01-30 00:26:44 +000044#include "file.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000045#include "handle.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000046#include "process.h"
47#include "thread.h"
Alexandre Julliard5bc78081999-06-22 17:26:53 +000048#include "request.h"
Alexandre Julliard1a66d222001-08-28 18:44:52 +000049#include "user.h"
Robert Shearman4bba2162005-06-20 13:18:38 +000050#include "security.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000051
52
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000053/* thread queues */
54
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000055struct thread_wait
56{
Alexandre Julliarde5dedb12001-03-08 01:16:41 +000057 struct thread_wait *next; /* next wait structure for this thread */
58 struct thread *thread; /* owner thread */
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000059 int count; /* count of objects */
60 int flags;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +000061 void *cookie; /* magic cookie to return to client */
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000062 struct timeval timeout;
Alexandre Julliard57e11311999-05-16 16:59:38 +000063 struct timeout_user *user;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000064 struct wait_queue_entry queues[1];
65};
66
Alexandre Julliard62a8b431999-01-19 17:48:23 +000067/* asynchronous procedure calls */
68
69struct thread_apc
70{
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +000071 struct list entry; /* queue linked list */
Alexandre Julliardea1afce2000-08-22 20:08:37 +000072 struct object *owner; /* object that queued this apc */
73 void *func; /* function to call in client */
74 enum apc_type type; /* type of apc function */
75 int nb_args; /* number of arguments */
Alexandre Julliard088bcf92003-04-04 22:26:34 +000076 void *arg1; /* function arguments */
77 void *arg2;
78 void *arg3;
Alexandre Julliard62a8b431999-01-19 17:48:23 +000079};
Alexandre Julliard62a8b431999-01-19 17:48:23 +000080
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000081
Alexandre Julliard642d3131998-07-12 19:29:36 +000082/* thread operations */
83
Alexandre Julliard767e6f61998-08-09 12:47:43 +000084static void dump_thread( struct object *obj, int verbose );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000085static int thread_signaled( struct object *obj, struct thread *thread );
Alexandre Julliard46d1b3e2005-12-12 15:03:07 +010086static unsigned int thread_map_access( struct object *obj, unsigned int access );
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +000087static void thread_poll_event( struct fd *fd, int event );
Alexandre Julliard642d3131998-07-12 19:29:36 +000088static void destroy_thread( struct object *obj );
Alexandre Julliard23623802001-01-06 01:48:51 +000089static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only );
Alexandre Julliard642d3131998-07-12 19:29:36 +000090
91static const struct object_ops thread_ops =
92{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000093 sizeof(struct thread), /* size */
94 dump_thread, /* dump */
95 add_queue, /* add_queue */
96 remove_queue, /* remove_queue */
97 thread_signaled, /* signaled */
98 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000099 no_signal, /* signal */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000100 no_get_fd, /* get_fd */
Alexandre Julliard46d1b3e2005-12-12 15:03:07 +0100101 thread_map_access, /* map_access */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000102 no_lookup_name, /* lookup_name */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000103 no_close_handle, /* close_handle */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000104 destroy_thread /* destroy */
105};
106
107static const struct fd_ops thread_fd_ops =
108{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000109 NULL, /* get_poll_events */
110 thread_poll_event, /* poll_event */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000111 no_flush, /* flush */
112 no_get_file_info, /* get_file_info */
Eric Pouech46344472005-01-14 19:54:38 +0000113 no_queue_async, /* queue_async */
114 no_cancel_async /* cancel_async */
Alexandre Julliard642d3131998-07-12 19:29:36 +0000115};
116
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000117static struct list thread_list = LIST_INIT(thread_list);
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000118
Alexandre Julliardf5242402001-02-28 21:45:23 +0000119/* initialize the structure for a newly allocated thread */
120inline static void init_thread_structure( struct thread *thread )
121{
122 int i;
123
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000124 thread->unix_pid = -1; /* not known yet */
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000125 thread->unix_tid = -1; /* not known yet */
Alexandre Julliardf5242402001-02-28 21:45:23 +0000126 thread->context = NULL;
Alexandre Julliard73c72392005-11-02 20:54:12 +0000127 thread->suspend_context = NULL;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000128 thread->teb = NULL;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000129 thread->debug_ctx = NULL;
130 thread->debug_event = NULL;
131 thread->queue = NULL;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000132 thread->wait = NULL;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000133 thread->error = 0;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000134 thread->req_data = NULL;
135 thread->req_toread = 0;
136 thread->reply_data = NULL;
137 thread->reply_towrite = 0;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000138 thread->request_fd = NULL;
139 thread->reply_fd = NULL;
140 thread->wait_fd = NULL;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000141 thread->state = RUNNING;
142 thread->attached = 0;
143 thread->exit_code = 0;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000144 thread->priority = THREAD_PRIORITY_NORMAL;
145 thread->affinity = 1;
146 thread->suspend = 0;
Ryan Cumming24f4ece2002-11-25 01:33:38 +0000147 thread->creation_time = time(NULL);
148 thread->exit_time = 0;
Alexandre Julliard92fec7b2005-06-28 19:37:52 +0000149 thread->desktop_users = 0;
Alexandre Julliardf5242402001-02-28 21:45:23 +0000150
Alexandre Julliard20894e22005-02-25 16:58:43 +0000151 list_init( &thread->mutex_list );
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000152 list_init( &thread->system_apc );
153 list_init( &thread->user_apc );
154
Alexandre Julliardf5242402001-02-28 21:45:23 +0000155 for (i = 0; i < MAX_INFLIGHT_FDS; i++)
156 thread->inflight[i].server = thread->inflight[i].client = -1;
157}
158
Alexandre Julliard0424f382005-07-13 12:12:43 +0000159/* check if address looks valid for a client-side data structure (TEB etc.) */
160static inline int is_valid_address( void *addr )
161{
162 return addr && !((unsigned int)addr % sizeof(int));
163}
164
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000165/* create a new thread */
Alexandre Julliard5b4f3e82000-05-01 16:24:22 +0000166struct thread *create_thread( int fd, struct process *process )
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000167{
168 struct thread *thread;
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000169
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000170 if (!(thread = alloc_object( &thread_ops ))) return NULL;
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000171
Alexandre Julliardf5242402001-02-28 21:45:23 +0000172 init_thread_structure( thread );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000173
Alexandre Julliardf5242402001-02-28 21:45:23 +0000174 thread->process = (struct process *)grab_object( process );
Alexandre Julliard78a3e632005-06-09 12:07:12 +0000175 thread->desktop = process->desktop;
Alexandre Julliard2fe57772000-01-25 01:40:27 +0000176 if (!current) current = thread;
177
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000178 list_add_head( &thread_list, &thread->entry );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000179
Alexandre Julliard91befe12003-02-01 01:38:40 +0000180 if (!(thread->id = alloc_ptid( thread )))
181 {
182 release_object( thread );
183 return NULL;
184 }
Alexandre Julliard580da242003-03-12 22:38:14 +0000185 if (!(thread->request_fd = create_anonymous_fd( &thread_fd_ops, fd, &thread->obj )))
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000186 {
187 release_object( thread );
188 return NULL;
189 }
Alexandre Julliard91befe12003-02-01 01:38:40 +0000190
Mike McCormack36cd6f52003-07-24 00:07:00 +0000191 thread->token = (struct token *) grab_object( process->token );
192
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000193 set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */
Alexandre Julliard8859d772001-03-01 22:13:49 +0000194 add_process_thread( thread->process, thread );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000195 return thread;
196}
197
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000198/* handle a client event */
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +0000199static void thread_poll_event( struct fd *fd, int event )
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000200{
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +0000201 struct thread *thread = get_fd_user( fd );
202 assert( thread->obj.ops == &thread_ops );
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000203
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000204 if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000205 else if (event & POLLIN) read_request( thread );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000206 else if (event & POLLOUT) write_reply( thread );
Alexandre Julliardf5242402001-02-28 21:45:23 +0000207}
208
209/* cleanup everything that is no longer needed by a dead thread */
210/* used by destroy_thread and kill_thread */
211static void cleanup_thread( struct thread *thread )
212{
213 int i;
214 struct thread_apc *apc;
215
216 while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000217 if (thread->req_data) free( thread->req_data );
218 if (thread->reply_data) free( thread->reply_data );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000219 if (thread->request_fd) release_object( thread->request_fd );
220 if (thread->reply_fd) release_object( thread->reply_fd );
221 if (thread->wait_fd) release_object( thread->wait_fd );
Alexandre Julliard73c72392005-11-02 20:54:12 +0000222 if (thread->suspend_context) free( thread->suspend_context );
Alexandre Julliard31022d62002-08-16 23:30:41 +0000223 free_msg_queue( thread );
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000224 cleanup_clipboard_thread(thread);
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000225 destroy_thread_windows( thread );
Alexandre Julliard1bf96e02005-06-08 18:44:50 +0000226 close_thread_desktop( thread );
Alexandre Julliardf5242402001-02-28 21:45:23 +0000227 for (i = 0; i < MAX_INFLIGHT_FDS; i++)
228 {
229 if (thread->inflight[i].client != -1)
230 {
231 close( thread->inflight[i].server );
232 thread->inflight[i].client = thread->inflight[i].server = -1;
233 }
234 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000235 thread->req_data = NULL;
236 thread->reply_data = NULL;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000237 thread->request_fd = NULL;
238 thread->reply_fd = NULL;
239 thread->wait_fd = NULL;
Alexandre Julliard73c72392005-11-02 20:54:12 +0000240 thread->context = NULL;
241 thread->suspend_context = NULL;
Alexandre Julliard1bf96e02005-06-08 18:44:50 +0000242 thread->desktop = 0;
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000243}
244
Alexandre Julliard642d3131998-07-12 19:29:36 +0000245/* destroy a thread when its refcount is 0 */
246static void destroy_thread( struct object *obj )
247{
248 struct thread *thread = (struct thread *)obj;
249 assert( obj->ops == &thread_ops );
250
Alexandre Julliarde712e071999-05-23 19:53:30 +0000251 assert( !thread->debug_ctx ); /* cannot still be debugging something */
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000252 list_remove( &thread->entry );
Alexandre Julliardf5242402001-02-28 21:45:23 +0000253 cleanup_thread( thread );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000254 release_object( thread->process );
Alexandre Julliard91befe12003-02-01 01:38:40 +0000255 if (thread->id) free_ptid( thread->id );
Mike McCormack36cd6f52003-07-24 00:07:00 +0000256 if (thread->token) release_object( thread->token );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000257}
258
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000259/* dump a thread on stdout for debugging purposes */
260static void dump_thread( struct object *obj, int verbose )
261{
262 struct thread *thread = (struct thread *)obj;
263 assert( obj->ops == &thread_ops );
264
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000265 fprintf( stderr, "Thread id=%04x unix pid=%d unix tid=%d teb=%p state=%d\n",
266 thread->id, thread->unix_pid, thread->unix_tid, thread->teb, thread->state );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000267}
268
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000269static int thread_signaled( struct object *obj, struct thread *thread )
270{
271 struct thread *mythread = (struct thread *)obj;
272 return (mythread->state == TERMINATED);
273}
274
Alexandre Julliard46d1b3e2005-12-12 15:03:07 +0100275static unsigned int thread_map_access( struct object *obj, unsigned int access )
276{
277 if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | SYNCHRONIZE;
278 if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | SYNCHRONIZE;
279 if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE;
280 if (access & GENERIC_ALL) access |= THREAD_ALL_ACCESS;
281 return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
282}
283
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000284/* get a thread pointer from a thread id (and increment the refcount) */
Alexandre Julliard54f22872002-10-03 19:54:57 +0000285struct thread *get_thread_from_id( thread_id_t id )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000286{
Alexandre Julliard91befe12003-02-01 01:38:40 +0000287 struct object *obj = get_ptid_entry( id );
288
289 if (obj && obj->ops == &thread_ops) return (struct thread *)grab_object( obj );
Alexandre Julliardf895ad12005-07-29 14:41:14 +0000290 set_error( STATUS_INVALID_CID );
Alexandre Julliard91befe12003-02-01 01:38:40 +0000291 return NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000292}
293
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000294/* get a thread from a handle (and increment the refcount) */
Alexandre Julliard51885742002-05-30 20:12:58 +0000295struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000296{
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000297 return (struct thread *)get_handle_obj( current->process, handle,
298 access, &thread_ops );
299}
300
Alexandre Julliard578c1001999-11-14 21:23:21 +0000301/* find a thread from a Unix pid */
302struct thread *get_thread_from_pid( int pid )
303{
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000304 struct thread *thread;
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000305
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000306 LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
307 {
308 if (thread->unix_tid == pid) return thread;
309 }
310 LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
311 {
312 if (thread->unix_pid == pid) return thread;
313 }
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000314 return NULL;
Alexandre Julliard578c1001999-11-14 21:23:21 +0000315}
316
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000317/* set all information about a thread */
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000318static void set_thread_info( struct thread *thread,
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000319 const struct set_thread_info_request *req )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000320{
321 if (req->mask & SET_THREAD_INFO_PRIORITY)
322 thread->priority = req->priority;
323 if (req->mask & SET_THREAD_INFO_AFFINITY)
324 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000325 if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000326 else thread->affinity = req->affinity;
327 }
Robert Shearman4bba2162005-06-20 13:18:38 +0000328 if (req->mask & SET_THREAD_INFO_TOKEN)
329 security_set_thread_token( thread, req->token );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000330}
331
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000332/* stop a thread (at the Unix level) */
333void stop_thread( struct thread *thread )
334{
Alexandre Julliardff7795e2005-11-01 21:47:07 +0000335 if (thread->context) return; /* already inside a debug event, no need for a signal */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000336 /* can't stop a thread while initialisation is in progress */
337 if (is_process_init_done(thread->process)) send_thread_signal( thread, SIGUSR1 );
338}
339
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000340/* suspend a thread */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000341static int suspend_thread( struct thread *thread )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000342{
343 int old_count = thread->suspend;
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000344 if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000345 {
Alexandre Julliard0a707831999-11-08 05:31:47 +0000346 if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000347 }
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000348 else set_error( STATUS_SUSPEND_COUNT_EXCEEDED );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000349 return old_count;
350}
351
352/* resume a thread */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000353static int resume_thread( struct thread *thread )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000354{
355 int old_count = thread->suspend;
356 if (thread->suspend > 0)
357 {
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000358 if (!(--thread->suspend + thread->process->suspend)) wake_thread( thread );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000359 }
360 return old_count;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000361}
362
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000363/* add a thread to an object wait queue; return 1 if OK, 0 on error */
Alexandre Julliarda8b8d9c1999-01-01 16:59:27 +0000364int add_queue( struct object *obj, struct wait_queue_entry *entry )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000365{
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000366 grab_object( obj );
Alexandre Julliardaa347682005-03-01 11:49:58 +0000367 entry->obj = obj;
368 list_add_tail( &obj->wait_queue, &entry->entry );
Alexandre Julliarda8b8d9c1999-01-01 16:59:27 +0000369 return 1;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000370}
371
372/* remove a thread from an object wait queue */
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000373void remove_queue( struct object *obj, struct wait_queue_entry *entry )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000374{
Alexandre Julliardaa347682005-03-01 11:49:58 +0000375 list_remove( &entry->entry );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000376 release_object( obj );
377}
378
379/* finish waiting */
380static void end_wait( struct thread *thread )
381{
382 struct thread_wait *wait = thread->wait;
383 struct wait_queue_entry *entry;
384 int i;
385
386 assert( wait );
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000387 for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
388 entry->obj->ops->remove_queue( entry->obj, entry );
Alexandre Julliard57e11311999-05-16 16:59:38 +0000389 if (wait->user) remove_timeout_user( wait->user );
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000390 thread->wait = wait->next;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000391 free( wait );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000392}
393
394/* build the thread wait structure */
Alexandre Julliard462172a2003-04-02 22:48:59 +0000395static int wait_on( int count, struct object *objects[], int flags, const abs_time_t *timeout )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000396{
397 struct thread_wait *wait;
398 struct wait_queue_entry *entry;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000399 int i;
400
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000401 if (!(wait = mem_alloc( sizeof(*wait) + (count-1) * sizeof(*entry) ))) return 0;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000402 wait->next = current->wait;
403 wait->thread = current;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000404 wait->count = count;
405 wait->flags = flags;
Alexandre Julliard57e11311999-05-16 16:59:38 +0000406 wait->user = NULL;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000407 current->wait = wait;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000408 if (flags & SELECT_TIMEOUT)
409 {
Alexandre Julliard462172a2003-04-02 22:48:59 +0000410 wait->timeout.tv_sec = timeout->sec;
411 wait->timeout.tv_usec = timeout->usec;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000412 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000413
414 for (i = 0, entry = wait->queues; i < count; i++, entry++)
415 {
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000416 struct object *obj = objects[i];
417 entry->thread = current;
Alexandre Julliarda8b8d9c1999-01-01 16:59:27 +0000418 if (!obj->ops->add_queue( obj, entry ))
419 {
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000420 wait->count = i;
421 end_wait( current );
Alexandre Julliarda8b8d9c1999-01-01 16:59:27 +0000422 return 0;
423 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000424 }
425 return 1;
426}
427
428/* check if the thread waiting condition is satisfied */
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000429static int check_wait( struct thread *thread )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000430{
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000431 int i, signaled;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000432 struct thread_wait *wait = thread->wait;
433 struct wait_queue_entry *entry = wait->queues;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000434
Peter Hunnisetta3c5ad42003-02-28 21:50:47 +0000435 /* Suspended threads may not acquire locks */
Robert Shearman37957092005-06-10 19:54:46 +0000436 if (thread->process->suspend + thread->suspend > 0) return -1;
Peter Hunnisetta3c5ad42003-02-28 21:50:47 +0000437
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000438 assert( wait );
439 if (wait->flags & SELECT_ALL)
440 {
Alexandre Julliard57e11311999-05-16 16:59:38 +0000441 int not_ok = 0;
442 /* Note: we must check them all anyway, as some objects may
443 * want to do something when signaled, even if others are not */
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000444 for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
Alexandre Julliard57e11311999-05-16 16:59:38 +0000445 not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
446 if (not_ok) goto other_checks;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000447 /* Wait satisfied: tell it to all objects */
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000448 signaled = 0;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000449 for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
450 if (entry->obj->ops->satisfied( entry->obj, thread ))
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000451 signaled = STATUS_ABANDONED_WAIT_0;
452 return signaled;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000453 }
454 else
455 {
456 for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
457 {
458 if (!entry->obj->ops->signaled( entry->obj, thread )) continue;
459 /* Wait satisfied: tell it to the object */
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000460 signaled = i;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000461 if (entry->obj->ops->satisfied( entry->obj, thread ))
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000462 signaled = i + STATUS_ABANDONED_WAIT_0;
463 return signaled;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000464 }
465 }
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000466
467 other_checks:
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000468 if ((wait->flags & SELECT_INTERRUPTIBLE) && !list_empty(&thread->system_apc)) return STATUS_USER_APC;
469 if ((wait->flags & SELECT_ALERTABLE) && !list_empty(&thread->user_apc)) return STATUS_USER_APC;
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000470 if (wait->flags & SELECT_TIMEOUT)
471 {
472 struct timeval now;
473 gettimeofday( &now, NULL );
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000474 if (!time_before( &now, &wait->timeout )) return STATUS_TIMEOUT;
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000475 }
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000476 return -1;
477}
478
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000479/* send the wakeup signal to a thread */
480static int send_thread_wakeup( struct thread *thread, void *cookie, int signaled )
481{
482 struct wake_up_reply reply;
483 int ret;
484
485 reply.cookie = cookie;
486 reply.signaled = signaled;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000487 if ((ret = write( get_unix_fd( thread->wait_fd ), &reply, sizeof(reply) )) == sizeof(reply))
488 return 0;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000489 if (ret >= 0)
490 fatal_protocol_error( thread, "partial wakeup write %d\n", ret );
491 else if (errno == EPIPE)
492 kill_thread( thread, 0 ); /* normal death */
493 else
494 fatal_protocol_perror( thread, "write" );
495 return -1;
496}
497
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000498/* attempt to wake up a thread */
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000499/* return >0 if OK, 0 if the wait condition is still not satisfied */
Peter Hunnisetta3c5ad42003-02-28 21:50:47 +0000500int wake_thread( struct thread *thread )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000501{
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000502 int signaled, count;
503 void *cookie;
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000504
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000505 for (count = 0; thread->wait; count++)
506 {
507 if ((signaled = check_wait( thread )) == -1) break;
508
509 cookie = thread->wait->cookie;
Alexandre Julliard91befe12003-02-01 01:38:40 +0000510 if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d cookie=%p\n",
511 thread->id, signaled, cookie );
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000512 end_wait( thread );
Andreas Mohrd66130a2001-08-07 19:31:43 +0000513 if (send_thread_wakeup( thread, cookie, signaled ) == -1) /* error */
514 break;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000515 }
516 return count;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000517}
518
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000519/* thread wait timeout */
520static void thread_timeout( void *ptr )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000521{
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000522 struct thread_wait *wait = ptr;
523 struct thread *thread = wait->thread;
524 void *cookie = wait->cookie;
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000525
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000526 wait->user = NULL;
527 if (thread->wait != wait) return; /* not the top-level wait, ignore it */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000528 if (thread->suspend + thread->process->suspend > 0) return; /* suspended, ignore it */
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000529
Alexandre Julliard91befe12003-02-01 01:38:40 +0000530 if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d cookie=%p\n",
Ge van Geldorp1a1583a2005-11-28 17:32:54 +0100531 thread->id, (int)STATUS_TIMEOUT, cookie );
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000532 end_wait( thread );
Alexandre Julliardff732502002-06-22 01:20:36 +0000533 if (send_thread_wakeup( thread, cookie, STATUS_TIMEOUT ) == -1) return;
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000534 /* check if other objects have become signaled in the meantime */
535 wake_thread( thread );
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000536}
537
Mike McCormackf92fff62005-04-24 17:35:52 +0000538/* try signaling an event flag, a semaphore or a mutex */
539static int signal_object( obj_handle_t handle )
540{
541 struct object *obj;
542 int ret = 0;
543
544 obj = get_handle_obj( current->process, handle, 0, NULL );
545 if (obj)
546 {
547 ret = obj->ops->signal( obj, get_handle_access( current->process, handle ));
548 release_object( obj );
549 }
550 return ret;
551}
552
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000553/* select on a list of handles */
Alexandre Julliard51885742002-05-30 20:12:58 +0000554static void select_on( int count, void *cookie, const obj_handle_t *handles,
Mike McCormackf92fff62005-04-24 17:35:52 +0000555 int flags, const abs_time_t *timeout, obj_handle_t signal_obj )
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000556{
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000557 int ret, i;
558 struct object *objects[MAXIMUM_WAIT_OBJECTS];
559
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000560 if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
561 {
562 set_error( STATUS_INVALID_PARAMETER );
563 return;
564 }
565 for (i = 0; i < count; i++)
566 {
567 if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
568 break;
569 }
570
571 if (i < count) goto done;
Alexandre Julliard462172a2003-04-02 22:48:59 +0000572 if (!wait_on( count, objects, flags, timeout )) goto done;
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000573
Mike McCormackf92fff62005-04-24 17:35:52 +0000574 /* signal the object */
575 if (signal_obj)
576 {
577 if (!signal_object( signal_obj ))
578 {
579 end_wait( current );
580 goto done;
581 }
582 /* check if we woke ourselves up */
583 if (!current->wait) goto done;
584 }
585
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000586 if ((ret = check_wait( current )) != -1)
587 {
588 /* condition is already satisfied */
589 end_wait( current );
590 set_error( ret );
591 goto done;
592 }
593
Alexandre Julliard57e11311999-05-16 16:59:38 +0000594 /* now we need to wait */
595 if (flags & SELECT_TIMEOUT)
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000596 {
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000597 if (!(current->wait->user = add_timeout_user( &current->wait->timeout,
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000598 thread_timeout, current->wait )))
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000599 {
600 end_wait( current );
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000601 goto done;
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000602 }
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000603 }
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000604 current->wait->cookie = cookie;
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000605 set_error( STATUS_PENDING );
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000606
Alexandre Julliardd90e9642001-02-21 04:21:50 +0000607done:
Alexandre Julliard9de03f42000-01-04 02:23:38 +0000608 while (--i >= 0) release_object( objects[i] );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000609}
610
611/* attempt to wake threads sleeping on the object wait queue */
612void wake_up( struct object *obj, int max )
613{
Alexandre Julliardaa347682005-03-01 11:49:58 +0000614 struct list *ptr, *next;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000615
Alexandre Julliardaa347682005-03-01 11:49:58 +0000616 LIST_FOR_EACH_SAFE( ptr, next, &obj->wait_queue )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000617 {
Alexandre Julliardaa347682005-03-01 11:49:58 +0000618 struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry );
619 if (wake_thread( entry->thread ))
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000620 {
621 if (max && !--max) break;
622 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000623 }
624}
625
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000626/* queue an async procedure call */
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000627int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
Alexandre Julliard088bcf92003-04-04 22:26:34 +0000628 enum apc_type type, int system, void *arg1, void *arg2, void *arg3 )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000629{
630 struct thread_apc *apc;
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000631 struct list *queue = system ? &thread->system_apc : &thread->user_apc;
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000632
633 /* cancel a possible previous APC with the same owner */
Alexandre Julliard23623802001-01-06 01:48:51 +0000634 if (owner) thread_cancel_apc( thread, owner, system );
Alexandre Julliard15979fd2002-03-23 18:50:04 +0000635 if (thread->state == TERMINATED) return 0;
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000636
Alexandre Julliard088bcf92003-04-04 22:26:34 +0000637 if (!(apc = mem_alloc( sizeof(*apc) ))) return 0;
Alexandre Julliard088bcf92003-04-04 22:26:34 +0000638 apc->owner = owner;
639 apc->func = func;
640 apc->type = type;
641 apc->arg1 = arg1;
642 apc->arg2 = arg2;
643 apc->arg3 = arg3;
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000644 list_add_tail( queue, &apc->entry );
645 if (!list_prev( queue, &apc->entry )) /* first one */
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000646 wake_thread( thread );
Martin Wilckb1c45b92002-01-09 19:09:57 +0000647
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000648 return 1;
649}
650
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000651/* cancel the async procedure call owned by a specific object */
Alexandre Julliard23623802001-01-06 01:48:51 +0000652void thread_cancel_apc( struct thread *thread, struct object *owner, int system )
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000653{
654 struct thread_apc *apc;
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000655 struct list *queue = system ? &thread->system_apc : &thread->user_apc;
656 LIST_FOR_EACH_ENTRY( apc, queue, struct thread_apc, entry )
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000657 {
658 if (apc->owner != owner) continue;
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000659 list_remove( &apc->entry );
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000660 free( apc );
661 return;
662 }
663}
664
665/* remove the head apc from the queue; the returned pointer must be freed by the caller */
Alexandre Julliard23623802001-01-06 01:48:51 +0000666static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only )
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000667{
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000668 struct thread_apc *apc = NULL;
669 struct list *ptr = list_head( &thread->system_apc );
Alexandre Julliard23623802001-01-06 01:48:51 +0000670
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000671 if (!ptr && !system_only) ptr = list_head( &thread->user_apc );
672 if (ptr)
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000673 {
Alexandre Julliard81b6a1f2005-02-25 14:01:40 +0000674 apc = LIST_ENTRY( ptr, struct thread_apc, entry );
675 list_remove( ptr );
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000676 }
677 return apc;
678}
679
Alexandre Julliardf5242402001-02-28 21:45:23 +0000680/* add an fd to the inflight list */
681/* return list index, or -1 on error */
682int thread_add_inflight_fd( struct thread *thread, int client, int server )
683{
684 int i;
685
686 if (server == -1) return -1;
687 if (client == -1)
688 {
689 close( server );
690 return -1;
691 }
692
693 /* first check if we already have an entry for this fd */
694 for (i = 0; i < MAX_INFLIGHT_FDS; i++)
695 if (thread->inflight[i].client == client)
696 {
697 close( thread->inflight[i].server );
698 thread->inflight[i].server = server;
699 return i;
700 }
701
702 /* now find a free spot to store it */
703 for (i = 0; i < MAX_INFLIGHT_FDS; i++)
704 if (thread->inflight[i].client == -1)
705 {
706 thread->inflight[i].client = client;
707 thread->inflight[i].server = server;
708 return i;
709 }
710 return -1;
711}
712
713/* get an inflight fd and purge it from the list */
714/* the fd must be closed when no longer used */
715int thread_get_inflight_fd( struct thread *thread, int client )
716{
717 int i, ret;
718
719 if (client == -1) return -1;
720
721 do
722 {
723 for (i = 0; i < MAX_INFLIGHT_FDS; i++)
724 {
725 if (thread->inflight[i].client == client)
726 {
727 ret = thread->inflight[i].server;
728 thread->inflight[i].server = thread->inflight[i].client = -1;
729 return ret;
730 }
731 }
732 } while (!receive_fd( thread->process )); /* in case it is still in the socket buffer */
733 return -1;
734}
735
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +0000736/* retrieve an LDT selector entry */
737static void get_selector_entry( struct thread *thread, int entry,
738 unsigned int *base, unsigned int *limit,
739 unsigned char *flags )
740{
Alexandre Julliard914406f2000-11-14 01:54:49 +0000741 if (!thread->process->ldt_copy)
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +0000742 {
743 set_error( STATUS_ACCESS_DENIED );
744 return;
745 }
746 if (entry >= 8192)
747 {
748 set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
749 return;
750 }
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000751 if (suspend_for_ptrace( thread ))
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +0000752 {
753 unsigned char flags_buf[4];
Alexandre Julliard914406f2000-11-14 01:54:49 +0000754 int *addr = (int *)thread->process->ldt_copy + entry;
Mike McCormacke659f1e2005-08-09 10:37:50 +0000755 if (read_thread_int( thread, addr, (int *)base ) == -1) goto done;
756 if (read_thread_int( thread, addr + 8192, (int *)limit ) == -1) goto done;
Alexandre Julliard914406f2000-11-14 01:54:49 +0000757 addr = (int *)thread->process->ldt_copy + 2*8192 + (entry >> 2);
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +0000758 if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done;
759 *flags = flags_buf[entry & 3];
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000760 done:
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000761 resume_after_ptrace( thread );
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +0000762 }
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +0000763}
764
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000765/* kill a thread on the spot */
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000766void kill_thread( struct thread *thread, int violent_death )
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000767{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000768 if (thread->state == TERMINATED) return; /* already killed */
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000769 thread->state = TERMINATED;
Ryan Cumming24f4ece2002-11-25 01:33:38 +0000770 thread->exit_time = time(NULL);
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000771 if (current == thread) current = NULL;
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000772 if (debug_level)
Alexandre Julliard91befe12003-02-01 01:38:40 +0000773 fprintf( stderr,"%04x: *killed* exit_code=%d\n",
774 thread->id, thread->exit_code );
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000775 if (thread->wait)
776 {
Alexandre Julliarde5dedb12001-03-08 01:16:41 +0000777 while (thread->wait) end_wait( thread );
778 send_thread_wakeup( thread, NULL, STATUS_PENDING );
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000779 /* if it is waiting on the socket, we don't need to send a SIGTERM */
780 violent_death = 0;
781 }
Eric Pouech3940d8a2001-12-04 20:17:43 +0000782 kill_console_processes( thread, 0 );
Alexandre Julliardff81d782000-03-08 12:01:30 +0000783 debug_exit_thread( thread );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000784 abandon_mutexes( thread );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000785 wake_up( &thread->obj, 0 );
Alexandre Julliard1b2adad2005-08-22 10:13:28 +0000786 if (violent_death) send_thread_signal( thread, SIGTERM );
Alexandre Julliardf5242402001-02-28 21:45:23 +0000787 cleanup_thread( thread );
Alexandre Julliard867ae262005-09-14 15:44:12 +0000788 remove_process_thread( thread->process, thread );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000789 release_object( thread );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000790}
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000791
Alexandre Julliard07d84462000-04-16 19:45:05 +0000792/* take a snapshot of currently running threads */
793struct thread_snapshot *thread_snap( int *count )
794{
795 struct thread_snapshot *snapshot, *ptr;
796 struct thread *thread;
797 int total = 0;
798
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000799 LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
Alexandre Julliard07d84462000-04-16 19:45:05 +0000800 if (thread->state != TERMINATED) total++;
801 if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL;
802 ptr = snapshot;
Alexandre Julliard73209eb2005-02-25 19:33:35 +0000803 LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
Alexandre Julliard07d84462000-04-16 19:45:05 +0000804 {
805 if (thread->state == TERMINATED) continue;
806 ptr->thread = thread;
807 ptr->count = thread->obj.refcount;
808 ptr->priority = thread->priority;
809 grab_object( thread );
810 ptr++;
811 }
812 *count = total;
813 return snapshot;
814}
815
Robert Shearmand2ea92d2005-04-22 21:17:15 +0000816/* gets the current impersonation token */
817struct token *thread_get_impersonation_token( struct thread *thread )
818{
819 if (thread->token)
820 return thread->token;
821 else
822 return thread->process->token;
823}
824
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000825/* create a new thread */
826DECL_HANDLER(new_thread)
827{
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000828 struct thread *thread;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000829 int request_fd = thread_get_inflight_fd( current, req->request_fd );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000830
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000831 if (request_fd == -1 || fcntl( request_fd, F_SETFL, O_NONBLOCK ) == -1)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000832 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000833 if (request_fd != -1) close( request_fd );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000834 set_error( STATUS_INVALID_HANDLE );
835 return;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000836 }
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000837
Alexandre Julliard8859d772001-03-01 22:13:49 +0000838 if ((thread = create_thread( request_fd, current->process )))
839 {
840 if (req->suspend) thread->suspend++;
Alexandre Julliard54f22872002-10-03 19:54:57 +0000841 reply->tid = get_thread_id( thread );
Alexandre Julliard24560e72005-12-09 13:58:25 +0100842 if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes )))
Alexandre Julliard8859d772001-03-01 22:13:49 +0000843 {
844 /* thread object will be released when the thread gets killed */
845 return;
846 }
847 kill_thread( thread, 1 );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000848 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000849}
850
851/* initialize a new thread */
852DECL_HANDLER(init_thread)
853{
Alexandre Julliard0424f382005-07-13 12:12:43 +0000854 struct process *process = current->process;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000855 int reply_fd = thread_get_inflight_fd( current, req->reply_fd );
856 int wait_fd = thread_get_inflight_fd( current, req->wait_fd );
857
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000858 if (current->unix_pid != -1)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000859 {
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000860 fatal_protocol_error( current, "init_thread: already running\n" );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000861 goto error;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000862 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000863 if (reply_fd == -1 || fcntl( reply_fd, F_SETFL, O_NONBLOCK ) == -1)
Alexandre Julliard8859d772001-03-01 22:13:49 +0000864 {
865 fatal_protocol_error( current, "bad reply fd\n" );
866 goto error;
867 }
868 if (wait_fd == -1)
869 {
870 fatal_protocol_error( current, "bad wait fd\n" );
871 goto error;
872 }
Alexandre Julliard3c68ab02003-10-27 22:10:22 +0000873 if (!(current->reply_fd = create_anonymous_fd( &thread_fd_ops, reply_fd, &current->obj )))
874 {
875 reply_fd = -1;
876 fatal_protocol_error( current, "could not allocate reply fd\n" );
877 goto error;
878 }
879 if (!(current->wait_fd = create_anonymous_fd( &thread_fd_ops, wait_fd, &current->obj )))
880 return;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000881
Alexandre Julliard0424f382005-07-13 12:12:43 +0000882 if (!is_valid_address(req->teb) || !is_valid_address(req->peb) || !is_valid_address(req->ldt_copy))
883 {
884 set_error( STATUS_INVALID_PARAMETER );
885 return;
886 }
887
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000888 current->unix_pid = req->unix_pid;
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000889 current->unix_tid = req->unix_tid;
Alexandre Julliard57e11311999-05-16 16:59:38 +0000890 current->teb = req->teb;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000891
Alexandre Julliard0424f382005-07-13 12:12:43 +0000892 if (!process->peb) /* first thread, initialize the process too */
893 {
894 process->peb = req->peb;
895 process->ldt_copy = req->ldt_copy;
Alexandre Julliard11ad6a02005-07-13 19:43:35 +0000896 reply->info_size = init_process( current );
Alexandre Julliard0424f382005-07-13 12:12:43 +0000897 }
898 else
899 {
900 if (current->suspend + process->suspend > 0) stop_thread( current );
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000901 generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, req->entry );
Alexandre Julliard0424f382005-07-13 12:12:43 +0000902 }
903 debug_level = max( debug_level, req->debug_level );
Alexandre Julliard8859d772001-03-01 22:13:49 +0000904
Alexandre Julliard0424f382005-07-13 12:12:43 +0000905 reply->pid = get_process_id( process );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000906 reply->tid = get_thread_id( current );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000907 reply->version = SERVER_PROTOCOL_VERSION;
Alexandre Julliard9ad56282005-07-14 10:32:46 +0000908 reply->server_start = server_start_time;
Alexandre Julliard8859d772001-03-01 22:13:49 +0000909 return;
910
911 error:
912 if (reply_fd != -1) close( reply_fd );
913 if (wait_fd != -1) close( wait_fd );
914}
915
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000916/* terminate a thread */
917DECL_HANDLER(terminate_thread)
918{
919 struct thread *thread;
920
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000921 reply->self = 0;
922 reply->last = 0;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000923 if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
924 {
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000925 thread->exit_code = req->exit_code;
926 if (thread != current) kill_thread( thread, 1 );
927 else
928 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000929 reply->self = 1;
930 reply->last = (thread->process->running_threads == 1);
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000931 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000932 release_object( thread );
933 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000934}
935
Chris Morgan417296c2002-04-02 00:49:05 +0000936/* open a handle to a thread */
937DECL_HANDLER(open_thread)
938{
939 struct thread *thread = get_thread_from_id( req->tid );
940
941 reply->handle = 0;
942 if (thread)
943 {
Alexandre Julliard24560e72005-12-09 13:58:25 +0100944 reply->handle = alloc_handle( current->process, thread, req->access, req->attributes );
Chris Morgan417296c2002-04-02 00:49:05 +0000945 release_object( thread );
946 }
947}
948
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000949/* fetch information about a thread */
950DECL_HANDLER(get_thread_info)
951{
952 struct thread *thread;
Alexandre Julliard51885742002-05-30 20:12:58 +0000953 obj_handle_t handle = req->handle;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000954
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000955 if (!handle) thread = get_thread_from_id( req->tid_in );
Alexandre Julliard9a0e28f2000-03-25 19:14:37 +0000956 else thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION );
957
958 if (thread)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000959 {
Alexandre Julliard4f196ea2003-07-09 02:57:57 +0000960 reply->pid = get_process_id( thread->process );
Ryan Cumming24f4ece2002-11-25 01:33:38 +0000961 reply->tid = get_thread_id( thread );
962 reply->teb = thread->teb;
963 reply->exit_code = (thread->state == TERMINATED) ? thread->exit_code : STILL_ACTIVE;
964 reply->priority = thread->priority;
Alexandre Julliard4f196ea2003-07-09 02:57:57 +0000965 reply->affinity = thread->affinity;
Ryan Cumming24f4ece2002-11-25 01:33:38 +0000966 reply->creation_time = thread->creation_time;
967 reply->exit_time = thread->exit_time;
968
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000969 release_object( thread );
970 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000971}
972
973/* set information about a thread */
974DECL_HANDLER(set_thread_info)
975{
976 struct thread *thread;
977
978 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_INFORMATION )))
979 {
980 set_thread_info( thread, req );
981 release_object( thread );
982 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000983}
984
985/* suspend a thread */
986DECL_HANDLER(suspend_thread)
987{
988 struct thread *thread;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000989
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000990 if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
991 {
François Gougetf6662572002-04-02 02:53:45 +0000992 if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED );
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000993 else reply->count = suspend_thread( thread );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000994 release_object( thread );
995 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000996}
997
998/* resume a thread */
999DECL_HANDLER(resume_thread)
1000{
1001 struct thread *thread;
Alexandre Julliardebe29ef1999-06-26 08:43:26 +00001002
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001003 if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
1004 {
François Gougetf6662572002-04-02 02:53:45 +00001005 if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED );
1006 else reply->count = resume_thread( thread );
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001007 release_object( thread );
1008 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001009}
1010
1011/* select on a handle list */
1012DECL_HANDLER(select)
1013{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001014 int count = get_req_data_size() / sizeof(int);
Mike McCormackf92fff62005-04-24 17:35:52 +00001015 select_on( count, req->cookie, get_req_data(), req->flags, &req->timeout, req->signal );
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001016}
1017
1018/* queue an APC for a thread */
1019DECL_HANDLER(queue_apc)
1020{
1021 struct thread *thread;
1022 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
1023 {
Alexandre Julliard088bcf92003-04-04 22:26:34 +00001024 thread_queue_apc( thread, NULL, req->func, APC_USER, !req->user,
1025 req->arg1, req->arg2, req->arg3 );
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001026 release_object( thread );
1027 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001028}
Alexandre Julliardebe29ef1999-06-26 08:43:26 +00001029
Alexandre Julliardea1afce2000-08-22 20:08:37 +00001030/* get next APC to call */
1031DECL_HANDLER(get_apc)
Alexandre Julliardebe29ef1999-06-26 08:43:26 +00001032{
Alexandre Julliardea1afce2000-08-22 20:08:37 +00001033 struct thread_apc *apc;
1034
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001035 for (;;)
Alexandre Julliardebe29ef1999-06-26 08:43:26 +00001036 {
Alexandre Julliard23623802001-01-06 01:48:51 +00001037 if (!(apc = thread_dequeue_apc( current, !req->alertable )))
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001038 {
1039 /* no more APCs */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001040 reply->func = NULL;
1041 reply->type = APC_NONE;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001042 return;
1043 }
1044 /* Optimization: ignore APCs that have a NULL func; they are only used
1045 * to wake up a thread, but since we got here the thread woke up already.
Martin Wilck2b47fb32002-04-05 22:53:57 +00001046 * Exception: for APC_ASYNC_IO, func == NULL is legal.
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001047 */
Martin Wilck2b47fb32002-04-05 22:53:57 +00001048 if (apc->func || apc->type == APC_ASYNC_IO) break;
Alexandre Julliardea1afce2000-08-22 20:08:37 +00001049 free( apc );
1050 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001051 reply->func = apc->func;
1052 reply->type = apc->type;
Alexandre Julliard088bcf92003-04-04 22:26:34 +00001053 reply->arg1 = apc->arg1;
1054 reply->arg2 = apc->arg2;
1055 reply->arg3 = apc->arg3;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +00001056 free( apc );
Alexandre Julliardebe29ef1999-06-26 08:43:26 +00001057}
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +00001058
Alexandre Julliard3f85e262005-11-02 14:12:13 +00001059/* retrieve the current context of a thread */
1060DECL_HANDLER(get_thread_context)
1061{
1062 struct thread *thread;
1063 void *data;
1064
1065 if (get_reply_max_size() < sizeof(CONTEXT))
1066 {
1067 set_error( STATUS_INVALID_PARAMETER );
1068 return;
1069 }
1070 if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
1071
Alexandre Julliard73c72392005-11-02 20:54:12 +00001072 if (req->suspend)
1073 {
1074 if (thread != current || !thread->suspend_context)
1075 {
1076 /* not suspended, shouldn't happen */
1077 set_error( STATUS_INVALID_PARAMETER );
1078 }
1079 else
1080 {
1081 if (thread->context == thread->suspend_context) thread->context = NULL;
1082 set_reply_data_ptr( thread->suspend_context, sizeof(CONTEXT) );
1083 thread->suspend_context = NULL;
1084 }
1085 }
1086 else if (thread != current && !thread->context)
1087 {
1088 /* thread is not suspended, retry (if it's still running) */
1089 if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
1090 else set_error( STATUS_PENDING );
1091 }
1092 else if ((data = set_reply_data_size( sizeof(CONTEXT) )))
Alexandre Julliard3f85e262005-11-02 14:12:13 +00001093 {
1094 memset( data, 0, sizeof(CONTEXT) );
1095 get_thread_context( thread, data, req->flags );
1096 }
Alexandre Julliard2878d992006-01-13 13:58:14 +01001097 reply->self = (thread == current);
Alexandre Julliard3f85e262005-11-02 14:12:13 +00001098 release_object( thread );
1099}
1100
1101/* set the current context of a thread */
1102DECL_HANDLER(set_thread_context)
1103{
1104 struct thread *thread;
1105
1106 if (get_req_data_size() < sizeof(CONTEXT))
1107 {
1108 set_error( STATUS_INVALID_PARAMETER );
1109 return;
1110 }
Alexandre Julliard73c72392005-11-02 20:54:12 +00001111 if (!(thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) return;
1112
1113 if (req->suspend)
1114 {
1115 if (thread != current || thread->context)
1116 {
1117 /* nested suspend or exception, shouldn't happen */
1118 set_error( STATUS_INVALID_PARAMETER );
1119 }
1120 else if ((thread->suspend_context = mem_alloc( sizeof(CONTEXT) )))
1121 {
1122 memcpy( thread->suspend_context, get_req_data(), sizeof(CONTEXT) );
1123 thread->context = thread->suspend_context;
1124 }
1125 }
1126 else if (thread != current && !thread->context)
1127 {
1128 /* thread is not suspended, retry (if it's still running) */
1129 if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
1130 else set_error( STATUS_PENDING );
1131 }
1132 else
Alexandre Julliard3f85e262005-11-02 14:12:13 +00001133 {
1134 set_thread_context( thread, get_req_data(), req->flags );
Alexandre Julliard3f85e262005-11-02 14:12:13 +00001135 }
Alexandre Julliard2654be02006-01-11 20:20:32 +01001136 reply->self = (thread == current);
Alexandre Julliard73c72392005-11-02 20:54:12 +00001137 release_object( thread );
Alexandre Julliard3f85e262005-11-02 14:12:13 +00001138}
1139
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +00001140/* fetch a selector entry for a thread */
1141DECL_HANDLER(get_selector_entry)
1142{
1143 struct thread *thread;
1144 if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
1145 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001146 get_selector_entry( thread, req->entry, &reply->base, &reply->limit, &reply->flags );
Alexandre Julliard0a7c1f62000-01-27 02:54:17 +00001147 release_object( thread );
1148 }
1149}