Rework pjlib++

git-svn-id: https://svn.pjsip.org/repos/pjproject/main@36 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Benny Prijono 2005-11-09 15:37:19 +00:00
parent 0e64113b96
commit 85d3f45399
34 changed files with 3131 additions and 1189 deletions

View File

@ -0,0 +1,102 @@
# Microsoft Developer Studio Project File - Name="pjlib++_test" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=pjlib++_test - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "pjlib++-test.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "pjlib++-test.mak" CFG="pjlib++_test - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "pjlib++_test - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "pjlib++_test - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "pjlib++_test - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "./output/pjlib++-test-i386-win32-vc6-release"
# PROP BASE Intermediate_Dir "./output/pjlib++-test-i386-win32-vc6-release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "./output/pjlib++-test-i386-win32-vc6-release"
# PROP Intermediate_Dir "./output/pjlib++-test-i386-win32-vc6-release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib-util/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../bin/pjlib++-test-i386-win32-vc6-release.exe"
!ELSEIF "$(CFG)" == "pjlib++_test - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "./output/pjlib++-test-i386-win32-vc6-debug"
# PROP BASE Intermediate_Dir "./output/pjlib++-test-i386-win32-vc6-debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "./output/pjlib++-test-i386-win32-vc6-debug"
# PROP Intermediate_Dir "./output/pjlib++-test-i386-win32-vc6-debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib-util/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjlib++-test-i386-win32-vc6-debug.exe" /pdbtype:sept
!ENDIF
# Begin Target
# Name "pjlib++_test - Win32 Release"
# Name "pjlib++_test - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE="..\src\pjlib++-test\main.cpp"
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@ -1,24 +1,24 @@
# Microsoft Developer Studio Project File - Name="pjlibpp" - Package Owner=<4> # Microsoft Developer Studio Project File - Name="pjlib++" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00 # Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT ** # ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104 # TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=pjlibpp - Win32 Debug CFG=pjlib++ - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run !MESSAGE use the Export Makefile command and run
!MESSAGE !MESSAGE
!MESSAGE NMAKE /f "pjlibpp.mak". !MESSAGE NMAKE /f "pjlib++.mak".
!MESSAGE !MESSAGE
!MESSAGE You can specify a configuration when running NMAKE !MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE !MESSAGE
!MESSAGE NMAKE /f "pjlibpp.mak" CFG="pjlibpp - Win32 Debug" !MESSAGE NMAKE /f "pjlib++.mak" CFG="pjlib++ - Win32 Debug"
!MESSAGE !MESSAGE
!MESSAGE Possible choices for configuration are: !MESSAGE Possible choices for configuration are:
!MESSAGE !MESSAGE
!MESSAGE "pjlibpp - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "pjlib++ - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "pjlibpp - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE "pjlib++ - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE !MESSAGE
# Begin Project # Begin Project
@ -28,20 +28,20 @@ CFG=pjlibpp - Win32 Debug
CPP=cl.exe CPP=cl.exe
RSC=rc.exe RSC=rc.exe
!IF "$(CFG)" == "pjlibpp - Win32 Release" !IF "$(CFG)" == "pjlib++ - Win32 Release"
# PROP BASE Use_MFC 0 # PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0 # PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\output\pjlibpp-i386-win32-vc6-release" # PROP BASE Output_Dir ".\output\pjlib++-i386-win32-vc6-release"
# PROP BASE Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-release" # PROP BASE Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-release"
# PROP BASE Target_Dir "" # PROP BASE Target_Dir ""
# PROP Use_MFC 0 # PROP Use_MFC 0
# PROP Use_Debug_Libraries 0 # PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\output\pjlibpp-i386-win32-vc6-release" # PROP Output_Dir ".\output\pjlib++-i386-win32-vc6-release"
# PROP Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-release" # PROP Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "../src" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "PJ_WIN32" /D "PJ_M_I386" /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FD /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
@ -52,20 +52,20 @@ LIB32=link.exe -lib
# ADD BASE LIB32 /nologo # ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"../lib/pjlibp_vc6s.lib" # ADD LIB32 /nologo /out:"../lib/pjlibp_vc6s.lib"
!ELSEIF "$(CFG)" == "pjlibpp - Win32 Debug" !ELSEIF "$(CFG)" == "pjlib++ - Win32 Debug"
# PROP BASE Use_MFC 0 # PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1 # PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir ".\output\pjlibpp-i386-win32-vc6-debug" # PROP BASE Output_Dir ".\output\pjlib++-i386-win32-vc6-debug"
# PROP BASE Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-debug" # PROP BASE Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-debug"
# PROP BASE Target_Dir "" # PROP BASE Target_Dir ""
# PROP Use_MFC 0 # PROP Use_MFC 0
# PROP Use_Debug_Libraries 1 # PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\output\pjlibpp-i386-win32-vc6-debug" # PROP Output_Dir ".\output\pjlib++-i386-win32-vc6-debug"
# PROP Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-debug" # PROP Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../src" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "PJ_WIN32" /D "PJ_M_I386" /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
@ -80,78 +80,62 @@ LIB32=link.exe -lib
# Begin Target # Begin Target
# Name "pjlibpp - Win32 Release" # Name "pjlib++ - Win32 Release"
# Name "pjlibpp - Win32 Debug" # Name "pjlib++ - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE="..\src\pj++\compiletest.cpp"
# End Source File
# Begin Source File
SOURCE="..\src\pj++\pj++.cpp"
# End Source File
# Begin Source File
SOURCE="..\src\pj++\proactor.cpp"
# End Source File
# End Group
# Begin Group "Header Files" # Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl" # PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\hash.hpp" SOURCE="..\include\pj++\file.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\ioqueue.hpp" SOURCE="..\include\pj++\hash.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\list.hpp" SOURCE="..\include\pj++\list.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\os.hpp" SOURCE="..\include\pj++\lock.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pjlib++.hpp" SOURCE="..\include\pj++\os.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\pool.hpp" SOURCE="..\include\pj++\pool.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\proactor.hpp" SOURCE="..\include\pj++\proactor.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\scanner.hpp" SOURCE="..\include\pj++\scanner.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\sock.hpp" SOURCE="..\include\pj++\sock.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\string.hpp" SOURCE="..\include\pj++\string.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\timer.hpp" SOURCE="..\include\pj++\timer.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\tree.hpp" SOURCE="..\include\pj++\tree.hpp"
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE="..\src\pj++\types.hpp" SOURCE="..\include\pj++\types.hpp"
# End Source File # End Source File
# End Group # End Group
# End Target # End Target

View File

@ -234,6 +234,13 @@ SOURCE=..\src\pj\ioqueue_select.c
# Begin Source File # Begin Source File
SOURCE=..\src\pj\ioqueue_winnt.c SOURCE=..\src\pj\ioqueue_winnt.c
!IF "$(CFG)" == "pjlib - Win32 Release"
!ELSEIF "$(CFG)" == "pjlib - Win32 Debug"
!ENDIF
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -3,14 +3,10 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
############################################################################### ###############################################################################
Project: "pjlib"=".\pjlib.dsp" - Package Owner=<4> Project: "pjlib"=.\pjlib.dsp - Package Owner=<4>
Package=<5> Package=<5>
{{{ {{{
begin source code control
"$/pjproject-0.3/pjlib/build", EJDAAAAA
.
end source code control
}}} }}}
Package=<4> Package=<4>
@ -19,14 +15,22 @@ Package=<4>
############################################################################### ###############################################################################
Project: "pjlib_samples"=".\pjlib_samples.dsp" - Package Owner=<4> Project: "pjlib++"=".\pjlib++.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "pjlib_samples"=.\pjlib_samples.dsp - Package Owner=<4>
Package=<5> Package=<5>
{{{ {{{
begin source code control
"$/pjproject-0.3/pjlib/build", EJDAAAAA
.
end source code control
}}} }}}
Package=<4> Package=<4>
@ -38,14 +42,10 @@ Package=<4>
############################################################################### ###############################################################################
Project: "pjlib_test"=".\pjlib_test.dsp" - Package Owner=<4> Project: "pjlib_test"=.\pjlib_test.dsp - Package Owner=<4>
Package=<5> Package=<5>
{{{ {{{
begin source code control
"$/pjproject-0.3/pjlib/build", EJDAAAAA
.
end source code control
}}} }}}
Package=<4> Package=<4>
@ -57,18 +57,20 @@ Package=<4>
############################################################################### ###############################################################################
Project: "pjlibpp"=".\pjlibpp.dsp" - Package Owner=<4> Project: "pjlib++_test"=.\pjlib++-test.dsp - Package Owner=<4>
Package=<5> Package=<5>
{{{ {{{
begin source code control
"$/pjproject-0.3/pjlib/build", EJDAAAAA
.
end source code control
}}} }}}
Package=<4> Package=<4>
{{{ {{{
Begin Project Dependency
Project_Dep_Name pjlib
End Project Dependency
Begin Project Dependency
Project_Dep_Name pjlib++
End Project Dependency
}}} }}}
############################################################################### ###############################################################################
@ -77,10 +79,6 @@ Global:
Package=<5> Package=<5>
{{{ {{{
begin source code control
"$/pjproject-0.3/pjlib/build", EJDAAAAA
.
end source code control
}}} }}}
Package=<3> Package=<3>

171
pjlib/include/pj++/file.hpp Normal file
View File

@ -0,0 +1,171 @@
/* $Id$ */
#ifndef __PJPP_FILE_HPP__
#define __PJPP_FILE_HPP__
#include <pj/file_io.h>
#include <pj/file_access.h>
#include <pj++/types.hpp>
#include <pj++/pool.hpp>
//
// File API.
//
class Pj_File_API
{
public:
//
// Check file existance.
//
static bool file_exists(const char *filename)
{
return pj_file_exists(filename) != 0;
}
//
// Get file size.
//
static pj_off_t file_size(const char *filename)
{
return pj_file_size(filename);
}
//
// Delete file.
//
static pj_status_t file_delete(const char *filename)
{
return pj_file_delete(filename);
}
//
// Move/rename file.
//
static pj_status_t file_move(const char *oldname, const char *newname)
{
return pj_file_move(oldname, newname);
}
//
// Get stat.
//
static pj_status_t file_stat(const char *filename, pj_file_stat *buf)
{
return pj_file_getstat(filename, buf);
}
};
//
// File.
//
class Pj_File : public Pj_Object
{
public:
//
// Offset type to be used in setpos.
//
enum Offset_Type
{
SEEK_SET = PJ_SEEK_SET,
SEEK_CUR = PJ_SEEK_CUR,
SEEK_END = PJ_SEEK_END,
};
//
// Default constructor.
//
Pj_File()
: hnd_(0)
{
}
//
// Construct and open a file.
//
Pj_File(Pj_Pool *pool, const char *filename,
unsigned access = PJ_O_RDONLY)
: hnd_(NULL)
{
open(pool, filename, access);
}
//
// Destructor closes the file.
//
~Pj_File()
{
close();
}
//
// Open a file.
//
pj_status_t open(Pj_Pool *pool, const char *filename,
unsigned access = PJ_O_RDONLY )
{
close();
return pj_file_open(pool->pool_(), filename, access, &hnd_);
}
//
// Close a file.
//
void close()
{
if (hnd_ != 0) {
pj_file_close(hnd_);
hnd_ = 0;
}
}
//
// Write data.
//
pj_ssize_t write(const void *buff, pj_size_t size)
{
pj_ssize_t bytes = size;
if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS)
return -1;
return bytes;
}
//
// Read data.
//
pj_ssize_t read(void *buf, pj_size_t size)
{
pj_ssize_t bytes = size;
if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS)
return -1;
return bytes;
}
//
// Set file position.
//
pj_status_t setpos(pj_off_t offset, Offset_Type whence)
{
return pj_file_setpos(hnd_, offset,
(enum pj_file_seek_type)whence);
}
//
// Get file position.
//
pj_off_t getpos()
{
pj_off_t pos;
if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS)
return -1;
return pos;
}
private:
pj_oshandle_t hnd_;
};
#endif /* __PJPP_FILE_HPP__ */

View File

@ -1,73 +1,139 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_HASH_H__ #ifndef __PJPP_HASH_H__
#define __PJPP_HASH_H__ #define __PJPP_HASH_H__
#include <pj++/types.hpp> #include <pj++/types.hpp>
#include <pj++/pool.hpp>
#include <pj/hash.h> #include <pj/hash.h>
class PJ_Hash_Table //
// Hash table.
//
class Pj_Hash_Table : public Pj_Object
{ {
public: public:
//
// Hash table iterator.
//
class iterator class iterator
{ {
public: public:
iterator() {} iterator()
explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i) : ht_(h), it_(i) {} {
iterator(const iterator &rhs) : ht_(rhs.ht_), it_(rhs.it_) {} }
void operator++() { it_ = pj_hash_next(ht_, it_); } explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i)
bool operator==(const iterator &rhs) { return ht_ == rhs.ht_ && it_ == rhs.it_; } : ht_(h), it_(i)
iterator & operator=(const iterator &rhs) { ht_=rhs.ht_; it_=rhs.it_; return *this; } {
}
iterator(const iterator &rhs)
: ht_(rhs.ht_), it_(rhs.it_)
{
}
void operator++()
{
it_ = pj_hash_next(ht_, it_);
}
bool operator==(const iterator &rhs)
{
return ht_ == rhs.ht_ && it_ == rhs.it_;
}
iterator & operator=(const iterator &rhs)
{
ht_=rhs.ht_; it_=rhs.it_;
return *this;
}
private: private:
pj_hash_table_t *ht_; pj_hash_table_t *ht_;
pj_hash_iterator_t it_val_; pj_hash_iterator_t it_val_;
pj_hash_iterator_t *it_; pj_hash_iterator_t *it_;
friend class PJ_Hash_Table; friend class Pj_Hash_Table;
}; };
static PJ_Hash_Table *create(PJ_Pool *pool, unsigned size) //
// Construct hash table.
//
Pj_Hash_Table(Pj_Pool *pool, unsigned size)
{ {
return (PJ_Hash_Table*) pj_hash_create(pool->pool_(), size); table_ = pj_hash_create(pool->pool_(), size);
} }
static pj_uint32_t calc(pj_uint32_t initial_hval, const void *key, unsigned keylen) //
// Destroy hash table.
//
~Pj_Hash_Table()
{
}
//
// Calculate hash value.
//
static pj_uint32_t calc( pj_uint32_t initial_hval,
const void *key,
unsigned keylen = PJ_HASH_KEY_STRING)
{ {
return pj_hash_calc(initial_hval, key, keylen); return pj_hash_calc(initial_hval, key, keylen);
} }
pj_hash_table_t *hash_table_() //
// Return pjlib compatible hash table object.
//
pj_hash_table_t *pj_hash_table_t_()
{ {
return (pj_hash_table_t*)this; return table_;
} }
void *get(const void *key, unsigned keylen) //
// Get the value associated with the specified key.
//
void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING)
{ {
return pj_hash_get(this->hash_table_(), key, keylen); return pj_hash_get(table_, key, keylen);
} }
void set(PJ_Pool *pool, const void *key, unsigned keylen, void *value) //
// Associate a value with a key.
// Set the value to NULL to delete the key from the hash table.
//
void set(Pj_Pool *pool,
const void *key,
void *value,
unsigned keylen = PJ_HASH_KEY_STRING)
{ {
pj_hash_set(pool->pool_(), this->hash_table_(), key, keylen, value); pj_hash_set(pool->pool_(), table_, key, keylen, value);
} }
//
// Get number of items in the hash table.
//
unsigned count() unsigned count()
{ {
return pj_hash_count(this->hash_table_()); return pj_hash_count(table_);
} }
//
// Iterate hash table.
//
iterator begin() iterator begin()
{ {
iterator it(this->hash_table_(), NULL); iterator it(table_, NULL);
it.it_ = pj_hash_first(this->hash_table_(), &it.it_val_); it.it_ = pj_hash_first(table_, &it.it_val_);
return it; return it;
} }
//
// End of items.
//
iterator end() iterator end()
{ {
return iterator(this->hash_table_(), NULL); return iterator(table_, NULL);
} }
private:
pj_hash_table_t *table_;
}; };
#endif /* __PJPP_HASH_H__ */ #endif /* __PJPP_HASH_H__ */

View File

@ -1,174 +0,0 @@
/* $Id$
*
*/
#ifndef __PJPP_IOQUEUE_H__
#define __PJPP_IOQUEUE_H__
#include <pj++/sock.hpp>
#include <pj++/pool.hpp>
#include <pj++/types.hpp>
#include <pj/ioqueue.h>
class PJ_IOQueue;
class PJ_IOQueue_Event_Handler
{
public:
virtual ~PJ_IOQueue_Event_Handler()
{
}
pj_ioqueue_key_t* get_key() const
{
return key_;
}
protected:
//
// Override this to get notification from I/O Queue
//
virtual void on_read_complete(pj_ssize_t bytes_read)
{
}
virtual void on_write_complete(pj_ssize_t bytes_sent)
{
}
virtual void on_accept_complete(int status)
{
}
virtual void on_connect_complete(int status)
{
}
protected:
PJ_IOQueue_Event_Handler()
: ioqueue_(NULL), key_(NULL)
{
}
private:
PJ_IOQueue *ioqueue_;
pj_ioqueue_key_t *key_;
static void read_complete_cb(pj_ioqueue_key_t *key, pj_ssize_t bytes_read)
{
PJ_IOQueue_Event_Handler *handler =
(PJ_IOQueue_Event_Handler*)pj_ioqueue_get_user_data(key);
handler->on_read_complete(bytes_read);
}
static void write_complete_cb(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent);
static void accept_complete_cb(pj_ioqueue_key_t *key, int status);
static void connect_complete_cb(pj_ioqueue_key_t *key, int status);
friend class PJ_IOQueue;
};
class PJ_IOQueue
{
typedef pj_ioqueue_t *B_;
public:
typedef pj_ioqueue_key_t Key;
enum Operation
{
OP_NONE = PJ_IOQUEUE_OP_NONE,
OP_READ = PJ_IOQUEUE_OP_READ,
OP_RECV_FROM = PJ_IOQUEUE_OP_RECV_FROM,
OP_WRITE = PJ_IOQUEUE_OP_WRITE,
OP_SEND_TO = PJ_IOQUEUE_OP_SEND_TO,
#if PJ_HAS_TCP
OP_ACCEPT = PJ_IOQUEUE_OP_ACCEPT,
OP_CONNECT = PJ_IOQUEUE_OP_CONNECT,
#endif
};
enum Status
{
IS_PENDING = PJ_IOQUEUE_PENDING
};
static PJ_IOQueue *create(PJ_Pool *pool, pj_size_t max_fd)
{
return (PJ_IOQueue*) pj_ioqueue_create(pool->pool_(), max_fd);
}
operator B_()
{
return (pj_ioqueue_t*)(PJ_IOQueue*)this;
}
pj_ioqueue_t *ioq_()
{
return (B_)this;
}
void destroy()
{
pj_ioqueue_destroy(this->ioq_());
}
Key *register_handle(PJ_Pool *pool, pj_oshandle_t hnd, void *user_data)
{
return pj_ioqueue_register(pool->pool_(), this->ioq_(), hnd, user_data);
}
Key *register_socket(PJ_Pool *pool, pj_sock_t hnd, void *user_data)
{
return pj_ioqueue_register(pool->pool_(), this->ioq_(), (pj_oshandle_t)hnd, user_data);
}
pj_status_t unregister(Key *key)
{
return pj_ioqueue_unregister(this->ioq_(), key);
}
void *get_user_data(Key *key)
{
return pj_ioqueue_get_user_data(key);
}
int poll(Key **key, pj_ssize_t *bytes_status, Operation *op, const PJ_Time_Val *timeout)
{
return pj_ioqueue_poll(this->ioq_(), key, bytes_status, (pj_ioqueue_operation_e*)op, timeout);
}
#if PJ_HAS_TCP
pj_status_t connect(Key *key, const pj_sockaddr_t *addr, int addrlen)
{
return pj_ioqueue_connect(this->ioq_(), key, addr, addrlen);
}
pj_status_t accept(Key *key, PJ_Socket *sock, pj_sockaddr_t *local, pj_sockaddr_t *remote, int *addrlen)
{
return pj_ioqueue_accept(this->ioq_(), key, &sock->get_handle(), local, remote, addrlen);
}
#endif
int read(Key *key, void *buf, pj_size_t len)
{
return pj_ioqueue_read(this->ioq_(), key, buf, len);
}
int recvfrom(Key *key, void *buf, pj_size_t len, pj_sockaddr_t *addr, int *addrlen)
{
return pj_ioqueue_recvfrom(this->ioq_(), key, buf, len, addr, addrlen);
}
int write(Key *key, const void *data, pj_size_t len)
{
return pj_ioqueue_write(this->ioq_(), key, data, len);
}
int sendto(Key *key, const void *data, pj_size_t len, const pj_sockaddr_t *addr, int addrlen)
{
return pj_ioqueue_sendto(this->ioq_(), key, data, len, addr, addrlen);
}
};
#endif /* __PJPP_IOQUEUE_H__ */

View File

@ -1,164 +1,290 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_LIST_H__ #ifndef __PJPP_LIST_H__
#define __PJPP_LIST_H__ #define __PJPP_LIST_H__
#include <pj/list.h> #include <pj/list.h>
#include <pj++/pool.hpp>
template <typename T>
struct PJ_List_Node
{
PJ_DECL_LIST_MEMBER(T)
};
template <class Node> //
class PJ_List // Linked-list.
//
// Note:
// List_Node must have public member next and prev. Normally
// it will be declared like:
//
// struct my_node
// {
// PJ_DECL_LIST_MEMBER(struct my_node);
// ..
// };
//
//
template <class List_Node>
class Pj_List : public Pj_Object
{ {
public: public:
PJ_List() { pj_list_init(&root_); if (0) compiletest(); } //
~PJ_List() {} // List const_iterator.
//
class const_iterator class const_iterator
{ {
public: public:
const_iterator() : node_(NULL) {} const_iterator()
const_iterator(const Node *nd) : node_((Node*)nd) {} : node_(NULL)
const Node * operator *() { return node_; } {}
const Node * operator -> () { return node_; } const_iterator(const List_Node *nd)
const_iterator operator++() { return const_iterator(node_->next); } : node_((List_Node*)nd)
bool operator==(const const_iterator &rhs) { return node_ == rhs.node_; } {}
bool operator!=(const const_iterator &rhs) { return node_ != rhs.node_; } const List_Node * operator *()
{
return node_;
}
const List_Node * operator -> ()
{
return node_;
}
const_iterator operator++()
{
return const_iterator(node_->next);
}
bool operator==(const const_iterator &rhs)
{
return node_ == rhs.node_;
}
bool operator!=(const const_iterator &rhs)
{
return node_ != rhs.node_;
}
protected: protected:
Node *node_; List_Node *node_;
}; };
//
// List iterator.
//
class iterator : public const_iterator class iterator : public const_iterator
{ {
public: public:
iterator() {} iterator()
iterator(Node *nd) : const_iterator(nd) {} {}
Node * operator *() { return node_; } iterator(List_Node *nd)
Node * operator -> () { return node_; } : const_iterator(nd)
iterator operator++() { return iterator(node_->next); } {}
bool operator==(const iterator &rhs) { return node_ == rhs.node_; } List_Node * operator *()
bool operator!=(const iterator &rhs) { return node_ != rhs.node_; } {
return node_;
}
List_Node * operator -> ()
{
return node_;
}
iterator operator++()
{
return iterator(node_->next);
}
bool operator==(const iterator &rhs)
{
return node_ == rhs.node_;
}
bool operator!=(const iterator &rhs)
{
return node_ != rhs.node_;
}
}; };
//
// Default constructor.
//
Pj_List()
{
pj_list_init(&root_);
if (0) compiletest();
}
//
// Check if list is empty.
//
bool empty() const bool empty() const
{ {
return pj_list_empty(&root_); return pj_list_empty(&root_);
} }
//
// Get first element.
//
iterator begin() iterator begin()
{ {
return iterator(root_.next); return iterator(root_.next);
} }
//
// Get first element.
//
const_iterator begin() const const_iterator begin() const
{ {
return const_iterator(root_.next); return const_iterator(root_.next);
} }
//
// Get end-of-element
//
const_iterator end() const const_iterator end() const
{ {
return const_iterator((Node*)&root_); return const_iterator((List_Node*)&root_);
} }
//
// Get end-of-element
//
iterator end() iterator end()
{ {
return iterator((Node*)&root_); return iterator((List_Node*)&root_);
} }
void insert_before (iterator &pos, Node *node) //
// Insert node.
//
void insert_before (iterator &pos, List_Node *node)
{ {
pj_list_insert_before( *pos, node ); pj_list_insert_before( *pos, node );
} }
void insert_after(iterator &pos, Node *node) //
// Insert node.
//
void insert_after(iterator &pos, List_Node *node)
{ {
pj_list_insert_after(*pos, node); pj_list_insert_after(*pos, node);
} }
void merge_first(Node *list2) //
// Merge list.
//
void merge_first(List_Node *list2)
{ {
pj_list_merge_first(&root_, list2); pj_list_merge_first(&root_, list2);
} }
void merge_last(PJ_List *list) //
// Merge list.
//
void merge_last(Pj_List *list)
{ {
pj_list_merge_last(&root_, &list->root_); pj_list_merge_last(&root_, &list->root_);
} }
void insert_nodes_before(iterator &pos, PJ_List *list2) //
// Insert list.
//
void insert_nodes_before(iterator &pos, Pj_List *list2)
{ {
pj_list_insert_nodes_before(*pos, &list2->root_); pj_list_insert_nodes_before(*pos, &list2->root_);
} }
void insert_nodes_after(iterator &pos, PJ_List *list2) //
// Insert list.
//
void insert_nodes_after(iterator &pos, Pj_List *list2)
{ {
pj_list_insert_nodes_after(*pos, &list2->root_); pj_list_insert_nodes_after(*pos, &list2->root_);
} }
//
// Erase an element.
//
void erase(iterator &it) void erase(iterator &it)
{ {
pj_list_erase(*it); pj_list_erase(*it);
} }
Node *front() //
// Get first element.
//
List_Node *front()
{ {
return root_.next; return root_.next;
} }
const Node *front() const //
// Get first element.
//
const List_Node *front() const
{ {
return root_.next; return root_.next;
} }
//
// Remove first element.
//
void pop_front() void pop_front()
{ {
pj_list_erase(root_.next); pj_list_erase(root_.next);
} }
Node *back() //
// Get last element.
//
List_Node *back()
{ {
return root_.prev; return root_.prev;
} }
const Node *back() const //
// Get last element.
//
const List_Node *back() const
{ {
return root_.prev; return root_.prev;
} }
//
// Remove last element.
//
void pop_back() void pop_back()
{ {
pj_list_erase(root_.prev); pj_list_erase(root_.prev);
} }
iterator find(Node *node) //
// Find a node.
//
iterator find(List_Node *node)
{ {
Node *n = pj_list_find_node(&root_, node); List_Node *n = pj_list_find_node(&root_, node);
return n ? iterator(n) : end(); return n ? iterator(n) : end();
} }
const_iterator find(Node *node) const //
// Find a node.
//
const_iterator find(List_Node *node) const
{ {
Node *n = pj_list_find_node(&root_, node); List_Node *n = pj_list_find_node(&root_, node);
return n ? const_iterator(n) : end(); return n ? const_iterator(n) : end();
} }
void push_back(Node *node) //
// Insert a node in the back.
//
void push_back(List_Node *node)
{ {
pj_list_insert_after(root_.prev, node); pj_list_insert_after(root_.prev, node);
} }
void push_front(Node *node) //
// Insert a node in the front.
//
void push_front(List_Node *node)
{ {
pj_list_insert_before(root_.next, node); pj_list_insert_before(root_.next, node);
} }
//
// Remove all elements.
//
void clear() void clear()
{ {
root_.next = &root_; root_.next = &root_;
@ -168,14 +294,14 @@ public:
private: private:
struct RootNode struct RootNode
{ {
PJ_DECL_LIST_MEMBER(Node) PJ_DECL_LIST_MEMBER(List_Node);
} root_; } root_;
void compiletest() void compiletest()
{ {
// If you see error in this line, // If you see error in this line,
// it's because Node is not derived from PJ_List_Node. // it's because List_Node is not derived from Pj_List_Node.
Node *n = (Node*)0; List_Node *n = (List_Node*)0;
n = n->next; n = n->prev; n = n->next; n = n->prev;
} }
}; };

131
pjlib/include/pj++/lock.hpp Normal file
View File

@ -0,0 +1,131 @@
/* $Id$ */
#ifndef __PJPP_LOCK_H__
#define __PJPP_LOCK_H__
#include <pj++/types.hpp>
#include <pj/lock.h>
#include <pj++/pool.hpp>
//////////////////////////////////////////////////////////////////////////////
// Lock object.
//
class Pj_Lock : public Pj_Object
{
public:
//
// Constructor.
//
explicit Pj_Lock(pj_lock_t *lock)
: lock_(lock)
{
}
//
// Destructor.
//
~Pj_Lock()
{
if (lock_)
pj_lock_destroy(lock_);
}
//
// Get pjlib compatible lock object.
//
pj_lock_t *pj_lock_t_()
{
return lock_;
}
//
// acquire lock.
//
pj_status_t acquire()
{
return pj_lock_acquire(lock_);
}
//
// release lock,.
//
pj_status_t release()
{
return pj_lock_release(lock_);
}
protected:
pj_lock_t *lock_;
};
//////////////////////////////////////////////////////////////////////////////
// Null lock object.
//
class Pj_Null_Lock : public Pj_Lock
{
public:
//
// Default constructor.
//
explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL)
: Pj_Lock(NULL)
{
pj_lock_create_null_mutex(pool->pool_(), name, &lock_);
}
};
//////////////////////////////////////////////////////////////////////////////
// Simple mutex lock object.
//
class Pj_Simple_Mutex_Lock : public Pj_Lock
{
public:
//
// Default constructor.
//
explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)
: Pj_Lock(NULL)
{
pj_lock_create_simple_mutex(pool->pool_(), name, &lock_);
}
};
//////////////////////////////////////////////////////////////////////////////
// Recursive mutex lock object.
//
class Pj_Recursive_Mutex_Lock : public Pj_Lock
{
public:
//
// Default constructor.
//
explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)
: Pj_Lock(NULL)
{
pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_);
}
};
//////////////////////////////////////////////////////////////////////////////
// Semaphore lock object.
//
class Pj_Semaphore_Lock : public Pj_Lock
{
public:
//
// Default constructor.
//
explicit Pj_Semaphore_Lock(Pj_Pool *pool,
unsigned max=PJ_MAXINT32,
unsigned initial=0,
const char *name=NULL)
: Pj_Lock(NULL)
{
pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_);
}
};
#endif /* __PJPP_LOCK_H__ */

View File

@ -1,5 +1,4 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_OS_H__ #ifndef __PJPP_OS_H__
#define __PJPP_OS_H__ #define __PJPP_OS_H__
@ -8,7 +7,96 @@
#include <pj++/types.hpp> #include <pj++/types.hpp>
#include <pj++/pool.hpp> #include <pj++/pool.hpp>
class PJ_Thread class Pj_Thread;
//
// Thread API.
//
class Pj_Thread_API
{
public:
//
// Create a thread.
//
static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread,
pj_thread_proc *proc, void *arg,
unsigned flags = 0,
const char *name = NULL,
pj_size_t stack_size = 0 )
{
return pj_thread_create(pool->pool_(), name, proc, arg, stack_size,
flags, thread);
}
//
// Register a thread.
//
static pj_status_t register_this_thread( pj_thread_desc desc,
pj_thread_t **thread,
const char *name = NULL )
{
return pj_thread_register( name, desc, thread );
}
//
// Get current thread.
// Will return pj_thread_t (sorry folks, not Pj_Thread).
//
static pj_thread_t *this_thread()
{
return pj_thread_this();
}
//
// Get thread name.
//
static const char *get_name(pj_thread_t *thread)
{
return pj_thread_get_name(thread);
}
//
// Resume thread.
//
static pj_status_t resume(pj_thread_t *thread)
{
return pj_thread_resume(thread);
}
//
// Sleep.
//
static pj_status_t sleep(unsigned msec)
{
return pj_thread_sleep(msec);
}
//
// Join the specified thread.
//
static pj_status_t join(pj_thread_t *thread)
{
return pj_thread_join(thread);
}
//
// Destroy thread
//
static pj_status_t destroy(pj_thread_t *thread)
{
return pj_thread_destroy(thread);
}
};
//
// Thread object.
//
// How to use:
// Derive a class from this class, then override main().
//
class Pj_Thread : public Pj_Object
{ {
public: public:
enum Flags enum Flags
@ -16,134 +104,305 @@ public:
FLAG_SUSPENDED = PJ_THREAD_SUSPENDED FLAG_SUSPENDED = PJ_THREAD_SUSPENDED
}; };
static PJ_Thread *create( PJ_Pool *pool, const char *thread_name, //
pj_thread_proc *proc, void *arg, // Default constructor.
pj_size_t stack_size, void *stack_ptr, //
unsigned flags) Pj_Thread()
: thread_(NULL)
{ {
return (PJ_Thread*) pj_thread_create( pool->pool_(), thread_name, proc, arg, stack_size, stack_ptr, flags);
} }
static PJ_Thread *register_current_thread(const char *name, pj_thread_desc desc) //
// Destroy thread.
//
~Pj_Thread()
{ {
return (PJ_Thread*) pj_thread_register(name, desc); destroy();
} }
static PJ_Thread *get_current_thread() //
// This is the main thread function.
//
virtual int main() = 0;
//
// Start a thread.
//
pj_status_t create( Pj_Pool *pool,
unsigned flags = 0,
const char *thread_name = NULL,
pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE)
{ {
return (PJ_Thread*) pj_thread_this(); destroy();
} return Pj_Thread_API::create( pool, &thread_, &thread_proc, this,
flags, thread_name);
static pj_status_t sleep(unsigned msec)
{
return pj_thread_sleep(msec);
}
static pj_status_t usleep(unsigned usec)
{
return pj_thread_usleep(usec);
} }
//
// Get pjlib compatible thread object.
//
pj_thread_t *pj_thread_t_() pj_thread_t *pj_thread_t_()
{ {
return (pj_thread_t*)this; return thread_;
} }
//
// Get thread name.
//
const char *get_name() const char *get_name()
{ {
return pj_thread_get_name( this->pj_thread_t_() ); return Pj_Thread_API::get_name(thread_);
} }
//
// Resume a suspended thread.
//
pj_status_t resume() pj_status_t resume()
{ {
return pj_thread_resume( this->pj_thread_t_() ); return Pj_Thread_API::resume(thread_);
} }
//
// Join this thread.
//
pj_status_t join() pj_status_t join()
{ {
return pj_thread_join( this->pj_thread_t_() ); return Pj_Thread_API::join(thread_);
} }
//
// Destroy thread.
//
pj_status_t destroy() pj_status_t destroy()
{ {
return pj_thread_destroy( this->pj_thread_t_() ); if (thread_) {
Pj_Thread_API::destroy(thread_);
thread_ = NULL;
}
}
protected:
pj_thread_t *thread_;
static int PJ_THREAD_FUNC thread_proc(void *obj)
{
Pj_Thread *thread_class = (Pj_Thread*)obj;
return thread_class->main();
} }
}; };
class PJ_Thread_Local //
// External Thread
// (threads that were started by external means, i.e. not
// with Pj_Thread::create).
//
// This class will normally be defined as local variable in
// external thread's stack, normally inside thread's main proc.
// But be aware that the handle will be destroyed on destructor!
//
class Pj_External_Thread : public Pj_Thread
{ {
public: public:
static PJ_Thread_Local *alloc() Pj_External_Thread()
{ {
long index = pj_thread_local_alloc();
return index < 0 ? NULL : (PJ_Thread_Local*)index;
}
void free()
{
pj_thread_local_free( this->tls_() );
} }
long tls_() const //
// Register external thread so that pjlib functions can work
// in that thread.
//
pj_status_t register_this_thread( const char *name=NULL )
{ {
return (long)this; return Pj_Thread_API::register_this_thread(desc_, &thread_,name);
} }
void set(void *value) private:
{ pj_thread_desc desc_;
pj_thread_local_set( this->tls_(), value );
}
void *get()
{
return pj_thread_local_get( this->tls_() );
}
}; };
class PJ_Atomic //
// Thread specific data/thread local storage/TLS.
//
class Pj_Thread_Local_API
{ {
public: public:
static PJ_Atomic *create(PJ_Pool *pool, long initial) //
// Allocate thread local storage (TLS) index.
//
static pj_status_t alloc(long *index)
{ {
return (PJ_Atomic*) pj_atomic_create(pool->pool_(), initial); return pj_thread_local_alloc(index);
} }
//
// Free TLS index.
//
static void free(long index)
{
pj_thread_local_free(index);
}
//
// Set thread specific data.
//
static pj_status_t set(long index, void *value)
{
return pj_thread_local_set(index, value);
}
//
// Get thread specific data.
//
static void *get(long index)
{
return pj_thread_local_get(index);
}
};
//
// Atomic variable
//
// How to use:
// Pj_Atomic_Var var(pool, 0);
// var.set(..);
//
class Pj_Atomic_Var : public Pj_Object
{
public:
//
// Default constructor, initialize variable with NULL.
//
Pj_Atomic_Var()
: var_(NULL)
{
}
//
// Construct atomic variable.
//
Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value)
: var_(NULL)
{
create(pool, value);
}
//
// Destructor.
//
~Pj_Atomic_Var()
{
destroy();
}
//
// Create atomic variable.
//
pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value)
{
destroy();
return pj_atomic_create(pool->pool_(), value, &var_);
}
//
// Destroy.
//
void destroy()
{
if (var_) {
pj_atomic_destroy(var_);
var_ = NULL;
}
}
//
// Get pjlib compatible atomic variable.
//
pj_atomic_t *pj_atomic_t_() pj_atomic_t *pj_atomic_t_()
{ {
return (pj_atomic_t*)this; return var_;
} }
pj_status_t destroy() //
// Set the value.
//
void set(pj_atomic_value_t val)
{ {
return pj_atomic_destroy( this->pj_atomic_t_() ); pj_atomic_set(var_, val);
} }
long set(long val) //
// Get the value.
//
pj_atomic_value_t get()
{ {
return pj_atomic_set( this->pj_atomic_t_(), val); return pj_atomic_get(var_);
} }
long get() //
// Increment.
//
void inc()
{ {
return pj_atomic_get( this->pj_atomic_t_() ); pj_atomic_inc(var_);
} }
long inc() //
// Increment and get the result.
//
pj_atomic_value_t inc_and_get()
{ {
return pj_atomic_inc( this->pj_atomic_t_() ); return pj_atomic_inc_and_get(var_);
} }
long dec() //
// Decrement.
//
void dec()
{ {
return pj_atomic_dec( this->pj_atomic_t_() ); pj_atomic_dec(var_);
} }
//
// Decrement and get the result.
//
pj_atomic_value_t dec_and_get()
{
return pj_atomic_dec_and_get(var_);
}
//
// Add the variable.
//
void add(pj_atomic_value_t value)
{
pj_atomic_add(var_, value);
}
//
// Add the variable and get the value.
//
pj_atomic_value_t add_and_get(pj_atomic_value_t value)
{
return pj_atomic_add_and_get(var_, value );
}
private:
pj_atomic_t *var_;
}; };
class PJ_Mutex //
// Mutex
//
class Pj_Mutex : public Pj_Object
{ {
public: public:
//
// Mutex type.
//
enum Type enum Type
{ {
DEFAULT = PJ_MUTEX_DEFAULT, DEFAULT = PJ_MUTEX_DEFAULT,
@ -151,194 +410,378 @@ public:
RECURSE = PJ_MUTEX_RECURSE, RECURSE = PJ_MUTEX_RECURSE,
}; };
static PJ_Mutex *create( PJ_Pool *pool, const char *name, Type type) //
// Default constructor will create default mutex.
//
explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT,
const char *name = NULL)
: mutex_(NULL)
{ {
return (PJ_Mutex*) pj_mutex_create( pool->pool_(), name, type); create(pool, type, name);
} }
pj_mutex_t *pj_mutex_() //
// Destructor.
//
~Pj_Mutex()
{ {
return (pj_mutex_t*)this; destroy();
} }
pj_status_t destroy() //
// Create mutex.
//
pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL)
{ {
return pj_mutex_destroy( this->pj_mutex_() ); destroy();
return pj_mutex_create( pool->pool_(), name, type,
&mutex_ );
} }
pj_status_t lock() //
// Create simple mutex.
//
pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL)
{ {
return pj_mutex_lock( this->pj_mutex_() ); return create(pool, SIMPLE, name);
} }
pj_status_t unlock() //
// Create recursive mutex.
//
pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL )
{ {
return pj_mutex_unlock( this->pj_mutex_() ); return create(pool, RECURSE, name);
} }
pj_status_t trylock() //
// Get pjlib compatible mutex object.
//
pj_mutex_t *pj_mutex_t_()
{ {
return pj_mutex_trylock( this->pj_mutex_() ); return mutex_;
} }
#if PJ_DEBUG //
pj_status_t is_locked() // Destroy mutex.
//
void destroy()
{ {
return pj_mutex_is_locked( this->pj_mutex_() ); if (mutex_) {
pj_mutex_destroy(mutex_);
mutex_ = NULL;
}
} }
#endif
//
// Lock mutex.
//
pj_status_t acquire()
{
return pj_mutex_lock(mutex_);
}
//
// Unlock mutex.
//
pj_status_t release()
{
return pj_mutex_unlock(mutex_);
}
//
// Try locking the mutex.
//
pj_status_t tryacquire()
{
return pj_mutex_trylock(mutex_);
}
private:
pj_mutex_t *mutex_;
}; };
class PJ_Semaphore //
// Semaphore
//
class Pj_Semaphore : public Pj_Object
{ {
public: public:
static PJ_Semaphore *create( PJ_Pool *pool, const char *name, unsigned initial, unsigned max) //
// Construct semaphore
//
Pj_Semaphore(Pj_Pool *pool, unsigned max,
unsigned initial = 0, const char *name = NULL)
: sem_(NULL)
{ {
return (PJ_Semaphore*) pj_sem_create( pool->pool_(), name, initial, max);
} }
//
// Destructor.
//
~Pj_Semaphore()
{
destroy();
}
//
// Create semaphore
//
pj_status_t create( Pj_Pool *pool, unsigned max,
unsigned initial = 0, const char *name = NULL )
{
destroy();
return pj_sem_create( pool->pool_(), name, initial, max, &sem_);
}
//
// Destroy semaphore.
//
void destroy()
{
if (sem_) {
pj_sem_destroy(sem_);
sem_ = NULL;
}
}
//
// Get pjlib compatible semaphore object.
//
pj_sem_t *pj_sem_t_() pj_sem_t *pj_sem_t_()
{ {
return (pj_sem_t*)this; return (pj_sem_t*)this;
} }
pj_status_t destroy() //
{ // Wait semaphore.
return pj_sem_destroy(this->pj_sem_t_()); //
}
pj_status_t wait() pj_status_t wait()
{ {
return pj_sem_wait(this->pj_sem_t_()); return pj_sem_wait(this->pj_sem_t_());
} }
pj_status_t lock() //
// Wait semaphore.
//
pj_status_t acquire()
{ {
return wait(); return wait();
} }
//
// Try wait semaphore.
//
pj_status_t trywait() pj_status_t trywait()
{ {
return pj_sem_trywait(this->pj_sem_t_()); return pj_sem_trywait(this->pj_sem_t_());
} }
pj_status_t trylock() //
// Try wait semaphore.
//
pj_status_t tryacquire()
{ {
return trywait(); return trywait();
} }
//
// Post semaphore.
//
pj_status_t post() pj_status_t post()
{ {
return pj_sem_post(this->pj_sem_t_()); return pj_sem_post(this->pj_sem_t_());
} }
pj_status_t unlock() //
// Post semaphore.
//
pj_status_t release()
{ {
return post(); return post();
} }
private:
pj_sem_t *sem_;
}; };
class PJ_Event //
// Event object.
//
class Pj_Event
{ {
public: public:
static PJ_Event *create( PJ_Pool *pool, const char *name, bool manual_reset, bool initial) //
// Construct event object.
//
Pj_Event( Pj_Pool *pool, bool manual_reset = false,
bool initial = false, const char *name = NULL )
: event_(NULL)
{ {
return (PJ_Event*) pj_event_create(pool->pool_(), name, manual_reset, initial); create(pool, manual_reset, initial, name);
} }
//
// Destructor.
//
~Pj_Event()
{
destroy();
}
//
// Create event object.
//
pj_status_t create( Pj_Pool *pool, bool manual_reset = false,
bool initial = false, const char *name = NULL)
{
destroy();
return pj_event_create(pool->pool_(), name, manual_reset, initial,
&event_);
}
//
// Get pjlib compatible event object.
//
pj_event_t *pj_event_t_() pj_event_t *pj_event_t_()
{ {
return (pj_event_t*)this; return event_;
} }
pj_status_t destroy() //
// Destroy event object.
//
void destroy()
{ {
return pj_event_destroy(this->pj_event_t_()); if (event_) {
pj_event_destroy(event_);
event_ = NULL;
}
} }
//
// Wait.
//
pj_status_t wait() pj_status_t wait()
{ {
return pj_event_wait(this->pj_event_t_()); return pj_event_wait(event_);
} }
//
// Try wait.
//
pj_status_t trywait() pj_status_t trywait()
{ {
return pj_event_trywait(this->pj_event_t_()); return pj_event_trywait(event_);
} }
//
// Set event state to signalled.
//
pj_status_t set() pj_status_t set()
{ {
return pj_event_set(this->pj_event_t_()); return pj_event_set(this->pj_event_t_());
} }
//
// Release one waiting thread.
//
pj_status_t pulse() pj_status_t pulse()
{ {
return pj_event_pulse(this->pj_event_t_()); return pj_event_pulse(this->pj_event_t_());
} }
//
// Set a non-signalled.
//
pj_status_t reset() pj_status_t reset()
{ {
return pj_event_reset(this->pj_event_t_()); return pj_event_reset(this->pj_event_t_());
} }
private:
pj_event_t *event_;
}; };
class PJ_OS //
// OS abstraction.
//
class Pj_OS_API
{ {
public: public:
static pj_status_t gettimeofday( PJ_Time_Val *tv ) //
// Get current time.
//
static pj_status_t gettimeofday( Pj_Time_Val *tv )
{ {
return pj_gettimeofday(tv); return pj_gettimeofday(tv);
} }
static pj_status_t time_decode( const PJ_Time_Val *tv, pj_parsed_time *pt ) //
// Parse to time of day.
//
static pj_status_t time_decode( const Pj_Time_Val *tv,
pj_parsed_time *pt )
{ {
return pj_time_decode(tv, pt); return pj_time_decode(tv, pt);
} }
static pj_status_t time_encode(const pj_parsed_time *pt, PJ_Time_Val *tv) //
// Parse from time of day.
//
static pj_status_t time_encode( const pj_parsed_time *pt,
Pj_Time_Val *tv)
{ {
return pj_time_encode(pt, tv); return pj_time_encode(pt, tv);
} }
static pj_status_t time_local_to_gmt( PJ_Time_Val *tv ) //
// Convert to GMT.
//
static pj_status_t time_local_to_gmt( Pj_Time_Val *tv )
{ {
return pj_time_local_to_gmt( tv ); return pj_time_local_to_gmt( tv );
} }
static pj_status_t time_gmt_to_local( PJ_Time_Val *tv) //
// Convert time to local.
//
static pj_status_t time_gmt_to_local( Pj_Time_Val *tv)
{ {
return pj_time_gmt_to_local( tv ); return pj_time_gmt_to_local( tv );
} }
}; };
//
inline pj_status_t PJ_Time_Val::gettimeofday() // Timeval inlines.
//
inline pj_status_t Pj_Time_Val::gettimeofday()
{ {
return PJ_OS::gettimeofday(this); return Pj_OS_API::gettimeofday(this);
} }
inline pj_parsed_time PJ_Time_Val::decode() inline pj_parsed_time Pj_Time_Val::decode()
{ {
pj_parsed_time pt; pj_parsed_time pt;
PJ_OS::time_decode(this, &pt); Pj_OS_API::time_decode(this, &pt);
return pt; return pt;
} }
inline pj_status_t PJ_Time_Val::encode(const pj_parsed_time *pt) inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt)
{ {
return PJ_OS::time_encode(pt, this); return Pj_OS_API::time_encode(pt, this);
} }
inline pj_status_t PJ_Time_Val::to_gmt() inline pj_status_t Pj_Time_Val::to_gmt()
{ {
return PJ_OS::time_local_to_gmt(this); return Pj_OS_API::time_local_to_gmt(this);
} }
inline pj_status_t PJ_Time_Val::to_local() inline pj_status_t Pj_Time_Val::to_local()
{ {
return PJ_OS::time_gmt_to_local(this); return Pj_OS_API::time_gmt_to_local(this);
} }
#endif /* __PJPP_OS_H__ */ #endif /* __PJPP_OS_H__ */

View File

@ -1,86 +1,244 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_POOL_H__ #ifndef __PJPP_POOL_H__
#define __PJPP_POOL_H__ #define __PJPP_POOL_H__
#include <pj/pool.h> #include <pj/pool.h>
class PJ_Pool class Pj_Pool;
class Pj_Caching_Pool;
//
// Base class for all Pjlib objects
//
class Pj_Object
{ {
public: public:
const char *getobjname() const void *operator new(unsigned int class_size, Pj_Pool *pool);
{ void operator delete(void*);
return pj_pool_getobjname(this->pool_()); void operator delete(void*, Pj_Pool*);
}
pj_pool_t *pool_() //
{ // Inline implementations at the end of this file.
return (pj_pool_t*)this; //
}
const pj_pool_t *pool_() const private:
{ // Can not use normal new operator; must use pool.
return (const pj_pool_t*)this; // e.g.:
} // obj = new(pool) Pj_The_Object(pool, ...);
//
void release() void *operator new(unsigned int)
{ {}
pj_pool_release(this->pool_());
}
void reset()
{
pj_pool_reset(this->pool_());
}
pj_size_t get_capacity()
{
pj_pool_get_capacity(this->pool_());
}
pj_size_t get_used_size()
{
pj_pool_get_used_size(this->pool_());
}
void *alloc(pj_size_t size)
{
return pj_pool_alloc(this->pool_(), size);
}
void *calloc(pj_size_t count, pj_size_t elem)
{
return pj_pool_calloc(this->pool_(), count, elem);
}
}; };
class PJ_Caching_Pool
//
// Pool.
//
class Pj_Pool : public Pj_Object
{ {
public: public:
void init(pj_size_t max_capacity, //
const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy) // Default constructor, initializes internal pool to NULL.
// Application must call attach() some time later.
//
Pj_Pool()
: p_(NULL)
{ {
pj_caching_pool_init(&cp_, pol, max_capacity);
} }
void destroy() //
// Create pool.
//
Pj_Pool(Pj_Caching_Pool &caching_pool,
pj_size_t initial_size,
pj_size_t increment_size,
const char *name = NULL,
pj_pool_callback *callback = NULL);
//
// Construct from existing pool.
//
explicit Pj_Pool(pj_pool_t *pool)
: p_(pool)
{
}
//
// Attach existing pool.
//
void attach(pj_pool_t *pool)
{
p_ = pool;
}
//
// Destructor.
//
// Release pool back to factory. Remember: if you delete pool, then
// make sure that all objects that have been allocated from this pool
// have been properly destroyed.
//
// This is where C++ is trickier than plain C!!
//
~Pj_Pool()
{
if (p_)
pj_pool_release(p_);
}
//
// Get name.
//
const char *getobjname() const
{
return pj_pool_getobjname(p_);
}
//
// Get pjlib compatible pool object.
//
pj_pool_t *pool_()
{
return p_;
}
//
// Get pjlib compatible pool object.
//
const pj_pool_t *pool_() const
{
return p_;
}
//
// Get pjlib compatible pool object.
//
pj_pool_t *pj_pool_t_()
{
return p_;
}
//
// Reset pool.
//
void reset()
{
pj_pool_reset(p_);
}
//
// Get current capacity.
//
pj_size_t get_capacity()
{
pj_pool_get_capacity(p_);
}
//
// Get current total bytes allocated from the pool.
//
pj_size_t get_used_size()
{
pj_pool_get_used_size(p_);
}
//
// Allocate.
//
void *alloc(pj_size_t size)
{
return pj_pool_alloc(p_, size);
}
//
// Allocate elements and zero fill the memory.
//
void *calloc(pj_size_t count, pj_size_t elem)
{
return pj_pool_calloc(p_, count, elem);
}
//
// Allocate and zero fill memory.
//
void *zalloc(pj_size_t size)
{
return pj_pool_zalloc(p_, size);
}
private:
pj_pool_t *p_;
};
//
// Caching pool.
//
class Pj_Caching_Pool
{
public:
//
// Construct caching pool.
//
Pj_Caching_Pool( pj_size_t cache_capacity = 0,
const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy)
{
pj_caching_pool_init(&cp_, pol, cache_capacity);
}
//
// Destroy caching pool.
//
~Pj_Caching_Pool()
{ {
pj_caching_pool_destroy(&cp_); pj_caching_pool_destroy(&cp_);
} }
PJ_Pool *create_pool(const char *name, pj_size_t initial_size, pj_size_t increment_size, pj_pool_callback *callback) //
// Create pool.
//
pj_pool_t *create_pool( pj_size_t initial_size,
pj_size_t increment_size,
const char *name = NULL,
pj_pool_callback *callback = NULL)
{ {
return (PJ_Pool*) (*cp_.factory.create_pool)(&cp_.factory, name, initial_size, increment_size, callback); return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name,
} initial_size,
increment_size,
void release_pool( PJ_Pool *pool ) callback);
{
pj_pool_release(pool->pool_());
} }
private: private:
pj_caching_pool cp_; pj_caching_pool cp_;
}; };
//
// Inlines for Pj_Object
//
inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool)
{
return pool->alloc(class_size);
}
inline void Pj_Object::operator delete(void *ptr)
{
}
inline void Pj_Object::operator delete(void *ptr, Pj_Pool*)
{
}
//
// Inlines for Pj_Pool
//
inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool,
pj_size_t initial_size,
pj_size_t increment_size,
const char *name,
pj_pool_callback *callback)
{
p_ = caching_pool.create_pool(initial_size, increment_size, name,
callback);
}
#endif /* __PJPP_POOL_H__ */ #endif /* __PJPP_POOL_H__ */

View File

@ -1,88 +1,481 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_EVENT_HANDLER_H__ #ifndef __PJPP_PROACTOR_H__
#define __PJPP_EVENT_HANDLER_H__ #define __PJPP_PROACTOR_H__
#include <pj/ioqueue.h> #include <pj/ioqueue.h>
#include <pj++/pool.hpp> #include <pj++/pool.hpp>
#include <pj++/sock.hpp> #include <pj++/sock.hpp>
#include <pj++/timer.hpp> #include <pj++/timer.hpp>
#include <pj/errno.h>
class PJ_Proactor; class Pj_Proactor;
class Pj_Event_Handler;
class PJ_Event_Handler //////////////////////////////////////////////////////////////////////////////
// Asynchronous operation key.
//
// Applications may inheric this class to put their application
// specific data.
//
class Pj_Async_Op : public pj_ioqueue_op_key_t
{ {
friend class PJ_Proactor;
public: public:
PJ_Event_Handler(); //
virtual ~PJ_Event_Handler(); // Constructor.
//
explicit Pj_Async_Op(Pj_Event_Handler *handler)
: handler_(handler)
{
pj_memset(this, 0, sizeof(pj_ioqueue_op_key_t));
}
virtual pj_oshandle_t get_handle() = 0; //
// Check whether operation is still pending for this key.
//
bool is_pending();
//
// Cancel the operation.
//
bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED);
protected:
Pj_Event_Handler *handler_;
};
//////////////////////////////////////////////////////////////////////////////
// Event handler.
//
// Applications should inherit this class to receive various event
// notifications.
//
// Applications should implement get_socket_handle().
//
class Pj_Event_Handler : public Pj_Object
{
friend class Pj_Proactor;
public:
//
// Default constructor.
//
Pj_Event_Handler()
: key_(NULL)
{
pj_memset(&timer_, 0, sizeof(timer_));
timer_.user_data = this;
timer_.cb = &timer_callback;
}
//
// Destroy.
//
virtual ~Pj_Event_Handler()
{
unregister();
}
//
// Unregister this handler from the ioqueue.
//
void unregister()
{
if (key_) {
pj_ioqueue_unregister(key_);
key_ = NULL;
}
}
//
// Get socket handle associated with this.
//
virtual pj_sock_t get_socket_handle()
{
return PJ_INVALID_SOCKET;
}
//
// Receive data.
//
pj_status_t recv( Pj_Async_Op *op_key,
void *buf, pj_ssize_t *len,
unsigned flags)
{
return pj_ioqueue_recv( key_, op_key,
buf, len, flags);
}
//
// Recvfrom()
//
pj_status_t recvfrom( Pj_Async_Op *op_key,
void *buf, pj_ssize_t *len, unsigned flags,
Pj_Inet_Addr *addr)
{
addr->addrlen_ = sizeof(Pj_Inet_Addr);
return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags,
addr, &addr->addrlen_ );
}
//
// send()
//
pj_status_t send( Pj_Async_Op *op_key,
const void *data, pj_ssize_t *len,
unsigned flags)
{
return pj_ioqueue_send( key_, op_key, data, len, flags);
}
//
// sendto()
//
pj_status_t sendto( Pj_Async_Op *op_key,
const void *data, pj_ssize_t *len, unsigned flags,
const Pj_Inet_Addr &addr)
{
return pj_ioqueue_sendto(key_, op_key, data, len, flags,
&addr, sizeof(addr));
}
bool read(void *buf, pj_size_t len);
bool recvfrom(void *buf, pj_size_t len, PJ_INET_Addr *addr);
bool write(const void *data, pj_size_t len);
bool sendto(const void *data, pj_size_t len, const PJ_INET_Addr &addr);
#if PJ_HAS_TCP #if PJ_HAS_TCP
bool connect(const PJ_INET_Addr &addr); //
bool accept(PJ_Socket *sock, PJ_INET_Addr *local=NULL, PJ_INET_Addr *remote=NULL); // connect()
//
pj_status_t connect(const Pj_Inet_Addr &addr)
{
return pj_ioqueue_connect(key_, &addr, sizeof(addr));
}
//
// accept.
//
pj_status_t accept( Pj_Async_Op *op_key,
Pj_Socket *sock,
Pj_Inet_Addr *local = NULL,
Pj_Inet_Addr *remote = NULL)
{
int *addrlen = local ? &local->addrlen_ : NULL;
return pj_ioqueue_accept( key_, op_key, &sock->sock_,
local, remote, addrlen );
}
#endif #endif
protected: protected:
// //////////////////
// Overridables // Overridables
//////////////////
// //
virtual void on_timeout(int data) {} // Timeout callback.
virtual void on_read_complete(pj_ssize_t bytes_read) {} //
virtual void on_write_complete(pj_ssize_t bytes_sent) {} virtual void on_timeout(int data)
{
}
//
// On read complete callback.
//
virtual void on_read_complete( Pj_Async_Op *op_key,
pj_ssize_t bytes_read)
{
}
//
// On write complete callback.
//
virtual void on_write_complete( Pj_Async_Op *op_key,
pj_ssize_t bytes_sent)
{
}
#if PJ_HAS_TCP #if PJ_HAS_TCP
virtual void on_connect_complete(int status) {} //
virtual void on_accept_complete(int status) {} // On connect complete callback.
//
virtual void on_connect_complete(pj_status_t status)
{
}
//
// On new connection callback.
//
virtual void on_accept_complete( Pj_Async_Op *op_key,
pj_sock_t new_sock,
pj_status_t status)
{
}
#endif #endif
private: private:
PJ_Proactor *proactor_;
pj_ioqueue_key_t *key_; pj_ioqueue_key_t *key_;
pj_timer_entry timer_; pj_timer_entry timer_;
int tmp_recvfrom_addr_len;
public: friend class Pj_Proactor;
// Internal IO Queue/timer callback. friend class Pj_Async_Op;
static void timer_callback( pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry);
static void read_complete_cb(pj_ioqueue_key_t *key, pj_ssize_t bytes_read); //
static void write_complete_cb(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent); // Static timer callback.
static void accept_complete_cb(pj_ioqueue_key_t *key, int status); //
static void connect_complete_cb(pj_ioqueue_key_t *key, int status); static void timer_callback( pj_timer_heap_t *timer_heap,
struct pj_timer_entry *entry)
{
Pj_Event_Handler *handler =
(Pj_Event_Handler*) entry->user_data;
handler->on_timeout(entry->id);
}
}; };
class PJ_Proactor inline bool Pj_Async_Op::is_pending()
{
return pj_ioqueue_is_pending(handler_->key_, this) != 0;
}
inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status)
{
return pj_ioqueue_post_completion(handler_->key_, this,
bytes_status) == PJ_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////////
// Proactor
//
class Pj_Proactor : public Pj_Object
{ {
public: public:
static PJ_Proactor *create(PJ_Pool *pool, pj_size_t max_fd, //
pj_size_t timer_entry_count, unsigned timer_flags=0); // Default constructor, initializes to NULL.
//
Pj_Proactor()
: ioq_(NULL), th_(NULL)
{
cb_.on_read_complete = &read_complete_cb;
cb_.on_write_complete = &write_complete_cb;
cb_.on_accept_complete = &accept_complete_cb;
cb_.on_connect_complete = &connect_complete_cb;
}
void destroy(); //
// Construct proactor.
//
Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd,
pj_size_t max_timer_entries )
: ioq_(NULL), th_(NULL)
{
cb_.on_read_complete = &read_complete_cb;
cb_.on_write_complete = &write_complete_cb;
cb_.on_accept_complete = &accept_complete_cb;
cb_.on_connect_complete = &connect_complete_cb;
}
bool register_handler(PJ_Pool *pool, PJ_Event_Handler *handler); //
void unregister_handler(PJ_Event_Handler *handler); // Destructor.
//
~Pj_Proactor()
{
destroy();
}
static bool schedule_timer( pj_timer_heap_t *timer, PJ_Event_Handler *handler, //
const PJ_Time_Val &delay, int id=-1); // Create proactor.
bool schedule_timer(PJ_Event_Handler *handler, const PJ_Time_Val &delay, int id=-1); //
bool cancel_timer(PJ_Event_Handler *handler); pj_status_t create( Pj_Pool *pool, pj_size_t max_fd,
pj_size_t timer_entry_count)
{
pj_status_t status;
bool handle_events(PJ_Time_Val *timeout); destroy();
pj_ioqueue_t *get_io_queue(); status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_);
pj_timer_heap_t *get_timer_heap(); if (status != PJ_SUCCESS)
return status;
status = pj_timer_heap_create(pool->pool_(),
timer_entry_count, &th_);
if (status != PJ_SUCCESS) {
pj_ioqueue_destroy(ioq_);
ioq_ = NULL;
return NULL;
}
status;
}
//
// Destroy proactor.
//
void destroy()
{
if (ioq_) {
pj_ioqueue_destroy(ioq_);
ioq_ = NULL;
}
if (th_) {
pj_timer_heap_destroy(th_);
th_ = NULL;
}
}
//
// Register handler.
// This will call handler->get_socket_handle()
//
pj_status_t register_socket_handler(Pj_Pool *pool,
Pj_Event_Handler *handler)
{
return pj_ioqueue_register_sock( pool->pool_(), ioq_,
handler->get_socket_handle(),
handler, &cb_, &handler->key_ );
}
//
// Unregister handler.
//
static void unregister_handler(Pj_Event_Handler *handler)
{
if (handler->key_) {
pj_ioqueue_unregister( handler->key_ );
handler->key_ = NULL;
}
}
//
// Scheduler timer.
//
bool schedule_timer( Pj_Event_Handler *handler,
const Pj_Time_Val &delay,
int id=-1)
{
return schedule_timer(th_, handler, delay, id);
}
//
// Cancel timer.
//
bool cancel_timer(Pj_Event_Handler *handler)
{
return pj_timer_heap_cancel(th_, &handler->timer_) == 1;
}
//
// Handle events.
//
int handle_events(Pj_Time_Val *max_timeout)
{
Pj_Time_Val timeout(0, 0);
int timer_count;
timer_count = pj_timer_heap_poll( th_, &timeout );
if (timeout.get_sec() < 0)
timeout.sec = PJ_MAXINT32;
/* If caller specifies maximum time to wait, then compare the value
* with the timeout to wait from timer, and use the minimum value.
*/
if (max_timeout && timeout >= *max_timeout) {
timeout = *max_timeout;
}
/* Poll events in ioqueue. */
int ioqueue_count;
ioqueue_count = pj_ioqueue_poll(ioq_, &timeout);
if (ioqueue_count < 0)
return ioqueue_count;
return ioqueue_count + timer_count;
}
//
// Get the internal ioqueue object.
//
pj_ioqueue_t *get_io_queue()
{
return ioq_;
}
//
// Get the internal timer heap object.
//
pj_timer_heap_t *get_timer_heap()
{
return th_;
}
private: private:
pj_ioqueue_t *ioq_; pj_ioqueue_t *ioq_;
pj_timer_heap_t *th_; pj_timer_heap_t *th_;
pj_ioqueue_callback cb_;
static bool schedule_timer( pj_timer_heap_t *timer,
Pj_Event_Handler *handler,
const Pj_Time_Val &delay,
int id=-1)
{
handler->timer_.id = id;
return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0;
}
//
// Static read completion callback.
//
static void read_complete_cb( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_read)
{
Pj_Event_Handler *handler =
(Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read);
}
//
// Static write completion callback.
//
static void write_complete_cb(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_sent)
{
Pj_Event_Handler *handler =
(Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent);
}
//
// Static accept completion callback.
//
static void accept_complete_cb(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_sock_t new_sock,
pj_status_t status)
{
Pj_Event_Handler *handler =
(Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status);
}
//
// Static connect completion callback.
//
static void connect_complete_cb(pj_ioqueue_key_t *key,
pj_status_t status)
{
Pj_Event_Handler *handler =
(Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_connect_complete(status);
}
PJ_Proactor() {}
}; };
#endif /* __PJPP_EVENT_HANDLER_H__ */ #endif /* __PJPP_PROACTOR_H__ */

View File

@ -4,13 +4,13 @@
#ifndef __PJPP_SCANNER_H__ #ifndef __PJPP_SCANNER_H__
#define __PJPP_SCANNER_H__ #define __PJPP_SCANNER_H__
#include <pj/scanner.h> #include <pjlib-util/scanner.h>
#include <pj++/string.hpp> #include <pj++/string.hpp>
class PJ_CharSpec class Pj_Char_Spec
{ {
public: public:
PJ_CharSpec() { pj_cs_init(cs__); } Pj_Char_Spec() { pj_cs_init(cs__); }
void set(int c) { pj_cs_set(cs__, c); } void set(int c) { pj_cs_set(cs__, c); }
void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); } void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); }
@ -36,10 +36,10 @@ private:
pj_char_spec cs__; pj_char_spec cs__;
}; };
class PJ_Scanner class Pj_Scanner
{ {
public: public:
PJ_Scanner() {} Pj_Scanner() {}
enum enum
{ {
@ -67,30 +67,30 @@ public:
int peek_char() const int peek_char() const
{ {
return *scanner_.current; return *scanner_.curptr;
} }
int peek(const PJ_CharSpec *cs, PJ_String *out) int peek(const Pj_Char_Spec *cs, Pj_String *out)
{ {
return pj_scan_peek(&scanner_, cs->cs_(), out); return pj_scan_peek(&scanner_, cs->cs_(), out);
} }
int peek_n(pj_size_t len, PJ_String *out) int peek_n(pj_size_t len, Pj_String *out)
{ {
return pj_scan_peek_n(&scanner_, len, out); return pj_scan_peek_n(&scanner_, len, out);
} }
int peek_until(const PJ_CharSpec *cs, PJ_String *out) int peek_until(const Pj_Char_Spec *cs, Pj_String *out)
{ {
return pj_scan_peek_until(&scanner_, cs->cs_(), out); return pj_scan_peek_until(&scanner_, cs->cs_(), out);
} }
void get(const PJ_CharSpec *cs, PJ_String *out) void get(const Pj_Char_Spec *cs, Pj_String *out)
{ {
pj_scan_get(&scanner_, cs->cs_(), out); pj_scan_get(&scanner_, cs->cs_(), out);
} }
void get_n(unsigned N, PJ_String *out) void get_n(unsigned N, Pj_String *out)
{ {
pj_scan_get_n(&scanner_, N, out); pj_scan_get_n(&scanner_, N, out);
} }
@ -100,7 +100,7 @@ public:
return pj_scan_get_char(&scanner_); return pj_scan_get_char(&scanner_);
} }
void get_quote(int begin_quote, int end_quote, PJ_String *out) void get_quote(int begin_quote, int end_quote, Pj_String *out)
{ {
pj_scan_get_quote(&scanner_, begin_quote, end_quote, out); pj_scan_get_quote(&scanner_, begin_quote, end_quote, out);
} }
@ -110,17 +110,17 @@ public:
pj_scan_get_newline(&scanner_); pj_scan_get_newline(&scanner_);
} }
void get_until(const PJ_CharSpec *cs, PJ_String *out) void get_until(const Pj_Char_Spec *cs, Pj_String *out)
{ {
pj_scan_get_until(&scanner_, cs->cs_(), out); pj_scan_get_until(&scanner_, cs->cs_(), out);
} }
void get_until_ch(int until_ch, PJ_String *out) void get_until_ch(int until_ch, Pj_String *out)
{ {
pj_scan_get_until_ch(&scanner_, until_ch, out); pj_scan_get_until_ch(&scanner_, until_ch, out);
} }
void get_until_chr(const char *spec, PJ_String *out) void get_until_chr(const char *spec, Pj_String *out)
{ {
pj_scan_get_until_chr(&scanner_, spec, out); pj_scan_get_until_chr(&scanner_, spec, out);
} }

View File

@ -1,196 +1,426 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_SOCK_H__ #ifndef __PJPP_SOCK_H__
#define __PJPP_SOCK_H__ #define __PJPP_SOCK_H__
#include <pj/sock.h> #include <pj/sock.h>
#include <pj/string.h>
class PJ_Addr class Pj_Event_Handler;
//
// Base class for address.
//
class Pj_Addr
{ {
}; };
class PJ_INET_Addr : public pj_sockaddr_in, public PJ_Addr //
// Internet address.
//
class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr
{ {
public: public:
//
// Get port number.
//
pj_uint16_t get_port_number() const pj_uint16_t get_port_number() const
{ {
return pj_sockaddr_get_port(this); return pj_sockaddr_in_get_port(this);
} }
//
// Set port number.
//
void set_port_number(pj_uint16_t port) void set_port_number(pj_uint16_t port)
{ {
sin_family = PJ_AF_INET; sin_family = PJ_AF_INET;
pj_sockaddr_set_port(this, port); pj_sockaddr_in_set_port(this, port);
} }
//
// Get IP address.
//
pj_uint32_t get_ip_address() const pj_uint32_t get_ip_address() const
{ {
return pj_sockaddr_get_addr(this); return pj_sockaddr_in_get_addr(this).s_addr;
} }
//
// Get address string.
//
const char *get_address() const const char *get_address() const
{ {
return pj_sockaddr_get_str_addr(this); return pj_inet_ntoa(sin_addr);
} }
//
// Set IP address.
//
void set_ip_address(pj_uint32_t addr) void set_ip_address(pj_uint32_t addr)
{ {
sin_family = PJ_AF_INET; sin_family = PJ_AF_INET;
pj_sockaddr_set_addr(this, addr); pj_sockaddr_in_set_addr(this, addr);
} }
//
// Set address.
//
pj_status_t set_address(const pj_str_t *addr) pj_status_t set_address(const pj_str_t *addr)
{ {
return pj_sockaddr_set_str_addr(this, addr); return pj_sockaddr_in_set_str_addr(this, addr);
} }
//
// Set address.
//
pj_status_t set_address(const char *addr) pj_status_t set_address(const char *addr)
{ {
return pj_sockaddr_set_str_addr2(this, addr); pj_str_t s;
return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr));
} }
int cmp(const PJ_INET_Addr &rhs) const //
// Compare for equality.
//
bool operator==(const Pj_Inet_Addr &rhs) const
{ {
return pj_sockaddr_cmp(this, &rhs); return sin_family == rhs.sin_family &&
sin_addr.s_addr == rhs.sin_addr.s_addr &&
sin_port == rhs.sin_port;
} }
bool operator==(const PJ_INET_Addr &rhs) const private:
{ //
return cmp(rhs) == 0; // Dummy length used in pj_ioqueue_recvfrom() etc
} //
friend class Pj_Event_Handler;
friend class Pj_Socket;
friend class Pj_Sock_Stream;
friend class Pj_Sock_Dgram;
int addrlen_;
}; };
class PJ_Socket
//
// Socket base class.
//
// Note:
// socket will not automatically be closed on destructor.
//
class Pj_Socket
{ {
public: public:
PJ_Socket() {} //
PJ_Socket(const PJ_Socket &rhs) : sock_(rhs.sock_) {} // Default constructor.
//
Pj_Socket()
: sock_(PJ_INVALID_SOCKET)
{
}
//
// Initialize from a socket handle.
//
explicit Pj_Socket(pj_sock_t sock)
: sock_(sock)
{
}
//
// Copy constructor.
//
Pj_Socket(const Pj_Socket &rhs)
: sock_(rhs.sock_)
{
}
//
// Destructor will not close the socket.
// You must call close() explicitly.
//
~Pj_Socket()
{
}
//
// Set socket handle.
//
void set_handle(pj_sock_t sock) void set_handle(pj_sock_t sock)
{ {
sock_ = sock; sock_ = sock;
} }
//
// Get socket handle.
//
pj_sock_t get_handle() const pj_sock_t get_handle() const
{ {
return sock_; return sock_;
} }
//
// Get socket handle.
//
pj_sock_t& get_handle() pj_sock_t& get_handle()
{ {
return sock_; return sock_;
} }
bool socket(int af, int type, int proto, pj_uint32_t flag=0) //
// See if the socket is valid.
//
bool is_valid() const
{ {
sock_ = pj_sock_socket(af, type, proto, flag); return sock_ != PJ_INVALID_SOCKET;
return sock_ != -1;
} }
bool bind(const PJ_INET_Addr &addr) //
// Create the socket.
//
pj_status_t create(int af, int type, int proto)
{ {
return pj_sock_bind(sock_, &addr, sizeof(PJ_INET_Addr)) == 0; return pj_sock_socket(af, type, proto, &sock_);
} }
bool close() //
// Bind socket.
//
pj_status_t bind(const Pj_Inet_Addr &addr)
{ {
return pj_sock_close(sock_) == 0; return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr));
} }
bool getpeername(PJ_INET_Addr *addr) //
// Close socket.
//
pj_status_t close()
{ {
int namelen; pj_sock_close(sock_);
return pj_sock_getpeername(sock_, addr, &namelen) == 0;
} }
bool getsockname(PJ_INET_Addr *addr) //
// Get peer socket name.
//
pj_status_t getpeername(Pj_Inet_Addr *addr)
{ {
int namelen; return pj_sock_getpeername(sock_, addr, &addr->addrlen_);
return pj_sock_getsockname(sock_, addr, &namelen) == 0;
} }
bool getsockopt(int level, int optname, void *optval, int *optlen) //
// getsockname
//
pj_status_t getsockname(Pj_Inet_Addr *addr)
{ {
return pj_sock_getsockopt(sock_, level, optname, optval, optlen) == 0; return pj_sock_getsockname(sock_, addr, &addr->addrlen_);
} }
bool setsockopt(int level, int optname, const void *optval, int optlen) //
// getsockopt.
//
pj_status_t getsockopt(int level, int optname,
void *optval, int *optlen)
{ {
return pj_sock_setsockopt(sock_, level, optname, optval, optlen) == 0; return pj_sock_getsockopt(sock_, level, optname, optval, optlen);
} }
bool ioctl(long cmd, pj_uint32_t *val) //
// setsockopt
//
pj_status_t setsockopt(int level, int optname,
const void *optval, int optlen)
{ {
return pj_sock_ioctl(sock_, cmd, val) == 0; return pj_sock_setsockopt(sock_, level, optname, optval, optlen);
} }
int recv(void *buf, int len, int flag = 0) //
// receive data.
//
pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0)
{ {
return pj_sock_recv(sock_, buf, len, flag); pj_ssize_t bytes = len;
if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS)
return -1;
return bytes;
} }
int send(const void *buf, int len, int flag = 0) //
// send data.
//
pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0)
{ {
return pj_sock_send(sock_, buf, len, flag); pj_ssize_t bytes = len;
if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS)
return -1;
return bytes;
}
//
// connect.
//
pj_status_t connect(const Pj_Inet_Addr &addr)
{
return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr));
}
//
// assignment.
//
Pj_Socket &operator=(const Pj_Socket &rhs)
{
sock_ = rhs.sock_;
return *this;
} }
protected: protected:
friend class Pj_Event_Handler;
pj_sock_t sock_; pj_sock_t sock_;
}; };
#if PJ_HAS_TCP #if PJ_HAS_TCP
class PJ_Sock_Stream : public PJ_Socket //
// Stream socket.
//
class Pj_Sock_Stream : public Pj_Socket
{ {
public: public:
PJ_Sock_Stream() {} //
PJ_Sock_Stream(const PJ_Sock_Stream &rhs) : PJ_Socket(rhs) {} // Default constructor.
PJ_Sock_Stream &operator=(const PJ_Sock_Stream &rhs) { sock_ = rhs.sock_; return *this; } //
Pj_Sock_Stream()
bool listen(int backlog = 5)
{ {
return pj_sock_listen(sock_, backlog) == 0;
} }
bool accept(PJ_Sock_Stream *new_sock, PJ_INET_Addr *addr, int *addrlen) //
// Initialize from a socket handle.
//
explicit Pj_Sock_Stream(pj_sock_t sock)
: Pj_Socket(sock)
{ {
pj_sock_t s = pj_sock_accept(sock_, addr, addrlen);
if (s == -1)
return false;
new_sock->set_handle(s);
return true;
} }
bool connect(const PJ_INET_Addr &addr) //
// Copy constructor.
//
Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs)
{ {
return pj_sock_connect(sock_, &addr, sizeof(PJ_INET_Addr)) == 0;
} }
bool shutdown(int how) //
// Assignment.
//
Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs)
{
sock_ = rhs.sock_;
return *this;
}
//
// listen()
//
pj_status_t listen(int backlog = 5)
{ {
return pj_sock_shutdown(sock_, how) == 0; return pj_sock_listen(sock_, backlog);
}
//
// blocking accept()
//
Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL)
{
pj_sock_t newsock;
int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL;
pj_status_t status;
status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen);
if (status != PJ_SUCCESS)
return Pj_Sock_Stream(-1);
return Pj_Sock_Stream(newsock);
}
//
// shutdown()
//
pj_status_t shutdown(int how = PJ_SHUT_RDWR)
{
return pj_sock_shutdown(sock_, how);
} }
}; };
#endif #endif
class PJ_Sock_Dgram : public PJ_Socket //
// Datagram socket.
//
class Pj_Sock_Dgram : public Pj_Socket
{ {
public: public:
PJ_Sock_Dgram() {} //
PJ_Sock_Dgram(const PJ_Sock_Dgram &rhs) : PJ_Socket(rhs) {} // Default constructor.
PJ_Sock_Dgram &operator=(const PJ_Sock_Dgram &rhs) { sock_ = rhs.sock_; return *this; } //
Pj_Sock_Dgram()
int recvfrom(void *buf, int len, int flag, PJ_INET_Addr *fromaddr)
{ {
int addrlen;
return pj_sock_recvfrom(sock_, buf, len, flag, fromaddr, &addrlen);
} }
int sendto(const void *buf, int len, int flag, const PJ_INET_Addr &addr) //
// Initialize from a socket handle.
//
explicit Pj_Sock_Dgram(pj_sock_t sock)
: Pj_Socket(sock)
{ {
return pj_sock_sendto(sock_, buf, len, flag, &addr, sizeof(PJ_INET_Addr)); }
//
// Copy constructor.
//
Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs)
: Pj_Socket(rhs)
{
}
//
// Assignment.
//
Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs)
{
Pj_Socket::operator =(rhs);
return *this;
}
//
// recvfrom()
//
pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0,
Pj_Inet_Addr *fromaddr = NULL)
{
pj_ssize_t bytes = len;
int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL;
if (pj_sock_recvfrom( sock_, buf, &bytes, flag,
fromaddr, addrlen) != PJ_SUCCESS)
{
return -1;
}
return bytes;
}
//
// sendto()
//
pj_ssize_t sendto( const void *buf, pj_size_t len, int flag,
const Pj_Inet_Addr &addr)
{
pj_ssize_t bytes = len;
if (pj_sock_sendto( sock_, buf, &bytes, flag,
&addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS)
{
return -1;
}
return bytes;
} }
}; };
#endif /* __PJPP_SOCK_H__ */ #endif /* __PJPP_SOCK_H__ */

View File

@ -1,249 +1,408 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_STRING_H__ #ifndef __PJPP_STRING_H__
#define __PJPP_STRING_H__ #define __PJPP_STRING_H__
#include <pj/string.h> #include <pj/string.h>
#include <pj++/pool.hpp> #include <pj++/pool.hpp>
#include <pj/assert.h>
class PJ_String : public pj_str_t //
// String wrapper class for pj_str_t.
//
class Pj_String : public pj_str_t
{ {
public: public:
PJ_String() //
// Default constructor.
//
Pj_String()
{ {
pj_assert(sizeof(PJ_String) == sizeof(pj_str_t)); pj_assert(sizeof(Pj_String) == sizeof(pj_str_t));
ptr=NULL; slen=0; ptr=NULL;
slen=0;
} }
explicit PJ_String(char *str) //
// Construct the buffer from a char*.
//
explicit Pj_String(char *str)
{ {
set(str); set(str);
} }
PJ_String(PJ_Pool *pool, const char *src) //
// Construct from a const char*.
//
Pj_String(Pj_Pool *pool, const char *src)
{ {
set(pool, src); set(pool, src);
} }
explicit PJ_String(pj_str_t *s) //
// Construct from pj_str_t*.
//
explicit Pj_String(pj_str_t *s)
{ {
set(s); set(s);
} }
PJ_String(PJ_Pool *pool, const pj_str_t *s) //
// Construct by copying from const pj_str_t*.
//
Pj_String(Pj_Pool *pool, const pj_str_t *s)
{ {
set(pool, s); set(pool, s);
} }
explicit PJ_String(PJ_String &rhs) //
// Construct from another Pj_String
//
explicit Pj_String(Pj_String &rhs)
{ {
set(rhs); set(rhs);
} }
PJ_String(PJ_Pool *pool, const PJ_String &rhs) //
// Construct by copying from Pj_String
//
Pj_String(Pj_Pool *pool, const Pj_String &rhs)
{ {
set(pool, rhs); set(pool, rhs);
} }
PJ_String(char *str, pj_size_t len) //
// Construct from a char* and a length.
//
Pj_String(char *str, pj_size_t len)
{ {
set(str, len); set(str, len);
} }
PJ_String(char *begin, char *end) //
// Construct from pair of pointer.
//
Pj_String(char *begin, char *end)
{ {
pj_strset3(this, begin, end); pj_strset3(this, begin, end);
} }
//
// Get the length of the string.
//
pj_size_t length() const pj_size_t length() const
{ {
return pj_strlen(this); return pj_strlen(this);
} }
//
// Get the length of the string.
//
pj_size_t size() const pj_size_t size() const
{ {
return length(); return length();
} }
//
// Get the string buffer.
//
const char *buf() const const char *buf() const
{ {
return ptr; return ptr;
} }
//
// Initialize buffer from char*.
//
void set(char *str) void set(char *str)
{ {
pj_strset2(this, str); pj_strset2(this, str);
} }
void set(PJ_Pool *pool, const char *s) //
// Initialize by copying from a const char*.
//
void set(Pj_Pool *pool, const char *s)
{ {
pj_strdup2(pool->pool_(), this, s); pj_strdup2(pool->pool_(), this, s);
} }
//
// Initialize from pj_str_t*.
//
void set(pj_str_t *s) void set(pj_str_t *s)
{ {
pj_strassign(this, s); pj_strassign(this, s);
} }
void set(PJ_Pool *pool, const pj_str_t *s) //
// Initialize by copying from const pj_str_t*.
//
void set(Pj_Pool *pool, const pj_str_t *s)
{ {
pj_strdup(pool->pool_(), this, s); pj_strdup(pool->pool_(), this, s);
} }
//
// Initialize from char* and length.
//
void set(char *str, pj_size_t len) void set(char *str, pj_size_t len)
{ {
pj_strset(this, str, len); pj_strset(this, str, len);
} }
//
// Initialize from pair of pointers.
//
void set(char *begin, char *end) void set(char *begin, char *end)
{ {
pj_strset3(this, begin, end); pj_strset3(this, begin, end);
} }
void set(PJ_String &rhs) //
// Initialize from other Pj_String.
//
void set(Pj_String &rhs)
{ {
pj_strassign(this, &rhs); pj_strassign(this, &rhs);
} }
void set(PJ_Pool *pool, const PJ_String *s) //
// Initialize by copying from a Pj_String*.
//
void set(Pj_Pool *pool, const Pj_String *s)
{ {
pj_strdup(pool->pool_(), this, s); pj_strdup(pool->pool_(), this, s);
} }
void set(PJ_Pool *pool, const PJ_String &s) //
// Initialize by copying from other Pj_String.
//
void set(Pj_Pool *pool, const Pj_String &s)
{ {
pj_strdup(pool->pool_(), this, &s); pj_strdup(pool->pool_(), this, &s);
} }
//
// Copy the contents of other string.
//
void strcpy(const pj_str_t *s) void strcpy(const pj_str_t *s)
{ {
pj_strcpy(this, s); pj_strcpy(this, s);
} }
void strcpy(const PJ_String &rhs) //
// Copy the contents of other string.
//
void strcpy(const Pj_String &rhs)
{ {
pj_strcpy(this, &rhs); pj_strcpy(this, &rhs);
} }
//
// Copy the contents of other string.
//
void strcpy(const char *s) void strcpy(const char *s)
{ {
pj_strcpy2(this, s); pj_strcpy2(this, s);
} }
//
// Compare string.
//
int strcmp(const char *s) const int strcmp(const char *s) const
{ {
return pj_strcmp2(this, s); return pj_strcmp2(this, s);
} }
//
// Compare string.
//
int strcmp(const pj_str_t *s) const int strcmp(const pj_str_t *s) const
{ {
return pj_strcmp(this, s); return pj_strcmp(this, s);
} }
int strcmp(const PJ_String &rhs) const //
// Compare string.
//
int strcmp(const Pj_String &rhs) const
{ {
return pj_strcmp(this, &rhs); return pj_strcmp(this, &rhs);
} }
//
// Compare string.
//
int strncmp(const char *s, pj_size_t len) const int strncmp(const char *s, pj_size_t len) const
{ {
return pj_strncmp2(this, s, len); return pj_strncmp2(this, s, len);
} }
//
// Compare string.
//
int strncmp(const pj_str_t *s, pj_size_t len) const int strncmp(const pj_str_t *s, pj_size_t len) const
{ {
return pj_strncmp(this, s, len); return pj_strncmp(this, s, len);
} }
int strncmp(const PJ_String &rhs, pj_size_t len) const //
// Compare string.
//
int strncmp(const Pj_String &rhs, pj_size_t len) const
{ {
return pj_strncmp(this, &rhs, len); return pj_strncmp(this, &rhs, len);
} }
//
// Compare string.
//
int stricmp(const char *s) const int stricmp(const char *s) const
{ {
return pj_stricmp2(this, s); return pj_stricmp2(this, s);
} }
//
// Compare string.
//
int stricmp(const pj_str_t *s) const int stricmp(const pj_str_t *s) const
{ {
return pj_stricmp(this, s); return pj_stricmp(this, s);
} }
int stricmp(const PJ_String &rhs) const //
// Compare string.
//
int stricmp(const Pj_String &rhs) const
{ {
return stricmp(&rhs); return stricmp(&rhs);
} }
//
// Compare string.
//
int strnicmp(const char *s, pj_size_t len) const int strnicmp(const char *s, pj_size_t len) const
{ {
return pj_strnicmp2(this, s, len); return pj_strnicmp2(this, s, len);
} }
//
// Compare string.
//
int strnicmp(const pj_str_t *s, pj_size_t len) const int strnicmp(const pj_str_t *s, pj_size_t len) const
{ {
return pj_strnicmp(this, s, len); return pj_strnicmp(this, s, len);
} }
int strnicmp(const PJ_String &rhs, pj_size_t len) const //
// Compare string.
//
int strnicmp(const Pj_String &rhs, pj_size_t len) const
{ {
return strnicmp(&rhs, len); return strnicmp(&rhs, len);
} }
//
// Compare contents for equality.
//
bool operator==(const char *s) const bool operator==(const char *s) const
{ {
return strcmp(s) == 0; return strcmp(s) == 0;
} }
//
// Compare contents for equality.
//
bool operator==(const pj_str_t *s) const bool operator==(const pj_str_t *s) const
{ {
return strcmp(s) == 0; return strcmp(s) == 0;
} }
bool operator==(const PJ_String &rhs) const //
// Compare contents for equality.
//
bool operator==(const Pj_String &rhs) const
{ {
return pj_strcmp(this, &rhs) == 0; return pj_strcmp(this, &rhs) == 0;
} }
//
// Find a character in the string.
//
char *strchr(int chr) char *strchr(int chr)
{ {
return pj_strchr(this, chr); return pj_strchr(this, chr);
} }
//
// Find a character in the string.
//
char *find(int chr) char *find(int chr)
{ {
return strchr(chr); return strchr(chr);
} }
void strcat(const PJ_String &rhs) //
// Concatenate string.
//
void strcat(const Pj_String &rhs)
{ {
pj_strcat(this, &rhs); pj_strcat(this, &rhs);
} }
//
// Left trim.
//
void ltrim() void ltrim()
{ {
pj_strltrim(this); pj_strltrim(this);
} }
//
// Right trim.
//
void rtrim() void rtrim()
{ {
pj_strrtrim(this); pj_strrtrim(this);
} }
//
// Left and right trim.
//
void trim() void trim()
{ {
pj_strtrim(this); pj_strtrim(this);
} }
unsigned long toul() const //
// Convert to unsigned long.
//
unsigned long to_ulong() const
{ {
return pj_strtoul(this); return pj_strtoul(this);
} }
//
// Convert from unsigned long.
//
void from_ulong(unsigned long value)
{
slen = pj_utoa(value, ptr);
}
//
// Convert from unsigned long with padding.
//
void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ')
{
slen = pj_utoa_pad(value, ptr, min_dig, pad);
}
private: private:
//PJ_String(const PJ_String &rhs) {} //Pj_String(const Pj_String &rhs) {}
void operator=(const PJ_String &rhs) { pj_assert(false); } void operator=(const Pj_String &rhs) { pj_assert(false); }
}; };
#endif /* __PJPP_STRING_H__ */ #endif /* __PJPP_STRING_H__ */

View File

@ -1,101 +1,174 @@
/* $Id$ /* $Id$
*
*/ */
#ifndef __PJPP_TIMER_H__ #ifndef __PJPP_TIMER_H__
#define __PJPP_TIMER_H__ #define __PJPP_TIMER_H__
#include <pj/timer.h> #include <pj/timer.h>
#include <pj++/types.hpp> #include <pj++/types.hpp>
#include <pj/assert.h>
#include <pj++/lock.hpp>
class PJ_Timer_Heap; class Pj_Timer_Heap;
class PJ_Timer_Entry : private pj_timer_entry //////////////////////////////////////////////////////////////////////////////
// Timer entry.
//
// How to use:
// Derive class from Pj_Timer_Entry and override on_timeout().
// Scheduler timer in Pj_Timer_Heap.
//
class Pj_Timer_Entry : public Pj_Object
{ {
friend class PJ_Timer_Heap; friend class Pj_Timer_Heap;
public: public:
static void timer_heap_callback(pj_timer_heap_t *, pj_timer_entry *); //
// Default constructor.
PJ_Timer_Entry() { cb = &timer_heap_callback; } //
PJ_Timer_Entry(int arg_id, void *arg_user_data) Pj_Timer_Entry()
{ {
cb = &timer_heap_callback; entry_.user_data = this;
init(arg_id, arg_user_data); entry_.cb = &timer_heap_callback;
} }
virtual void on_timeout() = 0; //
// Destructor, do nothing.
void init(int arg_id, void *arg_user_data) //
~Pj_Timer_Entry()
{ {
id = arg_id;
user_data = arg_user_data;
} }
int get_id() const //
// Override this to get the timeout notification.
//
virtual void on_timeout(int id) = 0;
private:
pj_timer_entry entry_;
static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e)
{ {
return id; Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data;
entry->on_timeout(e->id);
} }
void set_id(int arg_id)
{
id = arg_id;
}
void set_user_data(void *arg_user_data)
{
user_data = arg_user_data;
}
void *get_user_data() const
{
return user_data;
}
const PJ_Time_Val &get_timeout() const
{
pj_assert(sizeof(PJ_Time_Val) == sizeof(pj_time_val));
return (PJ_Time_Val&)_timer_value;
}
}; };
class PJ_Timer_Heap //////////////////////////////////////////////////////////////////////////////
// Timer heap.
//
class Pj_Timer_Heap : public Pj_Object
{ {
public: public:
PJ_Timer_Heap() {} //
// Default constructor.
bool create(PJ_Pool *pool, pj_size_t initial_count, //
unsigned flag = PJ_TIMER_HEAP_SYNCHRONIZE) Pj_Timer_Heap()
: ht_(NULL)
{ {
ht_ = pj_timer_heap_create(pool->pool_(), initial_count, flag);
return ht_ != NULL;
} }
//
// Construct timer heap.
//
Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count)
: ht_(NULL)
{
create(pool, initial_count);
}
//
// Destructor.
//
~Pj_Timer_Heap()
{
destroy();
}
//
// Create
//
pj_status_t create(Pj_Pool *pool, pj_size_t initial_count)
{
destroy();
return pj_timer_heap_create(pool->pool_(), initial_count, &ht_);
}
//
// Destroy
//
void destroy()
{
if (ht_) {
pj_timer_heap_destroy(ht_);
ht_ = NULL;
}
}
//
// Get pjlib compatible timer heap object.
//
pj_timer_heap_t *get_timer_heap() pj_timer_heap_t *get_timer_heap()
{ {
return ht_; return ht_;
} }
bool schedule( PJ_Timer_Entry *ent, const PJ_Time_Val &delay) //
// Set the lock object.
//
void set_lock( Pj_Lock *lock, bool auto_delete )
{ {
return pj_timer_heap_schedule(ht_, ent, &delay) == 0; pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete);
} }
bool cancel(PJ_Timer_Entry *ent) //
// Set maximum number of timed out entries to be processed per poll.
//
unsigned set_max_timed_out_per_poll(unsigned count)
{ {
return pj_timer_heap_cancel(ht_, ent) == 1; return pj_timer_heap_set_max_timed_out_per_poll(ht_, count);
} }
//
// Schedule a timer.
//
bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay,
int id)
{
ent->entry_.id = id;
return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0;
}
//
// Cancel a timer.
//
bool cancel(Pj_Timer_Entry *ent)
{
return pj_timer_heap_cancel(ht_, &ent->entry_) == 1;
}
//
// Get current number of timers
//
pj_size_t count() pj_size_t count()
{ {
return pj_timer_heap_count(ht_); return pj_timer_heap_count(ht_);
} }
void earliest_time(PJ_Time_Val *t) //
// Get the earliest time.
// Return false if no timer is found.
//
bool earliest_time(Pj_Time_Val *t)
{ {
pj_timer_heap_earliest_time(ht_, t); return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS;
} }
int poll(PJ_Time_Val *next_delay = NULL) //
// Poll the timer.
// Return number of timed out entries has been called.
//
unsigned poll(Pj_Time_Val *next_delay = NULL)
{ {
return pj_timer_heap_poll(ht_, next_delay); return pj_timer_heap_poll(ht_, next_delay);
} }

View File

@ -6,6 +6,9 @@
#include <pj/rbtree.h> #include <pj/rbtree.h>
//
// Tree.
//
class PJ_Tree class PJ_Tree
{ {
public: public:

View File

@ -6,55 +6,138 @@
#include <pj/types.h> #include <pj/types.h>
class PJ_Pool; class Pj_Pool;
class PJ_Socket; class Pj_Socket ;
class Pj_Lock;
class PJ_Time_Val : public pj_time_val //
// PJLIB initializer.
//
class Pjlib
{ {
public: public:
PJ_Time_Val() {} Pjlib()
PJ_Time_Val(const PJ_Time_Val &rhs) { sec=rhs.sec; msec=rhs.msec; } {
explicit PJ_Time_Val(const pj_time_val &tv) { sec = tv.sec; msec = tv.msec; } pj_init();
}
};
long get_sec() const { return sec; } //
long get_msec() const { return msec; } // Class Pj_Object is declared in pool.hpp
void set_sec (long s) { sec = s; } //
void set_msec(long ms) { msec = ms; normalize(); }
long to_msec() const { return PJ_TIME_VAL_MSEC((*this)); }
bool operator == (const PJ_Time_Val &rhs) const { return PJ_TIME_VAL_EQ((*this), rhs); } //
bool operator > (const PJ_Time_Val &rhs) const { return PJ_TIME_VAL_GT((*this), rhs); } // Time value wrapper.
bool operator >= (const PJ_Time_Val &rhs) const { return PJ_TIME_VAL_GTE((*this), rhs); } //
bool operator < (const PJ_Time_Val &rhs) const { return PJ_TIME_VAL_LT((*this), rhs); } class Pj_Time_Val : public pj_time_val
bool operator <= (const PJ_Time_Val &rhs) const { return PJ_TIME_VAL_LTE((*this), rhs); } {
public:
Pj_Time_Val()
{
}
PJ_Time_Val & operator = (const PJ_Time_Val &rhs) { Pj_Time_Val(long init_sec, long init_msec)
{
sec = init_sec;
msec = init_msec;
}
Pj_Time_Val(const Pj_Time_Val &rhs)
{
sec=rhs.sec;
msec=rhs.msec;
}
explicit Pj_Time_Val(const pj_time_val &tv)
{
sec = tv.sec;
msec = tv.msec;
}
long get_sec() const
{
return sec;
}
long get_msec() const
{
return msec;
}
void set_sec (long s)
{
sec = s;
}
void set_msec(long ms)
{
msec = ms;
normalize();
}
long to_msec() const
{
return PJ_TIME_VAL_MSEC((*this));
}
bool operator == (const Pj_Time_Val &rhs) const
{
return PJ_TIME_VAL_EQ((*this), rhs);
}
bool operator > (const Pj_Time_Val &rhs) const
{
return PJ_TIME_VAL_GT((*this), rhs);
}
bool operator >= (const Pj_Time_Val &rhs) const
{
return PJ_TIME_VAL_GTE((*this), rhs);
}
bool operator < (const Pj_Time_Val &rhs) const
{
return PJ_TIME_VAL_LT((*this), rhs);
}
bool operator <= (const Pj_Time_Val &rhs) const
{
return PJ_TIME_VAL_LTE((*this), rhs);
}
Pj_Time_Val & operator = (const Pj_Time_Val &rhs)
{
sec = rhs.sec; sec = rhs.sec;
msec = rhs.msec; msec = rhs.msec;
return *this; return *this;
} }
PJ_Time_Val & operator += (const PJ_Time_Val &rhs) { Pj_Time_Val & operator += (const Pj_Time_Val &rhs)
{
PJ_TIME_VAL_ADD((*this), rhs); PJ_TIME_VAL_ADD((*this), rhs);
return *this; return *this;
} }
PJ_Time_Val & operator -= (const PJ_Time_Val &rhs) { Pj_Time_Val & operator -= (const Pj_Time_Val &rhs)
{
PJ_TIME_VAL_SUB((*this), rhs); PJ_TIME_VAL_SUB((*this), rhs);
return *this; return *this;
} }
/* Must include os.hpp to use these, otherwise unresolved in linking */ /* Must include os.hpp to use these, otherwise unresolved in linking */
pj_status_t gettimeofday(); inline pj_status_t gettimeofday();
pj_parsed_time decode(); inline pj_parsed_time decode();
pj_status_t encode(const pj_parsed_time *pt); inline pj_status_t encode(const pj_parsed_time *pt);
pj_status_t to_gmt(); inline pj_status_t to_gmt();
pj_status_t to_local(); inline pj_status_t to_local();
private: private:
void normalize() { pj_time_val_normalize(this); } void normalize()
{
pj_time_val_normalize(this);
}
}; };

View File

@ -210,6 +210,11 @@ PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode,
* Invalid operation. * Invalid operation.
*/ */
#define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13) #define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13)
/**
* @hideinitializer
* Operation is cancelled.
*/
#define PJ_ECANCELLED (PJ_ERRNO_START_STATUS + 14)
/** @} */ /* pj_errnum */ /** @} */ /* pj_errnum */

View File

@ -297,14 +297,19 @@ PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
/** /**
* Unregister from the I/O Queue framework. Caller must make sure that * Unregister from the I/O Queue framework. Caller must make sure that
* the key doesn't have any pending operation before calling this function, * the key doesn't have any pending operations before calling this function,
* or otherwise the behaviour is undefined (either callback will be called * by calling #pj_ioqueue_is_pending() for all previously submitted
* later when the data is sent/received, or the callback will not be called, * operations except asynchronous connect, and if necessary call
* or even something else). * #pj_ioqueue_post_completion() to cancel the pending operations.
*
* Note that asynchronous connect operation will automatically be
* cancelled during the unregistration.
* *
* @param key The key that was previously obtained from registration. * @param key The key that was previously obtained from registration.
* *
* @return PJ_SUCCESS on success or the error code. * @return PJ_SUCCESS on success or the error code.
*
* @see pj_ioqueue_is_pending
*/ */
PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key ); PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );
@ -334,6 +339,41 @@ PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
void *user_data, void *user_data,
void **old_data); void **old_data);
/**
* Check if operation is pending on the specified operation key.
* The \c op_key must have been submitted as pending operation before,
* or otherwise the result is undefined.
*
* @param key The key.
* @param op_key The operation key, previously submitted to any of
* the I/O functions and has returned PJ_EPENDING.
*
* @return Non-zero if operation is still pending.
*/
PJ_DECL(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key );
/**
* Post completion status to the specified operation key and call the
* appropriate callback. When the callback is called, the number of bytes
* received in read/write callback or the status in accept/connect callback
* will be set from the \c bytes_status parameter.
*
* @param key The key.
* @param op_key Pending operation key.
* @param bytes_status Number of bytes or status to be set. A good value
* to put here is -PJ_ECANCELLED.
*
* @return PJ_SUCCESS if completion status has been successfully
* sent.
*/
PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_status );
#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 #if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
/** /**

View File

@ -324,12 +324,30 @@ PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var);
*/ */
PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var); PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var);
/**
* Increment the value of an atomic type and get the result.
*
* @param atomic_var the atomic variable.
*
* @return The incremented value.
*/
PJ_DECL(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var);
/** /**
* Decrement the value of an atomic type. * Decrement the value of an atomic type.
* *
* @param atomic_var the atomic variable. * @param atomic_var the atomic variable.
*/ */
PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var); PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);
/**
* Decrement the value of an atomic type and get the result.
*
* @param atomic_var the atomic variable.
*
* @return The decremented value.
*/
PJ_DECL(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var);
/** /**
* Add a value to an atomic type. * Add a value to an atomic type.
@ -339,6 +357,17 @@ PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);
*/ */
PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var, PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var,
pj_atomic_value_t value); pj_atomic_value_t value);
/**
* Add a value to an atomic type and get the result.
*
* @param atomic_var The atomic variable.
* @param value Value to be added.
*
* @return The result after the addition.
*/
PJ_DECL(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
pj_atomic_value_t value);
/** /**
* @} * @}

View File

@ -109,18 +109,6 @@ struct pj_timer_entry
}; };
/**
* Default flag for timer heap, indicates that synchronization will be
* used.
*/
#define PJ_TIMER_HEAP_SYNCHRONIZE (0)
/**
* Flag to indicate that thread synchronization is NOT needed for the
* timer heap.
*/
#define PJ_TIMER_HEAP_NO_SYNCHRONIZE (1)
/** /**
* Calculate memory size required to create a timer heap. * Calculate memory size required to create a timer heap.
* *
@ -140,16 +128,45 @@ PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count);
* @param count The maximum number of timer entries to be supported * @param count The maximum number of timer entries to be supported
* initially. If the application registers more entries * initially. If the application registers more entries
* during runtime, then the timer heap will resize. * during runtime, then the timer heap will resize.
* @param flag Creation flag, currently only PJ_TIMER_HEAP_NO_SYNCHRONIZE
* is recognized..
* @param ht Pointer to receive the created timer heap. * @param ht Pointer to receive the created timer heap.
* *
* @return PJ_SUCCESS, or the appropriate error code. * @return PJ_SUCCESS, or the appropriate error code.
*/ */
PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
pj_size_t count, pj_size_t count,
unsigned flag,
pj_timer_heap_t **ht); pj_timer_heap_t **ht);
/**
* Destroy the timer heap.
*
* @param ht The timer heap.
*/
PJ_DECL(void) pj_timer_heap_destroy( pj_timer_heap_t *ht );
/**
* Set lock object to be used by the timer heap. By default, the timer heap
* uses dummy synchronization.
*
* @param ht The timer heap.
* @param lock The lock object to be used for synchronization.
* @param auto_del If nonzero, the lock object will be destroyed when
* the timer heap is destroyed.
*/
PJ_DECL(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht,
pj_lock_t *lock,
pj_bool_t auto_del );
/**
* Set maximum number of timed out entries to process in a single poll.
*
* @param ht The timer heap.
* @param count Number of entries.
*
* @return The old number.
*/
PJ_DECL(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
unsigned count );
/** /**
* Initialize a timer entry. Application should call this function at least * Initialize a timer entry. Application should call this function at least
@ -215,19 +232,21 @@ PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht );
* @return PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled. * @return PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled.
*/ */
PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht,
pj_time_val *timeval); pj_time_val *timeval);
/** /**
* Poll the timer heap, check for expired timers and call the callback for * Poll the timer heap, check for expired timers and call the callback for
* each of the expired timers. * each of the expired timers.
* *
* @param ht The timer heap. * @param ht The timer heap.
* @param next_delay If this parameter is not NULL, it will be filled up with * @param next_delay If this parameter is not NULL, it will be filled up with
* the time delay until the next timer elapsed, or -1 in * the time delay until the next timer elapsed, or -1 in
* the sec part if no entry exist. * the sec part if no entry exist.
* @return The number of timers expired. *
* @return The number of timers expired.
*/ */
PJ_DECL(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay); PJ_DECL(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
pj_time_val *next_delay);
/** /**
* @} * @}

View File

@ -1,46 +0,0 @@
/* $Id$
*
*/
#include <pjlib++.hpp>
#if 0
struct MyNode
{
PJ_DECL_LIST_MEMBER(struct MyNode)
int data;
};
int test()
{
typedef PJ_List<MyNode> MyList;
MyList list;
MyList::iterator it, end = list.end();
for (it=list.begin(); it!=end; ++it) {
MyNode *n = *it;
}
return 0;
}
int test_scan()
{
PJ_Scanner scan;
PJ_String s;
PJ_CharSpec cs;
scan.get(&cs, &s);
return 0;
}
int test_scan_c()
{
pj_scanner scan;
pj_str_t s;
pj_char_spec cs;
pj_scan_get(&scan, cs, &s);
return 0;
}
#endif

View File

@ -1,17 +0,0 @@
/* $Id$
*
*/
#include <pj++/scanner.hpp>
#include <pj++/timer.hpp>
#include <pj/except.h>
void PJ_Scanner::syntax_error_handler_throw_pj(pj_scanner *)
{
PJ_THROW( PJ_Scanner::SYNTAX_ERROR );
}
void PJ_Timer_Entry::timer_heap_callback(pj_timer_heap_t *, pj_timer_entry *e)
{
PJ_Timer_Entry *entry = static_cast<PJ_Timer_Entry*>(e);
entry->on_timeout();
}

View File

@ -1,298 +0,0 @@
/* $Id$
*
*/
#include <pj++/proactor.hpp>
#include <pj/string.h> // memset
static struct pj_ioqueue_callback ioqueue_cb =
{
&PJ_Event_Handler::read_complete_cb,
&PJ_Event_Handler::write_complete_cb,
&PJ_Event_Handler::accept_complete_cb,
&PJ_Event_Handler::connect_complete_cb,
};
PJ_Event_Handler::PJ_Event_Handler()
: proactor_(NULL), key_(NULL)
{
pj_memset(&timer_, 0, sizeof(timer_));
timer_.user_data = this;
timer_.cb = &timer_callback;
}
PJ_Event_Handler::~PJ_Event_Handler()
{
}
#if PJ_HAS_TCP
bool PJ_Event_Handler::connect(const PJ_INET_Addr &addr)
{
pj_assert(key_ != NULL && proactor_ != NULL);
if (key_ == NULL || proactor_ == NULL)
return false;
int status = pj_ioqueue_connect(proactor_->get_io_queue(), key_,
&addr, sizeof(PJ_INET_Addr));
if (status == 0) {
on_connect_complete(0);
return true;
} else if (status == PJ_IOQUEUE_PENDING) {
return true;
} else {
return false;
}
}
bool PJ_Event_Handler::accept(PJ_Socket *sock, PJ_INET_Addr *local, PJ_INET_Addr *remote)
{
pj_assert(key_ != NULL && proactor_ != NULL);
if (key_ == NULL || proactor_ == NULL)
return false;
int status = pj_ioqueue_accept(proactor_->get_io_queue(), key_,
&sock->get_handle(),
local_addr, remote,
(remote? sizeof(*remote) : 0));
if (status == 0) {
on_accept_complete(0);
return true;
} else if (status == PJ_IOQUEUE_PENDING) {
return true;
} else {
return false;
}
}
#endif
bool PJ_Event_Handler::read(void *buf, pj_size_t len)
{
pj_assert(key_ != NULL && proactor_ != NULL);
if (key_ == NULL || proactor_ == NULL)
return false;
int bytes_status = pj_ioqueue_read(proactor_->get_io_queue(),
key_, buf, len);
if (bytes_status >= 0) {
on_read_complete(bytes_status);
return true;
} else if (bytes_status == PJ_IOQUEUE_PENDING) {
return true;
} else {
return false;
}
}
bool PJ_Event_Handler::recvfrom(void *buf, pj_size_t len, PJ_INET_Addr *addr)
{
pj_assert(key_ != NULL && proactor_ != NULL);
if (key_ == NULL || proactor_ == NULL)
return false;
tmp_recvfrom_addr_len = sizeof(PJ_INET_Addr);
int bytes_status = pj_ioqueue_recvfrom(proactor_->get_io_queue(),
key_, buf, len,
addr,
(addr? &tmp_recvfrom_addr_len : NULL));
if (bytes_status >= 0) {
on_read_complete(bytes_status);
return true;
} else if (bytes_status == PJ_IOQUEUE_PENDING) {
return true;
} else {
return false;
}
}
bool PJ_Event_Handler::write(const void *data, pj_size_t len)
{
pj_assert(key_ != NULL && proactor_ != NULL);
if (key_ == NULL || proactor_ == NULL)
return false;
int bytes_status = pj_ioqueue_write(proactor_->get_io_queue(),
key_, data, len);
if (bytes_status >= 0) {
on_write_complete(bytes_status);
return true;
} else if (bytes_status == PJ_IOQUEUE_PENDING) {
return true;
} else {
return false;
}
}
bool PJ_Event_Handler::sendto(const void *data, pj_size_t len, const PJ_INET_Addr &addr)
{
pj_assert(key_ != NULL && proactor_ != NULL);
if (key_ == NULL || proactor_ == NULL)
return false;
int bytes_status = pj_ioqueue_sendto(proactor_->get_io_queue(),
key_, data, len,
&addr, sizeof(PJ_INET_Addr));
if (bytes_status >= 0) {
on_write_complete(bytes_status);
return true;
} else if (bytes_status == PJ_IOQUEUE_PENDING) {
return true;
} else {
return false;
}
}
void PJ_Event_Handler::read_complete_cb(pj_ioqueue_key_t *key, pj_ssize_t bytes_read)
{
PJ_Event_Handler *handler =
(PJ_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_read_complete(bytes_read);
}
void PJ_Event_Handler::write_complete_cb(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent)
{
PJ_Event_Handler *handler =
(PJ_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_write_complete(bytes_sent);
}
void PJ_Event_Handler::accept_complete_cb(pj_ioqueue_key_t *key, int status)
{
#if PJ_HAS_TCP
PJ_Event_Handler *handler =
(PJ_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_accept_complete(status);
#endif
}
void PJ_Event_Handler::connect_complete_cb(pj_ioqueue_key_t *key, int status)
{
#if PJ_HAS_TCP
PJ_Event_Handler *handler =
(PJ_Event_Handler*) pj_ioqueue_get_user_data(key);
handler->on_connect_complete(status);
#endif
}
void PJ_Event_Handler::timer_callback( pj_timer_heap_t *timer_heap,
struct pj_timer_entry *entry)
{
PJ_Event_Handler *handler = (PJ_Event_Handler*) entry->user_data;
handler->on_timeout(entry->id);
}
PJ_Proactor *PJ_Proactor::create(PJ_Pool *pool, pj_size_t max_fd,
pj_size_t timer_entry_count, unsigned timer_flags)
{
PJ_Proactor *p = (PJ_Proactor*) pool->calloc(1, sizeof(PJ_Proactor));
if (!p) return NULL;
p->ioq_ = pj_ioqueue_create(pool->pool_(), max_fd);
if (!p->ioq_) return NULL;
p->th_ = pj_timer_heap_create(pool->pool_(), timer_entry_count, timer_flags);
if (!p->th_) return NULL;
return p;
}
void PJ_Proactor::destroy()
{
pj_ioqueue_destroy(ioq_);
}
bool PJ_Proactor::register_handler(PJ_Pool *pool, PJ_Event_Handler *handler)
{
pj_assert(handler->key_ == NULL && handler->proactor_ == NULL);
if (handler->key_ != NULL)
return false;
handler->key_ = pj_ioqueue_register_sock(pool->pool_(), ioq_,
handler->get_handle(),
handler, &ioqueue_cb);
if (handler->key_ != NULL) {
handler->proactor_ = this;
return true;
} else {
return false;
}
}
void PJ_Proactor::unregister_handler(PJ_Event_Handler *handler)
{
if (handler->key_ == NULL) return;
pj_ioqueue_unregister(ioq_, handler->key_);
handler->key_ = NULL;
handler->proactor_ = NULL;
}
bool PJ_Proactor::schedule_timer( pj_timer_heap_t *timer, PJ_Event_Handler *handler,
const PJ_Time_Val &delay, int id)
{
handler->timer_.id = id;
return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0;
}
bool PJ_Proactor::schedule_timer(PJ_Event_Handler *handler, const PJ_Time_Val &delay,
int id)
{
return schedule_timer(th_, handler, delay, id);
}
bool PJ_Proactor::cancel_timer(PJ_Event_Handler *handler)
{
return pj_timer_heap_cancel(th_, &handler->timer_) == 1;
}
bool PJ_Proactor::handle_events(PJ_Time_Val *max_timeout)
{
pj_time_val timeout;
timeout.sec = timeout.msec = 0; /* timeout is 'out' var. */
if (pj_timer_heap_poll( th_, &timeout ) > 0)
return true;
if (timeout.sec < 0) timeout.sec = PJ_MAXINT32;
/* If caller specifies maximum time to wait, then compare the value with
* the timeout to wait from timer, and use the minimum value.
*/
if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
timeout = *max_timeout;
}
/* Poll events in ioqueue. */
int result;
result = pj_ioqueue_poll(ioq_, &timeout);
if (result != 1)
return false;
return true;
}
pj_ioqueue_t *PJ_Proactor::get_io_queue()
{
return ioq_;
}
pj_timer_heap_t *PJ_Proactor::get_timer_heap()
{
return th_;
}

View File

@ -29,7 +29,8 @@ static const struct
{ PJ_ETOOMANY, "Too many objects of the specified type"}, { PJ_ETOOMANY, "Too many objects of the specified type"},
{ PJ_EBUSY, "Object is busy"}, { PJ_EBUSY, "Object is busy"},
{ PJ_ENOTSUP, "Option/operation is not supported"}, { PJ_ENOTSUP, "Option/operation is not supported"},
{ PJ_EINVALIDOP, "Invalid operation"} { PJ_EINVALIDOP, "Invalid operation"},
{ PJ_ECANCELLED, "Operation cancelled"}
}; };
/* /*

View File

@ -66,7 +66,8 @@ PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
clearerr((FILE*)fd); clearerr((FILE*)fd);
written = fwrite(data, 1, *size, (FILE*)fd); written = fwrite(data, 1, *size, (FILE*)fd);
if (ferror((FILE*)fd)) { if (ferror((FILE*)fd)) {
*size = -1;
return PJ_RETURN_OS_ERROR(errno); return PJ_RETURN_OS_ERROR(errno);
} }
@ -82,7 +83,8 @@ PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
clearerr((FILE*)fd); clearerr((FILE*)fd);
bytes = fread(data, 1, *size, (FILE*)fd); bytes = fread(data, 1, *size, (FILE*)fd);
if (ferror((FILE*)fd)) { if (ferror((FILE*)fd)) {
*size = -1;
return PJ_RETURN_OS_ERROR(errno); return PJ_RETURN_OS_ERROR(errno);
} }

View File

@ -227,7 +227,9 @@ void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
* so that send() can work in parallel. * so that send() can work in parallel.
*/ */
if (h->fd_type == PJ_SOCK_DGRAM) { if (h->fd_type == PJ_SOCK_DGRAM) {
pj_list_erase(write_op); pj_list_erase(write_op);
write_op->op = 0;
if (pj_list_empty(&h->write_list)) if (pj_list_empty(&h->write_list))
ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT); ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
@ -267,7 +269,8 @@ void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
{ {
if (h->fd_type != PJ_SOCK_DGRAM) { if (h->fd_type != PJ_SOCK_DGRAM) {
/* Write completion of the whole stream. */ /* Write completion of the whole stream. */
pj_list_erase(write_op); pj_list_erase(write_op);
write_op->op = 0;
/* Clear operation if there's no more data to send. */ /* Clear operation if there's no more data to send. */
if (pj_list_empty(&h->write_list)) if (pj_list_empty(&h->write_list))
@ -313,7 +316,8 @@ void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
/* Get one accept operation from the list. */ /* Get one accept operation from the list. */
accept_op = h->accept_list.next; accept_op = h->accept_list.next;
pj_list_erase(accept_op); pj_list_erase(accept_op);
accept_op->op = 0;
/* Clear bit in fdset if there is no more pending accept */ /* Clear bit in fdset if there is no more pending accept */
if (pj_list_empty(&h->accept_list)) if (pj_list_empty(&h->accept_list))
@ -346,7 +350,8 @@ void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
/* Get one pending read operation from the list. */ /* Get one pending read operation from the list. */
read_op = h->read_list.next; read_op = h->read_list.next;
pj_list_erase(read_op); pj_list_erase(read_op);
read_op->op = 0;
/* Clear fdset if there is no pending read. */ /* Clear fdset if there is no pending read. */
if (pj_list_empty(&h->read_list)) if (pj_list_empty(&h->read_list))
@ -475,6 +480,9 @@ PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL); PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
PJ_CHECK_STACK(); PJ_CHECK_STACK();
read_op = (struct read_operation*)op_key;
read_op->op = 0;
/* Try to see if there's data immediately available. /* Try to see if there's data immediately available.
*/ */
@ -496,8 +504,6 @@ PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
* No data is immediately available. * No data is immediately available.
* Must schedule asynchronous operation to the ioqueue. * Must schedule asynchronous operation to the ioqueue.
*/ */
read_op = (struct read_operation*)op_key;
read_op->op = PJ_IOQUEUE_OP_RECV; read_op->op = PJ_IOQUEUE_OP_RECV;
read_op->buf = buffer; read_op->buf = buffer;
read_op->size = *length; read_op->size = *length;
@ -530,6 +536,9 @@ PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL); PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
PJ_CHECK_STACK(); PJ_CHECK_STACK();
read_op = (struct read_operation*)op_key;
read_op->op = 0;
/* Try to see if there's data immediately available. /* Try to see if there's data immediately available.
*/ */
@ -552,8 +561,6 @@ PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
* No data is immediately available. * No data is immediately available.
* Must schedule asynchronous operation to the ioqueue. * Must schedule asynchronous operation to the ioqueue.
*/ */
read_op = (struct read_operation*)op_key;
read_op->op = PJ_IOQUEUE_OP_RECV_FROM; read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
read_op->buf = buffer; read_op->buf = buffer;
read_op->size = *length; read_op->size = *length;
@ -586,6 +593,9 @@ PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL); PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
PJ_CHECK_STACK(); PJ_CHECK_STACK();
write_op = (struct write_operation*)op_key;
write_op->op = 0;
/* Fast track: /* Fast track:
* Try to send data immediately, only if there's no pending write! * Try to send data immediately, only if there's no pending write!
@ -624,7 +634,6 @@ PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
/* /*
* Schedule asynchronous send. * Schedule asynchronous send.
*/ */
write_op = (struct write_operation*)op_key;
write_op->op = PJ_IOQUEUE_OP_SEND; write_op->op = PJ_IOQUEUE_OP_SEND;
write_op->buf = (void*)data; write_op->buf = (void*)data;
write_op->size = *length; write_op->size = *length;
@ -659,6 +668,9 @@ PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL); PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
PJ_CHECK_STACK(); PJ_CHECK_STACK();
write_op = (struct write_operation*)op_key;
write_op->op = 0;
/* Fast track: /* Fast track:
* Try to send data immediately, only if there's no pending write! * Try to send data immediately, only if there's no pending write!
@ -702,7 +714,6 @@ PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
/* /*
* Schedule asynchronous send. * Schedule asynchronous send.
*/ */
write_op = (struct write_operation*)op_key;
write_op->op = PJ_IOQUEUE_OP_SEND_TO; write_op->op = PJ_IOQUEUE_OP_SEND_TO;
write_op->buf = (void*)data; write_op->buf = (void*)data;
write_op->size = *length; write_op->size = *length;
@ -735,6 +746,9 @@ PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
/* check parameters. All must be specified! */ /* check parameters. All must be specified! */
PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL); PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
accept_op = (struct accept_operation*)op_key;
accept_op->op = 0;
/* Fast track: /* Fast track:
* See if there's new connection available immediately. * See if there's new connection available immediately.
@ -767,8 +781,6 @@ PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
* Schedule accept() operation to be completed when there is incoming * Schedule accept() operation to be completed when there is incoming
* connection available. * connection available.
*/ */
accept_op = (struct accept_operation*)op_key;
accept_op->op = PJ_IOQUEUE_OP_ACCEPT; accept_op->op = PJ_IOQUEUE_OP_ACCEPT;
accept_op->accept_fd = new_sock; accept_op->accept_fd = new_sock;
accept_op->rmt_addr = remote; accept_op->rmt_addr = remote;
@ -821,3 +833,82 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
} }
#endif /* PJ_HAS_TCP */ #endif /* PJ_HAS_TCP */
/*
* pj_ioqueue_is_pending()
*/
PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key )
{
struct generic_operation *op_rec;
PJ_UNUSED_ARG(key);
op_rec = (struct generic_operation*)op_key;
return op_rec->op != 0;
}
/*
* pj_ioqueue_post_completion()
*/
PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_status )
{
struct generic_operation *op_rec;
/*
* Find the operation key in all pending operation list to
* really make sure that it's still there; then call the callback.
*/
pj_mutex_lock(key->mutex);
/* Find the operation in the pending read list. */
op_rec = (struct generic_operation*)key->read_list.next;
while (op_rec != (void*)&key->read_list) {
if (op_rec == (void*)op_key) {
pj_list_erase(op_rec);
op_rec->op = 0;
pj_mutex_unlock(key->mutex);
(*key->cb.on_read_complete)(key, op_key, bytes_status);
return PJ_SUCCESS;
}
op_rec = op_rec->next;
}
/* Find the operation in the pending write list. */
op_rec = (struct generic_operation*)key->write_list.next;
while (op_rec != (void*)&key->write_list) {
if (op_rec == (void*)op_key) {
pj_list_erase(op_rec);
op_rec->op = 0;
pj_mutex_unlock(key->mutex);
(*key->cb.on_write_complete)(key, op_key, bytes_status);
return PJ_SUCCESS;
}
op_rec = op_rec->next;
}
/* Find the operation in the pending accept list. */
op_rec = (struct generic_operation*)key->accept_list.next;
while (op_rec != (void*)&key->accept_list) {
if (op_rec == (void*)op_key) {
pj_list_erase(op_rec);
op_rec->op = 0;
pj_mutex_unlock(key->mutex);
(*key->cb.on_accept_complete)(key, op_key,
PJ_INVALID_SOCKET,
bytes_status);
return PJ_SUCCESS;
}
op_rec = op_rec->next;
}
pj_mutex_unlock(key->mutex);
return PJ_EINVALIDOP;
}

View File

@ -891,3 +891,37 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
} }
#endif /* #if PJ_HAS_TCP */ #endif /* #if PJ_HAS_TCP */
PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key )
{
BOOL rc;
DWORD bytesTransfered;
rc = GetOverlappedResult( key->hnd, (LPOVERLAPPED)op_key,
&bytesTransfered, FALSE );
if (rc == FALSE) {
return GetLastError()==ERROR_IO_INCOMPLETE;
}
return FALSE;
}
PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_status )
{
BOOL rc;
rc = PostQueuedCompletionStatus(key->ioqueue->iocp, bytes_status,
(long)key, (OVERLAPPED*)op_key );
if (rc == FALSE) {
return PJ_RETURN_OS_ERROR(GetLastError());
}
return PJ_SUCCESS;
}

View File

@ -558,54 +558,91 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
return oldval; return oldval;
} }
/*
* pj_atomic_inc_and_get()
*/
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
{
pj_atomic_value_t new_value;
PJ_CHECK_STACK();
#if PJ_HAS_THREADS
pj_mutex_lock( atomic_var->mutex );
#endif
new_value = ++atomic_var->value;
#if PJ_HAS_THREADS
pj_mutex_unlock( atomic_var->mutex);
#endif
return new_value;
}
/* /*
* pj_atomic_inc() * pj_atomic_inc()
*/ */
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var) PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
{ {
PJ_CHECK_STACK(); pj_atomic_inc_and_get(atomic_var);
#if PJ_HAS_THREADS
pj_mutex_lock( atomic_var->mutex );
#endif
++atomic_var->value;
#if PJ_HAS_THREADS
pj_mutex_unlock( atomic_var->mutex);
#endif
} }
/* /*
* pj_atomic_dec() * pj_atomic_dec_and_get()
*/ */
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var) PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
{ {
pj_atomic_value_t new_value;
PJ_CHECK_STACK(); PJ_CHECK_STACK();
#if PJ_HAS_THREADS #if PJ_HAS_THREADS
pj_mutex_lock( atomic_var->mutex ); pj_mutex_lock( atomic_var->mutex );
#endif #endif
--atomic_var->value; new_value = --atomic_var->value;
#if PJ_HAS_THREADS #if PJ_HAS_THREADS
pj_mutex_unlock( atomic_var->mutex); pj_mutex_unlock( atomic_var->mutex);
#endif #endif
return new_value;
} }
/*
* pj_atomic_dec()
*/
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
{
pj_atomic_dec_and_get(atomic_var);
}
/* /*
* pj_atomic_add() * pj_atomic_add_and_get()
*/ */
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var, pj_atomic_value_t value ) PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
{ pj_atomic_value_t value )
{
pj_atomic_value_t new_value;
#if PJ_HAS_THREADS #if PJ_HAS_THREADS
pj_mutex_lock(atomic_var->mutex); pj_mutex_lock(atomic_var->mutex);
#endif #endif
atomic_var->value += value; atomic_var->value += value;
new_value = atomic_var->value;
#if PJ_HAS_THREADS #if PJ_HAS_THREADS
pj_mutex_unlock(atomic_var->mutex); pj_mutex_unlock(atomic_var->mutex);
#endif #endif
return new_value;
} }
/*
* pj_atomic_add()
*/
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
pj_atomic_value_t value )
{
pj_atomic_add_and_get(atomic_var, value);
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/* /*

View File

@ -512,32 +512,48 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
return atomic_var->value; return atomic_var->value;
} }
/*
* pj_atomic_inc_and_get()
*/
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
{
PJ_CHECK_STACK();
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
return InterlockedIncrement(&atomic_var->value);
#else
# error Fix Me
#endif
}
/* /*
* pj_atomic_inc() * pj_atomic_inc()
*/ */
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var) PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
{ {
PJ_CHECK_STACK(); pj_atomic_inc_and_get(atomic_var);
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
InterlockedIncrement(&atomic_var->value);
#else
# error Fix Me
#endif
} }
/*
* pj_atomic_dec_and_get()
*/
PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
{
PJ_CHECK_STACK();
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
return InterlockedDecrement(&atomic_var->value);
#else
# error Fix me
#endif
}
/* /*
* pj_atomic_dec() * pj_atomic_dec()
*/ */
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var) PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
{ {
PJ_CHECK_STACK(); pj_atomic_dec_and_get(atomic_var);
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
InterlockedDecrement(&atomic_var->value);
#else
# error Fix me
#endif
} }
/* /*
@ -546,10 +562,27 @@ PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var, PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
pj_atomic_value_t value ) pj_atomic_value_t value )
{ {
InterlockedExchangeAdd( &atomic_var->value, value ); #if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
InterlockedExchangeAdd( &atomic_var->value, value );
#else
# error Fix me
#endif
}
/*
* pj_atomic_add_and_get()
*/
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
pj_atomic_value_t value)
{
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
return oldValue + value;
#else
# error Fix me
#endif
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/* /*
* pj_thread_local_alloc() * pj_thread_local_alloc()

View File

@ -14,9 +14,13 @@
#include <pj/string.h> #include <pj/string.h>
#include <pj/assert.h> #include <pj/assert.h>
#include <pj/errno.h> #include <pj/errno.h>
#include <pj/lock.h>
#define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2)) #define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2))
#define HEAP_LEFT(X) (((X)+(X))+1) #define HEAP_LEFT(X) (((X)+(X))+1)
#define DEFAULT_MAX_TIMED_OUT_PER_POLL (64)
/** /**
@ -32,9 +36,15 @@ struct pj_timer_heap_t
/** Current size of the heap. */ /** Current size of the heap. */
pj_size_t cur_size; pj_size_t cur_size;
/** Max timed out entries to process per poll. */
unsigned max_entries_per_poll;
/** Mutex for synchronization, or NULL */ /** Lock object. */
pj_mutex_t *mutex; pj_lock_t *lock;
/** Autodelete lock. */
pj_bool_t auto_delete_lock;
/** /**
* Current contents of the Heap, which is organized as a "heap" of * Current contents of the Heap, which is organized as a "heap" of
@ -71,15 +81,15 @@ struct pj_timer_heap_t
PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht ) PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )
{ {
if (ht->mutex) { if (ht->lock) {
pj_mutex_lock(ht->mutex); pj_lock_acquire(ht->lock);
} }
} }
PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht ) PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )
{ {
if (ht->mutex) { if (ht->lock) {
pj_mutex_unlock(ht->mutex); pj_lock_release(ht->lock);
} }
} }
@ -319,7 +329,7 @@ PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
sizeof(pj_timer_heap_t) + sizeof(pj_timer_heap_t) +
/* size of each entry: */ /* size of each entry: */
(count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) + (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +
/* mutex, pool etc: */ /* lock, pool etc: */
132; 132;
} }
@ -328,7 +338,6 @@ PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
*/ */
PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
pj_size_t size, pj_size_t size,
unsigned flag,
pj_timer_heap_t **p_heap) pj_timer_heap_t **p_heap)
{ {
pj_timer_heap_t *ht; pj_timer_heap_t *ht;
@ -348,23 +357,14 @@ PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
/* Initialize timer heap sizes */ /* Initialize timer heap sizes */
ht->max_size = size; ht->max_size = size;
ht->cur_size = 0; ht->cur_size = 0;
ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;
ht->timer_ids_freelist = 1; ht->timer_ids_freelist = 1;
ht->pool = pool; ht->pool = pool;
/* Mutex. */ /* Lock. */
if (flag & PJ_TIMER_HEAP_NO_SYNCHRONIZE) { ht->lock = NULL;
ht->mutex = NULL; ht->auto_delete_lock = 0;
} else {
pj_status_t rc;
/* Mutex must be the recursive types.
* See commented code inside pj_timer_heap_poll()
*/
rc = pj_mutex_create(pool, "tmhp%p", PJ_MUTEX_RECURSE, &ht->mutex);
if (rc != PJ_SUCCESS)
return rc;
}
// Create the heap array. // Create the heap array.
ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size); ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);
@ -385,6 +385,34 @@ PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
*p_heap = ht; *p_heap = ht;
return PJ_SUCCESS; return PJ_SUCCESS;
} }
PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
{
if (ht->lock && ht->auto_delete_lock) {
pj_lock_destroy(ht->lock);
ht->lock = NULL;
}
}
PJ_DEF(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht,
pj_lock_t *lock,
pj_bool_t auto_del )
{
if (ht->lock && ht->auto_delete_lock)
pj_lock_destroy(ht->lock);
ht->lock = lock;
ht->auto_delete_lock = auto_del;
}
PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
unsigned count )
{
unsigned old_count = ht->max_entries_per_poll;
ht->max_entries_per_poll = count;
return old_count;
}
PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
int id, int id,
@ -433,12 +461,13 @@ PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
return count; return count;
} }
PJ_DEF(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay ) PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
pj_time_val *next_delay )
{ {
pj_time_val now; pj_time_val now;
int count; unsigned count;
PJ_ASSERT_RETURN(ht, -1); PJ_ASSERT_RETURN(ht, 0);
if (!ht->cur_size && next_delay) { if (!ht->cur_size && next_delay) {
next_delay->sec = next_delay->msec = PJ_MAXINT32; next_delay->sec = next_delay->msec = PJ_MAXINT32;
@ -450,16 +479,15 @@ PJ_DEF(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay )
lock_timer_heap(ht); lock_timer_heap(ht);
while ( ht->cur_size && while ( ht->cur_size &&
PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) ) PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) &&
count < ht->max_entries_per_poll )
{ {
pj_timer_entry *node = remove_node(ht, 0); pj_timer_entry *node = remove_node(ht, 0);
++count; ++count;
//Better not to temporarily release mutex to save some syscalls. unlock_timer_heap(ht);
//But then make sure the mutex must be the recursive types (PJ_MUTEX_RECURSE)!
//unlock_timer_heap(ht);
(*node->cb)(ht, node); (*node->cb)(ht, node);
//lock_timer_heap(ht); lock_timer_heap(ht);
} }
if (ht->cur_size && next_delay) { if (ht->cur_size && next_delay) {
*next_delay = ht->heap[0]->_timer_value; *next_delay = ht->heap[0]->_timer_value;
@ -473,7 +501,9 @@ PJ_DEF(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay )
} }
PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ) PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
{ {
PJ_ASSERT_RETURN(ht, 0);
return ht->cur_size; return ht->cur_size;
} }

View File

@ -0,0 +1,29 @@
#include <pj++/file.hpp>
#include <pj++/list.hpp>
#include <pj++/lock.hpp>
#include <pj++/hash.hpp>
#include <pj++/os.hpp>
#include <pj++/proactor.hpp>
#include <pj++/sock.hpp>
#include <pj++/string.hpp>
#include <pj++/timer.hpp>
#include <pj++/tree.hpp>
int main()
{
Pjlib lib;
Pj_Caching_Pool mem;
Pj_Pool the_pool;
Pj_Pool *pool = &the_pool;
the_pool.attach(mem.create_pool(4000,4000));
Pj_Semaphore_Lock lsem(pool);
Pj_Semaphore_Lock *plsem;
plsem = new(pool) Pj_Semaphore_Lock(pool);
delete plsem;
return 0;
}