Skip to content

Commit

Permalink
Moves os select wakeup to a separate file.
Browse files Browse the repository at this point in the history
  • Loading branch information
balazsracz committed Apr 10, 2015
1 parent 5b24456 commit b09ba70
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 59 deletions.
1 change: 1 addition & 0 deletions src/executor/Executor.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "utils/Queue.hxx"
#include "utils/SimpleQueue.hxx"
#include "utils/logging.h"
#include "os/OSSelectWakeup.hxx"

class ActiveTimers;

Expand Down
60 changes: 1 addition & 59 deletions src/os/OS.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -686,64 +686,6 @@ private:
/** handle to event object */
EventGroupHandle_t event;
};
#endif

/** Helper class that allows a select to be asynchronously woken up. */
class OSWakeupSelect
{
public:
OSWakeupSelect()
: pendingWakeup_(0), inSelect_(0) {}

/** Prepares the current thread for asynchronous wakeups. Can be called
* only once. */
void lock_to_thread();

void wakeup() {
pendingWakeup_ = 1;
if (inSelect_) {
#ifdef __FreeRTOS__
Device::select_wakeup(&selectInfo_);
#else
pthread_kill(thread_, WAKEUP_SIG);
#endif
}
}

void clear_wakeup() {
pendingWakeup_ = 0;
}

#ifdef __FreeRTOS__
void wakeup_from_isr() {
pendingWakeup_ = 1;
int woken;
Device::select_wakeup_from_isr(&selectInfo_, &woken);
}
#endif

void select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, long long deadline_nsec) {
inSelect_ = 1;
struct timespec timeout;
if (pendingWakeup_) {
deadline = 0;
}
timeout.tv_sec = deadline_nsec / 1000000000;
timeout.tv_nsec = deadline_nsec % 1000000000;
pselect(nfds, readfds, writefds, exceptfds, &timeout, );
pendingWakeup_ = 0;
inSelect_ = 0;
}

private:
static const int WAKEUP_SIG = SIGUSR1;
unsigned pendingWakeup_ : 1;
#ifdef __FreeRTOS__
Device::SelectInfo selectInfo_;
#else
os_thread_t thread_;
#endif
};

#endif // freertos

#endif /* _OS_OS_HXX_ */
177 changes: 177 additions & 0 deletions src/os/OSSelectWakeup.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/** \copyright
* Copyright (c) 2015, Balazs Racz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \file OSSelectWakeup.hxx
* Helper class for portable wakeup of a thread blocked in a select call.
*
* @author Balazs Racz
* @date 10 Apr 2015
*/

#ifndef _OS_OSSELECTWAKEUP_HXX_
#define _OS_OSSELECTWAKEUP_HXX_

#include "utils/Atomic.hxx"
#include "os/os.h"

#ifndef __FreeRTOS__
#include <signal.h>
#endif

/** Helper class that allows a select to be asynchronously woken up. */
class OSSelectWakeup : private Atomic
{
public:
OSSelectWakeup()
: pendingWakeup_(false)
, inSelect_(false)
{
}

/** Prepares the current thread for asynchronous wakeups. Can be called
* only once. */
void lock_to_thread()
{
#ifdef __FreeRTOS__
Device::select_insert(&selectInfo_);
#else
// Gets the current thread.
thread_ = os_thread_self();
// Blocks SIGUSR1 in the signal mask of the current thread.
sigset_t usrmask;
HASSERT(!sigemptyset(&usrmask));
HASSERT(!sigaddset(&usrmask, WAKEUP_SIG));
HASSERT(!sigprocmask(SIG_BLOCK, &usrmask, &origMask_));
HASSERT(!sigdelset(&origMask_, WAKEUP_SIG));
#endif
}

/** Wakes up the select in the locked thread. */
void wakeup()
{
bool need_wakeup = false;
{
AtomicHolder l(this);
pendingWakeup_ = true;
if (inSelect_)
{
need_wakeup = true;
}
}
if (need_wakeup)
{
#ifdef __FreeRTOS__
Device::select_wakeup(&selectInfo_);
#else
pthread_kill(thread_, WAKEUP_SIG);
#endif
}
}

void clear_wakeup()
{
pendingWakeup_ = false;
}

#ifdef __FreeRTOS__
void wakeup_from_isr()
{
pendingWakeup_ = true;
if (inSelect_)
{
int woken;
Device::select_wakeup_from_isr(&selectInfo_, &woken);
}
}
#endif

/** Portable call to a select that can be woken up asynchronously from a
* different thread or an ISR context.
*
* @param nfds, readfds, writefds, exceptfds is as a regular ::select call.
* @param deadline_nsec is the maximum time to sleep if no fd activity and
* no wakeup happens. -1 to sleep indefinitely, 0 to return immediately.
*
* return what select would return (number of live FDs, 0 in case of
* timeout), or -1 and errno==EINTR if the select was woken up
* asynchronously
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
long long deadline_nsec)
{
{
AtomicHolder l(this);
inSelect_ = true;
if (pendingWakeup_)
{
deadline_nsec = 0;
}
else
{
#ifdef __FreeRTOS__
Device::select_clear();
#endif
}
}
#ifdef __FreeRTOS__
int ret =
Device::select(nfds, readfds, writefds, exceptfds, deadline_nsec);
if (!ret && pendingWakeup_)
{
ret = -1;
errno = EINTR;
}
#else
struct timespec timeout;
timeout.tv_sec = deadline_nsec / 1000000000;
timeout.tv_nsec = deadline_nsec % 1000000000;
int ret =
::pselect(nfds, readfds, writefds, exceptfds, &timeout, &origMask_);
#endif
{
AtomicHolder l(this);
pendingWakeup_ = false;
inSelect_ = false;
}
return ret;
}

private:
/** This signal is used for the wakeup kill in a pthreads OS. */
static const int WAKEUP_SIG = SIGUSR1;
/** True if there was a wakeup call since the previous select finished. */
bool pendingWakeup_;
/** True during the duration of a select operation. */
bool inSelect_;
#ifdef __FreeRTOS__
Device::SelectInfo selectInfo_;
#else
os_thread_t thread_;
sigset_t origMask_;
#endif
};

#endif // _OS_OSSELECTWAKEUP_HXX_

0 comments on commit b09ba70

Please sign in to comment.