From a77e7147c1814b4ed19d6abce417c8d8c627cc32 Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Tue, 13 Dec 2011 14:57:51 +0100 Subject: Initial release --- .bzrignore | 10 ++ CMakeLists.txt | 60 +++++++++++ config.h.in | 1 + default.c | 172 ++++++++++++++++++++++++++++++ default.h | 20 ++++ fastwriter.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fastwriter.h | 44 ++++++++ fastwriter.pc.in | 10 ++ private.h | 55 ++++++++++ sysinfo.c | 173 ++++++++++++++++++++++++++++++ sysinfo.h | 7 ++ 11 files changed, 869 insertions(+) create mode 100644 .bzrignore create mode 100644 CMakeLists.txt create mode 100644 config.h.in create mode 100644 default.c create mode 100644 default.h create mode 100644 fastwriter.c create mode 100644 fastwriter.h create mode 100644 fastwriter.pc.in create mode 100644 private.h create mode 100644 sysinfo.c create mode 100644 sysinfo.h 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + + +#ifdef HAVE_LINUX_FALLOC_H +# include +#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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + + +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ -- cgit v1.2.1