diff --git a/samples/acache_client/Makefile b/samples/acache_client/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..13e5485b3d2f6bde68e58576a8563d9523698b1a --- /dev/null +++ b/samples/acache_client/Makefile @@ -0,0 +1,13 @@ +.PHONY: client clean + +CC = $(CROSS_COMPILE)gcc +CFLAGS = -Wall -g + + +OBJ = main.o connect.o +client: ${OBJ} + $(CC) $(CFLAGS) $^ -o acache_client +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ +clean: + rm -f *.o acache_client diff --git a/samples/acache_client/connect.c b/samples/acache_client/connect.c new file mode 100644 index 0000000000000000000000000000000000000000..2dd442415ee245f7728acb492fc9bdedc9b0f00c --- /dev/null +++ b/samples/acache_client/connect.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "connect.h" + +static int ACACHE_READWRITE_CAPACITY = 4096; +static struct connection readwrite_conn; +static struct readwrite_conn_metadata { + int initialized; + int fd; +} private; + +void *initialize(struct connection *self) +{ + long ret; + + private.fd = open(acache_path, O_RDWR | O_SYNC); + if (private.fd == -1) { + fprintf(stderr, "error opening device: %s\n", strerror(errno)); + exit(-1); + } + + struct acache_metadata { + uint32_t magic; + uint32_t conntype; + uint32_t devsize; + } acache_metadata; +#define ACACHE_GET_METADATA _IOR('a', 1, struct acache_metadata) + ret = ioctl(private.fd, ACACHE_GET_METADATA, &acache_metadata); + if (ret) { + fprintf(stderr, "error getting device memory length: %s\n", strerror(errno)); + exit(-1); + } + if (acache_metadata.magic != ACACHE_MAGIC) { + fprintf(stderr, "version not match; client: %u kernel: %u\n", + ACACHE_MAGIC, acache_metadata.magic); + exit(-1); + } + if (acache_metadata.conntype != ACACHE_READWRITE_CONN) { + fprintf(stderr, "connect type not match; client: %u kernel: %u\n", + ACACHE_READWRITE_CONN, acache_metadata.conntype); + exit(-1); + } + printf("got dev size %u\n", acache_metadata.devsize); + private.initialized = 1; + + return (void *)&private; +} + +struct readwrite_conn_metadata* get_metadata(struct connection *self) +{ + struct readwrite_conn_metadata *metadata; + + if (self == NULL) { + fprintf(stderr, "connenction uninitailized\n"); + return NULL; + } + + metadata = (struct readwrite_conn_metadata *)self->private; + + if (metadata->initialized == 0) { + fprintf(stderr, "connenction uninitailized\n"); + return NULL; + } + return metadata; +} + +int send_items(struct connection *self, struct acache_info *infos, + size_t count) +{ + long ret; + struct readwrite_conn_metadata *metadata = get_metadata(self); + + if (!metadata) { + return 0; + } + ret = write(metadata->fd, (void*)infos, count * sizeof(struct acache_info)); + if (ret < 0) { + fprintf(stderr, "error writing data: %ld\n", ret); + return 0; + } + if (ret % sizeof(struct acache_info)) { + fprintf(stderr, "error writing data: data length is not multiple of sizeof(struct acache_info): %ld %ld\n", + ret, sizeof(struct acache_info)); + return 0; + } + return ret / sizeof(struct acache_info); +} + +int fetch_items(struct connection *self, struct acache_info *infos, + size_t count) +{ + long ret; + struct readwrite_conn_metadata *metadata = get_metadata(self); + + if (!metadata) { + return 0; + } + ret = read(metadata->fd, (void*)infos, count * sizeof(struct acache_info)); + if (ret < 0) { + fprintf(stderr, "error reading data: %ld\n", ret); + return 0; + } + if (ret % sizeof(struct acache_info)) { + fprintf(stderr, "error reading data: data length is not multiple of sizeof(struct acache_info): %ld %ld\n", + ret, sizeof(struct acache_info)); + return 0; + } + return ret / sizeof(struct acache_info); +} + +int get_capacity() { + return ACACHE_READWRITE_CAPACITY; +} + +int close_conn(struct connection *self) +{ + struct readwrite_conn_metadata *metadata = get_metadata(self); + + if (!metadata) { + return 0; + } + close(metadata->fd); + return 0; + +} + +struct connection *initialize_conn_rw(void) +{ + readwrite_conn.ops.close = close_conn; + readwrite_conn.ops.initialize = initialize; + readwrite_conn.ops.send_items = send_items; + readwrite_conn.ops.fetch_items = fetch_items; + readwrite_conn.ops.get_capacity = get_capacity; + readwrite_conn.private = initialize(&readwrite_conn); + return &readwrite_conn; +} diff --git a/samples/acache_client/connect.h b/samples/acache_client/connect.h new file mode 100644 index 0000000000000000000000000000000000000000..b0357c78c8c4940e48080cdba5edeb71c6c7441b --- /dev/null +++ b/samples/acache_client/connect.h @@ -0,0 +1,74 @@ +#ifndef ACACHE_CONNENECT_H +#define ACACHE_CONNENECT_H +#include + +#define ACACHE_MAGIC 2 +enum acache_conn_types { + ACACHE_NO_CONN = 0, + ACACHE_RINGBUFFER_CONN, + ACACHE_READWRITE_CONN, +}; +#define acache_path "/dev/acache" + +struct acache_info { + uint64_t length; + uint64_t offset; + uint64_t start_time; + uint32_t dev; + int opcode; +}; + +struct connection; +struct connection_operations { + + /* + * initialize connnection + * parameters: none + * return values: + * - void *: private data for connection + */ + void *(*initialize)(struct connection *self); + /* + * send_items send items to peer side + * parameters: + * - infos: data to send + * - count: data length + * return values: + * - number of sent items + */ + int (*send_items)(struct connection *self, struct acache_info *infos, + size_t count); + /* + * send_items recieve items from peer side + * paremeters: + * - infos: buffer to place recieved items + * - count: length of buffer + * return values: + * - number of recieved items + */ + int (*fetch_items)(struct connection *self, struct acache_info *infos, + size_t count); + /* + * close closes the connection + */ + int (*close)(struct connection *self); + + /* + * get_capacity return the capacity of items that can send and revice at once + */ + int (*get_capacity)(struct connection *self); + +}; + +struct connection { + /* + * private data for specific connnetion + */ + void *private; + struct connection_operations ops; +}; + +struct connection *initialize_conn_rw(void); + +#endif + diff --git a/samples/acache_client/main.c b/samples/acache_client/main.c new file mode 100644 index 0000000000000000000000000000000000000000..929c70798cfb4bc1770f57af469820136f0f7721 --- /dev/null +++ b/samples/acache_client/main.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "connect.h" + +/* + * dev_t in userspace is 8-bytes long but 4-byte long in kernel + * work around this + */ +#define MINORBITS 20 +#define MINORMASK ((1U << MINORBITS) - 1) +#define MKDEV(ma, mi) ((ma)<> MINORBITS)) +#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) + +struct acache_info *inbuf, *outbuf; +struct connection *conn; + +void print_infos(const char *prefix, struct acache_info *infos, size_t length) +{ + size_t i; + struct acache_info *info; + + for (i = 0; i < length; i++) { + info = infos + i; + + printf("%4s,%20lu,%8u,%8u,%15lu,%12lu\n", + prefix, info->start_time, MAJOR(info->dev), + MINOR(info->dev), info->offset, info->length); + } +} + +int malloc_buffers(struct acache_info **inbuf, struct acache_info **outbuf, + size_t capacity) +{ + /* prepare buffers to store incoming or outgoing items */ + *inbuf = (struct acache_info *)malloc(sizeof(struct acache_info) * capacity); + *outbuf = (struct acache_info *)malloc(sizeof(struct acache_info) * capacity); + + if (!*inbuf || !*outbuf) { + fprintf(stderr, "error malloc memory: %s\n, size: %lu, %lu\n", + strerror(errno), + sizeof(struct acache_info) * capacity, + sizeof(struct acache_info) * capacity); + return -errno; + } + return 0; +} + +void free_buffer(struct acache_info **buf) +{ + if (buf && *buf) { + free(*buf); + *buf = NULL; + } +} + +void elegant_exit(int sig) { + printf("exiting..."); + free_buffer(&inbuf); + free_buffer(&outbuf); + conn->ops.close(conn); + exit(0); +} + +int main(int argc, char **argv) +{ + int debug = 0; + int ret; + int outbuf_tail; + size_t capacity; + + conn = initialize_conn_rw(); + + if (conn == NULL) { + fprintf(stderr, "error initialzied connnection\n"); + return -1; + } + + if (argc > 1 && strcmp("-d", argv[1]) == 0) + debug = 1; + + /* prepare buffers to store incoming or outgoing items */ + capacity = conn->ops.get_capacity(conn); + ret = malloc_buffers(&inbuf, &outbuf, capacity); + + if (ret < 0) + return ret; + + if (debug) { + printf("%4s,%20s,%8s,%8s,%15s,%12s\n", + "op","time(ns)","majorDev","minorDev","offset(B)","length(B)"); + } + /* main loop */ + if (signal(SIGINT, elegant_exit) == SIG_ERR) { + fprintf(stderr, "error handling SIGINT: %s\n", strerror(errno)); + } + if (signal(SIGTERM, elegant_exit) == SIG_ERR) { + fprintf(stderr, "error handling SIGTERM: %s\n", strerror(errno)); + } + while (1) { + unsigned int i, inlen; + + inlen = conn->ops.fetch_items(conn, inbuf, capacity); + if (!inlen) { + usleep(100); + continue; + } + + outbuf_tail = 0; + for (i = 0; i < inlen; i++) { + /* customize prefetch strategy here */ + memcpy(outbuf + outbuf_tail, inbuf + i, sizeof(struct acache_info)); + outbuf[outbuf_tail].offset += outbuf[outbuf_tail].length >> 9; + outbuf_tail++; + } + if (debug) { + print_infos("R", inbuf, inlen); + print_infos("P", outbuf, outbuf_tail); + } + if (outbuf_tail) { + conn->ops.send_items(conn, outbuf, outbuf_tail); + } + } + return 0; +}