diff options
-rw-r--r-- | .bzrignore | 10 | ||||
-rw-r--r-- | CMakeLists.txt | 60 | ||||
-rw-r--r-- | config.h.in | 1 | ||||
-rw-r--r-- | default.c | 172 | ||||
-rw-r--r-- | default.h | 20 | ||||
-rw-r--r-- | fastwriter.c | 317 | ||||
-rw-r--r-- | fastwriter.h | 44 | ||||
-rw-r--r-- | fastwriter.pc.in | 10 | ||||
-rw-r--r-- | private.h | 55 | ||||
-rw-r--r-- | sysinfo.c | 173 | ||||
-rw-r--r-- | sysinfo.h | 7 |
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 */ |