xref: /minix3/minix/lib/libblockdriver/mq.c (revision 0d6c408f48b4681da20972cec48f74e7f509dcbe)
1433d6423SLionel Sambuc /* This file contains a simple message queue implementation to support both
2433d6423SLionel Sambuc  * the singlethread and the multithreaded driver implementation.
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * Changes:
5433d6423SLionel Sambuc  *   Oct 27, 2011   rewritten to use sys/queue.h (D.C. van Moolenbroek)
6433d6423SLionel Sambuc  *   Aug 27, 2011   integrated into libblockdriver (A. Welzel)
7433d6423SLionel Sambuc  */
8433d6423SLionel Sambuc 
9433d6423SLionel Sambuc #include <minix/blockdriver_mt.h>
10433d6423SLionel Sambuc #include <sys/queue.h>
11433d6423SLionel Sambuc #include <assert.h>
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "const.h"
14433d6423SLionel Sambuc #include "mq.h"
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #define MQ_SIZE		128
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc struct mq_cell {
19433d6423SLionel Sambuc   message mess;
20433d6423SLionel Sambuc   int ipc_status;
21433d6423SLionel Sambuc   STAILQ_ENTRY(mq_cell) next;
22433d6423SLionel Sambuc };
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc static struct mq_cell pool[MQ_SIZE];
STAILQ_HEAD(queue,mq_cell)25433d6423SLionel Sambuc static STAILQ_HEAD(queue, mq_cell) queue[MAX_DEVICES];
26433d6423SLionel Sambuc static STAILQ_HEAD(free_list, mq_cell) free_list;
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc /*===========================================================================*
29433d6423SLionel Sambuc  *				mq_init					     *
30433d6423SLionel Sambuc  *===========================================================================*/
31433d6423SLionel Sambuc void mq_init(void)
32433d6423SLionel Sambuc {
33433d6423SLionel Sambuc /* Initialize the message queues and message cells.
34433d6423SLionel Sambuc  */
35433d6423SLionel Sambuc   int i;
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc   STAILQ_INIT(&free_list);
38433d6423SLionel Sambuc 
39433d6423SLionel Sambuc   for (i = 0; i < MAX_DEVICES; i++)
40433d6423SLionel Sambuc 	STAILQ_INIT(&queue[i]);
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc   for (i = 0; i < MQ_SIZE; i++)
43433d6423SLionel Sambuc 	STAILQ_INSERT_HEAD(&free_list, &pool[i], next);
44433d6423SLionel Sambuc }
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc /*===========================================================================*
47433d6423SLionel Sambuc  *				mq_enqueue				     *
48433d6423SLionel Sambuc  *===========================================================================*/
mq_enqueue(device_id_t device_id,const message * mess,int ipc_status)49433d6423SLionel Sambuc int mq_enqueue(device_id_t device_id, const message *mess,
50433d6423SLionel Sambuc   int ipc_status)
51433d6423SLionel Sambuc {
52433d6423SLionel Sambuc /* Add a message, including its IPC status, to the message queue of a device.
53433d6423SLionel Sambuc  * Return TRUE iff the message was added successfully.
54433d6423SLionel Sambuc  */
55433d6423SLionel Sambuc   struct mq_cell *cell;
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc   assert(device_id >= 0 && device_id < MAX_DEVICES);
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc   if (STAILQ_EMPTY(&free_list))
60433d6423SLionel Sambuc 	return FALSE;
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc   cell = STAILQ_FIRST(&free_list);
63433d6423SLionel Sambuc   STAILQ_REMOVE_HEAD(&free_list, next);
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc   cell->mess = *mess;
66433d6423SLionel Sambuc   cell->ipc_status = ipc_status;
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc   STAILQ_INSERT_TAIL(&queue[device_id], cell, next);
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc   return TRUE;
71433d6423SLionel Sambuc }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc /*===========================================================================*
74*0d6c408fSDavid van Moolenbroek  *				mq_isempty				     *
75*0d6c408fSDavid van Moolenbroek  *===========================================================================*/
mq_isempty(device_id_t device_id)76*0d6c408fSDavid van Moolenbroek int mq_isempty(device_id_t device_id)
77*0d6c408fSDavid van Moolenbroek {
78*0d6c408fSDavid van Moolenbroek /* Return whether the message queue for the given device is empty.
79*0d6c408fSDavid van Moolenbroek  */
80*0d6c408fSDavid van Moolenbroek 
81*0d6c408fSDavid van Moolenbroek   assert(device_id >= 0 && device_id < MAX_DEVICES);
82*0d6c408fSDavid van Moolenbroek 
83*0d6c408fSDavid van Moolenbroek   return STAILQ_EMPTY(&queue[device_id]);
84*0d6c408fSDavid van Moolenbroek }
85*0d6c408fSDavid van Moolenbroek 
86*0d6c408fSDavid van Moolenbroek /*===========================================================================*
87433d6423SLionel Sambuc  *				mq_dequeue				     *
88433d6423SLionel Sambuc  *===========================================================================*/
mq_dequeue(device_id_t device_id,message * mess,int * ipc_status)89433d6423SLionel Sambuc int mq_dequeue(device_id_t device_id, message *mess, int *ipc_status)
90433d6423SLionel Sambuc {
91433d6423SLionel Sambuc /* Return and remove a message, including its IPC status, from the message
92433d6423SLionel Sambuc  * queue of a thread. Return TRUE iff a message was available.
93433d6423SLionel Sambuc  */
94433d6423SLionel Sambuc   struct mq_cell *cell;
95433d6423SLionel Sambuc 
96*0d6c408fSDavid van Moolenbroek   if (mq_isempty(device_id))
97433d6423SLionel Sambuc 	return FALSE;
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc   cell = STAILQ_FIRST(&queue[device_id]);
100433d6423SLionel Sambuc   STAILQ_REMOVE_HEAD(&queue[device_id], next);
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc   *mess = cell->mess;
103433d6423SLionel Sambuc   *ipc_status = cell->ipc_status;
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   STAILQ_INSERT_HEAD(&free_list, cell, next);
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   return TRUE;
108433d6423SLionel Sambuc }
109