ahci: NCQ support
This commit is contained in:
parent
94da86cbee
commit
8ab7667da4
14 changed files with 615 additions and 398 deletions
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <minix/driver.h>
|
#include <minix/driver.h>
|
||||||
|
|
||||||
|
typedef int device_id_t;
|
||||||
typedef int thread_id_t;
|
typedef int thread_id_t;
|
||||||
|
|
||||||
/* Types supported for the 'type' field of struct blockdriver. */
|
/* Types supported for the 'type' field of struct blockdriver. */
|
||||||
|
@ -26,7 +27,7 @@ struct blockdriver {
|
||||||
_PROTOTYPE( void (*bdr_intr), (unsigned int irqs) );
|
_PROTOTYPE( void (*bdr_intr), (unsigned int irqs) );
|
||||||
_PROTOTYPE( void (*bdr_alarm), (clock_t stamp) );
|
_PROTOTYPE( void (*bdr_alarm), (clock_t stamp) );
|
||||||
_PROTOTYPE( int (*bdr_other), (message *m_ptr) );
|
_PROTOTYPE( int (*bdr_other), (message *m_ptr) );
|
||||||
_PROTOTYPE( int (*bdr_thread), (dev_t minor, thread_id_t *threadp) );
|
_PROTOTYPE( int (*bdr_device), (dev_t minor, device_id_t *id) );
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Functions defined by libblockdriver. These can be used for both
|
/* Functions defined by libblockdriver. These can be used for both
|
||||||
|
|
|
@ -4,13 +4,11 @@
|
||||||
#define BLOCKDRIVER_MT_API 1 /* do not expose the singlethreaded API */
|
#define BLOCKDRIVER_MT_API 1 /* do not expose the singlethreaded API */
|
||||||
#include <minix/blockdriver.h>
|
#include <minix/blockdriver.h>
|
||||||
|
|
||||||
/* The maximum number of worker threads. */
|
|
||||||
#define BLOCKDRIVER_MT_MAX_WORKERS 32
|
|
||||||
|
|
||||||
_PROTOTYPE( void blockdriver_mt_task, (struct blockdriver *driver_tab) );
|
_PROTOTYPE( void blockdriver_mt_task, (struct blockdriver *driver_tab) );
|
||||||
_PROTOTYPE( void blockdriver_mt_sleep, (void) );
|
_PROTOTYPE( void blockdriver_mt_sleep, (void) );
|
||||||
_PROTOTYPE( void blockdriver_mt_wakeup, (thread_id_t id) );
|
_PROTOTYPE( void blockdriver_mt_wakeup, (thread_id_t id) );
|
||||||
_PROTOTYPE( void blockdriver_mt_stop, (void) );
|
|
||||||
_PROTOTYPE( void blockdriver_mt_terminate, (void) );
|
_PROTOTYPE( void blockdriver_mt_terminate, (void) );
|
||||||
|
_PROTOTYPE( void blockdriver_mt_set_workers, (device_id_t id, int workers) );
|
||||||
|
_PROTOTYPE( thread_id_t blockdriver_mt_get_tid, (void) );
|
||||||
|
|
||||||
#endif /* _MINIX_BLOCKDRIVER_MT_H */
|
#endif /* _MINIX_BLOCKDRIVER_MT_H */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,13 +4,13 @@
|
||||||
#include <minix/drivers.h>
|
#include <minix/drivers.h>
|
||||||
|
|
||||||
#define NR_PORTS 32 /* maximum number of ports */
|
#define NR_PORTS 32 /* maximum number of ports */
|
||||||
#define NR_CMDS 1 /* maximum number of queued commands */
|
#define NR_CMDS 32 /* maximum number of queued commands */
|
||||||
|
|
||||||
/* Time values that can be set with options. */
|
/* Time values that can be set with options. */
|
||||||
#define SPINUP_TIMEOUT 5000 /* initial spin-up time (ms) */
|
#define SPINUP_TIMEOUT 5000 /* initial spin-up time (ms) */
|
||||||
#define SIG_TIMEOUT 250 /* time between signature checks (ms) */
|
#define SIG_TIMEOUT 250 /* time between signature checks (ms) */
|
||||||
#define NR_SIG_CHECKS 60 /* maximum number of times to check */
|
#define NR_SIG_CHECKS 60 /* maximum number of times to check */
|
||||||
#define COMMAND_TIMEOUT 5000 /* time to wait for non-I/O cmd (ms) */
|
#define COMMAND_TIMEOUT 10000 /* time to wait for non-I/O cmd (ms) */
|
||||||
#define TRANSFER_TIMEOUT 30000 /* time to wait for I/O cmd (ms) */
|
#define TRANSFER_TIMEOUT 30000 /* time to wait for I/O cmd (ms) */
|
||||||
#define FLUSH_TIMEOUT 60000 /* time to wait for flush cmd (ms) */
|
#define FLUSH_TIMEOUT 60000 /* time to wait for flush cmd (ms) */
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@
|
||||||
#define ATA_H2D_CMD 2 /* Command */
|
#define ATA_H2D_CMD 2 /* Command */
|
||||||
#define ATA_CMD_READ_DMA_EXT 0x25 /* READ DMA EXT */
|
#define ATA_CMD_READ_DMA_EXT 0x25 /* READ DMA EXT */
|
||||||
#define ATA_CMD_WRITE_DMA_EXT 0x35 /* WRITE DMA EXT */
|
#define ATA_CMD_WRITE_DMA_EXT 0x35 /* WRITE DMA EXT */
|
||||||
|
#define ATA_CMD_READ_FPDMA_QUEUED 0x60 /* READ FPDMA QUEUED */
|
||||||
|
#define ATA_CMD_WRITE_FPDMA_QUEUED 0x61 /* WRITE FPDMA QUEUED */
|
||||||
#define ATA_CMD_WRITE_DMA_FUA_EXT 0x3D /* WRITE DMA FUA EXT */
|
#define ATA_CMD_WRITE_DMA_FUA_EXT 0x3D /* WRITE DMA FUA EXT */
|
||||||
#define ATA_CMD_PACKET 0xA0 /* PACKET */
|
#define ATA_CMD_PACKET 0xA0 /* PACKET */
|
||||||
#define ATA_CMD_IDENTIFY_PACKET 0xA1 /* IDENTIFY PACKET DEVICE */
|
#define ATA_CMD_IDENTIFY_PACKET 0xA1 /* IDENTIFY PACKET DEVICE */
|
||||||
|
@ -44,14 +46,20 @@
|
||||||
#define ATA_H2D_LBA_HIGH 6 /* LBA High */
|
#define ATA_H2D_LBA_HIGH 6 /* LBA High */
|
||||||
#define ATA_H2D_DEV 7 /* Device */
|
#define ATA_H2D_DEV 7 /* Device */
|
||||||
#define ATA_DEV_LBA 0x40 /* use LBA addressing */
|
#define ATA_DEV_LBA 0x40 /* use LBA addressing */
|
||||||
|
#define ATA_DEV_FUA 0x80 /* Force Unit Access (FPDMA) */
|
||||||
#define ATA_H2D_LBA_LOW_EXP 8 /* LBA Low (exp) */
|
#define ATA_H2D_LBA_LOW_EXP 8 /* LBA Low (exp) */
|
||||||
#define ATA_H2D_LBA_MID_EXP 9 /* LBA Mid (exp) */
|
#define ATA_H2D_LBA_MID_EXP 9 /* LBA Mid (exp) */
|
||||||
#define ATA_H2D_LBA_HIGH_EXP 10 /* LBA High (exp) */
|
#define ATA_H2D_LBA_HIGH_EXP 10 /* LBA High (exp) */
|
||||||
#define ATA_H2D_FEAT_EXP 11 /* Features (exp) */
|
#define ATA_H2D_FEAT_EXP 11 /* Features (exp) */
|
||||||
#define ATA_H2D_SEC 12 /* Sector Count */
|
#define ATA_H2D_SEC 12 /* Sector Count */
|
||||||
|
#define ATA_SEC_TAG_SHIFT 3 /* NCQ command tag */
|
||||||
#define ATA_H2D_SEC_EXP 13 /* Sector Count (exp) */
|
#define ATA_H2D_SEC_EXP 13 /* Sector Count (exp) */
|
||||||
#define ATA_H2D_CTL 15 /* Control */
|
#define ATA_H2D_CTL 15 /* Control */
|
||||||
|
|
||||||
|
#define ATA_IS_FPDMA_CMD(c) \
|
||||||
|
((c) == ATA_CMD_READ_FPDMA_QUEUED || \
|
||||||
|
(c) == ATA_CMD_WRITE_FPDMA_QUEUED)
|
||||||
|
|
||||||
/* ATA constants. */
|
/* ATA constants. */
|
||||||
#define ATA_SECTOR_SIZE 512 /* default sector size */
|
#define ATA_SECTOR_SIZE 512 /* default sector size */
|
||||||
#define ATA_MAX_SECTORS 0x10000 /* max sectors per transfer */
|
#define ATA_MAX_SECTORS 0x10000 /* max sectors per transfer */
|
||||||
|
@ -73,6 +81,10 @@
|
||||||
#define ATA_ID_DMADIR 62 /* DMADIR */
|
#define ATA_ID_DMADIR 62 /* DMADIR */
|
||||||
#define ATA_ID_DMADIR_DMADIR 0x8000 /* DMADIR required */
|
#define ATA_ID_DMADIR_DMADIR 0x8000 /* DMADIR required */
|
||||||
#define ATA_ID_DMADIR_DMA 0x0400 /* DMA supported (DMADIR) */
|
#define ATA_ID_DMADIR_DMA 0x0400 /* DMA supported (DMADIR) */
|
||||||
|
#define ATA_ID_QDEPTH 75 /* NCQ queue depth */
|
||||||
|
#define ATA_ID_QDEPTH_MASK 0x000F /* NCQ queue depth mask */
|
||||||
|
#define ATA_ID_SATA_CAP 76 /* SATA capabilities */
|
||||||
|
#define ATA_ID_SATA_CAP_NCQ 0x0100 /* NCQ support */
|
||||||
#define ATA_ID_SUP0 82 /* Features supported (1/3) */
|
#define ATA_ID_SUP0 82 /* Features supported (1/3) */
|
||||||
#define ATA_ID_SUP0_WCACHE 0x0020 /* Write cache supported */
|
#define ATA_ID_SUP0_WCACHE 0x0020 /* Write cache supported */
|
||||||
#define ATA_ID_SUP1 83 /* Features supported (2/3) */
|
#define ATA_ID_SUP1 83 /* Features supported (2/3) */
|
||||||
|
@ -160,6 +172,7 @@
|
||||||
#define AHCI_PORT_IS_IFS (1L << 27) /* Interface Fatal */
|
#define AHCI_PORT_IS_IFS (1L << 27) /* Interface Fatal */
|
||||||
#define AHCI_PORT_IS_PRCS (1L << 22) /* PhyRdy Change */
|
#define AHCI_PORT_IS_PRCS (1L << 22) /* PhyRdy Change */
|
||||||
#define AHCI_PORT_IS_PCS (1L << 6) /* Port Conn Change */
|
#define AHCI_PORT_IS_PCS (1L << 6) /* Port Conn Change */
|
||||||
|
#define AHCI_PORT_IS_SDBS (1L << 3) /* Set Device Bits FIS */
|
||||||
#define AHCI_PORT_IS_PSS (1L << 1) /* PIO Setup FIS */
|
#define AHCI_PORT_IS_PSS (1L << 1) /* PIO Setup FIS */
|
||||||
#define AHCI_PORT_IS_DHRS (1L << 0) /* D2H Register FIS */
|
#define AHCI_PORT_IS_DHRS (1L << 0) /* D2H Register FIS */
|
||||||
#define AHCI_PORT_IS_RESTART \
|
#define AHCI_PORT_IS_RESTART \
|
||||||
|
@ -167,7 +180,7 @@
|
||||||
AHCI_PORT_IS_IFS)
|
AHCI_PORT_IS_IFS)
|
||||||
#define AHCI_PORT_IS_MASK \
|
#define AHCI_PORT_IS_MASK \
|
||||||
(AHCI_PORT_IS_RESTART | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS | \
|
(AHCI_PORT_IS_RESTART | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS | \
|
||||||
AHCI_PORT_IS_DHRS | AHCI_PORT_IS_PSS)
|
AHCI_PORT_IS_DHRS | AHCI_PORT_IS_PSS | AHCI_PORT_IS_SDBS)
|
||||||
#define AHCI_PORT_IE 5 /* Interrupt Enable */
|
#define AHCI_PORT_IE 5 /* Interrupt Enable */
|
||||||
#define AHCI_PORT_IE_MASK AHCI_PORT_IS_MASK
|
#define AHCI_PORT_IE_MASK AHCI_PORT_IS_MASK
|
||||||
#define AHCI_PORT_IE_PRCE AHCI_PORT_IS_PRCS
|
#define AHCI_PORT_IE_PRCE AHCI_PORT_IS_PRCS
|
||||||
|
@ -196,6 +209,7 @@
|
||||||
#define AHCI_PORT_SCTL_DET_NONE 0x00000000L /* No Action Req'd */
|
#define AHCI_PORT_SCTL_DET_NONE 0x00000000L /* No Action Req'd */
|
||||||
#define AHCI_PORT_SERR 12 /* Serial ATA Error */
|
#define AHCI_PORT_SERR 12 /* Serial ATA Error */
|
||||||
#define AHCI_PORT_SERR_DIAG_N (1L << 16) /* PhyRdy Change */
|
#define AHCI_PORT_SERR_DIAG_N (1L << 16) /* PhyRdy Change */
|
||||||
|
#define AHCI_PORT_SACT 13 /* Serial ATA Active */
|
||||||
#define AHCI_PORT_CI 14 /* Command Issue */
|
#define AHCI_PORT_CI 14 /* Command Issue */
|
||||||
|
|
||||||
/* Number of Physical Region Descriptors (PRDs). Must be at least NR_IOREQS+2,
|
/* Number of Physical Region Descriptors (PRDs). Must be at least NR_IOREQS+2,
|
||||||
|
@ -262,6 +276,12 @@ enum {
|
||||||
STATE_GOOD_DEV /* a usable device has been detected */
|
STATE_GOOD_DEV /* a usable device has been detected */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Command results. */
|
||||||
|
enum {
|
||||||
|
RESULT_FAILURE,
|
||||||
|
RESULT_SUCCESS
|
||||||
|
};
|
||||||
|
|
||||||
/* Port flags. */
|
/* Port flags. */
|
||||||
#define FLAG_ATAPI 0x00000001 /* is this an ATAPI device? */
|
#define FLAG_ATAPI 0x00000001 /* is this an ATAPI device? */
|
||||||
#define FLAG_HAS_MEDIUM 0x00000002 /* is a medium present? */
|
#define FLAG_HAS_MEDIUM 0x00000002 /* is a medium present? */
|
||||||
|
@ -274,6 +294,8 @@ enum {
|
||||||
#define FLAG_HAS_FLUSH 0x00000100 /* is FLUSH CACHE supported? */
|
#define FLAG_HAS_FLUSH 0x00000100 /* is FLUSH CACHE supported? */
|
||||||
#define FLAG_SUSPENDED 0x00000200 /* is the thread suspended? */
|
#define FLAG_SUSPENDED 0x00000200 /* is the thread suspended? */
|
||||||
#define FLAG_HAS_FUA 0x00000400 /* is WRITE DMA FUA EX sup.? */
|
#define FLAG_HAS_FUA 0x00000400 /* is WRITE DMA FUA EX sup.? */
|
||||||
|
#define FLAG_HAS_NCQ 0x00000800 /* is NCQ supported? */
|
||||||
|
#define FLAG_NCQ_MODE 0x00001000 /* issuing NCQ commands? */
|
||||||
|
|
||||||
/* Mapping between devices and ports. */
|
/* Mapping between devices and ports. */
|
||||||
#define NO_PORT -1 /* this device maps to no port */
|
#define NO_PORT -1 /* this device maps to no port */
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
LIB= blockdriver
|
LIB= blockdriver
|
||||||
|
|
||||||
SRCS= driver.c drvlib.c driver_st.c driver_mt.c mq.c event.c trace.c
|
SRCS= driver.c drvlib.c driver_st.c driver_mt.c mq.c trace.c
|
||||||
|
|
||||||
.if ${USE_STATECTL} != "no"
|
.if ${USE_STATECTL} != "no"
|
||||||
CPPFLAGS+= -DUSE_STATECTL
|
CPPFLAGS+= -DUSE_STATECTL
|
||||||
|
|
14
lib/libblockdriver/const.h
Normal file
14
lib/libblockdriver/const.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef _BLOCKDRIVER_CONST_H
|
||||||
|
#define _BLOCKDRIVER_CONST_H
|
||||||
|
|
||||||
|
/* Maximum number of devices supported. */
|
||||||
|
#define MAX_DEVICES 32
|
||||||
|
|
||||||
|
/* The maximum number of worker threads per device. */
|
||||||
|
#define MAX_WORKERS 32
|
||||||
|
|
||||||
|
#define MAX_THREADS (MAX_DEVICES * MAX_WORKERS) /* max nr of threads */
|
||||||
|
#define MAIN_THREAD (MAX_THREADS) /* main thread ID */
|
||||||
|
#define SINGLE_THREAD (0) /* single-thread ID */
|
||||||
|
|
||||||
|
#endif /* _BLOCKDRIVER_CONST_H */
|
|
@ -1,9 +1,6 @@
|
||||||
#ifndef _BLOCKDRIVER_DRIVER_H
|
#ifndef _BLOCKDRIVER_DRIVER_H
|
||||||
#define _BLOCKDRIVER_DRIVER_H
|
#define _BLOCKDRIVER_DRIVER_H
|
||||||
|
|
||||||
#define SINGLE_THREAD (0) /* single-thread ID */
|
|
||||||
#define MAIN_THREAD (BLOCKDRIVER_MT_MAX_WORKERS) /* main thread ID */
|
|
||||||
|
|
||||||
_PROTOTYPE( void blockdriver_handle_notify, (struct blockdriver *bdp,
|
_PROTOTYPE( void blockdriver_handle_notify, (struct blockdriver *bdp,
|
||||||
message *m_ptr) );
|
message *m_ptr) );
|
||||||
_PROTOTYPE( int blockdriver_handle_request, (struct blockdriver *bdp,
|
_PROTOTYPE( int blockdriver_handle_request, (struct blockdriver *bdp,
|
||||||
|
|
|
@ -8,84 +8,132 @@
|
||||||
* blockdriver_mt_terminate: break out of the main message loop
|
* blockdriver_mt_terminate: break out of the main message loop
|
||||||
* blockdriver_mt_sleep: put the current thread to sleep
|
* blockdriver_mt_sleep: put the current thread to sleep
|
||||||
* blockdriver_mt_wakeup: wake up a sleeping thread
|
* blockdriver_mt_wakeup: wake up a sleeping thread
|
||||||
* blockdriver_mt_stop: put up the current thread for termination
|
* blockdriver_mt_set_workers:set the number of worker threads
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <minix/blockdriver_mt.h>
|
#include <minix/blockdriver_mt.h>
|
||||||
#include <minix/mthread.h>
|
#include <minix/mthread.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "const.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include "mq.h"
|
#include "mq.h"
|
||||||
#include "event.h"
|
|
||||||
|
/* A thread ID is composed of a device ID and a per-device worker thread ID.
|
||||||
|
* All thread IDs must be in the range 0..(MAX_THREADS-1) inclusive.
|
||||||
|
*/
|
||||||
|
#define MAKE_TID(did, wid) ((did) * MAX_WORKERS + (wid))
|
||||||
|
#define TID_DEVICE(tid) ((tid) / MAX_WORKERS)
|
||||||
|
#define TID_WORKER(tid) ((tid) % MAX_WORKERS)
|
||||||
|
|
||||||
|
typedef int worker_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STATE_DEAD,
|
STATE_DEAD,
|
||||||
STATE_RUNNING,
|
STATE_RUNNING,
|
||||||
STATE_STOPPING,
|
STATE_BUSY,
|
||||||
STATE_EXITED
|
STATE_EXITED
|
||||||
} worker_state;
|
} worker_state;
|
||||||
|
|
||||||
/* Structure to handle running worker threads. */
|
/* Structure with information about a worker thread. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
thread_id_t id;
|
device_id_t device_id;
|
||||||
|
worker_id_t worker_id;
|
||||||
worker_state state;
|
worker_state state;
|
||||||
mthread_thread_t mthread;
|
mthread_thread_t mthread;
|
||||||
event_t queue_event;
|
mthread_event_t sleep_event;
|
||||||
event_t sleep_event;
|
|
||||||
} worker_t;
|
} worker_t;
|
||||||
|
|
||||||
|
/* Structure with information about a device. */
|
||||||
|
typedef struct {
|
||||||
|
device_id_t id;
|
||||||
|
unsigned int workers;
|
||||||
|
worker_t worker[MAX_WORKERS];
|
||||||
|
mthread_event_t queue_event;
|
||||||
|
mthread_rwlock_t barrier;
|
||||||
|
} device_t;
|
||||||
|
|
||||||
PRIVATE struct blockdriver *bdtab;
|
PRIVATE struct blockdriver *bdtab;
|
||||||
PRIVATE int running = FALSE;
|
PRIVATE int running = FALSE;
|
||||||
|
|
||||||
PRIVATE mthread_key_t worker_key;
|
PRIVATE mthread_key_t worker_key;
|
||||||
|
|
||||||
PRIVATE worker_t worker[BLOCKDRIVER_MT_MAX_WORKERS];
|
PRIVATE device_t device[MAX_DEVICES];
|
||||||
|
|
||||||
PRIVATE worker_t *exited[BLOCKDRIVER_MT_MAX_WORKERS];
|
PRIVATE worker_t *exited[MAX_THREADS];
|
||||||
PRIVATE int num_exited = 0;
|
PRIVATE int num_exited = 0;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* enqueue *
|
* enqueue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE void enqueue(worker_t *wp, const message *m_src, int ipc_status)
|
PRIVATE void enqueue(device_t *dp, const message *m_src, int ipc_status)
|
||||||
{
|
{
|
||||||
/* Enqueue a message into a worker thread's queue, and signal the thread.
|
/* Enqueue a message into the device's queue, and signal the event.
|
||||||
* Must be called from the master thread.
|
* Must be called from the master thread.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
assert(wp->state == STATE_RUNNING || wp->state == STATE_STOPPING);
|
if (!mq_enqueue(dp->id, m_src, ipc_status))
|
||||||
|
|
||||||
if (!mq_enqueue(wp->id, m_src, ipc_status))
|
|
||||||
panic("blockdriver_mt: enqueue failed (message queue full)");
|
panic("blockdriver_mt: enqueue failed (message queue full)");
|
||||||
|
|
||||||
event_fire(&wp->queue_event);
|
mthread_event_fire(&dp->queue_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* try_dequeue *
|
* try_dequeue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE int try_dequeue(worker_t *wp, message *m_dst, int *ipc_status)
|
PRIVATE int try_dequeue(device_t *dp, message *m_dst, int *ipc_status)
|
||||||
{
|
{
|
||||||
/* See if a message can be dequeued from the current worker thread's queue. If
|
/* See if a message can be dequeued from the current worker thread's device
|
||||||
* so, dequeue the message and return TRUE. If not, return FALSE. Must be
|
* queue. If so, dequeue the message and return TRUE. If not, return FALSE.
|
||||||
* called from a worker thread. Does not block.
|
* Must be called from a worker thread. Does not block.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return mq_dequeue(wp->id, m_dst, ipc_status);
|
return mq_dequeue(dp->id, m_dst, ipc_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* dequeue *
|
* dequeue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE void dequeue(worker_t *wp, message *m_dst, int *ipc_status)
|
PRIVATE int dequeue(device_t *dp, worker_t *wp, message *m_dst,
|
||||||
|
int *ipc_status)
|
||||||
{
|
{
|
||||||
/* Dequeue a message from the current worker thread's queue. Block the current
|
/* Dequeue a message from the current worker thread's device queue. Block the
|
||||||
* thread if necessary. Must be called from a worker thread. Always successful.
|
* current thread if necessary. Must be called from a worker thread. Either
|
||||||
|
* succeeds with a message (TRUE) or indicates that the thread should be
|
||||||
|
* terminated (FALSE).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while (!try_dequeue(wp, m_dst, ipc_status))
|
do {
|
||||||
event_wait(&wp->queue_event);
|
mthread_event_wait(&dp->queue_event);
|
||||||
|
|
||||||
|
/* If we were woken up as a result of terminate or set_workers, break
|
||||||
|
* out of the loop and terminate the thread.
|
||||||
|
*/
|
||||||
|
if (!running || wp->worker_id >= dp->workers)
|
||||||
|
return FALSE;
|
||||||
|
} while (!try_dequeue(dp, m_dst, ipc_status));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* is_transfer_req *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE int is_transfer_req(int type)
|
||||||
|
{
|
||||||
|
/* Return whether the given block device request is a transfer request.
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case BDEV_READ:
|
||||||
|
case BDEV_WRITE:
|
||||||
|
case BDEV_GATHER:
|
||||||
|
case BDEV_SCATTER:
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -99,36 +147,50 @@ PRIVATE void *worker_thread(void *param)
|
||||||
* for this condition and exit if so.
|
* for this condition and exit if so.
|
||||||
*/
|
*/
|
||||||
worker_t *wp;
|
worker_t *wp;
|
||||||
|
device_t *dp;
|
||||||
|
thread_id_t tid;
|
||||||
message m;
|
message m;
|
||||||
int ipc_status, r;
|
int ipc_status, r;
|
||||||
|
|
||||||
wp = (worker_t *) param;
|
wp = (worker_t *) param;
|
||||||
assert(wp != NULL);
|
assert(wp != NULL);
|
||||||
|
dp = &device[wp->device_id];
|
||||||
|
tid = MAKE_TID(wp->device_id, wp->worker_id);
|
||||||
|
|
||||||
if (mthread_setspecific(worker_key, wp))
|
if (mthread_setspecific(worker_key, wp))
|
||||||
panic("blockdriver_mt: could not save local thread pointer");
|
panic("blockdriver_mt: could not save local thread pointer");
|
||||||
|
|
||||||
while (running) {
|
while (running && wp->worker_id < dp->workers) {
|
||||||
|
|
||||||
/* See if a new message is available right away. */
|
/* See if a new message is available right away. */
|
||||||
if (!try_dequeue(wp, &m, &ipc_status)) {
|
if (!try_dequeue(dp, &m, &ipc_status)) {
|
||||||
/* If not, and this thread should be stopped, stop now. */
|
|
||||||
if (wp->state == STATE_STOPPING)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Otherwise, block waiting for a new message. */
|
/* If not, block waiting for a new message or a thread
|
||||||
dequeue(wp, &m, &ipc_status);
|
* termination event.
|
||||||
|
*/
|
||||||
if (!running)
|
if (!dequeue(dp, wp, &m, &ipc_status))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Even if the thread was stopped before, a new message resumes it. */
|
/* Even if the thread was stopped before, a new message resumes it. */
|
||||||
wp->state = STATE_RUNNING;
|
wp->state = STATE_BUSY;
|
||||||
|
|
||||||
/* Handle the request, and send a reply. */
|
/* If the request is a transfer request, we acquire the read barrier
|
||||||
r = blockdriver_handle_request(bdtab, &m, wp->id);
|
* lock. Otherwise, we acquire the write lock.
|
||||||
|
*/
|
||||||
|
if (is_transfer_req(m.m_type))
|
||||||
|
mthread_rwlock_rdlock(&dp->barrier);
|
||||||
|
else
|
||||||
|
mthread_rwlock_wrlock(&dp->barrier);
|
||||||
|
|
||||||
|
/* Handle the request and send a reply. */
|
||||||
|
r = blockdriver_handle_request(bdtab, &m, tid);
|
||||||
|
|
||||||
blockdriver_reply(&m, ipc_status, r);
|
blockdriver_reply(&m, ipc_status, r);
|
||||||
|
|
||||||
|
/* Switch the thread back to running state, and unlock the barrier. */
|
||||||
|
wp->state = STATE_RUNNING;
|
||||||
|
mthread_rwlock_unlock(&dp->barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up and terminate this thread. */
|
/* Clean up and terminate this thread. */
|
||||||
|
@ -145,23 +207,24 @@ PRIVATE void *worker_thread(void *param)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* master_create_worker *
|
* master_create_worker *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE void master_create_worker(worker_t *wp, thread_id_t id)
|
PRIVATE void master_create_worker(worker_t *wp, worker_id_t worker_id,
|
||||||
|
device_id_t device_id)
|
||||||
{
|
{
|
||||||
/* Start a new worker thread.
|
/* Start a new worker thread.
|
||||||
*/
|
*/
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
wp->id = id;
|
wp->device_id = device_id;
|
||||||
|
wp->worker_id = worker_id;
|
||||||
wp->state = STATE_RUNNING;
|
wp->state = STATE_RUNNING;
|
||||||
|
|
||||||
/* Initialize synchronization primitives. */
|
/* Initialize synchronization primitives. */
|
||||||
event_init(&wp->queue_event);
|
mthread_event_init(&wp->sleep_event);
|
||||||
event_init(&wp->sleep_event);
|
|
||||||
|
|
||||||
r = mthread_create(&wp->mthread, NULL /*attr*/, worker_thread, (void *) wp);
|
r = mthread_create(&wp->mthread, NULL /*attr*/, worker_thread, (void *) wp);
|
||||||
|
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
panic("blockdriver_mt: could not start thread %d (%d)", id, r);
|
panic("blockdriver_mt: could not start thread %d (%d)", worker_id, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -171,20 +234,16 @@ PRIVATE void master_destroy_worker(worker_t *wp)
|
||||||
{
|
{
|
||||||
/* Clean up resources used by an exited worker thread.
|
/* Clean up resources used by an exited worker thread.
|
||||||
*/
|
*/
|
||||||
message m;
|
|
||||||
int ipc_status;
|
|
||||||
|
|
||||||
assert(wp != NULL);
|
assert(wp != NULL);
|
||||||
assert(wp->state == STATE_EXITED);
|
assert(wp->state == STATE_EXITED);
|
||||||
assert(!mq_dequeue(wp->id, &m, &ipc_status));
|
|
||||||
|
|
||||||
/* Join the thread. */
|
/* Join the thread. */
|
||||||
if (mthread_join(wp->mthread, NULL))
|
if (mthread_join(wp->mthread, NULL))
|
||||||
panic("blockdriver_mt: could not join thread %d", wp->id);
|
panic("blockdriver_mt: could not join thread %d", wp->worker_id);
|
||||||
|
|
||||||
/* Destroy resources. */
|
/* Destroy resources. */
|
||||||
event_destroy(&wp->sleep_event);
|
mthread_event_destroy(&wp->sleep_event);
|
||||||
event_destroy(&wp->queue_event);
|
|
||||||
|
|
||||||
wp->state = STATE_DEAD;
|
wp->state = STATE_DEAD;
|
||||||
}
|
}
|
||||||
|
@ -209,13 +268,14 @@ PRIVATE void master_handle_exits(void)
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE void master_handle_request(message *m_ptr, int ipc_status)
|
PRIVATE void master_handle_request(message *m_ptr, int ipc_status)
|
||||||
{
|
{
|
||||||
/* For real request messages, query the thread ID, start a thread if one with
|
/* For real request messages, query the device ID, start a thread if none is
|
||||||
* that ID is not already running, and enqueue the message in the thread's
|
* free and the maximum number of threads for that device has not yet been
|
||||||
* message queue.
|
* reached, and enqueue the message in the devices's message queue.
|
||||||
*/
|
*/
|
||||||
thread_id_t thread_id;
|
device_id_t id;
|
||||||
worker_t *wp;
|
worker_t *wp;
|
||||||
int r;
|
device_t *dp;
|
||||||
|
int r, wid;
|
||||||
|
|
||||||
/* If this is not a block driver request, we cannot get the minor device
|
/* If this is not a block driver request, we cannot get the minor device
|
||||||
* associated with it, and thus we can not tell which thread should process
|
* associated with it, and thus we can not tell which thread should process
|
||||||
|
@ -230,27 +290,38 @@ PRIVATE void master_handle_request(message *m_ptr, int ipc_status)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Query the thread ID. Upon failure, send the error code to the caller. */
|
/* Query the device ID. Upon failure, send the error code to the caller. */
|
||||||
r = (*bdtab->bdr_thread)(m_ptr->DEVICE, &thread_id);
|
r = (*bdtab->bdr_device)(m_ptr->BDEV_MINOR, &id);
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
blockdriver_reply(m_ptr, ipc_status, r);
|
blockdriver_reply(m_ptr, ipc_status, r);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start the thread if it is not already running. */
|
/* Look up the device control block. */
|
||||||
assert(thread_id >= 0 && thread_id < BLOCKDRIVER_MT_MAX_WORKERS);
|
assert(id >= 0 && id < MAX_DEVICES);
|
||||||
|
dp = &device[id];
|
||||||
|
|
||||||
wp = &worker[thread_id];
|
/* Find the first non-busy worker thread. */
|
||||||
|
for (wid = 0; wid < dp->workers; wid++)
|
||||||
|
if (dp->worker[wid].state != STATE_BUSY)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If the worker thread is dead, start a thread now, unless we have already
|
||||||
|
* reached the maximum number of threads.
|
||||||
|
*/
|
||||||
|
if (wid < dp->workers) {
|
||||||
|
wp = &dp->worker[wid];
|
||||||
|
|
||||||
assert(wp->state != STATE_EXITED);
|
assert(wp->state != STATE_EXITED);
|
||||||
|
|
||||||
|
/* If the non-busy thread has not yet been created, create one now. */
|
||||||
if (wp->state == STATE_DEAD)
|
if (wp->state == STATE_DEAD)
|
||||||
master_create_worker(wp, thread_id);
|
master_create_worker(wp, wid, dp->id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Enqueue the message for the thread, and possibly wake it up. */
|
/* Enqueue the message at the device queue. */
|
||||||
enqueue(wp, m_ptr, ipc_status);
|
enqueue(dp, m_ptr, ipc_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -260,17 +331,25 @@ PRIVATE void master_init(struct blockdriver *bdp)
|
||||||
{
|
{
|
||||||
/* Initialize the state of the master thread.
|
/* Initialize the state of the master thread.
|
||||||
*/
|
*/
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
assert(bdp != NULL);
|
assert(bdp != NULL);
|
||||||
assert(bdp->bdr_thread != NULL);
|
assert(bdp->bdr_device != NULL);
|
||||||
|
|
||||||
mthread_init();
|
mthread_init();
|
||||||
|
|
||||||
bdtab = bdp;
|
bdtab = bdp;
|
||||||
|
|
||||||
for (i = 0; i < BLOCKDRIVER_MT_MAX_WORKERS; i++)
|
/* Initialize device-specific data structures. */
|
||||||
worker[i].state = STATE_DEAD;
|
for (i = 0; i < MAX_DEVICES; i++) {
|
||||||
|
device[i].id = i;
|
||||||
|
device[i].workers = 1;
|
||||||
|
mthread_event_init(&device[i].queue_event);
|
||||||
|
mthread_rwlock_init(&device[i].barrier);
|
||||||
|
|
||||||
|
for (j = 0; j < MAX_WORKERS; j++)
|
||||||
|
device[i].worker[j].state = STATE_DEAD;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize a per-thread key, where each worker thread stores its own
|
/* Initialize a per-thread key, where each worker thread stores its own
|
||||||
* reference to the worker structure.
|
* reference to the worker structure.
|
||||||
|
@ -279,6 +358,23 @@ PRIVATE void master_init(struct blockdriver *bdp)
|
||||||
panic("blockdriver_mt: error initializing worker key");
|
panic("blockdriver_mt: error initializing worker key");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* blockdriver_mt_get_tid *
|
||||||
|
*===========================================================================*/
|
||||||
|
PUBLIC thread_id_t blockdriver_mt_get_tid(void)
|
||||||
|
{
|
||||||
|
/* Return back the ID of this thread.
|
||||||
|
*/
|
||||||
|
worker_t *wp;
|
||||||
|
|
||||||
|
wp = (worker_t *) mthread_getspecific(worker_key);
|
||||||
|
|
||||||
|
if (wp == NULL)
|
||||||
|
panic("blockdriver_mt: master thread cannot query thread ID\n");
|
||||||
|
|
||||||
|
return MAKE_TID(wp->device_id, wp->worker_id);
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* blockdriver_mt_receive *
|
* blockdriver_mt_receive *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -301,7 +397,7 @@ PUBLIC void blockdriver_mt_task(struct blockdriver *driver_tab)
|
||||||
{
|
{
|
||||||
/* The multithreaded driver task.
|
/* The multithreaded driver task.
|
||||||
*/
|
*/
|
||||||
int ipc_status;
|
int ipc_status, i;
|
||||||
message mess;
|
message mess;
|
||||||
|
|
||||||
/* Initialize first if necessary. */
|
/* Initialize first if necessary. */
|
||||||
|
@ -329,6 +425,10 @@ PUBLIC void blockdriver_mt_task(struct blockdriver *driver_tab)
|
||||||
if (num_exited > 0)
|
if (num_exited > 0)
|
||||||
master_handle_exits();
|
master_handle_exits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free up resources. */
|
||||||
|
for (i = 0; i < MAX_DEVICES; i++)
|
||||||
|
mthread_event_destroy(&device[i].queue_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -356,7 +456,7 @@ PUBLIC void blockdriver_mt_sleep(void)
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
panic("blockdriver_mt: master thread cannot sleep");
|
panic("blockdriver_mt: master thread cannot sleep");
|
||||||
|
|
||||||
event_wait(&wp->sleep_event);
|
mthread_event_wait(&wp->sleep_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -367,32 +467,41 @@ PUBLIC void blockdriver_mt_wakeup(thread_id_t id)
|
||||||
/* Wake up a sleeping worker thread from the master thread.
|
/* Wake up a sleeping worker thread from the master thread.
|
||||||
*/
|
*/
|
||||||
worker_t *wp;
|
worker_t *wp;
|
||||||
|
device_id_t device_id;
|
||||||
|
worker_id_t worker_id;
|
||||||
|
|
||||||
assert(id >= 0 && id < BLOCKDRIVER_MT_MAX_WORKERS);
|
device_id = TID_DEVICE(id);
|
||||||
|
worker_id = TID_WORKER(id);
|
||||||
|
|
||||||
wp = &worker[id];
|
assert(device_id >= 0 && device_id < MAX_DEVICES);
|
||||||
|
assert(worker_id >= 0 && worker_id < MAX_WORKERS);
|
||||||
|
|
||||||
assert(wp->state == STATE_RUNNING || wp->state == STATE_STOPPING);
|
wp = &device[device_id].worker[worker_id];
|
||||||
|
|
||||||
event_fire(&wp->sleep_event);
|
assert(wp->state == STATE_RUNNING || wp->state == STATE_BUSY);
|
||||||
|
|
||||||
|
mthread_event_fire(&wp->sleep_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* blockdriver_mt_stop *
|
* blockdriver_mt_set_workers *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC void blockdriver_mt_stop(void)
|
PUBLIC void blockdriver_mt_set_workers(device_id_t id, int workers)
|
||||||
{
|
{
|
||||||
/* Put up the current worker thread for termination. Once the current dispatch
|
/* Set the number of worker threads for the given device.
|
||||||
* call has finished, and there are no more messages in the thread's message
|
|
||||||
* queue, the thread will be terminated. Any messages in the queue will undo
|
|
||||||
* the effect of this call.
|
|
||||||
*/
|
*/
|
||||||
worker_t *wp;
|
device_t *dp;
|
||||||
|
|
||||||
wp = (worker_t *) mthread_getspecific(worker_key);
|
assert(id >= 0 && id < MAX_DEVICES);
|
||||||
|
|
||||||
assert(wp != NULL);
|
if (workers > MAX_WORKERS)
|
||||||
assert(wp->state == STATE_RUNNING || wp->state == STATE_STOPPING);
|
workers = MAX_WORKERS;
|
||||||
|
|
||||||
wp->state = STATE_STOPPING;
|
dp = &device[id];
|
||||||
|
|
||||||
|
/* If we are cleaning up, wake up all threads waiting on a queue event. */
|
||||||
|
if (workers == 1 && dp->workers > workers)
|
||||||
|
mthread_event_fire_all(&dp->queue_event);
|
||||||
|
|
||||||
|
dp->workers = workers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <minix/drivers.h>
|
#include <minix/drivers.h>
|
||||||
#include <minix/blockdriver.h>
|
#include <minix/blockdriver.h>
|
||||||
|
|
||||||
|
#include "const.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include "mq.h"
|
#include "mq.h"
|
||||||
|
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
/* This file contains a simple thread event implementation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <minix/mthread.h>
|
|
||||||
#include <minix/sysutil.h>
|
|
||||||
|
|
||||||
#include "event.h"
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* event_init *
|
|
||||||
*===========================================================================*/
|
|
||||||
PUBLIC void event_init(event_t *event)
|
|
||||||
{
|
|
||||||
/* Initialize an event object.
|
|
||||||
*/
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((r = mthread_mutex_init(&event->mutex, NULL)) != 0)
|
|
||||||
panic("libblockdriver: error initializing mutex (%d)", r);
|
|
||||||
if ((r = mthread_cond_init(&event->cond, NULL)) != 0)
|
|
||||||
panic("libblockdriver: error initializing condvar (%d)", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* event_destroy *
|
|
||||||
*===========================================================================*/
|
|
||||||
PUBLIC void event_destroy(event_t *event)
|
|
||||||
{
|
|
||||||
/* Destroy an event object.
|
|
||||||
*/
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((r = mthread_cond_destroy(&event->cond)) != 0)
|
|
||||||
panic("libblockdriver: error destroying condvar (%d)", r);
|
|
||||||
if ((r = mthread_mutex_destroy(&event->mutex)) != 0)
|
|
||||||
panic("libblockdriver: error destroying mutex (%d)", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* event_wait *
|
|
||||||
*===========================================================================*/
|
|
||||||
PUBLIC void event_wait(event_t *event)
|
|
||||||
{
|
|
||||||
/* Wait for an event, blocking the current thread in the process.
|
|
||||||
*/
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((r = mthread_mutex_lock(&event->mutex)) != 0)
|
|
||||||
panic("libblockdriver: error locking mutex (%d)", r);
|
|
||||||
if ((r = mthread_cond_wait(&event->cond, &event->mutex)) != 0)
|
|
||||||
panic("libblockdriver: error waiting for condvar (%d)", r);
|
|
||||||
if ((r = mthread_mutex_unlock(&event->mutex)) != 0)
|
|
||||||
panic("libblockdriver: error unlocking mutex (%d)", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* event_fire *
|
|
||||||
*===========================================================================*/
|
|
||||||
PUBLIC void event_fire(event_t *event)
|
|
||||||
{
|
|
||||||
/* Fire an event, waking up any thread blocked on it without scheduling it.
|
|
||||||
*/
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((r = mthread_mutex_lock(&event->mutex)) != 0)
|
|
||||||
panic("libblockdriver: error locking mutex (%d)", r);
|
|
||||||
if ((r = mthread_cond_signal(&event->cond)) != 0)
|
|
||||||
panic("libblockdriver: error signaling condvar (%d)", r);
|
|
||||||
if ((r = mthread_mutex_unlock(&event->mutex)) != 0)
|
|
||||||
panic("libblockdriver: error unlocking mutex (%d)", r);
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifndef _BLOCKDRIVER_EVENT_H
|
|
||||||
#define _BLOCKDRIVER_EVENT_H
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
mthread_mutex_t mutex;
|
|
||||||
mthread_cond_t cond;
|
|
||||||
} event_t;
|
|
||||||
|
|
||||||
_PROTOTYPE( void event_init, (event_t *event) );
|
|
||||||
_PROTOTYPE( void event_destroy, (event_t *event) );
|
|
||||||
_PROTOTYPE( void event_wait, (event_t *event) );
|
|
||||||
_PROTOTYPE( void event_fire, (event_t *event) );
|
|
||||||
|
|
||||||
#endif /* _BLOCKDRIVER_EVENT_H */
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "const.h"
|
||||||
#include "mq.h"
|
#include "mq.h"
|
||||||
|
|
||||||
#define MQ_SIZE 128
|
#define MQ_SIZE 128
|
||||||
|
@ -21,8 +22,7 @@ struct mq_cell {
|
||||||
};
|
};
|
||||||
|
|
||||||
PRIVATE struct mq_cell pool[MQ_SIZE];
|
PRIVATE struct mq_cell pool[MQ_SIZE];
|
||||||
|
PRIVATE STAILQ_HEAD(queue, mq_cell) queue[MAX_DEVICES];
|
||||||
PRIVATE STAILQ_HEAD(queue, mq_cell) queue[BLOCKDRIVER_MT_MAX_WORKERS];
|
|
||||||
PRIVATE STAILQ_HEAD(free_list, mq_cell) free_list;
|
PRIVATE STAILQ_HEAD(free_list, mq_cell) free_list;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -36,7 +36,7 @@ PUBLIC void mq_init(void)
|
||||||
|
|
||||||
STAILQ_INIT(&free_list);
|
STAILQ_INIT(&free_list);
|
||||||
|
|
||||||
for (i = 0; i < BLOCKDRIVER_MT_MAX_WORKERS; i++)
|
for (i = 0; i < MAX_DEVICES; i++)
|
||||||
STAILQ_INIT(&queue[i]);
|
STAILQ_INIT(&queue[i]);
|
||||||
|
|
||||||
for (i = 0; i < MQ_SIZE; i++)
|
for (i = 0; i < MQ_SIZE; i++)
|
||||||
|
@ -46,15 +46,15 @@ PUBLIC void mq_init(void)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* mq_enqueue *
|
* mq_enqueue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC int mq_enqueue(thread_id_t thread_id, const message *mess,
|
PUBLIC int mq_enqueue(device_id_t device_id, const message *mess,
|
||||||
int ipc_status)
|
int ipc_status)
|
||||||
{
|
{
|
||||||
/* Add a message, including its IPC status, to the message queue of a thread.
|
/* Add a message, including its IPC status, to the message queue of a device.
|
||||||
* Return TRUE iff the message was added successfully.
|
* Return TRUE iff the message was added successfully.
|
||||||
*/
|
*/
|
||||||
struct mq_cell *cell;
|
struct mq_cell *cell;
|
||||||
|
|
||||||
assert(thread_id >= 0 && thread_id < BLOCKDRIVER_MT_MAX_WORKERS);
|
assert(device_id >= 0 && device_id < MAX_DEVICES);
|
||||||
|
|
||||||
if (STAILQ_EMPTY(&free_list))
|
if (STAILQ_EMPTY(&free_list))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -65,7 +65,7 @@ PUBLIC int mq_enqueue(thread_id_t thread_id, const message *mess,
|
||||||
cell->mess = *mess;
|
cell->mess = *mess;
|
||||||
cell->ipc_status = ipc_status;
|
cell->ipc_status = ipc_status;
|
||||||
|
|
||||||
STAILQ_INSERT_TAIL(&queue[thread_id], cell, next);
|
STAILQ_INSERT_TAIL(&queue[device_id], cell, next);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -73,20 +73,20 @@ PUBLIC int mq_enqueue(thread_id_t thread_id, const message *mess,
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* mq_dequeue *
|
* mq_dequeue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC int mq_dequeue(thread_id_t thread_id, message *mess, int *ipc_status)
|
PUBLIC 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
|
/* Return and remove a message, including its IPC status, from the message
|
||||||
* queue of a thread. Return TRUE iff a message was available.
|
* queue of a thread. Return TRUE iff a message was available.
|
||||||
*/
|
*/
|
||||||
struct mq_cell *cell;
|
struct mq_cell *cell;
|
||||||
|
|
||||||
assert(thread_id >= 0 && thread_id < BLOCKDRIVER_MT_MAX_WORKERS);
|
assert(device_id >= 0 && device_id < MAX_DEVICES);
|
||||||
|
|
||||||
if (STAILQ_EMPTY(&queue[thread_id]))
|
if (STAILQ_EMPTY(&queue[device_id]))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
cell = STAILQ_FIRST(&queue[thread_id]);
|
cell = STAILQ_FIRST(&queue[device_id]);
|
||||||
STAILQ_REMOVE_HEAD(&queue[thread_id], next);
|
STAILQ_REMOVE_HEAD(&queue[device_id], next);
|
||||||
|
|
||||||
*mess = cell->mess;
|
*mess = cell->mess;
|
||||||
*ipc_status = cell->ipc_status;
|
*ipc_status = cell->ipc_status;
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
#define _BLOCKDRIVER_MQ_H
|
#define _BLOCKDRIVER_MQ_H
|
||||||
|
|
||||||
_PROTOTYPE( void mq_init, (void) );
|
_PROTOTYPE( void mq_init, (void) );
|
||||||
_PROTOTYPE( int mq_enqueue, (thread_id_t thread_id, const message *mess,
|
_PROTOTYPE( int mq_enqueue, (device_id_t device_id, const message *mess,
|
||||||
int ipc_status) );
|
int ipc_status) );
|
||||||
_PROTOTYPE( int mq_dequeue, (thread_id_t thread_id, message *mess,
|
_PROTOTYPE( int mq_dequeue, (device_id_t device_id, message *mess,
|
||||||
int *ipc_status) );
|
int *ipc_status) );
|
||||||
|
|
||||||
#endif /* _BLOCKDRIVER_MQ_H */
|
#endif /* _BLOCKDRIVER_MQ_H */
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <minix/minlib.h>
|
#include <minix/minlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "const.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
#define NO_TRACEDEV ((dev_t) -1)
|
#define NO_TRACEDEV ((dev_t) -1)
|
||||||
|
@ -24,7 +25,7 @@ PRIVATE u64_t trace_tsc;
|
||||||
* plus one for the main thread). Each pointer is set to NULL whenever no
|
* plus one for the main thread). Each pointer is set to NULL whenever no
|
||||||
* operation is currently being traced for that thread, for whatever reason.
|
* operation is currently being traced for that thread, for whatever reason.
|
||||||
*/
|
*/
|
||||||
PRIVATE btrace_entry *trace_ptr[BLOCKDRIVER_MT_MAX_WORKERS + 1] = { NULL };
|
PRIVATE btrace_entry *trace_ptr[MAX_THREADS + 1] = { NULL };
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* trace_gettime *
|
* trace_gettime *
|
||||||
|
@ -175,7 +176,7 @@ PUBLIC void trace_start(thread_id_t id, message *m_ptr)
|
||||||
|
|
||||||
if (!trace_enabled || trace_dev != m_ptr->BDEV_MINOR) return;
|
if (!trace_enabled || trace_dev != m_ptr->BDEV_MINOR) return;
|
||||||
|
|
||||||
assert(id >= 0 && id < BLOCKDRIVER_MT_MAX_WORKERS + 1);
|
assert(id >= 0 && id < MAX_THREADS + 1);
|
||||||
|
|
||||||
if (trace_pos == trace_size)
|
if (trace_pos == trace_size)
|
||||||
return;
|
return;
|
||||||
|
@ -254,7 +255,7 @@ PUBLIC void trace_setsize(thread_id_t id, size_t size)
|
||||||
|
|
||||||
if (!trace_enabled) return;
|
if (!trace_enabled) return;
|
||||||
|
|
||||||
assert(id >= 0 && id < BLOCKDRIVER_MT_MAX_WORKERS + 1);
|
assert(id >= 0 && id < MAX_THREADS + 1);
|
||||||
|
|
||||||
if ((entry = trace_ptr[id]) == NULL) return;
|
if ((entry = trace_ptr[id]) == NULL) return;
|
||||||
|
|
||||||
|
@ -272,7 +273,7 @@ PUBLIC void trace_finish(thread_id_t id, int result)
|
||||||
|
|
||||||
if (!trace_enabled) return;
|
if (!trace_enabled) return;
|
||||||
|
|
||||||
assert(id >= 0 && id < BLOCKDRIVER_MT_MAX_WORKERS + 1);
|
assert(id >= 0 && id < MAX_THREADS + 1);
|
||||||
|
|
||||||
if ((entry = trace_ptr[id]) == NULL) return;
|
if ((entry = trace_ptr[id]) == NULL) return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue