forked from Mirrors/openclonk
StdScheduler: Split into StdSchedulerWin32/StdSchedulerPoll/StdSchedulerMac
parent
57463b61c4
commit
d504626a40
|
@ -977,6 +977,9 @@ add_executable(c4group
|
||||||
|
|
||||||
add_executable(netpuncher EXCLUDE_FROM_ALL
|
add_executable(netpuncher EXCLUDE_FROM_ALL
|
||||||
src/platform/StdScheduler.cpp
|
src/platform/StdScheduler.cpp
|
||||||
|
src/platform/StdSchedulerWin32.cpp
|
||||||
|
src/platform/StdSchedulerPoll.cpp
|
||||||
|
src/platform/StdSchedulerMac.mm
|
||||||
src/netpuncher/main.cpp
|
src/netpuncher/main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1006,6 +1009,9 @@ src/platform/StdFile.h
|
||||||
src/platform/StdRegistry.cpp
|
src/platform/StdRegistry.cpp
|
||||||
src/platform/StdRegistry.h
|
src/platform/StdRegistry.h
|
||||||
src/platform/StdScheduler.cpp
|
src/platform/StdScheduler.cpp
|
||||||
|
src/platform/StdSchedulerWin32.cpp
|
||||||
|
src/platform/StdSchedulerPoll.cpp
|
||||||
|
src/platform/StdSchedulerMac.mm
|
||||||
src/platform/StdScheduler.h
|
src/platform/StdScheduler.h
|
||||||
src/platform/C4TimeMilliseconds.cpp
|
src/platform/C4TimeMilliseconds.cpp
|
||||||
src/platform/C4TimeMilliseconds.h
|
src/platform/C4TimeMilliseconds.h
|
||||||
|
|
|
@ -927,6 +927,8 @@ C4NetIOTCP::Peer *C4NetIOTCP::Accept(SOCKET nsock, const addr_t &ConnectAddr) //
|
||||||
|
|
||||||
// clear add-lock
|
// clear add-lock
|
||||||
PeerListAddLock.Clear();
|
PeerListAddLock.Clear();
|
||||||
|
|
||||||
|
Changed();
|
||||||
|
|
||||||
// ask callback if connection should be permitted
|
// ask callback if connection should be permitted
|
||||||
if (pCB && !pCB->OnConn(addr, caddr, NULL, this))
|
if (pCB && !pCB->OnConn(addr, caddr, NULL, this))
|
||||||
|
@ -989,6 +991,7 @@ bool C4NetIOTCP::Listen(uint16_t inListenPort)
|
||||||
|
|
||||||
// ok
|
// ok
|
||||||
iListenPort = inListenPort;
|
iListenPort = inListenPort;
|
||||||
|
Changed();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,6 +1066,7 @@ void C4NetIOTCP::AddConnectWait(SOCKET sock, const addr_t &addr) // (mt-safe)
|
||||||
// unblock, so new FD can be realized
|
// unblock, so new FD can be realized
|
||||||
UnBlock();
|
UnBlock();
|
||||||
#endif
|
#endif
|
||||||
|
Changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
C4NetIOTCP::ConnectWait *C4NetIOTCP::GetConnectWait(const addr_t &addr) // (mt-safe)
|
C4NetIOTCP::ConnectWait *C4NetIOTCP::GetConnectWait(const addr_t &addr) // (mt-safe)
|
||||||
|
@ -3067,6 +3071,7 @@ void C4NetIOUDP::AddPeer(Peer *pPeer)
|
||||||
// add
|
// add
|
||||||
pPeer->Next = pPeerList;
|
pPeer->Next = pPeerList;
|
||||||
pPeerList = pPeer;
|
pPeerList = pPeer;
|
||||||
|
Changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void C4NetIOUDP::OnShareFree(CStdCSecEx *pCSec)
|
void C4NetIOUDP::OnShareFree(CStdCSecEx *pCSec)
|
||||||
|
|
|
@ -114,6 +114,7 @@ public:
|
||||||
virtual bool CloseBroadcast() = 0;
|
virtual bool CloseBroadcast() = 0;
|
||||||
|
|
||||||
virtual bool Execute(int iTimeout = -1, pollfd * = 0) = 0; // (for StdSchedulerProc)
|
virtual bool Execute(int iTimeout = -1, pollfd * = 0) = 0; // (for StdSchedulerProc)
|
||||||
|
virtual bool IsNotify() { return true; }
|
||||||
|
|
||||||
// * multithreading safe
|
// * multithreading safe
|
||||||
virtual bool Connect(const addr_t &addr) = 0; // async!
|
virtual bool Connect(const addr_t &addr) = 0; // async!
|
||||||
|
|
|
@ -97,7 +97,7 @@ public:
|
||||||
// Gamma
|
// Gamma
|
||||||
virtual bool ApplyGammaRamp(struct _GAMMARAMP &ramp, bool fForce);
|
virtual bool ApplyGammaRamp(struct _GAMMARAMP &ramp, bool fForce);
|
||||||
virtual bool SaveDefaultGammaRamp(struct _GAMMARAMP &ramp);
|
virtual bool SaveDefaultGammaRamp(struct _GAMMARAMP &ramp);
|
||||||
bool ScheduleProcs(int iTimeout = -1);
|
virtual bool ScheduleProcs(int iTimeout = -1);
|
||||||
bool FlushMessages();
|
bool FlushMessages();
|
||||||
C4Window * pWindow;
|
C4Window * pWindow;
|
||||||
bool fQuitMsgReceived; // if true, a quit message has been received and the application should terminate
|
bool fQuitMsgReceived; // if true, a quit message has been received and the application should terminate
|
||||||
|
|
|
@ -125,14 +125,14 @@
|
||||||
{
|
{
|
||||||
NSLog(@"Game running, only simulating Esc key");
|
NSLog(@"Game running, only simulating Esc key");
|
||||||
[self simulateKeyPressed:K_ESCAPE];
|
[self simulateKeyPressed:K_ESCAPE];
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Application.isEditor)
|
if (Application.isEditor)
|
||||||
Console.FileClose();
|
Console.FileClose();
|
||||||
Application.fQuitMsgReceived = true;
|
Application.fQuitMsgReceived = true;
|
||||||
return;
|
Application.ScheduleProcs();
|
||||||
|
Application.Quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
{
|
{
|
||||||
NSString* pathExtension = [[filename pathExtension] lowercaseString];
|
NSString* pathExtension = [[filename pathExtension] lowercaseString];
|
||||||
|
|
||||||
NSArray* clonkFileNameExtensions = [NSArray arrayWithObjects:@"ocd", @"ocs", @"ocf", @"ocg", nil];
|
NSArray* clonkFileNameExtensions = @[@"ocd", @"ocs", @"ocf", @"ocg"];
|
||||||
if ([clonkFileNameExtensions containsObject:pathExtension])
|
if ([clonkFileNameExtensions containsObject:pathExtension])
|
||||||
{
|
{
|
||||||
// later decide whether to install or run
|
// later decide whether to install or run
|
||||||
|
@ -150,19 +150,20 @@
|
||||||
- (void) delayedRun:(id)sender
|
- (void) delayedRun:(id)sender
|
||||||
{
|
{
|
||||||
running = YES;
|
running = YES;
|
||||||
while (!Application.fQuitMsgReceived)
|
//while (!Application.fQuitMsgReceived)
|
||||||
Application.ScheduleProcs();
|
// Application.ScheduleProcs();
|
||||||
[NSApp replyToApplicationShouldTerminate:YES];
|
//[NSApp replyToApplicationShouldTerminate:YES];
|
||||||
running = NO;
|
//running = NO;
|
||||||
[self quitAndMaybeRestart];
|
//[self quitAndMaybeRestart];
|
||||||
[NSApp terminate:self];
|
//[NSApp terminate:self];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)application
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)application
|
||||||
{
|
{
|
||||||
[self suggestQuitting:self];
|
if (!Application.fQuitMsgReceived)
|
||||||
return running ? NSTerminateCancel : NSTerminateNow;
|
[self suggestQuitting:self];
|
||||||
|
return NSTerminateNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)terminate:(NSApplication*)sender
|
- (void)terminate:(NSApplication*)sender
|
||||||
|
|
|
@ -94,7 +94,7 @@ void C4AbstractApp::Clear() {}
|
||||||
|
|
||||||
void C4AbstractApp::Quit()
|
void C4AbstractApp::Quit()
|
||||||
{
|
{
|
||||||
fQuitMsgReceived = true;
|
[NSApp terminate:[NSApp delegate]];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool C4AbstractApp::FlushMessages()
|
bool C4AbstractApp::FlushMessages()
|
||||||
|
|
|
@ -30,23 +30,16 @@
|
||||||
#ifdef HAVE_SHARE_H
|
#ifdef HAVE_SHARE_H
|
||||||
#include <share.h>
|
#include <share.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
|
||||||
#include <process.h>
|
|
||||||
#include <mmsystem.h>
|
|
||||||
|
|
||||||
static int pipe(int *phandles)
|
|
||||||
{
|
|
||||||
// This doesn't work with select(), rendering the non-event-solution
|
|
||||||
// unusable for Win32. Oh well, it isn't desirable performance-wise, anyway.
|
|
||||||
return _pipe(phandles, 10, O_BINARY);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
// For pipe()
|
// For pipe()
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// *** StdSchedulerProc
|
// *** StdSchedulerProc
|
||||||
|
|
||||||
// Keep calling Execute until timeout has elapsed
|
// Keep calling Execute until timeout has elapsed
|
||||||
|
@ -74,32 +67,10 @@ bool StdSchedulerProc::ExecuteUntil(int iTimeout)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this process currently signaled?
|
|
||||||
bool StdSchedulerProc::IsSignaled()
|
|
||||||
{
|
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
|
||||||
return GetEvent() && WaitForSingleObject(GetEvent(), 0) == WAIT_OBJECT_0;
|
|
||||||
#else
|
|
||||||
// Initialize file descriptor sets
|
|
||||||
std::vector<struct pollfd> fds;
|
|
||||||
|
|
||||||
// Get file descriptors
|
|
||||||
GetFDs(fds);
|
|
||||||
|
|
||||||
// Test
|
|
||||||
return poll(&fds[0], fds.size(), 0) > 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// *** StdScheduler
|
// *** StdScheduler
|
||||||
|
|
||||||
StdScheduler::StdScheduler()
|
StdScheduler::StdScheduler() : isInManualLoop(false)
|
||||||
: ppProcs(NULL), iProcCnt(0), iProcCapacity(0)
|
|
||||||
{
|
{
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
|
||||||
pEventHandles = NULL;
|
|
||||||
ppEventProcs = NULL;
|
|
||||||
#endif
|
|
||||||
Add(&Unblocker);
|
Add(&Unblocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,208 +79,79 @@ StdScheduler::~StdScheduler()
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int StdScheduler::getProc(StdSchedulerProc *pProc)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < iProcCnt; i++)
|
|
||||||
if (ppProcs[i] == pProc)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StdScheduler::Clear()
|
void StdScheduler::Clear()
|
||||||
{
|
{
|
||||||
delete[] ppProcs; ppProcs = NULL;
|
while (procs.size() > 0)
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
Remove(procs[procs.size()-1]);
|
||||||
delete[] pEventHandles; pEventHandles = NULL;
|
|
||||||
delete[] ppEventProcs; ppEventProcs = NULL;
|
|
||||||
#endif
|
|
||||||
iProcCnt = iProcCapacity = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StdScheduler::Set(StdSchedulerProc **ppnProcs, int inProcCnt)
|
void StdScheduler::Set(StdSchedulerProc **ppnProcs, int inProcCnt)
|
||||||
{
|
{
|
||||||
// Remove previous data
|
// Remove previous data
|
||||||
Clear();
|
Clear();
|
||||||
// Set size
|
|
||||||
Enlarge(inProcCnt - iProcCapacity);
|
|
||||||
// Copy new
|
// Copy new
|
||||||
iProcCnt = inProcCnt;
|
for (int i = 0; i < inProcCnt; i++)
|
||||||
for (int i = 0; i < iProcCnt; i++)
|
Add(ppnProcs[i]);
|
||||||
ppProcs[i] = ppnProcs[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StdScheduler::Add(StdSchedulerProc *pProc)
|
void StdScheduler::Add(StdSchedulerProc *pProc)
|
||||||
{
|
{
|
||||||
// Alrady in list?
|
// Already added to some scheduler
|
||||||
if (hasProc(pProc)) return;
|
if (pProc->scheduler)
|
||||||
// Enlarge
|
return;
|
||||||
if (iProcCnt >= iProcCapacity) Enlarge(10);
|
|
||||||
// Add
|
// Add
|
||||||
ppProcs[iProcCnt] = pProc;
|
procs.push_back(pProc);
|
||||||
iProcCnt++;
|
pProc->scheduler = this;
|
||||||
|
|
||||||
|
Added(pProc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StdScheduler::Remove(StdSchedulerProc *pProc)
|
void StdScheduler::Remove(StdSchedulerProc *pProc)
|
||||||
{
|
{
|
||||||
// Search
|
// :o ?
|
||||||
int iPos = getProc(pProc);
|
if (pProc->scheduler != this)
|
||||||
// Not found?
|
return;
|
||||||
if (iPos < 0 || iPos >= iProcCnt) return;
|
Removing(pProc);
|
||||||
// Remove
|
pProc->scheduler = NULL;
|
||||||
for (int i = iPos + 1; i < iProcCnt; i++)
|
auto pos = std::find(procs.begin(), procs.end(), pProc);
|
||||||
ppProcs[i-1] = ppProcs[i];
|
if (pos != procs.end())
|
||||||
iProcCnt--;
|
procs.erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdSchedulerProc::Changed()
|
||||||
|
{
|
||||||
|
auto s = scheduler;
|
||||||
|
if (s)
|
||||||
|
s->Changed(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
C4TimeMilliseconds StdSchedulerProc::GetNextTick(C4TimeMilliseconds tNow)
|
||||||
|
{
|
||||||
|
return C4TimeMilliseconds::PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StdScheduler::ScheduleProcs(int iTimeout)
|
bool StdScheduler::ScheduleProcs(int iTimeout)
|
||||||
{
|
{
|
||||||
|
isInManualLoop = true;
|
||||||
// Needs at least one process to work properly
|
// Needs at least one process to work properly
|
||||||
if (!iProcCnt) return false;
|
if (!procs.size()) return false;
|
||||||
|
|
||||||
// Get timeout
|
// Get timeout
|
||||||
int i;
|
|
||||||
C4TimeMilliseconds tProcTick;
|
C4TimeMilliseconds tProcTick;
|
||||||
C4TimeMilliseconds tNow = C4TimeMilliseconds::Now();
|
C4TimeMilliseconds tNow = C4TimeMilliseconds::Now();
|
||||||
for (i = 0; i < iProcCnt; i++)
|
for (auto i = 0; i < procs.size(); i++)
|
||||||
{
|
{
|
||||||
tProcTick = ppProcs[i]->GetNextTick(tNow);
|
auto proc = procs[i];
|
||||||
|
tProcTick = proc->GetNextTick(tNow);
|
||||||
if (iTimeout == -1 || tNow + iTimeout > tProcTick)
|
if (iTimeout == -1 || tNow + iTimeout > tProcTick)
|
||||||
{
|
{
|
||||||
iTimeout = Max<uint32_t>(tProcTick - tNow, 0);
|
iTimeout = Max<decltype(iTimeout)>(tProcTick - tNow, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
bool res = DoScheduleProcs(iTimeout);
|
||||||
|
isInManualLoop = false;
|
||||||
// Collect event handles
|
return res;
|
||||||
int iEventCnt = 0; HANDLE hEvent;
|
|
||||||
StdSchedulerProc *pMessageProc = NULL;
|
|
||||||
for (i = 0; i < iProcCnt; i++)
|
|
||||||
if ( (hEvent = ppProcs[i]->GetEvent()) )
|
|
||||||
{
|
|
||||||
if (hEvent == STDSCHEDULER_EVENT_MESSAGE)
|
|
||||||
pMessageProc = ppProcs[i];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pEventHandles[iEventCnt] = hEvent;
|
|
||||||
ppEventProcs[iEventCnt] = ppProcs[i];
|
|
||||||
iEventCnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for something to happen
|
|
||||||
DWORD ret; DWORD dwMsec = iTimeout < 0 ? INFINITE : iTimeout;
|
|
||||||
if (pMessageProc)
|
|
||||||
ret = MsgWaitForMultipleObjects(iEventCnt, pEventHandles, false, dwMsec, QS_ALLINPUT);
|
|
||||||
else
|
|
||||||
ret = WaitForMultipleObjects(iEventCnt, pEventHandles, false, dwMsec);
|
|
||||||
|
|
||||||
bool fSuccess = true;
|
|
||||||
|
|
||||||
// Event?
|
|
||||||
if (ret != WAIT_TIMEOUT)
|
|
||||||
{
|
|
||||||
// Which event?
|
|
||||||
int iEventNr = ret - WAIT_OBJECT_0;
|
|
||||||
|
|
||||||
// Execute the signaled process
|
|
||||||
StdSchedulerProc *pProc = iEventNr < iEventCnt ? ppEventProcs[iEventNr] : pMessageProc;
|
|
||||||
if (!pProc->Execute(0))
|
|
||||||
{
|
|
||||||
OnError(pProc);
|
|
||||||
fSuccess = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute all processes with timeout
|
|
||||||
tNow = C4TimeMilliseconds::Now();
|
|
||||||
for (i = 0; i < iProcCnt; i++)
|
|
||||||
{
|
|
||||||
tProcTick = ppProcs[i]->GetNextTick(tNow);
|
|
||||||
if (tProcTick <= tNow)
|
|
||||||
if (!ppProcs[i]->Execute(0))
|
|
||||||
{
|
|
||||||
OnError(ppProcs[i]);
|
|
||||||
fSuccess = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// Initialize file descriptor sets
|
|
||||||
std::vector<struct pollfd> fds;
|
|
||||||
std::map<StdSchedulerProc *, std::pair<unsigned int, unsigned int> > fds_for_proc;
|
|
||||||
|
|
||||||
// Collect file descriptors
|
|
||||||
for (i = 0; i < iProcCnt; i++)
|
|
||||||
{
|
|
||||||
unsigned int os = fds.size();
|
|
||||||
ppProcs[i]->GetFDs(fds);
|
|
||||||
if (os != fds.size())
|
|
||||||
fds_for_proc[ppProcs[i]] = std::pair<unsigned int, unsigned int>(os, fds.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for something to happen
|
|
||||||
int cnt = poll(&fds[0], fds.size(), iTimeout);
|
|
||||||
|
|
||||||
bool fSuccess = true;
|
|
||||||
|
|
||||||
if (cnt >= 0)
|
|
||||||
{
|
|
||||||
bool any_executed = false;
|
|
||||||
tNow = C4TimeMilliseconds::Now();
|
|
||||||
// Which process?
|
|
||||||
for (i = 0; i < iProcCnt; i++)
|
|
||||||
{
|
|
||||||
tProcTick = ppProcs[i]->GetNextTick(tNow);
|
|
||||||
if (tProcTick <= tNow)
|
|
||||||
{
|
|
||||||
struct pollfd * pfd = 0;
|
|
||||||
if (fds_for_proc.find(ppProcs[i]) != fds_for_proc.end())
|
|
||||||
pfd = &fds[fds_for_proc[ppProcs[i]].first];
|
|
||||||
if (!ppProcs[i]->Execute(0, pfd))
|
|
||||||
{
|
|
||||||
OnError(ppProcs[i]);
|
|
||||||
fSuccess = false;
|
|
||||||
}
|
|
||||||
any_executed = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// no fds?
|
|
||||||
if (fds_for_proc.find(ppProcs[i]) == fds_for_proc.end())
|
|
||||||
continue;
|
|
||||||
// Check intersection
|
|
||||||
unsigned int begin = fds_for_proc[ppProcs[i]].first;
|
|
||||||
unsigned int end = fds_for_proc[ppProcs[i]].second;
|
|
||||||
for (unsigned int j = begin; j < end; ++j)
|
|
||||||
{
|
|
||||||
if (fds[j].events & fds[j].revents)
|
|
||||||
{
|
|
||||||
if (any_executed && ppProcs[i]->IsLowPriority())
|
|
||||||
break;
|
|
||||||
if (!ppProcs[i]->Execute(0, &fds[begin]))
|
|
||||||
{
|
|
||||||
OnError(ppProcs[i]);
|
|
||||||
fSuccess = false;
|
|
||||||
}
|
|
||||||
any_executed = true;
|
|
||||||
// the list of procs might have been changed, but procs must be in both ppProcs and
|
|
||||||
// fds_for_proc to be executed, which prevents execution of any proc not polled this round
|
|
||||||
// or deleted. Some procs might be skipped or executed twice, but that should be save.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cnt < 0)
|
|
||||||
{
|
|
||||||
printf("StdScheduler::Execute: poll failed: %s\n",strerror(errno));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return fSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StdScheduler::UnBlock()
|
void StdScheduler::UnBlock()
|
||||||
|
@ -317,23 +159,6 @@ void StdScheduler::UnBlock()
|
||||||
Unblocker.Notify();
|
Unblocker.Notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StdScheduler::Enlarge(int iBy)
|
|
||||||
{
|
|
||||||
iProcCapacity += iBy;
|
|
||||||
// Realloc
|
|
||||||
StdSchedulerProc **ppnProcs = new StdSchedulerProc *[iProcCapacity];
|
|
||||||
// Set data
|
|
||||||
for (int i = 0; i < iProcCnt; i++)
|
|
||||||
ppnProcs[i] = ppProcs[i];
|
|
||||||
delete[] ppProcs;
|
|
||||||
ppProcs = ppnProcs;
|
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
|
||||||
// Allocate dummy arrays (one handle neede for unlocker!)
|
|
||||||
delete[] pEventHandles; pEventHandles = new HANDLE[iProcCapacity + 1];
|
|
||||||
delete[] ppEventProcs; ppEventProcs = new StdSchedulerProc *[iProcCapacity];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// *** StdSchedulerThread
|
// *** StdSchedulerThread
|
||||||
|
|
||||||
StdSchedulerThread::StdSchedulerThread()
|
StdSchedulerThread::StdSchedulerThread()
|
||||||
|
@ -446,7 +271,7 @@ unsigned int StdSchedulerThread::ThreadFunc()
|
||||||
{
|
{
|
||||||
// Keep calling Execute until someone gets fed up and calls StopThread()
|
// Keep calling Execute until someone gets fed up and calls StopThread()
|
||||||
while (fRunThreadRun)
|
while (fRunThreadRun)
|
||||||
ScheduleProcs();
|
ScheduleProcs(1000);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,7 +316,7 @@ void StdThread::Stop()
|
||||||
// Wait for thread to terminate itself
|
// Wait for thread to terminate itself
|
||||||
HANDLE hThread = reinterpret_cast<HANDLE>(iThread);
|
HANDLE hThread = reinterpret_cast<HANDLE>(iThread);
|
||||||
if (WaitForSingleObject(hThread, 10000) == WAIT_TIMEOUT)
|
if (WaitForSingleObject(hThread, 10000) == WAIT_TIMEOUT)
|
||||||
// ... or kill him in case he refuses to do so
|
// ... or kill it in case it refuses to do so
|
||||||
TerminateThread(hThread, -1);
|
TerminateThread(hThread, -1);
|
||||||
#elif defined(HAVE_PTHREAD)
|
#elif defined(HAVE_PTHREAD)
|
||||||
// wait for thread to terminate itself
|
// wait for thread to terminate itself
|
||||||
|
@ -503,20 +328,6 @@ void StdThread::Stop()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_WINTHREAD
|
|
||||||
void __cdecl StdThread::_ThreadFunc(void *pPar)
|
|
||||||
{
|
|
||||||
StdThread *pThread = reinterpret_cast<StdThread *>(pPar);
|
|
||||||
_endthreadex(pThread->ThreadFunc());
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_PTHREAD)
|
|
||||||
void *StdThread::_ThreadFunc(void *pPar)
|
|
||||||
{
|
|
||||||
StdThread *pThread = reinterpret_cast<StdThread *>(pPar);
|
|
||||||
return reinterpret_cast<void *>(pThread->ThreadFunc());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned int StdThread::ThreadFunc()
|
unsigned int StdThread::ThreadFunc()
|
||||||
{
|
{
|
||||||
// Keep calling Execute until someone gets fed up and calls Stop()
|
// Keep calling Execute until someone gets fed up and calls Stop()
|
||||||
|
@ -529,199 +340,3 @@ bool StdThread::IsStopSignaled()
|
||||||
{
|
{
|
||||||
return fStopSignaled;
|
return fStopSignaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
void Fail(const char* msg)
|
|
||||||
{
|
|
||||||
Log(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
|
||||||
CStdNotifyProc::CStdNotifyProc() : Event(true) {}
|
|
||||||
void CStdNotifyProc::Notify() { Event.Set(); }
|
|
||||||
bool CStdNotifyProc::CheckAndReset()
|
|
||||||
{
|
|
||||||
if (!Event.WaitFor(0)) return false;
|
|
||||||
Event.Reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else // STDSCHEDULER_USE_EVENTS
|
|
||||||
#ifdef HAVE_SYS_EVENTFD_H
|
|
||||||
#include <sys/eventfd.h>
|
|
||||||
|
|
||||||
CStdNotifyProc::CStdNotifyProc()
|
|
||||||
{
|
|
||||||
fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
|
||||||
if (fds[0] == -1)
|
|
||||||
Fail("eventfd failed");
|
|
||||||
}
|
|
||||||
CStdNotifyProc::~CStdNotifyProc()
|
|
||||||
{
|
|
||||||
close(fds[0]);
|
|
||||||
}
|
|
||||||
void CStdNotifyProc::Notify()
|
|
||||||
{
|
|
||||||
uint64_t n = 1;
|
|
||||||
if (write(fds[0], &n, 8) == -1)
|
|
||||||
Fail("write failed");
|
|
||||||
}
|
|
||||||
bool CStdNotifyProc::CheckAndReset()
|
|
||||||
{
|
|
||||||
uint64_t n;
|
|
||||||
return (read(fds[0], &n, 8) != -1);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
CStdNotifyProc::CStdNotifyProc()
|
|
||||||
{
|
|
||||||
if (pipe(fds) == -1)
|
|
||||||
Fail("pipe failed");
|
|
||||||
fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
|
|
||||||
fcntl(fds[0], F_SETFD, FD_CLOEXEC);
|
|
||||||
fcntl(fds[1], F_SETFD, FD_CLOEXEC);
|
|
||||||
}
|
|
||||||
CStdNotifyProc::~CStdNotifyProc()
|
|
||||||
{
|
|
||||||
close(fds[0]);
|
|
||||||
close(fds[1]);
|
|
||||||
}
|
|
||||||
void CStdNotifyProc::Notify()
|
|
||||||
{
|
|
||||||
char c = 42;
|
|
||||||
if (write(fds[1], &c, 1) == -1)
|
|
||||||
Fail("write failed");
|
|
||||||
}
|
|
||||||
bool CStdNotifyProc::CheckAndReset()
|
|
||||||
{
|
|
||||||
bool r = false;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
if (read(fds[0], &c, 1) <= 0)
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
r = true;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
void CStdNotifyProc::GetFDs(std::vector<struct pollfd> & checkfds)
|
|
||||||
{
|
|
||||||
pollfd pfd = { fds[0], POLLIN, 0 };
|
|
||||||
checkfds.push_back(pfd);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* CStdMultimediaTimerProc */
|
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
|
||||||
int CStdMultimediaTimerProc::iTimePeriod = 0;
|
|
||||||
|
|
||||||
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay) :
|
|
||||||
uCriticalTimerDelay(28),
|
|
||||||
idCriticalTimer(0),
|
|
||||||
uCriticalTimerResolution(5),
|
|
||||||
Event(true)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!iTimePeriod)
|
|
||||||
{
|
|
||||||
// Get resolution caps
|
|
||||||
TIMECAPS tc;
|
|
||||||
timeGetDevCaps(&tc, sizeof(tc));
|
|
||||||
// Establish minimum resolution
|
|
||||||
uCriticalTimerResolution = BoundBy(uCriticalTimerResolution, tc.wPeriodMin, tc.wPeriodMax);
|
|
||||||
timeBeginPeriod(uCriticalTimerResolution);
|
|
||||||
}
|
|
||||||
iTimePeriod++;
|
|
||||||
|
|
||||||
SetDelay(iDelay);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
|
|
||||||
{
|
|
||||||
if (idCriticalTimer)
|
|
||||||
{
|
|
||||||
timeKillEvent(idCriticalTimer);
|
|
||||||
idCriticalTimer = 0;
|
|
||||||
|
|
||||||
iTimePeriod--;
|
|
||||||
if (!iTimePeriod)
|
|
||||||
timeEndPeriod(uCriticalTimerResolution);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CStdMultimediaTimerProc::SetDelay(uint32_t iDelay)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Kill old timer (of any)
|
|
||||||
if (idCriticalTimer)
|
|
||||||
timeKillEvent(idCriticalTimer);
|
|
||||||
|
|
||||||
// Set new delay
|
|
||||||
uCriticalTimerDelay = iDelay;
|
|
||||||
|
|
||||||
// Set critical timer
|
|
||||||
idCriticalTimer=timeSetEvent(
|
|
||||||
uCriticalTimerDelay,uCriticalTimerResolution,
|
|
||||||
(LPTIMECALLBACK) Event.GetEvent(),0,TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
|
|
||||||
|
|
||||||
if(idCriticalTimer == 0)
|
|
||||||
DebugLogF("Creating Critical Timer failed: %d", GetLastError());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CStdMultimediaTimerProc::CheckAndReset()
|
|
||||||
{
|
|
||||||
if (!Check()) return false;
|
|
||||||
Event.Reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(HAVE_SYS_TIMERFD_H)
|
|
||||||
#include <sys/timerfd.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay)
|
|
||||||
{
|
|
||||||
fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
|
||||||
if (fd == -1)
|
|
||||||
Log("timerfd_create failed");
|
|
||||||
SetDelay(iDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CStdMultimediaTimerProc::SetDelay(uint32_t inDelay)
|
|
||||||
{
|
|
||||||
struct itimerspec nv, ov;
|
|
||||||
nv.it_interval.tv_sec = inDelay / 1000;
|
|
||||||
nv.it_interval.tv_nsec = (inDelay % 1000) * 1000000;
|
|
||||||
nv.it_value = nv.it_interval;
|
|
||||||
timerfd_settime(fd, 0, &nv, &ov);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CStdMultimediaTimerProc::Set()
|
|
||||||
{
|
|
||||||
struct itimerspec nv, ov;
|
|
||||||
timerfd_gettime(fd, &nv);
|
|
||||||
nv.it_value.tv_sec = 0;
|
|
||||||
nv.it_value.tv_nsec = 1;
|
|
||||||
timerfd_settime(fd, 0, &nv, &ov);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CStdMultimediaTimerProc::CheckAndReset()
|
|
||||||
{
|
|
||||||
uint64_t n;
|
|
||||||
return read(fd, &n, 8) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CStdMultimediaTimerProc::GetFDs(std::vector<struct pollfd> & checkfds)
|
|
||||||
{
|
|
||||||
pollfd pfd = { fd, POLLIN, 0 };
|
|
||||||
checkfds.push_back(pfd);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -42,12 +42,21 @@ struct pollfd;
|
||||||
#endif // HAVE_PTHREAD
|
#endif // HAVE_PTHREAD
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
typedef struct _GMainLoop GMainLoop;
|
typedef struct _GMainLoop GMainLoop;
|
||||||
|
|
||||||
// Abstract class for a process
|
// Abstract class for a process
|
||||||
class StdSchedulerProc
|
class StdSchedulerProc
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
class StdScheduler *scheduler;
|
||||||
|
protected:
|
||||||
|
void Changed();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
StdSchedulerProc(): scheduler(NULL) {}
|
||||||
virtual ~StdSchedulerProc() { }
|
virtual ~StdSchedulerProc() { }
|
||||||
|
|
||||||
// Do whatever the process wishes to do. Should not block longer than the timeout value.
|
// Do whatever the process wishes to do. Should not block longer than the timeout value.
|
||||||
|
@ -65,13 +74,17 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Call Execute() after this time has elapsed
|
// Call Execute() after this time has elapsed
|
||||||
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow) { return C4TimeMilliseconds::PositiveInfinity; };
|
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow);
|
||||||
|
|
||||||
// Is the process signal currently set?
|
// Is the process signal currently set?
|
||||||
bool IsSignaled();
|
bool IsSignaled();
|
||||||
|
|
||||||
// Is this the expensive game tick?
|
// Is this the expensive game tick?
|
||||||
virtual bool IsLowPriority() { return false; }
|
virtual bool IsLowPriority() { return false; }
|
||||||
|
virtual bool IsNotify() { return false; }
|
||||||
|
virtual uint32_t TimerInterval() { return 0; }
|
||||||
|
|
||||||
|
friend class StdScheduler;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,7 +104,7 @@ public:
|
||||||
{
|
{
|
||||||
tLastTimer = C4TimeMilliseconds::NegativeInfinity;
|
tLastTimer = C4TimeMilliseconds::NegativeInfinity;
|
||||||
}
|
}
|
||||||
void SetDelay(uint32_t inDelay) { iDelay = inDelay; }
|
void SetDelay(uint32_t inDelay) { iDelay = inDelay; Changed(); }
|
||||||
bool CheckAndReset()
|
bool CheckAndReset()
|
||||||
{
|
{
|
||||||
C4TimeMilliseconds tTime = C4TimeMilliseconds::Now();
|
C4TimeMilliseconds tTime = C4TimeMilliseconds::Now();
|
||||||
|
@ -107,6 +120,7 @@ public:
|
||||||
{
|
{
|
||||||
return tLastTimer + iDelay;
|
return tLastTimer + iDelay;
|
||||||
}
|
}
|
||||||
|
virtual uint32_t TimerInterval() { return iDelay; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// A simple alertable proc
|
// A simple alertable proc
|
||||||
|
@ -117,6 +131,7 @@ public:
|
||||||
|
|
||||||
void Notify();
|
void Notify();
|
||||||
bool CheckAndReset();
|
bool CheckAndReset();
|
||||||
|
virtual bool IsNotify() { return true; }
|
||||||
|
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
#ifdef STDSCHEDULER_USE_EVENTS
|
||||||
~CStdNotifyProc() { }
|
~CStdNotifyProc() { }
|
||||||
|
@ -197,8 +212,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Process list
|
// Process list
|
||||||
StdSchedulerProc **ppProcs;
|
std::vector<StdSchedulerProc*> procs;
|
||||||
int iProcCnt, iProcCapacity;
|
bool isInManualLoop;
|
||||||
|
|
||||||
// Unblocker
|
// Unblocker
|
||||||
class NoopNotifyProc : public CStdNotifyProc
|
class NoopNotifyProc : public CStdNotifyProc
|
||||||
|
@ -209,21 +224,25 @@ private:
|
||||||
|
|
||||||
// Dummy lists (preserved to reduce allocs)
|
// Dummy lists (preserved to reduce allocs)
|
||||||
#ifdef STDSCHEDULER_USE_EVENTS
|
#ifdef STDSCHEDULER_USE_EVENTS
|
||||||
HANDLE *pEventHandles;
|
std::vector<HANDLE> eventHandles;
|
||||||
StdSchedulerProc **ppEventProcs;
|
std::vector<StdSchedulerProc*> eventProcs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getProcCnt() const { return iProcCnt-1; } // ignore internal NoopNotifyProc
|
int getProcCnt() const { return procs.size()-1; } // ignore internal NoopNotifyProc
|
||||||
int getProc(StdSchedulerProc *pProc);
|
bool hasProc(StdSchedulerProc *pProc) { return std::find(procs.begin(), procs.end(), pProc) != procs.end(); }
|
||||||
bool hasProc(StdSchedulerProc *pProc) { return getProc(pProc) >= 0; }
|
bool IsInManualLoop() { return isInManualLoop; }
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void Set(StdSchedulerProc **ppProcs, int iProcCnt);
|
void Set(StdSchedulerProc **ppProcs, int iProcCnt);
|
||||||
void Add(StdSchedulerProc *pProc);
|
void Add(StdSchedulerProc *pProc);
|
||||||
void Remove(StdSchedulerProc *pProc);
|
void Remove(StdSchedulerProc *pProc);
|
||||||
|
|
||||||
|
void Added(StdSchedulerProc *pProc);
|
||||||
|
void Removing(StdSchedulerProc *pProc);
|
||||||
|
void Changed(StdSchedulerProc *pProc);
|
||||||
|
|
||||||
bool ScheduleProcs(int iTimeout = -1);
|
virtual bool ScheduleProcs(int iTimeout = -1);
|
||||||
void UnBlock();
|
void UnBlock();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -231,8 +250,7 @@ protected:
|
||||||
virtual void OnError(StdSchedulerProc *) { }
|
virtual void OnError(StdSchedulerProc *) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Enlarge(int iBy);
|
bool DoScheduleProcs(int iTimeout);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A simple process scheduler thread
|
// A simple process scheduler thread
|
||||||
|
@ -245,7 +263,7 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// thread control
|
// thread control
|
||||||
bool fRunThreadRun, fWait;
|
bool fRunThreadRun;
|
||||||
|
|
||||||
bool fThread;
|
bool fThread;
|
||||||
#ifdef HAVE_WINTHREAD
|
#ifdef HAVE_WINTHREAD
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
#include <C4Include.h>
|
||||||
|
#include <StdScheduler.h>
|
||||||
|
#ifdef USE_COCOA
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
@class SCHAdditions;
|
||||||
|
|
||||||
|
@interface SCHAddition : NSObject
|
||||||
|
{
|
||||||
|
@protected
|
||||||
|
__weak SCHAdditions* schedulerAdditions;
|
||||||
|
StdSchedulerProc* proc;
|
||||||
|
}
|
||||||
|
- (id) initWithProc:(StdSchedulerProc*)_proc;
|
||||||
|
- (void) registerAt:(SCHAdditions*) _additions;
|
||||||
|
- (void) unregisterFrom:(SCHAdditions*) _additions;
|
||||||
|
- (bool) shouldExecuteProc;
|
||||||
|
- (void) changed;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SCHNotify : SCHAddition
|
||||||
|
{
|
||||||
|
list<CFRunLoopSourceRef> socketSources;
|
||||||
|
}
|
||||||
|
- (void) registerAt:(SCHAdditions*) _additions;
|
||||||
|
- (void) unregisterFrom:(SCHAdditions*) _additions;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SCHTimer : SCHAddition
|
||||||
|
{
|
||||||
|
@private
|
||||||
|
NSTimer* timer;
|
||||||
|
}
|
||||||
|
- (void) registerAt:(SCHAdditions*) _additions;
|
||||||
|
- (void) unregisterFrom:(SCHAdditions*) _additions;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SCHAdditions : NSObject
|
||||||
|
{
|
||||||
|
NSMutableDictionary* procAdditions;
|
||||||
|
}
|
||||||
|
- (id) initWithScheduler:(StdScheduler*) scheduler;
|
||||||
|
- (SCHAddition*) additionForProc:(StdSchedulerProc*) proc;
|
||||||
|
- (SCHAddition*) assignAdditionForProc:(StdSchedulerProc*) proc;
|
||||||
|
+ (SCHAdditions*) requestAdditionForScheduler:(StdScheduler*) scheduler;
|
||||||
|
- (BOOL) removeAdditionForProc:(StdSchedulerProc*) proc;
|
||||||
|
@property(readonly) NSRunLoop* runLoop;
|
||||||
|
@property(readonly) StdScheduler* scheduler;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SCHAdditions
|
||||||
|
|
||||||
|
static NSMutableDictionary* additionsDictionary;
|
||||||
|
|
||||||
|
- (id) initWithScheduler:(StdScheduler*) scheduler
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_scheduler = scheduler;
|
||||||
|
_runLoop = [NSRunLoop currentRunLoop];
|
||||||
|
procAdditions = [NSMutableDictionary new];
|
||||||
|
return self;
|
||||||
|
} else
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (SCHAddition*) additionForProc:(StdSchedulerProc*) proc
|
||||||
|
{
|
||||||
|
return [procAdditions objectForKey:[NSNumber valueWithPointer:proc]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) removeAdditionForProc:(StdSchedulerProc*) proc
|
||||||
|
{
|
||||||
|
auto key = [NSNumber valueWithPointer:proc];
|
||||||
|
SCHAddition* x = [procAdditions objectForKey:key];
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
[x unregisterFrom:self];
|
||||||
|
[procAdditions removeObjectForKey:key];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (SCHAddition*) assignAdditionForProc:(StdSchedulerProc*) proc
|
||||||
|
{
|
||||||
|
auto timerInterval = proc->TimerInterval();
|
||||||
|
auto addition =
|
||||||
|
timerInterval ? [[SCHTimer alloc] initWithProc:proc] :
|
||||||
|
proc->IsNotify() ? [[SCHNotify alloc] initWithProc:proc] :
|
||||||
|
nullptr;
|
||||||
|
if (addition)
|
||||||
|
{
|
||||||
|
[procAdditions setObject:addition forKey:[NSNumber valueWithPointer:proc]];
|
||||||
|
return addition;
|
||||||
|
} else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SCHAdditions*) requestAdditionForScheduler:(StdScheduler *)scheduler
|
||||||
|
{
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken,
|
||||||
|
^{ additionsDictionary = [NSMutableDictionary new]; });
|
||||||
|
auto key = [NSNumber valueWithPointer:scheduler];
|
||||||
|
@synchronized (additionsDictionary)
|
||||||
|
{
|
||||||
|
SCHAdditions* additions = [additionsDictionary objectForKey:key];
|
||||||
|
if (!additions)
|
||||||
|
{
|
||||||
|
additions = [[SCHAdditions alloc] initWithScheduler:scheduler];
|
||||||
|
[additionsDictionary setObject:additions forKey:key];
|
||||||
|
}
|
||||||
|
return additions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SCHAddition
|
||||||
|
- (id) initWithProc:(StdSchedulerProc *) _proc
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
proc = _proc;
|
||||||
|
return self;
|
||||||
|
} else
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (bool) shouldExecuteProc
|
||||||
|
{
|
||||||
|
auto s = schedulerAdditions;
|
||||||
|
return s && !s.scheduler->IsInManualLoop();
|
||||||
|
}
|
||||||
|
- (void) registerAt:(SCHAdditions*) _additions
|
||||||
|
{
|
||||||
|
schedulerAdditions = _additions;
|
||||||
|
}
|
||||||
|
- (void) unregisterFrom:(SCHAdditions*) _additions
|
||||||
|
{
|
||||||
|
schedulerAdditions = nil;
|
||||||
|
}
|
||||||
|
- (void) changed
|
||||||
|
{
|
||||||
|
auto s = schedulerAdditions;
|
||||||
|
[self unregisterFrom:s];
|
||||||
|
[self registerAt:s];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SCHTimer
|
||||||
|
- (id) initWithProc:(StdSchedulerProc *) _proc
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
proc = _proc;
|
||||||
|
return self;
|
||||||
|
} else
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (void) run:(id) sender
|
||||||
|
{
|
||||||
|
auto i = timer;
|
||||||
|
if (i && [self shouldExecuteProc])
|
||||||
|
proc->Execute();
|
||||||
|
}
|
||||||
|
- (void) registerAt:(SCHAdditions*) _additions
|
||||||
|
{
|
||||||
|
[super registerAt:_additions];
|
||||||
|
auto loop = _additions.runLoop;
|
||||||
|
timer = [NSTimer timerWithTimeInterval:proc->TimerInterval()/1000.0 target:self selector:@selector(run:) userInfo:nil repeats:YES];
|
||||||
|
if ([timer respondsToSelector:@selector(setTolerance:)])
|
||||||
|
[timer setTolerance:0.0];
|
||||||
|
[loop addTimer:timer forMode:NSDefaultRunLoopMode];
|
||||||
|
}
|
||||||
|
- (void) unregisterFrom:(SCHAdditions*) _additions
|
||||||
|
{
|
||||||
|
[timer invalidate];
|
||||||
|
timer = nil;
|
||||||
|
[super unregisterFrom:_additions];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SCHNotify
|
||||||
|
void callback (CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
|
||||||
|
{
|
||||||
|
auto notify = (__bridge SCHNotify*)info;
|
||||||
|
pollfd p = {.fd=CFSocketGetNative(s)};
|
||||||
|
if ([notify shouldExecuteProc])
|
||||||
|
notify->proc->Execute(-1, &p);
|
||||||
|
}
|
||||||
|
- (void) registerAt:(SCHAdditions*) _additions
|
||||||
|
{
|
||||||
|
[super registerAt:_additions];
|
||||||
|
vector<struct pollfd> vecs;
|
||||||
|
proc->GetFDs(vecs);
|
||||||
|
CFSocketContext ctx = {};
|
||||||
|
ctx.info = (__bridge void*)self;
|
||||||
|
for (auto p : vecs)
|
||||||
|
{
|
||||||
|
auto socket = CFSocketCreateWithNative(NULL,
|
||||||
|
p.fd, kCFSocketReadCallBack,
|
||||||
|
callback, &ctx
|
||||||
|
);
|
||||||
|
auto runLoopSource = CFSocketCreateRunLoopSource(NULL, socket, 0);
|
||||||
|
CFRunLoopAddSource([_additions.runLoop getCFRunLoop], runLoopSource, kCFRunLoopDefaultMode);
|
||||||
|
socketSources.push_back(runLoopSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (void) unregisterFrom:(SCHAdditions*) _additions
|
||||||
|
{
|
||||||
|
for (auto r : socketSources)
|
||||||
|
{
|
||||||
|
CFRunLoopSourceInvalidate(r);
|
||||||
|
CFRelease(r);
|
||||||
|
}
|
||||||
|
socketSources.clear();
|
||||||
|
[super unregisterFrom:_additions];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
void StdScheduler::Added(StdSchedulerProc *pProc)
|
||||||
|
{
|
||||||
|
auto x = [SCHAdditions requestAdditionForScheduler:this];
|
||||||
|
auto addition = [x assignAdditionForProc:pProc];
|
||||||
|
if (addition)
|
||||||
|
[addition registerAt:x];
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdScheduler::Removing(StdSchedulerProc *pProc)
|
||||||
|
{
|
||||||
|
auto x = [SCHAdditions requestAdditionForScheduler:this];
|
||||||
|
[x removeAdditionForProc:pProc];
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdScheduler::Changed(StdSchedulerProc* pProc)
|
||||||
|
{
|
||||||
|
auto x = [SCHAdditions requestAdditionForScheduler:this];
|
||||||
|
auto addition = [x additionForProc:pProc];
|
||||||
|
if (addition)
|
||||||
|
[addition changed];
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,247 @@
|
||||||
|
#include "C4Include.h"
|
||||||
|
#include "StdScheduler.h"
|
||||||
|
#ifdef HAVE_POLL_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef HAVE_IO_H
|
||||||
|
#include <io.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SHARE_H
|
||||||
|
#include <share.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
// For pipe()
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
// Is this process currently signaled?
|
||||||
|
bool StdSchedulerProc::IsSignaled()
|
||||||
|
{
|
||||||
|
// Initialize file descriptor sets
|
||||||
|
std::vector<struct pollfd> fds;
|
||||||
|
|
||||||
|
// Get file descriptors
|
||||||
|
GetFDs(fds);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
return poll(&fds[0], fds.size(), 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void Fail(const char* msg)
|
||||||
|
{
|
||||||
|
Log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_EVENTFD_H
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
|
CStdNotifyProc::CStdNotifyProc()
|
||||||
|
{
|
||||||
|
fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||||
|
if (fds[0] == -1)
|
||||||
|
Fail("eventfd failed");
|
||||||
|
}
|
||||||
|
CStdNotifyProc::~CStdNotifyProc()
|
||||||
|
{
|
||||||
|
close(fds[0]);
|
||||||
|
}
|
||||||
|
void CStdNotifyProc::Notify()
|
||||||
|
{
|
||||||
|
uint64_t n = 1;
|
||||||
|
if (write(fds[0], &n, 8) == -1)
|
||||||
|
Fail("write failed");
|
||||||
|
}
|
||||||
|
bool CStdNotifyProc::CheckAndReset()
|
||||||
|
{
|
||||||
|
uint64_t n;
|
||||||
|
return (read(fds[0], &n, 8) != -1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
CStdNotifyProc::CStdNotifyProc()
|
||||||
|
{
|
||||||
|
if (pipe(fds) == -1)
|
||||||
|
Fail("pipe failed");
|
||||||
|
fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
|
||||||
|
fcntl(fds[0], F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(fds[1], F_SETFD, FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
CStdNotifyProc::~CStdNotifyProc()
|
||||||
|
{
|
||||||
|
close(fds[0]);
|
||||||
|
close(fds[1]);
|
||||||
|
}
|
||||||
|
void CStdNotifyProc::Notify()
|
||||||
|
{
|
||||||
|
char c = 42;
|
||||||
|
if (write(fds[1], &c, 1) == -1)
|
||||||
|
Fail("write failed");
|
||||||
|
}
|
||||||
|
bool CStdNotifyProc::CheckAndReset()
|
||||||
|
{
|
||||||
|
bool r = false;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
if (read(fds[0], &c, 1) <= 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
r = true;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void CStdNotifyProc::GetFDs(std::vector<struct pollfd> & checkfds)
|
||||||
|
{
|
||||||
|
pollfd pfd = { fds[0], POLLIN, 0 };
|
||||||
|
checkfds.push_back(pfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StdScheduler::DoScheduleProcs(int iTimeout)
|
||||||
|
{
|
||||||
|
// Initialize file descriptor sets
|
||||||
|
std::vector<struct pollfd> fds;
|
||||||
|
std::map<StdSchedulerProc *, std::pair<unsigned int, unsigned int> > fds_for_proc;
|
||||||
|
|
||||||
|
// Collect file descriptors
|
||||||
|
for (auto proc : procs)
|
||||||
|
{
|
||||||
|
unsigned int os = fds.size();
|
||||||
|
proc->GetFDs(fds);
|
||||||
|
if (os != fds.size())
|
||||||
|
fds_for_proc[proc] = std::pair<unsigned int, unsigned int>(os, fds.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for something to happen
|
||||||
|
int cnt = poll(&fds[0], fds.size(), iTimeout);
|
||||||
|
|
||||||
|
bool fSuccess = true;
|
||||||
|
|
||||||
|
if (cnt >= 0)
|
||||||
|
{
|
||||||
|
bool any_executed = false;
|
||||||
|
auto tNow = C4TimeMilliseconds::Now();
|
||||||
|
// Which process?
|
||||||
|
for (auto i = 0; i < procs.size(); i++)
|
||||||
|
{
|
||||||
|
auto proc = procs[i];
|
||||||
|
auto tProcTick = proc->GetNextTick(tNow);
|
||||||
|
if (tProcTick <= tNow)
|
||||||
|
{
|
||||||
|
struct pollfd * pfd = 0;
|
||||||
|
if (fds_for_proc.find(proc) != fds_for_proc.end())
|
||||||
|
pfd = &fds[fds_for_proc[proc].first];
|
||||||
|
if (!proc->Execute(0, pfd))
|
||||||
|
{
|
||||||
|
OnError(proc);
|
||||||
|
fSuccess = false;
|
||||||
|
}
|
||||||
|
any_executed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// no fds?
|
||||||
|
if (fds_for_proc.find(proc) == fds_for_proc.end())
|
||||||
|
continue;
|
||||||
|
// Check intersection
|
||||||
|
unsigned int begin = fds_for_proc[proc].first;
|
||||||
|
unsigned int end = fds_for_proc[proc].second;
|
||||||
|
for (unsigned int j = begin; j < end; ++j)
|
||||||
|
{
|
||||||
|
if (fds[j].events & fds[j].revents)
|
||||||
|
{
|
||||||
|
if (any_executed && proc->IsLowPriority())
|
||||||
|
break;
|
||||||
|
if (!proc->Execute(0, &fds[begin]))
|
||||||
|
{
|
||||||
|
OnError(proc);
|
||||||
|
fSuccess = false;
|
||||||
|
}
|
||||||
|
any_executed = true;
|
||||||
|
// the list of procs might have been changed, but procs must be in both ppProcs and
|
||||||
|
// fds_for_proc to be executed, which prevents execution of any proc not polled this round
|
||||||
|
// or deleted. Some procs might be skipped or executed twice, but that should be save.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cnt < 0)
|
||||||
|
{
|
||||||
|
printf("StdScheduler::Execute: poll failed: %s\n",strerror(errno));
|
||||||
|
}
|
||||||
|
return fSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_SYS_TIMERFD_H)
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay)
|
||||||
|
{
|
||||||
|
fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||||
|
if (fd == -1)
|
||||||
|
Log("timerfd_create failed");
|
||||||
|
SetDelay(iDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStdMultimediaTimerProc::SetDelay(uint32_t inDelay)
|
||||||
|
{
|
||||||
|
struct itimerspec nv, ov;
|
||||||
|
nv.it_interval.tv_sec = inDelay / 1000;
|
||||||
|
nv.it_interval.tv_nsec = (inDelay % 1000) * 1000000;
|
||||||
|
nv.it_value = nv.it_interval;
|
||||||
|
timerfd_settime(fd, 0, &nv, &ov);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStdMultimediaTimerProc::Set()
|
||||||
|
{
|
||||||
|
struct itimerspec nv, ov;
|
||||||
|
timerfd_gettime(fd, &nv);
|
||||||
|
nv.it_value.tv_sec = 0;
|
||||||
|
nv.it_value.tv_nsec = 1;
|
||||||
|
timerfd_settime(fd, 0, &nv, &ov);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CStdMultimediaTimerProc::CheckAndReset()
|
||||||
|
{
|
||||||
|
uint64_t n;
|
||||||
|
return read(fd, &n, 8) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStdMultimediaTimerProc::GetFDs(std::vector<struct pollfd> & checkfds)
|
||||||
|
{
|
||||||
|
pollfd pfd = { fd, POLLIN, 0 };
|
||||||
|
checkfds.push_back(pfd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_COCOA)
|
||||||
|
void StdScheduler::Added(StdSchedulerProc *pProc) {}
|
||||||
|
void StdScheduler::Removing(StdSchedulerProc *pProc) {}
|
||||||
|
void StdScheduler::Changed(StdSchedulerProc* pProc) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *StdThread::_ThreadFunc(void *pPar)
|
||||||
|
{
|
||||||
|
StdThread *pThread = reinterpret_cast<StdThread *>(pPar);
|
||||||
|
return reinterpret_cast<void *>(pThread->ThreadFunc());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,173 @@
|
||||||
|
// Events are Windows-specific
|
||||||
|
#include <C4Include.h>
|
||||||
|
#include <StdScheduler.h>
|
||||||
|
#ifdef USE_WIN32_WINDOWS
|
||||||
|
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
|
bool StdSchedulerProc::IsSignaled()
|
||||||
|
{
|
||||||
|
return GetEvent() && WaitForSingleObject(GetEvent(), 0) == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CStdNotifyProc::CStdNotifyProc() : Event(true) {}
|
||||||
|
void CStdNotifyProc::Notify() { Event.Set(); }
|
||||||
|
bool CStdNotifyProc::CheckAndReset()
|
||||||
|
{
|
||||||
|
if (!Event.WaitFor(0)) return false;
|
||||||
|
Event.Reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StdScheduler::DoScheduleProcs(int iTimeout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
// Collect event handles
|
||||||
|
int iEventCnt = 0; HANDLE hEvent;
|
||||||
|
StdSchedulerProc *pMessageProc = NULL;
|
||||||
|
for (i = 0; i < procs.size(); i++)
|
||||||
|
{
|
||||||
|
auto proc = procs[i];
|
||||||
|
if ( (hEvent = procs[i]->GetEvent()) )
|
||||||
|
{
|
||||||
|
if (hEvent == STDSCHEDULER_EVENT_MESSAGE)
|
||||||
|
pMessageProc = procs[i];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eventHandles[iEventCnt] = hEvent;
|
||||||
|
eventProcs[iEventCnt] = procs[i];
|
||||||
|
iEventCnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for something to happen
|
||||||
|
DWORD ret; DWORD dwMsec = iTimeout < 0 ? INFINITE : iTimeout;
|
||||||
|
if (pMessageProc)
|
||||||
|
ret = MsgWaitForMultipleObjects(iEventCnt, eventHandles.data(), false, dwMsec, QS_ALLINPUT);
|
||||||
|
else
|
||||||
|
ret = WaitForMultipleObjects(iEventCnt, eventHandles.data(), false, dwMsec);
|
||||||
|
|
||||||
|
bool fSuccess = true;
|
||||||
|
|
||||||
|
// Event?
|
||||||
|
if (ret != WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
// Which event?
|
||||||
|
int iEventNr = ret - WAIT_OBJECT_0;
|
||||||
|
|
||||||
|
// Execute the signaled process
|
||||||
|
StdSchedulerProc *pProc = iEventNr < iEventCnt ? eventProcs[iEventNr] : pMessageProc;
|
||||||
|
if (!pProc->Execute(0))
|
||||||
|
{
|
||||||
|
OnError(pProc);
|
||||||
|
fSuccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute all processes with timeout
|
||||||
|
auto tNow = C4TimeMilliseconds::Now();
|
||||||
|
for (auto proc : procs)
|
||||||
|
{
|
||||||
|
auto tProcTick = proc->GetNextTick(tNow);
|
||||||
|
if (tProcTick <= tNow)
|
||||||
|
if (!proc->Execute(0))
|
||||||
|
{
|
||||||
|
OnError(proc);
|
||||||
|
fSuccess = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CStdMultimediaTimerProc */
|
||||||
|
|
||||||
|
int CStdMultimediaTimerProc::iTimePeriod = 0;
|
||||||
|
|
||||||
|
CStdMultimediaTimerProc::CStdMultimediaTimerProc(uint32_t iDelay) :
|
||||||
|
uCriticalTimerDelay(28),
|
||||||
|
idCriticalTimer(0),
|
||||||
|
uCriticalTimerResolution(5),
|
||||||
|
Event(true)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!iTimePeriod)
|
||||||
|
{
|
||||||
|
// Get resolution caps
|
||||||
|
TIMECAPS tc;
|
||||||
|
timeGetDevCaps(&tc, sizeof(tc));
|
||||||
|
// Establish minimum resolution
|
||||||
|
uCriticalTimerResolution = BoundBy(uCriticalTimerResolution, tc.wPeriodMin, tc.wPeriodMax);
|
||||||
|
timeBeginPeriod(uCriticalTimerResolution);
|
||||||
|
}
|
||||||
|
iTimePeriod++;
|
||||||
|
|
||||||
|
SetDelay(iDelay);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
|
||||||
|
{
|
||||||
|
if (idCriticalTimer)
|
||||||
|
{
|
||||||
|
timeKillEvent(idCriticalTimer);
|
||||||
|
idCriticalTimer = 0;
|
||||||
|
|
||||||
|
iTimePeriod--;
|
||||||
|
if (!iTimePeriod)
|
||||||
|
timeEndPeriod(uCriticalTimerResolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStdMultimediaTimerProc::SetDelay(uint32_t iDelay)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Kill old timer (of any)
|
||||||
|
if (idCriticalTimer)
|
||||||
|
timeKillEvent(idCriticalTimer);
|
||||||
|
|
||||||
|
// Set new delay
|
||||||
|
uCriticalTimerDelay = iDelay;
|
||||||
|
|
||||||
|
// Set critical timer
|
||||||
|
idCriticalTimer=timeSetEvent(
|
||||||
|
uCriticalTimerDelay,uCriticalTimerResolution,
|
||||||
|
(LPTIMECALLBACK) Event.GetEvent(),0,TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
|
||||||
|
|
||||||
|
if(idCriticalTimer == 0)
|
||||||
|
DebugLogF("Creating Critical Timer failed: %d", GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdScheduler::Added(StdSchedulerProc *pProc)
|
||||||
|
{
|
||||||
|
if (procs.size() > eventProcs.size())
|
||||||
|
{
|
||||||
|
eventProcs.resize(procs.size());
|
||||||
|
eventHandles.resize(procs.size()+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdScheduler::Removing(StdSchedulerProc *pProc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdScheduler::Changed(StdSchedulerProc* pProc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CStdMultimediaTimerProc::CheckAndReset()
|
||||||
|
{
|
||||||
|
if (!Check()) return false;
|
||||||
|
Event.Reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cdecl StdThread::_ThreadFunc(void *pPar)
|
||||||
|
{
|
||||||
|
StdThread *pThread = reinterpret_cast<StdThread *>(pPar);
|
||||||
|
_endthreadex(pThread->ThreadFunc());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue