thread.c 44 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
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39 40
#include "ntstatus.h"
#define WIN32_NO_STATUS
41
#include "windef.h"
42
#include "winternl.h"
43

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


Alexandre Julliard's avatar
Alexandre Julliard committed
53 54 55 56
/* thread queues */

struct thread_wait
{
57 58
    struct thread_wait     *next;       /* next wait structure for this thread */
    struct thread          *thread;     /* owner thread */
Alexandre Julliard's avatar
Alexandre Julliard committed
59 60
    int                     count;      /* count of objects */
    int                     flags;
61
    void                   *cookie;     /* magic cookie to return to client */
62
    timeout_t               timeout;
63
    struct timeout_user    *user;
Alexandre Julliard's avatar
Alexandre Julliard committed
64 65 66
    struct wait_queue_entry queues[1];
};

67 68 69 70
/* asynchronous procedure calls */

struct thread_apc
{
71
    struct object       obj;      /* object header */
72
    struct list         entry;    /* queue linked list */
73
    struct thread      *caller;   /* thread that queued this apc */
74
    struct object      *owner;    /* object that queued this apc */
75
    int                 executed; /* has it been executed by the client? */
76 77
    apc_call_t          call;     /* call arguments */
    apc_result_t        result;   /* call results once executed */
78 79
};

80 81
static void dump_thread_apc( struct object *obj, int verbose );
static int thread_apc_signaled( struct object *obj, struct thread *thread );
82
static void thread_apc_destroy( struct object *obj );
83
static void clear_apc_queue( struct list *queue );
84 85 86 87 88

static const struct object_ops thread_apc_ops =
{
    sizeof(struct thread_apc),  /* size */
    dump_thread_apc,            /* dump */
89
    no_get_type,                /* get_type */
90 91 92 93 94 95 96
    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 */
97 98
    default_get_sd,             /* get_sd */
    default_set_sd,             /* set_sd */
99
    no_lookup_name,             /* lookup_name */
100
    no_open_file,               /* open_file */
101
    no_close_handle,            /* close_handle */
102
    thread_apc_destroy          /* destroy */
103 104
};

Alexandre Julliard's avatar
Alexandre Julliard committed
105

Alexandre Julliard's avatar
Alexandre Julliard committed
106 107
/* thread operations */

Alexandre Julliard's avatar
Alexandre Julliard committed
108
static void dump_thread( struct object *obj, int verbose );
Alexandre Julliard's avatar
Alexandre Julliard committed
109
static int thread_signaled( struct object *obj, struct thread *thread );
110
static unsigned int thread_map_access( struct object *obj, unsigned int access );
111
static void thread_poll_event( struct fd *fd, int event );
Alexandre Julliard's avatar
Alexandre Julliard committed
112 113 114 115
static void destroy_thread( struct object *obj );

static const struct object_ops thread_ops =
{
116 117
    sizeof(struct thread),      /* size */
    dump_thread,                /* dump */
118
    no_get_type,                /* get_type */
119 120 121 122
    add_queue,                  /* add_queue */
    remove_queue,               /* remove_queue */
    thread_signaled,            /* signaled */
    no_satisfied,               /* satisfied */
123
    no_signal,                  /* signal */
124
    no_get_fd,                  /* get_fd */
125
    thread_map_access,          /* map_access */
126 127
    default_get_sd,             /* get_sd */
    default_set_sd,             /* set_sd */
128
    no_lookup_name,             /* lookup_name */
129
    no_open_file,               /* open_file */
130
    no_close_handle,            /* close_handle */
131 132 133 134 135
    destroy_thread              /* destroy */
};

static const struct fd_ops thread_fd_ops =
{
136 137
    NULL,                       /* get_poll_events */
    thread_poll_event,          /* poll_event */
138 139
    NULL,                       /* flush */
    NULL,                       /* get_fd_type */
140
    NULL,                       /* ioctl */
141
    NULL,                       /* queue_async */
142
    NULL,                       /* reselect_async */
143
    NULL                        /* cancel_async */
Alexandre Julliard's avatar
Alexandre Julliard committed
144 145
};

146
static struct list thread_list = LIST_INIT(thread_list);
Alexandre Julliard's avatar
Alexandre Julliard committed
147

148
/* initialize the structure for a newly allocated thread */
149
static inline void init_thread_structure( struct thread *thread )
150 151 152
{
    int i;

153
    thread->unix_pid        = -1;  /* not known yet */
154
    thread->unix_tid        = -1;  /* not known yet */
155
    thread->context         = NULL;
156
    thread->suspend_context = NULL;
157 158 159
    thread->teb             = NULL;
    thread->debug_ctx       = NULL;
    thread->debug_event     = NULL;
160
    thread->debug_break     = 0;
161 162 163
    thread->queue           = NULL;
    thread->wait            = NULL;
    thread->error           = 0;
164 165 166 167
    thread->req_data        = NULL;
    thread->req_toread      = 0;
    thread->reply_data      = NULL;
    thread->reply_towrite   = 0;
168 169 170
    thread->request_fd      = NULL;
    thread->reply_fd        = NULL;
    thread->wait_fd         = NULL;
171 172
    thread->state           = RUNNING;
    thread->exit_code       = 0;
173
    thread->priority        = 0;
174 175
    thread->affinity        = 1;
    thread->suspend         = 0;
176
    thread->desktop_users   = 0;
177
    thread->token           = NULL;
178

179
    thread->creation_time = current_time;
180
    thread->exit_time     = 0;
181

182
    list_init( &thread->mutex_list );
183 184 185
    list_init( &thread->system_apc );
    list_init( &thread->user_apc );

186 187 188 189
    for (i = 0; i < MAX_INFLIGHT_FDS; i++)
        thread->inflight[i].server = thread->inflight[i].client = -1;
}

190 191 192
/* check if address looks valid for a client-side data structure (TEB etc.) */
static inline int is_valid_address( void *addr )
{
193
    return addr && !((unsigned long)addr % sizeof(int));
194 195
}

196
/* create a new thread */
197
struct thread *create_thread( int fd, struct process *process )
198 199 200
{
    struct thread *thread;

201
    if (!(thread = alloc_object( &thread_ops ))) return NULL;
202

203
    init_thread_structure( thread );
204

205
    thread->process = (struct process *)grab_object( process );
206
    thread->desktop = process->desktop;
207 208
    if (!current) current = thread;

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

211 212 213 214 215
    if (!(thread->id = alloc_ptid( thread )))
    {
        release_object( thread );
        return NULL;
    }
216
    if (!(thread->request_fd = create_anonymous_fd( &thread_fd_ops, fd, &thread->obj, 0 )))
217 218 219 220
    {
        release_object( thread );
        return NULL;
    }
221

222
    set_fd_events( thread->request_fd, POLLIN );  /* start listening to events */
223
    add_process_thread( thread->process, thread );
224
    return thread;
Alexandre Julliard's avatar
Alexandre Julliard committed
225 226
}

227
/* handle a client event */
228
static void thread_poll_event( struct fd *fd, int event )
229
{
230 231
    struct thread *thread = get_fd_user( fd );
    assert( thread->obj.ops == &thread_ops );
232

233
    if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
234
    else if (event & POLLIN) read_request( thread );
235
    else if (event & POLLOUT) write_reply( thread );
236 237 238 239 240 241 242 243
}

/* 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;

244 245
    clear_apc_queue( &thread->system_apc );
    clear_apc_queue( &thread->user_apc );
246 247
    free( thread->req_data );
    free( thread->reply_data );
248 249 250
    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 );
251
    free( thread->suspend_context );
252
    free_msg_queue( thread );
253
    cleanup_clipboard_thread(thread);
254
    destroy_thread_windows( thread );
255
    close_thread_desktop( thread );
256 257 258 259 260 261 262 263
    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;
        }
    }
264 265
    thread->req_data = NULL;
    thread->reply_data = NULL;
266 267 268
    thread->request_fd = NULL;
    thread->reply_fd = NULL;
    thread->wait_fd = NULL;
269 270
    thread->context = NULL;
    thread->suspend_context = NULL;
271
    thread->desktop = 0;
272 273
}

Alexandre Julliard's avatar
Alexandre Julliard committed
274 275 276 277 278 279
/* 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 );

280
    assert( !thread->debug_ctx );  /* cannot still be debugging something */
281
    list_remove( &thread->entry );
282
    cleanup_thread( thread );
283
    release_object( thread->process );
284
    if (thread->id) free_ptid( thread->id );
285
    if (thread->token) release_object( thread->token );
Alexandre Julliard's avatar
Alexandre Julliard committed
286 287
}

Alexandre Julliard's avatar
Alexandre Julliard committed
288 289 290 291 292 293
/* 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 );

294 295
    fprintf( stderr, "Thread id=%04x unix pid=%d unix tid=%d teb=%p state=%d\n",
             thread->id, thread->unix_pid, thread->unix_tid, thread->teb, thread->state );
Alexandre Julliard's avatar
Alexandre Julliard committed
296 297
}

Alexandre Julliard's avatar
Alexandre Julliard committed
298 299 300 301 302 303
static int thread_signaled( struct object *obj, struct thread *thread )
{
    struct thread *mythread = (struct thread *)obj;
    return (mythread->state == TERMINATED);
}

304 305 306 307 308 309 310 311 312
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);
}

313 314 315 316 317
static void dump_thread_apc( struct object *obj, int verbose )
{
    struct thread_apc *apc = (struct thread_apc *)obj;
    assert( obj->ops == &thread_apc_ops );

318
    fprintf( stderr, "APC owner=%p type=%u\n", apc->owner, apc->call.type );
319 320 321 322
}

static int thread_apc_signaled( struct object *obj, struct thread *thread )
{
323 324
    struct thread_apc *apc = (struct thread_apc *)obj;
    return apc->executed;
325 326
}

327 328 329 330
static void thread_apc_destroy( struct object *obj )
{
    struct thread_apc *apc = (struct thread_apc *)obj;
    if (apc->caller) release_object( apc->caller );
331
    if (apc->owner) release_object( apc->owner );
332 333
}

334 335 336 337 338 339 340 341
/* 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;
342
        apc->caller      = NULL;
343 344 345
        apc->owner       = owner;
        apc->executed    = 0;
        apc->result.type = APC_NONE;
346
        if (owner) grab_object( owner );
347 348 349 350
    }
    return apc;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
351
/* get a thread pointer from a thread id (and increment the refcount) */
352
struct thread *get_thread_from_id( thread_id_t id )
Alexandre Julliard's avatar
Alexandre Julliard committed
353
{
354 355 356
    struct object *obj = get_ptid_entry( id );

    if (obj && obj->ops == &thread_ops) return (struct thread *)grab_object( obj );
357
    set_error( STATUS_INVALID_CID );
358
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
359 360
}

Alexandre Julliard's avatar
Alexandre Julliard committed
361
/* get a thread from a handle (and increment the refcount) */
362
struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access )
Alexandre Julliard's avatar
Alexandre Julliard committed
363
{
Alexandre Julliard's avatar
Alexandre Julliard committed
364 365
    return (struct thread *)get_handle_obj( current->process, handle,
                                            access, &thread_ops );
Alexandre Julliard's avatar
Alexandre Julliard committed
366 367
}

368 369
/* find a thread from a Unix tid */
struct thread *get_thread_from_tid( int tid )
370
{
371
    struct thread *thread;
372

373 374
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
    {
375
        if (thread->unix_tid == tid) return thread;
376
    }
377 378 379 380 381 382 383 384
    return NULL;
}

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

385 386 387 388
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
    {
        if (thread->unix_pid == pid) return thread;
    }
389
    return NULL;
390 391
}

392 393 394
#define THREAD_PRIORITY_REALTIME_HIGHEST 6
#define THREAD_PRIORITY_REALTIME_LOWEST -7

395
/* set all information about a thread */
396
static void set_thread_info( struct thread *thread,
397
                             const struct set_thread_info_request *req )
398 399
{
    if (req->mask & SET_THREAD_INFO_PRIORITY)
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
    {
        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 );
    }
415 416
    if (req->mask & SET_THREAD_INFO_AFFINITY)
    {
417
        if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
418 419
        else thread->affinity = req->affinity;
    }
420 421
    if (req->mask & SET_THREAD_INFO_TOKEN)
        security_set_thread_token( thread, req->token );
422 423
}

424 425 426
/* stop a thread (at the Unix level) */
void stop_thread( struct thread *thread )
{
427
    if (thread->context) return;  /* already inside a debug event, no need for a signal */
428 429 430 431
    /* can't stop a thread while initialisation is in progress */
    if (is_process_init_done(thread->process)) send_thread_signal( thread, SIGUSR1 );
}

432
/* suspend a thread */
433
static int suspend_thread( struct thread *thread )
434 435
{
    int old_count = thread->suspend;
436
    if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
437
    {
438
        if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
439
    }
440
    else set_error( STATUS_SUSPEND_COUNT_EXCEEDED );
441 442 443 444
    return old_count;
}

/* resume a thread */
445
static int resume_thread( struct thread *thread )
446 447 448 449
{
    int old_count = thread->suspend;
    if (thread->suspend > 0)
    {
450
        if (!(--thread->suspend + thread->process->suspend)) wake_thread( thread );
451 452
    }
    return old_count;
Alexandre Julliard's avatar
Alexandre Julliard committed
453 454 455
}

/* add a thread to an object wait queue; return 1 if OK, 0 on error */
456
int add_queue( struct object *obj, struct wait_queue_entry *entry )
Alexandre Julliard's avatar
Alexandre Julliard committed
457
{
458
    grab_object( obj );
459 460
    entry->obj = obj;
    list_add_tail( &obj->wait_queue, &entry->entry );
461
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
462 463 464
}

/* remove a thread from an object wait queue */
465
void remove_queue( struct object *obj, struct wait_queue_entry *entry )
Alexandre Julliard's avatar
Alexandre Julliard committed
466
{
467
    list_remove( &entry->entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
468 469 470 471 472 473 474 475 476 477 478
    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 );
479
    thread->wait = wait->next;
480 481
    for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
        entry->obj->ops->remove_queue( entry->obj, entry );
482
    if (wait->user) remove_timeout_user( wait->user );
Alexandre Julliard's avatar
Alexandre Julliard committed
483 484 485 486
    free( wait );
}

/* build the thread wait structure */
487
static int wait_on( unsigned int count, struct object *objects[], int flags, timeout_t timeout )
Alexandre Julliard's avatar
Alexandre Julliard committed
488 489 490
{
    struct thread_wait *wait;
    struct wait_queue_entry *entry;
491
    unsigned int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
492

493
    if (!(wait = mem_alloc( FIELD_OFFSET(struct thread_wait, queues[count]) ))) return 0;
494 495
    wait->next    = current->wait;
    wait->thread  = current;
Alexandre Julliard's avatar
Alexandre Julliard committed
496 497
    wait->count   = count;
    wait->flags   = flags;
498
    wait->user    = NULL;
499
    wait->timeout = timeout;
500
    current->wait = wait;
Alexandre Julliard's avatar
Alexandre Julliard committed
501 502 503

    for (i = 0, entry = wait->queues; i < count; i++, entry++)
    {
504 505
        struct object *obj = objects[i];
        entry->thread = current;
506 507
        if (!obj->ops->add_queue( obj, entry ))
        {
508 509
            wait->count = i;
            end_wait( current );
510 511
            return 0;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
512 513 514 515 516
    }
    return 1;
}

/* check if the thread waiting condition is satisfied */
517
static int check_wait( struct thread *thread )
Alexandre Julliard's avatar
Alexandre Julliard committed
518
{
519
    int i, signaled;
Alexandre Julliard's avatar
Alexandre Julliard committed
520 521 522
    struct thread_wait *wait = thread->wait;
    struct wait_queue_entry *entry = wait->queues;

523 524 525 526 527
    assert( wait );

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
531 532
    if (wait->flags & SELECT_ALL)
    {
533 534 535
        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
536
        for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
537 538
            not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
        if (not_ok) goto other_checks;
Alexandre Julliard's avatar
Alexandre Julliard committed
539
        /* Wait satisfied: tell it to all objects */
540
        signaled = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
541 542
        for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
            if (entry->obj->ops->satisfied( entry->obj, thread ))
543 544
                signaled = STATUS_ABANDONED_WAIT_0;
        return signaled;
Alexandre Julliard's avatar
Alexandre Julliard committed
545 546 547 548 549 550 551
    }
    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 */
552
            signaled = i;
Alexandre Julliard's avatar
Alexandre Julliard committed
553
            if (entry->obj->ops->satisfied( entry->obj, thread ))
554 555
                signaled = i + STATUS_ABANDONED_WAIT_0;
            return signaled;
Alexandre Julliard's avatar
Alexandre Julliard committed
556 557
        }
    }
558 559

 other_checks:
560
    if ((wait->flags & SELECT_ALERTABLE) && !list_empty(&thread->user_apc)) return STATUS_USER_APC;
561
    if (wait->timeout <= current_time) return STATUS_TIMEOUT;
562 563 564
    return -1;
}

565 566 567 568 569 570 571 572
/* send the wakeup signal to a thread */
static int send_thread_wakeup( struct thread *thread, void *cookie, int signaled )
{
    struct wake_up_reply reply;
    int ret;

    reply.cookie   = cookie;
    reply.signaled = signaled;
573 574
    if ((ret = write( get_unix_fd( thread->wait_fd ), &reply, sizeof(reply) )) == sizeof(reply))
        return 0;
575 576 577 578 579 580 581 582 583
    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
584
/* attempt to wake up a thread */
585
/* return >0 if OK, 0 if the wait condition is still not satisfied */
586
int wake_thread( struct thread *thread )
Alexandre Julliard's avatar
Alexandre Julliard committed
587
{
588 589
    int signaled, count;
    void *cookie;
590

591 592 593 594 595
    for (count = 0; thread->wait; count++)
    {
        if ((signaled = check_wait( thread )) == -1) break;

        cookie = thread->wait->cookie;
596 597
        if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d cookie=%p\n",
                                  thread->id, signaled, cookie );
598
        end_wait( thread );
599 600
        if (send_thread_wakeup( thread, cookie, signaled ) == -1) /* error */
	    break;
601 602
    }
    return count;
Alexandre Julliard's avatar
Alexandre Julliard committed
603 604
}

605 606 607
/* thread wait timeout */
static void thread_timeout( void *ptr )
{
608 609 610
    struct thread_wait *wait = ptr;
    struct thread *thread = wait->thread;
    void *cookie = wait->cookie;
611

612 613
    wait->user = NULL;
    if (thread->wait != wait) return; /* not the top-level wait, ignore it */
614
    if (thread->suspend + thread->process->suspend > 0) return;  /* suspended, ignore it */
615

616
    if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d cookie=%p\n",
617
                              thread->id, (int)STATUS_TIMEOUT, cookie );
618
    end_wait( thread );
619
    if (send_thread_wakeup( thread, cookie, STATUS_TIMEOUT ) == -1) return;
620 621
    /* check if other objects have become signaled in the meantime */
    wake_thread( thread );
622 623
}

624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
/* 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;
}

639
/* select on a list of handles */
640 641
static timeout_t select_on( unsigned int count, void *cookie, const obj_handle_t *handles,
                            int flags, timeout_t timeout, obj_handle_t signal_obj )
Alexandre Julliard's avatar
Alexandre Julliard committed
642
{
643 644
    int ret;
    unsigned int i;
645
    struct object *objects[MAXIMUM_WAIT_OBJECTS];
646

647 648 649
    if (timeout <= 0) timeout = current_time - timeout;

    if (count > MAXIMUM_WAIT_OBJECTS)
650
    {
651
        set_error( STATUS_INVALID_PARAMETER );
652
        return 0;
653 654 655 656 657 658
    }
    for (i = 0; i < count; i++)
    {
        if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
            break;
    }
659 660

    if (i < count) goto done;
661
    if (!wait_on( count, objects, flags, timeout )) goto done;
662

663 664 665 666 667 668 669 670 671 672 673 674
    /* 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;
    }

675 676 677 678 679 680 681 682 683
    if ((ret = check_wait( current )) != -1)
    {
        /* condition is already satisfied */
        end_wait( current );
        set_error( ret );
        goto done;
    }

    /* now we need to wait */
684
    if (current->wait->timeout != TIMEOUT_INFINITE)
685
    {
686
        if (!(current->wait->user = add_timeout_user( current->wait->timeout,
687
                                                      thread_timeout, current->wait )))
688 689 690 691 692
        {
            end_wait( current );
            goto done;
        }
    }
693
    current->wait->cookie = cookie;
694 695 696
    set_error( STATUS_PENDING );

done:
697 698
    while (i > 0) release_object( objects[--i] );
    return timeout;
Alexandre Julliard's avatar
Alexandre Julliard committed
699 700 701 702 703
}

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

706
    LIST_FOR_EACH_SAFE( ptr, next, &obj->wait_queue )
Alexandre Julliard's avatar
Alexandre Julliard committed
707
    {
708 709
        struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry );
        if (wake_thread( entry->thread ))
Alexandre Julliard's avatar
Alexandre Julliard committed
710 711 712 713 714 715
        {
            if (max && !--max) break;
        }
    }
}

716 717 718 719 720 721 722 723 724 725 726 727 728 729
/* 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;
    }
}

730 731 732 733 734 735 736
/* 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)));
}

737 738
/* queue an existing APC to a given thread */
static int queue_apc( struct process *process, struct thread *thread, struct thread_apc *apc )
739
{
740 741 742 743 744
    struct list *queue;

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

746 747 748 749
        /* first try to find a waiting thread */
        LIST_FOR_EACH_ENTRY( candidate, &process->thread_list, struct thread, proc_entry )
        {
            if (candidate->state == TERMINATED) continue;
750
            if (is_in_apc_wait( candidate ))
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
            {
                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 */
769
        queue = get_apc_queue( thread, apc->call.type );
770 771 772 773
    }
    else
    {
        if (thread->state == TERMINATED) return 0;
774 775 776 777 778 779
        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;
        }
780 781 782
        /* cancel a possible previous APC with the same owner */
        if (apc->owner) thread_cancel_apc( thread, apc->owner, apc->call.type );
    }
783

784
    grab_object( apc );
785 786
    list_add_tail( queue, &apc->entry );
    if (!list_prev( queue, &apc->entry ))  /* first one */
787
        wake_thread( thread );
788

789 790 791
    return 1;
}

792 793 794 795 796 797 798 799 800 801 802 803 804 805
/* 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;
}

806
/* cancel the async procedure call owned by a specific object */
807
void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type )
808 809
{
    struct thread_apc *apc;
810 811
    struct list *queue = get_apc_queue( thread, type );

812
    LIST_FOR_EACH_ENTRY( apc, queue, struct thread_apc, entry )
813 814
    {
        if (apc->owner != owner) continue;
815
        list_remove( &apc->entry );
816 817
        apc->executed = 1;
        wake_up( &apc->obj, 0 );
818
        release_object( apc );
819 820 821 822
        return;
    }
}

823
/* remove the head apc from the queue; the returned object must be released by the caller */
824
static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only )
825
{
826 827
    struct thread_apc *apc = NULL;
    struct list *ptr = list_head( &thread->system_apc );
828

829 830
    if (!ptr && !system_only) ptr = list_head( &thread->user_apc );
    if (ptr)
831
    {
832 833
        apc = LIST_ENTRY( ptr, struct thread_apc, entry );
        list_remove( ptr );
834 835 836 837
    }
    return apc;
}

838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
/* 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 );
    }
}

853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
/* 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
909
/* kill a thread on the spot */
910
void kill_thread( struct thread *thread, int violent_death )
Alexandre Julliard's avatar
Alexandre Julliard committed
911
{
Alexandre Julliard's avatar
Alexandre Julliard committed
912
    if (thread->state == TERMINATED) return;  /* already killed */
Alexandre Julliard's avatar
Alexandre Julliard committed
913
    thread->state = TERMINATED;
914
    thread->exit_time = current_time;
915
    if (current == thread) current = NULL;
916
    if (debug_level)
917 918
        fprintf( stderr,"%04x: *killed* exit_code=%d\n",
                 thread->id, thread->exit_code );
919 920
    if (thread->wait)
    {
921 922
        while (thread->wait) end_wait( thread );
        send_thread_wakeup( thread, NULL, STATUS_PENDING );
923
        /* if it is waiting on the socket, we don't need to send a SIGQUIT */
924 925
        violent_death = 0;
    }
926
    kill_console_processes( thread, 0 );
927
    debug_exit_thread( thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
928
    abandon_mutexes( thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
929
    wake_up( &thread->obj, 0 );
930
    if (violent_death) send_thread_signal( thread, SIGQUIT );
931
    cleanup_thread( thread );
932
    remove_process_thread( thread->process, thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
933
    release_object( thread );
Alexandre Julliard's avatar
Alexandre Julliard committed
934
}
935

936 937 938 939 940 941 942
/* trigger a breakpoint event in a given thread */
void break_thread( struct thread *thread )
{
    struct debug_event_exception data;

    assert( thread->context );

943
    data.record.ExceptionCode    = STATUS_BREAKPOINT;
944 945 946 947 948 949 950 951 952
    data.record.ExceptionFlags   = EXCEPTION_CONTINUABLE;
    data.record.ExceptionRecord  = NULL;
    data.record.ExceptionAddress = get_context_ip( thread->context );
    data.record.NumberParameters = 0;
    data.first = 1;
    generate_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data );
    thread->debug_break = 0;
}

953 954 955 956 957 958 959
/* 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;

960
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
961 962 963
        if (thread->state != TERMINATED) total++;
    if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL;
    ptr = snapshot;
964
    LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry )
965 966 967 968 969 970 971 972 973 974 975 976
    {
        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;
}

977 978 979 980 981 982 983 984 985
/* 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;
}

986 987 988
/* create a new thread */
DECL_HANDLER(new_thread)
{
989
    struct thread *thread;
990
    int request_fd = thread_get_inflight_fd( current, req->request_fd );
991

992
    if (request_fd == -1 || fcntl( request_fd, F_SETFL, O_NONBLOCK ) == -1)
993
    {
994
        if (request_fd != -1) close( request_fd );
995 996 997 998 999 1000 1001
        set_error( STATUS_INVALID_HANDLE );
        return;
    }

    if ((thread = create_thread( request_fd, current->process )))
    {
        if (req->suspend) thread->suspend++;
1002
        reply->tid = get_thread_id( thread );
1003
        if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes )))
1004
        {
1005 1006
            /* thread object will be released when the thread gets killed */
            return;
1007
        }
1008
        kill_thread( thread, 1 );
1009 1010 1011 1012 1013 1014
    }
}

/* initialize a new thread */
DECL_HANDLER(init_thread)
{
1015
    struct process *process = current->process;
1016 1017 1018
    int reply_fd = thread_get_inflight_fd( current, req->reply_fd );
    int wait_fd = thread_get_inflight_fd( current, req->wait_fd );

1019
    if (current->reply_fd)  /* already initialised */
1020
    {
1021
        set_error( STATUS_INVALID_PARAMETER );
1022 1023
        goto error;
    }
1024 1025 1026

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

1027
    current->reply_fd = create_anonymous_fd( &thread_fd_ops, reply_fd, &current->obj, 0 );
1028 1029 1030
    reply_fd = -1;
    if (!current->reply_fd) goto error;

1031 1032
    if (wait_fd == -1)
    {
1033 1034
        set_error( STATUS_TOO_MANY_OPENED_FILES );  /* most likely reason */
        return;
1035
    }
1036
    if (!(current->wait_fd  = create_anonymous_fd( &thread_fd_ops, wait_fd, &current->obj, 0 )))
1037
        return;
1038

1039 1040 1041 1042 1043 1044
    if (!is_valid_address(req->teb) || !is_valid_address(req->peb) || !is_valid_address(req->ldt_copy))
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }

1045
    current->unix_pid = req->unix_pid;
1046
    current->unix_tid = req->unix_tid;
1047
    current->teb      = req->teb;
1048

1049 1050
    if (!process->peb)  /* first thread, initialize the process too */
    {
1051
        process->unix_pid = current->unix_pid;
1052 1053
        process->peb      = req->peb;
        process->ldt_copy = req->ldt_copy;
1054
        reply->info_size  = init_process( current );
1055 1056 1057
    }
    else
    {
1058 1059
        if (process->unix_pid != current->unix_pid)
            process->unix_pid = -1;  /* can happen with linuxthreads */
1060
        if (current->suspend + process->suspend > 0) stop_thread( current );
1061
        generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, req->entry );
1062 1063
    }
    debug_level = max( debug_level, req->debug_level );
1064

1065
    reply->pid     = get_process_id( process );
1066 1067
    reply->tid     = get_thread_id( current );
    reply->version = SERVER_PROTOCOL_VERSION;
1068
    reply->server_start = server_start_time;
1069 1070 1071 1072 1073 1074 1075
    return;

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

1076 1077 1078 1079 1080
/* terminate a thread */
DECL_HANDLER(terminate_thread)
{
    struct thread *thread;

1081 1082
    reply->self = 0;
    reply->last = 0;
1083 1084
    if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
    {
1085 1086 1087 1088
        thread->exit_code = req->exit_code;
        if (thread != current) kill_thread( thread, 1 );
        else
        {
1089 1090
            reply->self = 1;
            reply->last = (thread->process->running_threads == 1);
1091
        }
1092 1093 1094 1095
        release_object( thread );
    }
}

1096 1097 1098 1099 1100 1101 1102 1103
/* open a handle to a thread */
DECL_HANDLER(open_thread)
{
    struct thread *thread = get_thread_from_id( req->tid );

    reply->handle = 0;
    if (thread)
    {
1104
        reply->handle = alloc_handle( current->process, thread, req->access, req->attributes );
1105 1106 1107 1108
        release_object( thread );
    }
}

1109 1110 1111 1112
/* fetch information about a thread */
DECL_HANDLER(get_thread_info)
{
    struct thread *thread;
1113
    obj_handle_t handle = req->handle;
1114

1115
    if (!handle) thread = get_thread_from_id( req->tid_in );
1116 1117 1118
    else thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION );

    if (thread)
1119
    {
1120
        reply->pid            = get_process_id( thread->process );
1121 1122
        reply->tid            = get_thread_id( thread );
        reply->teb            = thread->teb;
1123
        reply->exit_code      = (thread->state == TERMINATED) ? thread->exit_code : STATUS_PENDING;
1124
        reply->priority       = thread->priority;
1125
        reply->affinity       = thread->affinity;
1126 1127
        reply->creation_time  = thread->creation_time;
        reply->exit_time      = thread->exit_time;
1128
        reply->last           = thread->process->running_threads == 1;
1129

1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
        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;
1150

1151 1152
    if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
    {
1153
        if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED );
1154
        else reply->count = suspend_thread( thread );
1155 1156 1157 1158 1159 1160 1161 1162
        release_object( thread );
    }
}

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

1164 1165
    if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
    {
1166 1167
        if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED );
        else reply->count = resume_thread( thread );
1168 1169 1170 1171 1172 1173 1174
        release_object( thread );
    }
}

/* select on a handle list */
DECL_HANDLER(select)
{
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
    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)
        {
1204
            if (apc->owner) async_set_result( apc->owner, apc->result.async_io.status, apc->result.async_io.total );
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
        }
        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 );
        }
    }
1234 1235
}

1236
/* queue an APC for a thread or process */
1237 1238
DECL_HANDLER(queue_apc)
{
1239 1240
    struct thread *thread = NULL;
    struct process *process = NULL;
1241 1242 1243 1244 1245
    struct thread_apc *apc;

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

    switch (apc->call.type)
1246
    {
1247 1248
    case APC_NONE:
    case APC_USER:
1249
        thread = get_thread_from_handle( req->thread, THREAD_SET_CONTEXT );
1250 1251 1252
        break;
    case APC_VIRTUAL_ALLOC:
    case APC_VIRTUAL_FREE:
1253
    case APC_VIRTUAL_PROTECT:
1254
    case APC_VIRTUAL_FLUSH:
1255 1256
    case APC_VIRTUAL_LOCK:
    case APC_VIRTUAL_UNLOCK:
1257
    case APC_UNMAP_VIEW:
1258 1259 1260 1261 1262
        process = get_process_from_handle( req->process, PROCESS_VM_OPERATION );
        break;
    case APC_VIRTUAL_QUERY:
        process = get_process_from_handle( req->process, PROCESS_QUERY_INFORMATION );
        break;
1263 1264
    case APC_MAP_VIEW:
        process = get_process_from_handle( req->process, PROCESS_VM_OPERATION );
1265
        if (process && process != current->process)
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
        {
            /* 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;
1278 1279
    case APC_CREATE_THREAD:
        process = get_process_from_handle( req->process, PROCESS_CREATE_THREAD );
1280 1281 1282 1283
        break;
    default:
        set_error( STATUS_INVALID_PARAMETER );
        break;
1284
    }
1285 1286 1287 1288 1289 1290 1291 1292

    if (thread)
    {
        if (!queue_apc( NULL, thread, apc )) set_error( STATUS_THREAD_IS_TERMINATING );
        release_object( thread );
    }
    else if (process)
    {
1293 1294
        reply->self = (process == current->process);
        if (!reply->self)
1295
        {
1296 1297
            obj_handle_t handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 );
            if (handle)
1298
            {
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
                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 );
                }
1309 1310 1311 1312 1313
            }
        }
        release_object( process );
    }

1314
    release_object( apc );
1315
}
1316

1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
/* 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 );
}

1334 1335 1336 1337
/* retrieve the current context of a thread */
DECL_HANDLER(get_thread_context)
{
    struct thread *thread;
1338
    CONTEXT *context;
1339 1340 1341 1342 1343 1344 1345 1346

    if (get_reply_max_size() < sizeof(CONTEXT))
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
    if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;

1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
    if (req->suspend)
    {
        if (thread != current || !thread->suspend_context)
        {
            /* not suspended, shouldn't happen */
            set_error( STATUS_INVALID_PARAMETER );
        }
        else
        {
            if (thread->context == thread->suspend_context) thread->context = NULL;
            set_reply_data_ptr( thread->suspend_context, sizeof(CONTEXT) );
            thread->suspend_context = NULL;
        }
    }
    else if (thread != current && !thread->context)
    {
        /* thread is not suspended, retry (if it's still running) */
        if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
        else set_error( STATUS_PENDING );
    }
1367
    else if ((context = set_reply_data_size( sizeof(CONTEXT) )))
1368
    {
1369 1370 1371 1372 1373 1374
        unsigned int flags = get_context_system_regs( req->flags );

        memset( context, 0, sizeof(CONTEXT) );
        context->ContextFlags = get_context_cpu_flag();
        if (thread->context) copy_context( context, thread->context, req->flags & ~flags );
        if (flags) get_thread_context( thread, context, flags );
1375
    }
1376
    reply->self = (thread == current);
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
    release_object( thread );
}

/* set the current context of a thread */
DECL_HANDLER(set_thread_context)
{
    struct thread *thread;

    if (get_req_data_size() < sizeof(CONTEXT))
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
    if (!(thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) return;

    if (req->suspend)
    {
        if (thread != current || thread->context)
        {
            /* nested suspend or exception, shouldn't happen */
            set_error( STATUS_INVALID_PARAMETER );
        }
        else if ((thread->suspend_context = mem_alloc( sizeof(CONTEXT) )))
        {
            memcpy( thread->suspend_context, get_req_data(), sizeof(CONTEXT) );
            thread->context = thread->suspend_context;
1403
            if (thread->debug_break) break_thread( thread );
1404 1405 1406 1407 1408 1409 1410 1411 1412
        }
    }
    else if (thread != current && !thread->context)
    {
        /* thread is not suspended, retry (if it's still running) */
        if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
        else set_error( STATUS_PENDING );
    }
    else
1413
    {
1414 1415 1416 1417 1418 1419
        const CONTEXT *context = get_req_data();
        unsigned int flags = get_context_system_regs( req->flags );

        if (flags) set_thread_context( thread, context, flags );
        if (thread->context && !get_error())
            copy_context( thread->context, context, req->flags & ~flags );
1420
    }
1421
    reply->self = (thread == current);
1422
    release_object( thread );
1423 1424
}

1425 1426 1427 1428 1429 1430
/* 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 )))
    {
1431
        get_selector_entry( thread, req->entry, &reply->base, &reply->limit, &reply->flags );
1432 1433 1434
        release_object( thread );
    }
}