thread.c 49.2 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Server-side thread management
 *
 * Copyright (C) 1998 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <assert.h>
25
#include <errno.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include <fcntl.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#include <signal.h>
28
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
29 30 31
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include <sys/types.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include <unistd.h>
34
#include <time.h>
35 36 37
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
38 39 40
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
41

42 43
#include "ntstatus.h"
#define WIN32_NO_STATUS
44
#include "windef.h"
45
#include "winternl.h"
46

47
#include "file.h"
48 49 50
#include "handle.h"
#include "process.h"
#include "thread.h"
51
#include "request.h"
52
#include "user.h"
53
#include "security.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
54 55


56 57 58 59 60 61 62 63
#ifdef __i386__
static const unsigned int supported_cpus = CPU_FLAG(CPU_x86);
#elif defined(__x86_64__)
static const unsigned int supported_cpus = CPU_FLAG(CPU_x86_64) | CPU_FLAG(CPU_x86);
#elif defined(__powerpc__)
static const unsigned int supported_cpus = CPU_FLAG(CPU_POWERPC);
#elif defined(__sparc__)
static const unsigned int supported_cpus = CPU_FLAG(CPU_SPARC);
64 65
#elif defined(__arm__)
static const unsigned int supported_cpus = CPU_FLAG(CPU_ARM);
66 67 68 69
#else
#error Unsupported CPU
#endif

Alexandre Julliard's avatar
Alexandre Julliard committed
70 71 72 73
/* thread queues */

struct thread_wait
{
74 75
    struct thread_wait     *next;       /* next wait structure for this thread */
    struct thread          *thread;     /* owner thread */
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77
    int                     count;      /* count of objects */
    int                     flags;
78
    client_ptr_t            cookie;     /* magic cookie to return to client */
79
    timeout_t               timeout;
80
    struct timeout_user    *user;
Alexandre Julliard's avatar
Alexandre Julliard committed
81 82 83
    struct wait_queue_entry queues[1];
};

84 85 86 87
/* asynchronous procedure calls */

struct thread_apc
{
88
    struct object       obj;      /* object header */
89
    struct list         entry;    /* queue linked list */
90
    struct thread      *caller;   /* thread that queued this apc */
91
    struct object      *owner;    /* object that queued this apc */
92
    int                 executed; /* has it been executed by the client? */
93 94
    apc_call_t          call;     /* call arguments */
    apc_result_t        result;   /* call results once executed */
95 96
};

97 98
static void dump_thread_apc( struct object *obj, int verbose );
static int thread_apc_signaled( struct object *obj, struct thread *thread );
99
static void thread_apc_destroy( struct object *obj );
100
static void clear_apc_queue( struct list *queue );
101 102 103 104 105

static const struct object_ops thread_apc_ops =
{
    sizeof(struct thread_apc),  /* size */
    dump_thread_apc,            /* dump */
106
    no_get_type,                /* get_type */
107 108 109 110 111 112 113
    add_queue,                  /* add_queue */
    remove_queue,               /* remove_queue */
    thread_apc_signaled,        /* signaled */
    no_satisfied,               /* satisfied */
    no_signal,                  /* signal */
    no_get_fd,                  /* get_fd */
    no_map_access,              /* map_access */
114 115
    default_get_sd,             /* get_sd */
    default_set_sd,             /* set_sd */
116
    no_lookup_name,             /* lookup_name */
117
    no_open_file,               /* open_file */
118
    no_close_handle,            /* close_handle */
119
    thread_apc_destroy          /* destroy */
120 121
};

Alexandre Julliard's avatar
Alexandre Julliard committed
122

Alexandre Julliard's avatar
Alexandre Julliard committed
123 124
/* thread operations */

Alexandre Julliard's avatar
Alexandre Julliard committed
125
static void dump_thread( struct object *obj, int verbose );
Alexandre Julliard's avatar
Alexandre Julliard committed
126
static int thread_signaled( struct object *obj, struct thread *thread );
127
static unsigned int thread_map_access( struct object *obj, unsigned int access );
128
static void thread_poll_event( struct fd *fd, int event );
Alexandre Julliard's avatar
Alexandre Julliard committed
129 130 131 132
static void destroy_thread( struct object *obj );

static const struct object_ops thread_ops =
{
133 134
    sizeof(struct thread),      /* size */
    dump_thread,                /* dump */
135
    no_get_type,                /* get_type */
136 137 138 139
    add_queue,                  /* add_queue */
    remove_queue,               /* remove_queue */
    thread_signaled,            /* signaled */
    no_satisfied,               /* satisfied */
140
    no_signal,                  /* signal */
141
    no_get_fd,                  /* get_fd */
142
    thread_map_access,          /* map_access */
143 144
    default_get_sd,             /* get_sd */
    default_set_sd,             /* set_sd */
145
    no_lookup_name,             /* lookup_name */
146
    no_open_file,               /* open_file */
147
    no_close_handle,            /* close_handle */
148 149 150 151 152
    destroy_thread              /* destroy */
};

static const struct fd_ops thread_fd_ops =
{
153 154
    NULL,                       /* get_poll_events */
    thread_poll_event,          /* poll_event */
155 156
    NULL,                       /* flush */
    NULL,                       /* get_fd_type */
157
    NULL,                       /* ioctl */
158
    NULL,                       /* queue_async */
159
    NULL,                       /* reselect_async */
160
    NULL                        /* cancel_async */
Alexandre Julliard's avatar
Alexandre Julliard committed
161 162
};

163
static struct list thread_list = LIST_INIT(thread_list);
Alexandre Julliard's avatar
Alexandre Julliard committed
164

165
/* initialize the structure for a newly allocated thread */
166
static inline void init_thread_structure( struct thread *thread )
167 168 169
{
    int i;

170
    thread->unix_pid        = -1;  /* not known yet */
171
    thread->unix_tid        = -1;  /* not known yet */
172
    thread->context         = NULL;
173
    thread->suspend_context = NULL;
174
    thread->teb             = 0;
175 176
    thread->debug_ctx       = NULL;
    thread->debug_event     = NULL;
177
    thread->debug_break     = 0;
178 179 180
    thread->queue           = NULL;
    thread->wait            = NULL;
    thread->error           = 0;
181 182 183 184
    thread->req_data        = NULL;
    thread->req_toread      = 0;
    thread->reply_data      = NULL;
    thread->reply_towrite   = 0;
185 186 187
    thread->request_fd      = NULL;
    thread->reply_fd        = NULL;
    thread->wait_fd         = NULL;
188 189
    thread->state           = RUNNING;
    thread->exit_code       = 0;
190
    thread->priority        = 0;
191
    thread->suspend         = 0;
192
    thread->desktop_users   = 0;
193
    thread->token           = NULL;
194

195
    thread->creation_time = current_time;
196
    thread->exit_time     = 0;
197

198
    list_init( &thread->mutex_list );
199 200 201
    list_init( &thread->system_apc );
    list_init( &thread->user_apc );

202 203 204 205
    for (i = 0; i < MAX_INFLIGHT_FDS; i++)
        thread->inflight[i].server = thread->inflight[i].client = -1;
}

206
/* check if address looks valid for a client-side data structure (TEB etc.) */
207
static inline int is_valid_address( client_ptr_t addr )
208
{
209
    return addr && !(addr % sizeof(int));
210 211
}

212
/* create a new thread */
213
struct thread *create_thread( int fd, struct process *process )
214 215 216
{
    struct thread *thread;

217
    if (!(thread = alloc_object( &thread_ops ))) return NULL;
218

219
    init_thread_structure( thread );
220

221
    thread->process = (struct process *)grab_object( process );
222
    thread->desktop = process->desktop;
223
    thread->affinity = process->affinity;
224 225
    if (!current) current = thread;

226
    list_add_head( &thread_list, &thread->entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
227

228 229 230 231 232
    if (!(thread->id = alloc_ptid( thread )))
    {
        release_object( thread );
        return NULL;
    }
233
    if (!(thread->request_fd = create_anonymous_fd( &thread_fd_ops, fd, &thread->obj, 0 )))
234 235 236 237
    {
        release_object( thread );
        return NULL;
    }
238

239
    set_fd_events( thread->request_fd, POLLIN );  /* start listening to events */
240
    add_process_thread( thread->process, thread );
241
    return thread;
Alexandre Julliard's avatar
Alexandre Julliard committed
242 243
}

244
/* handle a client event */
245
static void thread_poll_event( struct fd *fd, int event )
246
{
247 248
    struct thread *thread = get_fd_user( fd );
    assert( thread->obj.ops == &thread_ops );
249

250
    grab_object( thread );
251
    if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
252
    else if (event & POLLIN) read_request( thread );
253
    else if (event & POLLOUT) write_reply( thread );
254
    release_object( thread );
255 256 257 258 259 260 261 262
}

/* cleanup everything that is no longer needed by a dead thread */
/* used by destroy_thread and kill_thread */
static void cleanup_thread( struct thread *thread )
{
    int i;

263 264
    clear_apc_queue( &thread->system_apc );
    clear_apc_queue( &thread->user_apc );
265 266
    free( thread->req_data );
    free( thread->reply_data );
267 268 269
    if (thread->request_fd) release_object( thread->request_fd );
    if (thread->reply_fd) release_object( thread->reply_fd );
    if (thread->wait_fd) release_object( thread->wait_fd );
270
    free( thread->suspend_context );
271
    cleanup_clipboard_thread(thread);
272
    destroy_thread_windows( thread );
273
    free_msg_queue( thread );
274
    close_thread_desktop( thread );
275 276 277 278 279 280 281 282
    for (i = 0; i < MAX_INFLIGHT_FDS; i++)
    {
        if (thread->inflight[i].client != -1)
        {
            close( thread->inflight[i].server );
            thread->inflight[i].client = thread->inflight[i].server = -1;
        }
    }
283 284
    thread->req_data = NULL;
    thread->reply_data = NULL;
285 286 287
    thread->request_fd = NULL;
    thread->reply_fd = NULL;
    thread->wait_fd = NULL;
288 289
    thread->context = NULL;
    thread->suspend_context = NULL;
290
    thread->desktop = 0;
291 292
}

Alexandre Julliard's avatar
Alexandre Julliard committed
293 294 295 296 297 298
/* destroy a thread when its refcount is 0 */
static void destroy_thread( struct object *obj )
{
    struct thread *thread = (struct thread *)obj;
    assert( obj->ops == &thread_ops );

299
    assert( !thread->debug_ctx );  /* cannot still be debugging something */
300
    list_remove( &thread->entry );
301
    cleanup_thread( thread );
302
    release_object( thread->process );
303
    if (thread->id) free_ptid( thread->id );
304
    if (thread->token) release_object( thread->token );
Alexandre Julliard's avatar
Alexandre Julliard committed
305 306
}

Alexandre Julliard's avatar
Alexandre Julliard committed
307 308 309 310 311 312
/* dump a thread on stdout for debugging purposes */
static void dump_thread( struct object *obj, int verbose )
{
    struct thread *thread = (struct thread *)obj;
    assert( obj->ops == &thread_ops );

313 314
    fprintf( stderr, "Thread id=%04x unix pid=%d unix tid=%d state=%d\n",
             thread->id, thread->unix_pid, thread->unix_tid, thread->state );
Alexandre Julliard's avatar
Alexandre Julliard committed
315 316
}

Alexandre Julliard's avatar
Alexandre Julliard committed
317 318 319 320 321 322
static int thread_signaled( struct object *obj, struct thread *thread )
{
    struct thread *mythread = (struct thread *)obj;
    return (mythread->state == TERMINATED);
}

323 324 325 326 327 328 329 330 331
static unsigned int thread_map_access( struct object *obj, unsigned int access )
{
    if (access & GENERIC_READ)    access |= STANDARD_RIGHTS_READ | SYNCHRONIZE;
    if (access & GENERIC_WRITE)   access |= STANDARD_RIGHTS_WRITE | SYNCHRONIZE;
    if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE;
    if (access & GENERIC_ALL)     access |= THREAD_ALL_ACCESS;
    return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
}

332 333 334 335 336
static void dump_thread_apc( struct object *obj, int verbose )
{
    struct thread_apc *apc = (struct thread_apc *)obj;
    assert( obj->ops == &thread_apc_ops );

337
    fprintf( stderr, "APC owner=%p type=%u\n", apc->owner, apc->call.type );
338 339 340 341
}

static int thread_apc_signaled( struct object *obj, struct thread *thread )
{
342 343
    struct thread_apc *apc = (struct thread_apc *)obj;
    return apc->executed;
344 345
}

346 347 348 349
static void thread_apc_destroy( struct object *obj )
{
    struct thread_apc *apc = (struct thread_apc *)obj;
    if (apc->caller) release_object( apc->caller );
350
    if (apc->owner) release_object( apc->owner );
351 352
}

353 354 355 356 357 358 359 360
/* queue an async procedure call */
static struct thread_apc *create_apc( struct object *owner, const apc_call_t *call_data )
{
    struct thread_apc *apc;

    if ((apc = alloc_object( &thread_apc_ops )))
    {
        apc->call        = *call_data;
361
        apc->caller      = NULL;
362 363 364
        apc->owner       = owner;
        apc->executed    = 0;
        apc->result.type = APC_NONE;
365
        if (owner) grab_object( owner );
366 367 368 369
    }
    return apc;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
370
/* get a thread pointer from a thread id (and increment the refcount) */
371
struct thread *get_thread_from_id( thread_id_t id )
Alexandre Julliard's avatar
Alexandre Julliard committed
372
{
373 374 375
    struct object *obj = get_ptid_entry( id );

    if (obj && obj->ops == &thread_ops) return (struct thread *)grab_object( obj );
376
    set_error( STATUS_INVALID_CID );
377
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
378 379
}

Alexandre Julliard's avatar
Alexandre Julliard committed
380
/* get a thread from a handle (and increment the refcount) */
381
struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access )
Alexandre Julliard's avatar
Alexandre Julliard committed
382
{
Alexandre Julliard's avatar
Alexandre Julliard committed
383 384
    return (struct thread *)get_handle_obj( current->process, handle,
                                            access, &thread_ops );
Alexandre Julliard's avatar
Alexandre Julliard committed
385 386
}

387 388
/* find a thread from a Unix tid */
struct thread *get_thread_from_tid( int tid )
389
{
390
    struct thread *thread;
391

392 393
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
    {
394
        if (thread->unix_tid == tid) return thread;
395
    }
396 397 398 399 400 401 402 403
    return NULL;
}

/* find a thread from a Unix pid */
struct thread *get_thread_from_pid( int pid )
{
    struct thread *thread;

404 405 406 407
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
    {
        if (thread->unix_pid == pid) return thread;
    }
408
    return NULL;
409 410
}

411
int set_thread_affinity( struct thread *thread, affinity_t affinity )
412
{
413
    int ret = 0;
414
#ifdef HAVE_SCHED_SETAFFINITY
415
    if (thread->unix_tid != -1)
416 417 418 419 420 421 422 423 424
    {
        cpu_set_t set;
        int i;
        affinity_t mask;

        CPU_ZERO( &set );
        for (i = 0, mask = 1; mask; i++, mask <<= 1)
            if (affinity & mask) CPU_SET( i, &set );

425
        ret = sched_setaffinity( thread->unix_tid, sizeof(set), &set );
426 427
    }
#endif
428 429
    if (!ret) thread->affinity = affinity;
    return ret;
430 431
}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
affinity_t get_thread_affinity( struct thread *thread )
{
    affinity_t mask = 0;
#ifdef HAVE_SCHED_SETAFFINITY
    if (thread->unix_tid != -1)
    {
        cpu_set_t set;
        unsigned int i;

        if (!sched_getaffinity( thread->unix_tid, sizeof(set), &set ))
            for (i = 0; i < 8 * sizeof(mask); i++)
                if (CPU_ISSET( i, &set )) mask |= 1 << i;
    }
#endif
    if (!mask) mask = ~0;
    return mask;
}

450 451 452
#define THREAD_PRIORITY_REALTIME_HIGHEST 6
#define THREAD_PRIORITY_REALTIME_LOWEST -7

453
/* set all information about a thread */
454
static void set_thread_info( struct thread *thread,
455
                             const struct set_thread_info_request *req )
456 457
{
    if (req->mask & SET_THREAD_INFO_PRIORITY)
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
    {
        int max = THREAD_PRIORITY_HIGHEST;
        int min = THREAD_PRIORITY_LOWEST;
        if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME)
        {
            max = THREAD_PRIORITY_REALTIME_HIGHEST;
            min = THREAD_PRIORITY_REALTIME_LOWEST;
        }
        if ((req->priority >= min && req->priority <= max) ||
            req->priority == THREAD_PRIORITY_IDLE ||
            req->priority == THREAD_PRIORITY_TIME_CRITICAL)
            thread->priority = req->priority;
        else
            set_error( STATUS_INVALID_PARAMETER );
    }
473
    if (req->mask & SET_THREAD_INFO_AFFINITY)
474 475 476 477 478 479 480 481
    {
        if ((req->affinity & thread->process->affinity) != req->affinity)
            set_error( STATUS_INVALID_PARAMETER );
        else if (thread->state == TERMINATED)
            set_error( STATUS_ACCESS_DENIED );
        else if (set_thread_affinity( thread, req->affinity ))
            file_set_error();
    }
482 483
    if (req->mask & SET_THREAD_INFO_TOKEN)
        security_set_thread_token( thread, req->token );
484 485
}

486 487 488
/* stop a thread (at the Unix level) */
void stop_thread( struct thread *thread )
{
489
    if (thread->context) return;  /* already inside a debug event, no need for a signal */
490 491 492 493
    /* can't stop a thread while initialisation is in progress */
    if (is_process_init_done(thread->process)) send_thread_signal( thread, SIGUSR1 );
}

494 495 496 497 498 499
/* stop a thread if it's supposed to be suspended */
void stop_thread_if_suspended( struct thread *thread )
{
    if (thread->suspend + thread->process->suspend > 0) stop_thread( thread );
}

500
/* suspend a thread */
501
static int suspend_thread( struct thread *thread )
502 503
{
    int old_count = thread->suspend;
504
    if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
505
    {
506
        if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
507
    }
508
    else set_error( STATUS_SUSPEND_COUNT_EXCEEDED );
509 510 511 512
    return old_count;
}

/* resume a thread */
513
static int resume_thread( struct thread *thread )
514 515 516 517
{
    int old_count = thread->suspend;
    if (thread->suspend > 0)
    {
518
        if (!(--thread->suspend + thread->process->suspend)) wake_thread( thread );
519 520
    }
    return old_count;
Alexandre Julliard's avatar
Alexandre Julliard committed
521 522 523
}

/* add a thread to an object wait queue; return 1 if OK, 0 on error */
524
int add_queue( struct object *obj, struct wait_queue_entry *entry )
Alexandre Julliard's avatar
Alexandre Julliard committed
525
{
526
    grab_object( obj );
527 528
    entry->obj = obj;
    list_add_tail( &obj->wait_queue, &entry->entry );
529
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
530 531 532
}

/* remove a thread from an object wait queue */
533
void remove_queue( struct object *obj, struct wait_queue_entry *entry )
Alexandre Julliard's avatar
Alexandre Julliard committed
534
{
535
    list_remove( &entry->entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
536 537 538 539 540 541 542 543 544 545 546
    release_object( obj );
}

/* finish waiting */
static void end_wait( struct thread *thread )
{
    struct thread_wait *wait = thread->wait;
    struct wait_queue_entry *entry;
    int i;

    assert( wait );
547
    thread->wait = wait->next;
548 549
    for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
        entry->obj->ops->remove_queue( entry->obj, entry );
550
    if (wait->user) remove_timeout_user( wait->user );
Alexandre Julliard's avatar
Alexandre Julliard committed
551 552 553 554
    free( wait );
}

/* build the thread wait structure */
555
static int wait_on( unsigned int count, struct object *objects[], int flags, timeout_t timeout )
Alexandre Julliard's avatar
Alexandre Julliard committed
556 557 558
{
    struct thread_wait *wait;
    struct wait_queue_entry *entry;
559
    unsigned int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
560

561
    if (!(wait = mem_alloc( FIELD_OFFSET(struct thread_wait, queues[count]) ))) return 0;
562 563
    wait->next    = current->wait;
    wait->thread  = current;
Alexandre Julliard's avatar
Alexandre Julliard committed
564 565
    wait->count   = count;
    wait->flags   = flags;
566
    wait->user    = NULL;
567
    wait->timeout = timeout;
568
    current->wait = wait;
Alexandre Julliard's avatar
Alexandre Julliard committed
569 570 571

    for (i = 0, entry = wait->queues; i < count; i++, entry++)
    {
572 573
        struct object *obj = objects[i];
        entry->thread = current;
574 575
        if (!obj->ops->add_queue( obj, entry ))
        {
576 577
            wait->count = i;
            end_wait( current );
578 579
            return 0;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
580 581 582 583 584
    }
    return 1;
}

/* check if the thread waiting condition is satisfied */
585
static int check_wait( struct thread *thread )
Alexandre Julliard's avatar
Alexandre Julliard committed
586
{
587
    int i, signaled;
Alexandre Julliard's avatar
Alexandre Julliard committed
588
    struct thread_wait *wait = thread->wait;
589
    struct wait_queue_entry *entry;
Alexandre Julliard's avatar
Alexandre Julliard committed
590

591 592 593 594 595
    assert( wait );

    if ((wait->flags & SELECT_INTERRUPTIBLE) && !list_empty( &thread->system_apc ))
        return STATUS_USER_APC;

596
    /* Suspended threads may not acquire locks, but they can run system APCs */
597
    if (thread->process->suspend + thread->suspend > 0) return -1;
598

Alexandre Julliard's avatar
Alexandre Julliard committed
599 600
    if (wait->flags & SELECT_ALL)
    {
601 602 603
        int not_ok = 0;
        /* Note: we must check them all anyway, as some objects may
         * want to do something when signaled, even if others are not */
Alexandre Julliard's avatar
Alexandre Julliard committed
604
        for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
605 606
            not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
        if (not_ok) goto other_checks;
Alexandre Julliard's avatar
Alexandre Julliard committed
607
        /* Wait satisfied: tell it to all objects */
608
        signaled = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
609 610
        for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
            if (entry->obj->ops->satisfied( entry->obj, thread ))
611 612
                signaled = STATUS_ABANDONED_WAIT_0;
        return signaled;
Alexandre Julliard's avatar
Alexandre Julliard committed
613 614 615 616 617 618 619
    }
    else
    {
        for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
        {
            if (!entry->obj->ops->signaled( entry->obj, thread )) continue;
            /* Wait satisfied: tell it to the object */
620
            signaled = i;
Alexandre Julliard's avatar
Alexandre Julliard committed
621
            if (entry->obj->ops->satisfied( entry->obj, thread ))
622 623
                signaled = i + STATUS_ABANDONED_WAIT_0;
            return signaled;
Alexandre Julliard's avatar
Alexandre Julliard committed
624 625
        }
    }
626 627

 other_checks:
628
    if ((wait->flags & SELECT_ALERTABLE) && !list_empty(&thread->user_apc)) return STATUS_USER_APC;
629
    if (wait->timeout <= current_time) return STATUS_TIMEOUT;
630 631 632
    return -1;
}

633
/* send the wakeup signal to a thread */
634
static int send_thread_wakeup( struct thread *thread, client_ptr_t cookie, int signaled )
635 636 637 638
{
    struct wake_up_reply reply;
    int ret;

639
    memset( &reply, 0, sizeof(reply) );
640 641
    reply.cookie   = cookie;
    reply.signaled = signaled;
642 643
    if ((ret = write( get_unix_fd( thread->wait_fd ), &reply, sizeof(reply) )) == sizeof(reply))
        return 0;
644 645 646 647 648 649 650 651 652
    if (ret >= 0)
        fatal_protocol_error( thread, "partial wakeup write %d\n", ret );
    else if (errno == EPIPE)
        kill_thread( thread, 0 );  /* normal death */
    else
        fatal_protocol_perror( thread, "write" );
    return -1;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
653
/* attempt to wake up a thread */
654
/* return >0 if OK, 0 if the wait condition is still not satisfied */
655
int wake_thread( struct thread *thread )
Alexandre Julliard's avatar
Alexandre Julliard committed
656
{
657
    int signaled, count;
658
    client_ptr_t cookie;
659

660 661 662 663 664
    for (count = 0; thread->wait; count++)
    {
        if ((signaled = check_wait( thread )) == -1) break;

        cookie = thread->wait->cookie;
665
        if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d\n", thread->id, signaled );
666
        end_wait( thread );
667 668
        if (send_thread_wakeup( thread, cookie, signaled ) == -1) /* error */
	    break;
669 670
    }
    return count;
Alexandre Julliard's avatar
Alexandre Julliard committed
671 672
}

673 674 675
/* thread wait timeout */
static void thread_timeout( void *ptr )
{
676 677
    struct thread_wait *wait = ptr;
    struct thread *thread = wait->thread;
678
    client_ptr_t cookie = wait->cookie;
679

680 681
    wait->user = NULL;
    if (thread->wait != wait) return; /* not the top-level wait, ignore it */
682
    if (thread->suspend + thread->process->suspend > 0) return;  /* suspended, ignore it */
683

684
    if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=TIMEOUT\n", thread->id );
685
    end_wait( thread );
686
    if (send_thread_wakeup( thread, cookie, STATUS_TIMEOUT ) == -1) return;
687 688
    /* check if other objects have become signaled in the meantime */
    wake_thread( thread );
689 690
}

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
/* try signaling an event flag, a semaphore or a mutex */
static int signal_object( obj_handle_t handle )
{
    struct object *obj;
    int ret = 0;

    obj = get_handle_obj( current->process, handle, 0, NULL );
    if (obj)
    {
        ret = obj->ops->signal( obj, get_handle_access( current->process, handle ));
        release_object( obj );
    }
    return ret;
}

706
/* select on a list of handles */
707
static timeout_t select_on( unsigned int count, client_ptr_t cookie, const obj_handle_t *handles,
708
                            int flags, timeout_t timeout, obj_handle_t signal_obj )
Alexandre Julliard's avatar
Alexandre Julliard committed
709
{
710 711
    int ret;
    unsigned int i;
712
    struct object *objects[MAXIMUM_WAIT_OBJECTS];
713

714 715 716
    if (timeout <= 0) timeout = current_time - timeout;

    if (count > MAXIMUM_WAIT_OBJECTS)
717
    {
718
        set_error( STATUS_INVALID_PARAMETER );
719
        return 0;
720 721 722 723 724 725
    }
    for (i = 0; i < count; i++)
    {
        if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
            break;
    }
726 727

    if (i < count) goto done;
728
    if (!wait_on( count, objects, flags, timeout )) goto done;
729

730 731 732 733 734 735 736 737 738 739 740 741
    /* signal the object */
    if (signal_obj)
    {
        if (!signal_object( signal_obj ))
        {
            end_wait( current );
            goto done;
        }
        /* check if we woke ourselves up */
        if (!current->wait) goto done;
    }

742 743 744 745 746 747 748 749 750
    if ((ret = check_wait( current )) != -1)
    {
        /* condition is already satisfied */
        end_wait( current );
        set_error( ret );
        goto done;
    }

    /* now we need to wait */
751
    if (current->wait->timeout != TIMEOUT_INFINITE)
752
    {
753
        if (!(current->wait->user = add_timeout_user( current->wait->timeout,
754
                                                      thread_timeout, current->wait )))
755 756 757 758 759
        {
            end_wait( current );
            goto done;
        }
    }
760
    current->wait->cookie = cookie;
761 762 763
    set_error( STATUS_PENDING );

done:
764 765
    while (i > 0) release_object( objects[--i] );
    return timeout;
Alexandre Julliard's avatar
Alexandre Julliard committed
766 767 768 769 770
}

/* attempt to wake threads sleeping on the object wait queue */
void wake_up( struct object *obj, int max )
{
771
    struct list *ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
772

773
    LIST_FOR_EACH( ptr, &obj->wait_queue )
Alexandre Julliard's avatar
Alexandre Julliard committed
774
    {
775
        struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry );
776 777 778 779
        if (!wake_thread( entry->thread )) continue;
        if (max && !--max) break;
        /* restart at the head of the list since a wake up can change the object wait queue */
        ptr = &obj->wait_queue;
Alexandre Julliard's avatar
Alexandre Julliard committed
780 781 782
    }
}

783 784 785 786 787 788 789 790 791 792 793 794 795 796
/* return the apc queue to use for a given apc type */
static inline struct list *get_apc_queue( struct thread *thread, enum apc_type type )
{
    switch(type)
    {
    case APC_NONE:
    case APC_USER:
    case APC_TIMER:
        return &thread->user_apc;
    default:
        return &thread->system_apc;
    }
}

797 798 799 800 801 802 803
/* 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 ||
            (thread->wait && (thread->wait->flags & SELECT_INTERRUPTIBLE)));
}

804 805
/* queue an existing APC to a given thread */
static int queue_apc( struct process *process, struct thread *thread, struct thread_apc *apc )
806
{
807 808 809 810 811
    struct list *queue;

    if (!thread)  /* find a suitable thread inside the process */
    {
        struct thread *candidate;
812

813 814 815 816
        /* first try to find a waiting thread */
        LIST_FOR_EACH_ENTRY( candidate, &process->thread_list, struct thread, proc_entry )
        {
            if (candidate->state == TERMINATED) continue;
817
            if (is_in_apc_wait( candidate ))
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
            {
                thread = candidate;
                break;
            }
        }
        if (!thread)
        {
            /* then use the first one that accepts a signal */
            LIST_FOR_EACH_ENTRY( candidate, &process->thread_list, struct thread, proc_entry )
            {
                if (send_thread_signal( candidate, SIGUSR1 ))
                {
                    thread = candidate;
                    break;
                }
            }
        }
        if (!thread) return 0;  /* nothing found */
836
        queue = get_apc_queue( thread, apc->call.type );
837 838 839 840
    }
    else
    {
        if (thread->state == TERMINATED) return 0;
841 842 843 844 845 846
        queue = get_apc_queue( thread, apc->call.type );
        /* send signal for system APCs if needed */
        if (queue == &thread->system_apc && list_empty( queue ) && !is_in_apc_wait( thread ))
        {
            if (!send_thread_signal( thread, SIGUSR1 )) return 0;
        }
847 848 849
        /* cancel a possible previous APC with the same owner */
        if (apc->owner) thread_cancel_apc( thread, apc->owner, apc->call.type );
    }
850

851
    grab_object( apc );
852 853
    list_add_tail( queue, &apc->entry );
    if (!list_prev( queue, &apc->entry ))  /* first one */
854
        wake_thread( thread );
855

856 857 858
    return 1;
}

859 860 861 862 863 864 865 866 867 868 869 870 871 872
/* queue an async procedure call */
int thread_queue_apc( struct thread *thread, struct object *owner, const apc_call_t *call_data )
{
    struct thread_apc *apc;
    int ret = 0;

    if ((apc = create_apc( owner, call_data )))
    {
        ret = queue_apc( NULL, thread, apc );
        release_object( apc );
    }
    return ret;
}

873
/* cancel the async procedure call owned by a specific object */
874
void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type )
875 876
{
    struct thread_apc *apc;
877 878
    struct list *queue = get_apc_queue( thread, type );

879
    LIST_FOR_EACH_ENTRY( apc, queue, struct thread_apc, entry )
880 881
    {
        if (apc->owner != owner) continue;
882
        list_remove( &apc->entry );
883 884
        apc->executed = 1;
        wake_up( &apc->obj, 0 );
885
        release_object( apc );
886 887 888 889
        return;
    }
}

890
/* remove the head apc from the queue; the returned object must be released by the caller */
891
static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only )
892
{
893 894
    struct thread_apc *apc = NULL;
    struct list *ptr = list_head( &thread->system_apc );
895

896 897
    if (!ptr && !system_only) ptr = list_head( &thread->user_apc );
    if (ptr)
898
    {
899 900
        apc = LIST_ENTRY( ptr, struct thread_apc, entry );
        list_remove( ptr );
901 902 903 904
    }
    return apc;
}

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
/* clear an APC queue, cancelling all the APCs on it */
static void clear_apc_queue( struct list *queue )
{
    struct list *ptr;

    while ((ptr = list_head( queue )))
    {
        struct thread_apc *apc = LIST_ENTRY( ptr, struct thread_apc, entry );
        list_remove( &apc->entry );
        apc->executed = 1;
        wake_up( &apc->obj, 0 );
        release_object( apc );
    }
}

920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
/* add an fd to the inflight list */
/* return list index, or -1 on error */
int thread_add_inflight_fd( struct thread *thread, int client, int server )
{
    int i;

    if (server == -1) return -1;
    if (client == -1)
    {
        close( server );
        return -1;
    }

    /* first check if we already have an entry for this fd */
    for (i = 0; i < MAX_INFLIGHT_FDS; i++)
        if (thread->inflight[i].client == client)
        {
            close( thread->inflight[i].server );
            thread->inflight[i].server = server;
            return i;
        }

    /* now find a free spot to store it */
    for (i = 0; i < MAX_INFLIGHT_FDS; i++)
        if (thread->inflight[i].client == -1)
        {
            thread->inflight[i].client = client;
            thread->inflight[i].server = server;
            return i;
        }
    return -1;
}

/* get an inflight fd and purge it from the list */
/* the fd must be closed when no longer used */
int thread_get_inflight_fd( struct thread *thread, int client )
{
    int i, ret;

    if (client == -1) return -1;

    do
    {
        for (i = 0; i < MAX_INFLIGHT_FDS; i++)
        {
            if (thread->inflight[i].client == client)
            {
                ret = thread->inflight[i].server;
                thread->inflight[i].server = thread->inflight[i].client = -1;
                return ret;
            }
        }
    } while (!receive_fd( thread->process ));  /* in case it is still in the socket buffer */
    return -1;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
976
/* kill a thread on the spot */
977
void kill_thread( struct thread *thread, int violent_death )
Alexandre Julliard's avatar
Alexandre Julliard committed
978
{
Alexandre Julliard's avatar
Alexandre Julliard committed
979
    if (thread->state == TERMINATED) return;  /* already killed */
Alexandre Julliard's avatar
Alexandre Julliard committed
980
    thread->state = TERMINATED;
981
    thread->exit_time = current_time;
982
    if (current == thread) current = NULL;
983
    if (debug_level)
984 985
        fprintf( stderr,"%04x: *killed* exit_code=%d\n",
                 thread->id, thread->exit_code );
986 987
    if (thread->wait)
    {
988
        while (thread->wait) end_wait( thread );
989
        send_thread_wakeup( thread, 0, thread->exit_code );
990
        /* if it is waiting on the socket, we don't need to send a SIGQUIT */
991 992
        violent_death = 0;
    }
993
    kill_console_processes( thread, 0 );
994
    debug_exit_thread( thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
995
    abandon_mutexes( thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
996
    wake_up( &thread->obj, 0 );
997
    if (violent_death) send_thread_signal( thread, SIGQUIT );
998
    cleanup_thread( thread );
999
    remove_process_thread( thread->process, thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
1000
    release_object( thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
1001
}
1002

1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
/* copy parts of a context structure */
static void copy_context( context_t *to, const context_t *from, unsigned int flags )
{
    assert( to->cpu == from->cpu );
    to->flags |= flags;
    if (flags & SERVER_CTX_CONTROL) to->ctl = from->ctl;
    if (flags & SERVER_CTX_INTEGER) to->integer = from->integer;
    if (flags & SERVER_CTX_SEGMENTS) to->seg = from->seg;
    if (flags & SERVER_CTX_FLOATING_POINT) to->fp = from->fp;
    if (flags & SERVER_CTX_DEBUG_REGISTERS) to->debug = from->debug;
    if (flags & SERVER_CTX_EXTENDED_REGISTERS) to->ext = from->ext;
}

/* return the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
static unsigned int get_context_system_regs( enum cpu_type cpu )
{
    switch (cpu)
    {
    case CPU_x86:     return SERVER_CTX_DEBUG_REGISTERS;
    case CPU_x86_64:  return SERVER_CTX_DEBUG_REGISTERS;
    case CPU_POWERPC: return 0;
1025
    case CPU_ARM:     return 0;
1026 1027 1028 1029 1030
    case CPU_SPARC:   return 0;
    }
    return 0;
}

1031 1032 1033
/* trigger a breakpoint event in a given thread */
void break_thread( struct thread *thread )
{
1034
    debug_event_t data;
1035 1036 1037

    assert( thread->context );

1038 1039 1040 1041
    memset( &data, 0, sizeof(data) );
    data.exception.first     = 1;
    data.exception.exc_code  = STATUS_BREAKPOINT;
    data.exception.flags     = EXCEPTION_CONTINUABLE;
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
    switch (thread->context->cpu)
    {
    case CPU_x86:
        data.exception.address = thread->context->ctl.i386_regs.eip;
        break;
    case CPU_x86_64:
        data.exception.address = thread->context->ctl.x86_64_regs.rip;
        break;
    case CPU_POWERPC:
        data.exception.address = thread->context->ctl.powerpc_regs.iar;
        break;
    case CPU_SPARC:
        data.exception.address = thread->context->ctl.sparc_regs.pc;
        break;
1056 1057 1058
    case CPU_ARM:
        data.exception.address = thread->context->ctl.arm_regs.pc;
        break;
1059
    }
1060 1061 1062 1063
    generate_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data );
    thread->debug_break = 0;
}

1064 1065 1066 1067 1068 1069 1070
/* take a snapshot of currently running threads */
struct thread_snapshot *thread_snap( int *count )
{
    struct thread_snapshot *snapshot, *ptr;
    struct thread *thread;
    int total = 0;

1071
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
1072 1073 1074
        if (thread->state != TERMINATED) total++;
    if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL;
    ptr = snapshot;
1075
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
    {
        if (thread->state == TERMINATED) continue;
        ptr->thread   = thread;
        ptr->count    = thread->obj.refcount;
        ptr->priority = thread->priority;
        grab_object( thread );
        ptr++;
    }
    *count = total;
    return snapshot;
}

1088 1089 1090 1091 1092 1093 1094 1095 1096
/* gets the current impersonation token */
struct token *thread_get_impersonation_token( struct thread *thread )
{
    if (thread->token)
        return thread->token;
    else
        return thread->process->token;
}

1097 1098 1099
/* create a new thread */
DECL_HANDLER(new_thread)
{
1100
    struct thread *thread;
1101
    int request_fd = thread_get_inflight_fd( current, req->request_fd );
1102

1103
    if (request_fd == -1 || fcntl( request_fd, F_SETFL, O_NONBLOCK ) == -1)
1104
    {
1105
        if (request_fd != -1) close( request_fd );
1106 1107 1108 1109 1110 1111 1112
        set_error( STATUS_INVALID_HANDLE );
        return;
    }

    if ((thread = create_thread( request_fd, current->process )))
    {
        if (req->suspend) thread->suspend++;
1113
        reply->tid = get_thread_id( thread );
1114
        if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes )))
1115
        {
1116 1117
            /* thread object will be released when the thread gets killed */
            return;
1118
        }
1119
        kill_thread( thread, 1 );
1120 1121 1122 1123 1124 1125
    }
}

/* initialize a new thread */
DECL_HANDLER(init_thread)
{
1126
    unsigned int prefix_cpu_mask = get_prefix_cpu_mask();
1127
    struct process *process = current->process;
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
    int wait_fd, reply_fd;

    if ((reply_fd = thread_get_inflight_fd( current, req->reply_fd )) == -1)
    {
        set_error( STATUS_TOO_MANY_OPENED_FILES );
        return;
    }
    if ((wait_fd = thread_get_inflight_fd( current, req->wait_fd )) == -1)
    {
        set_error( STATUS_TOO_MANY_OPENED_FILES );
        goto error;
    }
1140

1141
    if (current->reply_fd)  /* already initialised */
1142
    {
1143
        set_error( STATUS_INVALID_PARAMETER );
1144 1145
        goto error;
    }
1146

1147
    if (fcntl( reply_fd, F_SETFL, O_NONBLOCK ) == -1) goto error;
1148

1149
    current->reply_fd = create_anonymous_fd( &thread_fd_ops, reply_fd, &current->obj, 0 );
1150 1151
    current->wait_fd  = create_anonymous_fd( &thread_fd_ops, wait_fd, &current->obj, 0 );
    if (!current->reply_fd || !current->wait_fd) return;
1152

1153
    if (!is_valid_address(req->teb))
1154 1155 1156 1157 1158
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }

1159
    current->unix_pid = req->unix_pid;
1160
    current->unix_tid = req->unix_tid;
1161
    current->teb      = req->teb;
1162

1163 1164
    if (!process->peb)  /* first thread, initialize the process too */
    {
1165
        if (!CPU_FLAG(req->cpu) || !(supported_cpus & prefix_cpu_mask & CPU_FLAG(req->cpu)))
1166
        {
1167 1168 1169 1170
            if (!(supported_cpus & CPU_64BIT_MASK))
                set_error( STATUS_NOT_SUPPORTED );
            else
                set_error( STATUS_NOT_REGISTRY_FILE );  /* server supports it but not the prefix */
1171 1172
            return;
        }
1173
        process->unix_pid = current->unix_pid;
1174
        process->peb      = req->entry;
1175
        process->cpu      = req->cpu;
1176
        reply->info_size  = init_process( current );
1177 1178 1179 1180
        if (!process->parent)
            process->affinity = current->affinity = get_thread_affinity( current );
        else
            set_thread_affinity( current, current->affinity );
1181 1182 1183
    }
    else
    {
1184 1185 1186 1187 1188
        if (req->cpu != process->cpu)
        {
            set_error( STATUS_INVALID_PARAMETER );
            return;
        }
1189 1190
        if (process->unix_pid != current->unix_pid)
            process->unix_pid = -1;  /* can happen with linuxthreads */
1191
        stop_thread_if_suspended( current );
1192
        generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, &req->entry );
1193
        set_thread_affinity( current, current->affinity );
1194 1195
    }
    debug_level = max( debug_level, req->debug_level );
1196

1197
    reply->pid     = get_process_id( process );
1198 1199
    reply->tid     = get_thread_id( current );
    reply->version = SERVER_PROTOCOL_VERSION;
1200
    reply->server_start = server_start_time;
1201
    reply->all_cpus     = supported_cpus & prefix_cpu_mask;
1202 1203 1204 1205 1206 1207 1208
    return;

 error:
    if (reply_fd != -1) close( reply_fd );
    if (wait_fd != -1) close( wait_fd );
}

1209 1210 1211 1212 1213
/* terminate a thread */
DECL_HANDLER(terminate_thread)
{
    struct thread *thread;

1214 1215
    reply->self = 0;
    reply->last = 0;
1216 1217
    if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
    {
1218 1219 1220 1221
        thread->exit_code = req->exit_code;
        if (thread != current) kill_thread( thread, 1 );
        else
        {
1222 1223
            reply->self = 1;
            reply->last = (thread->process->running_threads == 1);
1224
        }
1225 1226 1227 1228
        release_object( thread );
    }
}

1229 1230 1231 1232 1233 1234 1235 1236
/* open a handle to a thread */
DECL_HANDLER(open_thread)
{
    struct thread *thread = get_thread_from_id( req->tid );

    reply->handle = 0;
    if (thread)
    {
1237
        reply->handle = alloc_handle( current->process, thread, req->access, req->attributes );
1238 1239 1240 1241
        release_object( thread );
    }
}

1242 1243 1244 1245
/* fetch information about a thread */
DECL_HANDLER(get_thread_info)
{
    struct thread *thread;
1246
    obj_handle_t handle = req->handle;
1247

1248
    if (!handle) thread = get_thread_from_id( req->tid_in );
1249 1250 1251
    else thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION );

    if (thread)
1252
    {
1253
        reply->pid            = get_process_id( thread->process );
1254 1255
        reply->tid            = get_thread_id( thread );
        reply->teb            = thread->teb;
1256
        reply->exit_code      = (thread->state == TERMINATED) ? thread->exit_code : STATUS_PENDING;
1257
        reply->priority       = thread->priority;
1258
        reply->affinity       = thread->affinity;
1259 1260
        reply->creation_time  = thread->creation_time;
        reply->exit_time      = thread->exit_time;
1261
        reply->last           = thread->process->running_threads == 1;
1262

1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
        release_object( thread );
    }
}

/* set information about a thread */
DECL_HANDLER(set_thread_info)
{
    struct thread *thread;

    if ((thread = get_thread_from_handle( req->handle, THREAD_SET_INFORMATION )))
    {
        set_thread_info( thread, req );
        release_object( thread );
    }
}

/* suspend a thread */
DECL_HANDLER(suspend_thread)
{
    struct thread *thread;
1283

1284 1285
    if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
    {
1286
        if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED );
1287
        else reply->count = suspend_thread( thread );
1288 1289 1290 1291 1292 1293 1294 1295
        release_object( thread );
    }
}

/* resume a thread */
DECL_HANDLER(resume_thread)
{
    struct thread *thread;
1296

1297 1298
    if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
    {
1299
        reply->count = resume_thread( thread );
1300 1301 1302 1303 1304 1305 1306
        release_object( thread );
    }
}

/* select on a handle list */
DECL_HANDLER(select)
{
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
    struct thread_apc *apc;
    unsigned int count;
    const apc_result_t *result = get_req_data();
    const obj_handle_t *handles = (const obj_handle_t *)(result + 1);

    if (get_req_data_size() < sizeof(*result))
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
    count = (get_req_data_size() - sizeof(*result)) / sizeof(obj_handle_t);

    /* first store results of previous apc */
    if (req->prev_apc)
    {
        if (!(apc = (struct thread_apc *)get_handle_obj( current->process, req->prev_apc,
                                                         0, &thread_apc_ops ))) return;
        apc->result = *result;
        apc->executed = 1;
        if (apc->result.type == APC_CREATE_THREAD)  /* transfer the handle to the caller process */
        {
            obj_handle_t handle = duplicate_handle( current->process, apc->result.create_thread.handle,
                                                    apc->caller->process, 0, 0, DUP_HANDLE_SAME_ACCESS );
            close_handle( current->process, apc->result.create_thread.handle );
            apc->result.create_thread.handle = handle;
            clear_error();  /* ignore errors from the above calls */
        }
        else if (apc->result.type == APC_ASYNC_IO)
        {
1336 1337 1338
            if (apc->owner)
                async_set_result( apc->owner, apc->result.async_io.status,
                                  apc->result.async_io.total, apc->result.async_io.apc );
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
        }
        wake_up( &apc->obj, 0 );
        close_handle( current->process, req->prev_apc );
        release_object( apc );
    }

    reply->timeout = select_on( count, req->cookie, handles, req->flags, req->timeout, req->signal );

    if (get_error() == STATUS_USER_APC)
    {
        for (;;)
        {
            if (!(apc = thread_dequeue_apc( current, !(req->flags & SELECT_ALERTABLE) )))
                break;
            /* Optimization: ignore APC_NONE calls, they are only used to
             * wake up a thread, but since we got here the thread woke up already.
             */
            if (apc->call.type != APC_NONE)
            {
                if ((reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 )))
                    reply->call = apc->call;
                release_object( apc );
                break;
            }
            apc->executed = 1;
            wake_up( &apc->obj, 0 );
            release_object( apc );
        }
    }
1368 1369
}

1370
/* queue an APC for a thread or process */
1371 1372
DECL_HANDLER(queue_apc)
{
1373 1374
    struct thread *thread = NULL;
    struct process *process = NULL;
1375 1376 1377 1378 1379
    struct thread_apc *apc;

    if (!(apc = create_apc( NULL, &req->call ))) return;

    switch (apc->call.type)
1380
    {
1381 1382
    case APC_NONE:
    case APC_USER:
1383
        thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT );
1384 1385 1386
        break;
    case APC_VIRTUAL_ALLOC:
    case APC_VIRTUAL_FREE:
1387
    case APC_VIRTUAL_PROTECT:
1388
    case APC_VIRTUAL_FLUSH:
1389 1390
    case APC_VIRTUAL_LOCK:
    case APC_VIRTUAL_UNLOCK:
1391
    case APC_UNMAP_VIEW:
1392
        process = get_process_from_handle( req->handle, PROCESS_VM_OPERATION );
1393 1394
        break;
    case APC_VIRTUAL_QUERY:
1395
        process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION );
1396
        break;
1397
    case APC_MAP_VIEW:
1398
        process = get_process_from_handle( req->handle, PROCESS_VM_OPERATION );
1399
        if (process && process != current->process)
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
        {
            /* duplicate the handle into the target process */
            obj_handle_t handle = duplicate_handle( current->process, apc->call.map_view.handle,
                                                    process, 0, 0, DUP_HANDLE_SAME_ACCESS );
            if (handle) apc->call.map_view.handle = handle;
            else
            {
                release_object( process );
                process = NULL;
            }
        }
        break;
1412
    case APC_CREATE_THREAD:
1413
        process = get_process_from_handle( req->handle, PROCESS_CREATE_THREAD );
1414 1415 1416 1417
        break;
    default:
        set_error( STATUS_INVALID_PARAMETER );
        break;
1418
    }
1419 1420 1421 1422 1423 1424 1425 1426

    if (thread)
    {
        if (!queue_apc( NULL, thread, apc )) set_error( STATUS_THREAD_IS_TERMINATING );
        release_object( thread );
    }
    else if (process)
    {
1427 1428
        reply->self = (process == current->process);
        if (!reply->self)
1429
        {
1430 1431
            obj_handle_t handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 );
            if (handle)
1432
            {
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
                if (queue_apc( process, NULL, apc ))
                {
                    apc->caller = (struct thread *)grab_object( current );
                    reply->handle = handle;
                }
                else
                {
                    close_handle( current->process, handle );
                    set_error( STATUS_PROCESS_IS_TERMINATING );
                }
1443 1444 1445 1446 1447
            }
        }
        release_object( process );
    }

1448
    release_object( apc );
1449
}
1450

1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
/* Get the result of an APC call */
DECL_HANDLER(get_apc_result)
{
    struct thread_apc *apc;

    if (!(apc = (struct thread_apc *)get_handle_obj( current->process, req->handle,
                                                     0, &thread_apc_ops ))) return;
    if (!apc->executed) set_error( STATUS_PENDING );
    else
    {
        reply->result = apc->result;
        /* close the handle directly to avoid an extra round-trip */
        close_handle( current->process, req->handle );
    }
    release_object( apc );
}

1468 1469 1470 1471
/* retrieve the current context of a thread */
DECL_HANDLER(get_thread_context)
{
    struct thread *thread;
1472
    context_t *context;
1473

1474
    if (get_reply_max_size() < sizeof(context_t))
1475 1476 1477 1478 1479
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
    if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
1480
    reply->self = (thread == current);
1481

1482
    if (thread != current && !thread->context)
1483 1484
    {
        /* thread is not suspended, retry (if it's still running) */
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
        if (thread->state == RUNNING)
        {
            set_error( STATUS_PENDING );
            if (req->suspend)
            {
                release_object( thread );
                /* make sure we have suspend access */
                if (!(thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) return;
                suspend_thread( thread );
            }
        }
1496
        else set_error( STATUS_UNSUCCESSFUL );
1497
    }
1498
    else if ((context = set_reply_data_size( sizeof(context_t) )))
1499
    {
1500
        unsigned int flags = get_context_system_regs( thread->process->cpu );
1501

1502 1503
        memset( context, 0, sizeof(context_t) );
        context->cpu = thread->process->cpu;
1504 1505
        if (thread->context) copy_context( context, thread->context, req->flags & ~flags );
        if (flags) get_thread_context( thread, context, flags );
1506 1507 1508 1509 1510 1511 1512 1513
    }
    release_object( thread );
}

/* set the current context of a thread */
DECL_HANDLER(set_thread_context)
{
    struct thread *thread;
1514
    const context_t *context = get_req_data();
1515

1516
    if (get_req_data_size() < sizeof(context_t))
1517 1518 1519 1520
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
1521
    if (!(thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) return;
1522
    reply->self = (thread == current);
1523

1524
    if (thread != current && !thread->context)
1525 1526
    {
        /* thread is not suspended, retry (if it's still running) */
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
        if (thread->state == RUNNING)
        {
            set_error( STATUS_PENDING );
            if (req->suspend)
            {
                release_object( thread );
                /* make sure we have suspend access */
                if (!(thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) return;
                suspend_thread( thread );
            }
        }
1538
        else set_error( STATUS_UNSUCCESSFUL );
1539
    }
1540
    else if (context->cpu == thread->process->cpu)
1541
    {
1542 1543
        unsigned int system_flags = get_context_system_regs(context->cpu) & context->flags;
        unsigned int client_flags = context->flags & ~system_flags;
1544

1545 1546
        if (system_flags) set_thread_context( thread, context, system_flags );
        if (thread->context && !get_error()) copy_context( thread->context, context, client_flags );
1547
    }
1548 1549
    else set_error( STATUS_INVALID_PARAMETER );

1550
    release_object( thread );
1551 1552
}

1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
/* retrieve the suspended context of a thread */
DECL_HANDLER(get_suspend_context)
{
    if (get_reply_max_size() < sizeof(context_t))
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }

    if (current->suspend_context)
    {
        set_reply_data_ptr( current->suspend_context, sizeof(context_t) );
1565 1566 1567 1568 1569
        if (current->context == current->suspend_context)
        {
            current->context = NULL;
            stop_thread_if_suspended( current );
        }
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
        current->suspend_context = NULL;
    }
    else set_error( STATUS_INVALID_PARAMETER );  /* not suspended, shouldn't happen */
}

/* store the suspended context of a thread */
DECL_HANDLER(set_suspend_context)
{
    const context_t *context = get_req_data();

    if (get_req_data_size() < sizeof(context_t))
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }

    if (current->context || context->cpu != current->process->cpu)
    {
        /* nested suspend or exception, shouldn't happen */
        set_error( STATUS_INVALID_PARAMETER );
    }
    else if ((current->suspend_context = mem_alloc( sizeof(context_t) )))
    {
        memcpy( current->suspend_context, get_req_data(), sizeof(context_t) );
        current->context = current->suspend_context;
        if (current->debug_break) break_thread( current );
    }
}

1599 1600 1601 1602 1603 1604
/* fetch a selector entry for a thread */
DECL_HANDLER(get_selector_entry)
{
    struct thread *thread;
    if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
    {
1605
        get_selector_entry( thread, req->entry, &reply->base, &reply->limit, &reply->flags );
1606 1607 1608
        release_object( thread );
    }
}