dl-fldigi/src/include/threads.h

155 wiersze
4.2 KiB
C++

// ----------------------------------------------------------------------------
// threads.h
//
// Copyright (C) 2007-2009
// Stelios Bounanos, M0GLD
//
// This file is part of fldigi.
//
// Fldigi 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 3 of the License, or
// (at your option) any later version.
//
// Fldigi 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 fldigi. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#ifndef THREADS_H_
#define THREADS_H_
#include <config.h>
#include <pthread.h>
#include <stdint.h>
#include <semaphore.h>
#ifndef WIN32
#if !HAVE_SEM_TIMEDWAIT
# include <time.h>
int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout);
#endif
#else
#include <time.h>
#endif
int sem_timedwait_rel(sem_t* sem, double rel_timeout);
int pthread_cond_timedwait_rel(pthread_cond_t* cond, pthread_mutex_t* mutex, double rel_timeout);
enum {
INVALID_TID = -1,
TRX_TID,
QRZ_TID,
RIGCTL_TID,
NORIGCTL_TID,
EQSL_TID,
ADIF_RW_TID,
XMLRPC_TID,
ARQ_TID,
ARQSOCKET_TID,
MACLOGGER_TID,
KISS_TID,
KISSSOCKET_TID,
FLMAIN_TID,
NUM_THREADS,
NUM_QRUNNER_THREADS = NUM_THREADS - 1
};
#ifdef __linux__
void linux_log_tid(void);
# define LOG_THREAD_ID() linux_log_tid()
#else
# define LOG_THREAD_ID() /* nothing */
#endif
#if USE_TLS
# define THREAD_ID_TYPE __thread intptr_t
# define CREATE_THREAD_ID() thread_id_ = INVALID_TID
# define SET_THREAD_ID(x) do { thread_id_ = (x); LOG_THREAD_ID(); } while (0)
# define GET_THREAD_ID() thread_id_
#else
# define THREAD_ID_TYPE pthread_key_t
# define CREATE_THREAD_ID() pthread_key_create(&thread_id_, NULL)
# define SET_THREAD_ID(x) do { pthread_setspecific(thread_id_, (const void *)(x + 1)); LOG_THREAD_ID(); } while (0)
# define GET_THREAD_ID() ((intptr_t)pthread_getspecific(thread_id_) - 1)
#endif // USE_TLS
extern THREAD_ID_TYPE thread_id_;
#ifndef NDEBUG
# include "debug.h"
bool thread_in_list(int id, const int* list);
# define ENSURE_THREAD(...) \
do { \
int id_ = GET_THREAD_ID(); \
int t_[] = { __VA_ARGS__, INVALID_TID }; \
if (!thread_in_list(id_, t_)) \
LOG_ERROR("bad thread context: %d", id_); \
} while (0)
# define ENSURE_NOT_THREAD(...) \
do { \
int id_ = GET_THREAD_ID(); \
int t_[] = { __VA_ARGS__, INVALID_TID }; \
if (thread_in_list(id_, t_)) \
LOG_ERROR("bad thread context: %d", id_); \
} while (0)
#else
# define ENSURE_THREAD(...) ((void)0)
# define ENSURE_NOT_THREAD(...) ((void)0)
#endif // ! NDEBUG
// On POSIX systems we cancel threads by sending them SIGUSR2,
// which will also interrupt blocking calls. On woe32 we use
// pthread_cancel and there is no good/sane way to interrupt.
#ifndef __WOE32__
#include <signal.h>
# define SET_THREAD_CANCEL() \
do { \
sigset_t usr2; \
sigemptyset(&usr2); \
sigaddset(&usr2, SIGUSR2); \
pthread_sigmask(SIG_UNBLOCK, &usr2, NULL); \
} while (0)
# define TEST_THREAD_CANCEL() /* nothing */
# define CANCEL_THREAD(t__) pthread_kill(t__, SIGUSR2)
#else
// threads have PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DEFERRED when created
# define SET_THREAD_CANCEL() /* nothing */
# define TEST_THREAD_CANCEL() pthread_testcancel()
# define CANCEL_THREAD(t__) pthread_cancel(t__);
#endif
#include "fl_lock.h"
/// This ensures that a mutex is always unlocked when leaving a function or block.
class guard_lock
{
public:
guard_lock(pthread_mutex_t* m);
~guard_lock(void);
private:
pthread_mutex_t* mutex;
};
/// This wraps together a mutex and a condition variable which are used
/// together very often for queues etc...
class syncobj
{
pthread_mutex_t m_mutex ;
pthread_cond_t m_cond ;
public:
syncobj();
~syncobj();
pthread_mutex_t * mtxp(void) { return & m_mutex; }
void signal();
bool wait( double seconds );
};
#endif // !THREADS_H_