📄 win32.cxx
字号:
{ WSAENOTCONN, "Socket not connected" },
{ WSAECONNABORTED, "Connection aborted" },
{ WSAECONNRESET, "Connection reset" },
{ WSAESHUTDOWN, "Connection shutdown" },
{ WSAENOTSOCK, "Socket closed or invalid" },
{ WSAETIMEDOUT, "Timed out" },
{ WSAEMSGSIZE, "Message larger than buffer" },
{ WSAEWOULDBLOCK, "Would block" },
{ 0x1000000, "High level protocol failure" }
};
for (PINDEX i = 0; i < PARRAYSIZE(win32_errlist); i++)
if (win32_errlist[i].id == err)
return win32_errlist[i].msg;
return psprintf("WIN32 error %u", err);
}
BOOL PChannel::ConvertOSError(int status, Errors & lastError, int & osError)
{
if (status >= 0) {
lastError = NoError;
osError = 0;
return TRUE;
}
if (status != -2)
osError = errno;
else {
osError = GetLastError();
switch (osError) {
case ERROR_INVALID_HANDLE :
case WSAEBADF :
osError = EBADF;
break;
case ERROR_INVALID_PARAMETER :
case WSAEINVAL :
osError = EINVAL;
break;
case ERROR_ACCESS_DENIED :
case WSAEACCES :
osError = EACCES;
break;
case ERROR_NOT_ENOUGH_MEMORY :
osError = ENOMEM;
break;
case WSAEINTR :
osError = EINTR;
break;
case WSAEMSGSIZE :
osError |= PWIN32ErrorFlag;
lastError = BufferTooSmall;
return FALSE;
case WSAEWOULDBLOCK :
case WSAETIMEDOUT :
osError |= PWIN32ErrorFlag;
lastError = Timeout;
return FALSE;
default :
osError |= PWIN32ErrorFlag;
}
}
switch (osError) {
case 0 :
lastError = NoError;
return TRUE;
case ENOENT :
lastError = NotFound;
break;
case EEXIST :
lastError = FileExists;
break;
case EACCES :
lastError = AccessDenied;
break;
case ENOMEM :
lastError = NoMemory;
break;
case ENOSPC :
lastError = DiskFull;
break;
case EINVAL :
lastError = BadParameter;
break;
case EBADF :
lastError = NotOpen;
break;
case EAGAIN :
lastError = Timeout;
break;
case EINTR :
lastError = Interrupted;
break;
default :
lastError = Miscellaneous;
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// PWin32Overlapped
PWin32Overlapped::PWin32Overlapped()
{
memset(this, 0, sizeof(*this));
hEvent = CreateEvent(0, TRUE, 0, NULL);
}
PWin32Overlapped::~PWin32Overlapped()
{
if (hEvent != NULL)
CloseHandle(hEvent);
}
void PWin32Overlapped::Reset()
{
Offset = OffsetHigh = 0;
if (hEvent != NULL)
ResetEvent(hEvent);
}
///////////////////////////////////////////////////////////////////////////////
// Threads
UINT __stdcall PThread::MainFunction(void * threadPtr)
{
PThread * thread = (PThread *)PAssertNULL(threadPtr);
thread->SetThreadName(thread->GetThreadName());
PProcess & process = PProcess::Current();
#ifndef _WIN32_WCE
AttachThreadInput(thread->threadId, ((PThread&)process).threadId, TRUE);
AttachThreadInput(((PThread&)process).threadId, thread->threadId, TRUE);
#endif
process.activeThreadMutex.Wait();
process.activeThreads.SetAt(thread->threadId, thread);
process.activeThreadMutex.Signal();
process.SignalTimerChange();
thread->Main();
#ifdef _WIN32_WCE
#endif
return 0;
}
PThread::PThread(PINDEX stackSize,
AutoDeleteFlag deletion,
Priority priorityLevel,
const PString & name)
: threadName(name)
{
PAssert(stackSize > 0, PInvalidParameter);
originalStackSize = stackSize;
autoDelete = deletion == AutoDeleteThread;
#ifndef _WIN32_WCE
threadHandle = (HANDLE)_beginthreadex(NULL, stackSize, MainFunction,
this, CREATE_SUSPENDED, &threadId);
#else
threadHandle = CreateThread(NULL, stackSize,
(LPTHREAD_START_ROUTINE)MainFunction,
this, CREATE_SUSPENDED, (LPDWORD) &threadId);
#endif
PAssertOS(threadHandle != NULL);
SetPriority(priorityLevel);
if (autoDelete) {
PProcess & process = PProcess::Current();
process.deleteThreadMutex.Wait();
process.autoDeleteThreads.Append(this);
process.deleteThreadMutex.Signal();
}
}
PThread::~PThread()
{
if (originalStackSize <= 0)
return;
PProcess & process = PProcess::Current();
process.activeThreadMutex.Wait();
process.activeThreads.SetAt(threadId, NULL);
process.activeThreadMutex.Signal();
if (!IsTerminated())
Terminate();
if (threadHandle != NULL)
CloseHandle(threadHandle);
}
void PThread::Restart()
{
PAssert(IsTerminated(), "Cannot restart running thread");
#ifndef _WIN32_WCE
threadHandle = (HANDLE)_beginthreadex(NULL,
originalStackSize, MainFunction, this, 0, &threadId);
#else
threadHandle = CreateThread(NULL, originalStackSize,
(LPTHREAD_START_ROUTINE) MainFunction,
this, 0, (LPDWORD) &threadId);
#endif
PAssertOS(threadHandle != NULL);
}
void PThread::Terminate()
{
PAssert(originalStackSize > 0, PLogicError);
if (Current() == this)
ExitThread(0);
else
TerminateThread(threadHandle, 1);
}
BOOL PThread::IsTerminated() const
{
return WaitForTermination(0);
}
void PThread::WaitForTermination() const
{
WaitForTermination(PMaxTimeInterval);
}
BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
{
if (threadHandle == NULL)
return TRUE;
DWORD result;
PINDEX retries = 10;
while ((result = WaitForSingleObject(threadHandle, maxWait.GetInterval())) != WAIT_TIMEOUT) {
if (result == WAIT_OBJECT_0)
return TRUE;
if (::GetLastError() != ERROR_INVALID_HANDLE) {
PAssertAlways(POperatingSystemError);
return TRUE;
}
if (retries == 0)
return TRUE;
retries--;
}
return FALSE;
}
void PThread::Suspend(BOOL susp)
{
PAssert(!IsTerminated(), "Operation on terminated thread");
if (susp)
SuspendThread(threadHandle);
else
Resume();
}
void PThread::Resume()
{
PAssert(!IsTerminated(), "Operation on terminated thread");
ResumeThread(threadHandle);
}
BOOL PThread::IsSuspended() const
{
PAssert(!IsTerminated(), "Operation on terminated thread");
SuspendThread(threadHandle);
return ResumeThread(threadHandle) > 1;
}
void PThread::SetAutoDelete(AutoDeleteFlag deletion)
{
PAssert(deletion != AutoDeleteThread || this != &PProcess::Current(), PLogicError);
PProcess & process = PProcess::Current();
if (autoDelete && deletion != AutoDeleteThread) {
process.deleteThreadMutex.Wait();
process.autoDeleteThreads.DisallowDeleteObjects();
process.autoDeleteThreads.Remove(this);
process.autoDeleteThreads.AllowDeleteObjects();
process.deleteThreadMutex.Signal();
}
else if (!autoDelete && deletion == AutoDeleteThread) {
process.deleteThreadMutex.Wait();
process.autoDeleteThreads.Append(this);
process.deleteThreadMutex.Signal();
}
autoDelete = deletion == AutoDeleteThread;
}
#if !defined(_WIN32_WCE) || (_WIN32_WCE < 300)
#define PTHREAD_PRIORITY_LOWEST THREAD_PRIORITY_LOWEST
#define PTHREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_BELOW_NORMAL
#define PTHREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
#define PTHREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_ABOVE_NORMAL
#define PTHREAD_PRIORITY_HIGHEST THREAD_PRIORITY_HIGHEST
#else
#define PTHREAD_PRIORITY_LOWEST 243
#define PTHREAD_PRIORITY_BELOW_NORMAL 245
#define PTHREAD_PRIORITY_NORMAL 247
#define PTHREAD_PRIORITY_ABOVE_NORMAL 249
#define PTHREAD_PRIORITY_HIGHEST 251
#endif
void PThread::SetPriority(Priority priorityLevel)
{
PAssert(!IsTerminated(), "Operation on terminated thread");
static int const priorities[NumPriorities] = {
PTHREAD_PRIORITY_LOWEST,
PTHREAD_PRIORITY_BELOW_NORMAL,
PTHREAD_PRIORITY_NORMAL,
PTHREAD_PRIORITY_ABOVE_NORMAL,
PTHREAD_PRIORITY_HIGHEST
};
SetThreadPriority(threadHandle, priorities[priorityLevel]);
}
PThread::Priority PThread::GetPriority() const
{
PAssert(!IsTerminated(), "Operation on terminated thread");
switch (GetThreadPriority(threadHandle)) {
case PTHREAD_PRIORITY_LOWEST :
return LowestPriority;
case PTHREAD_PRIORITY_BELOW_NORMAL :
return LowPriority;
case PTHREAD_PRIORITY_NORMAL :
return NormalPriority;
case PTHREAD_PRIORITY_ABOVE_NORMAL :
return HighPriority;
case PTHREAD_PRIORITY_HIGHEST :
return HighestPriority;
}
PAssertAlways(POperatingSystemError);
return LowestPriority;
}
void PThread::Yield()
{
::Sleep(0);
}
void PThread::InitialiseProcessThread()
{
originalStackSize = 0;
autoDelete = FALSE;
threadHandle = GetCurrentThread();
threadId = GetCurrentThreadId();
((PProcess *)this)->activeThreads.DisallowDeleteObjects();
((PProcess *)this)->activeThreads.SetAt(threadId, this);
}
PThread * PThread::Current()
{
PProcess & process = PProcess::Current();
process.activeThreadMutex.Wait();
PThread * thread = process.activeThreads.GetAt(GetCurrentThreadId());
process.activeThreadMutex.Signal();
return thread;
}
///////////////////////////////////////////////////////////////////////////////
// PProcess::TimerThread
PProcess::HouseKeepingThread::HouseKeepingThread()
: PThread(1000, NoAutoDeleteThread, NormalPriority, "PWLib Housekeeper")
{
Resume();
}
void PProcess::HouseKeepingThread::Main()
{
PProcess & process = PProcess::Current();
for (;;) {
process.deleteThreadMutex.Wait();
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
DWORD numHandles = 1;
handles[0] = breakBlock.GetHandle();
for (PINDEX i = 0; i < process.autoDeleteThreads.GetSize(); i++) {
PThread & thread = process.autoDeleteThreads[i];
if (thread.IsTerminated())
process.autoDeleteThreads.RemoveAt(i--);
else {
handles[numHandles] = thread.GetHandle();
if (handles[numHandles] != process.GetHandle()) {
numHandles++;
if (numHandles >= MAXIMUM_WAIT_OBJECTS)
break;
}
}
}
process.deleteThreadMutex.Signal();
PTimeInterval nextTimer = process.timers.Process();
DWORD delay;
if (nextTimer == PMaxTimeInterval)
delay = INFINITE;
else if (nextTimer > 1000)
delay = 1000;
else
delay = nextTimer.GetInterval();
DWORD result;
PINDEX retries = 100;
while ((result = WaitForMultipleObjects(numHandles, handles, FALSE, delay)) == WAIT_FAILED) {
PAssertOS(::GetLastError() == ERROR_INVALID_HANDLE || retries > 0);
retries--;
}
}
}
void PProcess::SignalTimerChange()
{
if (houseKeeper == NULL)
houseKeeper = new HouseKeepingThread;
else
houseKeeper->breakBlock.Signal();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -