thread.c 28.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Win32 threads
 *
 * Copyright 1996 Alexandre Julliard
 *
 * 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
19 20 21 22 23 24 25
 */

#include "config.h"
#include "wine/port.h"

#include <assert.h>
#include <fcntl.h>
26
#include <stdarg.h>
27 28 29 30 31
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

32
#include "ntstatus.h"
33
#define WIN32_NO_STATUS
34
#include "windef.h"
35 36
#include "winbase.h"
#include "winerror.h"
37
#include "winternl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38
#include "wine/exception.h"
39
#include "wine/library.h"
40 41 42
#include "wine/server.h"
#include "wine/debug.h"

43 44
#include "kernel_private.h"

45
WINE_DEFAULT_DEBUG_CHANNEL(thread);
46 47 48 49 50


/***********************************************************************
 *           CreateThread   (KERNEL32.@)
 */
51 52
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack, LPTHREAD_START_ROUTINE start,
                                              LPVOID param, DWORD flags, LPDWORD id )
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
{
     return CreateRemoteThread( GetCurrentProcess(),
                                sa, stack, start, param, flags, id );
}


/***************************************************************************
 *                  CreateRemoteThread   (KERNEL32.@)
 *
 * Creates a thread that runs in the address space of another process
 *
 * PARAMS
 *
 * RETURNS
 *   Success: Handle to the new thread.
 *   Failure: NULL. Use GetLastError() to find the error cause.
 *
 * BUGS
 *   Improper memory allocation: there's no ability to free new_thread_info
 *   in other process.
 *   Bad start address for RtlCreateUserThread because the library
 *   may be loaded at different address in other process.
 */
HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
                                  LPTHREAD_START_ROUTINE start, LPVOID param,
                                  DWORD flags, LPDWORD id )
79
{
80 81 82 83
    HANDLE handle;
    CLIENT_ID client_id;
    NTSTATUS status;
    SIZE_T stack_reserve = 0, stack_commit = 0;
84

85 86
    if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
    else stack_commit = stack;
87

88
    status = RtlCreateUserThread( hProcess, NULL, TRUE,
89
                                  NULL, stack_reserve, stack_commit,
90
                                  (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id );
91
    if (status == STATUS_SUCCESS)
92
    {
93
        if (id) *id = HandleToULong(client_id.UniqueThread);
94 95
        if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
            SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
96 97 98 99 100 101 102 103 104 105
        if (!(flags & CREATE_SUSPENDED))
        {
            ULONG ret;
            if (NtResumeThread( handle, &ret ))
            {
                NtClose( handle );
                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                handle = 0;
            }
        }
106
    }
107
    else
108
    {
109 110
        SetLastError( RtlNtStatusToDosError(status) );
        handle = 0;
111 112 113 114 115 116 117 118 119 120
    }
    return handle;
}


/***********************************************************************
 * OpenThread  [KERNEL32.@]   Retrieves a handle to a thread from its thread id
 */
HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
{
121 122 123 124 125 126 127 128 129 130 131 132 133
    NTSTATUS status;
    HANDLE handle;
    OBJECT_ATTRIBUTES attr;
    CLIENT_ID cid;

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.Attributes = bInheritHandle ? OBJ_INHERIT : 0;
    attr.ObjectName = NULL;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

    cid.UniqueProcess = 0; /* FIXME */
134
    cid.UniqueThread = ULongToHandle(dwThreadId);
135 136
    status = NtOpenThread( &handle, dwDesiredAccess, &attr, &cid );
    if (status)
137
    {
138 139
        SetLastError( RtlNtStatusToDosError(status) );
        handle = 0;
140
    }
141
    return handle;
142 143 144 145 146 147 148 149 150 151 152
}


/***********************************************************************
 * ExitThread [KERNEL32.@]  Ends a thread
 *
 * RETURNS
 *    None
 */
void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
{
153
    RtlExitUserThread( code );
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
}


/**********************************************************************
 * TerminateThread [KERNEL32.@]  Terminates a thread
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
                             DWORD exit_code)  /* [in] Exit code for thread */
{
    NTSTATUS status = NtTerminateThread( handle, exit_code );
    if (status) SetLastError( RtlNtStatusToDosError(status) );
    return !status;
}


/***********************************************************************
 *           FreeLibraryAndExitThread (KERNEL32.@)
 */
void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
{
    FreeLibrary(hLibModule);
    ExitThread(dwExitCode);
}


/**********************************************************************
 *		GetExitCodeThread (KERNEL32.@)
 *
 * Gets termination status of thread.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI GetExitCodeThread(
    HANDLE hthread, /* [in]  Handle to thread */
    LPDWORD exitcode) /* [out] Address to receive termination status */
{
    THREAD_BASIC_INFORMATION info;
    NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
                                                &info, sizeof(info), NULL );

    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
    }
    if (exitcode) *exitcode = info.ExitStatus;
    return TRUE;
}
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297


/***********************************************************************
 * SetThreadContext [KERNEL32.@]  Sets context of thread.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
                              const CONTEXT *context ) /* [in] Address of context structure */
{
    NTSTATUS status = NtSetContextThread( handle, context );
    if (status) SetLastError( RtlNtStatusToDosError(status) );
    return !status;
}


/***********************************************************************
 * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
                              CONTEXT *context ) /* [out] Address of context structure */
{
    NTSTATUS status = NtGetContextThread( handle, context );
    if (status) SetLastError( RtlNtStatusToDosError(status) );
    return !status;
}


/**********************************************************************
 * SuspendThread [KERNEL32.@]  Suspends a thread.
 *
 * RETURNS
 *    Success: Previous suspend count
 *    Failure: 0xFFFFFFFF
 */
DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
{
    DWORD ret;
    NTSTATUS status = NtSuspendThread( hthread, &ret );

    if (status)
    {
        ret = ~0U;
        SetLastError( RtlNtStatusToDosError(status) );
    }
    return ret;
}


/**********************************************************************
 * ResumeThread [KERNEL32.@]  Resumes a thread.
 *
 * Decrements a thread's suspend count.  When count is zero, the
 * execution of the thread is resumed.
 *
 * RETURNS
 *    Success: Previous suspend count
 *    Failure: 0xFFFFFFFF
 *    Already running: 0
 */
DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
{
    DWORD ret;
    NTSTATUS status = NtResumeThread( hthread, &ret );

    if (status)
    {
        ret = ~0U;
        SetLastError( RtlNtStatusToDosError(status) );
    }
    return ret;
}


/**********************************************************************
 * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
 *
 * RETURNS
 *    Success: Thread's priority level.
 *    Failure: THREAD_PRIORITY_ERROR_RETURN
 */
INT WINAPI GetThreadPriority(
    HANDLE hthread) /* [in] Handle to thread */
{
298 299 300 301 302
    THREAD_BASIC_INFORMATION info;
    NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
                                                &info, sizeof(info), NULL );

    if (status)
303
    {
304 305
        SetLastError( RtlNtStatusToDosError(status) );
        return THREAD_PRIORITY_ERROR_RETURN;
306
    }
307
    return info.Priority;
308 309 310 311 312 313 314 315 316 317 318 319 320 321
}


/**********************************************************************
 * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI SetThreadPriority(
    HANDLE hthread, /* [in] Handle to thread */
    INT priority)   /* [in] Thread priority level */
{
322 323 324 325 326 327 328
    DWORD       prio = priority;
    NTSTATUS    status;

    status = NtSetInformationThread(hthread, ThreadBasePriority,
                                    &prio, sizeof(prio));

    if (status)
329
    {
330 331
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
332
    }
333 334

    return TRUE;
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
}


/**********************************************************************
 * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
 *
 * Always reports that priority boost is disabled.
 *
 * RETURNS
 *    Success: TRUE.
 *    Failure: FALSE
 */
BOOL WINAPI GetThreadPriorityBoost(
    HANDLE hthread, /* [in] Handle to thread */
    PBOOL pstate)   /* [out] pointer to var that receives the boost state */
{
    if (pstate) *pstate = FALSE;
352
    return TRUE;
353 354 355 356 357 358
}


/**********************************************************************
 * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
 *
359 360
 * Priority boost is not implemented, but we return TRUE
 * anyway because some games crash otherwise.
361 362 363 364 365
 */
BOOL WINAPI SetThreadPriorityBoost(
    HANDLE hthread, /* [in] Handle to thread */
    BOOL disable)   /* [in] TRUE to disable priority boost */
{
366
    return TRUE;
367 368 369
}


370 371 372 373 374
/**********************************************************************
 *           SetThreadStackGuarantee   (KERNEL32.@)
 */
BOOL WINAPI SetThreadStackGuarantee(PULONG stacksize)
{
375 376 377
    static int once;
    if (once++ == 0)
        FIXME("(%p): stub\n", stacksize);
378
    return TRUE;
379 380
}

381 382 383
/**********************************************************************
 *           SetThreadAffinityMask   (KERNEL32.@)
 */
384
DWORD_PTR WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask )
385
{
386 387 388 389 390 391
    NTSTATUS                    status;
    THREAD_BASIC_INFORMATION    tbi;

    status = NtQueryInformationThread( hThread, ThreadBasicInformation, 
                                       &tbi, sizeof(tbi), NULL );
    if (status)
392
    {
393 394
        SetLastError( RtlNtStatusToDosError(status) );
        return 0;
395
    }
396 397 398 399 400 401 402 403 404
    status = NtSetInformationThread( hThread, ThreadAffinityMask, 
                                     &dwThreadAffinityMask,
                                     sizeof(dwThreadAffinityMask));
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return 0;
    }
    return tbi.AffinityMask;
405 406 407 408
}


/**********************************************************************
409
 * SetThreadIdealProcessor [KERNEL32.@]  Sets preferred processor for thread.
410 411 412 413 414 415 416 417 418 419
 *
 * RETURNS
 *    Success: Value of last call to SetThreadIdealProcessor
 *    Failure: -1
 */
DWORD WINAPI SetThreadIdealProcessor(
    HANDLE hThread,          /* [in] Specifies the thread of interest */
    DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
{
    FIXME("(%p): stub\n",hThread);
420 421 422 423 424 425
    if (dwIdealProcessor > MAXIMUM_PROCESSORS)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return ~0u;
    }
    return 0;
426 427 428
}


429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
/***********************************************************************
 *           GetThreadSelectorEntry   (KERNEL32.@)
 */
BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent )
{
    THREAD_DESCRIPTOR_INFORMATION tdi;
    NTSTATUS status;

    tdi.Selector = sel;
    status = NtQueryInformationThread( hthread, ThreadDescriptorTableEntry, &tdi, sizeof(tdi), NULL);
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
    }
    *ldtent = tdi.Entry;
    return TRUE;
}


449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
/* callback for QueueUserAPC */
static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
{
    PAPCFUNC func = (PAPCFUNC)arg1;
    func( arg2 );
}

/***********************************************************************
 *              QueueUserAPC  (KERNEL32.@)
 */
DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
{
    NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );

    if (status) SetLastError( RtlNtStatusToDosError(status) );
    return !status;
}

467 468 469 470 471
/***********************************************************************
 *              QueueUserWorkItem  (KERNEL32.@)
 */
BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
{
472 473
    NTSTATUS status;

474
    TRACE("(%p,%p,0x%08x)\n", Function, Context, Flags);
475 476 477 478 479

    status = RtlQueueWorkItem( Function, Context, Flags );

    if (status) SetLastError( RtlNtStatusToDosError(status) );
    return !status;
480
}
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495

/**********************************************************************
 * GetThreadTimes [KERNEL32.@]  Obtains timing information.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI GetThreadTimes(
    HANDLE thread,         /* [in]  Specifies the thread of interest */
    LPFILETIME creationtime, /* [out] When the thread was created */
    LPFILETIME exittime,     /* [out] When the thread was destroyed */
    LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
    LPFILETIME usertime)     /* [out] Time thread spent in user mode */
{
496 497
    KERNEL_USER_TIMES   kusrt;
    NTSTATUS            status;
498

499 500 501
    status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
                                      sizeof(kusrt), NULL);
    if (status)
502
    {
503 504
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
505
    }
506
    if (creationtime)
507
    {
508 509
        creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
        creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
510
    }
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
    if (exittime)
    {
        exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
        exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
    }
    if (kerneltime)
    {
        kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
        kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
    }
    if (usertime)
    {
        usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
        usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
    }
    
    return TRUE;
528 529
}

530 531 532 533 534 535
/**********************************************************************
 * GetThreadId [KERNEL32.@]
 *
 * Retrieve the identifier of a thread.
 *
 * PARAMS
536
 *  Thread [I] The thread to retrieve the identifier of.
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
 *
 * RETURNS
 *    Success: Identifier of the target thread.
 *    Failure: 0
 */
DWORD WINAPI GetThreadId(HANDLE Thread)
{
    THREAD_BASIC_INFORMATION tbi;
    NTSTATUS status;

    TRACE("(%p)\n", Thread);

    status = NtQueryInformationThread(Thread, ThreadBasicInformation, &tbi,
                                      sizeof(tbi), NULL);
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return 0;
    }

    return HandleToULong(tbi.ClientId.UniqueThread);
}

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
/**********************************************************************
 * GetProcessIdOfThread [KERNEL32.@]
 *
 * Retrieve process identifier given thread belongs to.
 *
 * PARAMS
 *  Thread [I] The thread identifier.
 *
 * RETURNS
 *    Success: Process identifier
 *    Failure: 0
 */
DWORD WINAPI GetProcessIdOfThread(HANDLE Thread)
{
    THREAD_BASIC_INFORMATION tbi;
    NTSTATUS status;

    TRACE("(%p)\n", Thread);

    status = NtQueryInformationThread(Thread, ThreadBasicInformation, &tbi,
                                      sizeof(tbi), NULL);
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return 0;
    }

    return HandleToULong(tbi.ClientId.UniqueProcess);
}
589 590 591 592 593 594 595 596 597 598

/***********************************************************************
 * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
 *
 * RETURNS
 *    Pseudohandle for the current thread
 */
#undef GetCurrentThread
HANDLE WINAPI GetCurrentThread(void)
{
599
    return (HANDLE)~(ULONG_PTR)1;
600
}
601 602 603 604 605 606 607 608


#ifdef __i386__

/***********************************************************************
 *		SetLastError (KERNEL32.@)
 */
/* void WINAPI SetLastError( DWORD error ); */
609
__ASM_STDCALL_FUNC( SetLastError, 4,
610 611
                   "movl 4(%esp),%eax\n\t"
                   ".byte 0x64\n\t"
612
                   "movl %eax,0x34\n\t"
613
                   "ret $4" )
614 615 616 617 618

/***********************************************************************
 *		GetLastError (KERNEL32.@)
 */
/* DWORD WINAPI GetLastError(void); */
619
__ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
620 621 622 623 624

/***********************************************************************
 *		GetCurrentProcessId (KERNEL32.@)
 */
/* DWORD WINAPI GetCurrentProcessId(void) */
625
__ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
626 627 628 629 630

/***********************************************************************
 *		GetCurrentThreadId (KERNEL32.@)
 */
/* DWORD WINAPI GetCurrentThreadId(void) */
631
__ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
632

633 634 635 636 637 638
/***********************************************************************
 *		GetProcessHeap (KERNEL32.@)
 */
/* HANDLE WINAPI GetProcessHeap(void) */
__ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x64\n\tmovl 0x30,%eax\n\tmovl 0x18(%eax),%eax\n\tret");

639
#elif defined(__x86_64__) && !defined(__APPLE__)
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

/***********************************************************************
 *		SetLastError (KERNEL32.@)
 */
/* void WINAPI SetLastError( DWORD error ); */
__ASM_STDCALL_FUNC( SetLastError, 8, ".byte 0x65\n\tmovl %ecx,0x68\n\tret" );

/***********************************************************************
 *		GetLastError (KERNEL32.@)
 */
/* DWORD WINAPI GetLastError(void); */
__ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x65\n\tmovl 0x68,%eax\n\tret" );

/***********************************************************************
 *		GetCurrentProcessId (KERNEL32.@)
 */
/* DWORD WINAPI GetCurrentProcessId(void) */
__ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x65\n\tmovl 0x40,%eax\n\tret" );

/***********************************************************************
 *		GetCurrentThreadId (KERNEL32.@)
 */
/* DWORD WINAPI GetCurrentThreadId(void) */
__ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x65\n\tmovl 0x48,%eax\n\tret" );

/***********************************************************************
 *		GetProcessHeap (KERNEL32.@)
 */
/* HANDLE WINAPI GetProcessHeap(void) */
__ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x65\n\tmovq 0x60,%rax\n\tmovq 0x30(%rax),%rax\n\tret");

#else  /* __x86_64__ */
672 673 674 675 676

/**********************************************************************
 *		SetLastError (KERNEL32.@)
 *
 * Sets the last-error code.
677 678 679
 *
 * RETURNS
 * Nothing.
680 681 682
 */
void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
{
683
    NtCurrentTeb()->LastErrorValue = error;
684 685 686 687 688
}

/**********************************************************************
 *              GetLastError (KERNEL32.@)
 *
689 690 691 692
 * Get the last-error code.
 *
 * RETURNS
 *  last-error code.
693 694 695
 */
DWORD WINAPI GetLastError(void)
{
696
    return NtCurrentTeb()->LastErrorValue;
697 698 699 700 701
}

/***********************************************************************
 *		GetCurrentProcessId (KERNEL32.@)
 *
702 703 704 705
 * Get the current process identifier.
 *
 * RETURNS
 *  current process identifier
706 707 708
 */
DWORD WINAPI GetCurrentProcessId(void)
{
709
    return HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess);
710 711 712 713 714
}

/***********************************************************************
 *		GetCurrentThreadId (KERNEL32.@)
 *
715 716 717 718
 * Get the current thread identifier.
 *
 * RETURNS
 *  current thread identifier
719 720 721
 */
DWORD WINAPI GetCurrentThreadId(void)
{
722
    return HandleToULong(NtCurrentTeb()->ClientId.UniqueThread);
723 724
}

725 726 727 728 729 730 731 732
/***********************************************************************
 *           GetProcessHeap    (KERNEL32.@)
 */
HANDLE WINAPI GetProcessHeap(void)
{
    return NtCurrentTeb()->Peb->ProcessHeap;
}

733
#endif  /* __i386__ */
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753

/*************************************************************************
 *              rtlmode_to_win32mode
 */
static DWORD rtlmode_to_win32mode( DWORD rtlmode )
{
    DWORD win32mode = 0;

    if (rtlmode & 0x10)
        win32mode |= SEM_FAILCRITICALERRORS;
    if (rtlmode & 0x20)
        win32mode |= SEM_NOGPFAULTERRORBOX;
    if (rtlmode & 0x40)
        win32mode |= SEM_NOOPENFILEERRORBOX;

    return win32mode;
}

/***********************************************************************
 *              SetThreadErrorMode (KERNEL32.@)
754 755 756 757 758 759 760 761 762 763 764
 *
 * Set the thread local error mode.
 *
 * PARAMS
 *  mode    [I] The new error mode, a bitwise or of SEM_FAILCRITICALERRORS,
 *              SEM_NOGPFAULTERRORBOX and SEM_NOOPENFILEERRORBOX.
 *  oldmode [O] Destination of the old error mode (may be NULL)
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE, check GetLastError
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
 */
BOOL WINAPI SetThreadErrorMode( DWORD mode, LPDWORD oldmode )
{
    NTSTATUS status;
    DWORD tmp = 0;

    if (mode & ~(SEM_FAILCRITICALERRORS |
                 SEM_NOGPFAULTERRORBOX |
                 SEM_NOOPENFILEERRORBOX))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }

    if (mode & SEM_FAILCRITICALERRORS)
        tmp |= 0x10;
    if (mode & SEM_NOGPFAULTERRORBOX)
        tmp |= 0x20;
    if (mode & SEM_NOOPENFILEERRORBOX)
        tmp |= 0x40;

    status = RtlSetThreadErrorMode( tmp, oldmode );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
    }

    if (oldmode)
        *oldmode = rtlmode_to_win32mode(*oldmode);

    return TRUE;
}

/***********************************************************************
 *              GetThreadErrorMode (KERNEL32.@)
801 802 803 804 805 806 807 808
 *
 * Get the thread local error mode.
 *
 * PARAMS
 *  None.
 *
 * RETURNS
 *  The current thread local error mode.
809 810 811 812 813
 */
DWORD WINAPI GetThreadErrorMode( void )
{
    return rtlmode_to_win32mode( RtlGetThreadErrorMode() );
}
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832

/***********************************************************************
 *              GetThreadUILanguage (KERNEL32.@)
 *
 * Get the current thread's language identifier.
 *
 * PARAMS
 *  None.
 *
 * RETURNS
 *  The current thread's language identifier.
 */
LANGID WINAPI GetThreadUILanguage( void )
{
    LANGID lang;
    NtQueryDefaultUILanguage( &lang );
    FIXME(": stub, returning default language.\n");
    return lang;
}
833 834 835 836 837 838 839 840 841 842

/***********************************************************************
 *              GetThreadIOPendingFlag (KERNEL32.@)
 */
BOOL WINAPI GetThreadIOPendingFlag( HANDLE thread, PBOOL io_pending )
{
    FIXME("%p, %p\n", thread, io_pending);
    *io_pending = FALSE;
    return TRUE;
}
843 844 845 846 847 848 849 850 851

/***********************************************************************
 *              SetThreadPreferredUILanguages (KERNEL32.@)
 */
BOOL WINAPI SetThreadPreferredUILanguages( DWORD flags, PCZZWSTR buffer, PULONG count )
{
    FIXME( "%u, %p, %p\n", flags, buffer, count );
    return TRUE;
}
852 853 854 855 856 857 858 859 860 861 862

/***********************************************************************
 *              GetThreadPreferredUILanguages (KERNEL32.@)
 */
BOOL WINAPI GetThreadPreferredUILanguages( DWORD flags, PULONG count, PCZZWSTR buffer, PULONG buffersize )
{
    FIXME( "%u, %p, %p %p\n", flags, count, buffer, buffersize );
    *count = 0;
    *buffersize = 0;
    return TRUE;
}
863

864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882
/***********************************************************************
 *              CallbackMayRunLong (KERNEL32.@)
 */
BOOL WINAPI CallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
{
    NTSTATUS status;

    TRACE( "%p\n", instance );

    status = TpCallbackMayRunLong( instance );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
    }

    return TRUE;
}

883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
/***********************************************************************
 *              CreateThreadpool (KERNEL32.@)
 */
PTP_POOL WINAPI CreateThreadpool( PVOID reserved )
{
    TP_POOL *pool;
    NTSTATUS status;

    TRACE( "%p\n", reserved );

    status = TpAllocPool( &pool, reserved );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return NULL;
    }

    return pool;
}

903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
/***********************************************************************
 *              CreateThreadpoolCleanupGroup (KERNEL32.@)
 */
PTP_CLEANUP_GROUP WINAPI CreateThreadpoolCleanupGroup( void )
{
    TP_CLEANUP_GROUP *group;
    NTSTATUS status;

    TRACE( "\n" );

    status = TpAllocCleanupGroup( &group );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return NULL;
    }

    return group;
}
922

923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
/***********************************************************************
 *              CreateThreadpoolTimer (KERNEL32.@)
 */
PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userdata,
                                        TP_CALLBACK_ENVIRON *environment )
{
    TP_TIMER *timer;
    NTSTATUS status;

    TRACE( "%p, %p, %p\n", callback, userdata, environment );

    status = TpAllocTimer( &timer, callback, userdata, environment );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return NULL;
    }

    return timer;
}

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
/***********************************************************************
 *              CreateThreadpoolWait (KERNEL32.@)
 */
PTP_WAIT WINAPI CreateThreadpoolWait( PTP_WAIT_CALLBACK callback, PVOID userdata,
                                      TP_CALLBACK_ENVIRON *environment )
{
    TP_WAIT *wait;
    NTSTATUS status;

    TRACE( "%p, %p, %p\n", callback, userdata, environment );

    status = TpAllocWait( &wait, callback, userdata, environment );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return NULL;
    }

    return wait;
}

965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
/***********************************************************************
 *              CreateThreadpoolWork (KERNEL32.@)
 */
PTP_WORK WINAPI CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata,
                                      TP_CALLBACK_ENVIRON *environment )
{
    TP_WORK *work;
    NTSTATUS status;

    TRACE( "%p, %p, %p\n", callback, userdata, environment );

    status = TpAllocWork( &work, callback, userdata, environment );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return NULL;
    }

    return work;
}
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003

/***********************************************************************
 *              SetThreadpoolTimer (KERNEL32.@)
 */
VOID WINAPI SetThreadpoolTimer( TP_TIMER *timer, FILETIME *due_time,
                                DWORD period, DWORD window_length )
{
    LARGE_INTEGER timeout;

    TRACE( "%p, %p, %u, %u\n", timer, due_time, period, window_length );

    if (due_time)
    {
        timeout.u.LowPart = due_time->dwLowDateTime;
        timeout.u.HighPart = due_time->dwHighDateTime;
    }

    TpSetTimer( timer, due_time ? &timeout : NULL, period, window_length );
}
1004

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
/***********************************************************************
 *              SetThreadpoolWait (KERNEL32.@)
 */
VOID WINAPI SetThreadpoolWait( TP_WAIT *wait, HANDLE handle, FILETIME *due_time )
{
    LARGE_INTEGER timeout;

    TRACE( "%p, %p, %p\n", wait, handle, due_time );

    if (!handle)
    {
        due_time = NULL;
    }
    else if (due_time)
    {
        timeout.u.LowPart = due_time->dwLowDateTime;
        timeout.u.HighPart = due_time->dwHighDateTime;
    }

    TpSetWait( wait, handle, due_time ? &timeout : NULL );
}

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
/***********************************************************************
 *              TrySubmitThreadpoolCallback (KERNEL32.@)
 */
BOOL WINAPI TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
                                         TP_CALLBACK_ENVIRON *environment )
{
    NTSTATUS status;

    TRACE( "%p, %p, %p\n", callback, userdata, environment );

    status = TpSimpleTryPost( callback, userdata, environment );
    if (status)
    {
        SetLastError( RtlNtStatusToDosError(status) );
        return FALSE;
    }

    return TRUE;
}