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