blob: 31cb7313a481ffd49e67aba9502ace2d7b947861 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono5dcb38d2005-11-21 01:55:47 +00005 *
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>
Benny Prijonoac9d1422006-01-18 23:32:27 +000024#include <pj/string.h>
Benny Prijono5dcb38d2005-11-21 01:55:47 +000025#include <pj++/types.hpp>
26#include <pj++/pool.hpp>
27
28class Pj_Thread;
29
30//
31// Thread API.
32//
33class Pj_Thread_API
34{
35public:
36 //
37 // Create a thread.
38 //
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 //
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 //
63 static pj_thread_t *this_thread()
64 {
65 return pj_thread_this();
66 }
67
68 //
69 // Get thread name.
70 //
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 //
79 static pj_status_t resume(pj_thread_t *thread)
80 {
81 return pj_thread_resume(thread);
82 }
83
84 //
85 // Sleep.
86 //
87 static pj_status_t sleep(unsigned msec)
88 {
89 return pj_thread_sleep(msec);
90 }
91
92 //
93 // Join the specified thread.
94 //
95 static pj_status_t join(pj_thread_t *thread)
96 {
97 return pj_thread_join(thread);
98 }
99
100 //
101 // Destroy thread
102 //
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//
117class Pj_Thread : public Pj_Object
118{
119public:
120 enum Flags
121 {
122 FLAG_SUSPENDED = PJ_THREAD_SUSPENDED
123 };
124
125 //
126 // Default constructor.
127 //
128 Pj_Thread()
129 : thread_(NULL)
130 {
131 }
132
133 //
134 // Destroy thread.
135 //
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 //
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,
Benny Prijonoac9d1422006-01-18 23:32:27 +0000156 flags, thread_name, stack_size);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000157 }
158
159 //
160 // Get pjlib compatible thread object.
161 //
162 pj_thread_t *pj_thread_t_()
163 {
164 return thread_;
165 }
166
167 //
168 // Get thread name.
169 //
170 const char *get_name()
171 {
172 return Pj_Thread_API::get_name(thread_);
173 }
174
175 //
176 // Resume a suspended thread.
177 //
178 pj_status_t resume()
179 {
180 return Pj_Thread_API::resume(thread_);
181 }
182
183 //
184 // Join this thread.
185 //
186 pj_status_t join()
187 {
188 return Pj_Thread_API::join(thread_);
189 }
190
191 //
192 // Destroy thread.
193 //
194 pj_status_t destroy()
195 {
196 if (thread_) {
197 Pj_Thread_API::destroy(thread_);
198 thread_ = NULL;
199 }
200 }
201
202protected:
203 pj_thread_t *thread_;
204
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//
222class Pj_External_Thread : public Pj_Thread
223{
224public:
225 Pj_External_Thread()
226 {
227 }
228
229 //
230 // Register external thread so that pjlib functions can work
231 // in that thread.
232 //
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
238private:
239 pj_thread_desc desc_;
240};
241
242
243//
244// Thread specific data/thread local storage/TLS.
245//
246class Pj_Thread_Local_API
247{
248public:
249 //
250 // Allocate thread local storage (TLS) index.
251 //
252 static pj_status_t alloc(long *index)
253 {
254 return pj_thread_local_alloc(index);
255 }
256
257 //
258 // Free TLS index.
259 //
260 static void free(long index)
261 {
262 pj_thread_local_free(index);
263 }
264
265 //
266 // Set thread specific data.
267 //
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 //
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//
290class Pj_Atomic_Var : public Pj_Object
291{
292public:
293 //
294 // Default constructor, initialize variable with NULL.
295 //
296 Pj_Atomic_Var()
297 : var_(NULL)
298 {
299 }
300
301 //
302 // Construct atomic variable.
303 //
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 //
313 ~Pj_Atomic_Var()
314 {
315 destroy();
316 }
317
318 //
319 // Create atomic variable.
320 //
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 //
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 //
341 pj_atomic_t *pj_atomic_t_()
342 {
343 return var_;
344 }
345
346 //
347 // Set the value.
348 //
349 void set(pj_atomic_value_t val)
350 {
351 pj_atomic_set(var_, val);
352 }
353
354 //
355 // Get the value.
356 //
357 pj_atomic_value_t get()
358 {
359 return pj_atomic_get(var_);
360 }
361
362 //
363 // Increment.
364 //
365 void inc()
366 {
367 pj_atomic_inc(var_);
368 }
369
370 //
371 // Increment and get the result.
372 //
373 pj_atomic_value_t inc_and_get()
374 {
375 return pj_atomic_inc_and_get(var_);
376 }
377
378 //
379 // Decrement.
380 //
381 void dec()
382 {
383 pj_atomic_dec(var_);
384 }
385
386 //
387 // Decrement and get the result.
388 //
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 //
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 //
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
410private:
411 pj_atomic_t *var_;
412};
413
414
415//
416// Mutex
417//
418class Pj_Mutex : public Pj_Object
419{
420public:
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 //
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 //
444 ~Pj_Mutex()
445 {
446 destroy();
447 }
448
449 //
450 // Create mutex.
451 //
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 //
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 //
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 //
478 pj_mutex_t *pj_mutex_t_()
479 {
480 return mutex_;
481 }
482
483 //
484 // Destroy mutex.
485 //
486 void destroy()
487 {
488 if (mutex_) {
489 pj_mutex_destroy(mutex_);
490 mutex_ = NULL;
491 }
492 }
493
494 //
495 // Lock mutex.
496 //
497 pj_status_t acquire()
498 {
499 return pj_mutex_lock(mutex_);
500 }
501
502 //
503 // Unlock mutex.
504 //
505 pj_status_t release()
506 {
507 return pj_mutex_unlock(mutex_);
508 }
509
510 //
511 // Try locking the mutex.
512 //
513 pj_status_t tryacquire()
514 {
515 return pj_mutex_trylock(mutex_);
516 }
517
518private:
519 pj_mutex_t *mutex_;
520};
521
522
523//
524// Semaphore
525//
526class Pj_Semaphore : public Pj_Object
527{
528public:
529 //
530 // Construct semaphore
531 //
532 Pj_Semaphore(Pj_Pool *pool, unsigned max,
533 unsigned initial = 0, const char *name = NULL)
534 : sem_(NULL)
535 {
Benny Prijonoac9d1422006-01-18 23:32:27 +0000536 create(pool, max, initial, name);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000537 }
538
539 //
540 // Destructor.
541 //
542 ~Pj_Semaphore()
543 {
544 destroy();
545 }
546
547 //
548 // Create semaphore
549 //
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 //
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 //
571 pj_sem_t *pj_sem_t_()
572 {
573 return (pj_sem_t*)this;
574 }
575
576 //
577 // Wait semaphore.
578 //
579 pj_status_t wait()
580 {
581 return pj_sem_wait(this->pj_sem_t_());
582 }
583
584 //
585 // Wait semaphore.
586 //
587 pj_status_t acquire()
588 {
589 return wait();
590 }
591
592 //
593 // Try wait semaphore.
594 //
595 pj_status_t trywait()
596 {
597 return pj_sem_trywait(this->pj_sem_t_());
598 }
599
600 //
601 // Try wait semaphore.
602 //
603 pj_status_t tryacquire()
604 {
605 return trywait();
606 }
607
608 //
609 // Post semaphore.
610 //
611 pj_status_t post()
612 {
613 return pj_sem_post(this->pj_sem_t_());
614 }
615
616 //
617 // Post semaphore.
618 //
619 pj_status_t release()
620 {
621 return post();
622 }
623
624private:
625 pj_sem_t *sem_;
626};
627
628
629//
630// Event object.
631//
632class Pj_Event
633{
634public:
635 //
636 // Construct event object.
637 //
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 //
648 ~Pj_Event()
649 {
650 destroy();
651 }
652
653 //
654 // Create event object.
655 //
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 //
667 pj_event_t *pj_event_t_()
668 {
669 return event_;
670 }
671
672 //
673 // Destroy event object.
674 //
675 void destroy()
676 {
677 if (event_) {
678 pj_event_destroy(event_);
679 event_ = NULL;
680 }
681 }
682
683 //
684 // Wait.
685 //
686 pj_status_t wait()
687 {
688 return pj_event_wait(event_);
689 }
690
691 //
692 // Try wait.
693 //
694 pj_status_t trywait()
695 {
696 return pj_event_trywait(event_);
697 }
698
699 //
700 // Set event state to signalled.
701 //
702 pj_status_t set()
703 {
704 return pj_event_set(this->pj_event_t_());
705 }
706
707 //
708 // Release one waiting thread.
709 //
710 pj_status_t pulse()
711 {
712 return pj_event_pulse(this->pj_event_t_());
713 }
714
715 //
716 // Set a non-signalled.
717 //
718 pj_status_t reset()
719 {
720 return pj_event_reset(this->pj_event_t_());
721 }
722
723private:
724 pj_event_t *event_;
725};
726
727//
Benny Prijonoac9d1422006-01-18 23:32:27 +0000728// Timestamp
729//
730class Pj_Timestamp
731{
732public:
733 pj_status_t get_timestamp()
734 {
735 return pj_get_timestamp(&ts_);
736 }
737
738 Pj_Timestamp& operator += (const Pj_Timestamp &rhs)
739 {
740 pj_add_timestamp(&ts_, &rhs.ts_);
741 return *this;
742 }
743
744 Pj_Timestamp& operator -= (const Pj_Timestamp &rhs)
745 {
746 pj_sub_timestamp(&ts_, &rhs.ts_);
747 return *this;
748 }
749
750 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
757 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
764 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
771 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
778 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
785private:
786 pj_timestamp ts_;
787};
788
789
790//
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000791// OS abstraction.
792//
793class Pj_OS_API
794{
795public:
796 //
797 // Get current time.
798 //
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 //
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 //
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 //
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 //
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//
842inline pj_status_t Pj_Time_Val::gettimeofday()
843{
844 return Pj_OS_API::gettimeofday(this);
845}
846
847inline 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
854inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt)
855{
856 return Pj_OS_API::time_encode(pt, this);
857}
858
859inline pj_status_t Pj_Time_Val::to_gmt()
860{
861 return Pj_OS_API::time_local_to_gmt(this);
862}
863
864inline 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