blob: 07fd6e851bf4a31215bf62bdb411a73b7307b7b4 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#ifndef __PJPP_OS_HPP__
20#define __PJPP_OS_HPP__
21
22#include <pj/os.h>
Benny Prijonoac9d1422006-01-18 23:32:27 +000023#include <pj/string.h>
Benny Prijono5dcb38d2005-11-21 01:55:47 +000024#include <pj++/types.hpp>
25#include <pj++/pool.hpp>
26
27class Pj_Thread;
28
29//
30// Thread API.
31//
32class Pj_Thread_API
33{
34public:
35 //
36 // Create a thread.
37 //
38 static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread,
39 pj_thread_proc *proc, void *arg,
40 unsigned flags = 0,
41 const char *name = NULL,
42 pj_size_t stack_size = 0 )
43 {
44 return pj_thread_create(pool->pool_(), name, proc, arg, stack_size,
45 flags, thread);
46 }
47
48 //
49 // Register a thread.
50 //
51 static pj_status_t register_this_thread( pj_thread_desc desc,
52 pj_thread_t **thread,
53 const char *name = NULL )
54 {
55 return pj_thread_register( name, desc, thread );
56 }
57
58 //
59 // Get current thread.
60 // Will return pj_thread_t (sorry folks, not Pj_Thread).
61 //
62 static pj_thread_t *this_thread()
63 {
64 return pj_thread_this();
65 }
66
67 //
68 // Get thread name.
69 //
70 static const char *get_name(pj_thread_t *thread)
71 {
72 return pj_thread_get_name(thread);
73 }
74
75 //
76 // Resume thread.
77 //
78 static pj_status_t resume(pj_thread_t *thread)
79 {
80 return pj_thread_resume(thread);
81 }
82
83 //
84 // Sleep.
85 //
86 static pj_status_t sleep(unsigned msec)
87 {
88 return pj_thread_sleep(msec);
89 }
90
91 //
92 // Join the specified thread.
93 //
94 static pj_status_t join(pj_thread_t *thread)
95 {
96 return pj_thread_join(thread);
97 }
98
99 //
100 // Destroy thread
101 //
102 static pj_status_t destroy(pj_thread_t *thread)
103 {
104 return pj_thread_destroy(thread);
105 }
106};
107
108
109
110//
111// Thread object.
112//
113// How to use:
114// Derive a class from this class, then override main().
115//
116class Pj_Thread : public Pj_Object
117{
118public:
119 enum Flags
120 {
121 FLAG_SUSPENDED = PJ_THREAD_SUSPENDED
122 };
123
124 //
125 // Default constructor.
126 //
127 Pj_Thread()
128 : thread_(NULL)
129 {
130 }
131
132 //
133 // Destroy thread.
134 //
135 ~Pj_Thread()
136 {
137 destroy();
138 }
139
140 //
141 // This is the main thread function.
142 //
143 virtual int main() = 0;
144
145 //
146 // Start a thread.
147 //
148 pj_status_t create( Pj_Pool *pool,
149 unsigned flags = 0,
150 const char *thread_name = NULL,
151 pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE)
152 {
153 destroy();
154 return Pj_Thread_API::create( pool, &thread_, &thread_proc, this,
Benny Prijonoac9d1422006-01-18 23:32:27 +0000155 flags, thread_name, stack_size);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000156 }
157
158 //
159 // Get pjlib compatible thread object.
160 //
161 pj_thread_t *pj_thread_t_()
162 {
163 return thread_;
164 }
165
166 //
167 // Get thread name.
168 //
169 const char *get_name()
170 {
171 return Pj_Thread_API::get_name(thread_);
172 }
173
174 //
175 // Resume a suspended thread.
176 //
177 pj_status_t resume()
178 {
179 return Pj_Thread_API::resume(thread_);
180 }
181
182 //
183 // Join this thread.
184 //
185 pj_status_t join()
186 {
187 return Pj_Thread_API::join(thread_);
188 }
189
190 //
191 // Destroy thread.
192 //
193 pj_status_t destroy()
194 {
195 if (thread_) {
196 Pj_Thread_API::destroy(thread_);
197 thread_ = NULL;
198 }
199 }
200
201protected:
202 pj_thread_t *thread_;
203
204 static int PJ_THREAD_FUNC thread_proc(void *obj)
205 {
206 Pj_Thread *thread_class = (Pj_Thread*)obj;
207 return thread_class->main();
208 }
209};
210
211
212//
213// External Thread
214// (threads that were started by external means, i.e. not
215// with Pj_Thread::create).
216//
217// This class will normally be defined as local variable in
218// external thread's stack, normally inside thread's main proc.
219// But be aware that the handle will be destroyed on destructor!
220//
221class Pj_External_Thread : public Pj_Thread
222{
223public:
224 Pj_External_Thread()
225 {
226 }
227
228 //
229 // Register external thread so that pjlib functions can work
230 // in that thread.
231 //
232 pj_status_t register_this_thread( const char *name=NULL )
233 {
234 return Pj_Thread_API::register_this_thread(desc_, &thread_,name);
235 }
236
237private:
238 pj_thread_desc desc_;
239};
240
241
242//
243// Thread specific data/thread local storage/TLS.
244//
245class Pj_Thread_Local_API
246{
247public:
248 //
249 // Allocate thread local storage (TLS) index.
250 //
251 static pj_status_t alloc(long *index)
252 {
253 return pj_thread_local_alloc(index);
254 }
255
256 //
257 // Free TLS index.
258 //
259 static void free(long index)
260 {
261 pj_thread_local_free(index);
262 }
263
264 //
265 // Set thread specific data.
266 //
267 static pj_status_t set(long index, void *value)
268 {
269 return pj_thread_local_set(index, value);
270 }
271
272 //
273 // Get thread specific data.
274 //
275 static void *get(long index)
276 {
277 return pj_thread_local_get(index);
278 }
279
280};
281
282//
283// Atomic variable
284//
285// How to use:
286// Pj_Atomic_Var var(pool, 0);
287// var.set(..);
288//
289class Pj_Atomic_Var : public Pj_Object
290{
291public:
292 //
293 // Default constructor, initialize variable with NULL.
294 //
295 Pj_Atomic_Var()
296 : var_(NULL)
297 {
298 }
299
300 //
301 // Construct atomic variable.
302 //
303 Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value)
304 : var_(NULL)
305 {
306 create(pool, value);
307 }
308
309 //
310 // Destructor.
311 //
312 ~Pj_Atomic_Var()
313 {
314 destroy();
315 }
316
317 //
318 // Create atomic variable.
319 //
320 pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value)
321 {
322 destroy();
323 return pj_atomic_create(pool->pool_(), value, &var_);
324 }
325
326 //
327 // Destroy.
328 //
329 void destroy()
330 {
331 if (var_) {
332 pj_atomic_destroy(var_);
333 var_ = NULL;
334 }
335 }
336
337 //
338 // Get pjlib compatible atomic variable.
339 //
340 pj_atomic_t *pj_atomic_t_()
341 {
342 return var_;
343 }
344
345 //
346 // Set the value.
347 //
348 void set(pj_atomic_value_t val)
349 {
350 pj_atomic_set(var_, val);
351 }
352
353 //
354 // Get the value.
355 //
356 pj_atomic_value_t get()
357 {
358 return pj_atomic_get(var_);
359 }
360
361 //
362 // Increment.
363 //
364 void inc()
365 {
366 pj_atomic_inc(var_);
367 }
368
369 //
370 // Increment and get the result.
371 //
372 pj_atomic_value_t inc_and_get()
373 {
374 return pj_atomic_inc_and_get(var_);
375 }
376
377 //
378 // Decrement.
379 //
380 void dec()
381 {
382 pj_atomic_dec(var_);
383 }
384
385 //
386 // Decrement and get the result.
387 //
388 pj_atomic_value_t dec_and_get()
389 {
390 return pj_atomic_dec_and_get(var_);
391 }
392
393 //
394 // Add the variable.
395 //
396 void add(pj_atomic_value_t value)
397 {
398 pj_atomic_add(var_, value);
399 }
400
401 //
402 // Add the variable and get the value.
403 //
404 pj_atomic_value_t add_and_get(pj_atomic_value_t value)
405 {
406 return pj_atomic_add_and_get(var_, value );
407 }
408
409private:
410 pj_atomic_t *var_;
411};
412
413
414//
415// Mutex
416//
417class Pj_Mutex : public Pj_Object
418{
419public:
420 //
421 // Mutex type.
422 //
423 enum Type
424 {
425 DEFAULT = PJ_MUTEX_DEFAULT,
426 SIMPLE = PJ_MUTEX_SIMPLE,
427 RECURSE = PJ_MUTEX_RECURSE,
428 };
429
430 //
431 // Default constructor will create default mutex.
432 //
433 explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT,
434 const char *name = NULL)
435 : mutex_(NULL)
436 {
437 create(pool, type, name);
438 }
439
440 //
441 // Destructor.
442 //
443 ~Pj_Mutex()
444 {
445 destroy();
446 }
447
448 //
449 // Create mutex.
450 //
451 pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL)
452 {
453 destroy();
454 return pj_mutex_create( pool->pool_(), name, type,
455 &mutex_ );
456 }
457
458 //
459 // Create simple mutex.
460 //
461 pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL)
462 {
463 return create(pool, SIMPLE, name);
464 }
465
466 //
467 // Create recursive mutex.
468 //
469 pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL )
470 {
471 return create(pool, RECURSE, name);
472 }
473
474 //
475 // Get pjlib compatible mutex object.
476 //
477 pj_mutex_t *pj_mutex_t_()
478 {
479 return mutex_;
480 }
481
482 //
483 // Destroy mutex.
484 //
485 void destroy()
486 {
487 if (mutex_) {
488 pj_mutex_destroy(mutex_);
489 mutex_ = NULL;
490 }
491 }
492
493 //
494 // Lock mutex.
495 //
496 pj_status_t acquire()
497 {
498 return pj_mutex_lock(mutex_);
499 }
500
501 //
502 // Unlock mutex.
503 //
504 pj_status_t release()
505 {
506 return pj_mutex_unlock(mutex_);
507 }
508
509 //
510 // Try locking the mutex.
511 //
512 pj_status_t tryacquire()
513 {
514 return pj_mutex_trylock(mutex_);
515 }
516
517private:
518 pj_mutex_t *mutex_;
519};
520
521
522//
523// Semaphore
524//
525class Pj_Semaphore : public Pj_Object
526{
527public:
528 //
529 // Construct semaphore
530 //
531 Pj_Semaphore(Pj_Pool *pool, unsigned max,
532 unsigned initial = 0, const char *name = NULL)
533 : sem_(NULL)
534 {
Benny Prijonoac9d1422006-01-18 23:32:27 +0000535 create(pool, max, initial, name);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000536 }
537
538 //
539 // Destructor.
540 //
541 ~Pj_Semaphore()
542 {
543 destroy();
544 }
545
546 //
547 // Create semaphore
548 //
549 pj_status_t create( Pj_Pool *pool, unsigned max,
550 unsigned initial = 0, const char *name = NULL )
551 {
552 destroy();
553 return pj_sem_create( pool->pool_(), name, initial, max, &sem_);
554 }
555
556 //
557 // Destroy semaphore.
558 //
559 void destroy()
560 {
561 if (sem_) {
562 pj_sem_destroy(sem_);
563 sem_ = NULL;
564 }
565 }
566
567 //
568 // Get pjlib compatible semaphore object.
569 //
570 pj_sem_t *pj_sem_t_()
571 {
572 return (pj_sem_t*)this;
573 }
574
575 //
576 // Wait semaphore.
577 //
578 pj_status_t wait()
579 {
580 return pj_sem_wait(this->pj_sem_t_());
581 }
582
583 //
584 // Wait semaphore.
585 //
586 pj_status_t acquire()
587 {
588 return wait();
589 }
590
591 //
592 // Try wait semaphore.
593 //
594 pj_status_t trywait()
595 {
596 return pj_sem_trywait(this->pj_sem_t_());
597 }
598
599 //
600 // Try wait semaphore.
601 //
602 pj_status_t tryacquire()
603 {
604 return trywait();
605 }
606
607 //
608 // Post semaphore.
609 //
610 pj_status_t post()
611 {
612 return pj_sem_post(this->pj_sem_t_());
613 }
614
615 //
616 // Post semaphore.
617 //
618 pj_status_t release()
619 {
620 return post();
621 }
622
623private:
624 pj_sem_t *sem_;
625};
626
627
628//
629// Event object.
630//
631class Pj_Event
632{
633public:
634 //
635 // Construct event object.
636 //
637 Pj_Event( Pj_Pool *pool, bool manual_reset = false,
638 bool initial = false, const char *name = NULL )
639 : event_(NULL)
640 {
641 create(pool, manual_reset, initial, name);
642 }
643
644 //
645 // Destructor.
646 //
647 ~Pj_Event()
648 {
649 destroy();
650 }
651
652 //
653 // Create event object.
654 //
655 pj_status_t create( Pj_Pool *pool, bool manual_reset = false,
656 bool initial = false, const char *name = NULL)
657 {
658 destroy();
659 return pj_event_create(pool->pool_(), name, manual_reset, initial,
660 &event_);
661 }
662
663 //
664 // Get pjlib compatible event object.
665 //
666 pj_event_t *pj_event_t_()
667 {
668 return event_;
669 }
670
671 //
672 // Destroy event object.
673 //
674 void destroy()
675 {
676 if (event_) {
677 pj_event_destroy(event_);
678 event_ = NULL;
679 }
680 }
681
682 //
683 // Wait.
684 //
685 pj_status_t wait()
686 {
687 return pj_event_wait(event_);
688 }
689
690 //
691 // Try wait.
692 //
693 pj_status_t trywait()
694 {
695 return pj_event_trywait(event_);
696 }
697
698 //
699 // Set event state to signalled.
700 //
701 pj_status_t set()
702 {
703 return pj_event_set(this->pj_event_t_());
704 }
705
706 //
707 // Release one waiting thread.
708 //
709 pj_status_t pulse()
710 {
711 return pj_event_pulse(this->pj_event_t_());
712 }
713
714 //
715 // Set a non-signalled.
716 //
717 pj_status_t reset()
718 {
719 return pj_event_reset(this->pj_event_t_());
720 }
721
722private:
723 pj_event_t *event_;
724};
725
726//
Benny Prijonoac9d1422006-01-18 23:32:27 +0000727// Timestamp
728//
729class Pj_Timestamp
730{
731public:
732 pj_status_t get_timestamp()
733 {
734 return pj_get_timestamp(&ts_);
735 }
736
737 Pj_Timestamp& operator += (const Pj_Timestamp &rhs)
738 {
739 pj_add_timestamp(&ts_, &rhs.ts_);
740 return *this;
741 }
742
743 Pj_Timestamp& operator -= (const Pj_Timestamp &rhs)
744 {
745 pj_sub_timestamp(&ts_, &rhs.ts_);
746 return *this;
747 }
748
749 Pj_Time_Val to_time() const
750 {
751 Pj_Timestamp zero;
752 pj_memset(&zero, 0, sizeof(zero));
753 return Pj_Time_Val(pj_elapsed_time(&zero.ts_, &ts_));
754 }
755
756 pj_uint32_t to_msec() const
757 {
758 Pj_Timestamp zero;
759 pj_memset(&zero, 0, sizeof(zero));
760 return pj_elapsed_msec(&zero.ts_, &ts_);
761 }
762
763 pj_uint32_t to_usec() const
764 {
765 Pj_Timestamp zero;
766 pj_memset(&zero, 0, sizeof(zero));
767 return pj_elapsed_usec(&zero.ts_, &ts_);
768 }
769
770 pj_uint32_t to_nanosec() const
771 {
772 Pj_Timestamp zero;
773 pj_memset(&zero, 0, sizeof(zero));
774 return pj_elapsed_nanosec(&zero.ts_, &ts_);
775 }
776
777 pj_uint32_t to_cycle() const
778 {
779 Pj_Timestamp zero;
780 pj_memset(&zero, 0, sizeof(zero));
781 return pj_elapsed_cycle(&zero.ts_, &ts_);
782 }
783
784private:
785 pj_timestamp ts_;
786};
787
788
789//
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000790// OS abstraction.
791//
792class Pj_OS_API
793{
794public:
795 //
796 // Get current time.
797 //
798 static pj_status_t gettimeofday( Pj_Time_Val *tv )
799 {
800 return pj_gettimeofday(tv);
801 }
802
803 //
804 // Parse to time of day.
805 //
806 static pj_status_t time_decode( const Pj_Time_Val *tv,
807 pj_parsed_time *pt )
808 {
809 return pj_time_decode(tv, pt);
810 }
811
812 //
813 // Parse from time of day.
814 //
815 static pj_status_t time_encode( const pj_parsed_time *pt,
816 Pj_Time_Val *tv)
817 {
818 return pj_time_encode(pt, tv);
819 }
820
821 //
822 // Convert to GMT.
823 //
824 static pj_status_t time_local_to_gmt( Pj_Time_Val *tv )
825 {
826 return pj_time_local_to_gmt( tv );
827 }
828
829 //
830 // Convert time to local.
831 //
832 static pj_status_t time_gmt_to_local( Pj_Time_Val *tv)
833 {
834 return pj_time_gmt_to_local( tv );
835 }
836};
837
838//
839// Timeval inlines.
840//
841inline pj_status_t Pj_Time_Val::gettimeofday()
842{
843 return Pj_OS_API::gettimeofday(this);
844}
845
846inline pj_parsed_time Pj_Time_Val::decode()
847{
848 pj_parsed_time pt;
849 Pj_OS_API::time_decode(this, &pt);
850 return pt;
851}
852
853inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt)
854{
855 return Pj_OS_API::time_encode(pt, this);
856}
857
858inline pj_status_t Pj_Time_Val::to_gmt()
859{
860 return Pj_OS_API::time_local_to_gmt(this);
861}
862
863inline pj_status_t Pj_Time_Val::to_local()
864{
865 return Pj_OS_API::time_gmt_to_local(this);
866}
867
868#endif /* __PJPP_OS_HPP__ */
869