Example #1
0
/*++
Function:
  ResetEvent

See MSDN doc.
--*/
BOOL
PALAPI
ResetEvent(
    IN HANDLE hEvent)
{
    BOOL bRet = TRUE;
    Event *pEvent;
    GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo;

    PERF_ENTRY(ResetEvent);
    ENTRY("ResetEvent(hEvent=%p)\n", hEvent);

    pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT);

    SHMLock();

    if ( pEvent == NULL )
    {
        ERROR("Invalid handle\n");
        SetLastError(ERROR_INVALID_HANDLE);
        bRet = FALSE;
    }
    else
    {
        pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info);

        if (pEventInfo == NULL)
        {
            ASSERT("Invalid shared memory pointer\n");
            SetLastError(ERROR_INTERNAL_ERROR);
            SHMRelease();
            HMGRUnlockHandle(hEvent, &pEvent->objHeader);
            LOGEXIT("ResetEvent returns BOOL FALSE\n");
            PERF_EXIT(ResetEvent);
            return FALSE;
        }

        pEventInfo->state = FALSE;

        TRACE("Event(%p) being reset.\n", hEvent);
    }

    SHMRelease();
    if( NULL != pEvent)
    {
        HMGRUnlockHandle(hEvent, &pEvent->objHeader);
    }

    LOGEXIT("ResetEvent returns BOOL %d\n", bRet);
    PERF_EXIT(ResetEvent);
    return bRet;
}
Example #2
0
/*++
Function:
  GetThreadContext

See MSDN doc.
--*/
BOOL
CONTEXT_GetThreadContext(
         HANDLE hThread,
         LPCONTEXT lpContext)
{    
    BOOL ret = FALSE;
    DWORD processId;

#if HAVE_GETCONTEXT
    ucontext_t registers;
#elif HAVE_BSD_REGS_T
    struct reg registers;
#endif  // HAVE_BSD_REGS_T
    
    if (lpContext == NULL)
    {
        ERROR("Invalid lpContext parameter value\n");
        SetLastError(ERROR_NOACCESS);
        goto EXIT;
    }
    
    /* How to consider the case when hThread is different from the current
       thread of its owner process. Machine registers values could be retreived
       by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content. 
       Unfortunately, these two methods only depend on process ID, not on 
       thread ID. */
    if (!(processId = THREADGetThreadProcessId(hThread)))
    {
        ERROR("Couldn't retrieve the process owner of hThread:%p\n", hThread);
        SetLastError(ERROR_INTERNAL_ERROR);
        goto EXIT;
    }

    if (processId == GetCurrentProcessId())
    {
        THREAD *thread;

        thread = (THREAD *) HMGRLockHandle2(hThread, HOBJ_THREAD);

        if ((thread == NULL) || (thread->dwThreadId != GetCurrentThreadId()))
        {
            DWORD flags;
            // There aren't any APIs for this. We can potentially get the
            // context of another thread by using per-thread signals, but
            // on FreeBSD signal handlers that are called as a result
            // of signals raised via pthread_kill don't get a valid
            // sigcontext or ucontext_t. But we need this to return TRUE
            // to avoid an assertion in the CLR in code that manages to
            // cope reasonably well without a valid thread context.
            // Given that, we'll zero out our structure and return TRUE.
            ERROR("GetThreadContext on a thread other than the current "
                  "thread is returning TRUE\n");
            flags = lpContext->ContextFlags;
            memset(lpContext, 0, sizeof(*lpContext));
            lpContext->ContextFlags = flags;
            HMGRUnlockHandle(hThread, &(thread->objHeader));
            ret = TRUE;
            goto EXIT;
        }

        HMGRUnlockHandle(hThread, &(thread->objHeader));
    }

    if (lpContext->ContextFlags & 
        (CONTEXT_CONTROL | CONTEXT_INTEGER))
    {        
        if (CONTEXT_GetRegisters(processId, &registers) == FALSE)
        {
            SetLastError(ERROR_INTERNAL_ERROR);
            goto EXIT;
        }

        if (lpContext->ContextFlags & CONTEXT_CONTROL)
        {
#if HAVE_GETCONTEXT
            lpContext->Ebp    = registers.uc_mcontext.gregs[REG_EBP];
            lpContext->Eip    = registers.uc_mcontext.gregs[REG_EIP];
            lpContext->SegCs  = registers.uc_mcontext.gregs[REG_CS];
            lpContext->EFlags = registers.uc_mcontext.gregs[REG_EFL];
            lpContext->Esp    = registers.uc_mcontext.gregs[REG_ESP];
            lpContext->SegSs  = registers.uc_mcontext.gregs[REG_SS];
#elif HAVE_BSD_REGS_T
            lpContext->Ebp    = registers.r_ebp;
            lpContext->Eip    = registers.r_eip;
            lpContext->SegCs  = registers.r_cs;
            lpContext->EFlags = registers.r_eflags;
            lpContext->Esp    = registers.r_esp;            
            lpContext->SegSs  = registers.r_ss;
#endif  // HAVE_BSD_REGS_T
        }        
        if (lpContext->ContextFlags & CONTEXT_INTEGER)
        {
#if HAVE_GETCONTEXT
            lpContext->Edi    = registers.uc_mcontext.gregs[REG_EDI];
            lpContext->Esi    = registers.uc_mcontext.gregs[REG_ESI];
            lpContext->Ebx    = registers.uc_mcontext.gregs[REG_EBX];
            lpContext->Edx    = registers.uc_mcontext.gregs[REG_EDX];
            lpContext->Ecx    = registers.uc_mcontext.gregs[REG_ECX];
            lpContext->Eax    = registers.uc_mcontext.gregs[REG_EAX];
#elif HAVE_BSD_REGS_T
            lpContext->Edi = registers.r_edi;
            lpContext->Esi = registers.r_esi;
            lpContext->Ebx = registers.r_ebx;
            lpContext->Edx = registers.r_edx;
            lpContext->Ecx = registers.r_ecx;
            lpContext->Eax = registers.r_eax;
#endif  // HAVE_BSD_REGS_T
        }
    }    

    ret = TRUE;

EXIT:
    return ret;
}
Example #3
0
/*++
Function:
  EventRemoveWaitingThread

  Remove the CurrentThreadId from the list of waiting thread. This
  function is called when the current thread stops waiting on an Event
  for a different reason than the Event was signaled. (e.g. a timeout,
  or the thread was waiting on multiple objects and another object was
  signaled)

Parameters:
    IN hEvent:   event handle of the modify thread waiting list.

returns
    -1: an error occurred
    0: if the thread wasn't found in the list.
    1: if the thread was removed from the waiting list.
--*/
int
EventRemoveWaitingThread(
    IN HANDLE hEvent)
{
    Event *pEvent;
    GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo;
    int ret = 0;
    ThreadWaitingList *pWaitingThread;
    ThreadWaitingList *pNextWaitingThread;
    SHMPTR shmpWaitingThread;
    DWORD CurrentThreadId;
    DWORD currentPID;

    pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT);

    SHMLock();

    if ( (pEvent == NULL) || (!IsValidEventObject(pEvent)) )
    {
        ASSERT("Invalid event handle %p\n", hEvent);
        SHMRelease();
        return -1;
    }

    pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info);

    if (pEventInfo == NULL)
    {
        ASSERT("Invalid shared memory pointer\n");
        SHMRelease();
        HMGRUnlockHandle(hEvent,&pEvent->objHeader);
        return -1;
    }

    CurrentThreadId = GetCurrentThreadId();
    currentPID = GetCurrentProcessId();
    shmpWaitingThread = pEventInfo->waitingThreads;

    if (shmpWaitingThread == (SHMPTR) NULL)
    {
        ret = 0;  /* list is empty */
        goto RemoveThreadExit;
    }

    pWaitingThread = (ThreadWaitingList *) SHMPTR_TO_PTR(shmpWaitingThread);

    if (pWaitingThread == NULL)
    {
        ERROR("Invalid shared memory pointer\n");
        ret = 0;  /* list is empty */
        goto RemoveThreadExit;
    }

    /* check if it is the first element in the list */
    if (pWaitingThread->threadId == CurrentThreadId &&
            pWaitingThread->processId == currentPID)
    {
        pEventInfo->waitingThreads = pWaitingThread->ptr.shmNext;
        SHMfree(shmpWaitingThread);
        ret = 1;
        goto RemoveThreadExit;
    }
    else
    {
        while (pWaitingThread->ptr.shmNext)
        {
            pNextWaitingThread = (ThreadWaitingList *)
                                 SHMPTR_TO_PTR(pWaitingThread->ptr.shmNext);

            if (pNextWaitingThread == NULL)
            {
                ERROR("Invalid shared memory pointer\n");
                ret = 0;
                break;
            }

            if (pNextWaitingThread->threadId == CurrentThreadId &&
                    pNextWaitingThread->processId == currentPID)
            {
                /* found, so remove it */
                SHMPTR pTemp;
                pTemp = pWaitingThread->ptr.shmNext;
                pWaitingThread->ptr.shmNext = pNextWaitingThread->ptr.shmNext;
                SHMfree (pTemp);
                ret = 1;
                break;
            }

            pWaitingThread = pNextWaitingThread;
        }
    }

RemoveThreadExit:
    SHMRelease();
    HMGRUnlockHandle(hEvent,&pEvent->objHeader);

    if (ret == 0)
    {
        TRACE("ThreadId=%#x was not waiting on hEvent=%p\n",
              CurrentThreadId, hEvent);
    }
    else if (ret == 1)
    {
        TRACE("ThreadId=%#x is no longer waiting on hEvent=%p\n",
              CurrentThreadId, hEvent);
    }

    return ret;
}
Example #4
0
/*++
Function:
  EventWaitOn

  Check if the event is signaled. If not signaled place
  the current thread to the list of waiting thread. This function is
  called by WaitXXXX functions when it's time to wait on a Event.
  The caller is responsible for blocking the thread, this function does
  not wait on the event.

  This function set the last error, if an error occured.

Parameters:
    IN hEvent: handle of the event checked for the signaled state.
    SHMPTR wait_state : shared memory pointer to waiting thread's wait state

returns
    WAITON_CODE value (see thread.h)
--*/
int
EventWaitOn(
    IN HANDLE hEvent, SHMPTR wait_state)
{
    Event *pEvent;
    GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo;
    int ret;
    ThreadWaitingList *pWaitingThread;
    SHMPTR shmpWaitingThread;

    pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT);

    SHMLock();

    if ( pEvent == NULL )
    {
        SetLastError(ERROR_INVALID_HANDLE);
        ERROR("Invalid event handle %p\n", hEvent);
        SHMRelease();
        return WOC_ERROR;
    }

    pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info);

    if (pEventInfo == NULL)
    {
        SetLastError(ERROR_INTERNAL_ERROR);
        ASSERT("Invalid shared memory pointer\n");
        SHMRelease();
        HMGRUnlockHandle(hEvent,&pEvent->objHeader);
        return WOC_ERROR;
    }

    if (pEventInfo->state)
    {
        DWORD *pAwakenState;

        /* try to flag the thread as awakened, don't add it to the list if it
           already was. (this happens if an object is signaled while WFMO is
           still calling WaitOn()) */
        pAwakenState = SHMPTR_TO_PTR(wait_state);

        if(!THREADInterlockedAwaken(pAwakenState,FALSE))
        {
            TRACE("thread is already awake; not waiting on it\n");
            ret = WOC_INTERUPTED;
        }
        else
        {
            TRACE("Event(%p) is signaled, not waiting\n", hEvent);
            ret = WOC_SIGNALED;

            /* reset the event, if it's not a manual reset event */
            if (pEventInfo->manualReset == FALSE)
            {
                pEventInfo->state = FALSE;
            }
        }
    }
    else
    {
        /* this structure needs to be allocated in the shared memory in
           term of supporting event for inter-process synchronization */
        /* add the current thread to the list of waiting threads */
        shmpWaitingThread = SHMalloc(sizeof(ThreadWaitingList));

        if (shmpWaitingThread == (SHMPTR) NULL)
        {
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
            ERROR("Not enough memory to allocate a ThreadWaitingList\n");
            ret = WOC_ERROR;
        }
        else
        {
            pWaitingThread = (ThreadWaitingList *)
                             SHMPTR_TO_PTR(shmpWaitingThread);

            pWaitingThread->threadId = GetCurrentThreadId();
            pWaitingThread->processId = GetCurrentProcessId();
            pWaitingThread->blockingPipe = THREADGetPipe();
            pWaitingThread->ptr.shmNext = (SHMPTR) NULL;
            pWaitingThread->state.shmAwakened = wait_state;

            TRACE("ThreadId=%#x will wait on hEvent=%p\n",
                  pWaitingThread->threadId, hEvent);

            /* place the thread at the end of the list */
            if (pEventInfo->waitingThreads == (SHMPTR) NULL)
            {
                pEventInfo->waitingThreads = shmpWaitingThread;
            }
            else
            {
                ThreadWaitingList *pIter;
                ThreadWaitingList *pNext;

                pIter = (ThreadWaitingList *)
                        SHMPTR_TO_PTR(pEventInfo->waitingThreads);

                while (pIter && pIter->ptr.shmNext)
                {
                    pNext = (ThreadWaitingList *)
                            SHMPTR_TO_PTR(pIter->ptr.shmNext);
                    if (NULL == pNext)
                    {
                        ERROR("Invalid shared memory pointer\n");

                        /* the list is corrupted, but let's try to keep going
                           anyway with the part that's still good */
                        pIter->ptr.shmNext = 0;
                    }
                    else
                    {
                        pIter = pNext;
                    }
                }

                if(NULL == pIter)
                {
                    ERROR("Invalid shared memory pointer\n");

                    /* the list is completely corrupted... start a new one */
                    pEventInfo->waitingThreads = shmpWaitingThread;
                }
                else
                {
                    pIter->ptr.shmNext = shmpWaitingThread;
                }
            }

            TRACE("Event(%p) is not signaled,"
                  " current thread added to the waiting list\n",
                  hEvent);

            ret = WOC_WAITING;
        }
    }
    SHMRelease();
    HMGRUnlockHandle(hEvent,&pEvent->objHeader);

    return ret;
}
Example #5
0
/*++
Function:
  SetEvent

See MSDN doc.
--*/
BOOL
PALAPI
SetEvent(
    IN HANDLE hEvent)
{
    BOOL bRet = TRUE;
    Event *pEvent;
    GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo;
    SHMPTR pTemp;
    ThreadWaitingList *pWaitingThread;

    PERF_ENTRY(SetEvent);
    ENTRY("SetEvent(hEvent=%p)\n", hEvent);

    pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT);
    if(NULL == pEvent)
    {
        ERROR("Unable to lock handle %p!\n", hEvent);
        SetLastError(ERROR_INVALID_HANDLE);
        LOGEXIT("SetEvent returns BOOL %d\n",FALSE);
        PERF_EXIT(SetEvent);
        return FALSE;
    }

    SHMLock();

    pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info);

    if (pEventInfo == NULL)
    {
        ASSERT("Invalid shared memory pointer\n");
        SetLastError(ERROR_INTERNAL_ERROR);
        bRet = FALSE;
        goto SetEventExit;
    }

    if (!pEventInfo->state)
    {
        DWORD *pAwakenState;
        SHMPTR shmWaitingThread;
        ThreadWaitingList *prevThread = NULL;

        pEventInfo->state = TRUE;

        shmWaitingThread = pEventInfo->waitingThreads;

        /* wake up waiting threads */
        while (shmWaitingThread)
        {
            pWaitingThread = SHMPTR_TO_PTR(shmWaitingThread);

            if (pWaitingThread == NULL)
            {
                ASSERT("Invalid shared memory pointer\n");
                SetLastError(ERROR_INTERNAL_ERROR);
                bRet = FALSE;
                goto SetEventExit;
            }

            /* check whether thread is already awake. this can happen if
               another object already woke up the thread, but the thread hasn't
               yet had time to remove itself from all waiting lists. */
            pAwakenState = SHMPTR_TO_PTR(pWaitingThread->state.shmAwakened);

            if(!THREADInterlockedAwaken(pAwakenState, FALSE))
            {
                TRACE("thread is already awake, skipping it\n");
                prevThread = pWaitingThread;
                shmWaitingThread = pWaitingThread->ptr.shmNext;
                continue;
            }

            /* remove thread from waiting list */
            pTemp = shmWaitingThread;
            shmWaitingThread = pWaitingThread->ptr.shmNext;
            if(NULL == prevThread)
            {
                pEventInfo->waitingThreads = shmWaitingThread;
            }
            else
            {
                prevThread->ptr.shmNext = shmWaitingThread;
            }

            TRACE("Waking up thread(%#x) Event has been set (%p)\n",
                  pWaitingThread->threadId, hEvent);

            WakeUpThread(pWaitingThread->threadId,
                         pWaitingThread->processId,
                         pWaitingThread->blockingPipe,
                         WUTC_SIGNALED );

            SHMfree(pTemp);

            /* if the event is auto-reset, we only want to wake up one thread,
               so break out.*/
            if (pEventInfo->manualReset == FALSE)
            {
                pEventInfo->state = FALSE;
                break;
            }
        }
    }

SetEventExit:
    SHMRelease();
    HMGRUnlockHandle(hEvent, &pEvent->objHeader);

    LOGEXIT("SetEvent returns BOOL %d\n", bRet);
    PERF_EXIT(SetEvent);
    return bRet;
}