You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
4.9 KiB
219 lines
4.9 KiB
/* |
|
* Copyright 2008, 2011 Free Software Foundation, Inc. |
|
* |
|
* SPDX-License-Identifier: AGPL-3.0+ |
|
* |
|
* This software is distributed under the terms of the GNU Affero Public License. |
|
* See the COPYING file in the main directory for details. |
|
* |
|
* This use of this software may be subject to additional restrictions. |
|
* See the LEGAL file in the main directory for details. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU Affero General Public License as published by |
|
the Free Software Foundation, either version 3 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 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/>. |
|
|
|
*/ |
|
|
|
|
|
#ifndef THREADS_H |
|
#define THREADS_H |
|
|
|
#include "config.h" |
|
|
|
#include <pthread.h> |
|
#include <iostream> |
|
#include <assert.h> |
|
#include <unistd.h> |
|
|
|
class Mutex; |
|
|
|
|
|
/**@name Multithreaded access for standard streams. */ |
|
//@{ |
|
|
|
/**@name Functions for gStreamLock. */ |
|
//@{ |
|
extern Mutex gStreamLock; ///< global lock for cout and cerr |
|
void lockCerr(); ///< call prior to writing cerr |
|
void unlockCerr(); ///< call after writing cerr |
|
void lockCout(); ///< call prior to writing cout |
|
void unlockCout(); ///< call after writing cout |
|
//@} |
|
|
|
/**@name Macros for standard messages. */ |
|
//@{ |
|
#define COUT(text) { lockCout(); std::cout << text; unlockCout(); } |
|
#define CERR(text) { lockCerr(); std::cerr << __FILE__ << ":" << __LINE__ << ": " << text; unlockCerr(); } |
|
#ifdef NDEBUG |
|
#define DCOUT(text) {} |
|
#define OBJDCOUT(text) {} |
|
#else |
|
#define DCOUT(text) { COUT(__FILE__ << ":" << __LINE__ << " " << text); } |
|
#define OBJDCOUT(text) { DCOUT(this << " " << text); } |
|
#endif |
|
//@} |
|
//@} |
|
|
|
|
|
|
|
/**@defgroup C++ wrappers for pthread mechanisms. */ |
|
//@{ |
|
|
|
/** A class for recursive mutexes based on pthread_mutex. */ |
|
class Mutex { |
|
|
|
private: |
|
|
|
pthread_mutex_t mMutex; |
|
pthread_mutexattr_t mAttribs; |
|
|
|
public: |
|
|
|
Mutex(); |
|
|
|
~Mutex(); |
|
|
|
void lock() { pthread_mutex_lock(&mMutex); } |
|
|
|
bool trylock() { return pthread_mutex_trylock(&mMutex)==0; } |
|
|
|
void unlock() { pthread_mutex_unlock(&mMutex); } |
|
|
|
friend class Signal; |
|
|
|
}; |
|
|
|
|
|
class ScopedLock { |
|
|
|
private: |
|
Mutex& mMutex; |
|
|
|
public: |
|
ScopedLock(Mutex& wMutex) :mMutex(wMutex) { mMutex.lock(); } |
|
~ScopedLock() { mMutex.unlock(); } |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** A C++ interthread signal based on pthread condition variables. */ |
|
class Signal { |
|
|
|
private: |
|
|
|
mutable pthread_cond_t mSignal; |
|
|
|
public: |
|
|
|
Signal() { int s = pthread_cond_init(&mSignal,NULL); assert(!s); } |
|
|
|
~Signal() { pthread_cond_destroy(&mSignal); } |
|
|
|
/** |
|
Block for the signal up to the cancellation timeout. |
|
Under Linux, spurious returns are possible. |
|
*/ |
|
void wait(Mutex& wMutex, unsigned timeout) const; |
|
|
|
/** |
|
Block for the signal. |
|
Under Linux, spurious returns are possible. |
|
*/ |
|
void wait(Mutex& wMutex) const |
|
{ pthread_cond_wait(&mSignal,&wMutex.mMutex); } |
|
|
|
void signal() { pthread_cond_signal(&mSignal); } |
|
|
|
void broadcast() { pthread_cond_broadcast(&mSignal); } |
|
|
|
}; |
|
|
|
|
|
|
|
#define START_THREAD(thread,function,argument) \ |
|
thread.start((void *(*)(void*))function, (void*)argument); |
|
|
|
void set_selfthread_name(const char *name); |
|
void thread_enable_cancel(bool cancel); |
|
|
|
/** A C++ wrapper for pthread threads. */ |
|
class Thread { |
|
|
|
private: |
|
|
|
pthread_t mThread; |
|
pthread_attr_t mAttrib; |
|
// FIXME -- Can this be reduced now? |
|
size_t mStackSize; |
|
|
|
|
|
public: |
|
|
|
/** Create a thread in a non-running state. */ |
|
Thread(size_t wStackSize = 0):mThread((pthread_t)0) { |
|
pthread_attr_init(&mAttrib); // (pat) moved this here. |
|
mStackSize=wStackSize; |
|
} |
|
|
|
/** |
|
Destroy the Thread. |
|
It should be stopped and joined. |
|
*/ |
|
// (pat) If the Thread is destroyed without being started, then mAttrib is undefined. Oops. |
|
~Thread() { pthread_attr_destroy(&mAttrib); } |
|
|
|
|
|
/** Start the thread on a task. */ |
|
void start(void *(*task)(void*), void *arg); |
|
|
|
/** Join a thread that will stop on its own. */ |
|
void join() { |
|
if (mThread) { |
|
int s = pthread_join(mThread, NULL); |
|
assert(!s); |
|
} |
|
} |
|
|
|
/** Send cancellation to thread */ |
|
void cancel() { pthread_cancel(mThread); } |
|
}; |
|
|
|
#ifdef HAVE_ATOMIC_OPS |
|
#define osmo_trx_sync_fetch_and_and(ptr, value) __sync_fetch_and_and((ptr), (value)) |
|
#define osmo_trx_sync_or_and_fetch(ptr, value) __sync_or_and_fetch((ptr), (value)) |
|
#else |
|
extern pthread_mutex_t atomic_ops_mutex; |
|
static inline int osmo_trx_sync_fetch_and_and(int *ptr, int value) |
|
{ |
|
pthread_mutex_lock(&atomic_ops_mutex); |
|
int tmp = *ptr; |
|
*ptr &= value; |
|
pthread_mutex_unlock(&atomic_ops_mutex); |
|
return tmp; |
|
} |
|
|
|
static inline int osmo_trx_sync_or_and_fetch(int *ptr, int value) |
|
{ |
|
int tmp; |
|
pthread_mutex_lock(&atomic_ops_mutex); |
|
*ptr |= value; |
|
tmp = *ptr; |
|
pthread_mutex_unlock(&atomic_ops_mutex); |
|
return tmp; |
|
} |
|
#endif |
|
|
|
#endif |
|
// vim: ts=4 sw=4
|
|
|