mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2026-03-24 09:06:21 -04:00
Split out connection io buffer logic.
This commit is contained in:
parent
c5089878cb
commit
680f1c7025
4 changed files with 300 additions and 193 deletions
193
connection.c
Normal file
193
connection.c
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
|
||||
|
||||
struct wl_buffer {
|
||||
char data[4096];
|
||||
int head, tail;
|
||||
};
|
||||
|
||||
struct wl_connection {
|
||||
struct wl_buffer in, out;
|
||||
int fd;
|
||||
void *data;
|
||||
wl_connection_update_func_t update;
|
||||
};
|
||||
|
||||
struct wl_connection *
|
||||
wl_connection_create(int fd,
|
||||
wl_connection_update_func_t update,
|
||||
void *data)
|
||||
{
|
||||
struct wl_connection *connection;
|
||||
|
||||
connection = malloc(sizeof *connection);
|
||||
memset(connection, 0, sizeof *connection);
|
||||
connection->fd = fd;
|
||||
connection->update = update;
|
||||
connection->data = data;
|
||||
|
||||
connection->update(connection,
|
||||
WL_CONNECTION_READABLE,
|
||||
connection->data);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
void
|
||||
wl_connection_destroy(struct wl_connection *connection)
|
||||
{
|
||||
free(connection);
|
||||
}
|
||||
|
||||
void
|
||||
wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
|
||||
{
|
||||
struct wl_buffer *b;
|
||||
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
|
||||
wl_connection_consume(struct wl_connection *connection, size_t size)
|
||||
{
|
||||
struct wl_buffer *b;
|
||||
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)
|
||||
{
|
||||
struct wl_buffer *b;
|
||||
struct iovec iov[2];
|
||||
int len, head, tail, count, size, available;
|
||||
|
||||
if (mask & WL_CONNECTION_READABLE) {
|
||||
b = &connection->in;
|
||||
head = connection->in.head;
|
||||
if (head < b->tail) {
|
||||
iov[0].iov_base = b->data + head;
|
||||
iov[0].iov_len = b->tail - head;
|
||||
count = 1;
|
||||
} else {
|
||||
size = ARRAY_LENGTH(b->data) - head;
|
||||
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;
|
||||
}
|
||||
len = readv(connection->fd, iov, count);
|
||||
if (len < 0) {
|
||||
fprintf(stderr,
|
||||
"read error from connection %p: %m (%d)\n",
|
||||
connection, errno);
|
||||
return -1;
|
||||
} else if (len == 0) {
|
||||
/* FIXME: Handle this better? */
|
||||
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,
|
||||
* 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) {
|
||||
b = &connection->out;
|
||||
tail = b->tail;
|
||||
if (tail < b->head) {
|
||||
iov[0].iov_base = b->data + tail;
|
||||
iov[0].iov_len = b->head - tail;
|
||||
count = 1;
|
||||
} else {
|
||||
size = ARRAY_LENGTH(b->data) - tail;
|
||||
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;
|
||||
}
|
||||
len = writev(connection->fd, iov, count);
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "write error for connection %p: %m\n", connection);
|
||||
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
|
||||
* point if head equals tail, the buffer is empty. */
|
||||
|
||||
if (b->tail == b->head)
|
||||
connection->update(connection,
|
||||
WL_CONNECTION_READABLE,
|
||||
connection->data);
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
void
|
||||
wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
|
||||
{
|
||||
struct wl_buffer *b;
|
||||
size_t size;
|
||||
int head;
|
||||
|
||||
b = &connection->out;
|
||||
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,
|
||||
WL_CONNECTION_READABLE |
|
||||
WL_CONNECTION_WRITABLE,
|
||||
connection->data);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue