blob: 9f72c5c58a5ce6b815802ab1b2a544a594da4120 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// 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
37NAMESPACE_COMMONCPP
38
39class __EXPORT Mutex : protected ucommon::RecursiveMutex
40{
41public:
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 */
73class __EXPORT MutexCounter : public Mutex
74{
75protected:
76 volatile int counter;
77
78public:
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 */
119class __EXPORT MutexLock
120{
121private:
122 Mutex& mutex;
123
124public:
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
141class __EXPORT ThreadLock : protected ucommon::ThreadLock
142{
143public:
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 */
182class __EXPORT ReadLock
183{
184private:
185 ThreadLock& tl;
186
187public:
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 */
223class __EXPORT WriteLock
224{
225private:
226 ThreadLock& tl;
227
228public:
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
244class __EXPORT Conditional : private ucommon::Conditional
245{
246public:
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
260class __EXPORT Semaphore : private ucommon::Semaphore
261{
262public:
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 */
291class __EXPORT SemaphoreLock
292{
293private:
294 Semaphore& sem;
295
296public:
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
310class __EXPORT Event : private ucommon::TimedEvent
311{
312public:
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
328class __EXPORT Thread : protected ucommon::JoinableThread
329{
330public:
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
340private:
341 friend class Slog;
342
343 Throw exceptions;
344 bool detached, terminated;
345 Thread *parent;
346 size_t msgpos;
347 char msgbuf[128];
348
349public:
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 */
438class __EXPORT SysTime
439{
440public:
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 */
468class __EXPORT TimerPort
469{
470#ifndef _MSWINDOWS_
471 struct timeval timer;
472#else
473 DWORD timer;
474#endif
475 bool active;
476
477public:
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_
557struct timespec *getTimeout(struct timespec *spec, timeout_t timeout);
558#endif
559
560inline struct tm *localtime_r(const time_t *t, struct tm *b)
561 {return SysTime::getLocalTime(t, b);}
562
563inline char *ctime_r(const time_t *t, char *buf)
564 {return ctime(t);}
565
566inline struct tm *gmtime_r(const time_t *t, struct tm *b)
567 {return SysTime::getGMTTime(t, b);}
568
569inline char *asctime_r(const struct tm *tm, char *b)
570 {return asctime(tm);}
571
572inline 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_
597class __EXPORT Buffer : public Mutex
598#else
599class __EXPORT Buffer : public Conditional
600#endif
601{
602private:
603#ifdef _MSWINDOWS_
604 HANDLE sem_head, sem_tail;
605#endif
606 size_t _size;
607 size_t _used;
608
609protected:
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
631public:
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 */
708class __EXPORT FixedBuffer : public Buffer
709{
710private:
711 char *buf, *head, *tail;
712 size_t objsize;
713
714protected:
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
736public:
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 */
779class __EXPORT ThreadQueue : public Mutex, public Thread, public Semaphore
780{
781private:
782 void run(void); // private run method
783
784protected:
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
831public:
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 */
868inline size_t get(Buffer &b, void *o, timeout_t t = 0)
869 {return b.wait(o, t);}
870
871/** @relates Buffer */
872inline size_t put(Buffer &b, void *o, timeout_t t = 0)
873 {return b.post(o, t);}
874
875/** @relates Buffer */
876inline size_t peek(Buffer &b, void *o)
877 {return b.peek(o);}
878
879END_NAMESPACE
880
881#endif