/* * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __PJPP_OS_HPP__ #define __PJPP_OS_HPP__ #include #include #include #include class Pj_Thread; // // Thread API. // class Pj_Thread_API { public: // // Create a thread. // static pj_status_t 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 ) { return pj_thread_create(pool->pool_(), name, proc, arg, stack_size, flags, thread); } // // Register a thread. // static pj_status_t register_this_thread( pj_thread_desc desc, pj_thread_t **thread, const char *name = NULL ) { return pj_thread_register( name, desc, thread ); } // // Get current thread. // Will return pj_thread_t (sorry folks, not Pj_Thread). // static pj_thread_t *this_thread() { return pj_thread_this(); } // // Get thread name. // static const char *get_name(pj_thread_t *thread) { return pj_thread_get_name(thread); } // // Resume thread. // static pj_status_t resume(pj_thread_t *thread) { return pj_thread_resume(thread); } // // Sleep. // static pj_status_t sleep(unsigned msec) { return pj_thread_sleep(msec); } // // Join the specified thread. // static pj_status_t join(pj_thread_t *thread) { return pj_thread_join(thread); } // // Destroy thread // static pj_status_t destroy(pj_thread_t *thread) { return pj_thread_destroy(thread); } }; // // Thread object. // // How to use: // Derive a class from this class, then override main(). // class Pj_Thread : public Pj_Object { public: enum Flags { FLAG_SUSPENDED = PJ_THREAD_SUSPENDED }; // // Default constructor. // Pj_Thread() : thread_(NULL) { } // // Destroy thread. // ~Pj_Thread() { destroy(); } // // This is the main thread function. // virtual int main() = 0; // // Start a thread. // pj_status_t create( Pj_Pool *pool, unsigned flags = 0, const char *thread_name = NULL, pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE) { destroy(); return Pj_Thread_API::create( pool, &thread_, &thread_proc, this, flags, thread_name, stack_size); } // // Get pjlib compatible thread object. // pj_thread_t *pj_thread_t_() { return thread_; } // // Get thread name. // const char *get_name() { return Pj_Thread_API::get_name(thread_); } // // Resume a suspended thread. // pj_status_t resume() { return Pj_Thread_API::resume(thread_); } // // Join this thread. // pj_status_t join() { return Pj_Thread_API::join(thread_); } // // Destroy thread. // pj_status_t destroy() { if (thread_) { Pj_Thread_API::destroy(thread_); thread_ = NULL; } } protected: pj_thread_t *thread_; static int PJ_THREAD_FUNC thread_proc(void *obj) { Pj_Thread *thread_class = (Pj_Thread*)obj; return thread_class->main(); } }; // // External Thread // (threads that were started by external means, i.e. not // with Pj_Thread::create). // // This class will normally be defined as local variable in // external thread's stack, normally inside thread's main proc. // But be aware that the handle will be destroyed on destructor! // class Pj_External_Thread : public Pj_Thread { public: Pj_External_Thread() { } // // Register external thread so that pjlib functions can work // in that thread. // pj_status_t register_this_thread( const char *name=NULL ) { return Pj_Thread_API::register_this_thread(desc_, &thread_,name); } private: pj_thread_desc desc_; }; // // Thread specific data/thread local storage/TLS. // class Pj_Thread_Local_API { public: // // Allocate thread local storage (TLS) index. // static pj_status_t alloc(long *index) { return pj_thread_local_alloc(index); } // // Free TLS index. // static void free(long index) { pj_thread_local_free(index); } // // Set thread specific data. // static pj_status_t set(long index, void *value) { return pj_thread_local_set(index, value); } // // Get thread specific data. // static void *get(long index) { return pj_thread_local_get(index); } }; // // Atomic variable // // How to use: // Pj_Atomic_Var var(pool, 0); // var.set(..); // class Pj_Atomic_Var : public Pj_Object { public: // // Default constructor, initialize variable with NULL. // Pj_Atomic_Var() : var_(NULL) { } // // Construct atomic variable. // Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value) : var_(NULL) { create(pool, value); } // // Destructor. // ~Pj_Atomic_Var() { destroy(); } // // Create atomic variable. // pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value) { destroy(); return pj_atomic_create(pool->pool_(), value, &var_); } // // Destroy. // void destroy() { if (var_) { pj_atomic_destroy(var_); var_ = NULL; } } // // Get pjlib compatible atomic variable. // pj_atomic_t *pj_atomic_t_() { return var_; } // // Set the value. // void set(pj_atomic_value_t val) { pj_atomic_set(var_, val); } // // Get the value. // pj_atomic_value_t get() { return pj_atomic_get(var_); } // // Increment. // void inc() { pj_atomic_inc(var_); } // // Increment and get the result. // pj_atomic_value_t inc_and_get() { return pj_atomic_inc_and_get(var_); } // // Decrement. // void dec() { pj_atomic_dec(var_); } // // Decrement and get the result. // pj_atomic_value_t dec_and_get() { return pj_atomic_dec_and_get(var_); } // // Add the variable. // void add(pj_atomic_value_t value) { pj_atomic_add(var_, value); } // // Add the variable and get the value. // pj_atomic_value_t add_and_get(pj_atomic_value_t value) { return pj_atomic_add_and_get(var_, value ); } private: pj_atomic_t *var_; }; // // Mutex // class Pj_Mutex : public Pj_Object { public: // // Mutex type. // enum Type { DEFAULT = PJ_MUTEX_DEFAULT, SIMPLE = PJ_MUTEX_SIMPLE, RECURSE = PJ_MUTEX_RECURSE, }; // // Default constructor will create default mutex. // explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT, const char *name = NULL) : mutex_(NULL) { create(pool, type, name); } // // Destructor. // ~Pj_Mutex() { destroy(); } // // Create mutex. // pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL) { destroy(); return pj_mutex_create( pool->pool_(), name, type, &mutex_ ); } // // Create simple mutex. // pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL) { return create(pool, SIMPLE, name); } // // Create recursive mutex. // pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL ) { return create(pool, RECURSE, name); } // // Get pjlib compatible mutex object. // pj_mutex_t *pj_mutex_t_() { return mutex_; } // // Destroy mutex. // void destroy() { if (mutex_) { pj_mutex_destroy(mutex_); mutex_ = NULL; } } // // Lock mutex. // pj_status_t acquire() { return pj_mutex_lock(mutex_); } // // Unlock mutex. // pj_status_t release() { return pj_mutex_unlock(mutex_); } // // Try locking the mutex. // pj_status_t tryacquire() { return pj_mutex_trylock(mutex_); } private: pj_mutex_t *mutex_; }; // // Semaphore // class Pj_Semaphore : public Pj_Object { public: // // Construct semaphore // Pj_Semaphore(Pj_Pool *pool, unsigned max, unsigned initial = 0, const char *name = NULL) : sem_(NULL) { create(pool, max, initial, name); } // // Destructor. // ~Pj_Semaphore() { destroy(); } // // Create semaphore // pj_status_t create( Pj_Pool *pool, unsigned max, unsigned initial = 0, const char *name = NULL ) { destroy(); return pj_sem_create( pool->pool_(), name, initial, max, &sem_); } // // Destroy semaphore. // void destroy() { if (sem_) { pj_sem_destroy(sem_); sem_ = NULL; } } // // Get pjlib compatible semaphore object. // pj_sem_t *pj_sem_t_() { return (pj_sem_t*)this; } // // Wait semaphore. // pj_status_t wait() { return pj_sem_wait(this->pj_sem_t_()); } // // Wait semaphore. // pj_status_t acquire() { return wait(); } // // Try wait semaphore. // pj_status_t trywait() { return pj_sem_trywait(this->pj_sem_t_()); } // // Try wait semaphore. // pj_status_t tryacquire() { return trywait(); } // // Post semaphore. // pj_status_t post() { return pj_sem_post(this->pj_sem_t_()); } // // Post semaphore. // pj_status_t release() { return post(); } private: pj_sem_t *sem_; }; // // Event object. // class Pj_Event { public: // // Construct event object. // Pj_Event( Pj_Pool *pool, bool manual_reset = false, bool initial = false, const char *name = NULL ) : event_(NULL) { create(pool, manual_reset, initial, name); } // // Destructor. // ~Pj_Event() { destroy(); } // // Create event object. // pj_status_t create( Pj_Pool *pool, bool manual_reset = false, bool initial = false, const char *name = NULL) { destroy(); return pj_event_create(pool->pool_(), name, manual_reset, initial, &event_); } // // Get pjlib compatible event object. // pj_event_t *pj_event_t_() { return event_; } // // Destroy event object. // void destroy() { if (event_) { pj_event_destroy(event_); event_ = NULL; } } // // Wait. // pj_status_t wait() { return pj_event_wait(event_); } // // Try wait. // pj_status_t trywait() { return pj_event_trywait(event_); } // // Set event state to signalled. // pj_status_t set() { return pj_event_set(this->pj_event_t_()); } // // Release one waiting thread. // pj_status_t pulse() { return pj_event_pulse(this->pj_event_t_()); } // // Set a non-signalled. // pj_status_t reset() { return pj_event_reset(this->pj_event_t_()); } private: pj_event_t *event_; }; // // Timestamp // class Pj_Timestamp { public: pj_status_t get_timestamp() { return pj_get_timestamp(&ts_); } Pj_Timestamp& operator += (const Pj_Timestamp &rhs) { pj_add_timestamp(&ts_, &rhs.ts_); return *this; } Pj_Timestamp& operator -= (const Pj_Timestamp &rhs) { pj_sub_timestamp(&ts_, &rhs.ts_); return *this; } Pj_Time_Val to_time() const { Pj_Timestamp zero; pj_memset(&zero, 0, sizeof(zero)); return Pj_Time_Val(pj_elapsed_time(&zero.ts_, &ts_)); } pj_uint32_t to_msec() const { Pj_Timestamp zero; pj_memset(&zero, 0, sizeof(zero)); return pj_elapsed_msec(&zero.ts_, &ts_); } pj_uint32_t to_usec() const { Pj_Timestamp zero; pj_memset(&zero, 0, sizeof(zero)); return pj_elapsed_usec(&zero.ts_, &ts_); } pj_uint32_t to_nanosec() const { Pj_Timestamp zero; pj_memset(&zero, 0, sizeof(zero)); return pj_elapsed_nanosec(&zero.ts_, &ts_); } pj_uint32_t to_cycle() const { Pj_Timestamp zero; pj_memset(&zero, 0, sizeof(zero)); return pj_elapsed_cycle(&zero.ts_, &ts_); } private: pj_timestamp ts_; }; // // OS abstraction. // class Pj_OS_API { public: // // Get current time. // static pj_status_t gettimeofday( Pj_Time_Val *tv ) { return pj_gettimeofday(tv); } // // Parse to time of day. // static pj_status_t time_decode( const Pj_Time_Val *tv, pj_parsed_time *pt ) { return pj_time_decode(tv, pt); } // // Parse from time of day. // static pj_status_t time_encode( const pj_parsed_time *pt, Pj_Time_Val *tv) { return pj_time_encode(pt, tv); } // // Convert to GMT. // static pj_status_t time_local_to_gmt( Pj_Time_Val *tv ) { return pj_time_local_to_gmt( tv ); } // // Convert time to local. // static pj_status_t time_gmt_to_local( Pj_Time_Val *tv) { return pj_time_gmt_to_local( tv ); } }; // // Timeval inlines. // inline pj_status_t Pj_Time_Val::gettimeofday() { return Pj_OS_API::gettimeofday(this); } inline pj_parsed_time Pj_Time_Val::decode() { pj_parsed_time pt; Pj_OS_API::time_decode(this, &pt); return pt; } inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt) { return Pj_OS_API::time_encode(pt, this); } inline pj_status_t Pj_Time_Val::to_gmt() { return Pj_OS_API::time_local_to_gmt(this); } inline pj_status_t Pj_Time_Val::to_local() { return Pj_OS_API::time_gmt_to_local(this); } #endif /* __PJPP_OS_HPP__ */