<commit_before>/**
 * \file
 * \brief ThisThread::Signals namespace implementation
 *
 * \author Copyright (C) 2015 <NAME> http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-14
 */

#include "distortos/ThisThread-Signals.hpp"

#include "distortos/ThisThread.hpp"
#include "distortos/ThreadBase.hpp"

#include "distortos/scheduler/getScheduler.hpp"
#include "distortos/scheduler/Scheduler.hpp"

#include "distortos/signals/SignalsReceiverControlBlock.hpp"

#include "distortos/architecture/InterruptMaskingLock.hpp"

#include <cerrno>

namespace distortos
{

namespace ThisThread
{

namespace Signals
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// SignalsWaitUnblockFunctor is a functor executed when unblocking a thread that is waiting for signal
class SignalsWaitUnblockFunctor : public scheduler::ThreadControlBlock::UnblockFunctor
{
public:

	/**
	 * \brief SignalsWaitUnblockFunctor's constructor
	 *
	 * \param [in] pendingSignalSet is a reference to SignalSet that will be used to return saved pending signal set
	 */

	constexpr explicit SignalsWaitUnblockFunctor(SignalSet& pendingSignalSet) :
			pendingSignalSet_(pendingSignalSet)
	{

	}

	/**
	 * \brief SignalsWaitUnblockFunctor's function call operator
	 *
	 * Saves pending signal set of unblocked thread and clears pointer to set of signals that were "waited for".
	 *
	 * \param [in] threadControlBlock is a reference to ThreadControlBlock that is being unblocked
	 */

	void operator()(scheduler::ThreadControlBlock& threadControlBlock) const override
	{
		const auto signalsReceiverControlBlock = threadControlBlock.getSignalsReceiverControlBlock();
		if (signalsReceiverControlBlock == nullptr)
			return;

		pendingSignalSet_ = signalsReceiverControlBlock->getPendingSignalSet();
		signalsReceiverControlBlock->setWaitingSignalSet(nullptr);
	}

private:

	/// reference to SignalSet that will be used to return saved pending signal set
	SignalSet& pendingSignalSet_;
};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Implementation of distortos::ThisThread::Signals::wait(), distortos::ThisThread::Signals::tryWait() and
 * distortos::ThisThread::Signals::tryWaitUntil().
 *
 * \param [in] signalSet is a reference to set of signals that will be waited for
 * \param [in] nonBlocking selects whether this function operates in blocking mode (false) or non-blocking mode (true)
 * \param [in] timePoint is a pointer to time point at which the wait for signals will be terminated, used only if
 * blocking mode is selected, nullptr to block without timeout
 *
 * \return pair with return code (0 on success, error code otherwise) and signal number of signal that was accepted;
 * error codes:
 * - EAGAIN - no signal specified by \a signalSet was pending and non-blocking mode was selected;
 * - ETIMEDOUT - no signal specified by \a signalSet was generated before specified \a timePoint;
 */

std::pair<int, uint8_t> waitImplementation(const SignalSet& signalSet, const bool nonBlocking,
		const TickClock::time_point* const timePoint)
{
	auto& scheduler = scheduler::getScheduler();
	auto& currentThreadControlBlock = scheduler.getCurrentThreadControlBlock();
	const auto signalsReceiverControlBlock = currentThreadControlBlock.getSignalsReceiverControlBlock();
	if (signalsReceiverControlBlock == nullptr)
		return {ENOTSUP, {}};

	architecture::InterruptMaskingLock interruptMaskingLock;

	const auto bitset = signalSet.getBitset();
	auto pendingSignalSet = currentThreadControlBlock.getPendingSignalSet();
	auto pendingBitset = pendingSignalSet.getBitset();
	auto intersection = bitset & pendingBitset;

	if (intersection.none() == true)	// none of desired signals is pending, so current thread must be blocked
	{
		if (nonBlocking == true)
			return {EAGAIN, {}};

		scheduler::ThreadControlBlockList waitingList {scheduler.getThreadControlBlockListAllocator(),
				scheduler::ThreadControlBlock::State::WaitingForSignal};

		signalsReceiverControlBlock->setWaitingSignalSet(&signalSet);
		const SignalsWaitUnblockFunctor signalsWaitUnblockFunctor {pendingSignalSet};
		const auto ret = timePoint == nullptr ? scheduler.block(waitingList, &signalsWaitUnblockFunctor) :
				scheduler.blockUntil(waitingList, *timePoint, &signalsWaitUnblockFunctor);
		if (ret != 0)
			return {ret, {}};

		pendingBitset = pendingSignalSet.getBitset();
		intersection = bitset & pendingBitset;
	}

	const auto intersectionValue = intersection.to_ulong();
	// GCC builtin - "find first set" - https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
	const auto signalNumber = __builtin_ffsl(intersectionValue) - 1;
	const auto ret = signalsReceiverControlBlock->acceptPendingSignal(signalNumber);
	return {ret, signalNumber};
}

}	// namespace
<commit_msg>ThisThread-Signals: use SignalsReceiverControlBlock::getPendingSignalSet() instead of ThreadControlBlock::getPendingSignalSet() in local waitImplementation()<commit_after>/**
 * \file
 * \brief ThisThread::Signals namespace implementation
 *
 * \author Copyright (C) 2015 <NAME> http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-14
 */

#include "distortos/ThisThread-Signals.hpp"

#include "distortos/ThisThread.hpp"
#include "distortos/ThreadBase.hpp"

#include "distortos/scheduler/getScheduler.hpp"
#include "distortos/scheduler/Scheduler.hpp"

#include "distortos/signals/SignalsReceiverControlBlock.hpp"

#include "distortos/architecture/InterruptMaskingLock.hpp"

#include <cerrno>

namespace distortos
{

namespace ThisThread
{

namespace Signals
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// SignalsWaitUnblockFunctor is a functor executed when unblocking a thread that is waiting for signal
class SignalsWaitUnblockFunctor : public scheduler::ThreadControlBlock::UnblockFunctor
{
public:

	/**
	 * \brief SignalsWaitUnblockFunctor's constructor
	 *
	 * \param [in] pendingSignalSet is a reference to SignalSet that will be used to return saved pending signal set
	 */

	constexpr explicit SignalsWaitUnblockFunctor(SignalSet& pendingSignalSet) :
			pendingSignalSet_(pendingSignalSet)
	{

	}

	/**
	 * \brief SignalsWaitUnblockFunctor's function call operator
	 *
	 * Saves pending signal set of unblocked thread and clears pointer to set of signals that were "waited for".
	 *
	 * \param [in] threadControlBlock is a reference to ThreadControlBlock that is being unblocked
	 */

	void operator()(scheduler::ThreadControlBlock& threadControlBlock) const override
	{
		const auto signalsReceiverControlBlock = threadControlBlock.getSignalsReceiverControlBlock();
		if (signalsReceiverControlBlock == nullptr)
			return;

		pendingSignalSet_ = signalsReceiverControlBlock->getPendingSignalSet();
		signalsReceiverControlBlock->setWaitingSignalSet(nullptr);
	}

private:

	/// reference to SignalSet that will be used to return saved pending signal set
	SignalSet& pendingSignalSet_;
};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Implementation of distortos::ThisThread::Signals::wait(), distortos::ThisThread::Signals::tryWait() and
 * distortos::ThisThread::Signals::tryWaitUntil().
 *
 * \param [in] signalSet is a reference to set of signals that will be waited for
 * \param [in] nonBlocking selects whether this function operates in blocking mode (false) or non-blocking mode (true)
 * \param [in] timePoint is a pointer to time point at which the wait for signals will be terminated, used only if
 * blocking mode is selected, nullptr to block without timeout
 *
 * \return pair with return code (0 on success, error code otherwise) and signal number of signal that was accepted;
 * error codes:
 * - EAGAIN - no signal specified by \a signalSet was pending and non-blocking mode was selected;
 * - ETIMEDOUT - no signal specified by \a signalSet was generated before specified \a timePoint;
 */

std::pair<int, uint8_t> waitImplementation(const SignalSet& signalSet, const bool nonBlocking,
		const TickClock::time_point* const timePoint)
{
	auto& scheduler = scheduler::getScheduler();
	const auto signalsReceiverControlBlock = scheduler.getCurrentThreadControlBlock().getSignalsReceiverControlBlock();
	if (signalsReceiverControlBlock == nullptr)
		return {ENOTSUP, {}};

	architecture::InterruptMaskingLock interruptMaskingLock;

	const auto bitset = signalSet.getBitset();
	auto pendingSignalSet = signalsReceiverControlBlock->getPendingSignalSet();
	auto pendingBitset = pendingSignalSet.getBitset();
	auto intersection = bitset & pendingBitset;

	if (intersection.none() == true)	// none of desired signals is pending, so current thread must be blocked
	{
		if (nonBlocking == true)
			return {EAGAIN, {}};

		scheduler::ThreadControlBlockList waitingList {scheduler.getThreadControlBlockListAllocator(),
				scheduler::ThreadControlBlock::State::WaitingForSignal};

		signalsReceiverControlBlock->setWaitingSignalSet(&signalSet);
		const SignalsWaitUnblockFunctor signalsWaitUnblockFunctor {pendingSignalSet};
		const auto ret = timePoint == nullptr ? scheduler.block(waitingList, &signalsWaitUnblockFunctor) :
				scheduler.blockUntil(waitingList, *timePoint, &signalsWaitUnblockFunctor);
		if (ret != 0)
			return {ret, {}};

		pendingBitset = pendingSignalSet.getBitset();
		intersection = bitset & pendingBitset;
	}

	const auto intersectionValue = intersection.to_ulong();
	// GCC builtin - "find first set" - https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
	const auto signalNumber = __builtin_ffsl(intersectionValue) - 1;
	const auto ret = signalsReceiverControlBlock->acceptPendingSignal(signalNumber);
	return {ret, signalNumber};
}

}	// namespace

{'fraction_non_alphanumeric': 0.17187929927542878, 'fraction_numerical': 0.003668715032559846, 'mean_word_length': 3.3321414382201033, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 18, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '959219', 'n_tokens_mistral': 2993, 'n_tokens_neox': 2826, 'n_words': 847}