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