xref: /minix3/minix/lib/libblockdriver/mq.c (revision 0d6c408f48b4681da20972cec48f74e7f509dcbe)
1 /* This file contains a simple message queue implementation to support both
2  * the singlethread and the multithreaded driver implementation.
3  *
4  * Changes:
5  *   Oct 27, 2011   rewritten to use sys/queue.h (D.C. van Moolenbroek)
6  *   Aug 27, 2011   integrated into libblockdriver (A. Welzel)
7  */
8 
9 #include <minix/blockdriver_mt.h>
10 #include <sys/queue.h>
11 #include <assert.h>
12 
13 #include "const.h"
14 #include "mq.h"
15 
16 #define MQ_SIZE		128
17 
18 struct mq_cell {
19   message mess;
20   int ipc_status;
21   STAILQ_ENTRY(mq_cell) next;
22 };
23 
24 static struct mq_cell pool[MQ_SIZE];
STAILQ_HEAD(queue,mq_cell)25 static STAILQ_HEAD(queue, mq_cell) queue[MAX_DEVICES];
26 static STAILQ_HEAD(free_list, mq_cell) free_list;
27 
28 /*===========================================================================*
29  *				mq_init					     *
30  *===========================================================================*/
31 void mq_init(void)
32 {
33 /* Initialize the message queues and message cells.
34  */
35   int i;
36 
37   STAILQ_INIT(&free_list);
38 
39   for (i = 0; i < MAX_DEVICES; i++)
40 	STAILQ_INIT(&queue[i]);
41 
42   for (i = 0; i < MQ_SIZE; i++)
43 	STAILQ_INSERT_HEAD(&free_list, &pool[i], next);
44 }
45 
46 /*===========================================================================*
47  *				mq_enqueue				     *
48  *===========================================================================*/
mq_enqueue(device_id_t device_id,const message * mess,int ipc_status)49 int mq_enqueue(device_id_t device_id, const message *mess,
50   int ipc_status)
51 {
52 /* Add a message, including its IPC status, to the message queue of a device.
53  * Return TRUE iff the message was added successfully.
54  */
55   struct mq_cell *cell;
56 
57   assert(device_id >= 0 && device_id < MAX_DEVICES);
58 
59   if (STAILQ_EMPTY(&free_list))
60 	return FALSE;
61 
62   cell = STAILQ_FIRST(&free_list);
63   STAILQ_REMOVE_HEAD(&free_list, next);
64 
65   cell->mess = *mess;
66   cell->ipc_status = ipc_status;
67 
68   STAILQ_INSERT_TAIL(&queue[device_id], cell, next);
69 
70   return TRUE;
71 }
72 
73 /*===========================================================================*
74  *				mq_isempty				     *
75  *===========================================================================*/
mq_isempty(device_id_t device_id)76 int mq_isempty(device_id_t device_id)
77 {
78 /* Return whether the message queue for the given device is empty.
79  */
80 
81   assert(device_id >= 0 && device_id < MAX_DEVICES);
82 
83   return STAILQ_EMPTY(&queue[device_id]);
84 }
85 
86 /*===========================================================================*
87  *				mq_dequeue				     *
88  *===========================================================================*/
mq_dequeue(device_id_t device_id,message * mess,int * ipc_status)89 int mq_dequeue(device_id_t device_id, message *mess, int *ipc_status)
90 {
91 /* Return and remove a message, including its IPC status, from the message
92  * queue of a thread. Return TRUE iff a message was available.
93  */
94   struct mq_cell *cell;
95 
96   if (mq_isempty(device_id))
97 	return FALSE;
98 
99   cell = STAILQ_FIRST(&queue[device_id]);
100   STAILQ_REMOVE_HEAD(&queue[device_id], next);
101 
102   *mess = cell->mess;
103   *ipc_status = cell->ipc_status;
104 
105   STAILQ_INSERT_HEAD(&free_list, cell, next);
106 
107   return TRUE;
108 }
109