summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.bzrignore10
-rw-r--r--CMakeLists.txt60
-rw-r--r--config.h.in1
-rw-r--r--default.c172
-rw-r--r--default.h20
-rw-r--r--fastwriter.c317
-rw-r--r--fastwriter.h44
-rw-r--r--fastwriter.pc.in10
-rw-r--r--private.h55
-rw-r--r--sysinfo.c173
-rw-r--r--sysinfo.h7
11 files changed, 869 insertions, 0 deletions
diff --git a/.bzrignore b/.bzrignore
new file mode 100644
index 0000000..fc22479
--- /dev/null
+++ b/.bzrignore
@@ -0,0 +1,10 @@
+CMakeFiles
+config.h
+fastwriter.pc
+install_manifest.txt
+libfastwriter.so
+libfastwriter.so.0
+libfastwriter.so.0.0.1
+Makefile
+cmake_install.cmake
+CMakeCache.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..699790f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,60 @@
+project(fastwriter)
+
+set(FASTWRITER_VERSION "0.0.1")
+set(FASTWRITER_ABI_VERSION "0")
+
+cmake_minimum_required(VERSION 2.8)
+
+
+include(CheckIncludeFiles)
+check_include_files("linux/falloc.h" HAVE_LINUX_FALLOC_H)
+
+set(HEADERS fastwriter.h)
+add_definitions("-fPIC --std=c99 -Wall -O2 -pthread")
+
+add_library(fastwriter SHARED fastwriter.c sysinfo.c default.c)
+
+set_target_properties(fastwriter PROPERTIES
+ VERSION ${FASTWRITER_VERSION}
+ SOVERSION ${FASTWRITER_ABI_VERSION}
+ LINK_FLAGS "-pthread"
+)
+
+set(TARNAME "fastwriter")
+set(PACKAGE_VERSION ${FASTWRITER_VERSION})
+set(PACKAGE_NAME "${TARNAME}")
+set(PACKAGE_TARNAME "${TARNAME}")
+set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+set(PACKAGE_BUGREPORT "http://ufo.kit.edu/ufo/newticket")
+
+if(NOT DEFINED BIN_INSTALL_DIR)
+ set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin")
+endif(NOT DEFINED BIN_INSTALL_DIR)
+
+if(NOT DEFINED LIB_INSTALL_DIR)
+ set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib")
+endif(NOT DEFINED LIB_INSTALL_DIR)
+
+if(NOT DEFINED INCLUDE_INSTALL_DIR)
+ set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/${PACKAGE_TARNAME}")
+endif(NOT DEFINED INCLUDE_INSTALL_DIR)
+
+if(NOT DEFINED LOCALE_INSTALL_DIR)
+ set(LOCALE_INSTALL_DIR "${DATA_INSTALL_DIR}/locale/")
+endif(NOT DEFINED LOCALE_INSTALL_DIR)
+
+configure_file(fastwriter.pc.in ${CMAKE_CURRENT_BINARY_DIR}/fastwriter.pc)
+configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+install(TARGETS fastwriter
+ LIBRARY DESTINATION lib${LIB_SUFFIX}
+)
+
+install(FILES fastwriter.h
+ DESTINATION include
+)
+
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/fastwriter.pc
+ DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
+)
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..7c8ac8c
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1 @@
+#cmakedefine HAVE_LINUX_FALLOC_H
diff --git a/default.c b/default.c
new file mode 100644
index 0000000..693e157
--- /dev/null
+++ b/default.c
@@ -0,0 +1,172 @@
+#define _FASTWRITER_DEFAULT_C
+
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE 600
+#define _POSIX_C_SOURCE 200112L
+#define _LARGEFILE64_SOURCE
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+
+
+#ifdef HAVE_LINUX_FALLOC_H
+# include <linux/falloc.h>
+#endif /* HAVE_LINUX_FALLOC_H */
+
+#include "fastwriter.h"
+#include "private.h"
+#include "sysinfo.h"
+
+#define SYNC_MODE
+#define HAVE_FALLOCATE
+#define EXT4_WRITEBLOCK 4194304
+#define EXT4_PREALLOCATE 1073741824
+
+
+typedef struct {
+ int fd;
+
+ size_t prior_size; /**< original size of file */
+ size_t preallocated; /**< preallocated bytes */
+
+ size_t wr_block; /**< minimal block of data to write */
+ size_t pa_block; /**< preallocation setp */
+} fastwriter_default_t;
+
+
+int fastwriter_open_default(fastwriter_t *fw, const char *name, fastwriter_flags_t flags) {
+ int err;
+ char fs[16];
+
+ int open_flags = (O_CREAT|O_WRONLY|O_NOATIME|O_LARGEFILE);
+ int open_mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+#ifdef SYNC_MODE
+ open_flags |= O_DIRECT;//|O_SYNC;
+#endif /* SYNC_MODE */
+
+ fastwriter_default_t *ctx;
+
+ err = get_file_fs(name, sizeof(fs) - 1, fs);
+ if (err) return err;
+
+ ctx = (fastwriter_default_t*)malloc(sizeof(fastwriter_default_t));
+ if (!ctx) return ENOMEM;
+
+ memset(ctx, 0, sizeof(fastwriter_default_t));
+
+ fw->ctx = ctx;
+
+ if (!strcmp(fs, "raw")) {
+ ctx->wr_block = EXT4_WRITEBLOCK;
+ ctx->pa_block = 0;
+ } else if (!strcmp(fs, "ext4")) {
+ ctx->wr_block = EXT4_WRITEBLOCK;
+ ctx->pa_block = EXT4_PREALLOCATE;
+ } else if (!strcmp(fs, "btrfs")) {
+ ctx->wr_block = EXT4_WRITEBLOCK;
+ ctx->pa_block = EXT4_PREALLOCATE;
+ } else if (!strcmp(fs, "xfs")) {
+ ctx->wr_block = EXT4_WRITEBLOCK;
+ ctx->pa_block = EXT4_PREALLOCATE;
+ } else {
+ ctx->wr_block = EXT4_WRITEBLOCK;
+ ctx->pa_block = 0;
+ }
+
+ if (flags&FASTWRITER_FLAGS_OVERWRITE)
+ open_flags |= O_TRUNC;
+
+ ctx->fd = open(name, open_flags, open_mode);
+ if (ctx->fd < 0) return errno;
+
+ ctx->prior_size = 0;
+
+#ifndef HAVE_LINUX_FALLOC_H
+ if (((open_flags&FASTWRITER_FLAGS_OVERWRITE)==0)&&(strcmp(fs, "raw"))) {
+ ctx->prior_size = lseek(ctx->fd, 0, SEEK_END);
+ }
+#endif /* HAVE_LINUX_FALLOC_H */
+
+ ctx->preallocated = 0;
+
+ return 0;
+}
+
+
+void fastwriter_close_default(fastwriter_t *fw) {
+ if (fw->ctx) {
+ fastwriter_default_t *ctx = (fastwriter_default_t*)fw->ctx;
+
+ if (ctx->fd >= 0) {
+#ifndef HAVE_LINUX_FALLOC_H
+ if (ctx->prior_size) {
+ ftrucate(ctx->fd, ctx->prior_size + fw->written);
+ }
+#endif /* HAVE_LINUX_FALLOC_H */
+ close(ctx->fd);
+ }
+
+ free(ctx);
+ fw->ctx = NULL;
+ }
+}
+
+
+int fastwriter_write_default(fastwriter_t *fw, fastwriter_write_flags_t flags, size_t size, void *data, size_t *written) {
+ size_t sum = 0;
+ ssize_t res;
+ fastwriter_default_t *ctx = (fastwriter_default_t*)fw->ctx;
+
+ if ((flags&FASTWRITER_WRITE_FLAG_FORCE)==0) {
+ if (size < ctx->wr_block) {
+ *written = 0;
+ return 0;
+ }
+
+ size -= size % ctx->wr_block;
+ }
+
+ if ((ctx->pa_block)&&((fw->written + size) > ctx->preallocated)) {
+#ifdef HAVE_LINUX_FALLOC_H
+ if (fallocate(ctx->fd, FALLOC_FL_KEEP_SIZE, ctx->preallocated, ctx->pa_block)) {
+#else /* HAVE_LINUX_FALLOC_H */
+ if (posix_fallocate(ctx->fd, ctx->preallocated, ctx->pa_block)) {
+#endif /* HAVE_LINUX_FALLOC_H */
+ ctx->pa_block = 0;
+ } else {
+ ctx->preallocated += ctx->pa_block;
+ }
+ }
+
+ do {
+ res = write(ctx->fd, data, size);
+ if (res < 0) {
+ *written = sum;
+ return errno;
+ }
+
+ sum += res;
+ } while (sum < size);
+
+#ifdef SYNC_MODE
+ posix_fadvise(ctx->fd, fw->written, size, POSIX_FADV_DONTNEED);
+#endif /* SYNC_MODE */
+
+ *written = size;
+ return 0;
+}
diff --git a/default.h b/default.h
new file mode 100644
index 0000000..25f6556
--- /dev/null
+++ b/default.h
@@ -0,0 +1,20 @@
+#ifndef _FASTWRITER_DEFAULT_H
+#define _FASTWRITER_DEFAULT_H
+
+#include "private.h"
+
+int fastwriter_open_default(fastwriter_t *ctx, const char *name, fastwriter_flags_t flags);
+void fastwriter_close_default(fastwriter_t *ctx);
+int fastwriter_write_default(fastwriter_t *ctx, fastwriter_write_flags_t flags, size_t size, void *data, size_t *written);
+
+#ifdef _FASTWRITER_DEFAULT_C
+fastwriter_api_t fastwriter_default_api = {
+ fastwriter_default_open,
+ fastwriter_default_close,
+ fastwriter_default_write
+};
+#else /* _FASTWRITER_DEFAULT_C */
+extern fastwriter_api_t fastwriter_default_api;
+#endif /* _FASTWRITER_DEFAULT_C */
+
+#endif /* _FASTWRITER_DEFAULT_H */
diff --git a/fastwriter.c b/fastwriter.c
new file mode 100644
index 0000000..70f1043
--- /dev/null
+++ b/fastwriter.c
@@ -0,0 +1,317 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+
+
+#include "private.h"
+#include "default.h"
+#include "sysinfo.h"
+
+fastwriter_t *fastwriter_init(const char *fs, fastwriter_flags_t flags) {
+ fastwriter_t *ctx;
+
+ ctx = (fastwriter_t*)malloc(sizeof(fastwriter_t));
+ if (!ctx) return ctx;
+
+ memset(ctx, 0, sizeof(fastwriter_t));
+ ctx->params.flags = flags;
+ ctx->api = &fastwriter_default_api;
+
+ return ctx;
+}
+
+void fastwriter_destroy(fastwriter_t *ctx) {
+ free(ctx);
+}
+
+int fastwriter_set_buffer_size(fastwriter_t *ctx, size_t buffer_size) {
+ ctx->params.buffer_size = buffer_size;
+
+ return 0;
+}
+
+static void *fastwriter_writer_thread(void *user);
+
+int fastwriter_open(fastwriter_t *ctx, const char *name, fastwriter_flags_t flags) {
+ int i;
+ int err;
+ int e[4];
+
+ ctx->flags = flags | ctx->params.flags;
+
+ switch (ctx->params.buffer_size) {
+ case FASTWRITER_BUFFER_DEFAULT:
+ ctx->size = FASTWRITER_DEFAULT_BUFFER_SIZE;
+ break;
+ case FASTWRITER_BUFFER_MAX:
+ ctx->size = get_free_memory();
+
+ if ((ctx->size - FASTWRITER_RESERVE_MEMORY) < FASTWRITER_DEFAULT_BUFFER_SIZE)
+ ctx->size = FASTWRITER_DEFAULT_BUFFER_SIZE;
+ else
+ ctx->size -= FASTWRITER_RESERVE_MEMORY;
+
+ break;
+ default:
+ ctx->size = ctx->params.buffer_size;
+ }
+
+ ctx->buffer = malloc(ctx->size);
+ if (!ctx->buffer) {
+ fastwriter_close(ctx);
+ return ENOMEM;
+ }
+ ctx->err = 0;
+ ctx->written = 0;
+ ctx->commited = 0;
+ ctx->chunked = 0;
+
+ ctx->tail = 0;
+ ctx->head = 0;
+ ctx->pos = 0;
+
+ err = ctx->api->open(ctx, name, ctx->flags);
+ if (err) {
+ fastwriter_close(ctx);
+ return err;
+ }
+
+ e[0] = pthread_mutex_init(&ctx->data_cond_mutex, NULL);
+ e[1] = pthread_mutex_init(&ctx->space_cond_mutex, NULL);
+ e[2] = pthread_cond_init(&ctx->data_cond, NULL);
+ e[3] = pthread_cond_init(&ctx->space_cond, NULL);
+
+ if (e[0]|e[1]|e[2]|e[3]) {
+ if (!e[3]) pthread_cond_destroy(&ctx->space_cond);
+ if (!e[2]) pthread_cond_destroy(&ctx->data_cond);
+ if (!e[1]) pthread_mutex_destroy(&ctx->space_cond_mutex);
+ if (!e[0]) pthread_mutex_destroy(&ctx->data_cond_mutex);
+
+ fastwriter_close(ctx);
+
+ for (i = 0; i < 4; i++)
+ if (e[i]) return e[i];
+ }
+
+ ctx->clean_locks = 1;
+ ctx->run_flag = 1;
+
+ err = pthread_create(&ctx->wthread, NULL, &fastwriter_writer_thread, ctx);
+ if (err) {
+ ctx->run_flag = 0;
+ fastwriter_close(ctx);
+ return err;
+ }
+
+ return 0;
+}
+
+int fastwriter_close(fastwriter_t *ctx) {
+ if ((!ctx->err)&&(ctx->pos != ctx->head))
+ return EBADFD;
+
+ if (ctx->run_flag) {
+ ctx->run_flag = 0;
+
+ pthread_mutex_lock(&ctx->data_cond_mutex);
+ pthread_cond_broadcast(&ctx->data_cond);
+ pthread_mutex_unlock(&ctx->data_cond_mutex);
+
+ pthread_join(ctx->wthread, NULL);
+ }
+
+ if (ctx->clean_locks) {
+ pthread_cond_destroy(&ctx->space_cond);
+ pthread_cond_destroy(&ctx->data_cond);
+ pthread_mutex_destroy(&ctx->space_cond_mutex);
+ pthread_mutex_destroy(&ctx->data_cond_mutex);
+
+ ctx->clean_locks = 0;
+ }
+
+ ctx->api->close(ctx);
+
+ if (ctx->buffer) {
+ free(ctx->buffer);
+ ctx->buffer = NULL;
+ }
+
+ return 0;
+
+}
+
+
+static inline size_t fastwriter_compute_free_space(fastwriter_t *ctx) {
+ if (ctx->pos < ctx->tail) return ctx->tail - ctx->pos;
+ return ctx->tail + ctx->size - ctx->pos - 1;
+}
+
+int fastwriter_get_stats(fastwriter_t *ctx, fastwriter_stats_t *stats) {
+ stats->buffer_size = ctx->size;
+ stats->buffer_used = ctx->size - fastwriter_compute_free_space(ctx);
+ stats->buffer_max = ctx->max_usage;
+ stats->commited = ctx->commited;
+ stats->written = ctx->written;
+ return 0;
+}
+
+
+static void *fastwriter_writer_thread(void *user) {
+ int err = 0;
+ fastwriter_write_flags_t flags;
+ size_t size;
+ size_t head;
+
+ fastwriter_t *ctx = (fastwriter_t*)user;
+
+ while ((ctx->run_flag)||(ctx->head != ctx->tail)) {
+ if (ctx->head != ctx->tail) {
+ head = ctx->head;
+
+ if (head > ctx->tail) {
+ size = head - ctx->tail;
+ flags = FASTWRITER_WRITE_FLAGS_DEFAULT;
+ } else {
+ size = ctx->size - ctx->tail;
+ flags = FASTWRITER_WRITE_FLAG_FORCE;
+ }
+
+ if (!ctx->run_flag)
+ flags |= FASTWRITER_WRITE_FLAG_FORCE;
+
+ err = ctx->api->write(ctx, flags, size, ctx->buffer + ctx->tail, &size);
+ if (err) {
+ ctx->err = err;
+ ctx->run_flag = 0;
+
+ pthread_mutex_lock(&ctx->space_cond_mutex);
+ pthread_cond_broadcast(&ctx->space_cond);
+ pthread_mutex_unlock(&ctx->space_cond_mutex);
+
+ return NULL;
+ }
+
+ if (size > 0) {
+ ctx->written += size;
+
+ size += ctx->tail;
+ if (size == ctx->size) ctx->tail = 0;
+ else ctx->tail = size;
+
+ pthread_mutex_lock(&ctx->space_cond_mutex);
+ pthread_cond_broadcast(&ctx->space_cond);
+ pthread_mutex_unlock(&ctx->space_cond_mutex);
+ } else {
+ pthread_mutex_lock(&ctx->data_cond_mutex);
+ while ((ctx->run_flag)&&(ctx->head == head)) {
+ pthread_cond_wait(&ctx->data_cond, &ctx->data_cond_mutex);
+ }
+ }
+ } else {
+ pthread_mutex_lock(&ctx->data_cond_mutex);
+ while ((ctx->run_flag)&&(ctx->head == ctx->tail)) {
+ pthread_cond_wait(&ctx->data_cond, &ctx->data_cond_mutex);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+int fastwriter_push_chunk(fastwriter_t *ctx, size_t size, const void *data) {
+ size_t part1, end;
+ size_t free = fastwriter_compute_free_space(ctx);
+
+ if (free < size) {
+ ctx->max_usage = ctx->size;
+
+ if ((ctx->flags&FASTWRITER_FLAGS_BLOCK)==0)
+ return EWOULDBLOCK;
+
+ pthread_mutex_lock(&ctx->space_cond_mutex);
+ while ((ctx->run_flag)&&(fastwriter_compute_free_space(ctx) < size)) {
+ pthread_cond_wait(&ctx->space_cond, &ctx->space_cond_mutex);
+ }
+ pthread_mutex_unlock(&ctx->space_cond_mutex);
+ } else {
+ end = ctx->size - (free - size);
+ if (end > ctx->max_usage) ctx->max_usage = end;
+ }
+
+ if (!ctx->run_flag) {
+ if (ctx->err) return ctx->err;
+ return EBADFD;
+ }
+
+ if (ctx->pos < ctx->tail) end = ctx->tail;
+ else end = ctx->size;
+
+
+ part1 = end - ctx->pos;
+
+ if (part1 > size) {
+ // tail < pos (we have checked for free space)
+ end = size - part1;
+ memcpy(ctx->buffer + ctx->pos, data, part1);
+ memcpy(ctx->buffer, data + part1, end);
+ ctx->pos = end;
+ } else {
+ memcpy(ctx->buffer + ctx->pos, data, size);
+ ctx->pos += size;
+
+ if (ctx->pos == ctx->size) ctx->pos = 0;
+ }
+
+ ctx->chunked += size;
+
+ return 0;
+}
+
+
+int fastwriter_commit(fastwriter_t *ctx) {
+ ctx->head = ctx->pos;
+
+ pthread_mutex_lock(&ctx->data_cond_mutex);
+ pthread_cond_broadcast(&ctx->data_cond);
+ pthread_mutex_unlock(&ctx->data_cond_mutex);
+
+ ctx->commited += ctx->chunked;
+ ctx->chunked = 0;
+
+ return 0;
+}
+
+
+int fastwriter_cancel(fastwriter_t *ctx) {
+ ctx->pos = ctx->head;
+
+ ctx->chunked = 0;
+
+ return 0;
+}
+
+
+int fastwriter_push_data(fastwriter_t *ctx, size_t size, const void *buf) {
+ int err;
+ err = fastwriter_push_chunk(ctx, size, buf);
+ if (err) return err;
+
+ err = fastwriter_commit(ctx);
+ if (err) fastwriter_cancel(ctx);
+
+ return err;
+}
diff --git a/fastwriter.h b/fastwriter.h
new file mode 100644
index 0000000..389b0a9
--- /dev/null
+++ b/fastwriter.h
@@ -0,0 +1,44 @@
+#ifndef _FASTWRITER_H
+#define _FASTWRITER_H
+
+typedef struct fastwrtier_s fastwriter_t;
+
+typedef enum {
+ FASTWRITER_FLAGS_DEFAULT = 0,
+ FASTWRITER_FLAGS_BLOCK = 1, /**< by default the error will be returned if there is no space in the buffer to accomodate the data */
+ FASTWRITER_FLAGS_OVERWRITE = 2 /**< overwrite the data currently in the storage */
+} fastwriter_flags_t;
+
+typedef struct {
+ size_t buffer_size; /**< buffer size in bytes */
+ size_t buffer_used; /**< amount of data currently in the buffer */
+ size_t buffer_max; /**< maximal amount of data in the buffer */
+ size_t commited; /**< total commited data for current file */
+ size_t written; /**< total written data for currrent file */
+} fastwriter_stats_t;
+
+#define FASTWRITER_BUFFER_DEFAULT 0
+#define FASTWRITER_BUFFER_MAX ((size_t)-1)
+
+/*
+ * @fs - defines which writter implementation will be actually used. One can
+ * pass just a file name, then a type of partition will be autodetected.
+ * Otherwise, it is possible to pass the name of storage device. In this
+ * case either RingFS will be used or data will be pushed to the RAW device.
+ */
+fastwriter_t *fastwriter_init(const char *fs, fastwriter_flags_t flags);
+void fastwriter_destroy(fastwriter_t *ctx);
+
+int fastwriter_set_buffer_size(fastwriter_t *ctx, size_t buffer_size);
+int fastwriter_get_stats(fastwriter_t *ctx, fastwriter_stats_t *stats);
+
+int fastwriter_open(fastwriter_t *ctx, const char *name, fastwriter_flags_t flags);
+int fastwriter_close(fastwriter_t *ctx);
+
+int fastwriter_push_chunk(fastwriter_t *ctx, size_t size, const void *buf);
+int fastwriter_commit(fastwriter_t *ctx);
+int fastwriter_cancel(fastwriter_t *ctx);
+
+int fastwriter_push_data(fastwriter_t *ctx, size_t size, const void *buf);
+
+#endif /* _FASTWRITER_H */
diff --git a/fastwriter.pc.in b/fastwriter.pc.in
new file mode 100644
index 0000000..ceaa4d6
--- /dev/null
+++ b/fastwriter.pc.in
@@ -0,0 +1,10 @@
+prefix=${CMAKE_INSTALL_PREFIX}
+exec_prefix=${BIN_INSTALL_DIR}
+libdir=${LIB_INSTALL_DIR}
+includedir=${INCLUDE_INSTALL_DIR}
+
+Name: ${TARNAME}
+Description: Fast Streaming Storage Library
+Version: ${PACKAGE_VERSION}
+Libs: -L${LIB_INSTALL_DIR} -lfastwriter
+Cflags: -I${INCLUDE_INSTALL_DIR}
diff --git a/private.h b/private.h
new file mode 100644
index 0000000..6beb35b
--- /dev/null
+++ b/private.h
@@ -0,0 +1,55 @@
+#ifndef _FASTWRITER_PRIVATE_H
+#define _FASTWRITER_PRIVATE_H
+
+#define FASTWRITER_DEFAULT_BUFFER_SIZE 134217728 /* 128 MB */
+#define FASTWRITER_RESERVE_MEMORY 536870912 /* 512 MB */
+
+#include <pthread.h>
+#include "fastwriter.h"
+
+typedef struct {
+ fastwriter_flags_t flags;
+ size_t buffer_size;
+} fastwriter_parameters_t;
+
+typedef enum {
+ FASTWRITER_WRITE_FLAGS_DEFAULT = 0,
+ FASTWRITER_WRITE_FLAG_FORCE = 1 /**< Force writting all passed data */
+} fastwriter_write_flags_t;
+
+typedef struct {
+ int (*open)(fastwriter_t *ctx, const char *name, fastwriter_flags_t flags);
+ void (*close)(fastwriter_t *ctx);
+ int (*write)(fastwriter_t *ctx, fastwriter_write_flags_t flags, size_t size, void *data, size_t *written);
+} fastwriter_api_t;
+
+struct fastwrtier_s {
+ fastwriter_api_t *api; /**< Writer API */
+ void *ctx; /**< Writer Context */
+
+ fastwriter_flags_t flags;
+
+ int clean_locks;
+ volatile int err; /**< indicates error reported by the writter backend */
+ volatile int run_flag;
+ pthread_t wthread;
+ pthread_cond_t data_cond; /**< broadcasted when new data arrives */
+ pthread_mutex_t data_cond_mutex;
+ pthread_cond_t space_cond; /**< broadcasted when some space is freed */
+ pthread_mutex_t space_cond_mutex;
+
+ void *buffer;
+ size_t size; /**< size of the ring buffer in bytes */
+ size_t max_usage; /**< maximal number of bytes used in ring buffer */
+ volatile size_t tail; /**< first unwritten data in the ring buffer */
+ volatile size_t head; /**< last commited data in the ring buffer */
+ size_t pos; /**< last pushed data in the ring buffer */
+
+ size_t written; /**< number of bytes written */
+ size_t commited; /**< number of bytes commited */
+ size_t chunked; /**< number of bytes chunked */
+
+ fastwriter_parameters_t params;
+};
+
+#endif /* _FASTWRITER_PRIVATE_H */
diff --git a/sysinfo.c b/sysinfo.c
new file mode 100644
index 0000000..3805dcc
--- /dev/null
+++ b/sysinfo.c
@@ -0,0 +1,173 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+
+#define MEMINFO_FILE "/proc/meminfo"
+#define MTAB_FILE "/etc/mtab"
+
+#define BAD_OPEN_MESSAGE \
+"Error: /proc must be mounted\n" \
+" To mount /proc at boot you need an /etc/fstab line like:\n" \
+" /proc /proc proc defaults\n" \
+" In the meantime, run \"mount /proc /proc -t proc\"\n"
+
+/* This macro opens filename only if necessary and seeks to 0 so
+ * that successive calls to the functions are more efficient.
+ * It also reads the current contents of the file into the global buf.
+ */
+#define FILE_TO_BUF(filename) do{ \
+ static int fd, local_n; \
+ if ((fd = open(filename, O_RDONLY)) == -1) { \
+ fputs(BAD_OPEN_MESSAGE, stderr); \
+ fflush(NULL); \
+ _exit(102); \
+ } \
+ lseek(fd, 0L, SEEK_SET); \
+ if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
+ perror(filename); \
+ fflush(NULL); \
+ _exit(103); \
+ } \
+ buf[local_n] = '\0'; \
+ close(fd); \
+}while(0)
+
+
+typedef struct mem_table_struct {
+ const char *name; /* memory type name */
+ unsigned long *slot; /* slot in return struct */
+} mem_table_struct;
+
+static int compare_mem_table_structs(const void *a, const void *b){
+ return strcmp(((const mem_table_struct*)a)->name,((const mem_table_struct*)b)->name);
+}
+
+size_t get_free_memory(void){
+ char buf[4096];
+ unsigned long kb_main_buffers, kb_main_cached, kb_main_free;
+ char namebuf[16]; /* big enough to hold any row name */
+ mem_table_struct findme = { namebuf, NULL};
+ mem_table_struct *found;
+ char *head;
+ char *tail;
+
+ const mem_table_struct mem_table[] = {
+ {"Buffers", &kb_main_buffers}, // important
+ {"Cached", &kb_main_cached}, // important
+ {"MemFree", &kb_main_free}, // important
+ };
+ const int mem_table_count = sizeof(mem_table)/sizeof(mem_table_struct);
+
+ FILE_TO_BUF(MEMINFO_FILE);
+
+ head = buf;
+ for(;;){
+ tail = strchr(head, ':');
+ if(!tail) break;
+ *tail = '\0';
+ if(strlen(head) >= sizeof(namebuf)){
+ head = tail+1;
+ goto nextline;
+ }
+ strcpy(namebuf,head);
+ found = bsearch(&findme, mem_table, mem_table_count,
+ sizeof(mem_table_struct), compare_mem_table_structs
+ );
+ head = tail+1;
+ if(!found) goto nextline;
+ *(found->slot) = strtoul(head,&tail,10);
+nextline:
+ tail = strchr(head, '\n');
+ if(!tail) break;
+ head = tail+1;
+ }
+
+ return (kb_main_buffers + kb_main_cached + kb_main_free) * 1024;
+}
+
+
+int get_file_fs(const char *fname, size_t size, char *fs) {
+ int err = 0;
+ char buf[4096];
+ char *fn;
+
+ char *head;
+ char *tail;
+
+ size_t len, max = 0;
+ struct stat st;
+
+ if ((!fname)||(!fs)||(size < 3)) return EINVAL;
+
+ if (*fname == '/') {
+ fn = (char*)fname;
+ } else {
+ if (!getcwd(buf, 4095)) return errno;
+ fn = malloc(strlen(fname) + strlen(buf) + 2);
+ if (!fn) return ENOMEM;
+ sprintf(fn, "%s/%s", buf, fname);
+ }
+
+ if (!stat(fn, &st)) {
+ if (S_ISBLK(st.st_mode)) {
+ strcpy(fs, "raw");
+ goto clean;
+ }
+ }
+
+ FILE_TO_BUF(MTAB_FILE);
+
+ head = buf;
+ for(;;){
+ head = strchr(head, ' ');
+ if(!head) break;
+
+ head += 1;
+ tail = strchr(head, ' ');
+ if(!tail) break;
+
+ *tail = '\0';
+
+ len = strlen(head);
+ if((len <= max)||(strncmp(head, fn, len))) {
+ head = tail+1;
+ goto nextline;
+ }
+
+ head = tail + 1;
+ tail = strchr(head, ' ');
+ if(!tail) break;
+
+ *tail = '\0';
+
+ if (!strncasecmp(head,"root",4)) {
+ head = tail+1;
+ goto nextline;
+ }
+
+ max = len;
+
+ if (strlen(head) >= size) err = EFAULT;
+ else {
+ err = 0;
+ strcpy(fs, head);
+ }
+
+ head = tail+1;
+nextline:
+ tail = strchr(head, '\n');
+ if(!tail) break;
+ head = tail+1;
+ }
+
+clean:
+ if (fn != fname) free(fn);
+
+ return err;
+}
diff --git a/sysinfo.h b/sysinfo.h
new file mode 100644
index 0000000..d5636a7
--- /dev/null
+++ b/sysinfo.h
@@ -0,0 +1,7 @@
+#ifndef _PCITOOL_SYSINFO_H
+#define _PCITOOL_SYSINFO_H
+
+size_t get_free_memory();
+int get_file_fs(const char *fname, size_t size, char *fs);
+
+#endif /* _PCITOOL_SYSINFO_H */