📄 usersync.cpp
字号:
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
Thread *Platform::GetMainThread()
{
return ___pTheMainThread;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::AllocThreadKey()
{
for( int i=0; i<PI_MAXTHREADKEYS; i++ )
{
if ( !aUsedKeys[i] )
{
aUsedKeys[i] = 1;
return i;
};
};
PIERROR( PIAPI_EXHAUSTED );
return -1;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
bool Platform::DeleteThreadKey( int iKey )
{
if ( iKey<0 || iKey>=PI_MAXTHREADKEYS || !aUsedKeys[iKey] )
{
PIERROR( PIAPI_EINVAL );
return false;
};
aUsedKeys[iKey] = 0;
return true;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
void Platform::ThreadDbgDump( ostream &os )
{
DbgWriteAllThreads( os );
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::PollFD( int iFD, int iFlags, int iTimeout )
{
#if defined(CONFIG_OS_POSIX)
# if defined(CONFIG_OS_SOLARIS)
/*
** Solaris 2.x: man -s 3C select
**
** [File descriptors associated with regular files always select
** true for ready to read, ready to write, and error conditions.]
**
** NOTE:
** - What about pipes?
** - Also change other instances of this function
*/
/* so just return the requested status */
return iFlags;
# endif
return Platform::PollNetFD( iFD, iFlags, iTimeout );
#elif defined(CONFIG_OS_WIN32)
/* ---
Win32 SDK, says that WaitForSingleObject() can be used to
check if a file handle operation will succeed without blocking
'under certain circumstances' and is 'discouraged'. But there doesn't
seem to be another way to do this without side effects.
NOTE: The reason this is discouraged is because confusion can arise if
multiple waits exists for the the same handle, therefore its
suggested to use an event. Anyway.....
--- */
int iRetFlags = 0;
switch( ::WaitForSingleObject( (HANDLE)iFD, iTimeout*1000 ) )
{
case WAIT_FAILED:
PIOSERR;
return -1;
default:;
/* ---
Don't know what made the handle signalled so set the
return code based on what the callee requested. Files
are unidirectional anyway so this doesn't cause confusion
like it would with sockets
--- */
if ( iFlags & Platform::POLL_READ )
{ iRetFlags = iRetFlags | Platform::POLL_READ; };
if ( iFlags & Platform::POLL_WRITE )
{ iRetFlags = iRetFlags | Platform::POLL_WRITE; };
return iRetFlags;
};
#else
/*
** Return ready without yielding
*/
(void)iFD;
(void)iTimeout;
return iFlags;
#endif
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::PollPipeFD( int iFD, int iFlags, int iTimeout )
{
#if defined(CONFIG_OS_WIN32)
int iRetFlags = 0;
if ( iFlags & ~Platform::POLL_WRITE )
{
int iRet = Platform::PollFD( iFD, iFlags & ~Platform::POLL_WRITE,
iTimeout );
if ( iRet<0 )
{ return iRet; };
iRetFlags |= iRet;
};
/* ---
Named pipes on Win32. Always return 'Ready to Write'.
--- */
if ( iFlags & Platform::POLL_WRITE )
{ iRetFlags |= Platform::POLL_WRITE; };
return iRetFlags;
#endif
/*
** Otherwise behaviour is the same as Platform::PollFD
*/
return Platform::PollFD( iFD, iFlags, iTimeout );
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::PollNetFD( int iFD, int iFlags, int iTimeout )
{
if ( iFD<0 )
{
PIERROR( PIAPI_EINVAL );
return -1;
};
int iRet = PollInfo::Poll( ___pTheCurrentThread, iFD, iFlags,
(iTimeout==-1) ? -1 : (iTimeout * 1000) );
if ( iRet<=0 )
{ PIERROR(iRet); };
return iRet;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::Sleep( int iMilliseconds )
{
if ( iMilliseconds<0 )
{
PIERROR( PIAPI_EINVAL );
return -1;
};
int iRet = PollInfo::Poll( ___pTheCurrentThread, -1, 0, iMilliseconds );
if ( iRet!=0 )
{ PIERROR(iRet); };
return iRet;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
void Platform::CatchExceptions( void (* fn)( void *), void *pArg )
{
/* ---
It is an internal error for this function to be used on
threads other than the main thread
--- */
assert( ___pTheCurrentThread==___pTheMainThread );
assert( fn );
#if defined(CONFIG_CPP_EXCEPTIONS)
try {
(fn)( pArg );
}
catch( UserThread::StackUnwindException *pE )
{
PI_DELETE( pE );
}
catch( ... )
{
};
#else
if ( setjmp( ___pTheMainThread->tJmpBuf )==0 )
{ (fn)( pArg ); };
#endif
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::Read( int iFd, int iLength, void *pData )
{
assert( iFd!=-1 && iLength && pData );
if ( iFd==-1 || !iLength || !pData )
{
PIERROR( PIAPI_EINVAL );
return -1;
};
int iToRead = iLength;
int iRead;
for(; iToRead ;)
{
iRead = -1;
/* --- yield if necessary --- */
if ( Platform::PollFD( iFd, POLL_READ, -1 )<=0 )
{ break; };
#if defined(CONFIG_OS_POSIX)
iRead = ::read( iFd, pData, iLength );
if ( iRead==-1 && errno==EINTR )
{ continue; };
#elif defined(CONFIG_OS_WIN32)
/* ---
the cast from int * to DWORD * (DWORD is currrently unsigned long), is
not so bad because iLength is the maximum size that can be sent and
is also an int
--- */
if ( !::ReadFile( (HANDLE)iFd, pData, iLength, (DWORD *)&iRead,
0 ) )
{ iRead=-1; };
#endif
if ( !iRead || iRead==-1 )
{ break; };
iToRead -= iRead;
};
if ( iRead==-1 )
{
PIOSERR;
return PIAPI_ERROR;
};
return PIAPI_COMPLETED;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::Write( int iFd, int iLength, const void *pData )
{
assert( iFd!=-1 && iLength && pData );
if ( iFd==-1 || !iLength || !pData )
{
PIERROR( PIAPI_EINVAL );
return -1;
};
int iToWrite = iLength;
int iWritten;
for(; iToWrite ;)
{
iWritten = -1;
/* --- yield if necessary --- */
if ( Platform::PollFD( iFd, POLL_WRITE, -1 )<=0 )
{ break; };
#if defined(CONFIG_OS_POSIX)
iWritten = ::write( iFd, pData, iLength );
if ( iWritten==-1 && errno==EINTR )
{ continue; };
#elif defined(CONFIG_OS_WIN32)
/* ---
the cast from int * to DWORD * (DWORD is currrently unsigned long), is
not so bad because iLength is the maximum size that can be sent and
is also an int
--- */
if ( !::WriteFile( (HANDLE)iFd, pData, iLength, (DWORD *)&iWritten,
0 ) )
{ iWritten=-1; };
#endif
if ( !iWritten || iWritten==-1 )
{ break; };
iToWrite -= iWritten;
};
if ( iWritten==-1 )
{
PIOSERR;
return PIAPI_ERROR;
};
return PIAPI_COMPLETED;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::WriteAtomic( int iFd, int iLength, const void *pData )
{
assert( iFd!=-1 && iLength && pData );
if ( iFd==-1 || !iLength || !pData )
{
PIERROR( PIAPI_EINVAL );
return -1;
};
int iToWrite = iLength;
int iWritten;
/* --- yield until write is writtable --- */
if ( Platform::PollFD( iFd, POLL_WRITE, -1 )<=0 )
{ assert( 0 ); return PIAPI_ERROR; };
if ( Platform::LockFd( iFd )!=PIAPI_COMPLETED )
{
return PIAPI_ERROR;
};
for(; iToWrite ;)
{
iWritten = -1;
#if defined(CONFIG_OS_POSIX)
iWritten = ::write( iFd, pData, iLength );
if ( iWritten==-1 && errno==EINTR )
{ continue; };
#elif defined(CONFIG_OS_WIN32)
/* ---
the cast from int * to DWORD * (DWORD is currrently unsigned long), is
not so bad because iLength is the maximum size that can be sent and
is also an int
--- */
if ( !::WriteFile( (HANDLE)iFd, pData, iLength, (DWORD *)&iWritten,
0 ) )
{ iWritten=-1; };
#endif
if ( !iWritten || iWritten==-1 )
{ break; };
iToWrite -= iWritten;
};
iWritten = Platform::UnlockFd( iFd );
if ( iWritten!=PIAPI_COMPLETED )
{
PIOSERR;
return PIAPI_ERROR;
};
return PIAPI_COMPLETED;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
int Platform::WaitForProcess( int tProcess, int iFlags, int /* iTimeout */ )
{
(void)iFlags; /* not used */
#if defined(CONFIG_OS_POSIX)
for(;;)
{
int iRet = ::waitpid( tProcess, 0, WNOHANG );
#if !defined(CONFIG_NO_ERESTART)
if ( iRet==-1 && errno!=EINTR && errno!=ERESTART )
#else
if ( iRet==-1 && errno!=EINTR )
#endif
{
PIOSERR;
return PIAPI_ERROR;
};
if ( iRet==tProcess )
{ return PIAPI_COMPLETED; };
/* --- yield and try again --- */
Platform::YieldThread();
};
#elif defined(CONFIG_OS_WIN32)
for(;;)
{
DWORD dwWait=::WaitForSingleObject( (HANDLE)tProcess, 0 /* no wait */ );
switch( dwWait )
{
case WAIT_TIMEOUT:
/* --- yield and try again --- */
Platform::YieldThread(); // or yield timeslice
break;
case WAIT_OBJECT_0:
return PIAPI_COMPLETED;
case WAIT_FAILED:
PIOSERR;
return PIAPI_ERROR;
default:
/* how did we get here */
assert( 0 );
PIERROR( PIAPI_ERROR );
return PIAPI_ERROR;
};
};
#endif
(void)tProcess;
return PIAPI_NOTSUPPORTED;
}
/*___________________________________________________________________________*\
*
Function:
Synopsis: static, public:
Description:
\*___________________________________________________________________________*/
#if defined(CONFIG_LOCK_FLOCK)
# define PI_LOCK_BLOCK (LOCK_EX)
# define PI_LOCK_NOBLOCK (LOCK_EX | LOCK_NB)
#else
# define PI_LOCK_BLOCK (F_LOCK)
# define PI_LOCK_NOBLOCK (F_TLOCK)
#endif
int Platform::LockFd( int iFd )
{
assert( iFd!=-1 );
if ( iFd==-1 )
{
PIERROR( PIAPI_EINVAL );
return -1;
};
#if defined(CONFIG_OS_POSIX)
/* ---
Enter loop to obtain a lock on the file
--- */
int iFlags = PI_LOCK_NOBLOCK;
for(;;)
{
/* --- non-blocking call to flock --- */
#if defined(CONFIG_LOCK_FLOCK)
if ( ::flock( iFd, iFlags )==0 )
#else
if ( ::lockf( iFd, iFlags, 0 )==0 )
#endif
{
/* --- got the lock, continue --- */
break;
}
else if ( errno==EWOULDBLOCK || errno==EAGAIN )
{
/* ---
Another process has the lock, try to yield the thread.
If th
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -