186 lines
7.0 KiB
C
186 lines
7.0 KiB
C
#ifndef RING_H
|
|
#define RING_H
|
|
|
|
#ident "$Header: /proj/irix6.5.7m/isms/eoe/cmd/xfs/dump/common/RCS/ring.h,v 1.1 1995/06/21 22:47:25 cbullis Exp $"
|
|
|
|
/* ring - readahead/writeahead abstraction
|
|
*
|
|
* the ring is conceptually an ordered set of messages circulating between the
|
|
* client thread and the I/O slave thread. a message can be in one of four
|
|
* places: on the ready queue, held by the client, on the active queue, or held
|
|
* by the slave. The client and slave can each hold at most one message at a
|
|
* time. all others must be on one of the two queues. the messages must
|
|
* circulate in that order: ready, client, active, slave, ready, ...
|
|
* initially all messages are on the ready queue, with status set to
|
|
* INIT. The client uses ring_get to remove a message from the ready queue.
|
|
* the client can then use the message to read or write. to read, the client
|
|
* sets the op field to READ, and places the message on the active queue. the
|
|
* slave will remove messages from the active queue, invoke the client-supplied
|
|
* read function with the message's buffer, record the read function's return
|
|
* value in the message, set the message status to OK (read function returned 0)
|
|
* or ERROR (read returned non-zero), and place the message on the ready queue.
|
|
* the client will see the message after removing all messages ahead of it on
|
|
* the ready queue. to write, the client follows almost the same procedure,
|
|
* except the client fills the buffer and sets the op to WRITE prior to placing
|
|
* the message on the active queue.
|
|
*
|
|
* if the client-supplied read or write function returns an error, the slave
|
|
* will set the message status to ERROR. the slave will pass all subsequent
|
|
* messages appearing on the active queue directly to the ready queue with
|
|
* no I/O done and the message status set to IGNORE. the slave will remain
|
|
* in this state until a reset is performed (see below).
|
|
*
|
|
* The client may at anytime place a NOP msg on the ring. the slave does
|
|
* nothing with this mmessage other than to place it back on the ready queue
|
|
* with NOPACK status. This is useful for inhibiting read-ahead.
|
|
*
|
|
* To flush the ring, the client must repetatively place TRACE messages on the
|
|
* active queue until it sees an IGNORE msg on the ready queue. the slave will
|
|
* simply transfer TRACErs from active to ready with no other action taken
|
|
* (other than to set the message status to IGNORE).
|
|
*
|
|
* the client may at any time reset the ring. the reset will return to the
|
|
* client when the current I/O being executed by the slave completes, and
|
|
* all messages have been wiped clean and placed on the ready queue with
|
|
* status set to INIT. the ring_reset function accomplishes this internally by
|
|
* placing a RESET message on the active QUEUE, and continuing to remove
|
|
* messages from the ready queue (without placing them on the active queue)
|
|
* until the RESET message is seen the slave responds to a reset message by
|
|
* setting the status to RESETACK, queueing the message on the ready queue, and
|
|
* waiting for a message from the active queue. ring_reset will then re-
|
|
* initialize the ring and return. note that the client may be holding one
|
|
* message at the time the reset is called. if so, it must pass a pointer to
|
|
* that message into the reset call. otherwise it must pass in NULL.
|
|
*
|
|
* the ring_destroy function may be invoked to shut down the ring and kill the
|
|
* slave thread. it simply places a DIE message on the active queue, and waits
|
|
* for a DIEACK response. it then de-allocates all semaphores memory allocated
|
|
* by ring_create.
|
|
*
|
|
* the message structure includes a 64 bit field for the convenience
|
|
* of the client. it is not perturbed during any ring operations.
|
|
*
|
|
* the ring maintains four performance metering values: the number of times
|
|
* the slave and client attempted to get a message, and the number of times
|
|
* those attempts resulting in blocking.
|
|
*/
|
|
|
|
|
|
/* ring_msg - structure of messages managed by ring
|
|
*/
|
|
enum ring_op { RING_OP_NONE,
|
|
RING_OP_READ,
|
|
RING_OP_WRITE,
|
|
RING_OP_NOP,
|
|
RING_OP_TRACE,
|
|
RING_OP_RESET,
|
|
RING_OP_DIE };
|
|
|
|
typedef enum ring_op ring_op_t;
|
|
|
|
enum ring_stat { RING_STAT_INIT,
|
|
RING_STAT_OK,
|
|
RING_STAT_ERROR,
|
|
RING_STAT_NOPACK,
|
|
RING_STAT_IGNORE,
|
|
RING_STAT_RESETACK,
|
|
RING_STAT_DIEACK };
|
|
|
|
typedef enum ring_stat ring_stat_t;
|
|
|
|
enum ring_loc { RING_LOC_READY,
|
|
RING_LOC_ACTIVE,
|
|
RING_LOC_CLIENT,
|
|
RING_LOC_SLAVE };
|
|
|
|
typedef enum ring_loc ring_loc_t;
|
|
|
|
struct ring_msg {
|
|
ring_op_t rm_op;
|
|
ring_stat_t rm_stat;
|
|
intgen_t rm_rval;
|
|
off64_t rm_user;
|
|
char *rm_bufp;
|
|
/* ALL BELOW PRIVATE!!! */
|
|
size_t rm_mix;
|
|
ring_loc_t rm_loc;
|
|
};
|
|
|
|
typedef struct ring_msg ring_msg_t;
|
|
|
|
|
|
/* ring - instantiation of a ring
|
|
*/
|
|
struct ring {
|
|
off64_t r_client_msgcnt;
|
|
off64_t r_slave_msgcnt;
|
|
off64_t r_client_blkcnt;
|
|
off64_t r_slave_blkcnt;
|
|
time_t r_first_io_time;
|
|
off64_t r_all_io_cnt;
|
|
/* ALL BELOW PRIVATE!!! */
|
|
pid_t r_slavepid;
|
|
size_t r_len;
|
|
ring_msg_t *r_msgp;
|
|
size_t r_ready_in_ix;
|
|
size_t r_ready_out_ix;
|
|
qsemh_t r_ready_qsemh;
|
|
size_t r_active_in_ix;
|
|
size_t r_active_out_ix;
|
|
qsemh_t r_active_qsemh;
|
|
size_t r_client_cnt;
|
|
size_t r_slave_cnt;
|
|
int ( *r_readfunc )( void *contextp, char *bufp );
|
|
int ( *r_writefunc )( void *contextp, char *bufp );
|
|
void *r_clientctxp;
|
|
};
|
|
|
|
typedef struct ring ring_t;
|
|
|
|
|
|
/* ring_create - creates a ring. parameters supply the length of the ring,
|
|
* the read/write buffer size, a function for creating a thread, a function
|
|
* for reading, a function for writing, and a pointer to client context for the
|
|
* read and write functions. returns a pointer to a ring if successful, a NULL
|
|
* pointer if not. the read and write functions should return 0 on success,
|
|
* or an error code on failure which will be recorded in the rm_rval field
|
|
* of the message invoking the failed operation. if null pointer returned,
|
|
* the location pointed to by rvalp will contain one of the following:
|
|
* ENOMEM - could not allocate some portion of the ring memory;
|
|
* E2BIG - insufficient physical memory available for pinning;
|
|
* EPERM - exceeds allowed amount of pinned down memory.
|
|
*/
|
|
extern ring_t *ring_create( size_t ringlen,
|
|
size_t bufsz,
|
|
bool_t pinpr,
|
|
void ( * threadfunc )( void *clientctxp,
|
|
void ( * entryp )( void *ringctxp ),
|
|
void *ringctxp ),
|
|
int ( * readfunc )( void *clientctxp, char *bufp ),
|
|
int ( * writefunc )( void *clientctxp, char *bufp ),
|
|
void *clientctxp,
|
|
intgen_t *rvalp );
|
|
|
|
|
|
/* ring_get - get a message off the ready queue
|
|
*/
|
|
extern ring_msg_t *ring_get( ring_t *ringp );
|
|
|
|
|
|
/* ring_put - put a message on the active queue
|
|
*/
|
|
extern void ring_put( ring_t *ringp, ring_msg_t *msgp );
|
|
|
|
|
|
/* ring_reset - re-initialize the ring, after the current I/O completes.
|
|
* msgp must be NULL if the client is not currently holding a ring message.
|
|
* otherwise it must point to that message.
|
|
*/
|
|
extern void ring_reset( ring_t *ringp, ring_msg_t *msgp );
|
|
|
|
/* ring_destroy - de-allocates ring
|
|
*/
|
|
extern void ring_destroy( ring_t *ringp );
|
|
|
|
#endif /* RING_H */
|