From: Liu Yuan <tailai.ly at taobao.com> These are trivial helper wrappers around standard IO functions and interger hash function. "stolen" from git and Linux kernel. Signed-off-by: Liu Yuan <tailai.ly at taobao.com> --- include/util.h | 63 +++++++++++++++++++++++ sheep/util.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 0 deletions(-) create mode 100644 sheep/util.c diff --git a/include/util.h b/include/util.h index 2dccd16..c73a6d5 100644 --- a/include/util.h +++ b/include/util.h @@ -2,6 +2,8 @@ #define __UTIL_H__ #include <string.h> +#include <limits.h> +#include <stdint.h> #include "bitops.h" @@ -53,4 +55,65 @@ static inline void *zalloc(size_t size) return calloc(1, size); } +typedef void (*try_to_free_t)(size_t); +extern try_to_free_t set_try_to_free_routine(try_to_free_t); + +extern void *xmalloc(size_t size); +extern void *xzalloc(size_t size); +extern void *xrealloc(void *ptr, size_t size); +extern void *xcalloc(size_t nmemb, size_t size); +extern ssize_t xread(int fd, void *buf, size_t len); +extern ssize_t xwrite(int fd, const void *buf, size_t len); + +/* Integer hash functions, taken from Linux kernel. + * Use hash_long() to get most out of your cpu. + */ + +/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ +#define GOLDEN_RATIO_PRIME_32 0x9e370001UL +/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ +#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL + +#if __SIZEOF_POINTER__ == 4 +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32 +#define hash_long(val, bits) hash_32(val, bits) +#elif __SIZEOF_POINTER__ == 8 +#define hash_long(val, bits) hash_64(val, bits) +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64 +#else +#error Wordsize not 32 or 64 +#endif + +static inline uint64_t hash_64(uint64_t val, unsigned int bits) +{ + uint64_t hash = val; + + /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ + uint64_t n = hash; + n <<= 18; + hash -= n; + n <<= 33; + hash -= n; + n <<= 3; + hash += n; + n <<= 3; + hash -= n; + n <<= 4; + hash += n; + n <<= 2; + hash += n; + + /* High bits are more random, so use them. */ + return hash >> (64 - bits); +} + +static inline uint32_t hash_32(uint32_t val, unsigned int bits) +{ + /* On some cpus multiply is faster, on others gcc will do shifts */ + uint32_t hash = val * GOLDEN_RATIO_PRIME_32; + + /* High bits are more random, so use them. */ + return hash >> (32 - bits); +} + #endif diff --git a/sheep/util.c b/sheep/util.c new file mode 100644 index 0000000..ebcc1d8 --- /dev/null +++ b/sheep/util.c @@ -0,0 +1,150 @@ +/* + * Taken from git and Linux kernel by Liu Yuan <namei.unix at gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> + +#include "util.h" +#include "logger.h" + +static void do_nothing(size_t size) +{ +} + +static void (*try_to_free_routine)(size_t size) = do_nothing; + +try_to_free_t set_try_to_free_routine(try_to_free_t routine) +{ + try_to_free_t old = try_to_free_routine; + if (!routine) + routine = do_nothing; + try_to_free_routine = routine; + return old; +} + +void *xmalloc(size_t size) +{ + void *ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) { + try_to_free_routine(size); + ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) + panic("Out of memory"); + } + return ret; +} + +void *xzalloc(size_t size) +{ + void *ret; + ret = xmalloc(size); + memset(ret, 0, size); + return ret; +} + +void *xrealloc(void *ptr, size_t size) +{ + void *ret = realloc(ptr, size); + if (!ret && !size) + ret = realloc(ptr, 1); + if (!ret) { + try_to_free_routine(size); + ret = realloc(ptr, size); + if (!ret && !size) + ret = realloc(ptr, 1); + if (!ret) + panic("Out of memory"); + } + return ret; +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) { + try_to_free_routine(nmemb * size); + ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) + panic("Out of memory"); + } + return ret; +} + +static ssize_t _read(int fd, void *buf, size_t len) +{ + ssize_t nr; + while (1) { + nr = read(fd, buf, len); + if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) + continue; + return nr; + } +} + +static ssize_t _write(int fd, const void *buf, size_t len) +{ + ssize_t nr; + while (1) { + nr = write(fd, buf, len); + if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) + continue; + return nr; + } +} + +ssize_t xread(int fd, void *buf, size_t count) +{ + char *p = buf; + ssize_t total = 0; + + while (count > 0) { + ssize_t loaded = _read(fd, p, count); + if (loaded < 0) + return -1; + if (loaded == 0) + return total; + count -= loaded; + p += loaded; + total += loaded; + } + + return total; +} + +ssize_t xwrite(int fd, const void *buf, size_t count) +{ + const char *p = buf; + ssize_t total = 0; + + while (count > 0) { + ssize_t written = _write(fd, p, count); + if (written < 0) + return -1; + if (!written) { + errno = ENOSPC; + return -1; + } + count -= written; + p += written; + total += written; + } + + return total; +} -- 1.7.6.1 |