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