xref: /minix3/minix/lib/libblockdriver/mq.c (revision 3956ee9eeda988648c3f2092c7d31faa0a0e7294)
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];
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  *===========================================================================*/
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_dequeue				     *
75  *===========================================================================*/
76 int mq_dequeue(device_id_t device_id, message *mess, int *ipc_status)
77 {
78 /* Return and remove a message, including its IPC status, from the message
79  * queue of a thread. Return TRUE iff a message was available.
80  */
81   struct mq_cell *cell;
82 
83   assert(device_id >= 0 && device_id < MAX_DEVICES);
84 
85   if (STAILQ_EMPTY(&queue[device_id]))
86 	return FALSE;
87 
88   cell = STAILQ_FIRST(&queue[device_id]);
89   STAILQ_REMOVE_HEAD(&queue[device_id], next);
90 
91   *mess = cell->mess;
92   *ipc_status = cell->ipc_status;
93 
94   STAILQ_INSERT_HEAD(&free_list, cell, next);
95 
96   return TRUE;
97 }
98