📄 osutils.cxx
字号:
void PTimer::Construct()
{
timerList = PProcess::Current().GetTimerList();
timerId = timerList->GetNewTimerId();
state = Stopped;
StartRunning(PTrue);
}
PTimer & PTimer::operator=(DWORD milliseconds)
{
resetTime.SetInterval(milliseconds);
StartRunning(oneshot);
return *this;
}
PTimer & PTimer::operator=(const PTimeInterval & time)
{
resetTime = time;
StartRunning(oneshot);
return *this;
}
PTimer::~PTimer()
{
// queue a request to remove this timer, and always do it synchronously
timerList->QueueRequest(PTimerList::RequestType::Stop, this, true);
}
void PTimer::SetInterval(PInt64 milliseconds,
long seconds,
long minutes,
long hours,
int days)
{
resetTime.SetInterval(milliseconds, seconds, minutes, hours, days);
StartRunning(oneshot);
}
void PTimer::RunContinuous(const PTimeInterval & time)
{
resetTime = time;
StartRunning(PFalse);
}
void PTimer::StartRunning(PBoolean once)
{
PTimeInterval::operator=(resetTime);
oneshot = once;
state = (*this) != 0 ? Starting : Stopped;
if (IsRunning())
timerList->QueueRequest(PTimerList::RequestType::Start, this, false);
else
timerList->QueueRequest(PTimerList::RequestType::Stop, this);
}
void PTimer::Stop(bool wait)
{
state = Stopped;
milliseconds = 0;
timerList->QueueRequest(PTimerList::RequestType::Stop, this, wait);
}
void PTimer::Pause()
{
if (IsRunning()) {
state = Paused;
timerList->QueueRequest(PTimerList::RequestType::Stop, this);
}
}
void PTimer::Resume()
{
if (state == Paused) {
state = Starting;
timerList->QueueRequest(PTimerList::RequestType::Start, this);
}
}
void PTimer::Reset()
{
StartRunning(oneshot);
}
// called only from the timer thread
void PTimer::OnTimeout()
{
if (!callback.IsNULL())
callback(*this, IsRunning());
}
void PTimer::Process(const PTimeInterval & delta, PTimeInterval & minTimeLeft)
{
switch (state) {
case Starting :
state = Running;
if (resetTime < minTimeLeft)
minTimeLeft = resetTime;
break;
case Running :
operator-=(delta);
if (milliseconds > 0) {
if (milliseconds < minTimeLeft.GetMilliSeconds())
minTimeLeft = *this;
}
else {
if (oneshot) {
milliseconds = 0;
state = Stopped;
}
else {
PTimeInterval::operator=(resetTime);
if (resetTime < minTimeLeft)
minTimeLeft = resetTime;
}
/* This must be outside the mutex or if OnTimeout() changes the
timer value (quite plausible) it deadlocks.
*/
OnTimeout();
return;
}
break;
default : // Stopped or Paused, do nothing.
break;
}
}
///////////////////////////////////////////////////////////////////////////////
// PTimerList
PTimerList::PTimerList()
{
timerThread = NULL;
}
void PTimerList::QueueRequest(RequestType::Action action, PTimer * timer, bool _isSync)
{
// if this operation is occurring in the timer thread, then handle synchronoously
if (timerThread == PThread::Current()) {
switch (action) {
case PTimerList::RequestType::Start:
{
TimerInfoMapType::iterator r = timerInfoMap.find(timer->GetTimerId());
if (r == timerInfoMap.end())
timerInfoMap.insert(TimerInfoMapType::value_type(timer->GetTimerId(), TimerInfoType(timer)));
}
break;
case PTimerList::RequestType::Stop:
{
TimerInfoMapType::iterator r = timerInfoMap.find(timer->GetTimerId());
if (r != timerInfoMap.end())
r->second.removed = true;
}
break;
}
return;
}
// handle asynchronoously
RequestType request(action, timer);
PSyncPoint sync;
bool isSync = false;
if (_isSync) {
request.sync = &sync;
isSync = true;
}
{
PWaitAndSignal m(queueMutex);
requestQueue.push(request);
}
PProcess::Current().SignalTimerChange();
if (isSync)
sync.Wait();
}
PTimeInterval PTimerList::Process()
{
timerThread = PThread::Current();
PWaitAndSignal l(timerListMutex);
// process the requests in the timer request queue
{
PWaitAndSignal q(queueMutex);
while (requestQueue.size() > 0) {
RequestType request = requestQueue.front();
requestQueue.pop();
TimerInfoMapType::iterator r = timerInfoMap.find(request.id);
switch (request.action) {
case PTimerList::RequestType::Start:
if (r == timerInfoMap.end())
timerInfoMap.insert(TimerInfoMapType::value_type(request.id, TimerInfoType(request.timer)));
break;
case PTimerList::RequestType::Stop:
if (r != timerInfoMap.end())
timerInfoMap.erase(r);
break;
default:
PAssertAlways("unknown timer request code");
break;
}
if (request.sync != NULL)
request.sync->Signal();
}
}
// calculate interval since last processing, and update time of last processing to now
PTimeInterval now = PTimer::Tick();
PTimeInterval sampleTime;
if (lastSample == 0 || lastSample > now)
sampleTime = 0;
else {
sampleTime = now - lastSample;
if (now < lastSample)
sampleTime += PMaxTimeInterval;
}
lastSample = now;
// process the timers and find the minimum amount of time remaining
// also remove any timer labelled as removed
PTimeInterval minTimeLeft = PMaxTimeInterval;
{
TimerInfoMapType::iterator r = timerInfoMap.begin();
while (r != timerInfoMap.end()) {
PTimeInterval oldMinTimeLeft(minTimeLeft);
if (!r->second.removed)
r->second.timer->Process(sampleTime, minTimeLeft);
if (!r->second.removed)
++r;
else {
if (r == timerInfoMap.begin()) {
timerInfoMap.erase(r);
r = timerInfoMap.begin();
}
else
{
TimerInfoMapType::iterator s = r;
--s;
timerInfoMap.erase(r);
r = s;
}
minTimeLeft = oldMinTimeLeft;
}
}
}
return minTimeLeft;
}
///////////////////////////////////////////////////////////////////////////////
// PArgList
PArgList::PArgList(const char * theArgStr,
const char * theArgumentSpec,
PBoolean optionsBeforeParams)
{
// get the program arguments
if (theArgStr != NULL)
SetArgs(theArgStr);
// if we got an argument spec - so process them
if (theArgumentSpec != NULL)
Parse(theArgumentSpec, optionsBeforeParams);
}
PArgList::PArgList(const PString & theArgStr,
const char * argumentSpecPtr,
PBoolean optionsBeforeParams)
{
// get the program arguments
SetArgs(theArgStr);
// if we got an argument spec - so process them
if (argumentSpecPtr != NULL)
Parse(argumentSpecPtr, optionsBeforeParams);
}
PArgList::PArgList(const PString & theArgStr,
const PString & argumentSpecStr,
PBoolean optionsBeforeParams)
{
// get the program arguments
SetArgs(theArgStr);
// if we got an argument spec - so process them
Parse(argumentSpecStr, optionsBeforeParams);
}
PArgList::PArgList(int theArgc, char ** theArgv,
const char * theArgumentSpec,
PBoolean optionsBeforeParams)
{
// get the program arguments
SetArgs(theArgc, theArgv);
// if we got an argument spec - so process them
if (theArgumentSpec != NULL)
Parse(theArgumentSpec, optionsBeforeParams);
}
PArgList::PArgList(int theArgc, char ** theArgv,
const PString & theArgumentSpec,
PBoolean optionsBeforeParams)
{
// get the program name and path
SetArgs(theArgc, theArgv);
// we got an argument spec - so process them
Parse(theArgumentSpec, optionsBeforeParams);
}
void PArgList::PrintOn(ostream & strm) const
{
for (PINDEX i = 0; i < argumentArray.GetSize(); i++) {
if (i > 0)
strm << strm.fill();
strm << argumentArray[i];
}
}
void PArgList::ReadFrom(istream & strm)
{
PString line;
strm >> line;
SetArgs(line);
}
void PArgList::SetArgs(const PString & argStr)
{
argumentArray.SetSize(0);
const char * str = argStr;
for (;;) {
while (isspace(*str)) // Skip leading whitespace
str++;
if (*str == '\0')
break;
PString & arg = argumentArray[argumentArray.GetSize()];
while (*str != '\0' && !isspace(*str)) {
switch (*str) {
case '"' :
str++;
while (*str != '\0' && *str != '"')
arg += *str++;
if (*str != '\0')
str++;
break;
case '\'' :
str++;
while (*str != '\0' && *str != '\'')
arg += *str++;
if (*str != '\0')
str++;
break;
default :
if (str[0] == '\\' && str[1] != '\0')
str++;
arg += *str++;
}
}
}
SetArgs(argumentArray);
}
void PArgList::SetArgs(const PStringArray & theArgs)
{
argumentArray = theArgs;
shift = 0;
optionLetters = "";
optionNames.SetSize(0);
parameterIndex.SetSize(argumentArray.GetSize());
for (PINDEX i = 0; i < argumentArray.GetSize(); i++)
parameterIndex[i] = i;
}
PBoolean PArgList::Parse(const char * spec, PBoolean optionsBeforeParams)
{
if (PAssertNULL(spec) == NULL)
return PFalse;
// Find starting point, start at shift if first Parse() call.
PINDEX arg = optionLetters.IsEmpty() ? shift : 0;
// If not in parse all mode, have been parsed before, and had some parameters
// from last time, then start argument parsing somewhere along instead of start.
if (optionsBeforeParams && !optionLetters && parameterIndex.GetSize() > 0)
arg = parameterIndex[parameterIndex.GetSize()-1] + 1;
// Parse the option specification
optionLetters = "";
optionNames.SetSize(0);
PIntArray canHaveOptionString;
PINDEX codeCount = 0;
while (*spec != '\0') {
if (*spec == '-')
optionLetters += ' ';
else
optionLetters += *spec++;
if (*spec == '-') {
const char * base = ++spec;
while (*spec != '\0' && *spec != '.' && *spec != ':' && *spec != ';')
spec++;
optionNames[codeCount] = PString(base, spec-base);
if (*spec == '.')
spec++;
}
if (*spec == ':' || *spec == ';') {
canHaveOptionString.SetSize(codeCount+1);
canHaveOptionString[codeCount] = *spec == ':' ? 2 : 1;
spec++;
}
codeCount++;
}
// Clear and reset size of option information
optionCount.SetSize(0);
optionCount.SetSize(codeCount);
optionString.SetSize(0);
optionString.SetSize(codeCount);
// Clear parameter indexes
parameterIndex.SetSize(0);
shift = 0;
// Now work through the arguments and split out the options
PINDEX param = 0;
PBoolean hadMinusMinus = PFalse;
while (arg < argumentArray.GetSize()) {
const PString & argStr = argumentArray[arg];
if (hadMinusMinus || argStr[0] != '-' || argStr[1] == '\0') {
// have a parameter string
parameterIndex.SetSize(param+1);
parameterIndex[param++] = arg;
}
else if (optionsBeforeParams && parameterIndex.GetSize() > 0)
break;
else if (argStr == "--") // ALL remaining args are parameters not options
hadMinusMinus = PTrue;
else if (argStr[1] == '-')
ParseOption(optionNames.GetValuesIndex(argStr.Mid(2)), 0, arg, canHaveOptionString);
else {
for (PINDEX i = 1; i < argStr.GetLength(); i++)
if (ParseOption(optionLetters.Find(argStr[i]), i+1, arg, canHaveOptionString))
break;
}
arg++;
}
return param > 0;
}
PBoolean PArgList::ParseOption(PINDEX idx, PINDEX offset, PINDEX & arg,
const PIntArray & canHaveOptionString)
{
if (idx == P_MAX_INDEX) {
UnknownOption(argumentArray[arg]);
return PFalse;
}
optionCount[idx]++;
if (canHaveOptionString[idx] == 0)
return PFalse;
if (!optionString[idx])
optionString[idx] += '\n';
if (offset != 0 &&
(canHaveOptionString[idx] == 1 || argumentArray[arg][offset] != '\0')) {
optionString[idx] += argumentArray[arg].Mid(offset);
return PTrue;
}
if (++arg >= argumentArray.GetSize())
return PFalse;
optionString[idx] += argumentArray[arg];
return PTrue;
}
PINDEX PArgList::GetOptionCount(char option) const
{
return GetOptionCountByIndex(optionLetters.Find(option));
}
PINDEX PArgList::GetOptionCount(const char * option) const
{
return GetOptionCountByIndex(optionNames.GetValuesIndex(PString(option)));
}
PINDEX PArgList::GetOptionCount(const PString & option) const
{
return GetOptionCountByIndex(optionNames.GetValuesIndex(option));
}
PINDEX PArgList::GetOptionCountByIndex(PINDEX idx) const
{
if (idx < optionCount.GetSize())
return optionCount[idx];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -