#ifndef UCORE_WQUEUE_H_ #define UCORE_WQUEUE_H_ #include "mbuf.h" #include "iomux.h" enum UC_WQ_RESULT { /** INdicates the MBuf was fully processed and can be freed*/ UC_WQ_DONE = 1, /** Indicates the MBuf was not fully processed, and will not be freed */ UC_WQ_PARTIAL = 0, /** Indicats an error and further processing of the wqueue should not be done*/ UC_WQ_ABORT = -1 }; /** * Callback that will be called when data can be written to the fd. * The return value from this function must be strictly followed. * Write events on an fd will be processed before read events. * * For one write event, the callback is called for all mbufs in the queue, * as long as UC_WQ_DONE is returned. * * If UC_WQ_PARTIAL is returned, queue processing is stopped, but any read * events will also be dispatched. * If UC_WQ_ABORT is done, no further processing is done, and the wqueue is not * acccessed any more, making it safe to destroy the wqueue before UC_WQ_ABORY is * returned. * * @param mux associated IOMux * @param the fd of the current wqueue * @return UC_WQ_DONE when the entire mbuf was written, and its memory can be released. * UC_WQ_PARTIAL when partial data was written, the mbuf is not released, * queue procesing is stopped, and the callback will be passed the same mbuf * on the next write event, you need to provide a mean to know where to * start processing the mbuf on the next event. * UC_WQ_ABORT when all processing, both write and read events should be aborted * for this event. * */ typedef enum UC_WQ_RESULT (*wqueue_write_cb)(struct IOMux *mux, struct IOMuxFD *fd, struct MBuf *mbuf); /** * Callback when read events are indicated. * The return value is currently unused. The wqueue is not accessed after * this callback returns, making it safe to destroy the wqueue before * the callback function returns. * * @param mux associated IOMux * @param the fd of the current wqueue */ typedef enum UC_WQ_RESULT (*wqueue_read_cb)(struct IOMux *mux, struct IOMuxFD *fd); /** Represents a queue of data to write. */ struct UCWQueue { struct IOMuxFD fd; struct TailQ queue; struct IOMux *mux; wqueue_read_cb read_cb; wqueue_write_cb write_cb; unsigned int queue_len; }; /** Initialize a wqueue. After this you need to * set the read_cb, write_cb. Set the fd.fd and fd.event * and register the fd with the same IOMux as the mux parameter. * Do not set the fd.callback. * * Note that on some IOMux'es the read_cb may be called as * a result of read events, even if you havn't enabled * MUX_EV_READ events. * * The wqueue manages a queue of MBufs, and will enable write events * on the IOMux * and call the write_cb when messages are enqueued. * * @param wqueue wqueue to initialize * @param mux the IOMux that you intend to register wqueue->fd on. */ void uc_wqueue_init(struct UCWQueue *wqueue, struct IOMux *mux); /** * Frees all the enqueued mbufs. * * @return code from iomux_update_events, when write events need * to be unregisrted on the IOMux */ int uc_wqueue_clear(struct UCWQueue *wqueue); /** * Enqueues an mbuf onto the wqueue. The wqueue will take ownership * of the mbuf, and will be responsible for releasing its memory, * mbuf->entry will be used by the wqueue. * * Write events will be enabled on the IOMux, and on write events * the write_cb is invoked for each message in the queue. * * @param wqueueu * @param mbuf mbuf to enqueue * @return code from iomux_update_events, when write events need * to be regisrted on the IOMux */ int uc_wqueue_enqueue(struct UCWQueue *wqueue, struct MBuf *mbuf); /** * Immediately write mbufs. * This invokes the wqueue write callback immediately, just as if an * write event from the IOMux had happened. * * As for a normal write event, the entire queue might not be * written, if the associated write callback detectes it cannot write * more data. * * @param wqueue * * return 0 if no error occured, -1 if the write callback returned * UC_WQ_ABORT */ int uc_wqueue_flush(struct UCWQueue *wqueue); #endif