blob: 9a20ec21cfc1312a7b36b35c672dd7f0178bd9a9 [file] [log] [blame]
/*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#ifndef THREAD_INCLUDED
#define THREAD_INCLUDED
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <pthread.h>
#include "system/System.h"
/**
* General purpose <b>Thread</b> abstractions. This interface defines object
* types and methods for handling threads, synchronization and semaphores.
*
* @see http://www.mmonit.com/
* @file
*/
/** @cond hidden */
#define wrapper(F) do { \
int status= (F); if (! (status == 0 || status==ETIMEDOUT)) \
THROW(AssertException, "%s -- %s", #F, System_getError(status)); \
} while (0)
/** @endcond */
/** @name Abstract Data Types */
//@{
/**
* Thread object type
* @hideinitializer
*/
#define Thread_T pthread_t
/**
* Semaphore object type
* @hideinitializer
*/
#define Sem_T pthread_cond_t
/**
* Mutex object type
* @hideinitializer
*/
#define Mutex_T pthread_mutex_t
/**
* Read/Write Lock object type
* @hideinitializer
*/
#define Lock_T pthread_rwlock_t
/**
* Thread Data object type
* @hideinitializer
*/
#define ThreadData_T pthread_key_t
//@}
/** @name Thread methods */
//@{
/**
* Create a new thread
* @param thread The thread to create
* @param threadFunc The thread routine to execute
* @param threadArgs Arguments to <code>threadFunc</code>
* @exception AssertException If thread creation failed
* @hideinitializer
*/
#define Thread_create(thread, threadFunc, threadArgs) \
wrapper(pthread_create(&thread, NULL, threadFunc, (void*)threadArgs))
/**
* Returns the thread ID of the calling thread
* @return The id of the calling thread
* @hideinitializer
*/
#define Thread_self() pthread_self()
/**
* Detach a thread
* @param thread The thread to detach
* @exception AssertException If detaching the thread failed
* @hideinitializer
*/
#define Thread_detach(thread) wrapper(pthread_detach(thread))
/**
* Cancel execution of a thread
* @param thread The thread to cancel
* @exception AssertException If thread cancelation failed
* @hideinitializer
*/
#define Thread_cancel(thread) wrapper(pthread_cancel(thread))
/**
* Wait for thread termination
* @param thread The thread to wait for
* @exception AssertException If thread join failed
* @hideinitializer
*/
#define Thread_join(thread) wrapper(pthread_join(thread, NULL))
//@}
/** @name Semaphore methods */
//@{
/**
* Initialize a new semaphore
* @param sem The semaphore to initialize
* @exception AssertException If initialization failed
* @hideinitializer
*/
#define Sem_init(sem) wrapper(pthread_cond_init(&sem, NULL))
/**
* Wait on a semaphore
* @param sem The semaphore to wait on
* @param mutex A mutex to unlock on wait
* @exception AssertException If wait failed
* @hideinitializer
*/
#define Sem_wait(sem, mutex) wrapper(pthread_cond_wait(&sem, &(mutex)))
/**
* Unblock a thread waiting for a semaphore
* @param sem The semaphore to signal
* @exception AssertException If signal failed
* @hideinitializer
*/
#define Sem_signal(sem) wrapper(pthread_cond_signal(&sem))
/**
* Unblock all threads waiting for a semaphore
* @param sem The semaphore to broadcast
* @exception AssertException If broadcast failed
* @hideinitializer
*/
#define Sem_broadcast(sem) wrapper(pthread_cond_broadcast(&sem))
/**
* Destroy a semaphore
* @param sem The semaphore to destroy
* @exception AssertException If destroy failed
* @hideinitializer
*/
#define Sem_destroy(sem) wrapper(pthread_cond_destroy(&sem))
/**
* Wait on a semaphore for a specific amount of time. During the wait
* the mutex is unlocked and reacquired afterwards
* @param sem The semaphore to wait on
* @param mutex A mutex to unlock on wait
* @param time time to wait
* @exception AssertException If the timed wait failed
* @hideinitializer
*/
#define Sem_timeWait(sem, mutex, time) \
wrapper(pthread_cond_timedwait(&sem, &(mutex), &time))
//@}
/** @name Mutex methods */
//@{
/**
* Initialize a new mutex
* @param mutex The mutex to initialize
* @exception AssertException If initialization failed
* @hideinitializer
*/
#define Mutex_init(mutex) wrapper(pthread_mutex_init(&(mutex), NULL))
/**
* Destroy a the given mutex
* @param mutex The mutex to destroy
* @exception AssertException If destroy failed
* @hideinitializer
*/
#define Mutex_destroy(mutex) wrapper(pthread_mutex_destroy(&(mutex)))
/**
* Locks a mutex
* @param mutex The mutex to lock
* @exception AssertException If mutex lock failed
* @hideinitializer
*/
#define Mutex_lock(mutex) wrapper(pthread_mutex_lock(&(mutex)))
/**
* Unlocks a mutex
* @param mutex The mutex to unlock
* @exception AssertException If mutex unlock failed
* @hideinitializer
*/
#define Mutex_unlock(mutex) wrapper(pthread_mutex_unlock(&(mutex)))
/**
* Defines a block of code to execute after the given mutex is locked
* @param mutex The mutex to lock
* @hideinitializer
*/
#define LOCK(mutex) do { Mutex_T *_yymutex= &(mutex); assert(pthread_mutex_lock(_yymutex)==0);
/**
* Ends a LOCK block
* @hideinitializer
*/
#define END_LOCK assert(pthread_mutex_unlock(_yymutex)==0); } while (0)
//@}
/** @name Read/Write Lock methods */
//@{
/**
* Initialize a new read/write lock
* @param lock The lock to initialize
* @exception AssertException If initialization failed
* @hideinitializer
*/
#define Lock_init(lock) wrapper(pthread_rwlock_init(&(lock), NULL))
/**
* Destroy a read/write lock
* @param lock The lock to destroy
* @exception AssertException If destroy failed
* @hideinitializer
*/
#define Lock_destroy(lock) wrapper(pthread_rwlock_destroy(&(lock)))
/**
* Acquire a read/write lock for reading
* @param lock A read/write lock
* @exception AssertException If failed
* @hideinitializer
*/
#define Lock_read(lock) wrapper(pthread_rwlock_rdlock(&(lock)))
/**
* Acquire a read/write lock for writing
* @param lock A read/write lock
* @exception AssertException If failed
* @hideinitializer
*/
#define Lock_write(lock) wrapper(pthread_rwlock_wrlock(&(lock)))
/**
* Release a read/write lock
* @param lock A read/write lock
* @exception AssertException If failed
* @hideinitializer
*/
#define Lock_unlock(lock) wrapper(pthread_rwlock_unlock(&(lock)))
/**
* Defines a block of code to execute after the given read locked is acquired
* @param lock The read lock
* @hideinitializer
*/
#define RLOCK(lock) do { Lock_T *_yyrlock= &(lock); assert(pthread_rwlock_rdlock(_yyrlock)==0);
/**
* Ends a RLOCK block
* @hideinitializer
*/
#define END_RLOCK assert(pthread_rwlock_unlock(_yyrlock)==0); } while (0)
/**
* Defines a block of code to execute after the given write locked is acquired
* @param lock The write lock
* @hideinitializer
*/
#define WLOCK(lock) do { Lock_T *_yywlock= &(lock); assert(pthread_rwlock_wrlock(_yywlock)==0);
/**
* Ends a RLOCK block
* @hideinitializer
*/
#define END_WLOCK assert(pthread_rwlock_unlock(_yywlock)==0); } while (0)
//@}
/** @name Thread data methods */
//@{
/**
* Creates a thread-specific data key.
* @param key The ThreadData_T key to create
* @exception AssertException If thread data creation failed
* @hideinitializer
*/
#define ThreadData_create(key) wrapper(pthread_key_create(&(key), NULL))
/**
* Sets a thread-specific data value. The key is of type ThreadData_T
* @param key The ThreadData_T key to set a new value for
* @param value The value for key
* @exception AssertException If setting thread data failed
* @hideinitializer
*/
#define ThreadData_set(key, value) wrapper(pthread_setspecific((key), (value)))
/**
* Gets a thread-specific data value
* @param key The ThreadData_T key
* @return value of key or NULL of no value was set for the key
* @hideinitializer
*/
#define ThreadData_get(key) pthread_getspecific((key))
//@}
/* ----------------------------------------------------------------- Methods */
//<< Start filter-out
/**
* Initialize Threads. This method should be called at program startup
*/
void Thread_init(void);
/**
* Shutdown and cleanup threads. This method should be called at program termination
*/
void Thread_fini(void);
//>> End filter-out
/**
* Create a new thread in a detached state
* @param thread The thread to create
* @param threadFunc The thread routine to execute
* @param threadArgs Arguments to <code>threadFunc</code>
* @exception AssertException If thread creation failed
*/
void Thread_createDetached(Thread_T *thread, void *(*threadFunc)(void *threadArgs), void *threadArgs);
#endif