1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/*=============================================================================
29VCOS - packet-like messages, based loosely on those found in TRIPOS.
30
31In the simple case, only the server thread creates a message queue, and
32clients wait for replies on a semaphore. In more complex cases, clients can
33also create message queues (not yet implemented).
34
35Although it's possible for a thread to create multiple queues and listen
36on them in turn, if you find yourself doing this it's probably a bug.
37=============================================================================*/
38
39#ifndef VCOS_MSGQUEUE_H
40#define VCOS_MSGQUEUE_H
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46#include "vcos_types.h"
47#include "vcos.h"
48#include "vcos_blockpool.h"
49
50/**
51 * \file
52 *
53 * Packet-like messages, based loosely on those found in TRIPOS and
54 * derivatives thereof.
55 *
56 * A task can send a message *pointer* to another task, where it is
57 * queued on a linked list and the task woken up. The receiving task
58 * consumes all of the messages on its input queue, and optionally
59 * sends back replies using the original message memory.
60 *
61 * A caller can wait for the reply to a specific message - any other
62 * messages that arrive in the meantime are queued separately.
63 *
64 *
65 * All messages have a standard common layout, but the payload area can
66 * be used freely to extend this.
67 */
68
69#define VCOS_MSGQ_MAGIC 0x5147534d
70
71/** Map the payload portion of a message to a structure pointer.
72 */
73#define VCOS_MSG_DATA(_msg) (void*)((_msg)->data)
74
75/** Standard message ids - FIXME - these need to be done properly! */
76#define VCOS_MSG_N_QUIT 1
77#define VCOS_MSG_N_OPEN 2
78#define VCOS_MSG_N_CLOSE 3
79#define VCOS_MSG_N_PRIVATE (1<<20)
80
81#define VCOS_MSG_REPLY_BIT (1<<31)
82
83/** Make gnuc compiler be happy about pointer punning */
84#ifdef __GNUC__
85#define __VCOS_MAY_ALIAS __attribute__((__may_alias__))
86#else
87#define __VCOS_MAY_ALIAS
88#endif
89
90struct VCOS_MSG_T;
91
92/* Replies go to one of these objects.
93 */
94typedef struct VCOS_MSG_WAITER_T
95{
96 /* When the reply is sent, this function gets called with the
97 * address of the waiter.
98 */
99 void (*on_reply)(struct VCOS_MSG_WAITER_T *waiter,
100 struct VCOS_MSG_T *msg);
101} VCOS_MSG_WAITER_T;
102
103/** A single message queue.
104 */
105typedef struct VCOS_MSGQUEUE_T
106{
107 VCOS_MSG_WAITER_T waiter; /**< So we can wait on a queue */
108 struct VCOS_MSG_T *head; /**< head of linked list of messages waiting on this queue */
109 struct VCOS_MSG_T *tail; /**< tail of message queue */
110 VCOS_SEMAPHORE_T sem; /**< thread waits on this for new messages */
111 VCOS_MUTEX_T lock; /**< locks the messages list */
112 int attached; /**< Is this attached to a thread? */
113} VCOS_MSGQUEUE_T;
114
115/** A single message
116 */
117typedef struct VCOS_MSG_T
118{
119 uint32_t magic; /**< Sanity checking */
120 uint32_t code; /**< message code */
121 struct VCOS_MSG_T *next; /**< next in queue */
122 VCOS_THREAD_T *src_thread; /**< for debug */
123 struct VCOS_MSG_WAITER_T *waiter; /**< client waiter structure */
124 struct VCOS_MSGQ_POOL_T *pool; /**< Pool allocated from, or NULL */
125} VCOS_MSG_T;
126
127#define MSG_REPLY_BIT (1<<31)
128
129/** Initialize a VCOS_MSG_T. Can also use vcos_msg_init().
130 */
131#define VCOS_MSG_INITIALIZER {VCOS_MSGQ_MAGIC, 0, NULL, NULL, NULL, 0}
132
133/** A pool of messages. This contains its own waiter and
134 * semaphore, as well as a blockpool for the actual memory
135 * management.
136 *
137 * When messages are returned to the waiter, it posts the
138 * semaphore.
139 *
140 * When waiting for a message, we just wait on the semaphore.
141 * When allocating without waiting, we just try-wait on the
142 * semaphore.
143 *
144 * If we managed to claim the semaphore, then by definition
145 * there must be at least that many free messages in the
146 * blockpool.
147 */
148typedef struct VCOS_MSGQ_POOL_T
149{
150 VCOS_MSG_WAITER_T waiter;
151 VCOS_BLOCKPOOL_T blockpool;
152 VCOS_SEMAPHORE_T sem;
153 uint32_t magic;
154} VCOS_MSGQ_POOL_T;
155
156/** Initialise the library. Normally called from vcos_init().
157 */
158VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_init(void);
159
160/** De-initialise the library. Normally called from vcos_deinit().
161 */
162VCOSPRE_ void VCOSPOST_ vcos_msgq_deinit(void);
163
164/** Send a message.
165 *
166 * @param dest Destination message queue
167 * @param code Message code.
168 * @param msg Pointer to message to send. Must not go out of scope before
169 * message is received (do not declare on the stack).
170 */
171VCOSPRE_ void VCOSPOST_ vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg);
172
173/** Send a message and wait for a reply.
174 *
175 * @param dest Destination message queue
176 * @param code Message code.
177 * @param msg Pointer to message to send. May be declared on the stack.
178 */
179VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msg_sendwait(VCOS_MSGQUEUE_T *queue, uint32_t code, VCOS_MSG_T *msg);
180
181/** Wait for a message on a queue.
182 */
183VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_wait(VCOS_MSGQUEUE_T *queue);
184
185/** Peek for a message on this thread's endpoint. If a message is not
186 * available, NULL is returned. If a message is available it will be
187 * removed from the endpoint and returned.
188 */
189VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_peek(VCOS_MSGQUEUE_T *queue);
190
191/** Send a reply to a message
192 */
193VCOSPRE_ void VCOSPOST_ vcos_msg_reply(VCOS_MSG_T *msg);
194
195/** Set the reply queue for a message. When the message is replied-to, it
196 * will return to the given queue.
197 *
198 * @param msg Message
199 * @param queue Message queue the message should return to
200 */
201VCOSPRE_ void VCOSPOST_ vcos_msg_set_source(VCOS_MSG_T *msg, VCOS_MSGQUEUE_T *queue);
202
203/** Initialise a newly allocated message. This only needs to be called
204 * for messages allocated on the stack, heap or statically. It is not
205 * needed for messages allocated from a pool.
206 */
207VCOSPRE_ void VCOSPOST_ vcos_msg_init(VCOS_MSG_T *msg);
208
209/** Create a message queue to wait on.
210 */
211VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_create(VCOS_MSGQUEUE_T *queue, const char *name);
212
213/** Destroy a queue
214 */
215VCOSPRE_ void VCOSPOST_ vcos_msgq_delete(VCOS_MSGQUEUE_T *queue);
216
217/*
218 * Message pools
219 */
220
221/** Create a pool of messages. Messages can be allocated from the pool and
222 * sent to a message queue. Replying to the message will automatically
223 * free it back to the pool.
224 *
225 * The pool is threadsafe.
226 *
227 * @param count number of messages in the pool
228 * @param payload_size maximum message payload size, not including MSG_T.
229 */
230VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_pool_create(
231 VCOS_MSGQ_POOL_T *pool,
232 size_t count,
233 size_t payload_size,
234 const char *name);
235
236/** Destroy a message pool.
237 */
238VCOSPRE_ void VCOSPOST_ vcos_msgq_pool_delete(VCOS_MSGQ_POOL_T *pool);
239
240/** Allocate a message from a message pool.
241 *
242 * Note:
243 *
244 * If the alloc fails (returns NULL) then your worker thread has stopped
245 * servicing requests or your pool is too small for the latency in
246 * the system. Your best bet to handle this is to fail the call that
247 * needs to send the message.
248 *
249 * The returned message payload area is initialised to zero.
250 *
251 * @param pool Pool to allocate from.
252 * @return Message or NULL if pool exhausted.
253 */
254VCOSPRE_ VCOS_MSG_T *VCOSPOST_ vcos_msgq_pool_alloc(VCOS_MSGQ_POOL_T *pool);
255
256/** Wait for a message from a message pool. Waits until a
257 * message is available in the pool and then allocates it. If
258 * one is already available, returns immediately.
259 *
260 * This call can never fail.
261 *
262 * The returned message payload area is initialised to zero.
263 *
264 * @param pool Pool to allocate from.
265 * @return Message
266 */
267VCOSPRE_ VCOS_MSG_T *VCOSPOST_ vcos_msgq_pool_wait(VCOS_MSGQ_POOL_T *pool);
268
269/** Explicitly free a message and return it to its pool.
270 *
271 * @param msg Message to free. No-op if NULL.
272 */
273VCOSPRE_ void VCOSPOST_ vcos_msgq_pool_free(VCOS_MSG_T *msg);
274
275#ifdef __cplusplus
276}
277#endif
278#endif
279
280
281