diff options
| author | Mike Buland <eichlan@xagasoft.com> | 2007-04-26 15:06:49 +0000 |
|---|---|---|
| committer | Mike Buland <eichlan@xagasoft.com> | 2007-04-26 15:06:49 +0000 |
| commit | 530014a3cce53e86dce8917e98a4e86d02f176aa (patch) | |
| tree | c667c996fb91692b101f75296206b8420f19bf73 | |
| parent | 066282ae6de25cf92780dbdaa2fd70a033e95659 (diff) | |
| download | libbu++-530014a3cce53e86dce8917e98a4e86d02f176aa.tar.gz libbu++-530014a3cce53e86dce8917e98a4e86d02f176aa.tar.bz2 libbu++-530014a3cce53e86dce8917e98a4e86d02f176aa.tar.xz libbu++-530014a3cce53e86dce8917e98a4e86d02f176aa.zip | |
Merged Ito and put it in the BU namespace. I should probably clean up the
formatting on the comments, some of the lines wrap, but I'm not too worried
about it right now. I also fixed up the doxygen config and build.conf files
so that everything is building nice and smooth now.
Diffstat (limited to '')
| -rw-r--r-- | Doxyfile | 4 | ||||
| -rw-r--r-- | build.conf | 26 | ||||
| -rwxr-xr-x | mkincs.sh | 5 | ||||
| -rw-r--r-- | src/exceptions.cpp | 1 | ||||
| -rw-r--r-- | src/exceptions.h | 1 | ||||
| -rw-r--r-- | src/ito.cpp | 40 | ||||
| -rw-r--r-- | src/ito.h | 98 | ||||
| -rw-r--r-- | src/itoatom.h | 56 | ||||
| -rw-r--r-- | src/itocondition.cpp | 42 | ||||
| -rw-r--r-- | src/itocondition.h | 81 | ||||
| -rw-r--r-- | src/itomutex.cpp | 27 | ||||
| -rw-r--r-- | src/itomutex.h | 61 | ||||
| -rw-r--r-- | src/itoqueue.h | 231 | ||||
| -rw-r--r-- | src/main.dox | 14 | ||||
| -rw-r--r-- | src/serversocket.cpp | 148 | ||||
| -rw-r--r-- | src/serversocket.h | 31 | ||||
| -rw-r--r-- | src/socket.cpp | 16 | ||||
| -rw-r--r-- | src/socket.h | 4 | ||||
| -rw-r--r-- | src/tests/itoqueue1.cpp | 110 | ||||
| -rw-r--r-- | src/tests/itoqueue2.cpp | 83 |
20 files changed, 1059 insertions, 20 deletions
| @@ -74,9 +74,9 @@ QUIET = NO | |||
| 74 | WARNINGS = YES | 74 | WARNINGS = YES |
| 75 | WARN_IF_UNDOCUMENTED = YES | 75 | WARN_IF_UNDOCUMENTED = YES |
| 76 | WARN_IF_DOC_ERROR = YES | 76 | WARN_IF_DOC_ERROR = YES |
| 77 | WARN_NO_PARAMDOC = NO | 77 | WARN_NO_PARAMDOC = YES |
| 78 | WARN_FORMAT = "$file:$line: $text" | 78 | WARN_FORMAT = "$file:$line: $text" |
| 79 | WARN_LOGFILE = | 79 | WARN_LOGFILE = Doxywarn |
| 80 | #--------------------------------------------------------------------------- | 80 | #--------------------------------------------------------------------------- |
| 81 | # configuration options related to the input files | 81 | # configuration options related to the input files |
| 82 | #--------------------------------------------------------------------------- | 82 | #--------------------------------------------------------------------------- |
| @@ -1,13 +1,17 @@ | |||
| 1 | # This is a build file for libbu++ | 1 | # This is a build file for libbu++ |
| 2 | 2 | ||
| 3 | default action: check "libbu++.a" | 3 | default action: check group "lnhdrs", check "libbu++.a" |
| 4 | "clean" action: clean targets() | 4 | "tests" action: check group "lnhdrs", check group "tests" |
| 5 | "tests" action: check targets() filter regexp("^tests/.*$") | 5 | "all" action: check group "lnhdrs", check targets() |
| 6 | "all" action: check targets() | ||
| 7 | "fstring" action: check "tests/fstring" | ||
| 8 | 6 | ||
| 9 | set "CXXFLAGS" += "-ggdb -Wall" | 7 | set "CXXFLAGS" += "-ggdb -Wall" |
| 10 | 8 | ||
| 9 | filesIn("src") filter regexp("^src/(.*)\\.h$", "src/bu/{re:1}.h"): | ||
| 10 | rule "hln", | ||
| 11 | group "lnhdrs", | ||
| 12 | target file, | ||
| 13 | input "src/{re:1}.h" | ||
| 14 | |||
| 11 | "libbu++.a": | 15 | "libbu++.a": |
| 12 | rule "lib", | 16 | rule "lib", |
| 13 | target file, | 17 | target file, |
| @@ -17,6 +21,7 @@ set "CXXFLAGS" += "-ggdb -Wall" | |||
| 17 | directoriesIn("src/tests","tests/"): | 21 | directoriesIn("src/tests","tests/"): |
| 18 | rule "exe", | 22 | rule "exe", |
| 19 | target file, | 23 | target file, |
| 24 | group "tests", | ||
| 20 | requires "libbu++.a", | 25 | requires "libbu++.a", |
| 21 | set "CXXFLAGS" += "-Isrc", | 26 | set "CXXFLAGS" += "-Isrc", |
| 22 | set "LDFLAGS" += "-L. -lbu++", | 27 | set "LDFLAGS" += "-L. -lbu++", |
| @@ -25,14 +30,18 @@ directoriesIn("src/tests","tests/"): | |||
| 25 | filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): | 30 | filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): |
| 26 | rule "exe", | 31 | rule "exe", |
| 27 | target file, | 32 | target file, |
| 33 | group "tests", | ||
| 28 | requires "libbu++.a", | 34 | requires "libbu++.a", |
| 29 | set "CXXFLAGS" += "-Isrc", | 35 | set "CXXFLAGS" += "-Isrc", |
| 30 | set "LDFLAGS" += "-L. -lbu++", | 36 | set "LDFLAGS" += "-L. -lbu++", |
| 31 | input "src/{target}.cpp" | 37 | input "src/{target}.cpp" |
| 32 | 38 | ||
| 39 | ["tests/itoqueue1", "tests/itoqueue2"]: set "LDFLAGS" += "-lpthread" | ||
| 40 | |||
| 33 | directoriesIn("src/unit","unit/"): | 41 | directoriesIn("src/unit","unit/"): |
| 34 | rule "exe", | 42 | rule "exe", |
| 35 | target file, | 43 | target file, |
| 44 | group "tests", | ||
| 36 | requires "libbu++.a", | 45 | requires "libbu++.a", |
| 37 | set "CXXFLAGS" += "-Isrc", | 46 | set "CXXFLAGS" += "-Isrc", |
| 38 | set "LDFLAGS" += "-L. -lbu++", | 47 | set "LDFLAGS" += "-L. -lbu++", |
| @@ -41,6 +50,7 @@ directoriesIn("src/unit","unit/"): | |||
| 41 | filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): | 50 | filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): |
| 42 | rule "exe", | 51 | rule "exe", |
| 43 | target file, | 52 | target file, |
| 53 | group "tests", | ||
| 44 | requires "libbu++.a", | 54 | requires "libbu++.a", |
| 45 | set "CXXFLAGS" += "-Isrc", | 55 | set "CXXFLAGS" += "-Isrc", |
| 46 | set "LDFLAGS" += "-L. -lbu++", | 56 | set "LDFLAGS" += "-L. -lbu++", |
| @@ -63,3 +73,9 @@ rule "cpp": | |||
| 63 | produces "{re:1}.o", | 73 | produces "{re:1}.o", |
| 64 | requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), | 74 | requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), |
| 65 | perform command("g++ {CXXFLAGS} -c -o {target} {match}") | 75 | perform command("g++ {CXXFLAGS} -c -o {target} {match}") |
| 76 | |||
| 77 | rule "hln": | ||
| 78 | matches regexp("src/(.*)\\.h"), | ||
| 79 | produces "src/bu/{re:1}.h", | ||
| 80 | perform command("ln -s ../{re:1}.h {target}") | ||
| 81 | |||
diff --git a/mkincs.sh b/mkincs.sh new file mode 100755 index 0000000..6f72f89 --- /dev/null +++ b/mkincs.sh | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | cd src/bu | ||
| 4 | rm * | ||
| 5 | for i in ../*.h; do ln -s $i; done | ||
diff --git a/src/exceptions.cpp b/src/exceptions.cpp index a512105..d9f4e70 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp | |||
| @@ -5,6 +5,7 @@ namespace Bu | |||
| 5 | { | 5 | { |
| 6 | subExceptionDef( XmlException ) | 6 | subExceptionDef( XmlException ) |
| 7 | subExceptionDef( FileException ) | 7 | subExceptionDef( FileException ) |
| 8 | subExceptionDef( SocketException ) | ||
| 8 | subExceptionDef( ConnectionException ) | 9 | subExceptionDef( ConnectionException ) |
| 9 | subExceptionDef( PluginException ) | 10 | subExceptionDef( PluginException ) |
| 10 | subExceptionDef( UnsupportedException ) | 11 | subExceptionDef( UnsupportedException ) |
diff --git a/src/exceptions.h b/src/exceptions.h index 3efa19f..f146b73 100644 --- a/src/exceptions.h +++ b/src/exceptions.h | |||
| @@ -8,6 +8,7 @@ namespace Bu | |||
| 8 | { | 8 | { |
| 9 | subExceptionDecl( XmlException ) | 9 | subExceptionDecl( XmlException ) |
| 10 | subExceptionDecl( FileException ) | 10 | subExceptionDecl( FileException ) |
| 11 | subExceptionDecl( SocketException ) | ||
| 11 | subExceptionDecl( ConnectionException ) | 12 | subExceptionDecl( ConnectionException ) |
| 12 | subExceptionDecl( PluginException ) | 13 | subExceptionDecl( PluginException ) |
| 13 | subExceptionDecl( UnsupportedException ) | 14 | subExceptionDecl( UnsupportedException ) |
diff --git a/src/ito.cpp b/src/ito.cpp new file mode 100644 index 0000000..001ca06 --- /dev/null +++ b/src/ito.cpp | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include "ito.h" | ||
| 2 | |||
| 3 | Bu::Ito::Ito() | ||
| 4 | { | ||
| 5 | } | ||
| 6 | |||
| 7 | Bu::Ito::~Ito() | ||
| 8 | { | ||
| 9 | } | ||
| 10 | |||
| 11 | bool Bu::Ito::start() | ||
| 12 | { | ||
| 13 | nHandle = pthread_create( &ptHandle, NULL, threadRunner, this ); | ||
| 14 | |||
| 15 | return true; | ||
| 16 | } | ||
| 17 | |||
| 18 | bool Bu::Ito::stop() | ||
| 19 | { | ||
| 20 | pthread_exit( &ptHandle ); | ||
| 21 | |||
| 22 | return true; | ||
| 23 | } | ||
| 24 | |||
| 25 | void *Bu::Ito::threadRunner( void *pThread ) | ||
| 26 | { | ||
| 27 | return ((Ito *)pThread)->run(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool Bu::Ito::join() | ||
| 31 | { | ||
| 32 | pthread_join( ptHandle, NULL ); | ||
| 33 | return true; | ||
| 34 | } | ||
| 35 | |||
| 36 | void Bu::Ito::yield() | ||
| 37 | { | ||
| 38 | pthread_yield(); | ||
| 39 | } | ||
| 40 | |||
diff --git a/src/ito.h b/src/ito.h new file mode 100644 index 0000000..01253f5 --- /dev/null +++ b/src/ito.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #ifndef ITO_H | ||
| 2 | #define ITO_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | namespace Bu | ||
| 7 | { | ||
| 8 | /** | ||
| 9 | * Simple thread class. This wraps the basic pthread (posix threads) system in | ||
| 10 | * an object oriented sort of way. It allows you to create a class with | ||
| 11 | * standard member variables and callable functions that can be run in it's own | ||
| 12 | * thread, one per class instance. | ||
| 13 | *@author Mike Buland | ||
| 14 | */ | ||
| 15 | class Ito | ||
| 16 | { | ||
| 17 | public: | ||
| 18 | /** | ||
| 19 | * Construct an Ito thread. | ||
| 20 | */ | ||
| 21 | Ito(); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Destroy an Ito thread. | ||
| 25 | */ | ||
| 26 | virtual ~Ito(); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Begin thread execution. This will call the overridden run function, | ||
| 30 | * which will simply execute in it's own thread until the function exits, | ||
| 31 | * the thread is killed, or the thread is cancelled (optionally). The | ||
| 32 | * thread started in this manner has access to all of it's class variables, | ||
| 33 | * but be sure to protect possible multiple-access with ItoMutex objects. | ||
| 34 | *@returns True if starting the thread was successful. False if something | ||
| 35 | * went wrong and the thread has not started. | ||
| 36 | */ | ||
| 37 | bool start(); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Forcibly kill a thread. This is not generally considered a good thing to | ||
| 41 | * do, but in those rare cases you need it, it's invaluable. The problem | ||
| 42 | * with stopping (or killing) a thread is that it stops it the moment you | ||
| 43 | * call stop, no matter what it's doing. The object oriented approach to | ||
| 44 | * this will help clean up any class variables that were used, but anything | ||
| 45 | * not managed as a member variable will probably create a memory leak type | ||
| 46 | * of situation. Instead of stop, consider using cancel, which can be | ||
| 47 | * handled by the running thread in a graceful manner. | ||
| 48 | *@returns True if the thread was stopped, false otherwise. When this | ||
| 49 | * function returns the thread may not have stopped, to ensure that the | ||
| 50 | * thread has really stopped, call join. | ||
| 51 | */ | ||
| 52 | bool stop(); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * The workhorse of the Ito class. This is the function that will run in | ||
| 56 | * the thread, when this function exits the thread dies and is cleaned up | ||
| 57 | * by the system. Make sure to read up on ItoMutex, ItoCondition, and | ||
| 58 | * cancel to see how to control and protect everything you do in a safe way | ||
| 59 | * within this function. | ||
| 60 | *@returns I'm not sure right now, but this is the posix standard form. | ||
| 61 | */ | ||
| 62 | virtual void *run()=0; | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Join the thread in action. This function performs what is commonly | ||
| 66 | * called a thread join. That is that it effectively makes the calling | ||
| 67 | * thread an the Ito thread contained in the called object one in the same, | ||
| 68 | * and pauses the calling thread until the called thread exits. That is, | ||
| 69 | * when called from, say, your main(), mythread.join() will not return until | ||
| 70 | * the thread mythread has exited. This is very handy at the end of | ||
| 71 | * programs to ensure all of your data was cleaned up. | ||
| 72 | *@returns True if the thread was joined, false if the thread couldn't be | ||
| 73 | * joined, usually because it isn't running to begin with. | ||
| 74 | */ | ||
| 75 | bool join(); | ||
| 76 | |||
| 77 | private: | ||
| 78 | pthread_t ptHandle; /**< Internal handle to the posix thread. */ | ||
| 79 | int nHandle; /**< Numeric handle to the posix thread. */ | ||
| 80 | |||
| 81 | protected: | ||
| 82 | /** | ||
| 83 | * This is the hidden-heard of the thread system. While run is what the | ||
| 84 | * user gets to override, and everything said about it is true, this is | ||
| 85 | * the function that actually makes up the thread, it simply calls the | ||
| 86 | * run member function in an OO-friendly way. This is what allows us to | ||
| 87 | * use member variables from within the thread itself. | ||
| 88 | *@param Should always be this. | ||
| 89 | *@returns This is specified by posix, I'm not sure yet. | ||
| 90 | */ | ||
| 91 | static void *threadRunner( void *pThread ); | ||
| 92 | |||
| 93 | void yield(); | ||
| 94 | |||
| 95 | }; | ||
| 96 | } | ||
| 97 | |||
| 98 | #endif | ||
diff --git a/src/itoatom.h b/src/itoatom.h new file mode 100644 index 0000000..96090f2 --- /dev/null +++ b/src/itoatom.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #ifndef ITO_QUEUE_H | ||
| 2 | #define ITO_QUEUE_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | #include "itomutex.h" | ||
| 7 | #include "itocondition.h" | ||
| 8 | |||
| 9 | /** | ||
| 10 | * A thread-safe wrapper class. | ||
| 11 | *@author Mike Buland | ||
| 12 | */ | ||
| 13 | template <class T> | ||
| 14 | class ItoAtom | ||
| 15 | { | ||
| 16 | public: | ||
| 17 | /** | ||
| 18 | * Construct an empty queue. | ||
| 19 | */ | ||
| 20 | ItoAtom() | ||
| 21 | { | ||
| 22 | } | ||
| 23 | |||
| 24 | ItoAtom( const T &src ) : | ||
| 25 | data( src ) | ||
| 26 | { | ||
| 27 | } | ||
| 28 | |||
| 29 | ~ItoQueue() | ||
| 30 | { | ||
| 31 | } | ||
| 32 | |||
| 33 | T get() | ||
| 34 | { | ||
| 35 | mOperate.lock(); | ||
| 36 | mOperate.unlock(); | ||
| 37 | return data; | ||
| 38 | } | ||
| 39 | |||
| 40 | void set( const T &val ) | ||
| 41 | { | ||
| 42 | mOperate.lock(); | ||
| 43 | data = val; | ||
| 44 | cBlock.signal(); | ||
| 45 | mOperate.unlock(); | ||
| 46 | } | ||
| 47 | |||
| 48 | private: | ||
| 49 | Item *pStart; /**< The start of the queue, the next element to dequeue. */ | ||
| 50 | Item *pEnd; /**< The end of the queue, the last element to dequeue. */ | ||
| 51 | |||
| 52 | ItoMutex mOperate; /**< The master mutex, used on all operations. */ | ||
| 53 | ItoCondition cBlock; /**< The condition for blocking dequeues. */ | ||
| 54 | }; | ||
| 55 | |||
| 56 | #endif | ||
diff --git a/src/itocondition.cpp b/src/itocondition.cpp new file mode 100644 index 0000000..d8f5375 --- /dev/null +++ b/src/itocondition.cpp | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #include <sys/time.h> | ||
| 2 | |||
| 3 | #include "itocondition.h" | ||
| 4 | |||
| 5 | Bu::ItoCondition::ItoCondition() | ||
| 6 | { | ||
| 7 | pthread_cond_init( &cond, NULL ); | ||
| 8 | } | ||
| 9 | |||
| 10 | Bu::ItoCondition::~ItoCondition() | ||
| 11 | { | ||
| 12 | pthread_cond_destroy( &cond ); | ||
| 13 | } | ||
| 14 | |||
| 15 | int Bu::ItoCondition::wait() | ||
| 16 | { | ||
| 17 | return pthread_cond_wait( &cond, &mutex ); | ||
| 18 | } | ||
| 19 | |||
| 20 | int Bu::ItoCondition::wait( int nSec, int nUSec ) | ||
| 21 | { | ||
| 22 | struct timeval now; | ||
| 23 | struct timespec timeout; | ||
| 24 | struct timezone tz; | ||
| 25 | |||
| 26 | gettimeofday( &now, &tz ); | ||
| 27 | timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000); | ||
| 28 | timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000; | ||
| 29 | |||
| 30 | return pthread_cond_timedwait( &cond, &mutex, &timeout ); | ||
| 31 | } | ||
| 32 | |||
| 33 | int Bu::ItoCondition::signal() | ||
| 34 | { | ||
| 35 | return pthread_cond_signal( &cond ); | ||
| 36 | } | ||
| 37 | |||
| 38 | int Bu::ItoCondition::broadcast() | ||
| 39 | { | ||
| 40 | return pthread_cond_broadcast( &cond ); | ||
| 41 | } | ||
| 42 | |||
diff --git a/src/itocondition.h b/src/itocondition.h new file mode 100644 index 0000000..4771b22 --- /dev/null +++ b/src/itocondition.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | #ifndef ITO_CONDITION_H | ||
| 2 | #define ITO_CONDITION_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | #include "itomutex.h" | ||
| 7 | |||
| 8 | namespace Bu | ||
| 9 | { | ||
| 10 | /** | ||
| 11 | * Ito condition. This is a fairly simple condition mechanism. As you may | ||
| 12 | * notice this class inherits from the ItoMutex class, this is because all | ||
| 13 | * conditions must be within a locked block. The standard usage of a condition | ||
| 14 | * is to pause one thread, perhaps indefinately, until another thread signals | ||
| 15 | * that it is alright to procede. | ||
| 16 | * <br> | ||
| 17 | * Standard usage for the thread that wants to wait is as follows: | ||
| 18 | * <pre> | ||
| 19 | * ItoCondition cond; | ||
| 20 | * ... // Perform setup and enter your run loop | ||
| 21 | * cond.lock(); | ||
| 22 | * while( !isFinished() ) // Could be anything you're waiting for | ||
| 23 | * cond.wait(); | ||
| 24 | * ... // Take care of what you have to. | ||
| 25 | * cond.unlock(); | ||
| 26 | * </pre> | ||
| 27 | * The usage for the triggering thread is much simpler, when it needs to tell | ||
| 28 | * the others that it's time to grab some data it calls either signal or | ||
| 29 | * broadcast. See both of those functions for the difference. | ||
| 30 | *@author Mike Buland | ||
| 31 | */ | ||
| 32 | class ItoCondition : public ItoMutex | ||
| 33 | { | ||
| 34 | public: | ||
| 35 | /** | ||
| 36 | * Create a condition. | ||
| 37 | */ | ||
| 38 | ItoCondition(); | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Destroy a condition. | ||
| 42 | */ | ||
| 43 | ~ItoCondition(); | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Wait forever, or until signalled. This has to be called from within a | ||
| 47 | * locked section, i.e. before calling this this object's lock function | ||
| 48 | * should be called. | ||
| 49 | */ | ||
| 50 | int wait(); | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Wait for a maximum of nSec seconds and nUSec micro-seconds or until | ||
| 54 | * signalled. This is a little more friendly function if you want to | ||
| 55 | * perform other operations in the thrad loop that calls this function. | ||
| 56 | * Like the other wait function, this must be inside a locked section. | ||
| 57 | *@param nSec The seconds to wait. | ||
| 58 | *@param nUSec the micro-seconds to wait. | ||
| 59 | */ | ||
| 60 | int wait( int nSec, int nUSec ); | ||
| 61 | |||
| 62 | /** | ||
| 63 | * Notify the next thread waiting on this condition that they can go ahead. | ||
| 64 | * This only signals one thread, the next one in the condition queue, that | ||
| 65 | * it is safe to procede with whatever operation was being waited on. | ||
| 66 | */ | ||
| 67 | int signal(); | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Notify all threads waiting on this condition that they can go ahead now. | ||
| 71 | * This function is slower than signal, but more effective in certain | ||
| 72 | * situations where you may not know how many threads should be activated. | ||
| 73 | */ | ||
| 74 | int broadcast(); | ||
| 75 | |||
| 76 | private: | ||
| 77 | pthread_cond_t cond; /**< Internal condition reference. */ | ||
| 78 | }; | ||
| 79 | } | ||
| 80 | |||
| 81 | #endif | ||
diff --git a/src/itomutex.cpp b/src/itomutex.cpp new file mode 100644 index 0000000..dc51af9 --- /dev/null +++ b/src/itomutex.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #include "itomutex.h" | ||
| 2 | |||
| 3 | Bu::ItoMutex::ItoMutex() | ||
| 4 | { | ||
| 5 | pthread_mutex_init( &mutex, NULL ); | ||
| 6 | } | ||
| 7 | |||
| 8 | Bu::ItoMutex::~ItoMutex() | ||
| 9 | { | ||
| 10 | pthread_mutex_destroy( &mutex ); | ||
| 11 | } | ||
| 12 | |||
| 13 | int Bu::ItoMutex::lock() | ||
| 14 | { | ||
| 15 | return pthread_mutex_lock( &mutex ); | ||
| 16 | } | ||
| 17 | |||
| 18 | int Bu::ItoMutex::unlock() | ||
| 19 | { | ||
| 20 | return pthread_mutex_unlock( &mutex ); | ||
| 21 | } | ||
| 22 | |||
| 23 | int Bu::ItoMutex::trylock() | ||
| 24 | { | ||
| 25 | return pthread_mutex_trylock( &mutex ); | ||
| 26 | } | ||
| 27 | |||
diff --git a/src/itomutex.h b/src/itomutex.h new file mode 100644 index 0000000..80956b8 --- /dev/null +++ b/src/itomutex.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | #ifndef ITO_MUTEX_H | ||
| 2 | #define ITO_MUTEX_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | namespace Bu | ||
| 7 | { | ||
| 8 | /** | ||
| 9 | * Simple mutex wrapper. Currently this doesn't do anything extra for you | ||
| 10 | * except keep all of the functionality together in an OO sorta' way and keep | ||
| 11 | * you from having to worry about cleaning up your mutexes properly, or initing | ||
| 12 | * them. | ||
| 13 | *@author Mike Buland | ||
| 14 | */ | ||
| 15 | class ItoMutex | ||
| 16 | { | ||
| 17 | public: | ||
| 18 | /** | ||
| 19 | * Create an unlocked mutex. | ||
| 20 | */ | ||
| 21 | ItoMutex(); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Destroy a mutex. This can only be done when a mutex is unlocked. | ||
| 25 | * Failure to unlock before destroying a mutex object could cause it to | ||
| 26 | * wait for the mutex to unlock, the odds of which are usually farily low | ||
| 27 | * at deconstruction time. | ||
| 28 | */ | ||
| 29 | ~ItoMutex(); | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Lock the mutex. This causes all future calls to lock on this instance | ||
| 33 | * of mutex to block until the first thread that called mutex unlocks it. | ||
| 34 | * At that point the next thread that called lock will get a chance to go | ||
| 35 | * to work. Because of the nature of a mutex lock it is a very bad idea to | ||
| 36 | * do any kind of serious or rather time consuming computation within a | ||
| 37 | * locked section. This can cause thread-deadlock and your program may | ||
| 38 | * hang. | ||
| 39 | */ | ||
| 40 | int lock(); | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Unlock the mutex. This allows the next thread that asked for a lock to | ||
| 44 | * lock the mutex and continue with execution. | ||
| 45 | */ | ||
| 46 | int unlock(); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Try to lock the mutex. This is the option to go with if you cannot avoid | ||
| 50 | * putting lengthy operations within a locked section. trylock will attempt | ||
| 51 | * to lock the mutex, if the mutex is already locked this function returns | ||
| 52 | * immediately with an error code. | ||
| 53 | */ | ||
| 54 | int trylock(); | ||
| 55 | |||
| 56 | protected: | ||
| 57 | pthread_mutex_t mutex; /**< The internal mutex reference. */ | ||
| 58 | }; | ||
| 59 | } | ||
| 60 | |||
| 61 | #endif | ||
diff --git a/src/itoqueue.h b/src/itoqueue.h new file mode 100644 index 0000000..322698d --- /dev/null +++ b/src/itoqueue.h | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | #ifndef ITO_QUEUE_H | ||
| 2 | #define ITO_QUEUE_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | #include "itomutex.h" | ||
| 7 | #include "itocondition.h" | ||
| 8 | |||
| 9 | namespace Bu | ||
| 10 | { | ||
| 11 | /** | ||
| 12 | * A thread-safe queue class. This class is a very simple queue with some cool | ||
| 13 | * extra functionality for use with the Ito system. The main extra that it | ||
| 14 | * provides is the option to either dequeue without blocking, with infinite | ||
| 15 | * blocking, or with timed blocking, which will return a value if something is | ||
| 16 | * enqueued within the specified time limit, or NULL if the time limit is | ||
| 17 | * exceded. | ||
| 18 | *@author Mike Buland | ||
| 19 | */ | ||
| 20 | template <class T> | ||
| 21 | class ItoQueue | ||
| 22 | { | ||
| 23 | private: | ||
| 24 | /** | ||
| 25 | * Helper struct. Keeps track of linked-list items for the queue data. | ||
| 26 | */ | ||
| 27 | typedef struct Item | ||
| 28 | { | ||
| 29 | T pData; | ||
| 30 | Item *pNext; | ||
| 31 | } Item; | ||
| 32 | |||
| 33 | public: | ||
| 34 | /** | ||
| 35 | * Construct an empty queue. | ||
| 36 | */ | ||
| 37 | ItoQueue() : | ||
| 38 | pStart( NULL ), | ||
| 39 | pEnd( NULL ), | ||
| 40 | nSize( 0 ) | ||
| 41 | { | ||
| 42 | } | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Destroy the queue. This function will simply free all contained | ||
| 46 | * structures. If you stored pointers in the queue, this will lose the | ||
| 47 | * pointers without cleaning up the memory they pointed to. Make sure | ||
| 48 | * you're queue is empty before allowing it to be destroyed! | ||
| 49 | */ | ||
| 50 | ~ItoQueue() | ||
| 51 | { | ||
| 52 | Item *pCur = pStart; | ||
| 53 | while( pCur ) | ||
| 54 | { | ||
| 55 | Item *pTmp = pCur->pNext; | ||
| 56 | delete pCur; | ||
| 57 | pCur = pTmp; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Enqueue a pieces of data. The new data will go at the end of the queue, | ||
| 63 | * and unless another piece of data is enqueued, will be the last piece of | ||
| 64 | * data to be dequeued. | ||
| 65 | *@param pData The data to enqueue. If this is not a primitive data type | ||
| 66 | * it's probably best to use a pointer type. | ||
| 67 | */ | ||
| 68 | void enqueue( T pData ) | ||
| 69 | { | ||
| 70 | mOperate.lock(); | ||
| 71 | |||
| 72 | if( pStart == NULL ) | ||
| 73 | { | ||
| 74 | pStart = pEnd = new Item; | ||
| 75 | pStart->pData = pData; | ||
| 76 | pStart->pNext = NULL; | ||
| 77 | nSize++; | ||
| 78 | } | ||
| 79 | else | ||
| 80 | { | ||
| 81 | pEnd->pNext = new Item; | ||
| 82 | pEnd = pEnd->pNext; | ||
| 83 | pEnd->pData = pData; | ||
| 84 | pEnd->pNext = NULL; | ||
| 85 | nSize++; | ||
| 86 | } | ||
| 87 | |||
| 88 | cBlock.signal(); | ||
| 89 | |||
| 90 | mOperate.unlock(); | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Dequeue the first item from the queue. This function can operate in two | ||
| 95 | * different modes, blocking and non-blocking. In non-blocking mode it will | ||
| 96 | * return immediately weather there was data in the queue or not. If there | ||
| 97 | * was data it will remove it from the queue and return it to the caller. | ||
| 98 | * In blocking mode it will block forever wating for data to be enqueued. | ||
| 99 | * When data finally is enqueued this function will return immediately with | ||
| 100 | * the new data. The only way this function should ever return a null in | ||
| 101 | * blocking mode is if the calling thread was cancelled. It's probably a | ||
| 102 | * good idea to check for NULL return values even if you use blocking, just | ||
| 103 | * to be on the safe side. | ||
| 104 | *@param bBlock Set to true to enable blocking, leave as false to work in | ||
| 105 | * non-blocking mode. | ||
| 106 | *@returns The next piece of data in the queue, or NULL if no data was in | ||
| 107 | * the queue. | ||
| 108 | */ | ||
| 109 | T dequeue( bool bBlock=false ) | ||
| 110 | { | ||
| 111 | mOperate.lock(); | ||
| 112 | if( pStart == NULL ) | ||
| 113 | { | ||
| 114 | mOperate.unlock(); | ||
| 115 | |||
| 116 | if( bBlock ) | ||
| 117 | { | ||
| 118 | cBlock.lock(); | ||
| 119 | |||
| 120 | while( pStart == NULL ) | ||
| 121 | cBlock.wait(); | ||
| 122 | |||
| 123 | T tmp = dequeue( false ); | ||
| 124 | |||
| 125 | cBlock.unlock(); | ||
| 126 | return tmp; | ||
| 127 | |||
| 128 | } | ||
| 129 | |||
| 130 | return NULL; | ||
| 131 | } | ||
| 132 | else | ||
| 133 | { | ||
| 134 | T pTmp = pStart->pData; | ||
| 135 | Item *pDel = pStart; | ||
| 136 | pStart = pStart->pNext; | ||
| 137 | delete pDel; | ||
| 138 | nSize--; | ||
| 139 | |||
| 140 | mOperate.unlock(); | ||
| 141 | return pTmp; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Operates just like the other dequeue function in blocking mode with one | ||
| 147 | * twist. This function will block for at most nSec seconds and nUSec | ||
| 148 | * micro-seconds. If the timer is up and no data is available, this will | ||
| 149 | * just return NULL. If data is enqueued before the timeout expires, it | ||
| 150 | * will dequeue and exit immediately. | ||
| 151 | *@param nSec The number of seconds to wait, max. | ||
| 152 | *@param nUSec The number of micro-seconds to wait, max. | ||
| 153 | *@returns The next piece of data in the queue, or NULL if the timeout was | ||
| 154 | * exceeded. | ||
| 155 | */ | ||
| 156 | T dequeue( int nSec, int nUSec ) | ||
| 157 | { | ||
| 158 | mOperate.lock(); | ||
| 159 | if( pStart == NULL ) | ||
| 160 | { | ||
| 161 | mOperate.unlock(); | ||
| 162 | |||
| 163 | cBlock.lock(); | ||
| 164 | |||
| 165 | cBlock.wait( nSec, nUSec ); | ||
| 166 | |||
| 167 | if( pStart == NULL ) | ||
| 168 | { | ||
| 169 | cBlock.unlock(); | ||
| 170 | return NULL; | ||
| 171 | } | ||
| 172 | |||
| 173 | mOperate.lock(); | ||
| 174 | T pTmp = pStart->pData; | ||
| 175 | Item *pDel = pStart; | ||
| 176 | pStart = pStart->pNext; | ||
| 177 | delete pDel; | ||
| 178 | nSize--; | ||
| 179 | mOperate.unlock(); | ||
| 180 | |||
| 181 | cBlock.unlock(); | ||
| 182 | return pTmp; | ||
| 183 | } | ||
| 184 | else | ||
| 185 | { | ||
| 186 | T pTmp = pStart->pData; | ||
| 187 | Item *pDel = pStart; | ||
| 188 | pStart = pStart->pNext; | ||
| 189 | delete pDel; | ||
| 190 | nSize--; | ||
| 191 | |||
| 192 | mOperate.unlock(); | ||
| 193 | return pTmp; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * Checks to see if the queue has data in it or not. Note that there is no | ||
| 199 | * function to determine the length of the queue. This data isn't kept | ||
| 200 | * track of. If you really need to know, fix this. | ||
| 201 | *@returns True if the queue is empty, false if it has data in it. | ||
| 202 | */ | ||
| 203 | bool isEmpty() | ||
| 204 | { | ||
| 205 | mOperate.lock(); | ||
| 206 | bool bEmpty = (pStart == NULL ); | ||
| 207 | mOperate.unlock(); | ||
| 208 | |||
| 209 | return bEmpty; | ||
| 210 | } | ||
| 211 | |||
| 212 | long getSize() | ||
| 213 | { | ||
| 214 | mOperate.lock(); | ||
| 215 | long nRet = nSize; | ||
| 216 | mOperate.unlock(); | ||
| 217 | |||
| 218 | return nRet; | ||
| 219 | } | ||
| 220 | |||
| 221 | private: | ||
| 222 | Item *pStart; /**< The start of the queue, the next element to dequeue. */ | ||
| 223 | Item *pEnd; /**< The end of the queue, the last element to dequeue. */ | ||
| 224 | long nSize; /**< The number of items in the queue. */ | ||
| 225 | |||
| 226 | ItoMutex mOperate; /**< The master mutex, used on all operations. */ | ||
| 227 | ItoCondition cBlock; /**< The condition for blocking dequeues. */ | ||
| 228 | }; | ||
| 229 | } | ||
| 230 | |||
| 231 | #endif | ||
diff --git a/src/main.dox b/src/main.dox new file mode 100644 index 0000000..668d2e3 --- /dev/null +++ b/src/main.dox | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | /** | ||
| 2 | *@mainpage libbu++ utility library | ||
| 3 | * | ||
| 4 | *@section secIntro Introduction | ||
| 5 | * | ||
| 6 | * Libbu++ is a C++ library of general utility classes and functions. They | ||
| 7 | * cover a wide range of topics from streams and sockets to data structures to | ||
| 8 | * data serialization and xml handling to threading. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | /** | ||
| 13 | *@namespace Bu The core libbu++ namespace, to ensure things don't get muddied. | ||
| 14 | */ | ||
diff --git a/src/serversocket.cpp b/src/serversocket.cpp new file mode 100644 index 0000000..c53c80d --- /dev/null +++ b/src/serversocket.cpp | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | #include <time.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <errno.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <unistd.h> | ||
| 7 | #include <sys/types.h> | ||
| 8 | #include <sys/socket.h> | ||
| 9 | #include <termios.h> | ||
| 10 | #include <netinet/in.h> | ||
| 11 | #include <netdb.h> | ||
| 12 | #include <arpa/inet.h> | ||
| 13 | #include <fcntl.h> | ||
| 14 | #include "serversocket.h" | ||
| 15 | #include "exceptions.h" | ||
| 16 | |||
| 17 | Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : | ||
| 18 | nPort( nPort ) | ||
| 19 | { | ||
| 20 | /* Create the socket and set it up to accept connections. */ | ||
| 21 | struct sockaddr_in name; | ||
| 22 | |||
| 23 | /* Give the socket a name. */ | ||
| 24 | name.sin_family = AF_INET; | ||
| 25 | name.sin_port = htons( nPort ); | ||
| 26 | |||
| 27 | // I think this specifies who we will accept connections from, | ||
| 28 | // a good thing to make configurable later on | ||
| 29 | name.sin_addr.s_addr = htonl( INADDR_ANY ); | ||
| 30 | |||
| 31 | startServer( name, nPoolSize ); | ||
| 32 | } | ||
| 33 | |||
| 34 | Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : | ||
| 35 | nPort( nPort ) | ||
| 36 | { | ||
| 37 | /* Create the socket and set it up to accept connections. */ | ||
| 38 | struct sockaddr_in name; | ||
| 39 | |||
| 40 | /* Give the socket a name. */ | ||
| 41 | name.sin_family = AF_INET; | ||
| 42 | name.sin_port = htons( nPort ); | ||
| 43 | |||
| 44 | inet_aton( sAddr.getStr(), &name.sin_addr ); | ||
| 45 | |||
| 46 | startServer( name, nPoolSize ); | ||
| 47 | } | ||
| 48 | |||
| 49 | Bu::ServerSocket::~ServerSocket() | ||
| 50 | { | ||
| 51 | } | ||
| 52 | |||
| 53 | void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) | ||
| 54 | { | ||
| 55 | /* Create the socket. */ | ||
| 56 | nServer = socket( PF_INET, SOCK_STREAM, 0 ); | ||
| 57 | if( nServer < 0 ) | ||
| 58 | { | ||
| 59 | throw Bu::SocketException("Couldn't create a listen socket."); | ||
| 60 | } | ||
| 61 | |||
| 62 | int opt = 1; | ||
| 63 | setsockopt( | ||
| 64 | nServer, | ||
| 65 | SOL_SOCKET, | ||
| 66 | SO_REUSEADDR, | ||
| 67 | (char *)&opt, | ||
| 68 | sizeof( opt ) | ||
| 69 | ); | ||
| 70 | |||
| 71 | if( bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) | ||
| 72 | { | ||
| 73 | throw Bu::SocketException("Couldn't bind to the listen socket."); | ||
| 74 | } | ||
| 75 | |||
| 76 | if( listen( nServer, nPoolSize ) < 0 ) | ||
| 77 | { | ||
| 78 | throw Bu::SocketException( | ||
| 79 | "Couldn't begin listening to the server socket." | ||
| 80 | ); | ||
| 81 | } | ||
| 82 | |||
| 83 | FD_ZERO( &fdActive ); | ||
| 84 | /* Initialize the set of active sockets. */ | ||
| 85 | FD_SET( nServer, &fdActive ); | ||
| 86 | } | ||
| 87 | |||
| 88 | int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | ||
| 89 | { | ||
| 90 | fd_set fdRead = fdActive; | ||
| 91 | |||
| 92 | struct timeval xT; | ||
| 93 | |||
| 94 | xT.tv_sec = nTimeoutSec; | ||
| 95 | xT.tv_usec = nTimeoutUSec; | ||
| 96 | |||
| 97 | if( TEMP_FAILURE_RETRY(select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) | ||
| 98 | { | ||
| 99 | throw SocketException( | ||
| 100 | "Error scanning for new connections: %s", strerror( errno ) | ||
| 101 | ); | ||
| 102 | } | ||
| 103 | |||
| 104 | if( FD_ISSET( nServer, &fdRead ) ) | ||
| 105 | { | ||
| 106 | struct sockaddr_in clientname; | ||
| 107 | size_t size; | ||
| 108 | int nClient; | ||
| 109 | |||
| 110 | size = sizeof( clientname ); | ||
| 111 | #ifdef __CYGWIN__ | ||
| 112 | nClient = ::accept( nServer, (struct sockaddr *)&clientname, | ||
| 113 | (int *)&size | ||
| 114 | ); | ||
| 115 | #else | ||
| 116 | nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); | ||
| 117 | #endif | ||
| 118 | if( nClient < 0 ) | ||
| 119 | { | ||
| 120 | throw SocketException( | ||
| 121 | "Error accepting a new connection: %s", strerror( errno ) | ||
| 122 | ); | ||
| 123 | } | ||
| 124 | char tmpa[20]; | ||
| 125 | inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); | ||
| 126 | //"New connection from host %s, port %hd.", | ||
| 127 | // tmpa, ntohs (clientname.sin_port) ); | ||
| 128 | |||
| 129 | { | ||
| 130 | int flags; | ||
| 131 | |||
| 132 | flags = fcntl( nClient, F_GETFL, 0 ); | ||
| 133 | flags |= O_NONBLOCK; | ||
| 134 | if( fcntl( nClient, F_SETFL, flags ) < 0) | ||
| 135 | { | ||
| 136 | throw SocketException( | ||
| 137 | "Error setting option on client socket: %s", | ||
| 138 | strerror( errno ) | ||
| 139 | ); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return nClient; | ||
| 144 | } | ||
| 145 | |||
| 146 | return -1; | ||
| 147 | } | ||
| 148 | |||
diff --git a/src/serversocket.h b/src/serversocket.h new file mode 100644 index 0000000..9a26e2d --- /dev/null +++ b/src/serversocket.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #ifndef SERVER_SOCKET_H | ||
| 2 | #define SERVER_SOCKET_H | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include "fstring.h" | ||
| 6 | #include "socket.h" | ||
| 7 | |||
| 8 | namespace Bu | ||
| 9 | { | ||
| 10 | /** | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | class ServerSocket | ||
| 14 | { | ||
| 15 | public: | ||
| 16 | ServerSocket( int nPort, int nPoolSize=40 ); | ||
| 17 | ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); | ||
| 18 | virtual ~ServerSocket(); | ||
| 19 | |||
| 20 | int accept( int nTimeoutSec, int nTimeoutUSec ); | ||
| 21 | |||
| 22 | private: | ||
| 23 | void startServer( struct sockaddr_in &name, int nPoolSize ); | ||
| 24 | |||
| 25 | fd_set fdActive; | ||
| 26 | int nServer; | ||
| 27 | int nPort; | ||
| 28 | }; | ||
| 29 | } | ||
| 30 | |||
| 31 | #endif | ||
diff --git a/src/socket.cpp b/src/socket.cpp index c4f914b..455b5c8 100644 --- a/src/socket.cpp +++ b/src/socket.cpp | |||
| @@ -118,6 +118,7 @@ void Bu::Socket::close() | |||
| 118 | //} | 118 | //} |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | /* | ||
| 121 | void Bu::Socket::read() | 122 | void Bu::Socket::read() |
| 122 | { | 123 | { |
| 123 | char buffer[RBS]; | 124 | char buffer[RBS]; |
| @@ -132,7 +133,6 @@ void Bu::Socket::read() | |||
| 132 | if( nbytes < 0 && errno != 0 && errno != EAGAIN ) | 133 | if( nbytes < 0 && errno != 0 && errno != EAGAIN ) |
| 133 | { | 134 | { |
| 134 | //printf("errno: %d, %s\n", errno, strerror( errno ) ); | 135 | //printf("errno: %d, %s\n", errno, strerror( errno ) ); |
| 135 | /* Read error. */ | ||
| 136 | //perror("readInput"); | 136 | //perror("readInput"); |
| 137 | throw ConnectionException( | 137 | throw ConnectionException( |
| 138 | excodeReadError, | 138 | excodeReadError, |
| @@ -146,15 +146,13 @@ void Bu::Socket::read() | |||
| 146 | break; | 146 | break; |
| 147 | nTotalRead += nbytes; | 147 | nTotalRead += nbytes; |
| 148 | sReadBuf.append( buffer, nbytes ); | 148 | sReadBuf.append( buffer, nbytes ); |
| 149 | /* Data read. */ | ||
| 150 | if( nbytes < RBS ) | 149 | if( nbytes < RBS ) |
| 151 | { | 150 | { |
| 152 | break; | 151 | break; |
| 153 | } | 152 | } |
| 154 | 153 | ||
| 155 | /* New test, if data is divisible by RBS bytes on some libs the | 154 | // New test, if data is divisible by RBS bytes on some libs the |
| 156 | * read could block, this keeps it from happening. | 155 | // read could block, this keeps it from happening. |
| 157 | */ | ||
| 158 | { | 156 | { |
| 159 | fd_set rfds; | 157 | fd_set rfds; |
| 160 | FD_ZERO(&rfds); | 158 | FD_ZERO(&rfds); |
| @@ -171,13 +169,7 @@ void Bu::Socket::read() | |||
| 171 | } | 169 | } |
| 172 | } | 170 | } |
| 173 | } | 171 | } |
| 174 | 172 | }*/ | |
| 175 | /* | ||
| 176 | if( pProtocol != NULL && nTotalRead > 0 ) | ||
| 177 | { | ||
| 178 | pProtocol->onNewData(); | ||
| 179 | }*/ | ||
| 180 | } | ||
| 181 | 173 | ||
| 182 | size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | 174 | size_t Bu::Socket::read( void *pBuf, size_t nBytes ) |
| 183 | { | 175 | { |
diff --git a/src/socket.h b/src/socket.h index 3d0125d..568cad6 100644 --- a/src/socket.h +++ b/src/socket.h | |||
| @@ -19,7 +19,7 @@ namespace Bu | |||
| 19 | virtual ~Socket(); | 19 | virtual ~Socket(); |
| 20 | 20 | ||
| 21 | virtual void close(); | 21 | virtual void close(); |
| 22 | virtual void read(); | 22 | //virtual void read(); |
| 23 | virtual size_t read( void *pBuf, size_t nBytes ); | 23 | virtual size_t read( void *pBuf, size_t nBytes ); |
| 24 | virtual size_t write( const void *pBuf, size_t nBytes ); | 24 | virtual size_t write( const void *pBuf, size_t nBytes ); |
| 25 | 25 | ||
| @@ -33,6 +33,8 @@ namespace Bu | |||
| 33 | virtual bool canWrite(); | 33 | virtual bool canWrite(); |
| 34 | virtual bool canSeek(); | 34 | virtual bool canSeek(); |
| 35 | 35 | ||
| 36 | |||
| 37 | |||
| 36 | private: | 38 | private: |
| 37 | int nSocket; | 39 | int nSocket; |
| 38 | bool bActive; | 40 | bool bActive; |
diff --git a/src/tests/itoqueue1.cpp b/src/tests/itoqueue1.cpp new file mode 100644 index 0000000..f73f4d3 --- /dev/null +++ b/src/tests/itoqueue1.cpp | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | #include <string> | ||
| 2 | #include "bu/ito.h" | ||
| 3 | #include "bu/itoqueue.h" | ||
| 4 | |||
| 5 | class Reader : public Bu::Ito | ||
| 6 | { | ||
| 7 | public: | ||
| 8 | Reader( Bu::ItoQueue<std::string *> &q, int id ) : | ||
| 9 | q( q ), | ||
| 10 | id( id ) | ||
| 11 | { | ||
| 12 | } | ||
| 13 | |||
| 14 | void *run() | ||
| 15 | { | ||
| 16 | for( int i = 0; i < 10; i++ ) | ||
| 17 | { | ||
| 18 | std::string *pStr = q.dequeue( true ); | ||
| 19 | if( pStr == NULL ) | ||
| 20 | { | ||
| 21 | printf("Null received...\n"); | ||
| 22 | } | ||
| 23 | else | ||
| 24 | { | ||
| 25 | printf("[%d] read: %s\n", id, pStr->c_str() ); | ||
| 26 | delete pStr; | ||
| 27 | } | ||
| 28 | usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) ); | ||
| 29 | } | ||
| 30 | |||
| 31 | return NULL; | ||
| 32 | } | ||
| 33 | |||
| 34 | private: | ||
| 35 | Bu::ItoQueue<std::string *> &q; | ||
| 36 | int id; | ||
| 37 | }; | ||
| 38 | |||
| 39 | class Writer : public Bu::Ito | ||
| 40 | { | ||
| 41 | public: | ||
| 42 | Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) : | ||
| 43 | q( q ), | ||
| 44 | strbase( strbase ), | ||
| 45 | id( id ) | ||
| 46 | { | ||
| 47 | } | ||
| 48 | |||
| 49 | void *run() | ||
| 50 | { | ||
| 51 | for( int i = 0; i < 11; i++ ) | ||
| 52 | { | ||
| 53 | usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) ); | ||
| 54 | q.enqueue( new std::string( strbase ) ); | ||
| 55 | printf("[%d] write: %s\n", id, strbase ); | ||
| 56 | } | ||
| 57 | |||
| 58 | return NULL; | ||
| 59 | } | ||
| 60 | |||
| 61 | private: | ||
| 62 | Bu::ItoQueue<std::string *> &q; | ||
| 63 | const char *strbase; | ||
| 64 | int id; | ||
| 65 | }; | ||
| 66 | |||
| 67 | int main() | ||
| 68 | { | ||
| 69 | Writer *wr[5]; | ||
| 70 | Reader *rd[5]; | ||
| 71 | const char bob[][7]={ | ||
| 72 | {"Test 1"}, | ||
| 73 | {"Test 2"}, | ||
| 74 | {"Test 3"}, | ||
| 75 | {"Test 4"}, | ||
| 76 | {"Test 5"} | ||
| 77 | }; | ||
| 78 | |||
| 79 | Bu::ItoQueue<std::string *> q; | ||
| 80 | |||
| 81 | for( int j = 0; j < 5; j++ ) | ||
| 82 | { | ||
| 83 | wr[j] = new Writer( q, j, bob[j] ); | ||
| 84 | rd[j] = new Reader( q, j ); | ||
| 85 | } | ||
| 86 | |||
| 87 | for( int j = 0; j < 5; j++ ) | ||
| 88 | { | ||
| 89 | rd[j]->start(); | ||
| 90 | } | ||
| 91 | |||
| 92 | for( int j = 0; j < 5; j++ ) | ||
| 93 | { | ||
| 94 | wr[j]->start(); | ||
| 95 | } | ||
| 96 | |||
| 97 | for( int j = 0; j < 5; j++ ) | ||
| 98 | { | ||
| 99 | rd[j]->join(); | ||
| 100 | } | ||
| 101 | |||
| 102 | for( int j = 0; j < 5; j++ ) | ||
| 103 | { | ||
| 104 | delete wr[j]; | ||
| 105 | delete rd[j]; | ||
| 106 | } | ||
| 107 | |||
| 108 | return 0; | ||
| 109 | } | ||
| 110 | |||
diff --git a/src/tests/itoqueue2.cpp b/src/tests/itoqueue2.cpp new file mode 100644 index 0000000..f4b5e19 --- /dev/null +++ b/src/tests/itoqueue2.cpp | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #include <string> | ||
| 2 | #include "bu/ito.h" | ||
| 3 | #include "bu/itoqueue.h" | ||
| 4 | #include <errno.h> | ||
| 5 | |||
| 6 | class Reader : public Bu::Ito | ||
| 7 | { | ||
| 8 | public: | ||
| 9 | Reader( Bu::ItoQueue<std::string *> &q, int id ) : | ||
| 10 | q( q ), | ||
| 11 | id( id ) | ||
| 12 | { | ||
| 13 | } | ||
| 14 | |||
| 15 | void *run() | ||
| 16 | { | ||
| 17 | for( int i = 0; i < 10; i++ ) | ||
| 18 | { | ||
| 19 | std::string *pStr = q.dequeue( 0, 500000 ); | ||
| 20 | if( pStr == NULL ) | ||
| 21 | { | ||
| 22 | printf("Null received...\n"); | ||
| 23 | i--; | ||
| 24 | } | ||
| 25 | else | ||
| 26 | { | ||
| 27 | printf("[%d] read: %s\n", id, pStr->c_str() ); | ||
| 28 | delete pStr; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | return NULL; | ||
| 33 | } | ||
| 34 | |||
| 35 | private: | ||
| 36 | Bu::ItoQueue<std::string *> &q; | ||
| 37 | int id; | ||
| 38 | }; | ||
| 39 | |||
| 40 | class Writer : public Bu::Ito | ||
| 41 | { | ||
| 42 | public: | ||
| 43 | Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) : | ||
| 44 | q( q ), | ||
| 45 | strbase( strbase ), | ||
| 46 | id( id ) | ||
| 47 | { | ||
| 48 | } | ||
| 49 | |||
| 50 | void *run() | ||
| 51 | { | ||
| 52 | for( int i = 0; i < 11; i++ ) | ||
| 53 | { | ||
| 54 | sleep( 2 ); | ||
| 55 | printf("[%d] write: %s\n", id, strbase ); | ||
| 56 | q.enqueue( new std::string( strbase ) ); | ||
| 57 | } | ||
| 58 | |||
| 59 | return NULL; | ||
| 60 | } | ||
| 61 | |||
| 62 | private: | ||
| 63 | Bu::ItoQueue<std::string *> &q; | ||
| 64 | const char *strbase; | ||
| 65 | int id; | ||
| 66 | }; | ||
| 67 | |||
| 68 | int main() | ||
| 69 | { | ||
| 70 | printf("ETIMEDOUT: %d\n", ETIMEDOUT ); | ||
| 71 | Bu::ItoQueue<std::string *> q; | ||
| 72 | Writer wr( q, 0, "writer" ); | ||
| 73 | Reader rd( q, 0 ); | ||
| 74 | |||
| 75 | rd.start(); | ||
| 76 | wr.start(); | ||
| 77 | |||
| 78 | rd.join(); | ||
| 79 | wr.join(); | ||
| 80 | |||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
