Add possibility to wait several times on a semaphore

This commit is contained in:
Johan Wikman
2017-04-24 15:38:08 +03:00
parent 19cf8c489e
commit 1eb409a666
3 changed files with 155 additions and 12 deletions

View File

@ -95,7 +95,7 @@ public:
/** /**
* @brief Waits on the semaphore. * @brief Waits on the semaphore.
* *
* If the semaphore count is greater that zero, decrements the count and * If the semaphore count is greater than zero, decrements the count and
* returns immediately. Otherwise blocks the caller until someone posts * returns immediately. Otherwise blocks the caller until someone posts
* the semaphore. * the semaphore.
* *
@ -120,6 +120,39 @@ public:
return rc == 0; 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. * @brief Waits on the semaphore.
* *
@ -190,6 +223,46 @@ public:
return rc == 0; 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. * @brief Waits on the semaphore.
* *
@ -212,7 +285,43 @@ public:
*/ */
bool timedwait(time_t seconds, bool timedwait(time_t seconds,
long nseconds, long nseconds,
signal_approach_t signal_approach = IGNORE_SIGNALS) const; 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. * @brief Waits on the semaphore.
@ -237,6 +346,36 @@ public:
return timedwait(seconds, 0, signal_approach); 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: private:
mutable sem_t m_sem; mutable sem_t m_sem;
}; };

View File

@ -17,13 +17,14 @@
namespace maxscale namespace maxscale
{ {
bool Semaphore::timedwait(time_t seconds, //static
void Semaphore::get_current_timespec(time_t seconds,
long nseconds, long nseconds,
signal_approach_t signal_approach) const timespec* pTs)
{ {
ss_dassert(nseconds <= 999999999); ss_dassert(nseconds <= 999999999);
timespec ts; timespec& ts = *pTs;
ss_debug(int rc=) clock_gettime(CLOCK_REALTIME, &ts); ss_debug(int rc=) clock_gettime(CLOCK_REALTIME, &ts);
ss_dassert(rc == 0); ss_dassert(rc == 0);
@ -39,8 +40,6 @@ bool Semaphore::timedwait(time_t seconds,
} }
ts.tv_nsec = nseconds_sum; ts.tv_nsec = nseconds_sum;
return timedwait(ts, signal_approach);
} }
} }

View File

@ -65,6 +65,14 @@ void test_simple()
ss_dassert(rv); ss_dassert(rv);
cout << "Waited" << endl; cout << "Waited" << endl;
sem2.post();
sem2.post();
sem2.post();
cout << "Waiting 3 times for semaphore with a count of 3." << endl;
rv = sem2.wait_n(3);
cout << "Waited" << endl;
Semaphore sem3; Semaphore sem3;
time_t started; time_t started;
@ -118,10 +126,7 @@ void test_threads()
cout << "Waiting for threads." << endl; cout << "Waiting for threads." << endl;
for (int i = 0; i < n_threads; ++i) sem.wait_n(n_threads);
{
sem.wait();
}
cout << "Joining threads." << endl; cout << "Joining threads." << endl;