📄 osutils.cxx
字号:
#include <ctype.h>
class PSimpleThread : public PThread
{
PCLASSINFO(PSimpleThread, PThread);
public:
PSimpleThread(
const PNotifier & notifier,
INT parameter,
AutoDeleteFlag deletion,
Priority priorityLevel,
const PString & threadName,
PINDEX stackSize
);
void Main();
protected:
PNotifier callback;
INT parameter;
};
static PMutex * PTraceMutex = NULL;
#ifndef __NUCLEUS_PLUS__
static ostream * PErrorStream = &cerr;
#else
static ostream * PErrorStream = NULL;
#endif
ostream & PGetErrorStream()
{
return *PErrorStream;
}
void PSetErrorStream(ostream * s)
{
#ifndef __NUCLEUS_PLUS__
PErrorStream = s != NULL ? s : &cerr;
#else
PErrorStream = s;
#endif
}
//////////////////////////////////////////////////////////////////////////////
#if !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE)
static ostream * PTraceStream = &cerr;
#else
#ifdef __NUCLEUS_PLUS__
static ostream * PTraceStream = 0L;
#endif
#ifdef _WIN32_WCE
static YWinCEOStream * PTraceStream = &cerr;
#endif
#endif
static unsigned PTraceOptions = PTrace::FileAndLine;
static unsigned PTraceLevelThreshold = 0;
static unsigned PTraceBlockIndentLevel = 0;
static PTimeInterval ApplicationStartTick = PTimer::Tick();
void PTrace::SetStream(ostream * s)
{
#if !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE)
PTraceStream = s != NULL ? s : &cerr;
#else
#ifdef __NUCLEUS_PLUS__
PTraceStream = s;
#endif
#ifdef _WIN32_WCE
PTraceStream = &cerr;
#endif
#endif
}
void PTrace::Initialise(unsigned level, const char * filename, unsigned options)
{
#if PTRACING
PProcess & process = PProcess::Current();
#endif
// If we have a tracing version, then open trace file and set modes
PTraceOptions = options;
PTraceLevelThreshold = level;
if (filename != NULL) {
#if PMEMORY_CHECK
BOOL ignoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
#endif
PTextFile * traceOutput = new PTextFile(filename, PFile::WriteOnly);
#if PMEMORY_CHECK
PMemoryHeap::SetIgnoreAllocations(ignoreAllocations);
#endif
if (traceOutput->IsOpen())
PTrace::SetStream(traceOutput);
else {
PTRACE(0, process.GetName() << "Could not open trace output file \"" << filename << '"');
delete traceOutput;
}
}
PTRACE(1, process.GetName()
<< "\tVersion " << process.GetVersion(TRUE)
<< " by " << process.GetManufacturer()
<< " on " << process.GetOSClass() << ' ' << process.GetOSName()
<< " (" << process.GetOSVersion() << '-' << process.GetOSHardware()
<< ") at " << PTime().AsString("yyyy/M/d h:mm:ss.uuu"));
}
void PTrace::SetOptions(unsigned options)
{
PTraceOptions |= options;
}
void PTrace::ClearOptions(unsigned options)
{
PTraceOptions &= ~options;
}
unsigned PTrace::GetOptions()
{
return PTraceOptions;
}
void PTrace::SetLevel(unsigned level)
{
PTraceLevelThreshold = level;
}
unsigned PTrace::GetLevel()
{
return PTraceLevelThreshold;
}
BOOL PTrace::CanTrace(unsigned level)
{
return level <= PTraceLevelThreshold;
}
ostream & PTrace::Begin(unsigned level, const char * fileName, int lineNum)
{
if (PTraceMutex == NULL) {
// This flag must never be destroyed before it is finished with. As we
// cannot assure destruction at the right time we simply allocate it and
// NEVER destroy it! This is OK as the only reason for its destruction is
// the program is exiting and then who cares?
#if PMEMORY_CHECK
BOOL ignoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
#endif
PTraceMutex = new PMutex;
#if PMEMORY_CHECK
PMemoryHeap::SetIgnoreAllocations(ignoreAllocations);
#endif
}
PTraceMutex->Wait();
if (level == UINT_MAX)
return *PTraceStream;
if ((PTraceOptions&SystemLogStream) != 0) {
unsigned lvl = level+PSystemLog::Warning;
if (lvl >= PSystemLog::NumLogLevels)
lvl = PSystemLog::NumLogLevels-1;
((PSystemLog*)PTraceStream)->SetLevel((PSystemLog::Level)lvl);
}
else {
if ((PTraceOptions&DateAndTime) != 0) {
PTime now;
*PTraceStream << now.AsString("yyyy/MM/dd hh:mm:ss\t");
}
if ((PTraceOptions&Timestamp) != 0)
*PTraceStream << setprecision(3) << setw(10) << (PTimer::Tick()-ApplicationStartTick) << '\t';
if ((PTraceOptions&Thread) != 0) {
PThread * thread = PThread::Current();
if (thread == NULL)
*PTraceStream << setw(23) << "<<unknown>>";
else {
PString name = thread->GetThreadName();
if (name.GetLength() <= 23)
*PTraceStream << setw(23) << name;
else
*PTraceStream << name.Left(10) << "..." << name.Right(10);
}
*PTraceStream << '\t';
}
if ((PTraceOptions&ThreadAddress) != 0)
*PTraceStream << hex << setfill('0')
<< setw(7) << (unsigned)PThread::Current()
<< dec << setfill(' ') << '\t';
}
if ((PTraceOptions&TraceLevel) != 0)
*PTraceStream << level << '\t';
if ((PTraceOptions&FileAndLine) != 0 && fileName != NULL) {
const char * file = strrchr(fileName, '/');
if (file != NULL)
file++;
else {
file = strrchr(fileName, '\\');
if (file != NULL)
file++;
else
file = fileName;
}
*PTraceStream << setw(16) << file << '(' << lineNum << ")\t";
}
return *PTraceStream;
}
ostream & PTrace::End(ostream & s)
{
/* Only output if there is something to output, this prevents some blank trace
entries from appearing under some patholgical conditions. Unfortunately if
stderr is used the unitbuf flag causes the out_waiting() not to work so we
must suffer with blank lines in that case.
*/
if ((s.flags()&ios::unitbuf) != 0 || s.rdbuf()->out_waiting() > 0) {
if ((PTraceOptions&SystemLogStream) != 0)
s.flush();
else
s << endl;
}
PTraceMutex->Signal();
return s;
}
PTrace::Block::Block(const char * fileName, int lineNum, const char * traceName)
{
file = fileName;
line = lineNum;
name = traceName;
PTraceBlockIndentLevel += 2;
if ((PTraceOptions&Blocks) != 0) {
ostream & s = PTrace::Begin(1, file, line);
for (unsigned i = 0; i < PTraceBlockIndentLevel; i++)
s << '=';
s << "> " << name << PTrace::End;
}
}
PTrace::Block::~Block()
{
if ((PTraceOptions&Blocks) != 0) {
ostream & s = PTrace::Begin(1, file, line);
s << '<';
for (unsigned i = 0; i < PTraceBlockIndentLevel; i++)
s << '=';
s << ' ' << name << PTrace::End;
}
PTraceBlockIndentLevel -= 2;
}
///////////////////////////////////////////////////////////////////////////////
// PDirectory
void PDirectory::CloneContents(const PDirectory * d)
{
CopyContents(*d);
}
///////////////////////////////////////////////////////////////////////////////
// PTimer
PTimer::PTimer(long millisecs, int seconds, int minutes, int hours, int days)
: resetTime(millisecs, seconds, minutes, hours, days)
{
Construct();
}
PTimer::PTimer(const PTimeInterval & time)
: resetTime(time)
{
Construct();
}
void PTimer::Construct()
{
state = Stopped;
timerList = PProcess::Current().GetTimerList();
timerList->listMutex.Wait();
timerList->Append(this);
timerList->listMutex.Signal();
timerList->processingMutex.Wait();
StartRunning(TRUE);
}
PTimer & PTimer::operator=(DWORD milliseconds)
{
timerList->processingMutex.Wait();
resetTime.SetInterval(milliseconds);
StartRunning(oneshot);
return *this;
}
PTimer & PTimer::operator=(const PTimeInterval & time)
{
timerList->processingMutex.Wait();
resetTime = time;
StartRunning(oneshot);
return *this;
}
PTimer::~PTimer()
{
timerList->listMutex.Wait();
timerList->Remove(this);
timerList->listMutex.Signal();
timerList->inTimeoutMutex.Wait();
timerList->inTimeoutMutex.Signal();
}
void PTimer::RunContinuous(const PTimeInterval & time)
{
timerList->processingMutex.Wait();
resetTime = time;
StartRunning(FALSE);
}
void PTimer::StartRunning(BOOL once)
{
PTimeInterval::operator=(resetTime);
oneshot = once;
state = (*this) != 0 ? Starting : Stopped;
#if defined(P_PLATFORM_HAS_THREADS)
if (IsRunning())
PProcess::Current().SignalTimerChange();
#endif
// This must have been set by the caller
timerList->processingMutex.Signal();
}
void PTimer::Stop()
{
timerList->processingMutex.Wait();
state = Stopped;
SetInterval(0);
timerList->processingMutex.Signal();
}
void PTimer::Pause()
{
timerList->processingMutex.Wait();
if (IsRunning())
state = Paused;
timerList->processingMutex.Signal();
}
void PTimer::Resume()
{
timerList->processingMutex.Wait();
if (state == Paused)
state = Starting;
timerList->processingMutex.Signal();
}
void PTimer::Reset()
{
timerList->processingMutex.Wait();
StartRunning(oneshot);
}
void PTimer::OnTimeout()
{
if (!callback.IsNULL())
callback(*this, IsRunning());
}
void PTimer::Process(const PTimeInterval & delta, PTimeInterval & minTimeLeft)
{
/*Ideally there should be a processingMutex for each individual timer, but
that seems incredibly profligate of system resources as there can be a
LOT of PTimer instances about. So use one one mutex for all.
*/
timerList->processingMutex.Wait();
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) {
SetInterval(0);
state = Stopped;
}
else {
PTimeInterval::operator=(resetTime);
if (resetTime < minTimeLeft)
minTimeLeft = resetTime;
}
timerList->processingMutex.Signal();
/* 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;
}
timerList->processingMutex.Signal();
}
///////////////////////////////////////////////////////////////////////////////
// PTimerList
PTimerList::PTimerList()
{
DisallowDeleteObjects();
}
PTimeInterval PTimerList::Process()
{
PINDEX i;
PTimeInterval minTimeLeft = PMaxTimeInterval;
listMutex.Wait();
PTimeInterval now = PTimer::Tick();
PTimeInterval sampleTime;
if (lastSample == 0)
sampleTime = 0;
else {
sampleTime = now - lastSample;
if (now < lastSample)
sampleTime += PMaxTimeInterval;
}
lastSample = now;
for (i = 0; i < GetSize(); i++) {
PTimer & timer = (*this)[i];
inTimeoutMutex.Wait();
listMutex.Signal();
timer.Process(sampleTime, minTimeLeft);
listMutex.Wait();
inTimeoutMutex.Signal();
}
listMutex.Signal();
return minTimeLeft;
}
///////////////////////////////////////////////////////////////////////////////
// PArgList
PArgList::PArgList(const char * theArgStr,
const char * theArgumentSpec,
BOOL 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,
BOOL 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,
BOOL 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,
BOOL 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,
BOOL optionsBeforeParams)
{
// get the program name and path
SetArgs(theArgc, theArgv);
// we got an argument spec - so process them
Parse(theArgumentSpec, optionsBeforeParams);
}
void PArgList::SetArgs(const PString & argStr)
{
argumentArray.SetSize(0);
const char * str = argStr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -