void Server(UT_ARGUMENT arg) { serverStarted = true; if ( clientStarted ) UtActivate(utClient); for (;;) { if (!hasWork) UtDeactivate(); if (end) break; res = factorial(n); hasAnswer = true; hasWork = false; UtActivate(utClient); } }
VOID EventSignal (PEVENT Event) { if (IsListEmpty(&Event->Waiters)) { Event->Signaled = TRUE; } else { PWAIT_BLOCK WaitBlockPtr = CONTAINING_RECORD(RemoveHeadList(&Event->Waiters), WAIT_BLOCK, Link); UtActivate(WaitBlockPtr->Thread); } }
void Client(UT_ARGUMENT arg) { int i; long * numbers = (long *)arg; clientStarted = true; if ( ! serverStarted ) UtDeactivate(); for (i = 0; i < MAX_WORK; i++) { n = numbers[i]; hasWork = true; hasAnswer = false; UtActivate(utServer); if (!hasAnswer) UtDeactivate(); numbers[i] = res; } end = true; hasWork = true; UtActivate(utServer); }
VOID SignalLatch (PCountDownLatch CountDownLatch) { // decrementa o contador interno, desbloqueando todas as threads em espera se este chegar a zero if (CountDownLatch->counter == 0) { } CountDownLatch->counter--; if (CountDownLatch->counter == 0) { while (!IsListEmpty(&CountDownLatch->Waiters)) { PWAIT_BLOCK WaitBlockPtr = CONTAINING_RECORD(RemoveHeadList(&CountDownLatch->Waiters), WAIT_BLOCK, Link); UtActivate(WaitBlockPtr->Thread); } } }
// // Creates a user thread to run the specified function. The thread is placed // at the end of the ready queue. // HANDLE UtCreate64(UT_FUNCTION Function, UT_ARGUMENT Argument, PUCHAR name, DWORD stacksize) { PUTHREAD Thread; // // Dynamically allocate an instance of UTHREAD and the associated stack. // Thread = (PUTHREAD)malloc(sizeof(UTHREAD)); Thread->Name = name; Thread->Stack = (PUCHAR)malloc(stacksize); //Thread->Stack = (PUCHAR) malloc(STACK_SIZE); _ASSERTE(Thread != NULL && Thread->Stack != NULL); // // Zero the stack for emotional confort. // //memset(Thread->Stack, 0, STACK_SIZE); memset(Thread->Stack, 0, stacksize); // // Memorize Function and Argument for use in InternalStart. // Thread->Function = Function; Thread->Argument = Argument; Thread->State = READY; // // Map an UTHREAD_CONTEXT instance on the thread's stack. // We'll use it to save the initial context of the thread. // // +------------+ <- Highest word of a thread's stack space // | 0x00000000 | (needs to be set to 0 for Visual Studio to // +------------+ correctly present a thread's call stack). // | 0x00000000 | \ // +------------+ | // | 0x00000000 | | <-- Shadow Area for Internal Start // +------------+ | // | 0x00000000 | | // +------------+ | // | 0x00000000 | / // +============+ // | RetAddr | \ // +------------+ | // | RBP | | // +------------+ | // | RBX | > Thread->ThreadContext mapped on the stack. // +------------+ | // | RDI | | // +------------+ | // | RSI | | // +------------+ | // | R12 | | // +------------+ | // | R13 | | // +------------+ | // | R14 | | // +------------+ | // | R15 | / <- The stack pointer will be set to this address // +============+ at the next context switch to this thread. // | | \ // +------------+ | // | : | | // : > Remaining stack space. // | : | | // +------------+ | // | | / <- Lowest word of a thread's stack space // +------------+ (Thread->Stack always points to this location). // Thread->ThreadContext = (PUTHREAD_CONTEXT)(Thread->Stack + STACK_SIZE - sizeof(UTHREAD_CONTEXT) - sizeof(ULONGLONG) * 5); // // Set the thread's initial context by initializing the values of // registers that must be saved by the called (R15,R14,R13,R12, RSI, RDI, RBCX, RBP) // // Upon the first context switch to this thread, after popping the dummy // values of the "saved" registers, a ret instruction will place the // address of InternalStart on EIP. // Thread->ThreadContext->R15 = 0x77777777; Thread->ThreadContext->R14 = 0x66666666; Thread->ThreadContext->R13 = 0x55555555; Thread->ThreadContext->R12 = 0x44444444; Thread->ThreadContext->RSI = 0x33333333; Thread->ThreadContext->RDI = 0x11111111; Thread->ThreadContext->RBX = 0x22222222; Thread->ThreadContext->RBP = 0x11111111; Thread->ThreadContext->RetAddr = InternalStart; InitializeListHead(&Thread->Joiners); InsertTailList(&AliveThreads, &Thread->alive); // // Ready the thread. // NumberOfThreads += 1; UtActivate((HANDLE)Thread); return (HANDLE)Thread; }
// // Creates a user thread to run the specified function. The thread is placed // at the end of the ready queue. // HANDLE UtCreate32(UT_FUNCTION Function, UT_ARGUMENT Argument, PUCHAR name, DWORD stacksize) { PUTHREAD Thread; // // Dynamically allocate an instance of UTHREAD and the associated stack. // Thread = (PUTHREAD)malloc(sizeof(UTHREAD)); Thread->Name = name; //Thread->Stack = (PUCHAR) malloc(STACK_SIZE); Thread->Stack = (PUCHAR)malloc(stacksize); _ASSERTE(Thread != NULL && Thread->Stack != NULL); // // Zero the stack for emotional confort. // //memset(Thread->Stack, 0, STACK_SIZE); memset(Thread->Stack, 0, stacksize); // // Memorize Function and Argument for use in InternalStart. // Thread->Function = Function; Thread->Argument = Argument; // // Map an UTHREAD_CONTEXT instance on the thread's stack. // We'll use it to save the initial context of the thread. // // +------------+ // | 0x00000000 | <- Highest word of a thread's stack space // +============+ (needs to be set to 0 for Visual Studio to // | RetAddr | \ correctly present a thread's call stack). // +------------+ | // | EBP | | // +------------+ | // | EBX | > Thread->ThreadContext mapped on the stack. // +------------+ | // | ESI | | // +------------+ | // | EDI | / <- The stack pointer will be set to this address // +============+ at the next context switch to this thread. // | | \ // +------------+ | // | : | | // : > Remaining stack space. // | : | | // +------------+ | // | | / <- Lowest word of a thread's stack space // +------------+ (Thread->Stack always points to this location). // /*Thread->ThreadContext = (PUTHREAD_CONTEXT) (Thread->Stack + STACK_SIZE - sizeof (ULONG) - sizeof (UTHREAD_CONTEXT));*/ Thread->ThreadContext = (PUTHREAD_CONTEXT)(Thread->Stack + stacksize - sizeof(ULONG) - sizeof(UTHREAD_CONTEXT)); // // Set the thread's initial context by initializing the values of EDI, // EBX, ESI and EBP (must be zero for Visual Studio to correctly present // a thread's call stack) and by hooking the return address. // // Upon the first context switch to this thread, after popping the dummy // values of the "saved" registers, a ret instruction will place the // address of InternalStart on EIP. // Thread->ThreadContext->EDI = 0x33333333; Thread->ThreadContext->EBX = 0x11111111; Thread->ThreadContext->ESI = 0x22222222; Thread->ThreadContext->EBP = 0x00000000; Thread->ThreadContext->RetAddr = InternalStart; //initialize joiners InitializeListHead(&Thread->Joiners); InsertTailList(&AliveThreads, &Thread->alive); // // Ready the thread. // NumberOfThreads += 1; Thread->State = READY; UtActivate((HANDLE)Thread); return (HANDLE)Thread; }