870 lines
16 KiB
C++
870 lines
16 KiB
C++
/*
|
|
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
|
|
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
|
|
*
|
|
* 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 <pj/os.h>
|
|
#include <pj/string.h>
|
|
#include <pj++/types.hpp>
|
|
#include <pj++/pool.hpp>
|
|
|
|
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__ */
|
|
|