Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091/* * Synchronization tests * * Copyright 2005 Mike McCormack for CodeWeavers * * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include <stdarg.h>#include <stdlib.h>#include <stdio.h>
#include "ntstatus.h"#define WIN32_NO_STATUS#include <windef.h>#include <winbase.h>#include <winternl.h>#include <setjmp.h>
#include "wine/test.h"
#undef __fastcall#define __fastcall __stdcall
static HANDLE (WINAPI *pCreateMemoryResourceNotification)(MEMORY_RESOURCE_NOTIFICATION_TYPE);static BOOL (WINAPI *pQueryMemoryResourceNotification)(HANDLE, PBOOL);static VOID (WINAPI *pInitOnceInitialize)(PINIT_ONCE);static BOOL (WINAPI *pInitOnceExecuteOnce)(PINIT_ONCE,PINIT_ONCE_FN,PVOID,LPVOID*);static BOOL (WINAPI *pInitOnceBeginInitialize)(PINIT_ONCE,DWORD,BOOL*,LPVOID*);static BOOL (WINAPI *pInitOnceComplete)(PINIT_ONCE,DWORD,LPVOID);
static BOOL (WINAPI *pInitializeCriticalSectionEx)(CRITICAL_SECTION*,DWORD,DWORD);static VOID (WINAPI *pInitializeConditionVariable)(PCONDITION_VARIABLE);static BOOL (WINAPI *pSleepConditionVariableCS)(PCONDITION_VARIABLE,PCRITICAL_SECTION,DWORD);static BOOL (WINAPI *pSleepConditionVariableSRW)(PCONDITION_VARIABLE,PSRWLOCK,DWORD,ULONG);static VOID (WINAPI *pWakeAllConditionVariable)(PCONDITION_VARIABLE);static VOID (WINAPI *pWakeConditionVariable)(PCONDITION_VARIABLE);
static VOID (WINAPI *pInitializeSRWLock)(PSRWLOCK);static VOID (WINAPI *pAcquireSRWLockExclusive)(PSRWLOCK);static VOID (WINAPI *pAcquireSRWLockShared)(PSRWLOCK);static VOID (WINAPI *pReleaseSRWLockExclusive)(PSRWLOCK);static VOID (WINAPI *pReleaseSRWLockShared)(PSRWLOCK);static BOOLEAN (WINAPI *pTryAcquireSRWLockExclusive)(PSRWLOCK);static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(PSRWLOCK);
static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG);static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);static NTSTATUS (WINAPI *pNtWaitForSingleObject)(HANDLE, BOOLEAN, const LARGE_INTEGER *);static NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*);static PSLIST_ENTRY (__fastcall *pRtlInterlockedPushListSList)(PSLIST_HEADER list, PSLIST_ENTRY first, PSLIST_ENTRY last, ULONG count);static PSLIST_ENTRY (WINAPI *pRtlInterlockedPushListSListEx)(PSLIST_HEADER list, PSLIST_ENTRY first, PSLIST_ENTRY last, ULONG count);static NTSTATUS (WINAPI *pNtQueueApcThread)(HANDLE,PNTAPCFUNC,ULONG_PTR,ULONG_PTR,ULONG_PTR);static NTSTATUS (WINAPI *pNtTestAlert)(void);
#ifdef __i386__
#include "pshpack1.h"struct fastcall_thunk{ BYTE pop_edx; /* popl %edx (ret addr) */ BYTE pop_eax; /* popl %eax (func) */ BYTE pop_ecx; /* popl %ecx (param 1) */ BYTE xchg[3]; /* xchgl (%esp),%edx (param 2) */ WORD jmp_eax; /* jmp *%eax */};#include "poppack.h"
static void * (WINAPI *call_fastcall_func4)(void *func, const void *a, const void *b, const void *c, const void *d);
static void init_fastcall_thunk(void){ struct fastcall_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE); thunk->pop_edx = 0x5a; /* popl %edx */ thunk->pop_eax = 0x58; /* popl %eax */ thunk->pop_ecx = 0x59; /* popl %ecx */ thunk->xchg[0] = 0x87; /* xchgl (%esp),%edx */ thunk->xchg[1] = 0x14; thunk->xchg[2] = 0x24; thunk->jmp_eax = 0xe0ff; /* jmp *%eax */ call_fastcall_func4 = (void *)thunk;}
#define call_func4(func, a, b, c, d) call_fastcall_func4(func, (const void *)(a), \ (const void *)(b), (const void *)(c), (const void *)(d))
#else /* __i386__ */
#define init_fastcall_thunk() do { } while(0)#define call_func4(func, a, b, c, d) func(a, b, c, d)
#endif /* __i386__ */
static void test_signalandwait(void){ DWORD r; HANDLE event[2], semaphore[2], file; int i;
/* invalid parameters */ r = SignalObjectAndWait(NULL, NULL, 0, 0); ok( r == WAIT_FAILED, "should fail\n");
event[0] = CreateEventW(NULL, 0, 0, NULL); event[1] = CreateEventW(NULL, 1, 1, NULL);
ok( event[0] && event[1], "failed to create event flags\n");
r = SignalObjectAndWait(event[0], NULL, 0, FALSE); ok( r == WAIT_FAILED, "should fail\n");
r = SignalObjectAndWait(NULL, event[0], 0, FALSE); ok( r == WAIT_FAILED, "should fail\n");
/* valid parameters */ r = SignalObjectAndWait(event[0], event[1], 0, FALSE); ok( r == WAIT_OBJECT_0, "should succeed\n");
/* event[0] is now signalled - we repeat this test multiple times * to ensure that the wineserver handles this situation properly. */ for (i = 0; i < 10000; i++) { r = SignalObjectAndWait(event[0], event[0], 0, FALSE); ok(r == WAIT_OBJECT_0, "should succeed\n"); }
/* event[0] is not signalled */ r = WaitForSingleObject(event[0], 0); ok( r == WAIT_TIMEOUT, "event was signalled\n");
r = SignalObjectAndWait(event[0], event[0], 0, FALSE); ok( r == WAIT_OBJECT_0, "should succeed\n");
/* clear event[1] and check for a timeout */ ok(ResetEvent(event[1]), "failed to clear event[1]\n"); r = SignalObjectAndWait(event[0], event[1], 0, FALSE); ok( r == WAIT_TIMEOUT, "should timeout\n");
CloseHandle(event[0]); CloseHandle(event[1]);
/* semaphores */ semaphore[0] = CreateSemaphoreW( NULL, 0, 1, NULL ); semaphore[1] = CreateSemaphoreW( NULL, 1, 1, NULL ); ok( semaphore[0] && semaphore[1], "failed to create semaphore\n");
r = SignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE); ok( r == WAIT_OBJECT_0, "should succeed\n");
r = SignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE); ok( r == WAIT_FAILED, "should fail\n");
r = ReleaseSemaphore(semaphore[0],1,NULL); ok( r == FALSE, "should fail\n");
r = ReleaseSemaphore(semaphore[1],1,NULL); ok( r == TRUE, "should succeed\n");
CloseHandle(semaphore[0]); CloseHandle(semaphore[1]);
/* try a registry key */ file = CreateFileA("x", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); r = SignalObjectAndWait(file, file, 0, FALSE); ok( r == WAIT_FAILED, "should fail\n"); ok( ERROR_INVALID_HANDLE == GetLastError(), "should return invalid handle error\n"); CloseHandle(file);}
static void test_temporary_objects(void){ HANDLE handle;
SetLastError(0xdeadbeef); handle = CreateMutexA(NULL, FALSE, "WineTestMutex2"); ok(handle != NULL, "CreateMutex failed with error %ld\n", GetLastError()); CloseHandle(handle);
SetLastError(0xdeadbeef); handle = OpenMutexA(READ_CONTROL, FALSE, "WineTestMutex2"); ok(!handle, "OpenMutex succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle = CreateSemaphoreA(NULL, 0, 1, "WineTestSemaphore2"); ok(handle != NULL, "CreateSemaphore failed with error %ld\n", GetLastError()); CloseHandle(handle);
SetLastError(0xdeadbeef); handle = OpenSemaphoreA(READ_CONTROL, FALSE, "WineTestSemaphore2"); ok(!handle, "OpenSemaphore succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle = CreateEventA(NULL, FALSE, FALSE, "WineTestEvent2"); ok(handle != NULL, "CreateEvent failed with error %ld\n", GetLastError()); CloseHandle(handle);
SetLastError(0xdeadbeef); handle = OpenEventA(READ_CONTROL, FALSE, "WineTestEvent2"); ok(!handle, "OpenEvent succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle = CreateWaitableTimerA(NULL, FALSE, "WineTestWaitableTimer2"); ok(handle != NULL, "CreateWaitableTimer failed with error %ld\n", GetLastError()); CloseHandle(handle);
SetLastError(0xdeadbeef); handle = OpenWaitableTimerA(READ_CONTROL, FALSE, "WineTestWaitableTimer2"); ok(!handle, "OpenWaitableTimer succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());}
static void test_mutex(void){ DWORD wait_ret; BOOL ret; HANDLE hCreated; HANDLE hOpened; int i; DWORD failed = 0;
SetLastError(0xdeadbeef); hOpened = OpenMutexA(0, FALSE, "WineTestMutex"); ok(hOpened == NULL, "OpenMutex succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); hCreated = CreateMutexA(NULL, FALSE, "WineTestMutex"); ok(hCreated != NULL, "CreateMutex failed with error %ld\n", GetLastError());
SetLastError(0xdeadbeef); hOpened = OpenMutexA(0, FALSE, "WineTestMutex"); todo_wine ok(hOpened == NULL, "OpenMutex succeeded\n"); todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); hOpened = OpenMutexA(GENERIC_EXECUTE, FALSE, "WineTestMutex"); ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); wait_ret = WaitForSingleObject(hOpened, INFINITE); ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error %ld\n", GetLastError()); CloseHandle(hOpened);
for(i=0; i < 31; i++) { wait_ret = WaitForSingleObject(hCreated, INFINITE); ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08lx\n", wait_ret); }
SetLastError(0xdeadbeef); hOpened = OpenMutexA(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex"); ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); wait_ret = WaitForSingleObject(hOpened, INFINITE); ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n"); CloseHandle(hOpened);
for (i = 0; i < 32; i++) { SetLastError(0xdeadbeef); hOpened = OpenMutexA(0x1 << i, FALSE, "WineTestMutex"); if(hOpened != NULL) { SetLastError(0xdeadbeef); ret = ReleaseMutex(hOpened); ok(ret, "ReleaseMutex failed with error %ld, access %x\n", GetLastError(), 1 << i); CloseHandle(hOpened); } else { if ((1 << i) == ACCESS_SYSTEM_SECURITY) todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "wrong error %lu, access %x\n", GetLastError(), 1 << i); else todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu, , access %x\n", GetLastError(), 1 << i); ReleaseMutex(hCreated); failed |=0x1 << i; } }
todo_wine ok( failed == 0x0de0fffe, "open succeeded when it shouldn't: %lx\n", failed);
SetLastError(0xdeadbeef); ret = ReleaseMutex(hCreated); ok(!ret && (GetLastError() == ERROR_NOT_OWNER), "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %ld\n", GetLastError());
/* test case sensitivity */
SetLastError(0xdeadbeef); hOpened = OpenMutexA(READ_CONTROL, FALSE, "WINETESTMUTEX"); ok(!hOpened, "OpenMutex succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); hOpened = OpenMutexA(READ_CONTROL, FALSE, "winetestmutex"); ok(!hOpened, "OpenMutex succeeded\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); hOpened = OpenMutexA(READ_CONTROL, FALSE, NULL); ok(!hOpened, "OpenMutex succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); hOpened = OpenMutexW(READ_CONTROL, FALSE, NULL); ok(!hOpened, "OpenMutex succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); hOpened = CreateMutexA(NULL, FALSE, "WineTestMutex"); ok(hOpened != NULL, "CreateMutex failed with error %ld\n", GetLastError()); ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle(hOpened);
SetLastError(0xdeadbeef); hOpened = CreateMutexA(NULL, FALSE, "WINETESTMUTEX"); ok(hOpened != NULL, "CreateMutex failed with error %ld\n", GetLastError()); ok(GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle(hOpened);
CloseHandle(hCreated);}
static void test_slist(void){ struct item { SLIST_ENTRY entry; int value; } item1, item2, item3, *item; SLIST_HEADER slist_header; SLIST_ENTRY *entry; USHORT size; int i;
item1.value = 1; item2.value = 2; item3.value = 3;
memset(&slist_header, 0xff, sizeof(slist_header)); InitializeSListHead(&slist_header); size = QueryDepthSList(&slist_header); ok(size == 0, "Expected size == 0, got %u\n", size);
/* test PushEntry, PopEntry and Flush */ entry = InterlockedPushEntrySList(&slist_header, &item1.entry); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); size = QueryDepthSList(&slist_header); ok(size == 1, "Expected size == 1, got %u\n", size);
entry = InterlockedPushEntrySList(&slist_header, &item2.entry); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 1, "Expected item->value == 1, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 2, "Expected size == 2, got %u\n", size);
entry = InterlockedPushEntrySList(&slist_header, &item3.entry); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 2, "Expected item->value == 2, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 3, "Expected size == 3, got %u\n", size);
entry = InterlockedPopEntrySList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 3, "Expected item->value == 3, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 2, "Expected size == 2, got %u\n", size);
entry = InterlockedFlushSList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 2, "Expected item->value == 2, got %u\n", item->value); item = CONTAINING_RECORD(item->entry.Next, struct item, entry); ok(item->value == 1, "Expected item->value == 1, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 0, "Expected size == 0, got %u\n", size); entry = InterlockedPopEntrySList(&slist_header); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry);
/* test RtlInterlockedPushListSList */ entry = InterlockedPushEntrySList(&slist_header, &item3.entry); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); entry = call_func4(pRtlInterlockedPushListSList, &slist_header, &item2.entry, &item1.entry, 42); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 3, "Expected item->value == 3, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 43, "Expected size == 43, got %u\n", size);
entry = InterlockedPopEntrySList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 2, "Expected item->value == 2, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 42, "Expected size == 42, got %u\n", size);
entry = InterlockedPopEntrySList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 1, "Expected item->value == 1, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 41, "Expected size == 41, got %u\n", size);
entry = InterlockedPopEntrySList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 3, "Expected item->value == 3, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 40, "Expected size == 40, got %u\n", size);
entry = InterlockedPopEntrySList(&slist_header); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); size = QueryDepthSList(&slist_header); ok(size == 40, "Expected size == 40, got %u\n", size);
entry = InterlockedFlushSList(&slist_header); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); size = QueryDepthSList(&slist_header); ok(size == 40 || broken(size == 0) /* >= Win 8 */, "Expected size == 40, got %u\n", size);
entry = InterlockedPushEntrySList(&slist_header, &item1.entry); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); entry = InterlockedFlushSList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 1, "Expected item->value == 1, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 0, "Expected size == 0, got %u\n", size);
/* test RtlInterlockedPushListSListEx */ if (pRtlInterlockedPushListSListEx) { entry = InterlockedPushEntrySList(&slist_header, &item3.entry); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); entry = pRtlInterlockedPushListSListEx(&slist_header, &item2.entry, &item1.entry, 42); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 3, "Expected item->value == 3, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 43, "Expected size == 43, got %u\n", size);
entry = InterlockedFlushSList(&slist_header); ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == 2, "Expected item->value == 2, got %u\n", item->value); item = CONTAINING_RECORD(item->entry.Next, struct item, entry); ok(item->value == 1, "Expected item->value == 1, got %u\n", item->value); item = CONTAINING_RECORD(item->entry.Next, struct item, entry); ok(item->value == 3, "Expected item->value == 3, got %u\n", item->value); size = QueryDepthSList(&slist_header); ok(size == 0, "Expected size == 0, got %u\n", size); } else win_skip("RtlInterlockedPushListSListEx not available, skipping tests\n");
/* test with a lot of items */ for (i = 0; i < 65536; i++) { item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item)); item->value = i + 1; entry = InterlockedPushEntrySList(&slist_header, &item->entry); if (i) { ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == i, "Expected item->value == %u, got %u\n", i, item->value); } else { ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); } size = QueryDepthSList(&slist_header); ok(size == ((i + 1) & 0xffff), "Expected size == %u, got %u\n", (i + 1) & 0xffff, size); }
entry = InterlockedFlushSList(&slist_header); for (i = 65536; i > 0; i--) { ok(entry != NULL, "Expected entry != NULL, got %p\n", entry); item = CONTAINING_RECORD(entry, struct item, entry); ok(item->value == i, "Expected item->value == %u, got %u\n", i, item->value); entry = item->entry.Next; HeapFree(GetProcessHeap(), 0, item); } ok(entry == NULL, "Expected entry == NULL, got %p\n", entry); size = QueryDepthSList(&slist_header); ok(size == 0, "Expected size == 0, got %u\n", size); entry = InterlockedPopEntrySList(&slist_header); ok(entry == NULL, "Expected entry == NULL, got %p\n", entry);}
static void test_event(void){ HANDLE handle, handle2; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; ACL acl; DWORD ret; BOOL val;
/* no sd */#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");#endif ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle);
sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
/* blank sd */#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateEventA(&sa, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");#endif ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle);
/* sd with NULL dacl */ SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateEventA(&sa, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");#endif ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle);
/* sd with empty dacl */ InitializeAcl(&acl, sizeof(acl), ACL_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, &acl, FALSE);#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateEventA(&sa, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");#endif ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle);
/* test case sensitivity */
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");#endif ok( handle != NULL, "CreateEvent failed with error %lu\n", GetLastError()); ok( GetLastError() == 0, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");#endif ok( handle2 != NULL, "CreateEvent failed with error %ld\n", GetLastError()); ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": TEST EVENT");#else handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": TEST EVENT");#endif ok( handle2 != NULL, "CreateEvent failed with error %ld\n", GetLastError()); ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event");#endif ok( handle2 != NULL, "OpenEvent failed with error %ld\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": TEST EVENT");#else handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT");#endif ok( !handle2, "OpenEvent succeeded\n"); ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenEvent succeeded\n"); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle2 = OpenEventW( EVENT_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenEvent succeeded\n"); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
CloseHandle( handle );
/* resource notifications are events too */
if (!pCreateMemoryResourceNotification || !pQueryMemoryResourceNotification) { trace( "memory resource notifications not supported\n" ); return; } handle = pCreateMemoryResourceNotification( HighMemoryResourceNotification + 1 ); ok( !handle, "CreateMemoryResourceNotification succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pQueryMemoryResourceNotification( handle, &val ); ok( !ret, "QueryMemoryResourceNotification succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
handle = pCreateMemoryResourceNotification( LowMemoryResourceNotification ); ok( handle != 0, "CreateMemoryResourceNotification failed err %lu\n", GetLastError() ); ret = WaitForSingleObject( handle, 10 ); ok( ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT, "WaitForSingleObject wrong ret %lu\n", ret );
val = ~0; ret = pQueryMemoryResourceNotification( handle, &val ); ok( ret, "QueryMemoryResourceNotification failed err %lu\n", GetLastError() ); ok( val == FALSE || val == TRUE, "wrong value %u\n", val ); ret = CloseHandle( handle ); ok( ret, "CloseHandle failed err %lu\n", GetLastError() );
#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event");#else handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");#endif val = ~0; ret = pQueryMemoryResourceNotification( handle, &val ); ok( ret, "QueryMemoryResourceNotification failed err %lu\n", GetLastError() ); ok( val == FALSE || val == TRUE, "wrong value %u\n", val ); CloseHandle( handle );}
static void test_semaphore(void){ HANDLE handle, handle2;
/* test case sensitivity */
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateSemaphoreA(NULL, 0, 1, __FILE_FW_SLASH__ ": Test Semaphore");#else handle = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");#endif ok(handle != NULL, "CreateSemaphore failed with error %lu\n", GetLastError()); ok(GetLastError() == 0, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE_FW_SLASH__ ": Test Semaphore");#else handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");#endif ok( handle2 != NULL, "CreateSemaphore failed with error %ld\n", GetLastError()); ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE_FW_SLASH__ ": TEST SEMAPHORE");#else handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": TEST SEMAPHORE");#endif ok( handle2 != NULL, "CreateSemaphore failed with error %ld\n", GetLastError()); ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": Test Semaphore");#else handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore");#endif ok( handle2 != NULL, "OpenSemaphore failed with error %ld\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": TEST SEMAPHORE");#else handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE");#endif ok( !handle2, "OpenSemaphore succeeded\n"); ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenSemaphore succeeded\n"); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle2 = OpenSemaphoreW( SEMAPHORE_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenSemaphore succeeded\n"); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
CloseHandle( handle );}
static void test_waitable_timer(void){ HANDLE handle, handle2;
/* test case sensitivity */
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle = CreateWaitableTimerA(NULL, FALSE, __FILE_FW_SLASH__ ": Test WaitableTimer");#else handle = CreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");#endif ok(handle != NULL, "CreateWaitableTimer failed with error %lu\n", GetLastError()); ok(GetLastError() == 0, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE_FW_SLASH__ ": Test WaitableTimer");#else handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");#endif ok( handle2 != NULL, "CreateWaitableTimer failed with error %ld\n", GetLastError()); ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE_FW_SLASH__ ": TEST WAITABLETIMER");#else handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER");#endif ok( handle2 != NULL, "CreateWaitableTimer failed with error %ld\n", GetLastError()); ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": Test WaitableTimer");#else handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer");#endif ok( handle2 != NULL, "OpenWaitableTimer failed with error %ld\n", GetLastError()); CloseHandle( handle2 );
SetLastError(0xdeadbeef);#if defined(__REACTOS__) && defined(_MSC_VER) handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": TEST WAITABLETIMER");#else handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER");#endif ok( !handle2, "OpenWaitableTimer succeeded\n"); ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenWaitableTimer failed with error %ld\n", GetLastError()); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
SetLastError(0xdeadbeef); handle2 = OpenWaitableTimerW( TIMER_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenWaitableTimer failed with error %ld\n", GetLastError()); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError());
CloseHandle( handle );}
static HANDLE sem = 0;
static void CALLBACK iocp_callback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped){ ReleaseSemaphore(sem, 1, NULL);}
static BOOL (WINAPI *p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL;
static void test_iocp_callback(void){ char temp_path[MAX_PATH]; char filename[MAX_PATH]; DWORD ret; BOOL retb; static const char prefix[] = "pfx"; HANDLE hFile; HMODULE hmod = GetModuleHandleA("kernel32.dll"); DWORD bytesWritten; const char *buffer = "12345678123456781234567812345678"; OVERLAPPED overlapped;
p_BindIoCompletionCallback = (void*)GetProcAddress(hmod, "BindIoCompletionCallback"); if(!p_BindIoCompletionCallback) { win_skip("BindIoCompletionCallback not found in this DLL\n"); return; }
sem = CreateSemaphoreW(NULL, 0, 1, NULL); ok(sem != INVALID_HANDLE_VALUE, "Creating a semaphore failed\n");
ret = GetTempPathA(MAX_PATH, temp_path); ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
ret = GetTempFileNameA(temp_path, prefix, 0, filename); ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError());
retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %ld\n", GetLastError());
ret = CloseHandle(hFile); ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); ok( ret, "DeleteFileA: error %ld\n", GetLastError());
hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0); ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError());
retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == TRUE, "BindIoCompletionCallback failed\n");
memset(&overlapped, 0, sizeof(overlapped)); retb = WriteFile(hFile, buffer, 4, &bytesWritten, &overlapped); ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %ld\n", GetLastError());
ret = WaitForSingleObject(sem, 5000); ok(ret == WAIT_OBJECT_0, "Wait for the IO completion callback failed\n"); CloseHandle(sem);
retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the same callback on the file again\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(hFile, NULL, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the callback to NULL\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %ld\n", GetLastError());
ret = CloseHandle(hFile); ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); ok( ret, "DeleteFileA: error %ld\n", GetLastError());
/* win2k3 requires the Flags parameter to be zero */ SetLastError(0xdeadbeef); hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0); ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(hFile, iocp_callback, 12345); if (!retb) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); else ok(retb == TRUE, "BindIoCompletionCallback failed with Flags != 0\n"); ret = CloseHandle(hFile); ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); ok( ret, "DeleteFileA: error %ld\n", GetLastError());
retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n"); ok(GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_INVALID_PARAMETER, /* vista */ "Last error is %ld\n", GetLastError());}
static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut){ int *pn = p; ok(timedOut, "Timer callbacks should always time out\n"); ++*pn;}
struct timer_queue_data1{ int num_calls; int max_calls; HANDLE q, t;};
static void CALLBACK timer_queue_cb2(PVOID p, BOOLEAN timedOut){ struct timer_queue_data1 *d = p; ok(timedOut, "Timer callbacks should always time out\n"); if (d->t && ++d->num_calls == d->max_calls) { BOOL ret; SetLastError(0xdeadbeef); /* Note, XP SP2 does *not* do any deadlock checking, so passing INVALID_HANDLE_VALUE here will just hang. */ ret = DeleteTimerQueueTimer(d->q, d->t, NULL); ok(!ret, "DeleteTimerQueueTimer\n"); ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n"); }}
static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut){ struct timer_queue_data1 *d = p; ok(timedOut, "Timer callbacks should always time out\n"); if (d->t && ++d->num_calls == d->max_calls) { /* Basically kill the timer since it won't have time to run again. */ BOOL ret = ChangeTimerQueueTimer(d->q, d->t, 10000, 0); ok(ret, "ChangeTimerQueueTimer\n"); }}
static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut){ struct timer_queue_data1 *d = p; ok(timedOut, "Timer callbacks should always time out\n"); if (d->t) { /* This tests whether a timer gets flagged for deletion before or after the callback runs. If we start this timer with a period of zero (run once), then ChangeTimerQueueTimer will fail if the timer is already flagged. Hence we really run only once. Otherwise we will run multiple times. */ BOOL ret = ChangeTimerQueueTimer(d->q, d->t, 50, 50); ok(ret, "ChangeTimerQueueTimer\n"); ++d->num_calls; }}
static void CALLBACK timer_queue_cb5(PVOID p, BOOLEAN timedOut){ DWORD_PTR delay = (DWORD_PTR) p; ok(timedOut, "Timer callbacks should always time out\n"); if (delay) Sleep(delay);}
static void CALLBACK timer_queue_cb6(PVOID p, BOOLEAN timedOut){ struct timer_queue_data1 *d = p; ok(timedOut, "Timer callbacks should always time out\n"); /* This tests an original implementation bug where a deleted timer may get to run, but it is tricky to set up. */ if (d->q && d->num_calls++ == 0) { /* First run: delete ourselves, then insert and remove a timer that goes in front of us in the sorted timeout list. Once removed, we will still timeout at the faster timer's due time, but this should be a no-op if we are bug-free. There should not be a second run. We can test the value of num_calls later. */ BOOL ret; HANDLE t;
/* The delete will pend while we are in this callback. */ SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(d->q, d->t, NULL); ok(!ret, "DeleteTimerQueueTimer\n"); ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
ret = CreateTimerQueueTimer(&t, d->q, timer_queue_cb1, NULL, 100, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t != NULL, "CreateTimerQueueTimer\n");
ret = DeleteTimerQueueTimer(d->q, t, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueTimer\n");
/* Now we stay alive by hanging around in the callback. */ Sleep(500); }}
static void test_timer_queue(void){ HANDLE q, t0, t1, t2, t3, t4, t5; int n0, n1, n2, n3, n4, n5; struct timer_queue_data1 d1, d2, d3, d4; HANDLE e, et1, et2; BOOL ret, ret0;
/* Test asynchronous deletion of the queue. */ q = CreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError());
/* Test synchronous deletion of the queue and running timers. */ q = CreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
/* Not called. */ t0 = NULL; n0 = 0; ret = CreateTimerQueueTimer(&t0, q, timer_queue_cb1, &n0, 0, 300, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t0 != NULL, "CreateTimerQueueTimer\n"); ret0 = DeleteTimerQueueTimer(q, t0, NULL); ok((!ret0 && GetLastError() == ERROR_IO_PENDING) || broken(ret0), /* Win 2000 & XP & 2003 */ "DeleteTimerQueueTimer ret=%d le=%lu\n", ret0, GetLastError());
/* Called once. */ t1 = NULL; n1 = 0; ret = CreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 0, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t1 != NULL, "CreateTimerQueueTimer\n");
/* A slow one. */ t2 = NULL; n2 = 0; ret = CreateTimerQueueTimer(&t2, q, timer_queue_cb1, &n2, 0, 100, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t2 != NULL, "CreateTimerQueueTimer\n");
/* A fast one. */ t3 = NULL; n3 = 0; ret = CreateTimerQueueTimer(&t3, q, timer_queue_cb1, &n3, 0, 10, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t3 != NULL, "CreateTimerQueueTimer\n");
/* Start really late (it won't start). */ t4 = NULL; n4 = 0; ret = CreateTimerQueueTimer(&t4, q, timer_queue_cb1, &n4, 10000, 10, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t4 != NULL, "CreateTimerQueueTimer\n");
/* Start soon, but delay so long it won't run again. */ t5 = NULL; n5 = 0; ret = CreateTimerQueueTimer(&t5, q, timer_queue_cb1, &n5, 0, 10000, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t5 != NULL, "CreateTimerQueueTimer\n");
/* Give them a chance to do some work. */ Sleep(500);
/* Test deleting a once-only timer. */ ret = DeleteTimerQueueTimer(q, t1, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueTimer\n");
/* A periodic timer. */ ret = DeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueTimer\n");
ret = DeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueEx\n"); todo_wine ok(n0 == 1 || broken(ret0 && n0 == 0), "Timer callback 0 expected 1 got %d\n", n0); ok(n1 == 1, "Timer callback 1 expected 1 got %d\n", n1); ok(n2 < n3, "Timer callback 2 & 3 expected %d < %d\n", n2, n3); ok(n4 == 0, "Timer callback 4 expected 0 got %d\n", n4); ok(n5 == 1, "Timer callback 5 expected 1 got %d\n", n5);
/* Test synchronous deletion of the timer/queue with event trigger. */ e = CreateEventW(NULL, TRUE, FALSE, NULL); et1 = CreateEventW(NULL, TRUE, FALSE, NULL); et2 = CreateEventW(NULL, TRUE, FALSE, NULL); if (!e || !et1 || !et2) { skip("Failed to create timer queue descruction event\n"); return; }
q = CreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
/* Run once and finish quickly (should be done when we delete it). */ t1 = NULL; ret = CreateTimerQueueTimer(&t1, q, timer_queue_cb5, NULL, 0, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t1 != NULL, "CreateTimerQueueTimer\n");
/* Run once and finish slowly (shouldn't be done when we delete it). */ t2 = NULL; ret = CreateTimerQueueTimer(&t2, q, timer_queue_cb5, (PVOID) 1000, 0, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t2 != NULL, "CreateTimerQueueTimer\n");
/* Run once and finish quickly (should be done when we delete it). */ t3 = NULL; ret = CreateTimerQueueTimer(&t3, q, timer_queue_cb5, NULL, 0, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t3 != NULL, "CreateTimerQueueTimer\n");
/* Run once and finish slowly (shouldn't be done when we delete it). */ t4 = NULL; ret = CreateTimerQueueTimer(&t4, q, timer_queue_cb5, (PVOID) 1000, 0, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t4 != NULL, "CreateTimerQueueTimer\n");
/* Give them a chance to start. */ Sleep(400);
/* DeleteTimerQueueTimer always returns PENDING with a NULL event, even if the timer is finished. */ SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(q, t1, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(q, t2, NULL); ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n"); ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(q, t3, et1); ok(ret, "DeleteTimerQueueTimer call was expected to fail\n"); ok(GetLastError() == 0xdeadbeef, "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %ld\n", GetLastError()); ok(WaitForSingleObject(et1, 250) == WAIT_OBJECT_0, "Timer destruction event not triggered\n");
SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(q, t4, et2); ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n"); ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); ok(WaitForSingleObject(et2, 1000) == WAIT_OBJECT_0, "Timer destruction event not triggered\n");
SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, e); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0, "Queue destruction event not triggered\n"); CloseHandle(e);
/* Test deleting/changing a timer in execution. */ q = CreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
/* Test changing a once-only timer before it fires (this is allowed, whereas after it fires you cannot). */ n1 = 0; ret = CreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 10000, 0, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t1 != NULL, "CreateTimerQueueTimer\n"); ret = ChangeTimerQueueTimer(q, t1, 0, 0); ok(ret, "ChangeTimerQueueTimer\n");
d2.t = t2 = NULL; d2.num_calls = 0; d2.max_calls = 3; d2.q = q; ret = CreateTimerQueueTimer(&t2, q, timer_queue_cb2, &d2, 10, 10, 0); d2.t = t2; ok(ret, "CreateTimerQueueTimer\n"); ok(t2 != NULL, "CreateTimerQueueTimer\n");
d3.t = t3 = NULL; d3.num_calls = 0; d3.max_calls = 4; d3.q = q; ret = CreateTimerQueueTimer(&t3, q, timer_queue_cb3, &d3, 10, 10, 0); d3.t = t3; ok(ret, "CreateTimerQueueTimer\n"); ok(t3 != NULL, "CreateTimerQueueTimer\n");
d4.t = t4 = NULL; d4.num_calls = 0; d4.q = q; ret = CreateTimerQueueTimer(&t4, q, timer_queue_cb4, &d4, 10, 0, 0); d4.t = t4; ok(ret, "CreateTimerQueueTimer\n"); ok(t4 != NULL, "CreateTimerQueueTimer\n");
Sleep(500);
ret = DeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueEx\n"); ok(n1 == 1, "ChangeTimerQueueTimer\n"); ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n"); ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n"); ok(d4.num_calls == 1, "Timer flagged for deletion incorrectly\n");
/* Test an obscure bug that was in the original implementation. */ q = CreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
/* All the work is done in the callback. */ d1.t = t1 = NULL; d1.num_calls = 0; d1.q = q; ret = CreateTimerQueueTimer(&t1, q, timer_queue_cb6, &d1, 100, 100, WT_EXECUTELONGFUNCTION); d1.t = t1; ok(ret, "CreateTimerQueueTimer\n"); ok(t1 != NULL, "CreateTimerQueueTimer\n");
Sleep(750);
SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n");
/* Test functions on the default timer queue. */ t1 = NULL; n1 = 0; ret = CreateTimerQueueTimer(&t1, NULL, timer_queue_cb1, &n1, 1000, 1000, 0); ok(ret, "CreateTimerQueueTimer, default queue\n"); ok(t1 != NULL, "CreateTimerQueueTimer, default queue\n");
ret = ChangeTimerQueueTimer(NULL, t1, 2000, 2000); ok(ret, "ChangeTimerQueueTimer, default queue\n");
ret = DeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueTimer, default queue\n");
/* Try mixing default and non-default queues. Apparently this works. */ q = CreateTimerQueue(); ok(q != NULL, "CreateTimerQueue\n");
t1 = NULL; n1 = 0; ret = CreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 1000, 1000, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t1 != NULL, "CreateTimerQueueTimer\n");
t2 = NULL; n2 = 0; ret = CreateTimerQueueTimer(&t2, NULL, timer_queue_cb1, &n2, 1000, 1000, 0); ok(ret, "CreateTimerQueueTimer\n"); ok(t2 != NULL, "CreateTimerQueueTimer\n");
ret = ChangeTimerQueueTimer(NULL, t1, 2000, 2000); ok(ret, "ChangeTimerQueueTimer\n");
ret = ChangeTimerQueueTimer(q, t2, 2000, 2000); ok(ret, "ChangeTimerQueueTimer\n");
ret = DeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueTimer\n");
ret = DeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE); ok(ret, "DeleteTimerQueueTimer\n");
/* Try to delete the default queue? In any case: not allowed. */ SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(NULL, NULL); ok(!ret, "DeleteTimerQueueEx call was expected to fail\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, "DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError());}
static HANDLE modify_handle(HANDLE handle, DWORD modify){ DWORD tmp = HandleToULong(handle); tmp |= modify; return ULongToHandle(tmp);}
static void test_WaitForSingleObject(void){ HANDLE signaled, nonsignaled, invalid; LARGE_INTEGER timeout; NTSTATUS status; DWORD ret;
signaled = CreateEventW(NULL, TRUE, TRUE, NULL); nonsignaled = CreateEventW(NULL, TRUE, FALSE, NULL); invalid = (HANDLE) 0xdeadbee0;
/* invalid handle with different values for lower 2 bits */ SetLastError(0xdeadbeef); ret = WaitForSingleObject(invalid, 0); ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(invalid, 1), 0); ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(invalid, 2), 0); ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(invalid, 3), 0); ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
/* valid handle with different values for lower 2 bits */ SetLastError(0xdeadbeef); ret = WaitForSingleObject(nonsignaled, 0); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(nonsignaled, 1), 0); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(nonsignaled, 2), 0); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(nonsignaled, 3), 0); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
/* valid handle with different values for lower 2 bits */ SetLastError(0xdeadbeef); ret = WaitForSingleObject(signaled, 0); ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(signaled, 1), 0); ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(signaled, 2), 0); ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(signaled, 3), 0); ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
/* pseudo handles are allowed in WaitForSingleObject and NtWaitForSingleObject */ ret = WaitForSingleObject(GetCurrentProcess(), 100); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret);
ret = WaitForSingleObject(GetCurrentThread(), 100); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret);
timeout.QuadPart = -1000000; status = pNtWaitForSingleObject(GetCurrentProcess(), FALSE, &timeout); ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status);
timeout.QuadPart = -1000000; status = pNtWaitForSingleObject(GetCurrentThread(), FALSE, &timeout); ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status);
CloseHandle(signaled); CloseHandle(nonsignaled);}
static void test_WaitForMultipleObjects(void){ LARGE_INTEGER timeout; NTSTATUS status; DWORD r; int i; HANDLE maxevents[MAXIMUM_WAIT_OBJECTS];
/* create the maximum number of events and make sure * we can wait on that many */ for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++) { maxevents[i] = CreateEventW(NULL, i==0, TRUE, NULL); ok( maxevents[i] != 0, "should create enough events\n"); }
/* a manual-reset event remains signaled, an auto-reset event is cleared */ r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %ld\n", r); r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %ld\n", r); ok(ResetEvent(maxevents[0]), "ResetEvent\n"); for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++) { /* the lowest index is checked first and remaining events are untouched */ r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); ok( r == WAIT_OBJECT_0+i, "should signal handle #%d first, got %ld\n", i, r); }
/* run same test with Nt* call */ for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++) SetEvent(maxevents[i]);
/* a manual-reset event remains signaled, an auto-reset event is cleared */ status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, FALSE, NULL);#if defined(__REACTOS__) && defined(_WIN64) ok(status == STATUS_WAIT_0 || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */, "should signal lowest handle first, got %08lx\n", status);#else ok(status == STATUS_WAIT_0, "should signal lowest handle first, got %08lx\n", status);#endif status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, FALSE, NULL);#if defined(__REACTOS__) && defined(_WIN64) ok(status == STATUS_WAIT_0 || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */, "should signal handle #0 first, got %08lx\n", status);#else ok(status == STATUS_WAIT_0, "should signal handle #0 first, got %08lx\n", status);#endif ok(ResetEvent(maxevents[0]), "ResetEvent\n"); for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++) { /* the lowest index is checked first and remaining events are untouched */ status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, FALSE, NULL);#if defined(__REACTOS__) && defined(_WIN64) ok(status == STATUS_WAIT_0 + i || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */, "should signal handle #%d first, got %08lx\n", i, status);#else ok(status == STATUS_WAIT_0 + i, "should signal handle #%d first, got %08lx\n", i, status);#endif }
for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++) if (maxevents[i]) CloseHandle(maxevents[i]);
/* in contrast to WaitForSingleObject, pseudo handles are not allowed in * WaitForMultipleObjects and NtWaitForMultipleObjects */ maxevents[0] = GetCurrentProcess(); SetLastError(0xdeadbeef); r = WaitForMultipleObjects(1, maxevents, FALSE, 100); todo_wine ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r);#if defined(__REACTOS__) && defined(_WIN64) todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */,#else todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE,#endif "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError());
maxevents[0] = GetCurrentThread(); SetLastError(0xdeadbeef); r = WaitForMultipleObjects(1, maxevents, FALSE, 100); todo_wine ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r);#if defined(__REACTOS__) && defined(_WIN64) todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */,#else todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE,#endif "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError());
timeout.QuadPart = -1000000; maxevents[0] = GetCurrentProcess(); status = pNtWaitForMultipleObjects(1, maxevents, TRUE, FALSE, &timeout);#if defined(__REACTOS__) && defined(_WIN64) todo_wine ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */, "expected STATUS_INVALID_HANDLE, got %08lx\n", status);#else todo_wine ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status);#endif
timeout.QuadPart = -1000000; maxevents[0] = GetCurrentThread(); status = pNtWaitForMultipleObjects(1, maxevents, TRUE, FALSE, &timeout);#if defined(__REACTOS__) && defined(_WIN64) todo_wine ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_PARAMETER_3) /* x86_64 */, "expected STATUS_INVALID_HANDLE, got %08lx\n", status);#else todo_wine ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status);#endif}
static BOOL g_initcallback_ret, g_initcallback_called;static void *g_initctxt;
static BOOL CALLBACK initonce_callback(INIT_ONCE *initonce, void *parameter, void **ctxt){ g_initcallback_called = TRUE; /* zero bit set means here that initialization is taking place - initialization locked */ ok(g_initctxt == *ctxt, "got wrong context value %p, expected %p\n", *ctxt, g_initctxt); ok(initonce->Ptr == (void*)0x1, "got %p\n", initonce->Ptr); ok(parameter == (void*)0xdeadbeef, "got wrong parameter\n"); return g_initcallback_ret;}
static void test_initonce(void){ INIT_ONCE initonce; BOOL ret, pending;
if (!pInitOnceInitialize || !pInitOnceExecuteOnce) { win_skip("one-time initialization API not supported\n"); return; }
/* blocking initialization with callback */ initonce.Ptr = (void*)0xdeadbeef; pInitOnceInitialize(&initonce); ok(initonce.Ptr == NULL, "got %p\n", initonce.Ptr);
/* initialisation completed successfully */ g_initcallback_ret = TRUE; g_initctxt = NULL; ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0x2, "got %p\n", initonce.Ptr); ok(g_initctxt == NULL, "got %p\n", g_initctxt); ok(g_initcallback_called, "got %d\n", g_initcallback_called);
/* so it's been called already so won't be called again */ g_initctxt = NULL; g_initcallback_called = FALSE; ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0x2, "got %p\n", initonce.Ptr); ok(g_initctxt == NULL, "got %p\n", g_initctxt); ok(!g_initcallback_called, "got %d\n", g_initcallback_called);
pInitOnceInitialize(&initonce); g_initcallback_called = FALSE; /* 2 lower order bits should never be used, you'll get a crash in result */ g_initctxt = (void*)0xFFFFFFF0; ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0xFFFFFFF2, "got %p\n", initonce.Ptr); ok(g_initctxt == (void*)0xFFFFFFF0, "got %p\n", g_initctxt); ok(g_initcallback_called, "got %d\n", g_initcallback_called);
/* callback failed */ g_initcallback_ret = FALSE; g_initcallback_called = FALSE; g_initctxt = NULL; pInitOnceInitialize(&initonce); SetLastError( 0xdeadbeef ); ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt); ok(!ret && GetLastError() == 0xdeadbeef, "got wrong ret value %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == NULL, "got %p\n", initonce.Ptr); ok(g_initctxt == NULL, "got %p\n", g_initctxt); ok(g_initcallback_called, "got %d\n", g_initcallback_called);
/* blocking initialization without a callback */ pInitOnceInitialize(&initonce); g_initctxt = NULL; pending = FALSE; ret = pInitOnceBeginInitialize(&initonce, 0, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr); ok(g_initctxt == NULL, "got %p\n", g_initctxt); /* another attempt to begin initialization with block a single thread */
g_initctxt = NULL; pending = 0xf; SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_GEN_FAILURE, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending == 0xf, "got %d\n", pending); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr); ok(g_initctxt == NULL, "got %p\n", g_initctxt);
g_initctxt = (void*)0xdeadbee0; SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED, g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr);
/* once failed already */ g_initctxt = (void*)0xdeadbee0; ret = pInitOnceComplete(&initonce, 0, g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr);
pInitOnceInitialize(&initonce); SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED, NULL); ok(!ret && GetLastError() == ERROR_GEN_FAILURE, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == NULL, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == NULL, "got %p\n", initonce.Ptr);
ret = pInitOnceBeginInitialize(&initonce, 0, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, 0, (void *)0xdeadbeef); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr);
ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED, NULL); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == NULL, "got %p\n", initonce.Ptr);
pInitOnceInitialize(&initonce); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)3, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, 0, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());
ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)3, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)3, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)3, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_ASYNC, (void *)0xdeadbeef); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)3, "got %p\n", initonce.Ptr);
ret = pInitOnceComplete(&initonce, INIT_ONCE_ASYNC, (void *)0xdeadbee0); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceComplete(&initonce, INIT_ONCE_INIT_FAILED | INIT_ONCE_ASYNC, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr);
pInitOnceInitialize(&initonce); ret = pInitOnceBeginInitialize(&initonce, 0, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr);
/* test INIT_ONCE_CHECK_ONLY */
pInitOnceInitialize(&initonce); SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_GEN_FAILURE, "wrong ret %d err %lu\n", ret, GetLastError()); SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());
ret = pInitOnceBeginInitialize(&initonce, 0, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)1, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_GEN_FAILURE, "wrong ret %d err %lu\n", ret, GetLastError()); SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());
ret = pInitOnceComplete(&initonce, 0, (void *)0xdeadbee0); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr);
ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY, &pending, &g_initctxt); ok(ret, "got wrong ret value %d err %lu\n", ret, GetLastError()); ok(!pending, "got %d\n", pending); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr); ok(g_initctxt == (void*)0xdeadbee0, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());
pInitOnceInitialize(&initonce); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(pending, "got %d\n", pending); ok(initonce.Ptr == (void*)3, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_GEN_FAILURE, "wrong ret %d err %lu\n", ret, GetLastError()); SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());
ret = pInitOnceComplete(&initonce, INIT_ONCE_ASYNC, (void *)0xdeadbee0); ok(ret, "wrong ret %d err %lu\n", ret, GetLastError()); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr);
ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY, &pending, &g_initctxt); ok(ret, "got wrong ret value %d err %lu\n", ret, GetLastError()); ok(!pending, "got %d\n", pending); ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr); ok(g_initctxt == (void*)0xdeadbee0, "got %p\n", initonce.Ptr);
SetLastError( 0xdeadbeef ); ret = pInitOnceBeginInitialize(&initonce, INIT_ONCE_CHECK_ONLY|INIT_ONCE_ASYNC, &pending, &g_initctxt); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "wrong ret %d err %lu\n", ret, GetLastError());}
static CONDITION_VARIABLE buffernotempty = CONDITION_VARIABLE_INIT;static CONDITION_VARIABLE buffernotfull = CONDITION_VARIABLE_INIT;static CRITICAL_SECTION buffercrit;static BOOL condvar_stop = FALSE, condvar_sleeperr = FALSE;static LONG bufferlen,totalproduced,totalconsumed;static LONG condvar_producer_sleepcnt,condvar_consumer_sleepcnt;
#define BUFFER_SIZE 5
static DWORD WINAPI condvar_producer(LPVOID x) { DWORD sleepinterval = 5;
while (1) { Sleep(sleepinterval); if (sleepinterval > 1) sleepinterval -= 1;
EnterCriticalSection(&buffercrit); while ((bufferlen == BUFFER_SIZE) && !condvar_stop) { condvar_producer_sleepcnt++; if (!pSleepConditionVariableCS(&buffernotfull, &buffercrit, sleepinterval)) { if (GetLastError() != ERROR_TIMEOUT) condvar_sleeperr = TRUE; } } if (condvar_stop) { LeaveCriticalSection(&buffercrit); break; } bufferlen++; totalproduced++; LeaveCriticalSection(&buffercrit); pWakeConditionVariable(&buffernotempty); } return 0;}
static DWORD WINAPI condvar_consumer(LPVOID x) { DWORD *cnt = (DWORD*)x; DWORD sleepinterval = 1;
while (1) { EnterCriticalSection(&buffercrit); while ((bufferlen == 0) && !condvar_stop) { condvar_consumer_sleepcnt++; if (!pSleepConditionVariableCS (&buffernotempty, &buffercrit, sleepinterval)) { if (GetLastError() != ERROR_TIMEOUT) condvar_sleeperr = TRUE; } } if (condvar_stop && (bufferlen == 0)) { LeaveCriticalSection(&buffercrit); break; } bufferlen--; totalconsumed++; (*cnt)++; LeaveCriticalSection(&buffercrit); pWakeConditionVariable(&buffernotfull); Sleep(sleepinterval); if (sleepinterval < 5) sleepinterval += 1; } return 0;}
static void test_condvars_consumer_producer(void){ HANDLE hp1,hp2,hp3,hc1,hc2,hc3; DWORD dummy; DWORD cnt1,cnt2,cnt3;
if (!pInitializeConditionVariable) { /* function is not yet in XP, only in newer Windows */ win_skip("no condition variable support.\n"); return; }
/* Implement a producer / consumer scheme with non-full / non-empty triggers */
/* If we have static initialized condition variables, InitializeConditionVariable * is not strictly necessary. * pInitializeConditionVariable(&buffernotfull); */ pInitializeConditionVariable(&buffernotempty); InitializeCriticalSection(&buffercrit);
/* Larger Test: consumer/producer example */
bufferlen = totalproduced = totalconsumed = cnt1 = cnt2 = cnt3 = 0;
hp1 = CreateThread(NULL, 0, condvar_producer, NULL, 0, &dummy); hp2 = CreateThread(NULL, 0, condvar_producer, NULL, 0, &dummy); hp3 = CreateThread(NULL, 0, condvar_producer, NULL, 0, &dummy); hc1 = CreateThread(NULL, 0, condvar_consumer, (PVOID)&cnt1, 0, &dummy); hc2 = CreateThread(NULL, 0, condvar_consumer, (PVOID)&cnt2, 0, &dummy); hc3 = CreateThread(NULL, 0, condvar_consumer, (PVOID)&cnt3, 0, &dummy);
/* Limit run to 0.5 seconds. */ Sleep(500);
/* tear down start */ condvar_stop = TRUE;
/* final wake up call */ pWakeAllConditionVariable (&buffernotfull); pWakeAllConditionVariable (&buffernotempty);
/* (mostly an implementation detail) * ok(buffernotfull.Ptr == NULL, "buffernotfull.Ptr is %p\n", buffernotfull.Ptr); */
WaitForSingleObject(hp1, 1000); WaitForSingleObject(hp2, 1000); WaitForSingleObject(hp3, 1000); WaitForSingleObject(hc1, 1000); WaitForSingleObject(hc2, 1000); WaitForSingleObject(hc3, 1000);
ok(totalconsumed == totalproduced, "consumed %ld != produced %ld\n", totalconsumed, totalproduced); ok (!condvar_sleeperr, "error occurred during SleepConditionVariableCS\n");
/* Checking cnt1 - cnt2 for non-0 would be not good, the case where * one consumer does not get anything to do is possible. */ trace("produced %ld, c1 %ld, c2 %ld, c3 %ld\n", totalproduced, cnt1, cnt2, cnt3); /* The sleeps of the producer or consumer should not go above 100* produced count, * otherwise the implementation does not sleep correctly. But yet again, this is * not hard defined. */ trace("producer sleep %ld, consumer sleep %ld\n", condvar_producer_sleepcnt, condvar_consumer_sleepcnt);}
/* Sample test for some sequence of events happening, sequenced using "condvar_seq" */static DWORD condvar_seq = 0;static CONDITION_VARIABLE aligned_cv;static CRITICAL_SECTION condvar_crit;static SRWLOCK condvar_srwlock;
#include "pshpack1.h"static struct{ char c; CONDITION_VARIABLE cv;} unaligned_cv;#include "poppack.h"
/* Sequence of wake/sleep to check boundary conditions: * 0: init * 1: producer emits a WakeConditionVariable without consumer waiting. * 2: consumer sleeps without a wake expecting timeout * 3: producer emits a WakeAllConditionVariable without consumer waiting. * 4: consumer sleeps without a wake expecting timeout * 5: a wake is handed to a SleepConditionVariableCS * 6: a wakeall is handed to a SleepConditionVariableCS * 7: sleep after above should timeout * 8: wake with crit section locked into the sleep timeout * * the following tests will only be executed if InitializeSRWLock is available * * 9: producer (exclusive) wakes up consumer (exclusive) * 10: producer (exclusive) wakes up consumer (shared) * 11: producer (shared) wakes up consumer (exclusive) * 12: producer (shared) wakes up consumer (shared) * 13: end */static DWORD WINAPI condvar_base_producer(void *arg){ CONDITION_VARIABLE *cv = arg;
while (condvar_seq < 1) Sleep(1);
pWakeConditionVariable(cv); condvar_seq = 2;
while (condvar_seq < 3) Sleep(1); pWakeAllConditionVariable(cv); condvar_seq = 4;
while (condvar_seq < 5) Sleep(1); EnterCriticalSection (&condvar_crit); pWakeConditionVariable(cv); LeaveCriticalSection (&condvar_crit); while (condvar_seq < 6) Sleep(1); EnterCriticalSection (&condvar_crit); pWakeAllConditionVariable(cv); LeaveCriticalSection (&condvar_crit);
while (condvar_seq < 8) Sleep(1); EnterCriticalSection (&condvar_crit); pWakeConditionVariable(cv); Sleep(50); LeaveCriticalSection (&condvar_crit);
/* skip over remaining tests if InitializeSRWLock is not available */ if (!pInitializeSRWLock) return 0;
while (condvar_seq < 9) Sleep(1); pAcquireSRWLockExclusive(&condvar_srwlock); pWakeConditionVariable(cv); pReleaseSRWLockExclusive(&condvar_srwlock);
while (condvar_seq < 10) Sleep(1); pAcquireSRWLockExclusive(&condvar_srwlock); pWakeConditionVariable(cv); pReleaseSRWLockExclusive(&condvar_srwlock);
while (condvar_seq < 11) Sleep(1); pAcquireSRWLockShared(&condvar_srwlock); pWakeConditionVariable(cv); pReleaseSRWLockShared(&condvar_srwlock);
while (condvar_seq < 12) Sleep(1); Sleep(50); /* ensure that consumer waits for cond variable */ pAcquireSRWLockShared(&condvar_srwlock); pWakeConditionVariable(cv); pReleaseSRWLockShared(&condvar_srwlock);
return 0;}
static DWORD WINAPI condvar_base_consumer(void *arg){ CONDITION_VARIABLE *cv = arg; BOOL ret;
while (condvar_seq < 2) Sleep(1);
/* wake was emitted, but we were not sleeping */ EnterCriticalSection (&condvar_crit); ret = pSleepConditionVariableCS(cv, &condvar_crit, 10); LeaveCriticalSection (&condvar_crit); ok (!ret, "SleepConditionVariableCS should return FALSE on out of band wake\n"); ok (GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableCS should return ERROR_TIMEOUT on out of band wake, not %ld\n", GetLastError());
condvar_seq = 3; while (condvar_seq < 4) Sleep(1);
/* wake all was emitted, but we were not sleeping */ EnterCriticalSection (&condvar_crit); ret = pSleepConditionVariableCS(cv, &condvar_crit, 10); LeaveCriticalSection (&condvar_crit); ok (!ret, "SleepConditionVariableCS should return FALSE on out of band wake\n"); ok (GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableCS should return ERROR_TIMEOUT on out of band wake, not %ld\n", GetLastError());
EnterCriticalSection (&condvar_crit); condvar_seq = 5; ret = pSleepConditionVariableCS(cv, &condvar_crit, 200); LeaveCriticalSection (&condvar_crit); ok (ret, "SleepConditionVariableCS should return TRUE on good wake\n");
EnterCriticalSection (&condvar_crit); condvar_seq = 6; ret = pSleepConditionVariableCS(cv, &condvar_crit, 200); LeaveCriticalSection (&condvar_crit); ok (ret, "SleepConditionVariableCS should return TRUE on good wakeall\n"); condvar_seq = 7;
EnterCriticalSection (&condvar_crit); ret = pSleepConditionVariableCS(cv, &condvar_crit, 10); LeaveCriticalSection (&condvar_crit); ok (!ret, "SleepConditionVariableCS should return FALSE on out of band wake\n"); ok (GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableCS should return ERROR_TIMEOUT on out of band wake, not %ld\n", GetLastError());
EnterCriticalSection (&condvar_crit); condvar_seq = 8; ret = pSleepConditionVariableCS(cv, &condvar_crit, 20); LeaveCriticalSection (&condvar_crit); ok (ret, "SleepConditionVariableCS should still return TRUE on crit unlock delay\n");
/* skip over remaining tests if InitializeSRWLock is not available */ if (!pInitializeSRWLock) { win_skip("no srw lock support.\n"); condvar_seq = 13; /* end */ return 0; }
pAcquireSRWLockExclusive(&condvar_srwlock); condvar_seq = 9; ret = pSleepConditionVariableSRW(cv, &condvar_srwlock, 200, 0); pReleaseSRWLockExclusive(&condvar_srwlock); ok (ret, "pSleepConditionVariableSRW should return TRUE on good wake\n");
pAcquireSRWLockShared(&condvar_srwlock); condvar_seq = 10; ret = pSleepConditionVariableSRW(cv, &condvar_srwlock, 200, CONDITION_VARIABLE_LOCKMODE_SHARED); pReleaseSRWLockShared(&condvar_srwlock); ok (ret, "pSleepConditionVariableSRW should return TRUE on good wake\n");
pAcquireSRWLockExclusive(&condvar_srwlock); condvar_seq = 11; ret = pSleepConditionVariableSRW(cv, &condvar_srwlock, 200, 0); pReleaseSRWLockExclusive(&condvar_srwlock); ok (ret, "pSleepConditionVariableSRW should return TRUE on good wake\n");
pAcquireSRWLockShared(&condvar_srwlock); condvar_seq = 12; ret = pSleepConditionVariableSRW(cv, &condvar_srwlock, 200, CONDITION_VARIABLE_LOCKMODE_SHARED); pReleaseSRWLockShared(&condvar_srwlock); ok (ret, "pSleepConditionVariableSRW should return TRUE on good wake\n");
condvar_seq = 13; return 0;}
static void test_condvars_base(RTL_CONDITION_VARIABLE *cv){ HANDLE hp, hc; DWORD dummy; BOOL ret;
if (!pInitializeConditionVariable) { /* function is not yet in XP, only in newer Windows */ win_skip("no condition variable support.\n"); return; }
InitializeCriticalSection (&condvar_crit);
if (pInitializeSRWLock) pInitializeSRWLock(&condvar_srwlock);
EnterCriticalSection (&condvar_crit); ret = pSleepConditionVariableCS(cv, &condvar_crit, 10); LeaveCriticalSection (&condvar_crit);
ok (!ret, "SleepConditionVariableCS should return FALSE on untriggered condvar\n"); ok (GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableCS should return ERROR_TIMEOUT on untriggered condvar, not %ld\n", GetLastError());
if (pInitializeSRWLock) { pAcquireSRWLockExclusive(&condvar_srwlock); ret = pSleepConditionVariableSRW(cv, &condvar_srwlock, 10, 0); pReleaseSRWLockExclusive(&condvar_srwlock);
ok(!ret, "SleepConditionVariableSRW should return FALSE on untriggered condvar\n"); ok(GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableSRW should return ERROR_TIMEOUT on untriggered condvar, not %ld\n", GetLastError());
pAcquireSRWLockShared(&condvar_srwlock); ret = pSleepConditionVariableSRW(cv, &condvar_srwlock, 10, CONDITION_VARIABLE_LOCKMODE_SHARED); pReleaseSRWLockShared(&condvar_srwlock);
ok(!ret, "SleepConditionVariableSRW should return FALSE on untriggered condvar\n"); ok(GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableSRW should return ERROR_TIMEOUT on untriggered condvar, not %ld\n", GetLastError()); }
condvar_seq = 0; hp = CreateThread(NULL, 0, condvar_base_producer, cv, 0, &dummy); hc = CreateThread(NULL, 0, condvar_base_consumer, cv, 0, &dummy);
condvar_seq = 1; /* go */
while (condvar_seq < 9) Sleep (5); WaitForSingleObject(hp, 100); WaitForSingleObject(hc, 100);}
static LONG srwlock_seq = 0;static SRWLOCK aligned_srwlock;static struct{ LONG wrong_execution_order; LONG samethread_excl_excl; LONG samethread_excl_shared; LONG samethread_shared_excl; LONG multithread_excl_excl; LONG excl_not_preferred; LONG trylock_excl; LONG trylock_shared;} srwlock_base_errors;
#if defined(__i386__) || defined(__x86_64__)#include "pshpack1.h"struct{ char c; SRWLOCK lock;} unaligned_srwlock;#include "poppack.h"#endif
/* Sequence of acquire/release to check boundary conditions: * 0: init * * 1: thread2 acquires an exclusive lock and tries to acquire a second exclusive lock * 2: thread1 expects a deadlock and releases the waiting lock * thread2 releases the lock again * * 3: thread2 acquires an exclusive lock and tries to acquire a shared lock * 4: thread1 expects a deadlock and releases the waiting lock * thread2 releases the lock again * * 5: thread2 acquires a shared lock and tries to acquire an exclusive lock * 6: thread1 expects a deadlock and releases the waiting lock * thread2 releases the lock again * * 7: thread2 acquires and releases two nested shared locks * * 8: thread1 acquires an exclusive lock * 9: thread2 tries to acquire the exclusive lock, too * thread1 releases the exclusive lock again * 10: thread2 enters the exclusive lock and leaves it immediately again * * 11: thread1 acquires a shared lock * 12: thread2 acquires and releases a shared lock * thread1 releases the lock again * * 13: thread1 acquires a shared lock * 14: thread2 tries to acquire an exclusive lock * 15: thread3 tries to acquire a shared lock * 16: thread1 releases the shared lock * 17: thread2 wakes up and releases the exclusive lock * 18: thread3 wakes up and releases the shared lock * * the following tests will only be executed if TryAcquireSRWLock* is available * * 19: thread1 calls TryAcquireSRWLockExclusive which should return TRUE * thread1 checks the result of recursive calls to TryAcquireSRWLock* * thread1 releases the exclusive lock * * thread1 calls TryAcquireSRWLockShared which should return TRUE * thread1 checks the result of recursive calls to TryAcquireSRWLock* * thread1 releases the shared lock * * thread1 acquires an exclusive lock * 20: thread2 calls TryAcquireSRWLockShared which should return FALSE * thread2 calls TryAcquireSRWLockExclusive which should return FALSE * 21: thread1 releases the exclusive lock * * thread1 acquires an shared lock * 22: thread2 calls TryAcquireSRWLockShared which should return TRUE * thread2 calls TryAcquireSRWLockExclusive which should return FALSE * 23: thread1 releases the shared lock * * thread1 acquires a shared lock and tries to acquire an exclusive lock * 24: thread2 calls TryAcquireSRWLockShared which should return FALSE * thread2 calls TryAcquireSRWLockExclusive which should return FALSE * 25: thread1 releases the exclusive lock * * thread1 acquires two shared locks * 26: thread2 calls TryAcquireSRWLockShared which should return TRUE * thread2 calls TryAcquireSRWLockExclusive which should return FALSE * 27: thread1 releases one shared lock * 28: thread2 calls TryAcquireSRWLockShared which should return TRUE * thread2 calls TryAcquireSRWLockExclusive which should return FALSE * 29: thread1 releases the second shared lock * 30: thread2 calls TryAcquireSRWLockShared which should return TRUE * thread2 calls TryAcquireSRWLockExclusive which should return TRUE * * 31: end */
static DWORD WINAPI srwlock_base_thread1(void *arg){ SRWLOCK *lock = arg;
/* seq 2 */ while (srwlock_seq < 2) Sleep(1); Sleep(100); if (InterlockedIncrement(&srwlock_seq) != 3) InterlockedIncrement(&srwlock_base_errors.samethread_excl_excl); pReleaseSRWLockExclusive(lock);
/* seq 4 */ while (srwlock_seq < 4) Sleep(1); Sleep(100); if (InterlockedIncrement(&srwlock_seq) != 5) InterlockedIncrement(&srwlock_base_errors.samethread_excl_shared); pReleaseSRWLockExclusive(lock);
/* seq 6 */ while (srwlock_seq < 6) Sleep(1); Sleep(100); if (InterlockedIncrement(&srwlock_seq) != 7) InterlockedIncrement(&srwlock_base_errors.samethread_shared_excl); pReleaseSRWLockShared(lock);
/* seq 8 */ while (srwlock_seq < 8) Sleep(1); pAcquireSRWLockExclusive(lock); if (InterlockedIncrement(&srwlock_seq) != 9) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order); Sleep(100); if (InterlockedIncrement(&srwlock_seq) != 10) InterlockedIncrement(&srwlock_base_errors.multithread_excl_excl); pReleaseSRWLockExclusive(lock);
/* seq 11 */ while (srwlock_seq < 11) Sleep(1); pAcquireSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 12) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 13 */ while (srwlock_seq < 13) Sleep(1); pReleaseSRWLockShared(lock); pAcquireSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 14) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 16 */ while (srwlock_seq < 16) Sleep(1); Sleep(50); /* ensure that both the exclusive and shared access thread are queued */ if (InterlockedIncrement(&srwlock_seq) != 17) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order); pReleaseSRWLockShared(lock);
/* skip over remaining tests if TryAcquireSRWLock* is not available */ if (!pTryAcquireSRWLockExclusive) return 0;
/* seq 19 */ while (srwlock_seq < 19) Sleep(1); if (pTryAcquireSRWLockExclusive(lock)) { if (pTryAcquireSRWLockShared(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); pReleaseSRWLockExclusive(lock); } else InterlockedIncrement(&srwlock_base_errors.trylock_excl);
if (pTryAcquireSRWLockShared(lock)) { if (pTryAcquireSRWLockShared(lock)) pReleaseSRWLockShared(lock); else InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); pReleaseSRWLockShared(lock); } else InterlockedIncrement(&srwlock_base_errors.trylock_shared);
pAcquireSRWLockExclusive(lock); if (InterlockedIncrement(&srwlock_seq) != 20) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 21 */ while (srwlock_seq < 21) Sleep(1); pReleaseSRWLockExclusive(lock); pAcquireSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 22) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 23 */ while (srwlock_seq < 23) Sleep(1); pReleaseSRWLockShared(lock); pAcquireSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 24) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 25 */ pAcquireSRWLockExclusive(lock); if (srwlock_seq != 25) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order); pReleaseSRWLockExclusive(lock);
pAcquireSRWLockShared(lock); pAcquireSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 26) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 27 */ while (srwlock_seq < 27) Sleep(1); pReleaseSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 28) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 29 */ while (srwlock_seq < 29) Sleep(1); pReleaseSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 30) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
return 0;}
static DWORD WINAPI srwlock_base_thread2(void *arg){ SRWLOCK *lock = arg;
/* seq 1 */ while (srwlock_seq < 1) Sleep(1); pAcquireSRWLockExclusive(lock); if (InterlockedIncrement(&srwlock_seq) != 2) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 3 */ pAcquireSRWLockExclusive(lock); if (srwlock_seq != 3) InterlockedIncrement(&srwlock_base_errors.samethread_excl_excl); pReleaseSRWLockExclusive(lock); pAcquireSRWLockExclusive(lock); if (InterlockedIncrement(&srwlock_seq) != 4) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 5 */ pAcquireSRWLockShared(lock); if (srwlock_seq != 5) InterlockedIncrement(&srwlock_base_errors.samethread_excl_shared); pReleaseSRWLockShared(lock); pAcquireSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 6) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 7 */ pAcquireSRWLockExclusive(lock); if (srwlock_seq != 7) InterlockedIncrement(&srwlock_base_errors.samethread_shared_excl); pReleaseSRWLockExclusive(lock); pAcquireSRWLockShared(lock); pAcquireSRWLockShared(lock); pReleaseSRWLockShared(lock); pReleaseSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 8) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 9, 10 */ while (srwlock_seq < 9) Sleep(1); pAcquireSRWLockExclusive(lock); if (srwlock_seq != 10) InterlockedIncrement(&srwlock_base_errors.multithread_excl_excl); pReleaseSRWLockExclusive(lock); if (InterlockedIncrement(&srwlock_seq) != 11) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 12 */ while (srwlock_seq < 12) Sleep(1); pAcquireSRWLockShared(lock); pReleaseSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 13) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 14 */ while (srwlock_seq < 14) Sleep(1); if (InterlockedIncrement(&srwlock_seq) != 15) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 17 */ pAcquireSRWLockExclusive(lock); if (srwlock_seq != 17) InterlockedIncrement(&srwlock_base_errors.excl_not_preferred); if (InterlockedIncrement(&srwlock_seq) != 18) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order); pReleaseSRWLockExclusive(lock);
/* skip over remaining tests if TryAcquireSRWLock* is not available */ if (!pTryAcquireSRWLockExclusive) return 0;
/* seq 20 */ while (srwlock_seq < 20) Sleep(1); if (pTryAcquireSRWLockShared(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); if (InterlockedIncrement(&srwlock_seq) != 21) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 22 */ while (srwlock_seq < 22) Sleep(1); if (pTryAcquireSRWLockShared(lock)) pReleaseSRWLockShared(lock); else InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); if (InterlockedIncrement(&srwlock_seq) != 23) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 24 */ while (srwlock_seq < 24) Sleep(1); Sleep(50); /* ensure that exclusive access request is queued */ if (pTryAcquireSRWLockShared(lock)) { pReleaseSRWLockShared(lock); InterlockedIncrement(&srwlock_base_errors.excl_not_preferred); } if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); if (InterlockedIncrement(&srwlock_seq) != 25) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order); pReleaseSRWLockShared(lock);
/* seq 26 */ while (srwlock_seq < 26) Sleep(1); if (pTryAcquireSRWLockShared(lock)) pReleaseSRWLockShared(lock); else InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); if (InterlockedIncrement(&srwlock_seq) != 27) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 28 */ while (srwlock_seq < 28) Sleep(1); if (pTryAcquireSRWLockShared(lock)) pReleaseSRWLockShared(lock); else InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) InterlockedIncrement(&srwlock_base_errors.trylock_excl); if (InterlockedIncrement(&srwlock_seq) != 29) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 30 */ while (srwlock_seq < 30) Sleep(1); if (pTryAcquireSRWLockShared(lock)) pReleaseSRWLockShared(lock); else InterlockedIncrement(&srwlock_base_errors.trylock_shared); if (pTryAcquireSRWLockExclusive(lock)) pReleaseSRWLockExclusive(lock); else InterlockedIncrement(&srwlock_base_errors.trylock_excl); if (InterlockedIncrement(&srwlock_seq) != 31) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
return 0;}
static DWORD WINAPI srwlock_base_thread3(void *arg){ SRWLOCK *lock = arg;
/* seq 15 */ while (srwlock_seq < 15) Sleep(1); Sleep(50); /* some delay, so that thread2 can try to acquire a second exclusive lock */ if (InterlockedIncrement(&srwlock_seq) != 16) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* seq 18 */ pAcquireSRWLockShared(lock); if (srwlock_seq != 18) InterlockedIncrement(&srwlock_base_errors.excl_not_preferred); pReleaseSRWLockShared(lock); if (InterlockedIncrement(&srwlock_seq) != 19) InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
/* skip over remaining tests if TryAcquireSRWLock* is not available */ if (!pTryAcquireSRWLockExclusive) { /* function is only in Windows 7 and newer */ win_skip("no srw trylock support.\n"); srwlock_seq = 31; /* end */ return 0; }
return 0;}
static void test_srwlock_base(SRWLOCK *lock){ HANDLE h1, h2, h3; DWORD dummy;
if (!pInitializeSRWLock) { /* function is not yet in XP, only in newer Windows */ win_skip("no srw lock support.\n"); return; }
pInitializeSRWLock(lock); memset(&srwlock_base_errors, 0, sizeof(srwlock_base_errors)); srwlock_seq = 0;
h1 = CreateThread(NULL, 0, srwlock_base_thread1, lock, 0, &dummy); h2 = CreateThread(NULL, 0, srwlock_base_thread2, lock, 0, &dummy); h3 = CreateThread(NULL, 0, srwlock_base_thread3, lock, 0, &dummy);
srwlock_seq = 1; /* go */ while (srwlock_seq < 31) Sleep(5);
WaitForSingleObject(h1, 100); WaitForSingleObject(h2, 100); WaitForSingleObject(h3, 100);
ok(!srwlock_base_errors.wrong_execution_order, "thread commands were executed in the wrong order (occurred %ld times).\n", srwlock_base_errors.wrong_execution_order);
ok(!srwlock_base_errors.samethread_excl_excl, "AcquireSRWLockExclusive didn't block when called multiple times from the same thread (occurred %ld times).\n", srwlock_base_errors.samethread_excl_excl);
ok(!srwlock_base_errors.samethread_excl_shared, "AcquireSRWLockShared didn't block when the same thread holds an exclusive lock (occurred %ld times).\n", srwlock_base_errors.samethread_excl_shared);
ok(!srwlock_base_errors.samethread_shared_excl, "AcquireSRWLockExclusive didn't block when the same thread holds a shared lock (occurred %ld times).\n", srwlock_base_errors.samethread_shared_excl);
ok(!srwlock_base_errors.multithread_excl_excl, "AcquireSRWLockExclusive didn't block when a second thread holds the exclusive lock (occurred %ld times).\n", srwlock_base_errors.multithread_excl_excl);
ok(!srwlock_base_errors.excl_not_preferred, "thread waiting for exclusive access to the SHMLock was not preferred (occurred %ld times).\n", srwlock_base_errors.excl_not_preferred);
ok(!srwlock_base_errors.trylock_excl, "TryAcquireSRWLockExclusive didn't behave as expected (occurred %ld times).\n", srwlock_base_errors.trylock_excl);
ok(!srwlock_base_errors.trylock_shared, "TryAcquireSRWLockShared didn't behave as expected (occurred %ld times).\n", srwlock_base_errors.trylock_shared);
}
static SRWLOCK srwlock_example;static LONG srwlock_protected_value = 0;static LONG srwlock_example_errors = 0, srwlock_inside = 0, srwlock_cnt = 0;static BOOL srwlock_stop = FALSE;
static DWORD WINAPI srwlock_example_thread(LPVOID x) { DWORD *cnt = x; LONG old;
while (!srwlock_stop) {
/* periodically request exclusive access */ if (InterlockedIncrement(&srwlock_cnt) % 13 == 0) { pAcquireSRWLockExclusive(&srwlock_example); if (InterlockedIncrement(&srwlock_inside) != 1) InterlockedIncrement(&srwlock_example_errors);
InterlockedIncrement(&srwlock_protected_value); Sleep(1);
if (InterlockedDecrement(&srwlock_inside) != 0) InterlockedIncrement(&srwlock_example_errors); pReleaseSRWLockExclusive(&srwlock_example); }
/* request shared access */ pAcquireSRWLockShared(&srwlock_example); InterlockedIncrement(&srwlock_inside); old = srwlock_protected_value;
(*cnt)++; Sleep(1);
if (old != srwlock_protected_value) InterlockedIncrement(&srwlock_example_errors); InterlockedDecrement(&srwlock_inside); pReleaseSRWLockShared(&srwlock_example); }
return 0;}
static void test_srwlock_example(void){ HANDLE h1, h2, h3; DWORD dummy; DWORD cnt1, cnt2, cnt3;
if (!pInitializeSRWLock) { /* function is not yet in XP, only in newer Windows */ win_skip("no srw lock support.\n"); return; }
pInitializeSRWLock(&srwlock_example);
cnt1 = cnt2 = cnt3 = 0;
h1 = CreateThread(NULL, 0, srwlock_example_thread, &cnt1, 0, &dummy); h2 = CreateThread(NULL, 0, srwlock_example_thread, &cnt2, 0, &dummy); h3 = CreateThread(NULL, 0, srwlock_example_thread, &cnt3, 0, &dummy);
/* limit run to 1 second. */ Sleep(1000);
/* tear down start */ srwlock_stop = TRUE;
WaitForSingleObject(h1, 1000); WaitForSingleObject(h2, 1000); WaitForSingleObject(h3, 1000);
ok(!srwlock_inside, "threads didn't terminate properly, srwlock_inside is %ld.\n", srwlock_inside); ok(!srwlock_example_errors, "errors occurred while running SRWLock example test (number of errors: %ld)\n", srwlock_example_errors);
trace("number of shared accesses per thread are c1 %ld, c2 %ld, c3 %ld\n", cnt1, cnt2, cnt3); trace("number of total exclusive accesses is %ld\n", srwlock_protected_value);}
static void test_srwlock_quirk(void){ union { SRWLOCK *s; LONG *l; } u = { &srwlock_example };
if (!pInitializeSRWLock) { /* function is not yet in XP, only in newer Windows */ win_skip("no srw lock support.\n"); return; }
/* WeCom 4.x checks releasing a lock with value 0x1 results in it becoming 0x0. */ *u.l = 1; pReleaseSRWLockExclusive(&srwlock_example); ok(*u.l == 0, "expected 0x0, got %lx\n", *u.l);}
static DWORD WINAPI alertable_wait_thread(void *param){ HANDLE *semaphores = param; LARGE_INTEGER timeout; NTSTATUS status; DWORD result;
ReleaseSemaphore(semaphores[0], 1, NULL); result = WaitForMultipleObjectsEx(1, &semaphores[1], TRUE, 1000, TRUE); ok(result == WAIT_IO_COMPLETION, "expected WAIT_IO_COMPLETION, got %lu\n", result); result = WaitForMultipleObjectsEx(1, &semaphores[1], TRUE, 200, TRUE); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result);
ReleaseSemaphore(semaphores[0], 1, NULL); timeout.QuadPart = -10000000; status = pNtWaitForMultipleObjects(1, &semaphores[1], FALSE, TRUE, &timeout); ok(status == STATUS_USER_APC, "expected STATUS_USER_APC, got %08lx\n", status); timeout.QuadPart = -2000000; status = pNtWaitForMultipleObjects(1, &semaphores[1], FALSE, TRUE, &timeout); ok(status == STATUS_WAIT_0, "expected STATUS_WAIT_0, got %08lx\n", status);
ReleaseSemaphore(semaphores[0], 1, NULL); timeout.QuadPart = -10000000; status = pNtWaitForMultipleObjects(1, &semaphores[1], FALSE, TRUE, &timeout); ok(status == STATUS_USER_APC, "expected STATUS_USER_APC, got %08lx\n", status); result = WaitForSingleObject(semaphores[0], 0); ok(result == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", result);
return 0;}
static void CALLBACK alertable_wait_apc(ULONG_PTR userdata){ HANDLE *semaphores = (void *)userdata; ReleaseSemaphore(semaphores[1], 1, NULL);}
static void CALLBACK alertable_wait_apc2(ULONG_PTR userdata){ HANDLE *semaphores = (void *)userdata; DWORD result;
result = WaitForSingleObject(semaphores[0], 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result);}
static void test_alertable_wait(void){ HANDLE thread, semaphores[2]; DWORD result;
semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); ok(semaphores[0] != NULL, "CreateSemaphore failed with %lu\n", GetLastError()); semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); ok(semaphores[1] != NULL, "CreateSemaphore failed with %lu\n", GetLastError()); thread = CreateThread(NULL, 0, alertable_wait_thread, semaphores, 0, NULL); ok(thread != NULL, "CreateThread failed with %lu\n", GetLastError());
result = WaitForSingleObject(semaphores[0], 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); Sleep(100); /* ensure the thread is blocking in WaitForMultipleObjectsEx */ result = QueueUserAPC(alertable_wait_apc, thread, (ULONG_PTR)semaphores); ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
result = WaitForSingleObject(semaphores[0], 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); Sleep(100); /* ensure the thread is blocking in NtWaitForMultipleObjects */ result = QueueUserAPC(alertable_wait_apc, thread, (ULONG_PTR)semaphores); ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
result = WaitForSingleObject(semaphores[0], 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); Sleep(100); /* ensure the thread is blocking in NtWaitForMultipleObjects */ result = QueueUserAPC(alertable_wait_apc2, thread, (ULONG_PTR)semaphores); ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); result = QueueUserAPC(alertable_wait_apc2, thread, (ULONG_PTR)semaphores); ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); ReleaseSemaphore(semaphores[0], 2, NULL);
result = WaitForSingleObject(thread, 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); CloseHandle(thread); CloseHandle(semaphores[0]); CloseHandle(semaphores[1]);}
struct apc_deadlock_info{ PROCESS_INFORMATION *pi; HANDLE event; BOOL running;};
static DWORD WINAPI apc_deadlock_thread(void *param){ struct apc_deadlock_info *info = param; PROCESS_INFORMATION *pi = info->pi; NTSTATUS status; SIZE_T size; void *base;
while (info->running) { base = NULL; size = 0x1000; status = pNtAllocateVirtualMemory(pi->hProcess, &base, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); ok(!status, "expected STATUS_SUCCESS, got %08lx\n", status); ok(base != NULL, "expected base != NULL, got %p\n", base); SetEvent(info->event);
size = 0; status = pNtFreeVirtualMemory(pi->hProcess, &base, &size, MEM_RELEASE); ok(!status, "expected STATUS_SUCCESS, got %08lx\n", status); SetEvent(info->event); }
return 0;}
static void test_apc_deadlock(void){ struct apc_deadlock_info info; PROCESS_INFORMATION pi; STARTUPINFOA si = { sizeof(si) }; char cmdline[MAX_PATH]; HANDLE event, thread; DWORD result; BOOL success; char **argv; int i;
winetest_get_mainargs(&argv); sprintf(cmdline, "\"%s\" sync apc_deadlock", argv[0]); success = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); ok(success, "CreateProcess failed with %lu\n", GetLastError());
event = CreateEventA(NULL, FALSE, FALSE, NULL); ok(event != NULL, "CreateEvent failed with %lu\n", GetLastError());
info.pi = π info.event = event; info.running = TRUE;
thread = CreateThread(NULL, 0, apc_deadlock_thread, &info, 0, NULL); ok(thread != NULL, "CreateThread failed with %lu\n", GetLastError()); result = WaitForSingleObject(event, 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result);
for (i = 0; i < 1000 && info.running; i++) { result = SuspendThread(pi.hThread); ok(result == 0, "expected 0, got %lu\n", result);
WaitForSingleObject(event, 0); /* reset event */ result = WaitForSingleObject(event, 1000); if (result == WAIT_TIMEOUT) { todo_wine ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); info.running = FALSE; } else ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result);
result = ResumeThread(pi.hThread); ok(result == 1, "expected 1, got %lu\n", result); Sleep(1); }
info.running = FALSE; result = WaitForSingleObject(thread, 1000); ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); CloseHandle(thread); CloseHandle(event);
TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hThread); CloseHandle(pi.hProcess);}
static jmp_buf bad_cs_jmpbuf;
static LONG WINAPI bad_cs_handler( EXCEPTION_POINTERS *eptr ){ EXCEPTION_RECORD *rec = eptr->ExceptionRecord;
ok(!rec->NumberParameters, "got %lu.\n", rec->NumberParameters); ok(rec->ExceptionFlags == EXCEPTION_NONCONTINUABLE || rec->ExceptionFlags == (EXCEPTION_NONCONTINUABLE | EXCEPTION_SOFTWARE_ORIGINATE), "got %#lx.\n", rec->ExceptionFlags); longjmp(bad_cs_jmpbuf, rec->ExceptionCode); return EXCEPTION_CONTINUE_SEARCH;}
static void test_crit_section(void){ void *vectored_handler; CRITICAL_SECTION cs; int exc_code; HANDLE old; BOOL ret;
/* Win8+ does not initialize debug info, one has to use RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO to override that. */ memset(&cs, 0, sizeof(cs)); InitializeCriticalSection(&cs); ok(cs.DebugInfo == (void *)(ULONG_PTR)-1 || broken(!!cs.DebugInfo) /* before Win8 */, "Unexpected debug info pointer %p.\n", cs.DebugInfo); DeleteCriticalSection(&cs); ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
if (!pInitializeCriticalSectionEx) { win_skip("InitializeCriticalSectionEx isn't available, skipping tests.\n"); return; }
memset(&cs, 0, sizeof(cs)); ret = pInitializeCriticalSectionEx(&cs, 0, 0); ok(ret, "Failed to initialize critical section.\n"); ok(cs.DebugInfo == (void *)(ULONG_PTR)-1 || broken(!!cs.DebugInfo) /* before Win8 */, "Unexpected debug info pointer %p.\n", cs.DebugInfo); DeleteCriticalSection(&cs); ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
memset(&cs, 0, sizeof(cs)); ret = pInitializeCriticalSectionEx(&cs, 0, CRITICAL_SECTION_NO_DEBUG_INFO); ok(ret, "Failed to initialize critical section.\n"); ok(cs.DebugInfo == (void *)(ULONG_PTR)-1, "Unexpected debug info pointer %p.\n", cs.DebugInfo); DeleteCriticalSection(&cs); ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
memset(&cs, 0, sizeof(cs)); ret = pInitializeCriticalSectionEx(&cs, 0, 0); ok(ret, "Failed to initialize critical section.\n"); ok(cs.DebugInfo == (void *)(ULONG_PTR)-1 || broken(!!cs.DebugInfo) /* before Win8 */, "Unexpected debug info pointer %p.\n", cs.DebugInfo); DeleteCriticalSection(&cs); ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
memset(&cs, 0, sizeof(cs)); ret = pInitializeCriticalSectionEx(&cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); ok(ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* before Win8 */, "Failed to initialize critical section, error %lu.\n", GetLastError()); if (!ret) { ret = pInitializeCriticalSectionEx(&cs, 0, 0); ok(ret, "Failed to initialize critical section.\n"); } ok(cs.DebugInfo && cs.DebugInfo != (void *)(ULONG_PTR)-1, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
ret = TryEnterCriticalSection(&cs); ok(ret, "Failed to enter critical section.\n"); LeaveCriticalSection(&cs);
cs.DebugInfo = NULL;
ret = TryEnterCriticalSection(&cs); ok(ret, "Failed to enter critical section.\n"); LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs); ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo);
ret = pInitializeCriticalSectionEx(&cs, 0, 0); ok(ret, "got error %lu.\n", GetLastError()); old = cs.LockSemaphore; cs.LockSemaphore = (HANDLE)0xdeadbeef;
cs.LockCount = 0; vectored_handler = AddVectoredExceptionHandler(TRUE, bad_cs_handler); if (!(exc_code = setjmp(bad_cs_jmpbuf))) EnterCriticalSection(&cs); ok(cs.LockCount, "got %ld.\n", cs.LockCount); ok(exc_code == STATUS_INVALID_HANDLE, "got %#x.\n", exc_code); RemoveVectoredExceptionHandler(vectored_handler); cs.LockSemaphore = old; DeleteCriticalSection(&cs);}
static DWORD WINAPI thread_proc(LPVOID unused){ Sleep(INFINITE); return 0;}
static int apc_count;
static void CALLBACK user_apc(ULONG_PTR unused){ apc_count++;}
static void CALLBACK call_user_apc(ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3){ PAPCFUNC func = (PAPCFUNC)arg1; func(arg2);}
static void test_QueueUserAPC(void){ HANDLE thread; DWORD tid, ret; NTSTATUS status;
thread = CreateThread(NULL, 0, thread_proc, NULL, CREATE_SUSPENDED, &tid); ok(thread != NULL, "CreateThread error %lu\n", GetLastError());
ret = TerminateThread(thread, 0xdeadbeef); ok(ret, "TerminateThread error %lu\n", GetLastError());
ret = WaitForSingleObject(thread, 1000); ok(ret == WAIT_OBJECT_0, "got %lu\n", ret);
ret = pNtQueueApcThread(thread, call_user_apc, (ULONG_PTR)user_apc, 0, 0); ok(ret == STATUS_UNSUCCESSFUL, "got %#lx\n", ret); ret = pNtQueueApcThread(thread, NULL, 0, 0, 0); ok(ret == STATUS_UNSUCCESSFUL, "got %#lx\n", ret);
SetLastError(0xdeadbeef); ret = QueueUserAPC(user_apc, thread, 0); ok(!ret, "QueueUserAPC should fail\n");#ifdef __REACTOS__ ok(GetLastError() == ERROR_GEN_FAILURE || broken(GetLastError() == 0xdeadbeef) /* WS03 */, "got %lu\n", GetLastError());#else ok(GetLastError() == ERROR_GEN_FAILURE, "got %lu\n", GetLastError());#endif
CloseHandle(thread);
apc_count = 0; ret = QueueUserAPC(user_apc, GetCurrentThread(), 0); ok(ret, "QueueUserAPC failed err %lu\n", GetLastError()); ok(!apc_count, "APC count %u\n", apc_count); ret = SleepEx( 100, TRUE ); ok( ret == WAIT_IO_COMPLETION, "SleepEx returned %lu\n", ret); ok(apc_count == 1, "APC count %u\n", apc_count);
ret = pNtQueueApcThread( GetCurrentThread(), NULL, 0, 0, 0 ); ok( !ret, "got %#lx\n", ret); ret = SleepEx( 100, TRUE ); ok( ret == WAIT_OBJECT_0, "SleepEx returned %lu\n", ret);
apc_count = 0; ret = QueueUserAPC(user_apc, GetCurrentThread(), 0); ok(ret, "QueueUserAPC failed err %lu\n", GetLastError()); ok(!apc_count, "APC count %u\n", apc_count); status = pNtTestAlert(); ok(!status, "got %lx\n", status); ok(apc_count == 1, "APC count %u\n", apc_count); status = pNtTestAlert(); ok(!status, "got %lx\n", status); ok(apc_count == 1, "APC count %u\n", apc_count);}
START_TEST(sync){ char **argv; int argc; HMODULE hdll = GetModuleHandleA("kernel32.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll");
pInitOnceInitialize = (void *)GetProcAddress(hdll, "InitOnceInitialize"); pInitOnceExecuteOnce = (void *)GetProcAddress(hdll, "InitOnceExecuteOnce"); pInitOnceBeginInitialize = (void *)GetProcAddress(hdll, "InitOnceBeginInitialize"); pInitOnceComplete = (void *)GetProcAddress(hdll, "InitOnceComplete"); pInitializeConditionVariable = (void *)GetProcAddress(hdll, "InitializeConditionVariable"); pSleepConditionVariableCS = (void *)GetProcAddress(hdll, "SleepConditionVariableCS"); pSleepConditionVariableSRW = (void *)GetProcAddress(hdll, "SleepConditionVariableSRW"); pWakeAllConditionVariable = (void *)GetProcAddress(hdll, "WakeAllConditionVariable"); pWakeConditionVariable = (void *)GetProcAddress(hdll, "WakeConditionVariable"); pInitializeCriticalSectionEx = (void *)GetProcAddress(hdll, "InitializeCriticalSectionEx"); pInitializeSRWLock = (void *)GetProcAddress(hdll, "InitializeSRWLock"); pAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "AcquireSRWLockExclusive"); pAcquireSRWLockShared = (void *)GetProcAddress(hdll, "AcquireSRWLockShared"); pReleaseSRWLockExclusive = (void *)GetProcAddress(hdll, "ReleaseSRWLockExclusive"); pReleaseSRWLockShared = (void *)GetProcAddress(hdll, "ReleaseSRWLockShared"); pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "TryAcquireSRWLockExclusive"); pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared"); pNtAllocateVirtualMemory = (void *)GetProcAddress(hntdll, "NtAllocateVirtualMemory"); pNtFreeVirtualMemory = (void *)GetProcAddress(hntdll, "NtFreeVirtualMemory"); pNtWaitForSingleObject = (void *)GetProcAddress(hntdll, "NtWaitForSingleObject"); pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects"); pRtlInterlockedPushListSList = (void *)GetProcAddress(hntdll, "RtlInterlockedPushListSList"); pRtlInterlockedPushListSListEx = (void *)GetProcAddress(hntdll, "RtlInterlockedPushListSListEx"); pNtQueueApcThread = (void *)GetProcAddress(hntdll, "NtQueueApcThread"); pNtTestAlert = (void *)GetProcAddress(hntdll, "NtTestAlert");
argc = winetest_get_mainargs( &argv ); if (argc >= 3) { if (!strcmp(argv[2], "apc_deadlock")) { for (;;) SleepEx(INFINITE, TRUE); } return; }
init_fastcall_thunk();
test_QueueUserAPC(); test_signalandwait(); test_temporary_objects(); test_mutex(); test_slist(); test_event(); test_semaphore(); test_waitable_timer(); test_iocp_callback(); test_timer_queue(); test_WaitForSingleObject(); test_WaitForMultipleObjects(); test_initonce(); test_condvars_base(&aligned_cv); test_condvars_base(&unaligned_cv.cv); test_condvars_consumer_producer(); test_srwlock_base(&aligned_srwlock); test_srwlock_quirk();#if defined(__i386__) || defined(__x86_64__) /* unaligned locks only work on x86 platforms */ test_srwlock_base(&unaligned_srwlock.lock);#endif test_srwlock_example(); test_alertable_wait(); test_apc_deadlock(); test_crit_section();}