Directory restructuring to make it easier to version projects that don't build zdoom.exe.
SVN r4 (trunk)
This commit is contained in:
commit
cf11cbdb30
821 changed files with 361202 additions and 0 deletions
295
src/win32/helperthread.cpp
Normal file
295
src/win32/helperthread.cpp
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
** helperthread.cpp
|
||||
**
|
||||
** Implements FHelperThread, the base class for helper threads. Includes
|
||||
** a message queue for passing messages from the main thread to the
|
||||
** helper thread.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2005 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include "helperthread.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ---Constructor---
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FHelperThread::FHelperThread ()
|
||||
{
|
||||
ThreadHandle = NULL;
|
||||
ThreadID = 0;
|
||||
Thread_Events[0] = Thread_Events[1] = 0;
|
||||
memset (Messages, 0, sizeof(Messages));
|
||||
MessageHead = 0;
|
||||
MessageTail = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ---Destructor---
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FHelperThread::~FHelperThread ()
|
||||
{
|
||||
DestroyThread ();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// LaunchThread
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FHelperThread::LaunchThread ()
|
||||
{
|
||||
int i;
|
||||
|
||||
MessageHead = MessageTail = 0;
|
||||
for (i = 0; i < MSG_QUEUE_SIZE; i++)
|
||||
{
|
||||
if ((Messages[i].CompletionEvent = CreateEvent (NULL, FALSE, i > 0, NULL)) == NULL)
|
||||
break;
|
||||
}
|
||||
if (i < MSG_QUEUE_SIZE)
|
||||
{
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
CloseHandle (Messages[i].CompletionEvent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
InitializeCriticalSection (&Thread_Critical);
|
||||
if ((Thread_Events[0] = CreateEvent (NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
if ((Thread_Events[1] = CreateEvent (NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
if ((ThreadHandle = CreateThread (NULL, 0, ThreadLaunch, (LPVOID)this, 0, &ThreadID)))
|
||||
{
|
||||
HANDLE waiters[2] = { Messages[0].CompletionEvent, ThreadHandle };
|
||||
|
||||
if (WaitForMultipleObjects (2, waiters, FALSE, INFINITE) == WAIT_OBJECT_0+1)
|
||||
{ // Init failed, and the thread exited
|
||||
DestroyThread ();
|
||||
return false;
|
||||
}
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Give the thread a name in the debugger
|
||||
struct
|
||||
{
|
||||
DWORD type;
|
||||
LPCSTR name;
|
||||
DWORD threadID;
|
||||
DWORD flags;
|
||||
} info =
|
||||
{
|
||||
0x1000, ThreadName(), ThreadID, 0
|
||||
};
|
||||
__try
|
||||
{
|
||||
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
CloseHandle (Thread_Events[1]);
|
||||
}
|
||||
CloseHandle (Thread_Events[0]);
|
||||
}
|
||||
DeleteCriticalSection (&Thread_Critical);
|
||||
for (i = 0; i < MSG_QUEUE_SIZE; i++)
|
||||
{
|
||||
CloseHandle (Messages[i].CompletionEvent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DestroyThread
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FHelperThread::DestroyThread ()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ThreadHandle == NULL)
|
||||
return;
|
||||
|
||||
SetEvent (Thread_Events[THREAD_KillSelf]);
|
||||
// 5 seconds should be sufficient. If not, then we'll crash, but at
|
||||
// least that's better than hanging indefinitely.
|
||||
WaitForSingleObject (ThreadHandle, 5000);
|
||||
CloseHandle (ThreadHandle);
|
||||
|
||||
EnterCriticalSection (&Thread_Critical);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
CloseHandle (Messages[i].CompletionEvent);
|
||||
}
|
||||
CloseHandle (Thread_Events[0]);
|
||||
CloseHandle (Thread_Events[1]);
|
||||
|
||||
LeaveCriticalSection (&Thread_Critical);
|
||||
DeleteCriticalSection (&Thread_Critical);
|
||||
|
||||
ThreadHandle = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// HaveThread
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FHelperThread::HaveThread () const
|
||||
{
|
||||
return ThreadHandle != NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SendMessage
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DWORD FHelperThread::SendMessage (DWORD method,
|
||||
DWORD parm1, DWORD parm2, DWORD parm3, bool wait)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
EnterCriticalSection (&Thread_Critical);
|
||||
if (MessageHead - MessageTail == MSG_QUEUE_SIZE)
|
||||
{ // No room, so wait for oldest message to complete
|
||||
HANDLE waitEvent = Messages[MessageTail].CompletionEvent;
|
||||
LeaveCriticalSection (&Thread_Critical);
|
||||
WaitForSingleObject (waitEvent, 1000);
|
||||
}
|
||||
|
||||
int head = MessageHead++ % MSG_QUEUE_SIZE;
|
||||
Messages[head].Method = method;
|
||||
Messages[head].Parm1 = parm1;
|
||||
Messages[head].Parm2 = parm2;
|
||||
Messages[head].Parm3 = parm3;
|
||||
ResetEvent (Messages[head].CompletionEvent);
|
||||
LeaveCriticalSection (&Thread_Critical);
|
||||
|
||||
SetEvent (Thread_Events[THREAD_NewMessage]);
|
||||
|
||||
if (wait)
|
||||
{
|
||||
WaitForSingleObject (Messages[head].CompletionEvent, INFINITE);
|
||||
return Messages[head].Return;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ThreadLaunch (static)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DWORD WINAPI FHelperThread::ThreadLaunch (LPVOID me)
|
||||
{
|
||||
return ((FHelperThread *)me)->ThreadLoop ();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ThreadLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DWORD FHelperThread::ThreadLoop ()
|
||||
{
|
||||
if (!Init ())
|
||||
{
|
||||
ExitThread (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEvent (Messages[0].CompletionEvent);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch (MsgWaitForMultipleObjects (2, Thread_Events,
|
||||
FALSE, INFINITE, QS_ALLEVENTS))
|
||||
{
|
||||
case WAIT_OBJECT_0+1:
|
||||
// We should quit now.
|
||||
Deinit ();
|
||||
ExitThread (0);
|
||||
break;
|
||||
|
||||
case WAIT_OBJECT_0:
|
||||
// Process any new messages. MessageTail is not updated until *after*
|
||||
// the message is finished processing.
|
||||
for (;;)
|
||||
{
|
||||
EnterCriticalSection (&Thread_Critical);
|
||||
if (MessageHead == MessageTail)
|
||||
{
|
||||
ResetEvent (Thread_Events[0]);
|
||||
LeaveCriticalSection (&Thread_Critical);
|
||||
break; // Resume outer for (Wait for more messages)
|
||||
}
|
||||
int spot = MessageTail % MSG_QUEUE_SIZE;
|
||||
LeaveCriticalSection (&Thread_Critical);
|
||||
|
||||
Messages[spot].Return = Dispatch (Messages[spot].Method,
|
||||
Messages[spot].Parm1, Messages[spot].Parm2,
|
||||
Messages[spot].Parm3);
|
||||
|
||||
// No need to enter critical section, because only the CD thread
|
||||
// is allowed to touch MessageTail or signal the CompletionEvent
|
||||
SetEvent (Messages[spot].CompletionEvent);
|
||||
MessageTail++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DefaultDispatch ();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue