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