connection: Factor out circular buffer functionality
This commit is contained in:
parent
4363d2aa4d
commit
d6f4da7927
219
connection.c
219
connection.c
@ -43,6 +43,8 @@ struct wl_buffer {
|
|||||||
int head, tail;
|
int head, tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MASK(i) ((i) & 4095)
|
||||||
|
|
||||||
struct wl_connection {
|
struct wl_connection {
|
||||||
struct wl_buffer in, out;
|
struct wl_buffer in, out;
|
||||||
int fd;
|
int fd;
|
||||||
@ -50,6 +52,86 @@ struct wl_connection {
|
|||||||
wl_connection_update_func_t update;
|
wl_connection_update_func_t update;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
|
||||||
|
{
|
||||||
|
int head, size;
|
||||||
|
|
||||||
|
head = MASK(b->head);
|
||||||
|
if (head + count <= sizeof b->data) {
|
||||||
|
memcpy(b->data + head, data, count);
|
||||||
|
} else {
|
||||||
|
size = sizeof b->data - head;
|
||||||
|
memcpy(b->data + head, data, size);
|
||||||
|
memcpy(b->data, (const char *) data + size, count - size);
|
||||||
|
}
|
||||||
|
|
||||||
|
b->head += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count)
|
||||||
|
{
|
||||||
|
int head, tail;
|
||||||
|
|
||||||
|
head = MASK(b->head);
|
||||||
|
tail = MASK(b->tail);
|
||||||
|
if (head < tail) {
|
||||||
|
iov[0].iov_base = b->data + head;
|
||||||
|
iov[0].iov_len = tail - head;
|
||||||
|
*count = 1;
|
||||||
|
} else if (tail == 0) {
|
||||||
|
iov[0].iov_base = b->data + head;
|
||||||
|
iov[0].iov_len = sizeof b->data - head;
|
||||||
|
*count = 1;
|
||||||
|
} else {
|
||||||
|
iov[0].iov_base = b->data + head;
|
||||||
|
iov[0].iov_len = sizeof b->data - head;
|
||||||
|
iov[1].iov_base = b->data;
|
||||||
|
iov[1].iov_len = tail;
|
||||||
|
*count = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count)
|
||||||
|
{
|
||||||
|
int head, tail;
|
||||||
|
|
||||||
|
head = MASK(b->head);
|
||||||
|
tail = MASK(b->tail);
|
||||||
|
if (tail < head) {
|
||||||
|
iov[0].iov_base = b->data + tail;
|
||||||
|
iov[0].iov_len = head - tail;
|
||||||
|
*count = 1;
|
||||||
|
} else if (head == 0) {
|
||||||
|
iov[0].iov_base = b->data + tail;
|
||||||
|
iov[0].iov_len = sizeof b->data - tail;
|
||||||
|
*count = 1;
|
||||||
|
} else {
|
||||||
|
iov[0].iov_base = b->data + tail;
|
||||||
|
iov[0].iov_len = sizeof b->data - tail;
|
||||||
|
iov[1].iov_base = b->data;
|
||||||
|
iov[1].iov_len = head;
|
||||||
|
*count = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wl_buffer_copy(struct wl_buffer *b, void *data, size_t count)
|
||||||
|
{
|
||||||
|
int tail, size;
|
||||||
|
|
||||||
|
tail = MASK(b->tail);
|
||||||
|
if (tail + count <= sizeof b->data) {
|
||||||
|
memcpy(data, b->data + tail, count);
|
||||||
|
} else {
|
||||||
|
size = sizeof b->data - tail;
|
||||||
|
memcpy(data, b->data + tail, size);
|
||||||
|
memcpy((char *) data + size, b->data, count - size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct wl_connection *
|
struct wl_connection *
|
||||||
wl_connection_create(int fd,
|
wl_connection_create(int fd,
|
||||||
wl_connection_update_func_t update,
|
wl_connection_update_func_t update,
|
||||||
@ -80,67 +162,35 @@ wl_connection_destroy(struct wl_connection *connection)
|
|||||||
void
|
void
|
||||||
wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
|
wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
|
||||||
{
|
{
|
||||||
struct wl_buffer *b;
|
wl_buffer_copy(&connection->in, data, size);
|
||||||
int tail, rest;
|
|
||||||
|
|
||||||
b = &connection->in;
|
|
||||||
tail = b->tail;
|
|
||||||
if (tail + size <= ARRAY_LENGTH(b->data)) {
|
|
||||||
memcpy(data, b->data + tail, size);
|
|
||||||
} else {
|
|
||||||
rest = ARRAY_LENGTH(b->data) - tail;
|
|
||||||
memcpy(data, b->data + tail, rest);
|
|
||||||
memcpy(data + rest, b->data, size - rest);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wl_connection_consume(struct wl_connection *connection, size_t size)
|
wl_connection_consume(struct wl_connection *connection, size_t size)
|
||||||
{
|
{
|
||||||
struct wl_buffer *b;
|
connection->in.tail += size;
|
||||||
int tail, rest;
|
|
||||||
|
|
||||||
b = &connection->in;
|
|
||||||
tail = b->tail;
|
|
||||||
if (tail + size <= ARRAY_LENGTH(b->data)) {
|
|
||||||
b->tail += size;
|
|
||||||
} else {
|
|
||||||
rest = ARRAY_LENGTH(b->data) - tail;
|
|
||||||
b->tail = size - rest;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wl_connection_data(struct wl_connection *connection, uint32_t mask)
|
int wl_connection_data(struct wl_connection *connection, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct wl_buffer *b;
|
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
int len, head, tail, count, size, available;
|
int len, count;
|
||||||
|
|
||||||
if (mask & WL_CONNECTION_READABLE) {
|
if (mask & WL_CONNECTION_READABLE) {
|
||||||
b = &connection->in;
|
wl_buffer_put_iov(&connection->in, iov, &count);
|
||||||
head = connection->in.head;
|
|
||||||
if (head < b->tail) {
|
msg.msg_name = NULL;
|
||||||
iov[0].iov_base = b->data + head;
|
msg.msg_namelen = 0;
|
||||||
iov[0].iov_len = b->tail - head;
|
msg.msg_iov = iov;
|
||||||
count = 1;
|
msg.msg_iovlen = count;
|
||||||
} else {
|
msg.msg_control = NULL;
|
||||||
size = ARRAY_LENGTH(b->data) - head;
|
msg.msg_controllen = 0;
|
||||||
iov[0].iov_base = b->data + head;
|
|
||||||
iov[0].iov_len = size;
|
|
||||||
iov[1].iov_base = b->data;
|
|
||||||
iov[1].iov_len = b->tail;
|
|
||||||
count = 2;
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
msg.msg_name = NULL;
|
|
||||||
msg.msg_namelen = 0;
|
|
||||||
msg.msg_iov = iov;
|
|
||||||
msg.msg_iovlen = count;
|
|
||||||
msg.msg_control = NULL;
|
|
||||||
msg.msg_controllen = 0;
|
|
||||||
len = recvmsg(connection->fd, &msg, 0);
|
len = recvmsg(connection->fd, &msg, 0);
|
||||||
} while (len < 0 && errno == EINTR);
|
} while (len < 0 && errno == EINTR);
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"read error from connection %p: %m (%d)\n",
|
"read error from connection %p: %m (%d)\n",
|
||||||
@ -149,90 +199,47 @@ int wl_connection_data(struct wl_connection *connection, uint32_t mask)
|
|||||||
} else if (len == 0) {
|
} else if (len == 0) {
|
||||||
/* FIXME: Handle this better? */
|
/* FIXME: Handle this better? */
|
||||||
return -1;
|
return -1;
|
||||||
} else if (head + len <= ARRAY_LENGTH(b->data)) {
|
|
||||||
b->head += len;
|
|
||||||
} else {
|
|
||||||
b->head = head + len - ARRAY_LENGTH(b->data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We know we have data in the buffer at this point,
|
connection->in.head += len;
|
||||||
* so if head equals tail, it means the buffer is
|
|
||||||
* full. */
|
|
||||||
|
|
||||||
available = b->head - b->tail;
|
|
||||||
if (available == 0)
|
|
||||||
available = sizeof b->data;
|
|
||||||
else if (available < 0)
|
|
||||||
available += ARRAY_LENGTH(b->data);
|
|
||||||
} else {
|
|
||||||
available = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & WL_CONNECTION_WRITABLE) {
|
if (mask & WL_CONNECTION_WRITABLE) {
|
||||||
b = &connection->out;
|
wl_buffer_get_iov(&connection->out, iov, &count);
|
||||||
tail = b->tail;
|
|
||||||
if (tail < b->head) {
|
msg.msg_name = NULL;
|
||||||
iov[0].iov_base = b->data + tail;
|
msg.msg_namelen = 0;
|
||||||
iov[0].iov_len = b->head - tail;
|
msg.msg_iov = iov;
|
||||||
count = 1;
|
msg.msg_iovlen = count;
|
||||||
} else {
|
msg.msg_control = NULL;
|
||||||
size = ARRAY_LENGTH(b->data) - tail;
|
msg.msg_controllen = 0;
|
||||||
iov[0].iov_base = b->data + tail;
|
|
||||||
iov[0].iov_len = size;
|
|
||||||
iov[1].iov_base = b->data;
|
|
||||||
iov[1].iov_len = b->head;
|
|
||||||
count = 2;
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
msg.msg_name = NULL;
|
|
||||||
msg.msg_namelen = 0;
|
|
||||||
msg.msg_iov = iov;
|
|
||||||
msg.msg_iovlen = count;
|
|
||||||
msg.msg_control = NULL;
|
|
||||||
msg.msg_controllen = 0;
|
|
||||||
len = sendmsg(connection->fd, &msg, 0);
|
len = sendmsg(connection->fd, &msg, 0);
|
||||||
} while (len < 0 && errno == EINTR);
|
} while (len < 0 && errno == EINTR);
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
fprintf(stderr, "write error for connection %p: %m\n", connection);
|
fprintf(stderr, "write error for connection %p: %m\n", connection);
|
||||||
return -1;
|
return -1;
|
||||||
} else if (tail + len <= ARRAY_LENGTH(b->data)) {
|
|
||||||
b->tail += len;
|
|
||||||
} else {
|
|
||||||
b->tail = tail + len - ARRAY_LENGTH(b->data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We just took data out of the buffer, so at this
|
connection->out.tail += len;
|
||||||
* point if head equals tail, the buffer is empty. */
|
if (connection->out.tail == connection->out.head)
|
||||||
|
|
||||||
if (b->tail == b->head)
|
|
||||||
connection->update(connection,
|
connection->update(connection,
|
||||||
WL_CONNECTION_READABLE,
|
WL_CONNECTION_READABLE,
|
||||||
connection->data);
|
connection->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return available;
|
return connection->in.head - connection->in.tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
|
wl_connection_write(struct wl_connection *connection,
|
||||||
|
const void *data, size_t count)
|
||||||
{
|
{
|
||||||
struct wl_buffer *b;
|
wl_buffer_put(&connection->out, data, count);
|
||||||
size_t size;
|
|
||||||
int head;
|
|
||||||
|
|
||||||
b = &connection->out;
|
if (connection->out.head - connection->out.tail == count)
|
||||||
head = b->head;
|
|
||||||
if (head + count <= ARRAY_LENGTH(b->data)) {
|
|
||||||
memcpy(b->data + head, data, count);
|
|
||||||
b->head += count;
|
|
||||||
} else {
|
|
||||||
size = ARRAY_LENGTH(b->data) - head;
|
|
||||||
memcpy(b->data + head, data, size);
|
|
||||||
memcpy(b->data, data + size, count - size);
|
|
||||||
b->head = count - size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b->tail == head)
|
|
||||||
connection->update(connection,
|
connection->update(connection,
|
||||||
WL_CONNECTION_READABLE |
|
WL_CONNECTION_READABLE |
|
||||||
WL_CONNECTION_WRITABLE,
|
WL_CONNECTION_WRITABLE,
|
||||||
|
Loading…
Reference in New Issue
Block a user