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