MXS-2017 Move maxscale::Semaphore to maxbase::Semaphore
This commit is contained in:
@ -15,8 +15,8 @@
|
||||
#include <maxscale/ccdefs.hh>
|
||||
|
||||
#include <atomic>
|
||||
#include <maxbase/semaphore.hh>
|
||||
#include <maxscale/monitor.h>
|
||||
#include <maxscale/semaphore.hh>
|
||||
#include <maxscale/worker.hh>
|
||||
|
||||
namespace maxscale
|
||||
@ -209,10 +209,10 @@ protected:
|
||||
|
||||
private:
|
||||
std::atomic<bool> m_thread_running; /**< Thread state. Only visible inside MonitorInstance. */
|
||||
int32_t m_shutdown; /**< Non-zero if the monitor should shut down. */
|
||||
bool m_checked; /**< Whether server access has been checked. */
|
||||
Semaphore m_semaphore; /**< Semaphore for synchronizing with monitor thread. */
|
||||
int64_t m_loop_called; /**< When was the loop called the last time. */
|
||||
int32_t m_shutdown; /**< Non-zero if the monitor should shut down. */
|
||||
bool m_checked; /**< Whether server access has been checked. */
|
||||
mxb::Semaphore m_semaphore; /**< Semaphore for synchronizing with monitor thread. */
|
||||
int64_t m_loop_called; /**< When was the loop called the last time. */
|
||||
|
||||
bool pre_run() final;
|
||||
void post_run() final;
|
||||
|
@ -1,384 +0,0 @@
|
||||
#pragma once
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||
*
|
||||
* Change Date: 2022-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <maxscale/ccdefs.hh>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <maxbase/semaphore.h>
|
||||
#include <maxscale/debug.h>
|
||||
|
||||
namespace maxscale
|
||||
{
|
||||
|
||||
class Semaphore
|
||||
{
|
||||
Semaphore(const Semaphore&);
|
||||
Semaphore& operator = (const Semaphore&);
|
||||
|
||||
public:
|
||||
enum signal_approach_t
|
||||
{
|
||||
HONOUR_SIGNALS, /* Honour signals and return when interrupted. */
|
||||
IGNORE_SIGNALS /* Ignore signals and re-issue the comment when signals occur. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param initial_count The initial count of the semaphore.
|
||||
*
|
||||
* @attention If the value `initial_count` is larger than `SEM_VALUE_MAX`,
|
||||
* the the value will be adjusted down to `SEM_VALUE_MAX`.
|
||||
*/
|
||||
Semaphore(uint32_t initial_count = 0)
|
||||
{
|
||||
if (initial_count > SEM_VALUE_MAX)
|
||||
{
|
||||
initial_count = SEM_VALUE_MAX;
|
||||
}
|
||||
|
||||
ss_debug(int rc =) sem_init(&m_sem, 0, initial_count);
|
||||
ss_dassert(rc == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*
|
||||
* When the semaphore is destructed, its count should be 0 and nobody
|
||||
* should be waiting on it.
|
||||
*/
|
||||
~Semaphore()
|
||||
{
|
||||
#ifdef SS_DEBUG
|
||||
int count;
|
||||
int rc = sem_getvalue(&m_sem, &count);
|
||||
ss_dassert(rc == 0);
|
||||
ss_dassert(count == 0);
|
||||
#endif
|
||||
ss_debug(rc =) sem_destroy(&m_sem);
|
||||
ss_dassert(rc == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Post the semaphore.
|
||||
*
|
||||
* Increments the semaphore. If others threads were blocked in `wait`
|
||||
* one of them will subsequently return.
|
||||
*
|
||||
* @return `True` if the semaphore could be posed, otherwise `false`.
|
||||
* If `false` is returned, then the maximum count of the sempahore
|
||||
* has been reached.
|
||||
*/
|
||||
bool post() const
|
||||
{
|
||||
int rc = sem_post(&m_sem);
|
||||
ss_dassert((rc == 0) || (errno == EOVERFLOW));
|
||||
#ifdef SS_DEBUG
|
||||
if ((rc != 0) && (errno == EOVERFLOW))
|
||||
{
|
||||
ss_info_dassert(!true, "Semaphore overflow; indicates endless loop.");
|
||||
}
|
||||
#endif
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* If the semaphore count is greater than zero, decrements the count and
|
||||
* returns immediately. Otherwise blocks the caller until someone posts
|
||||
* the semaphore.
|
||||
*
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return `True` if the semaphore was waited for, `false` otherwise.
|
||||
*
|
||||
* @attention The function can return `false` only if `signal_approach`
|
||||
* is `HONOUR_SIGNALS`.
|
||||
*/
|
||||
bool wait(signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
rc = sem_wait(&m_sem);
|
||||
}
|
||||
while ((rc != 0) && ((errno == EINTR) && (signal_approach == IGNORE_SIGNALS)));
|
||||
|
||||
ss_dassert((rc == 0) || ((errno == EINTR) && (signal_approach == HONOUR_SIGNALS)));
|
||||
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits multiple times on the semaphore.
|
||||
*
|
||||
* If the semaphore count is greater than or equal to the specified amount,
|
||||
* decrements the count and returns immediately. Otherwise blocks the caller
|
||||
* until the semaphore has been posted the required number of times.
|
||||
*
|
||||
* @param n_wait How many times should be waited.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return How many times the semaphore has been waited on.
|
||||
*
|
||||
* @attention The function can return a different number than `n_wait` only
|
||||
* if `signal_approach` is `HONOUR_SIGNALS`.
|
||||
*/
|
||||
size_t wait_n(size_t n_wait,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
bool waited = true;
|
||||
size_t n_waited = 0;
|
||||
|
||||
while (waited && n_wait--)
|
||||
{
|
||||
waited = wait(signal_approach);
|
||||
if (waited)
|
||||
{
|
||||
++n_waited;
|
||||
}
|
||||
}
|
||||
|
||||
return n_waited;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* If the semaphore count is greater that zero, decrements the count and
|
||||
* returns immediately.
|
||||
*
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return `True` if the semaphore was waited for, `false` otherwise.
|
||||
*
|
||||
* @attention If the function returns `false` and `signal_approch` is
|
||||
* `HONOUR_SIGNALS` then the caller must check the value of
|
||||
* `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `EAGAIN`
|
||||
* and in the latter `EINTR`.
|
||||
*/
|
||||
bool trywait(signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
rc = sem_trywait(&m_sem);
|
||||
}
|
||||
while ((rc != 0) && ((errno == EINTR) && (signal_approach == IGNORE_SIGNALS)));
|
||||
|
||||
ss_dassert((rc == 0) ||
|
||||
(errno == EAGAIN) ||
|
||||
((errno == EINTR) && (signal_approach == HONOUR_SIGNALS)));
|
||||
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* Waits on the sempahore at most until the specified time.
|
||||
*
|
||||
* @param ts The *absolute* time until which the waiting at
|
||||
* most is performed.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return True if the waiting could be performed, false otherwise.
|
||||
*
|
||||
* @attention If the function returns `false` and `signal_approch` is
|
||||
* `HONOUR_SIGNALS` then the caller must check the value of
|
||||
* `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `ETIMEDOUT`
|
||||
* and in the latter `EINTR.
|
||||
*/
|
||||
bool timedwait(struct timespec& ts,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
rc = sem_timedwait(&m_sem, &ts);
|
||||
}
|
||||
while ((rc != 0) && ((errno == EINTR) && (signal_approach == IGNORE_SIGNALS)));
|
||||
|
||||
ss_dassert((rc == 0) ||
|
||||
(errno == ETIMEDOUT) ||
|
||||
((errno == EINTR) && (signal_approach == HONOUR_SIGNALS)));
|
||||
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* Waits on the sempahore the specified number of times, at most until the
|
||||
* specified time.
|
||||
*
|
||||
* @param n_wait How many times should be waited.
|
||||
* @param ts The *absolute* time until which the waiting at
|
||||
* most is performed.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return How many times the semaphore has been waited on. If the
|
||||
* function times out or is interrupted, then the returned
|
||||
* value will be less than `n_wait`.
|
||||
*
|
||||
* @attention If the function returns a value less than `n_count` and
|
||||
* `signal_approch` is `HONOUR_SIGNALS` then the caller must check
|
||||
* the value of `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `ETIMEDOUT`
|
||||
* and in the latter `EINTR.
|
||||
*/
|
||||
size_t timedwait_n(size_t n_wait,
|
||||
struct timespec& ts,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
bool waited = true;
|
||||
size_t n_waited = 0;
|
||||
|
||||
while (waited && n_wait--)
|
||||
{
|
||||
waited = timedwait(ts, signal_approach);
|
||||
if (waited)
|
||||
{
|
||||
++n_waited;
|
||||
}
|
||||
}
|
||||
|
||||
return n_waited;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* Waits on the sempahore at most until the specified amount of time
|
||||
* has passed.
|
||||
*
|
||||
* @param seconds How many seconds to wait at most.
|
||||
* @param nseconds How many nanonseconds to wait at most.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return True if the waiting could be performed, false otherwise.
|
||||
*
|
||||
* @attention `nseconds` must be less than 1000000000.
|
||||
*
|
||||
* @attention If the function returns `false` and `signal_approch` is
|
||||
* `HONOUR_SIGNALS` then the caller must check the value of
|
||||
* `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `ETIMEDOUT`
|
||||
* and in the latter `EINTR.
|
||||
*/
|
||||
bool timedwait(time_t seconds,
|
||||
long nseconds,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
timespec ts;
|
||||
get_current_timespec(seconds, nseconds, &ts);
|
||||
return timedwait(ts, signal_approach);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* Waits on the sempahore the specified number of times at most until the
|
||||
* specified time.
|
||||
*
|
||||
* @param n_wait How many times should be waited.
|
||||
* @param seconds How many seconds to wait at most.
|
||||
* @param nseconds How many nanonseconds to wait at most.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return How many times the semaphore has been waited on. If the
|
||||
* function times out or is interrupted, then the returned
|
||||
* value will be less than `n_wait`.
|
||||
*
|
||||
* @attention If the function returns a value less than `n_count` and
|
||||
* `signal_approch` is `HONOUR_SIGNALS` then the caller must check
|
||||
* the value of `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `ETIMEDOUT`
|
||||
* and in the latter `EINTR.
|
||||
*/
|
||||
size_t timedwait_n(size_t n_wait,
|
||||
time_t seconds,
|
||||
long nseconds,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
timespec ts;
|
||||
get_current_timespec(seconds, nseconds, &ts);
|
||||
return timedwait_n(n_wait, ts, signal_approach);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* Waits on the sempahore at most until the specified amount of time
|
||||
* has passed.
|
||||
*
|
||||
* @param seconds How many seconds to wait at most.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return True if the waiting could be performed, false otherwise.
|
||||
*
|
||||
* @attention If the function returns `false` and `signal_approch` is
|
||||
* `HONOUR_SIGNALS` then the caller must check the value of
|
||||
* `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `ETIMEDOUT`
|
||||
* and in the latter `EINTR.
|
||||
*/
|
||||
bool timedwait(time_t seconds,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
return timedwait(seconds, 0, signal_approach);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the semaphore.
|
||||
*
|
||||
* Waits on the sempahore the specified number of times at most until the
|
||||
* specified time.
|
||||
*
|
||||
* @param n_wait How many times should be waited.
|
||||
* @param seconds How many seconds to wait at most.
|
||||
* @param signal_approach Whether signals should be ignored or honoured.
|
||||
*
|
||||
* @return How many times the semaphore has been waited on. If the
|
||||
* function times out or is interrupted, then the returned
|
||||
* value will be less than `n_wait`.
|
||||
*
|
||||
* @attention If the function returns a value less than `n_count` and
|
||||
* `signal_approch` is `HONOUR_SIGNALS` then the caller must check
|
||||
* the value of `errno` to find out whether the call was timed out or
|
||||
* interrupted. In the former case the value will be `ETIMEDOUT`
|
||||
* and in the latter `EINTR.
|
||||
*/
|
||||
bool timedwait_n(size_t n_wait,
|
||||
time_t seconds,
|
||||
signal_approach_t signal_approach = IGNORE_SIGNALS) const
|
||||
{
|
||||
return timedwait_n(n_wait, seconds, 0, signal_approach);
|
||||
}
|
||||
|
||||
private:
|
||||
static void get_current_timespec(time_t seconds, long nseconds, timespec* pTs);
|
||||
|
||||
private:
|
||||
mutable sem_t m_sem;
|
||||
};
|
||||
|
||||
}
|
@ -20,6 +20,7 @@
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <maxbase/semaphore.hh>
|
||||
#include <maxscale/platform.h>
|
||||
#include <maxscale/session.h>
|
||||
#include <maxscale/utils.hh>
|
||||
@ -31,8 +32,6 @@
|
||||
namespace maxscale
|
||||
{
|
||||
|
||||
class Semaphore;
|
||||
|
||||
struct WORKER_STATISTICS
|
||||
{
|
||||
WORKER_STATISTICS()
|
||||
@ -728,7 +727,7 @@ public:
|
||||
* The semaphore can be used for waiting for the task to be finished.
|
||||
*
|
||||
* @code
|
||||
* Semaphore sem;
|
||||
* mxb::Semaphore sem;
|
||||
* MyTask task;
|
||||
*
|
||||
* pWorker->execute(&task, &sem);
|
||||
@ -737,7 +736,7 @@ public:
|
||||
* MyResult& result = task.result();
|
||||
* @endcode
|
||||
*/
|
||||
bool execute(Task* pTask, Semaphore* pSem, enum execute_mode_t mode);
|
||||
bool execute(Task* pTask, mxb::Semaphore* pSem, enum execute_mode_t mode);
|
||||
|
||||
bool execute(Task* pTask, enum execute_mode_t mode)
|
||||
{
|
||||
@ -765,7 +764,7 @@ public:
|
||||
*
|
||||
* @return True, if task was posted to the worker
|
||||
*/
|
||||
bool execute(std::function<void ()> func, Semaphore* pSem, enum execute_mode_t mode);
|
||||
bool execute(std::function<void ()> func, mxb::Semaphore* pSem, enum execute_mode_t mode);
|
||||
|
||||
bool execute(std::function<void ()> func, enum execute_mode_t mode)
|
||||
{
|
||||
|
Reference in New Issue
Block a user