diff options
| author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-12-13 14:57:51 +0100 | 
|---|---|---|
| committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-12-13 14:57:51 +0100 | 
| commit | a77e7147c1814b4ed19d6abce417c8d8c627cc32 (patch) | |
| tree | 0827dabe5bea4a5bb26199675e3a4fa52c2905fd | |
| download | fastwriter-a77e7147c1814b4ed19d6abce417c8d8c627cc32.tar.gz fastwriter-a77e7147c1814b4ed19d6abce417c8d8c627cc32.tar.bz2 fastwriter-a77e7147c1814b4ed19d6abce417c8d8c627cc32.tar.xz fastwriter-a77e7147c1814b4ed19d6abce417c8d8c627cc32.zip | |
Initial release
| -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 */ | 
