aboutsummaryrefslogtreecommitdiffstats
path: root/include/distortos/internal/synchronization/FifoQueueBase.hpp
blob: f45eec8bc0d134c9c19b5cc36d7e167de12961e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * \file
 * \brief FifoQueueBase class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel 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/.
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_FIFOQUEUEBASE_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_FIFOQUEUEBASE_HPP_

#include "distortos/Semaphore.hpp"

#include "distortos/internal/synchronization/QueueFunctor.hpp"
#include "distortos/internal/synchronization/SemaphoreFunctor.hpp"

#include <memory>

namespace distortos
{

namespace internal
{

/// FifoQueueBase class implements basic functionality of FifoQueue template class
class FifoQueueBase
{
public:

	/// unique_ptr (with deleter) to storage
	using StorageUniquePointer = std::unique_ptr<void, void(&)(void*)>;

	/**
	 * \brief FifoQueueBase's constructor
	 *
	 * \param [in] storageUniquePointer is a rvalue reference to StorageUniquePointer with storage for queue elements
	 * (sufficiently large for \a maxElements, each \a elementSize bytes long) and appropriate deleter
	 * \param [in] elementSize is the size of single queue element, bytes
	 * \param [in] maxElements is the number of elements in storage
	 */

	FifoQueueBase(StorageUniquePointer&& storageUniquePointer, size_t elementSize, size_t maxElements);

	/**
	 * \brief FifoQueueBase's destructor
	 */

	~FifoQueueBase();

	/**
	 * \return size of single queue element, bytes
	 */

	size_t getElementSize() const
	{
		return elementSize_;
	}

	/**
	 * \brief Implementation of pop() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a popSemaphore_
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to popping - it will get
	 * readPosition_ as argument
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int pop(const SemaphoreFunctor& waitSemaphoreFunctor, const QueueFunctor& functor)
	{
		return popPush(waitSemaphoreFunctor, functor, popSemaphore_, pushSemaphore_, readPosition_);
	}

	/**
	 * \brief Implementation of push() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a pushSemaphore_
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to pushing - it will get
	 * writePosition_ as argument
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int push(const SemaphoreFunctor& waitSemaphoreFunctor, const QueueFunctor& functor)
	{
		return popPush(waitSemaphoreFunctor, functor, pushSemaphore_, popSemaphore_, writePosition_);
	}

private:

	/**
	 * \brief Implementation of pop() and push() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a waitSemaphore
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to popping/pushing - it
	 * will get \a storage as argument
	 * \param [in] waitSemaphore is a reference to semaphore that will be waited for, \a popSemaphore_ for pop(), \a
	 * pushSemaphore_ for push()
	 * \param [in] postSemaphore is a reference to semaphore that will be posted after the operation, \a pushSemaphore_
	 * for pop(), \a popSemaphore_ for push()
	 * \param [in] storage is a reference to appropriate pointer to storage, which will be passed to \a functor, \a
	 * readPosition_ for pop(), \a writePosition_ for push()
	 *
	 * \return zero if operation was successful, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int popPush(const SemaphoreFunctor& waitSemaphoreFunctor, const QueueFunctor& functor, Semaphore& waitSemaphore,
			Semaphore& postSemaphore, void*& storage);

	/// semaphore guarding access to "pop" functions - its value is equal to the number of available elements
	Semaphore popSemaphore_;

	/// semaphore guarding access to "push" functions - its value is equal to the number of free slots
	Semaphore pushSemaphore_;

	/// storage for queue elements
	const StorageUniquePointer storageUniquePointer_;

	/// pointer to past-the-last element of storage for queue elements
	const void* const storageEnd_;

	/// pointer to first element available for reading
	void* readPosition_;

	/// pointer to first free slot available for writing
	void* writePosition_;

	/// size of single queue element, bytes
	const size_t elementSize_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_FIFOQUEUEBASE_HPP_