stream: support async operation using watcher
This commit is contained in:
@@ -38,6 +38,28 @@ struct private_stream_t {
|
|||||||
* FILE* for convenience functions, or NULL
|
* FILE* for convenience functions, or NULL
|
||||||
*/
|
*/
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback if data is ready to read
|
||||||
|
*/
|
||||||
|
stream_cb_t read_cb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for read-ready callback
|
||||||
|
*/
|
||||||
|
void *read_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback if write is non-blocking
|
||||||
|
*/
|
||||||
|
stream_cb_t write_cb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for write-ready callback
|
||||||
|
*/
|
||||||
|
void *write_data;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(stream_t, read_, ssize_t,
|
METHOD(stream_t, read_, ssize_t,
|
||||||
@@ -96,6 +118,90 @@ METHOD(stream_t, write_, ssize_t,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a registered watcher
|
||||||
|
*/
|
||||||
|
static void remove_watcher(private_stream_t *this)
|
||||||
|
{
|
||||||
|
if (this->read_cb || this->write_cb)
|
||||||
|
{
|
||||||
|
lib->watcher->remove(lib->watcher, this->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watcher callback
|
||||||
|
*/
|
||||||
|
static bool watch(private_stream_t *this, int fd, watcher_event_t event)
|
||||||
|
{
|
||||||
|
bool keep = FALSE;
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case WATCHER_READ:
|
||||||
|
keep = this->read_cb(this->read_data, &this->public);
|
||||||
|
if (!keep)
|
||||||
|
{
|
||||||
|
this->read_cb = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WATCHER_WRITE:
|
||||||
|
keep = this->write_cb(this->write_data, &this->public);
|
||||||
|
if (!keep)
|
||||||
|
{
|
||||||
|
this->write_cb = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WATCHER_EXCEPT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return keep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register watcher for stream callbacks
|
||||||
|
*/
|
||||||
|
static void add_watcher(private_stream_t *this)
|
||||||
|
{
|
||||||
|
watcher_event_t events = 0;
|
||||||
|
|
||||||
|
if (this->read_cb)
|
||||||
|
{
|
||||||
|
events |= WATCHER_READ;
|
||||||
|
}
|
||||||
|
if (this->write_cb)
|
||||||
|
{
|
||||||
|
events |= WATCHER_WRITE;
|
||||||
|
}
|
||||||
|
if (events)
|
||||||
|
{
|
||||||
|
lib->watcher->add(lib->watcher, this->fd, events,
|
||||||
|
(watcher_cb_t)watch, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(stream_t, on_read, void,
|
||||||
|
private_stream_t *this, stream_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
remove_watcher(this);
|
||||||
|
|
||||||
|
this->read_cb = cb;
|
||||||
|
this->read_data = data;
|
||||||
|
|
||||||
|
add_watcher(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(stream_t, on_write, void,
|
||||||
|
private_stream_t *this, stream_cb_t cb, void *data)
|
||||||
|
{
|
||||||
|
remove_watcher(this);
|
||||||
|
|
||||||
|
this->write_cb = cb;
|
||||||
|
this->write_data = data;
|
||||||
|
|
||||||
|
add_watcher(this);
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(stream_t, vprint, int,
|
METHOD(stream_t, vprint, int,
|
||||||
private_stream_t *this, char *format, va_list ap)
|
private_stream_t *this, char *format, va_list ap)
|
||||||
{
|
{
|
||||||
@@ -126,6 +232,7 @@ METHOD(stream_t, print, int,
|
|||||||
METHOD(stream_t, destroy, void,
|
METHOD(stream_t, destroy, void,
|
||||||
private_stream_t *this)
|
private_stream_t *this)
|
||||||
{
|
{
|
||||||
|
remove_watcher(this);
|
||||||
if (this->file)
|
if (this->file)
|
||||||
{
|
{
|
||||||
fclose(this->file);
|
fclose(this->file);
|
||||||
@@ -147,7 +254,9 @@ stream_t *stream_create_from_fd(int fd)
|
|||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
.read = _read_,
|
.read = _read_,
|
||||||
|
.on_read = _on_read,
|
||||||
.write = _write_,
|
.write = _write_,
|
||||||
|
.on_write = _on_write,
|
||||||
.print = _print,
|
.print = _print,
|
||||||
.vprint = _vprint,
|
.vprint = _vprint,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
|
|||||||
@@ -33,6 +33,23 @@ typedef struct stream_t stream_t;
|
|||||||
*/
|
*/
|
||||||
typedef stream_t*(*stream_constructor_t)(char *uri);
|
typedef stream_t*(*stream_constructor_t)(char *uri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function prototype, called when stream is ready.
|
||||||
|
*
|
||||||
|
* It is not allowed to destroy the stream during the callback, this would
|
||||||
|
* deadlock. Instead, return FALSE to destroy the stream. It is not allowed
|
||||||
|
* to call on_read()/on_write() during this callback.
|
||||||
|
*
|
||||||
|
* As select() may return even if a read()/write() would actually block, it is
|
||||||
|
* recommended to use the non-blocking calls and handle return values
|
||||||
|
* appropriately.
|
||||||
|
*
|
||||||
|
* @param data data passed during callback registration
|
||||||
|
* @param stream associated stream
|
||||||
|
* @return FALSE to destroy the stream
|
||||||
|
*/
|
||||||
|
typedef bool (*stream_cb_t)(void *data, stream_t *stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstraction of a Berkley socket using stream semantics.
|
* Abstraction of a Berkley socket using stream semantics.
|
||||||
*/
|
*/
|
||||||
@@ -51,6 +68,14 @@ struct stream_t {
|
|||||||
*/
|
*/
|
||||||
ssize_t (*read)(stream_t *this, void *buf, size_t len, bool block);
|
ssize_t (*read)(stream_t *this, void *buf, size_t len, bool block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback to invoke when stream has data to read.
|
||||||
|
*
|
||||||
|
* @param cb callback function, NULL to unregister
|
||||||
|
* @param data data to pass to callback
|
||||||
|
*/
|
||||||
|
void (*on_read)(stream_t *this, stream_cb_t cb, void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data to the stream.
|
* Write data to the stream.
|
||||||
*
|
*
|
||||||
@@ -64,6 +89,14 @@ struct stream_t {
|
|||||||
*/
|
*/
|
||||||
ssize_t (*write)(stream_t *this, void *buf, size_t len, bool block);
|
ssize_t (*write)(stream_t *this, void *buf, size_t len, bool block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback to invoke when a write would not block.
|
||||||
|
*
|
||||||
|
* @param cb callback function, NULL to unregister
|
||||||
|
* @param data data to pass to callback
|
||||||
|
*/
|
||||||
|
void (*on_write)(stream_t *this, stream_cb_t cb, void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* printf() convenience function for this stream.
|
* printf() convenience function for this stream.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user