From 85d3f4539934d8bed905fd943090f24a28a4f756 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Wed, 9 Nov 2005 15:37:19 +0000 Subject: [PATCH] Rework pjlib++ git-svn-id: https://svn.pjsip.org/repos/pjproject/main@36 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/build/pjlib++-test.dsp | 102 +++ pjlib/build/{pjlibpp.dsp => pjlib++.dsp} | 82 +-- .../build/{pjlibpp.vcproj => pjlib++.vcproj} | 0 pjlib/build/pjlib.dsp | 7 + pjlib/build/pjlib.dsw | 46 +- pjlib/include/pj++/file.hpp | 171 +++++ pjlib/include/pj++/hash.hpp | 110 ++- pjlib/include/pj++/ioqueue.hpp | 174 ----- pjlib/include/pj++/list.hpp | 222 ++++-- pjlib/include/pj++/lock.hpp | 131 ++++ pjlib/include/pj++/os.hpp | 667 +++++++++++++++--- pjlib/include/pj++/pool.hpp | 270 +++++-- pjlib/include/pj++/proactor.hpp | 483 +++++++++++-- pjlib/include/pj++/scanner.hpp | 30 +- pjlib/include/pj++/sock.hpp | 368 ++++++++-- pjlib/include/pj++/string.hpp | 215 +++++- pjlib/include/pj++/timer.hpp | 177 +++-- pjlib/include/pj++/tree.hpp | 3 + pjlib/include/pj++/types.hpp | 133 +++- pjlib/include/pj/errno.h | 5 + pjlib/include/pj/ioqueue.h | 50 +- pjlib/include/pj/os.h | 29 + pjlib/include/pj/timer.h | 59 +- pjlib/src/pj++/compiletest.cpp | 46 -- pjlib/src/pj++/pj++.cpp | 17 - pjlib/src/pj++/proactor.cpp | 298 -------- pjlib/src/pj/errno.c | 3 +- pjlib/src/pj/file_io_ansi.c | 6 +- pjlib/src/pj/ioqueue_common_abs.c | 115 ++- pjlib/src/pj/ioqueue_winnt.c | 34 + pjlib/src/pj/os_core_unix.c | 75 +- pjlib/src/pj/os_core_win32.c | 69 +- pjlib/src/pj/timer.c | 94 ++- pjlib/src/pjlib++-test/main.cpp | 29 + 34 files changed, 3131 insertions(+), 1189 deletions(-) create mode 100644 pjlib/build/pjlib++-test.dsp rename pjlib/build/{pjlibpp.dsp => pjlib++.dsp} (52%) rename pjlib/build/{pjlibpp.vcproj => pjlib++.vcproj} (100%) create mode 100644 pjlib/include/pj++/file.hpp delete mode 100644 pjlib/include/pj++/ioqueue.hpp create mode 100644 pjlib/include/pj++/lock.hpp delete mode 100644 pjlib/src/pj++/compiletest.cpp delete mode 100644 pjlib/src/pj++/pj++.cpp delete mode 100644 pjlib/src/pj++/proactor.cpp create mode 100644 pjlib/src/pjlib++-test/main.cpp diff --git a/pjlib/build/pjlib++-test.dsp b/pjlib/build/pjlib++-test.dsp new file mode 100644 index 000000000..88ae04a1a --- /dev/null +++ b/pjlib/build/pjlib++-test.dsp @@ -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 diff --git a/pjlib/build/pjlibpp.dsp b/pjlib/build/pjlib++.dsp similarity index 52% rename from pjlib/build/pjlibpp.dsp rename to pjlib/build/pjlib++.dsp index 34b31a81b..77057fbf8 100644 --- a/pjlib/build/pjlibpp.dsp +++ b/pjlib/build/pjlib++.dsp @@ -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 # ** DO NOT EDIT ** # 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 use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "pjlibpp.mak". +!MESSAGE NMAKE /f "pjlib++.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 "pjlibpp.mak" CFG="pjlibpp - Win32 Debug" +!MESSAGE NMAKE /f "pjlib++.mak" CFG="pjlib++ - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "pjlibpp - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "pjlibpp - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "pjlib++ - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "pjlib++ - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project @@ -28,20 +28,20 @@ CFG=pjlibpp - Win32 Debug CPP=cl.exe RSC=rc.exe -!IF "$(CFG)" == "pjlibpp - Win32 Release" +!IF "$(CFG)" == "pjlib++ - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\output\pjlibpp-i386-win32-vc6-release" -# PROP BASE Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-release" +# PROP BASE Output_Dir ".\output\pjlib++-i386-win32-vc6-release" +# PROP BASE Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".\output\pjlibpp-i386-win32-vc6-release" -# PROP Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-release" +# PROP Output_Dir ".\output\pjlib++-i386-win32-vc6-release" +# PROP Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-release" # PROP Target_Dir "" # 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 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -52,20 +52,20 @@ LIB32=link.exe -lib # ADD BASE LIB32 /nologo # 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_Debug_Libraries 1 -# PROP BASE Output_Dir ".\output\pjlibpp-i386-win32-vc6-debug" -# PROP BASE Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-debug" +# PROP BASE Output_Dir ".\output\pjlib++-i386-win32-vc6-debug" +# PROP BASE Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".\output\pjlibpp-i386-win32-vc6-debug" -# PROP Intermediate_Dir ".\output\pjlibpp-i386-win32-vc6-debug" +# PROP Output_Dir ".\output\pjlib++-i386-win32-vc6-debug" +# PROP Intermediate_Dir ".\output\pjlib++-i386-win32-vc6-debug" # 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 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 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -80,78 +80,62 @@ LIB32=link.exe -lib # Begin Target -# Name "pjlibpp - Win32 Release" -# Name "pjlibpp - 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 +# Name "pjlib++ - Win32 Release" +# Name "pjlib++ - Win32 Debug" # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File -SOURCE="..\src\pj++\hash.hpp" +SOURCE="..\include\pj++\file.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\ioqueue.hpp" +SOURCE="..\include\pj++\hash.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\list.hpp" +SOURCE="..\include\pj++\list.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\os.hpp" +SOURCE="..\include\pj++\lock.hpp" # End Source File # Begin Source File -SOURCE="..\src\pjlib++.hpp" +SOURCE="..\include\pj++\os.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\pool.hpp" +SOURCE="..\include\pj++\pool.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\proactor.hpp" +SOURCE="..\include\pj++\proactor.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\scanner.hpp" +SOURCE="..\include\pj++\scanner.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\sock.hpp" +SOURCE="..\include\pj++\sock.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\string.hpp" +SOURCE="..\include\pj++\string.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\timer.hpp" +SOURCE="..\include\pj++\timer.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\tree.hpp" +SOURCE="..\include\pj++\tree.hpp" # End Source File # Begin Source File -SOURCE="..\src\pj++\types.hpp" +SOURCE="..\include\pj++\types.hpp" # End Source File # End Group # End Target diff --git a/pjlib/build/pjlibpp.vcproj b/pjlib/build/pjlib++.vcproj similarity index 100% rename from pjlib/build/pjlibpp.vcproj rename to pjlib/build/pjlib++.vcproj diff --git a/pjlib/build/pjlib.dsp b/pjlib/build/pjlib.dsp index 8b95515af..a4222ca20 100644 --- a/pjlib/build/pjlib.dsp +++ b/pjlib/build/pjlib.dsp @@ -234,6 +234,13 @@ SOURCE=..\src\pj\ioqueue_select.c # Begin Source File SOURCE=..\src\pj\ioqueue_winnt.c + +!IF "$(CFG)" == "pjlib - Win32 Release" + +!ELSEIF "$(CFG)" == "pjlib - Win32 Debug" + +!ENDIF + # End Source File # Begin Source File diff --git a/pjlib/build/pjlib.dsw b/pjlib/build/pjlib.dsw index 87ebf475c..41d8c9e0a 100644 --- a/pjlib/build/pjlib.dsw +++ b/pjlib/build/pjlib.dsw @@ -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> {{{ - begin source code control - "$/pjproject-0.3/pjlib/build", EJDAAAAA - . - end source code control }}} 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> {{{ - begin source code control - "$/pjproject-0.3/pjlib/build", EJDAAAAA - . - end source code control }}} 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> {{{ - begin source code control - "$/pjproject-0.3/pjlib/build", EJDAAAAA - . - end source code control }}} 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> {{{ - begin source code control - "$/pjproject-0.3/pjlib/build", EJDAAAAA - . - end source code control }}} 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> {{{ - begin source code control - "$/pjproject-0.3/pjlib/build", EJDAAAAA - . - end source code control }}} Package=<3> diff --git a/pjlib/include/pj++/file.hpp b/pjlib/include/pj++/file.hpp new file mode 100644 index 000000000..dfd78d510 --- /dev/null +++ b/pjlib/include/pj++/file.hpp @@ -0,0 +1,171 @@ +/* $Id$ */ + +#ifndef __PJPP_FILE_HPP__ +#define __PJPP_FILE_HPP__ + +#include +#include +#include +#include + +// +// 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__ */ + diff --git a/pjlib/include/pj++/hash.hpp b/pjlib/include/pj++/hash.hpp index 26f480105..6d4a5e681 100644 --- a/pjlib/include/pj++/hash.hpp +++ b/pjlib/include/pj++/hash.hpp @@ -1,73 +1,139 @@ /* $Id$ - * */ #ifndef __PJPP_HASH_H__ #define __PJPP_HASH_H__ #include +#include #include -class PJ_Hash_Table +// +// Hash table. +// +class Pj_Hash_Table : public Pj_Object { public: + // + // Hash table iterator. + // class iterator { public: - 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_); } - 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; } + 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_); + } + 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: pj_hash_table_t *ht_; pj_hash_iterator_t it_val_; 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); } - 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() { - return pj_hash_count(this->hash_table_()); + return pj_hash_count(table_); } + // + // Iterate hash table. + // iterator begin() { - iterator it(this->hash_table_(), NULL); - it.it_ = pj_hash_first(this->hash_table_(), &it.it_val_); + iterator it(table_, NULL); + it.it_ = pj_hash_first(table_, &it.it_val_); return it; } + // + // End of items. + // iterator end() { - return iterator(this->hash_table_(), NULL); + return iterator(table_, NULL); } + +private: + pj_hash_table_t *table_; }; + #endif /* __PJPP_HASH_H__ */ + diff --git a/pjlib/include/pj++/ioqueue.hpp b/pjlib/include/pj++/ioqueue.hpp deleted file mode 100644 index 5724ecd66..000000000 --- a/pjlib/include/pj++/ioqueue.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/* $Id$ - * - */ -#ifndef __PJPP_IOQUEUE_H__ -#define __PJPP_IOQUEUE_H__ - -#include -#include -#include -#include - -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__ */ diff --git a/pjlib/include/pj++/list.hpp b/pjlib/include/pj++/list.hpp index 68076785a..9895c1c24 100644 --- a/pjlib/include/pj++/list.hpp +++ b/pjlib/include/pj++/list.hpp @@ -1,164 +1,290 @@ /* $Id$ - * */ #ifndef __PJPP_LIST_H__ #define __PJPP_LIST_H__ #include - -template -struct PJ_List_Node -{ - PJ_DECL_LIST_MEMBER(T) -}; +#include -template -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 Pj_List : public Pj_Object { public: - PJ_List() { pj_list_init(&root_); if (0) compiletest(); } - ~PJ_List() {} - + // + // List const_iterator. + // class const_iterator { public: - const_iterator() : node_(NULL) {} - const_iterator(const Node *nd) : node_((Node*)nd) {} - const Node * operator *() { return node_; } - const 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_; } + const_iterator() + : node_(NULL) + {} + const_iterator(const List_Node *nd) + : node_((List_Node*)nd) + {} + 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: - Node *node_; + List_Node *node_; }; + // + // List iterator. + // class iterator : public const_iterator { public: - iterator() {} - iterator(Node *nd) : const_iterator(nd) {} - Node * operator *() { return node_; } - 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_; } + iterator() + {} + iterator(List_Node *nd) + : const_iterator(nd) + {} + List_Node * operator *() + { + 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 { return pj_list_empty(&root_); } + // + // Get first element. + // iterator begin() { return iterator(root_.next); } + // + // Get first element. + // const_iterator begin() const { return const_iterator(root_.next); } + // + // Get end-of-element + // const_iterator end() const { - return const_iterator((Node*)&root_); + return const_iterator((List_Node*)&root_); } + // + // Get end-of-element + // 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 ); } - void insert_after(iterator &pos, Node *node) + // + // Insert node. + // + void insert_after(iterator &pos, List_Node *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); } - void merge_last(PJ_List *list) + // + // Merge list. + // + void merge_last(Pj_List *list) { 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_); } - 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_); } + // + // Erase an element. + // void erase(iterator &it) { pj_list_erase(*it); } - Node *front() + // + // Get first element. + // + List_Node *front() { return root_.next; } - const Node *front() const + // + // Get first element. + // + const List_Node *front() const { return root_.next; } + // + // Remove first element. + // void pop_front() { pj_list_erase(root_.next); } - Node *back() + // + // Get last element. + // + List_Node *back() { return root_.prev; } - const Node *back() const + // + // Get last element. + // + const List_Node *back() const { return root_.prev; } + // + // Remove last element. + // void pop_back() { 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(); } - 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(); } - void push_back(Node *node) + // + // Insert a node in the back. + // + void push_back(List_Node *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); } + // + // Remove all elements. + // void clear() { root_.next = &root_; @@ -168,14 +294,14 @@ public: private: struct RootNode { - PJ_DECL_LIST_MEMBER(Node) + PJ_DECL_LIST_MEMBER(List_Node); } root_; void compiletest() { // If you see error in this line, - // it's because Node is not derived from PJ_List_Node. - Node *n = (Node*)0; + // it's because List_Node is not derived from Pj_List_Node. + List_Node *n = (List_Node*)0; n = n->next; n = n->prev; } }; diff --git a/pjlib/include/pj++/lock.hpp b/pjlib/include/pj++/lock.hpp new file mode 100644 index 000000000..93a435e67 --- /dev/null +++ b/pjlib/include/pj++/lock.hpp @@ -0,0 +1,131 @@ +/* $Id$ */ +#ifndef __PJPP_LOCK_H__ +#define __PJPP_LOCK_H__ + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// 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__ */ + diff --git a/pjlib/include/pj++/os.hpp b/pjlib/include/pj++/os.hpp index af89ac87a..1101daea1 100644 --- a/pjlib/include/pj++/os.hpp +++ b/pjlib/include/pj++/os.hpp @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJPP_OS_H__ #define __PJPP_OS_H__ @@ -8,7 +7,96 @@ #include #include -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: enum Flags @@ -16,134 +104,305 @@ public: FLAG_SUSPENDED = PJ_THREAD_SUSPENDED }; - static PJ_Thread *create( PJ_Pool *pool, const char *thread_name, - pj_thread_proc *proc, void *arg, - pj_size_t stack_size, void *stack_ptr, - unsigned flags) + // + // Default constructor. + // + 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(); - } - - static pj_status_t sleep(unsigned msec) - { - return pj_thread_sleep(msec); - } - - static pj_status_t usleep(unsigned usec) - { - return pj_thread_usleep(usec); + destroy(); + return Pj_Thread_API::create( pool, &thread_, &thread_proc, this, + flags, thread_name); } + // + // Get pjlib compatible thread object. + // pj_thread_t *pj_thread_t_() { - return (pj_thread_t*)this; + return thread_; } + // + // Get thread 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() { - return pj_thread_resume( this->pj_thread_t_() ); + return Pj_Thread_API::resume(thread_); } + // + // Join this thread. + // pj_status_t join() { - return pj_thread_join( this->pj_thread_t_() ); + return Pj_Thread_API::join(thread_); } + // + // Destroy thread. + // 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: - 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) - { - pj_thread_local_set( this->tls_(), value ); - } - - void *get() - { - return pj_thread_local_get( this->tls_() ); - } +private: + pj_thread_desc desc_; }; -class PJ_Atomic +// +// Thread specific data/thread local storage/TLS. +// +class Pj_Thread_Local_API { 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_() { - 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: + // + // Mutex type. + // enum Type { DEFAULT = PJ_MUTEX_DEFAULT, @@ -151,194 +410,378 @@ public: 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: - 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_() { return (pj_sem_t*)this; } - pj_status_t destroy() - { - return pj_sem_destroy(this->pj_sem_t_()); - } - + // + // Wait semaphore. + // pj_status_t wait() { return pj_sem_wait(this->pj_sem_t_()); } - pj_status_t lock() + // + // Wait semaphore. + // + pj_status_t acquire() { return wait(); } + // + // Try wait semaphore. + // pj_status_t trywait() { return pj_sem_trywait(this->pj_sem_t_()); } - pj_status_t trylock() + // + // Try wait semaphore. + // + pj_status_t tryacquire() { return trywait(); } + // + // Post semaphore. + // pj_status_t post() { return pj_sem_post(this->pj_sem_t_()); } - pj_status_t unlock() + // + // Post semaphore. + // + pj_status_t release() { return post(); } + +private: + pj_sem_t *sem_; }; -class PJ_Event +// +// Event object. +// +class Pj_Event { 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_() { - 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() { - return pj_event_wait(this->pj_event_t_()); + return pj_event_wait(event_); } + // + // Try wait. + // 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() { return pj_event_set(this->pj_event_t_()); } + // + // Release one waiting thread. + // pj_status_t pulse() { return pj_event_pulse(this->pj_event_t_()); } + // + // Set a non-signalled. + // pj_status_t reset() { return pj_event_reset(this->pj_event_t_()); } + +private: + pj_event_t *event_; }; -class PJ_OS +// +// OS abstraction. +// +class Pj_OS_API { 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); } - 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); } - 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); } - 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 ); } - 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 ); } }; - -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_OS::time_decode(this, &pt); + Pj_OS_API::time_decode(this, &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__ */ diff --git a/pjlib/include/pj++/pool.hpp b/pjlib/include/pj++/pool.hpp index d2af77bb6..611cd7a72 100644 --- a/pjlib/include/pj++/pool.hpp +++ b/pjlib/include/pj++/pool.hpp @@ -1,86 +1,244 @@ /* $Id$ - * */ #ifndef __PJPP_POOL_H__ #define __PJPP_POOL_H__ #include -class PJ_Pool +class Pj_Pool; +class Pj_Caching_Pool; + +// +// Base class for all Pjlib objects +// +class Pj_Object { public: - const char *getobjname() const - { - return pj_pool_getobjname(this->pool_()); - } + void *operator new(unsigned int class_size, Pj_Pool *pool); + void operator delete(void*); + void operator delete(void*, Pj_Pool*); - pj_pool_t *pool_() - { - return (pj_pool_t*)this; - } + // + // Inline implementations at the end of this file. + // - const pj_pool_t *pool_() const - { - return (const pj_pool_t*)this; - } - - void release() - { - 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); - } +private: + // Can not use normal new operator; must use pool. + // e.g.: + // obj = new(pool) Pj_The_Object(pool, ...); + // + void *operator new(unsigned int) + {} }; -class PJ_Caching_Pool + +// +// Pool. +// +class Pj_Pool : public Pj_Object { 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_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); - } - - void release_pool( PJ_Pool *pool ) - { - pj_pool_release(pool->pool_()); + return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name, + initial_size, + increment_size, + callback); } private: 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__ */ diff --git a/pjlib/include/pj++/proactor.hpp b/pjlib/include/pj++/proactor.hpp index cae9cf433..7021a5a0d 100644 --- a/pjlib/include/pj++/proactor.hpp +++ b/pjlib/include/pj++/proactor.hpp @@ -1,88 +1,481 @@ /* $Id$ - * */ -#ifndef __PJPP_EVENT_HANDLER_H__ -#define __PJPP_EVENT_HANDLER_H__ +#ifndef __PJPP_PROACTOR_H__ +#define __PJPP_PROACTOR_H__ #include #include #include #include +#include -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: - 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 - 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 protected: - // + ////////////////// // Overridables + ////////////////// + // - virtual void on_timeout(int data) {} - virtual void on_read_complete(pj_ssize_t bytes_read) {} - virtual void on_write_complete(pj_ssize_t bytes_sent) {} + // Timeout callback. + // + 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 - 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 + private: - PJ_Proactor *proactor_; pj_ioqueue_key_t *key_; pj_timer_entry timer_; - int tmp_recvfrom_addr_len; -public: - // Internal IO Queue/timer callback. - 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 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_Proactor; + friend class Pj_Async_Op; + + // + // Static timer callback. + // + 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: - 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); - bool schedule_timer(PJ_Event_Handler *handler, const PJ_Time_Val &delay, int id=-1); - bool cancel_timer(PJ_Event_Handler *handler); + // + // Create proactor. + // + 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(); - pj_timer_heap_t *get_timer_heap(); + status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_); + 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: pj_ioqueue_t *ioq_; 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__ */ diff --git a/pjlib/include/pj++/scanner.hpp b/pjlib/include/pj++/scanner.hpp index 80ac0a8b4..9ddac0974 100644 --- a/pjlib/include/pj++/scanner.hpp +++ b/pjlib/include/pj++/scanner.hpp @@ -4,13 +4,13 @@ #ifndef __PJPP_SCANNER_H__ #define __PJPP_SCANNER_H__ -#include +#include #include -class PJ_CharSpec +class Pj_Char_Spec { public: - PJ_CharSpec() { pj_cs_init(cs__); } + Pj_Char_Spec() { pj_cs_init(cs__); } void set(int c) { pj_cs_set(cs__, c); } void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); } @@ -36,10 +36,10 @@ private: pj_char_spec cs__; }; -class PJ_Scanner +class Pj_Scanner { public: - PJ_Scanner() {} + Pj_Scanner() {} enum { @@ -67,30 +67,30 @@ public: 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); } - 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); } - 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); } - 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); } - void get_n(unsigned N, PJ_String *out) + void get_n(unsigned N, Pj_String *out) { pj_scan_get_n(&scanner_, N, out); } @@ -100,7 +100,7 @@ public: 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); } @@ -110,17 +110,17 @@ public: 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); } - 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); } - 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); } diff --git a/pjlib/include/pj++/sock.hpp b/pjlib/include/pj++/sock.hpp index a38fd22d9..1c6c2dd97 100644 --- a/pjlib/include/pj++/sock.hpp +++ b/pjlib/include/pj++/sock.hpp @@ -1,196 +1,426 @@ /* $Id$ - * */ #ifndef __PJPP_SOCK_H__ #define __PJPP_SOCK_H__ #include +#include -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: + // + // Get port number. + // 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) { 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 { - return pj_sockaddr_get_addr(this); + return pj_sockaddr_in_get_addr(this).s_addr; } + // + // Get address string. + // 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) { 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) { - 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) { - 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 - { - return cmp(rhs) == 0; - } +private: + // + // 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: - 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) { sock_ = sock; } + // + // Get socket handle. + // pj_sock_t get_handle() const { return sock_; } + // + // Get socket handle. + // pj_sock_t& get_handle() { 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_ != -1; + return sock_ != PJ_INVALID_SOCKET; } - 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; - return pj_sock_getpeername(sock_, addr, &namelen) == 0; + pj_sock_close(sock_); } - bool getsockname(PJ_INET_Addr *addr) + // + // Get peer socket name. + // + pj_status_t getpeername(Pj_Inet_Addr *addr) { - int namelen; - return pj_sock_getsockname(sock_, addr, &namelen) == 0; + return pj_sock_getpeername(sock_, addr, &addr->addrlen_); } - 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: + friend class Pj_Event_Handler; pj_sock_t sock_; }; + #if PJ_HAS_TCP -class PJ_Sock_Stream : public PJ_Socket +// +// Stream socket. +// +class Pj_Sock_Stream : public Pj_Socket { public: - PJ_Sock_Stream() {} - PJ_Sock_Stream(const PJ_Sock_Stream &rhs) : PJ_Socket(rhs) {} - PJ_Sock_Stream &operator=(const PJ_Sock_Stream &rhs) { sock_ = rhs.sock_; return *this; } - - bool listen(int backlog = 5) + // + // Default constructor. + // + Pj_Sock_Stream() { - 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 -class PJ_Sock_Dgram : public PJ_Socket +// +// Datagram socket. +// +class Pj_Sock_Dgram : public Pj_Socket { public: - PJ_Sock_Dgram() {} - PJ_Sock_Dgram(const PJ_Sock_Dgram &rhs) : PJ_Socket(rhs) {} - PJ_Sock_Dgram &operator=(const PJ_Sock_Dgram &rhs) { sock_ = rhs.sock_; return *this; } - - int recvfrom(void *buf, int len, int flag, PJ_INET_Addr *fromaddr) + // + // Default constructor. + // + Pj_Sock_Dgram() { - 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__ */ diff --git a/pjlib/include/pj++/string.hpp b/pjlib/include/pj++/string.hpp index d55e737b2..456e1ff30 100644 --- a/pjlib/include/pj++/string.hpp +++ b/pjlib/include/pj++/string.hpp @@ -1,249 +1,408 @@ /* $Id$ - * */ #ifndef __PJPP_STRING_H__ #define __PJPP_STRING_H__ #include #include +#include -class PJ_String : public pj_str_t +// +// String wrapper class for pj_str_t. +// +class Pj_String : public pj_str_t { public: - PJ_String() + // + // Default constructor. + // + Pj_String() { - pj_assert(sizeof(PJ_String) == sizeof(pj_str_t)); - ptr=NULL; slen=0; + pj_assert(sizeof(Pj_String) == sizeof(pj_str_t)); + ptr=NULL; + slen=0; } - explicit PJ_String(char *str) + // + // Construct the buffer from a char*. + // + explicit Pj_String(char *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); } - explicit PJ_String(pj_str_t *s) + // + // Construct from pj_str_t*. + // + explicit Pj_String(pj_str_t *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); } - explicit PJ_String(PJ_String &rhs) + // + // Construct from another Pj_String + // + explicit Pj_String(Pj_String &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); } - 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); } - PJ_String(char *begin, char *end) + // + // Construct from pair of pointer. + // + Pj_String(char *begin, char *end) { pj_strset3(this, begin, end); } + // + // Get the length of the string. + // pj_size_t length() const { return pj_strlen(this); } + // + // Get the length of the string. + // pj_size_t size() const { return length(); } + // + // Get the string buffer. + // const char *buf() const { return ptr; } + // + // Initialize buffer from char*. + // void set(char *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); } + // + // Initialize from pj_str_t*. + // void set(pj_str_t *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); } + // + // Initialize from char* and length. + // void set(char *str, pj_size_t len) { pj_strset(this, str, len); } + // + // Initialize from pair of pointers. + // void set(char *begin, char *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); } - 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); } - 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); } + // + // Copy the contents of other string. + // void strcpy(const pj_str_t *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); } + // + // Copy the contents of other string. + // void strcpy(const char *s) { pj_strcpy2(this, s); } + // + // Compare string. + // int strcmp(const char *s) const { return pj_strcmp2(this, s); } + // + // Compare string. + // int strcmp(const pj_str_t *s) const { 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); } + // + // Compare string. + // int strncmp(const char *s, pj_size_t len) const { return pj_strncmp2(this, s, len); } + // + // Compare string. + // int strncmp(const pj_str_t *s, pj_size_t len) const { 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); } + // + // Compare string. + // int stricmp(const char *s) const { return pj_stricmp2(this, s); } + // + // Compare string. + // int stricmp(const pj_str_t *s) const { return pj_stricmp(this, s); } - int stricmp(const PJ_String &rhs) const + // + // Compare string. + // + int stricmp(const Pj_String &rhs) const { return stricmp(&rhs); } + // + // Compare string. + // int strnicmp(const char *s, pj_size_t len) const { return pj_strnicmp2(this, s, len); } + // + // Compare string. + // int strnicmp(const pj_str_t *s, pj_size_t len) const { 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); } + // + // Compare contents for equality. + // bool operator==(const char *s) const { return strcmp(s) == 0; } + // + // Compare contents for equality. + // bool operator==(const pj_str_t *s) const { 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; } + // + // Find a character in the string. + // char *strchr(int chr) { return pj_strchr(this, chr); } + // + // Find a character in the string. + // char *find(int chr) { return strchr(chr); } - void strcat(const PJ_String &rhs) + // + // Concatenate string. + // + void strcat(const Pj_String &rhs) { pj_strcat(this, &rhs); } + // + // Left trim. + // void ltrim() { pj_strltrim(this); } + // + // Right trim. + // void rtrim() { pj_strrtrim(this); } + // + // Left and right trim. + // void trim() { pj_strtrim(this); } - unsigned long toul() const + // + // Convert to unsigned long. + // + unsigned long to_ulong() const { 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: - //PJ_String(const PJ_String &rhs) {} - void operator=(const PJ_String &rhs) { pj_assert(false); } + //Pj_String(const Pj_String &rhs) {} + void operator=(const Pj_String &rhs) { pj_assert(false); } }; #endif /* __PJPP_STRING_H__ */ diff --git a/pjlib/include/pj++/timer.hpp b/pjlib/include/pj++/timer.hpp index 8357a1989..b1070421b 100644 --- a/pjlib/include/pj++/timer.hpp +++ b/pjlib/include/pj++/timer.hpp @@ -1,101 +1,174 @@ /* $Id$ - * */ #ifndef __PJPP_TIMER_H__ #define __PJPP_TIMER_H__ #include #include +#include +#include -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: - static void timer_heap_callback(pj_timer_heap_t *, pj_timer_entry *); - - PJ_Timer_Entry() { cb = &timer_heap_callback; } - PJ_Timer_Entry(int arg_id, void *arg_user_data) - { - cb = &timer_heap_callback; - init(arg_id, arg_user_data); + // + // Default constructor. + // + Pj_Timer_Entry() + { + entry_.user_data = this; + entry_.cb = &timer_heap_callback; } - virtual void on_timeout() = 0; - - void init(int arg_id, void *arg_user_data) + // + // Destructor, do nothing. + // + ~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: - PJ_Timer_Heap() {} - - bool create(PJ_Pool *pool, pj_size_t initial_count, - unsigned flag = PJ_TIMER_HEAP_SYNCHRONIZE) + // + // Default constructor. + // + 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() { 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() { 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); } diff --git a/pjlib/include/pj++/tree.hpp b/pjlib/include/pj++/tree.hpp index db5e8d2ab..7d30c678f 100644 --- a/pjlib/include/pj++/tree.hpp +++ b/pjlib/include/pj++/tree.hpp @@ -6,6 +6,9 @@ #include +// +// Tree. +// class PJ_Tree { public: diff --git a/pjlib/include/pj++/types.hpp b/pjlib/include/pj++/types.hpp index efa743991..637c12224 100644 --- a/pjlib/include/pj++/types.hpp +++ b/pjlib/include/pj++/types.hpp @@ -6,55 +6,138 @@ #include -class PJ_Pool; -class PJ_Socket; +class Pj_Pool; +class Pj_Socket ; +class Pj_Lock; -class PJ_Time_Val : public pj_time_val +// +// PJLIB initializer. +// +class Pjlib { public: - PJ_Time_Val() {} - 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; } + Pjlib() + { + pj_init(); + } +}; - 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)); } +// +// Class Pj_Object is declared in pool.hpp +// - 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); } +// +// Time value wrapper. +// +class Pj_Time_Val : public pj_time_val +{ +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; msec = rhs.msec; 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); 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); return *this; } /* Must include os.hpp to use these, otherwise unresolved in linking */ - pj_status_t gettimeofday(); - pj_parsed_time decode(); - pj_status_t encode(const pj_parsed_time *pt); - pj_status_t to_gmt(); - pj_status_t to_local(); + inline pj_status_t gettimeofday(); + inline pj_parsed_time decode(); + inline pj_status_t encode(const pj_parsed_time *pt); + inline pj_status_t to_gmt(); + inline pj_status_t to_local(); private: - void normalize() { pj_time_val_normalize(this); } + void normalize() + { + pj_time_val_normalize(this); + } }; diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h index 11fab3e79..e7b3ab933 100644 --- a/pjlib/include/pj/errno.h +++ b/pjlib/include/pj/errno.h @@ -210,6 +210,11 @@ PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, * Invalid operation. */ #define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13) +/** + * @hideinitializer + * Operation is cancelled. + */ +#define PJ_ECANCELLED (PJ_ERRNO_START_STATUS + 14) /** @} */ /* pj_errnum */ diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h index 1ecec1b4f..c44b7ced5 100644 --- a/pjlib/include/pj/ioqueue.h +++ b/pjlib/include/pj/ioqueue.h @@ -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 - * the key doesn't have any pending operation before calling this function, - * or otherwise the behaviour is undefined (either callback will be called - * later when the data is sent/received, or the callback will not be called, - * or even something else). + * the key doesn't have any pending operations before calling this function, + * by calling #pj_ioqueue_is_pending() for all previously submitted + * operations except asynchronous connect, and if necessary call + * #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. * - * @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 ); @@ -334,6 +339,41 @@ PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key, void *user_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 /** diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h index 536992f23..a1fef6b8a 100644 --- a/pjlib/include/pj/os.h +++ b/pjlib/include/pj/os.h @@ -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); +/** + * 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. * * @param atomic_var the atomic variable. */ 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. @@ -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_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); /** * @} diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h index 3f1402aba..e8772f22a 100644 --- a/pjlib/include/pj/timer.h +++ b/pjlib/include/pj/timer.h @@ -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. * @@ -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 * initially. If the application registers more entries * 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. * * @return PJ_SUCCESS, or the appropriate error code. */ PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, pj_size_t count, - unsigned flag, 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 @@ -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. */ 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 * 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 * the time delay until the next timer elapsed, or -1 in - * the sec part if no entry exist. - * @return The number of timers expired. + * the sec part if no entry exist. + * + * @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); /** * @} diff --git a/pjlib/src/pj++/compiletest.cpp b/pjlib/src/pj++/compiletest.cpp deleted file mode 100644 index 5bc4f8bdf..000000000 --- a/pjlib/src/pj++/compiletest.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* $Id$ - * - */ -#include - - -#if 0 -struct MyNode -{ - PJ_DECL_LIST_MEMBER(struct MyNode) - int data; -}; - -int test() -{ - typedef PJ_List 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 diff --git a/pjlib/src/pj++/pj++.cpp b/pjlib/src/pj++/pj++.cpp deleted file mode 100644 index 45442098a..000000000 --- a/pjlib/src/pj++/pj++.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* $Id$ - * - */ -#include -#include -#include - -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(e); - entry->on_timeout(); -} diff --git a/pjlib/src/pj++/proactor.cpp b/pjlib/src/pj++/proactor.cpp deleted file mode 100644 index dba9370ba..000000000 --- a/pjlib/src/pj++/proactor.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/* $Id$ - * - */ -#include -#include // 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_; -} - diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c index 682d9b6c9..25bf5b7f8 100644 --- a/pjlib/src/pj/errno.c +++ b/pjlib/src/pj/errno.c @@ -29,7 +29,8 @@ static const struct { PJ_ETOOMANY, "Too many objects of the specified type"}, { PJ_EBUSY, "Object is busy"}, { PJ_ENOTSUP, "Option/operation is not supported"}, - { PJ_EINVALIDOP, "Invalid operation"} + { PJ_EINVALIDOP, "Invalid operation"}, + { PJ_ECANCELLED, "Operation cancelled"} }; /* diff --git a/pjlib/src/pj/file_io_ansi.c b/pjlib/src/pj/file_io_ansi.c index f95c74a9c..0946eddc4 100644 --- a/pjlib/src/pj/file_io_ansi.c +++ b/pjlib/src/pj/file_io_ansi.c @@ -66,7 +66,8 @@ PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd, clearerr((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); } @@ -82,7 +83,8 @@ PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd, clearerr((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); } diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c index 4cffcae46..75774eded 100644 --- a/pjlib/src/pj/ioqueue_common_abs.c +++ b/pjlib/src/pj/ioqueue_common_abs.c @@ -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. */ 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)) 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) { /* 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. */ 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. */ 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 */ 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. */ 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. */ 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_CHECK_STACK(); + + read_op = (struct read_operation*)op_key; + read_op->op = 0; /* 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. * Must schedule asynchronous operation to the ioqueue. */ - read_op = (struct read_operation*)op_key; - read_op->op = PJ_IOQUEUE_OP_RECV; read_op->buf = buffer; 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_CHECK_STACK(); + + read_op = (struct read_operation*)op_key; + read_op->op = 0; /* 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. * Must schedule asynchronous operation to the ioqueue. */ - read_op = (struct read_operation*)op_key; - read_op->op = PJ_IOQUEUE_OP_RECV_FROM; read_op->buf = buffer; 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_CHECK_STACK(); + + write_op = (struct write_operation*)op_key; + write_op->op = 0; /* Fast track: * 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. */ - write_op = (struct write_operation*)op_key; write_op->op = PJ_IOQUEUE_OP_SEND; write_op->buf = (void*)data; 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_CHECK_STACK(); + + write_op = (struct write_operation*)op_key; + write_op->op = 0; /* Fast track: * 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. */ - write_op = (struct write_operation*)op_key; write_op->op = PJ_IOQUEUE_OP_SEND_TO; write_op->buf = (void*)data; 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! */ PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL); + + accept_op = (struct accept_operation*)op_key; + accept_op->op = 0; /* Fast track: * 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 * connection available. */ - accept_op = (struct accept_operation*)op_key; - accept_op->op = PJ_IOQUEUE_OP_ACCEPT; accept_op->accept_fd = new_sock; 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 */ +/* + * 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; +} + diff --git a/pjlib/src/pj/ioqueue_winnt.c b/pjlib/src/pj/ioqueue_winnt.c index 7944953fa..93cbb6d55 100644 --- a/pjlib/src/pj/ioqueue_winnt.c +++ b/pjlib/src/pj/ioqueue_winnt.c @@ -891,3 +891,37 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key, } #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; +} + diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c index 3892b64b1..cc57aab29 100644 --- a/pjlib/src/pj/os_core_unix.c +++ b/pjlib/src/pj/os_core_unix.c @@ -558,54 +558,91 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var) 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_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var) { - PJ_CHECK_STACK(); - -#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_inc_and_get(atomic_var); } /* - * 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(); #if PJ_HAS_THREADS pj_mutex_lock( atomic_var->mutex ); #endif - --atomic_var->value; + new_value = --atomic_var->value; #if PJ_HAS_THREADS 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 pj_mutex_lock(atomic_var->mutex); #endif - atomic_var->value += value; + atomic_var->value += value; + new_value = atomic_var->value; #if PJ_HAS_THREADS 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); +} /////////////////////////////////////////////////////////////////////////////// /* diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c index 68416c665..be770d56a 100644 --- a/pjlib/src/pj/os_core_win32.c +++ b/pjlib/src/pj/os_core_win32.c @@ -512,32 +512,48 @@ PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var) 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_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var) -{ - PJ_CHECK_STACK(); - -#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 - InterlockedIncrement(&atomic_var->value); -#else -# error Fix Me -#endif +{ + pj_atomic_inc_and_get(atomic_var); } - + +/* + * 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_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var) { - PJ_CHECK_STACK(); - -#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 - InterlockedDecrement(&atomic_var->value); -#else -# error Fix me -#endif + pj_atomic_dec_and_get(atomic_var); } /* @@ -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_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() diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c index 9fa190a19..ffec1f4d6 100644 --- a/pjlib/src/pj/timer.c +++ b/pjlib/src/pj/timer.c @@ -14,9 +14,13 @@ #include #include #include +#include #define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2)) #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. */ pj_size_t cur_size; + + /** Max timed out entries to process per poll. */ + unsigned max_entries_per_poll; - /** Mutex for synchronization, or NULL */ - pj_mutex_t *mutex; + /** Lock object. */ + pj_lock_t *lock; + + /** Autodelete lock. */ + pj_bool_t auto_delete_lock; /** * 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 ) { - if (ht->mutex) { - pj_mutex_lock(ht->mutex); + if (ht->lock) { + pj_lock_acquire(ht->lock); } } PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht ) { - if (ht->mutex) { - pj_mutex_unlock(ht->mutex); + if (ht->lock) { + 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) + /* size of each entry: */ (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) + - /* mutex, pool etc: */ + /* lock, pool etc: */ 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_size_t size, - unsigned flag, pj_timer_heap_t **p_heap) { 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 */ 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->pool = pool; + ht->pool = pool; - /* Mutex. */ - if (flag & PJ_TIMER_HEAP_NO_SYNCHRONIZE) { - ht->mutex = NULL; - } 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; - } + /* Lock. */ + ht->lock = NULL; + ht->auto_delete_lock = 0; // Create the heap array. 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; 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, int id, @@ -433,12 +461,13 @@ PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, 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; - int count; + unsigned count; - PJ_ASSERT_RETURN(ht, -1); + PJ_ASSERT_RETURN(ht, 0); if (!ht->cur_size && next_delay) { 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); 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); ++count; - //Better not to temporarily release mutex to save some syscalls. - //But then make sure the mutex must be the recursive types (PJ_MUTEX_RECURSE)! - //unlock_timer_heap(ht); + unlock_timer_heap(ht); (*node->cb)(ht, node); - //lock_timer_heap(ht); + lock_timer_heap(ht); } if (ht->cur_size && next_delay) { *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_ASSERT_RETURN(ht, 0); + return ht->cur_size; } diff --git a/pjlib/src/pjlib++-test/main.cpp b/pjlib/src/pjlib++-test/main.cpp new file mode 100644 index 000000000..4a6d0aaad --- /dev/null +++ b/pjlib/src/pjlib++-test/main.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} +