/* * 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 . */ #ifndef THREADS_H #define THREADS_H #include #include #include #include #include #include #include #include "config.h" #include "Timeval.h" class Mutex; /**@defgroup C++ wrappers for pthread mechanisms. */ //@{ /** A class for recursive mutexes. */ class Mutex { std::recursive_mutex m; public: void lock() { m.lock(); } bool trylock() { return m.try_lock(); } void unlock() { m.unlock(); } friend class Signal; }; class ScopedLock { Mutex &mMutex; public: ScopedLock(Mutex &wMutex) : mMutex(wMutex) { mMutex.lock(); } ~ScopedLock() { mMutex.unlock(); } }; /** A C++ interthread signal. */ class Signal { /* any, because for some reason our mutex is recursive... */ std::condition_variable_any mSignal; public: void wait(Mutex &wMutex, unsigned timeout) { mSignal.wait_for(wMutex.m, std::chrono::milliseconds(timeout)); } void wait(Mutex &wMutex) { mSignal.wait(wMutex.m); } void signal() { mSignal.notify_one(); } void broadcast() { mSignal.notify_all(); } }; 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