minix3/lib/libblockdriver/mq.c

98 lines
2.5 KiB
C

/* This file contains a simple message queue implementation to support both
* the singlethread and the multithreaded driver implementation.
*
* Changes:
* Oct 27, 2011 rewritten to use sys/queue.h (D.C. van Moolenbroek)
* Aug 27, 2011 integrated into libblockdriver (A. Welzel)
*/
#include <minix/blockdriver_mt.h>
#include <sys/queue.h>
#include <assert.h>
#include "const.h"
#include "mq.h"
#define MQ_SIZE 128
struct mq_cell {
message mess;
int ipc_status;
STAILQ_ENTRY(mq_cell) next;
};
static struct mq_cell pool[MQ_SIZE];
static STAILQ_HEAD(queue, mq_cell) queue[MAX_DEVICES];
static STAILQ_HEAD(free_list, mq_cell) free_list;
/*===========================================================================*
* mq_init *
*===========================================================================*/
void mq_init(void)
{
/* Initialize the message queues and message cells.
*/
int i;
STAILQ_INIT(&free_list);
for (i = 0; i < MAX_DEVICES; i++)
STAILQ_INIT(&queue[i]);
for (i = 0; i < MQ_SIZE; i++)
STAILQ_INSERT_HEAD(&free_list, &pool[i], next);
}
/*===========================================================================*
* mq_enqueue *
*===========================================================================*/
int mq_enqueue(device_id_t device_id, const message *mess,
int ipc_status)
{
/* Add a message, including its IPC status, to the message queue of a device.
* Return TRUE iff the message was added successfully.
*/
struct mq_cell *cell;
assert(device_id >= 0 && device_id < MAX_DEVICES);
if (STAILQ_EMPTY(&free_list))
return FALSE;
cell = STAILQ_FIRST(&free_list);
STAILQ_REMOVE_HEAD(&free_list, next);
cell->mess = *mess;
cell->ipc_status = ipc_status;
STAILQ_INSERT_TAIL(&queue[device_id], cell, next);
return TRUE;
}
/*===========================================================================*
* mq_dequeue *
*===========================================================================*/
int mq_dequeue(device_id_t device_id, message *mess, int *ipc_status)
{
/* Return and remove a message, including its IPC status, from the message
* queue of a thread. Return TRUE iff a message was available.
*/
struct mq_cell *cell;
assert(device_id >= 0 && device_id < MAX_DEVICES);
if (STAILQ_EMPTY(&queue[device_id]))
return FALSE;
cell = STAILQ_FIRST(&queue[device_id]);
STAILQ_REMOVE_HEAD(&queue[device_id], next);
*mess = cell->mess;
*ipc_status = cell->ipc_status;
STAILQ_INSERT_HEAD(&free_list, cell, next);
return TRUE;
}