Alexandre Lision | ddd731e | 2014-01-31 11:50:08 -0500 | [diff] [blame] | 1 | // Copyright (C) 1999-2005 Open Source Telecom Corporation. |
| 2 | // Copyright (C) 2006-2010 David Sugar, Tycho Softworks. |
| 3 | // |
| 4 | // This program is free software; you can redistribute it and/or modify |
| 5 | // it under the terms of the GNU General Public License as published by |
| 6 | // the Free Software Foundation; either version 3 of the License, or |
| 7 | // (at your option) any later version. |
| 8 | // |
| 9 | // This program is distributed in the hope that it will be useful, |
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | // GNU General Public License for more details. |
| 13 | // |
| 14 | // You should have received a copy of the GNU General Public License |
| 15 | // along with this program; if not, write to the Free Software |
| 16 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 17 | |
| 18 | /** |
| 19 | * @file commoncpp/thread.h |
| 20 | * @short Common C++ thread class and sychronization objects |
| 21 | **/ |
| 22 | |
| 23 | #ifndef COMMONCPP_THREAD_H_ |
| 24 | #define COMMONCPP_THREAD_H_ |
| 25 | |
| 26 | #ifndef COMMONCPP_CONFIG_H_ |
| 27 | #include <commoncpp/config.h> |
| 28 | #endif |
| 29 | |
| 30 | #ifndef COMMONCPP_STRING_H_ |
| 31 | #include <commoncpp/string.h> |
| 32 | #endif |
| 33 | |
| 34 | #define ENTER_CRITICAL enterMutex(); |
| 35 | #define LEAVE_CRITICAL leaveMutex(); |
| 36 | |
| 37 | NAMESPACE_COMMONCPP |
| 38 | |
| 39 | class __EXPORT Mutex : protected ucommon::RecursiveMutex |
| 40 | { |
| 41 | public: |
| 42 | inline Mutex() : RecursiveMutex() {}; |
| 43 | |
| 44 | inline void enterMutex(void) |
| 45 | {RecursiveMutex::lock();}; |
| 46 | |
| 47 | inline void leaveMutex(void) |
| 48 | {RecursiveMutex::release();}; |
| 49 | |
| 50 | inline bool tryEnterMutex(void) |
| 51 | {return RecursiveMutex::lock(0l);}; |
| 52 | |
| 53 | inline void enter(void) |
| 54 | {RecursiveMutex::lock();}; |
| 55 | |
| 56 | inline void leave(void) |
| 57 | {RecursiveMutex::release();}; |
| 58 | |
| 59 | inline bool test(void) |
| 60 | {return RecursiveMutex::lock(0l);}; |
| 61 | |
| 62 | }; |
| 63 | |
| 64 | /** |
| 65 | * The Mutex Counter is a counter variable which can safely be incremented |
| 66 | * or decremented by multiple threads. A Mutex is used to protect access |
| 67 | * to the counter variable (an integer). An initial value can be specified |
| 68 | * for the counter, and it can be manipulated with the ++ and -- operators. |
| 69 | * |
| 70 | * @author David Sugar <dyfet@ostel.com> |
| 71 | * @short Thread protected integer counter. |
| 72 | */ |
| 73 | class __EXPORT MutexCounter : public Mutex |
| 74 | { |
| 75 | protected: |
| 76 | volatile int counter; |
| 77 | |
| 78 | public: |
| 79 | /** |
| 80 | * Create and optionally name a mutex protected counter. |
| 81 | */ |
| 82 | MutexCounter(); |
| 83 | |
| 84 | /** |
| 85 | * Create and optionally name a mutex protected counter with |
| 86 | * an initial value. |
| 87 | * |
| 88 | * @param initial value of counter. |
| 89 | */ |
| 90 | MutexCounter(int initial); |
| 91 | |
| 92 | int operator++(); |
| 93 | int operator--(); |
| 94 | }; |
| 95 | |
| 96 | /** |
| 97 | * The MutexLock class is used to protect a section of code so that at any |
| 98 | * given time only a single thread can perform the protected operation. |
| 99 | * |
| 100 | * It use Mutex to protect operation. Using this class is usefull and |
| 101 | * exception safe. The mutex that has been locked is automatically |
| 102 | * released when the function call stack falls out of scope, so one doesnt |
| 103 | * have to remember to unlock the mutex at each function return. |
| 104 | * |
| 105 | * A common use is |
| 106 | * |
| 107 | * void func_to_protect() |
| 108 | * { |
| 109 | * MutexLock lock(mutex); |
| 110 | * ... operation ... |
| 111 | * } |
| 112 | * |
| 113 | * NOTE: do not declare variable as "MutexLock (mutex)", the mutex will be |
| 114 | * released at statement end. |
| 115 | * |
| 116 | * @author Frediano Ziglio <freddy77@angelfire.com> |
| 117 | * @short Mutex automatic locker for protected access. |
| 118 | */ |
| 119 | class __EXPORT MutexLock |
| 120 | { |
| 121 | private: |
| 122 | Mutex& mutex; |
| 123 | |
| 124 | public: |
| 125 | /** |
| 126 | * Acquire the mutex |
| 127 | * |
| 128 | * @param _mutex reference to mutex to aquire. |
| 129 | */ |
| 130 | inline MutexLock( Mutex& _mutex ) : mutex( _mutex ) |
| 131 | { mutex.enterMutex(); } |
| 132 | |
| 133 | /** |
| 134 | * Release the mutex automatically |
| 135 | */ |
| 136 | // this should be not-virtual |
| 137 | inline ~MutexLock() |
| 138 | { mutex.leaveMutex(); } |
| 139 | }; |
| 140 | |
| 141 | class __EXPORT ThreadLock : protected ucommon::ThreadLock |
| 142 | { |
| 143 | public: |
| 144 | inline ThreadLock() : ucommon::ThreadLock() {}; |
| 145 | |
| 146 | inline void readLock(void) |
| 147 | {ucommon::ThreadLock::access();}; |
| 148 | |
| 149 | inline void writeLock(void) |
| 150 | {ucommon::ThreadLock::modify();}; |
| 151 | |
| 152 | inline void tryReadLock(void) |
| 153 | {ucommon::ThreadLock::access(0);}; |
| 154 | |
| 155 | inline void tryWriteLock(void) |
| 156 | {ucommon::ThreadLock::modify(0);}; |
| 157 | |
| 158 | inline void unlock(void) |
| 159 | {ucommon::ThreadLock::release();}; |
| 160 | }; |
| 161 | |
| 162 | /** |
| 163 | * The ReadLock class is used to protect a section of code through |
| 164 | * a ThreadLock for "read" access to the member function. The |
| 165 | * ThreadLock is automatically released when the object falls out of |
| 166 | * scope. |
| 167 | * |
| 168 | * A common use is |
| 169 | * |
| 170 | * void func_to_protect() |
| 171 | * { |
| 172 | * ReadLock lock(threadlock); |
| 173 | * ... operation ... |
| 174 | * } |
| 175 | * |
| 176 | * NOTE: do not declare variable as "ReadLock (threadlock)", the |
| 177 | * mutex will be released at statement end. |
| 178 | * |
| 179 | * @author David Sugar <dyfet@gnu.org> |
| 180 | * @short Read mode automatic locker for protected access. |
| 181 | */ |
| 182 | class __EXPORT ReadLock |
| 183 | { |
| 184 | private: |
| 185 | ThreadLock& tl; |
| 186 | |
| 187 | public: |
| 188 | /** |
| 189 | * Wait for read access |
| 190 | * |
| 191 | * @param _tl reference to lock to aquire. |
| 192 | */ |
| 193 | inline ReadLock( ThreadLock& _tl ) : tl( _tl ) |
| 194 | { tl.readLock(); } |
| 195 | /** |
| 196 | * Post the semaphore automatically |
| 197 | */ |
| 198 | // this should be not-virtual |
| 199 | inline ~ReadLock() |
| 200 | { tl.unlock(); } |
| 201 | }; |
| 202 | |
| 203 | /** |
| 204 | * The WriteLock class is used to protect a section of code through |
| 205 | * a ThreadLock for "write" access to the member function. The |
| 206 | * ThreadLock is automatically released when the object falls out of |
| 207 | * scope. |
| 208 | * |
| 209 | * A common use is |
| 210 | * |
| 211 | * void func_to_protect() |
| 212 | * { |
| 213 | * WriteLock lock(threadlock); |
| 214 | * ... operation ... |
| 215 | * } |
| 216 | * |
| 217 | * NOTE: do not declare variable as "WriteLock (threadlock)", the |
| 218 | * mutex will be released at statement end. |
| 219 | * |
| 220 | * @author David Sugar <dyfet@gnu.org> |
| 221 | * @short Read mode automatic locker for protected access. |
| 222 | */ |
| 223 | class __EXPORT WriteLock |
| 224 | { |
| 225 | private: |
| 226 | ThreadLock& tl; |
| 227 | |
| 228 | public: |
| 229 | /** |
| 230 | * Wait for write access |
| 231 | * |
| 232 | * @param _tl reference to threadlock to aquire. |
| 233 | */ |
| 234 | inline WriteLock( ThreadLock& _tl ) : tl( _tl ) |
| 235 | { tl.writeLock(); } |
| 236 | /** |
| 237 | * Post the semaphore automatically |
| 238 | */ |
| 239 | // this should be not-virtual |
| 240 | inline ~WriteLock() |
| 241 | { tl.unlock(); } |
| 242 | }; |
| 243 | |
| 244 | class __EXPORT Conditional : private ucommon::Conditional |
| 245 | { |
| 246 | public: |
| 247 | inline Conditional() : ucommon::Conditional() {}; |
| 248 | |
| 249 | bool wait(timeout_t timeout, bool locked = false); |
| 250 | |
| 251 | void signal(bool broadcast); |
| 252 | |
| 253 | inline void enterMutex(void) |
| 254 | {ucommon::Conditional::lock();}; |
| 255 | |
| 256 | inline void leaveMutex(void) |
| 257 | {ucommon::Conditional::unlock();}; |
| 258 | }; |
| 259 | |
| 260 | class __EXPORT Semaphore : private ucommon::Semaphore |
| 261 | { |
| 262 | public: |
| 263 | inline Semaphore(unsigned size=0) : ucommon::Semaphore(size) {}; |
| 264 | |
| 265 | inline bool wait(timeout_t timeout = 0) |
| 266 | {return ucommon::Semaphore::wait(timeout);}; |
| 267 | |
| 268 | inline void post(void) |
| 269 | {ucommon::Semaphore::release();}; |
| 270 | }; |
| 271 | |
| 272 | /** |
| 273 | * The SemaphoreLock class is used to protect a section of code through |
| 274 | * a semaphore so that only x instances of the member function may |
| 275 | * execute concurrently. |
| 276 | * |
| 277 | * A common use is |
| 278 | * |
| 279 | * void func_to_protect() |
| 280 | * { |
| 281 | * SemaphoreLock lock(semaphore); |
| 282 | * ... operation ... |
| 283 | * } |
| 284 | * |
| 285 | * NOTE: do not declare variable as "SemaohoreLock (semaphore)", the |
| 286 | * mutex will be released at statement end. |
| 287 | * |
| 288 | * @author David Sugar <dyfet@gnu.org> |
| 289 | * @short Semaphore automatic locker for protected access. |
| 290 | */ |
| 291 | class __EXPORT SemaphoreLock |
| 292 | { |
| 293 | private: |
| 294 | Semaphore& sem; |
| 295 | |
| 296 | public: |
| 297 | /** |
| 298 | * Wait for the semaphore |
| 299 | */ |
| 300 | inline SemaphoreLock( Semaphore& _sem ) : sem( _sem ) |
| 301 | { sem.wait(); } |
| 302 | /** |
| 303 | * Post the semaphore automatically |
| 304 | */ |
| 305 | // this should be not-virtual |
| 306 | inline ~SemaphoreLock() |
| 307 | { sem.post(); } |
| 308 | }; |
| 309 | |
| 310 | class __EXPORT Event : private ucommon::TimedEvent |
| 311 | { |
| 312 | public: |
| 313 | inline Event() : TimedEvent() {}; |
| 314 | |
| 315 | inline void wait(void) |
| 316 | {ucommon::TimedEvent::wait(Timer::inf);}; |
| 317 | |
| 318 | inline bool wait(timeout_t timeout) |
| 319 | {return ucommon::TimedEvent::wait(timeout);}; |
| 320 | |
| 321 | inline void signal(void) |
| 322 | {ucommon::TimedEvent::signal();}; |
| 323 | |
| 324 | inline void reset(void) |
| 325 | {ucommon::TimedEvent::reset();}; |
| 326 | }; |
| 327 | |
| 328 | class __EXPORT Thread : protected ucommon::JoinableThread |
| 329 | { |
| 330 | public: |
| 331 | /** |
| 332 | * How to raise error |
| 333 | */ |
| 334 | typedef enum Throw { |
| 335 | throwNothing, /**< continue without throwing error */ |
| 336 | throwObject, /**< throw object that cause error (throw this) */ |
| 337 | throwException /**< throw an object relative to error */ |
| 338 | } Throw; |
| 339 | |
| 340 | private: |
| 341 | friend class Slog; |
| 342 | |
| 343 | Throw exceptions; |
| 344 | bool detached, terminated; |
| 345 | Thread *parent; |
| 346 | size_t msgpos; |
| 347 | char msgbuf[128]; |
| 348 | |
| 349 | public: |
| 350 | Thread(int pri = 0, size_t stack = 0); |
| 351 | |
| 352 | virtual ~Thread(); |
| 353 | |
| 354 | inline void map(void) |
| 355 | {JoinableThread::map();}; |
| 356 | |
| 357 | virtual void initial(void); |
| 358 | virtual void notify(Thread *thread); |
| 359 | virtual void final(void); |
| 360 | virtual void run(void) = 0; |
| 361 | |
| 362 | void terminate(void); |
| 363 | void finalize(void); |
| 364 | |
| 365 | void detach(void); |
| 366 | void start(void); |
| 367 | void exit(void); |
| 368 | |
| 369 | inline void join(void) |
| 370 | {JoinableThread::join();}; |
| 371 | |
| 372 | inline void sync(void) |
| 373 | {Thread::exit();}; |
| 374 | |
| 375 | static inline Thread *get(void) |
| 376 | {return (Thread *)JoinableThread::get();}; |
| 377 | |
| 378 | inline static void yield(void) |
| 379 | {ucommon::Thread::yield();}; |
| 380 | |
| 381 | inline static void sleep(timeout_t msec = TIMEOUT_INF) |
| 382 | {ucommon::Thread::sleep(msec);}; |
| 383 | |
| 384 | bool isRunning(void); |
| 385 | |
| 386 | bool isThread(void); |
| 387 | |
| 388 | /** |
| 389 | * Get exception mode of the current thread. |
| 390 | * |
| 391 | * @return exception mode. |
| 392 | */ |
| 393 | static Throw getException(void); |
| 394 | |
| 395 | /** |
| 396 | * Set exception mode of the current thread. |
| 397 | * |
| 398 | * @return exception mode. |
| 399 | */ |
| 400 | static void setException(Throw mode); |
| 401 | |
| 402 | /** |
| 403 | * Get the thread id. |
| 404 | */ |
| 405 | inline pthread_t getId(void) |
| 406 | {return tid;}; |
| 407 | }; |
| 408 | |
| 409 | /** |
| 410 | * This class is used to access non-reentrant date and time functions in the |
| 411 | * standard C library. |
| 412 | * |
| 413 | * The class has two purposes: |
| 414 | * - 1 To be used internaly in CommonCpp's date and time classes to make them |
| 415 | * thread safe. |
| 416 | * - 2 To be used by clients as thread safe replacements to the standard C |
| 417 | * functions, much like Thread::sleep() represents a thread safe version |
| 418 | * of the standard sleep() function. |
| 419 | * |
| 420 | * @note The class provides one function with the same name as its equivalent |
| 421 | * standard function and one with another, unique name. For new clients, |
| 422 | * the version with the unique name is recommended to make it easy to |
| 423 | * grep for accidental usage of the standard functions. The version with |
| 424 | * the standard name is provided for existing clients to sed replace their |
| 425 | * original version. |
| 426 | * |
| 427 | * @note Also note that some functions that returned pointers have been redone |
| 428 | * to take that pointer as an argument instead, making the caller |
| 429 | * responsible for memory allocation/deallocation. This is almost |
| 430 | * how POSIX specifies *_r functions (reentrant versions of the |
| 431 | * standard time functions), except the POSIX functions also return the |
| 432 | * given pointer while we do not. We don't use the *_r functions as they |
| 433 | * aren't all generally available on all platforms yet. |
| 434 | * |
| 435 | * @author Idar Tollefsen <idar@cognita.no> |
| 436 | * @short Thread safe date and time functions. |
| 437 | */ |
| 438 | class __EXPORT SysTime |
| 439 | { |
| 440 | public: |
| 441 | static time_t getTime(time_t *tloc = NULL); |
| 442 | static time_t time(time_t *tloc) |
| 443 | { return getTime(tloc); }; |
| 444 | |
| 445 | static int getTimeOfDay(struct timeval *tp); |
| 446 | static int gettimeofday(struct timeval *tp, struct timezone *) |
| 447 | { return getTimeOfDay(tp); }; |
| 448 | |
| 449 | static struct tm *getLocalTime(const time_t *clock, struct tm *result); |
| 450 | static struct tm *locatime(const time_t *clock, struct tm *result) |
| 451 | { return getLocalTime(clock, result); }; |
| 452 | |
| 453 | static struct tm *getGMTTime(const time_t *clock, struct tm *result); |
| 454 | static struct tm *gmtime(const time_t *clock, struct tm *result) |
| 455 | { return getGMTTime(clock, result);}; |
| 456 | }; |
| 457 | |
| 458 | /** |
| 459 | * Timer ports are used to provide synchronized timing events when managed |
| 460 | * under a "service thread" such as SocketService. This is made into a |
| 461 | * stand-alone base class since other derived libraries (such as the |
| 462 | * serial handlers) may also use the pooled "service thread" model |
| 463 | * and hence also require this code for managing timing. |
| 464 | * |
| 465 | * @author David Sugar <dyfet@ostel.com> |
| 466 | * @short synchronized millisecond timing for service threads. |
| 467 | */ |
| 468 | class __EXPORT TimerPort |
| 469 | { |
| 470 | #ifndef _MSWINDOWS_ |
| 471 | struct timeval timer; |
| 472 | #else |
| 473 | DWORD timer; |
| 474 | #endif |
| 475 | bool active; |
| 476 | |
| 477 | public: |
| 478 | /** |
| 479 | * Create a timer, mark it as inactive, and set the initial |
| 480 | * "start" time to the creation time of the timer object. This |
| 481 | * allows "incTimer" to initially refer to time delays relative |
| 482 | * to the original start time of the object. |
| 483 | */ |
| 484 | TimerPort(); |
| 485 | |
| 486 | /** |
| 487 | * Set a new start time for the object based on when this call is |
| 488 | * made and optionally activate the timer for a specified number |
| 489 | * of milliseconds. This can be used to set the starting time |
| 490 | * of a realtime session. |
| 491 | * |
| 492 | * @param timeout delay in milliseconds from "now" |
| 493 | */ |
| 494 | void setTimer(timeout_t timeout = 0); |
| 495 | |
| 496 | /** |
| 497 | * Set a timeout based on the current time reference value either |
| 498 | * from object creation or the last setTimer(). This reference |
| 499 | * can be used to time synchronize realtime data over specified |
| 500 | * intervals and force expiration when a new frame should be |
| 501 | * released in a synchronized manner. |
| 502 | * |
| 503 | * @param timeout delay in milliseconds from reference. |
| 504 | */ |
| 505 | void incTimer(timeout_t timeout); |
| 506 | |
| 507 | /** |
| 508 | * Adjust a timeout based on the current time reference value either |
| 509 | * from object creation or the last setTimer(). This reference |
| 510 | * can be used to time synchronize realtime data over specified |
| 511 | * intervals and force expiration when a new frame should be |
| 512 | * released in a synchronized manner. |
| 513 | * |
| 514 | * @param timeout delay in milliseconds from reference. |
| 515 | */ |
| 516 | void decTimer(timeout_t timeout); |
| 517 | |
| 518 | /** |
| 519 | * Sleep until the current timer expires. This is useful in time |
| 520 | * syncing realtime periodic tasks. |
| 521 | */ |
| 522 | void sleepTimer(void); |
| 523 | |
| 524 | /** |
| 525 | * This is used to "disable" the service thread from expiring |
| 526 | * the timer object. It does not effect the reference time from |
| 527 | * either creation or a setTimer(). |
| 528 | */ |
| 529 | void endTimer(void); |
| 530 | |
| 531 | /** |
| 532 | * This is used by service threads to determine how much time |
| 533 | * remains before the timer expires based on a timeout specified |
| 534 | * in setTimer() or incTimer(). It can also be called after |
| 535 | * setting a timeout with incTimer() to see if the current timeout |
| 536 | * has already expired and hence that the application is already |
| 537 | * delayed and should skip frame(s). |
| 538 | * |
| 539 | * return time remaining in milliseconds, or TIMEOUT_INF if |
| 540 | * inactive. |
| 541 | */ |
| 542 | timeout_t getTimer(void) const; |
| 543 | |
| 544 | /** |
| 545 | * This is used to determine how much time has elapsed since a |
| 546 | * timer port setTimer benchmark time was initially set. This |
| 547 | * allows one to use setTimer() to set the timer to the current |
| 548 | * time and then measure elapsed time from that point forward. |
| 549 | * |
| 550 | * return time elapsed in milliseconds, or TIMEOUT_INF if |
| 551 | * inactive. |
| 552 | */ |
| 553 | timeout_t getElapsed(void) const; |
| 554 | }; |
| 555 | |
| 556 | #ifndef _MSWINDOWS_ |
| 557 | struct timespec *getTimeout(struct timespec *spec, timeout_t timeout); |
| 558 | #endif |
| 559 | |
| 560 | inline struct tm *localtime_r(const time_t *t, struct tm *b) |
| 561 | {return SysTime::getLocalTime(t, b);} |
| 562 | |
| 563 | inline char *ctime_r(const time_t *t, char *buf) |
| 564 | {return ctime(t);} |
| 565 | |
| 566 | inline struct tm *gmtime_r(const time_t *t, struct tm *b) |
| 567 | {return SysTime::getGMTTime(t, b);} |
| 568 | |
| 569 | inline char *asctime_r(const struct tm *tm, char *b) |
| 570 | {return asctime(tm);} |
| 571 | |
| 572 | inline Thread *getThread(void) |
| 573 | {return Thread::get();} |
| 574 | |
| 575 | /** |
| 576 | * The buffer class represents an IPC service that is built upon a buffer |
| 577 | * of fixed capacity that can be used to transfer objects between one or |
| 578 | * more producer and consumer threads. Producer threads post objects |
| 579 | * into the buffer, and consumer threads wait for and receive objects from |
| 580 | * the buffer. Semaphores are used to to block the buffer from overflowing |
| 581 | * and indicate when there is data available, and mutexes are used to protect |
| 582 | * multiple consumers and producer threads from stepping over each other. |
| 583 | * |
| 584 | * The buffer class is an abstract class in that the actual data being |
| 585 | * buffered is not directly specified within the buffer class itself. The |
| 586 | * buffer class should be used as a base class for a class that actually |
| 587 | * impliments buffering and which may be aware of the data types actually |
| 588 | * are being buffered. A template class could be created based on buffer |
| 589 | * for this purpose. Another possibility is to create a class derived |
| 590 | * from both Thread and Buffer which can be used to implement message passing |
| 591 | * threads. |
| 592 | * |
| 593 | * @author David Sugar <dyfet@ostel.com> |
| 594 | * @short Producer/Consumer buffer for use between threads. |
| 595 | */ |
| 596 | #ifdef _MSWINDOWS_ |
| 597 | class __EXPORT Buffer : public Mutex |
| 598 | #else |
| 599 | class __EXPORT Buffer : public Conditional |
| 600 | #endif |
| 601 | { |
| 602 | private: |
| 603 | #ifdef _MSWINDOWS_ |
| 604 | HANDLE sem_head, sem_tail; |
| 605 | #endif |
| 606 | size_t _size; |
| 607 | size_t _used; |
| 608 | |
| 609 | protected: |
| 610 | /** |
| 611 | * Invoke derived class buffer peeking method. |
| 612 | * @return size of object found. |
| 613 | * @param buf pointer to copy contents of head of buffer to. |
| 614 | */ |
| 615 | virtual size_t onPeek(void *buf) = 0; |
| 616 | |
| 617 | /** |
| 618 | * Invoke derived class object request from buffer. |
| 619 | * @return size of object returned. |
| 620 | * @param buf pointer to hold object returned from the buffer. |
| 621 | */ |
| 622 | virtual size_t onWait(void *buf) = 0; |
| 623 | |
| 624 | /** |
| 625 | * Invoke derived class posting of object to buffer. |
| 626 | * @return size of object posted. |
| 627 | * @param buf pointer to object being posted to the buffer. |
| 628 | */ |
| 629 | virtual size_t onPost(void *buf) = 0; |
| 630 | |
| 631 | public: |
| 632 | /** |
| 633 | * value to return when a timed operation returned with a |
| 634 | * timeout. |
| 635 | */ |
| 636 | static const size_t timeout; |
| 637 | |
| 638 | /** |
| 639 | * Create a buffer object of known capacity. |
| 640 | * @param capacity is the integer capacity of the buffer. |
| 641 | */ |
| 642 | Buffer(size_t capacity); |
| 643 | /** |
| 644 | * In derived functions, may be used to free the actual memory |
| 645 | * used to hold buffered data. |
| 646 | */ |
| 647 | virtual ~Buffer(); |
| 648 | |
| 649 | /** |
| 650 | * Return the capacity of the buffer as specified at creation. |
| 651 | * @return size of buffer. |
| 652 | */ |
| 653 | inline size_t getSize(void) |
| 654 | {return _size;}; |
| 655 | |
| 656 | /** |
| 657 | * Return the current capacity in use for the buffer. Free space |
| 658 | * is technically getSize() - getUsed(). |
| 659 | * @return integer used capacity of the buffer. |
| 660 | * @see #getSize |
| 661 | */ |
| 662 | inline size_t getUsed(void) |
| 663 | {return _used;}; |
| 664 | |
| 665 | /** |
| 666 | * Let one or more threads wait for an object to become available |
| 667 | * in the buffer. The waiting thread(s) will wait forever if no |
| 668 | * object is ever placed into the buffer. |
| 669 | * |
| 670 | * @return size of object passed by buffer in bytes. |
| 671 | * @param buf pointer to store object retrieved from the buffer. |
| 672 | * @param timeout time to wait. |
| 673 | */ |
| 674 | size_t wait(void *buf, timeout_t timeout = 0); |
| 675 | |
| 676 | /** |
| 677 | * Post an object into the buffer and enable a waiting thread to |
| 678 | * receive it. |
| 679 | * |
| 680 | * @return size of object posted in bytes. |
| 681 | * @param buf pointer to object to store in the buffer. |
| 682 | * @param timeout time to wait. |
| 683 | */ |
| 684 | size_t post(void *buf, timeout_t timeout = 0); |
| 685 | |
| 686 | /** |
| 687 | * Peek at the current content (first object) in the buffer. |
| 688 | * |
| 689 | * @return size of object in the buffer. |
| 690 | * @param buf pointer to store object found in the buffer. |
| 691 | */ |
| 692 | size_t peek(void *buf); |
| 693 | |
| 694 | /** |
| 695 | * New virtual to test if buffer is a valid object. |
| 696 | * @return true if object is valid. |
| 697 | */ |
| 698 | virtual bool isValid(void); |
| 699 | }; |
| 700 | |
| 701 | /** |
| 702 | * A buffer class that holds a known capacity of fixed sized objects defined |
| 703 | * during creation. |
| 704 | * |
| 705 | * @author David Sugar <dyfet@ostel.com> |
| 706 | * @short producer/consumer buffer for fixed size objects. |
| 707 | */ |
| 708 | class __EXPORT FixedBuffer : public Buffer |
| 709 | { |
| 710 | private: |
| 711 | char *buf, *head, *tail; |
| 712 | size_t objsize; |
| 713 | |
| 714 | protected: |
| 715 | /** |
| 716 | * Return the first object in the buffer. |
| 717 | * @return predefined size of this buffers objects. |
| 718 | * @param buf pointer to copy contents of head of buffer to. |
| 719 | */ |
| 720 | size_t onPeek(void *buf); |
| 721 | |
| 722 | /** |
| 723 | * Wait for and return a fixed object in the buffer. |
| 724 | * @return predefined size of this buffers objects. |
| 725 | * @param buf pointer to hold object returned from the buffer. |
| 726 | */ |
| 727 | size_t onWait(void *buf); |
| 728 | |
| 729 | /** |
| 730 | * Post an object of the appropriate size into the buffer. |
| 731 | * @return predefined size of this buffers objects. |
| 732 | * @param buf pointer to data to copy into the buffer. |
| 733 | */ |
| 734 | size_t onPost(void *buf); |
| 735 | |
| 736 | public: |
| 737 | /** |
| 738 | * Create a buffer of known capacity for objects of a specified |
| 739 | * size. |
| 740 | * |
| 741 | * @param capacity of the buffer. |
| 742 | * @param objsize for each object held in the buffer. |
| 743 | */ |
| 744 | FixedBuffer(size_t capacity, size_t objsize); |
| 745 | |
| 746 | /** |
| 747 | * Create a copy of an existing fixed size buffer and duplicate |
| 748 | * it's contents. |
| 749 | * |
| 750 | * @param fb existing FixedBuffer object. |
| 751 | */ |
| 752 | FixedBuffer(const FixedBuffer &fb); |
| 753 | |
| 754 | /** |
| 755 | * Destroy the fixed buffer and free the memory used to store objects. |
| 756 | */ |
| 757 | virtual ~FixedBuffer(); |
| 758 | |
| 759 | FixedBuffer &operator=(const FixedBuffer &fb); |
| 760 | |
| 761 | bool isValid(void); |
| 762 | }; |
| 763 | |
| 764 | /** |
| 765 | * Somewhat generic queue processing class to establish a producer |
| 766 | * consumer queue. This may be used to buffer cdr records, or for |
| 767 | * other purposes where an in-memory queue is needed for rapid |
| 768 | * posting. This class is derived from Mutex and maintains a linked |
| 769 | * list. A thread is used to dequeue data and pass it to a callback |
| 770 | * method that is used in place of "run" for each item present on the |
| 771 | * queue. The conditional is used to signal the run thread when new |
| 772 | * data is posted. |
| 773 | * |
| 774 | * This class was changed by Angelo Naselli to have a timeout on the queue |
| 775 | * |
| 776 | * @short in memory data queue interface. |
| 777 | * @author David Sugar <dyfet@ostel.com> |
| 778 | */ |
| 779 | class __EXPORT ThreadQueue : public Mutex, public Thread, public Semaphore |
| 780 | { |
| 781 | private: |
| 782 | void run(void); // private run method |
| 783 | |
| 784 | protected: |
| 785 | typedef struct _data { |
| 786 | struct _data *next; |
| 787 | unsigned len; |
| 788 | char data[1]; |
| 789 | } data_t; |
| 790 | |
| 791 | timeout_t timeout; |
| 792 | bool started; |
| 793 | |
| 794 | data_t *first, *last; // head/tail of list |
| 795 | |
| 796 | String name; |
| 797 | |
| 798 | /* |
| 799 | * Overloading of final(). It demarks Semaphore to avoid deadlock. |
| 800 | */ |
| 801 | virtual void final(); |
| 802 | |
| 803 | /** |
| 804 | * Start of dequeing. Maybe we need to connect a database |
| 805 | * or something, so we have a virtual... |
| 806 | */ |
| 807 | virtual void startQueue(void); |
| 808 | |
| 809 | /** |
| 810 | * End of dequeing, we expect the queue is empty for now. Maybe |
| 811 | * we need to disconnect a database or something, so we have |
| 812 | * another virtual. |
| 813 | */ |
| 814 | virtual void stopQueue(void); |
| 815 | |
| 816 | /** |
| 817 | * A derivable method to call when the timout is expired. |
| 818 | */ |
| 819 | virtual void onTimer(void); |
| 820 | |
| 821 | /** |
| 822 | * Virtual callback method to handle processing of a queued |
| 823 | * data items. After the item is processed, it is deleted from |
| 824 | * memory. We can call multiple instances of runQueue in order |
| 825 | * if multiple items are waiting. |
| 826 | * |
| 827 | * @param data item being dequed. |
| 828 | */ |
| 829 | virtual void runQueue(void *data) = 0; |
| 830 | |
| 831 | public: |
| 832 | /** |
| 833 | * Create instance of our queue and give it a process priority. |
| 834 | * |
| 835 | * @param id queue ID. |
| 836 | * @param pri process priority. |
| 837 | * @param stack stack size. |
| 838 | */ |
| 839 | ThreadQueue(const char *id, int pri, size_t stack = 0); |
| 840 | |
| 841 | /** |
| 842 | * Destroy the queue. |
| 843 | */ |
| 844 | virtual ~ThreadQueue(); |
| 845 | |
| 846 | /** |
| 847 | * Set the queue timeout. |
| 848 | * When the timer expires, the onTimer() method is called |
| 849 | * for the thread |
| 850 | * |
| 851 | * @param timeout timeout in milliseconds. |
| 852 | */ |
| 853 | void setTimer(timeout_t timeout); |
| 854 | |
| 855 | /** |
| 856 | * Put some unspecified data into this queue. A new qd |
| 857 | * structure is created and sized to contain a copy of |
| 858 | * the actual content. |
| 859 | * |
| 860 | * @param data pointer to data. |
| 861 | * @param len size of data. |
| 862 | */ |
| 863 | void post(const void *data, unsigned len); |
| 864 | }; |
| 865 | |
| 866 | |
| 867 | /** @relates Buffer */ |
| 868 | inline size_t get(Buffer &b, void *o, timeout_t t = 0) |
| 869 | {return b.wait(o, t);} |
| 870 | |
| 871 | /** @relates Buffer */ |
| 872 | inline size_t put(Buffer &b, void *o, timeout_t t = 0) |
| 873 | {return b.post(o, t);} |
| 874 | |
| 875 | /** @relates Buffer */ |
| 876 | inline size_t peek(Buffer &b, void *o) |
| 877 | {return b.peek(o);} |
| 878 | |
| 879 | END_NAMESPACE |
| 880 | |
| 881 | #endif |