From 325a3743eb3d14712ef6d2edec6442cebc008eb8 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 9 Aug 2013 16:37:56 +0100 Subject: [PATCH 01/97] small changes in build system --- Makefile.am.coverage | 2 +- m4/gcov.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am.coverage b/Makefile.am.coverage index c45711a..52643e5 100644 --- a/Makefile.am.coverage +++ b/Makefile.am.coverage @@ -21,7 +21,7 @@ generate-coverage-html: @echo Collecting coverage data - $(LCOV) -d $(top_builddir) -c -o coverage.run --gcov-tool /usr/x86_64-pc-linux-gnu/gcc-bin/4.5.3/gcov + $(LCOV) -d $(top_builddir) -c -o coverage.run --gcov-tool /usr/bin/gcov $(LCOV) -d $(top_builddir) -a ./coverage.base -a ./coverage.run -o coverage.info LANG=C $(GENHTML) --prefix $(top_builddir) --output-directory coveragereport --title "Code Coverage" --legend --branch-coverage --show-details coverage.run diff --git a/m4/gcov.m4 b/m4/gcov.m4 index 77dffe8..1495f86 100644 --- a/m4/gcov.m4 +++ b/m4/gcov.m4 @@ -31,7 +31,7 @@ AC_DEFUN([AC_TDD_GCOV], AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) fi - lcov_version_list="1.6 1.7 1.8 1.9" + lcov_version_list="1.6 1.7 1.8 1.9 1.10" AC_CHECK_PROG(LCOV, lcov, lcov) AC_CHECK_PROG(GENHTML, genhtml, genhtml) From d31a5cad7b0dad32d286ea63373cbea0ebc86ddf Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 12 Aug 2013 16:39:44 +0100 Subject: [PATCH 02/97] configure.ac --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index fdf5771..daef328 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,7 +25,7 @@ AM_CFLAGS = -Wall -I ../include/ bin_PROGRAMS = taskrambler taskrambler_SOURCES = taskrambler.c $(IFACE) $(UTILS) -taskrambler_CFLAGS = -Wall -I ../include/# $(COVERAGE_CFLAGS) +taskrambler_CFLAGS = -Wall -DPWD=\"$(PWD)\" -I ../include/# $(COVERAGE_CFLAGS) taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap #taskrambler_LDFLAGS = $(COVERAGE_LDFLAGS) From ea6482c7f7c456f265633e13a43928c8538d1e03 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 12 Aug 2013 16:42:02 +0100 Subject: [PATCH 03/97] add build dir as macro definition to daemonze.c thus been able to chdir there so that all assets would be found. --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index 0fafc8c..fff3090 100644 --- a/configure.ac +++ b/configure.ac @@ -19,6 +19,9 @@ AC_SUBST(COVERAGE_CFLAGS) AC_SUBST(COVERAGE_CXXFLAGS) AC_SUBST(COVERAGE_LDFLAGS) +PWD=$(/bin/pwd) +AC_SUBST(PWD) + # Checks for programs. AC_PROG_CXX AC_PROG_CC From f65bf3e1f8c747a9ed99217c1986bcb6d0fecfcd Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 12 Aug 2013 16:42:37 +0100 Subject: [PATCH 04/97] make a more real daemonizing --- src/utils/daemonize.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/utils/daemonize.c b/src/utils/daemonize.c index 6dd8318..5b1cce3 100644 --- a/src/utils/daemonize.c +++ b/src/utils/daemonize.c @@ -25,7 +25,14 @@ #include // for printf() and fprintf() #include // for getopt #include +#include +#include +#include + + +#define WORKDIR "/" +#define UMASK 0 void daemonize(void) { pid_t pid; @@ -40,6 +47,23 @@ void daemonize(void) { // make new child session leader setsid(); + if (0 > ((pid = fork()))) { + perror("deamoinze[fork]"); + exit(EXIT_FAILURE); + } else if (0 != pid) { + exit(EXIT_SUCCESS); + } + + // set umask and change to working directory to / + umask(UMASK); + chdir(PWD); // this should root and assets needs to be found + // via some kind of configuration. + + // we should close all open filedescriptors now. + // But I assume that this function is called at the very start of the + // program and no more filedescriptors are open than the standard + // ones. + // connect all standard streams to /dev/null stderr = freopen("/dev/null", "w", stderr); stdin = freopen("/dev/null", "r", stdin); From 7ce2adf1fe49c887346266024260e837252456aa Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 12 Aug 2013 16:43:52 +0100 Subject: [PATCH 05/97] only code format changes --- src/http/parser/parse.c | 2 +- src/server/server.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/http/parser/parse.c b/src/http/parser/parse.c index 742ffd2..ad12b67 100644 --- a/src/http/parser/parse.c +++ b/src/http/parser/parse.c @@ -83,7 +83,7 @@ httpParserParse(void * _this, Stream st) case HTTP_MESSAGE_START: if (NULL == (line = cbufGetLine(this->buffer, &line_end))) { if (! cbufIsEmpty(this->buffer)) { - this->isize = this->buffer->bused; + this->isize = this->buffer->bused; this->incomplete = malloc(this->isize); memcpy(this->incomplete, cbufGetData(this->buffer, this->isize), diff --git a/src/server/server.c b/src/server/server.c index 5f43eb0..8f76a3a 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -61,15 +61,15 @@ serverCtor(void * _this, va_list * params) port = va_arg(* params, int); backlog = va_arg(* params, unsigned int); - this->fds = calloc(sizeof(struct pollfd), this->max_fds); - this->conns = calloc(sizeof(struct conns), this->max_fds); + this->fds = calloc(sizeof(struct pollfd), this->max_fds); + this->conns = calloc(sizeof(struct conns), this->max_fds); - this->sock = new(Sock, this->logger, port); - flags = fcntl(this->sock->handle, F_GETFL, 0); + this->sock = new(Sock, this->logger, port); + flags = fcntl(this->sock->handle, F_GETFL, 0); fcntl(this->sock->handle, F_SETFL, flags | O_NONBLOCK); this->sockSSL = new(Sock, this->logger, port+1); - flags = fcntl(this->sockSSL->handle, F_GETFL, 0); + flags = fcntl(this->sockSSL->handle, F_GETFL, 0); fcntl(this->sockSSL->handle, F_SETFL, flags | O_NONBLOCK); SSL_library_init(); From e6d275faa288e951d39b0532ea47b8fc78c210e1 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 12 Aug 2013 16:45:02 +0100 Subject: [PATCH 06/97] put daemonize before our working child is forked. --- src/taskrambler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/taskrambler.c b/src/taskrambler.c index 5e900aa..363f7de 100644 --- a/src/taskrambler.c +++ b/src/taskrambler.c @@ -72,6 +72,7 @@ main() setrlimit(RLIMIT_NOFILE, &limit); init_signals(); + daemonize(); shm = shm_open("/fooshm", O_RDWR|O_CREAT, S_IRWXU); ftruncate(shm, psize); @@ -145,7 +146,6 @@ main() worker = new(HttpWorker, "testserver", value, auth); server = new(Server, logger, worker, 11212, SOMAXCONN); - //daemonize(); if (NULL != server) { serverRun(server); } From a22bce5a46074cc35c4397738ab261eba25a6dc0 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 12 Aug 2013 16:46:02 +0100 Subject: [PATCH 07/97] add test-driver to git ignores --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b964f61..e6bf2fd 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ stamp-h1 src/taskrambler /tests/*Test gmon.out +test-driver From b2d221c4c4121d7b9a544e8fe22885762cef7cfc Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 09:48:43 +0100 Subject: [PATCH 08/97] added comment about idea of Quick Fit memory management system to improve performance --- src/utils/memory.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/utils/memory.c b/src/utils/memory.c index 8784759..579d5a2 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -1,5 +1,26 @@ /** - * \file + * \file This holds all stufff related our memory managent. + * I try the best as far as I can to reduce memory fragmentation + * and unneccessary calls to alloc and free. + * + * To achive this I try an approach described here as "Quick Fit". + * http://www.flounder.com/memory_allocation.htm + * + * The basic idea is to keep allocated memory segments and don't free + * them again. Instead I will put them in a tree indexed by their size. + * To get new memory I first have a look in the tree if there is + * a fitting memory segment. Fitting mean, larger or exactly the size + * I need. If there is one, use it. If not create a new one using + * usual malloc approach. + * I won't split the reagions at all because most likely they will be + * free soon again. This way I might waste some memory, so I have to + * keep an eye on this. + * + * Right now I don't build an upper limit for allocation. The limit + * still is the system memory itself. + * + * This is not implemented as a class because it will be used in the + * process of object creation. * * \author Georg Hopp * From 5156df0ef44c7bb0ce88e35a257f487b48ba8929 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 10:52:23 +0100 Subject: [PATCH 09/97] started implementing the Quick Fit memory management --- src/utils/memory.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/utils/memory.c b/src/utils/memory.c index 579d5a2..ba1b293 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -42,9 +42,85 @@ */ #include +#include #include "utils/memory.h" +struct memSegment { + size_t size; + void * ptr; +} + +void ** segments = NULL; + +/** + * this will interpret any memory segment that is not smaller + * than the expected size as fitting. + * + * @param void * size_ptr a pointer to a size_t value searched for + * @param void * subject a pointer to the currently analysed tree element + */ +static +int +segmentFindCmp(const void * size_ptr, const void * subject) +{ + if (*size_ptr < subject->size) + return -1; + + return 0; +} + +/** + * this returns exact fits....uhh.....I can't relate solely on + * the size argument as then same sized segments will never + * be stored. + * Maybe a tree is not the best data structure to use to store + * these. + * Anyway, right now take the ptr into account if size if equal. + */ +static +int +segmentSearchCmd(const void * search, const void * subject) +{ + size_t idx = search->size - subject->size; + + if (0 == idx) { + return search->ptr - subject->ptr; + } + + return idx; +} + +/** + * we do NOT ensure that the memory region is zeroed + * because we want the best performance. + * Most times this is not neccessary at all. + */ +struct memSegment * +memCalloc(size_t nmemb, size_t size) +{ + return memMalloc(nmemb * size); +} + + +struct memSegment * +memMalloc(size_t size) +{ + struct memSegment * seg = tfind(&size, segments, segmentFindCmp); + + if (NULL == seg) { + seg = (struct memSegment *)malloc(sizeof(struct memSegment) + size); + + seg->size = size; + seg->ptr = seg + sizeof(struct memSegment); + } else { + // remove the found one from the tree. + tdelete((void *)seg, segments, segmentSearchCmp); + } + + return seg; +} + void ffree(void ** data) { From 1563d3e87f95d3900a43965c0da9df9e81f76edb Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 10:53:34 +0100 Subject: [PATCH 10/97] added idea comment for a cbuf pool to not always reinitialize these all the time... --- include/cbufpool.h | 10 ++++++++++ src/cbufpool.c | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 include/cbufpool.h create mode 100644 src/cbufpool.c diff --git a/include/cbufpool.h b/include/cbufpool.h new file mode 100644 index 0000000..71d8576 --- /dev/null +++ b/include/cbufpool.h @@ -0,0 +1,10 @@ +/** + * As the initializations of cbufs is complicated and time consuming + * with all this shared memory initialization stuff and each cbuf + * always is the same (at least for this application) we don't free + * them after they are not used anymore. + * Instead we store the in this pool and reuse then the next time + * they are needed. + * + * Well thats the idea of this. + */ diff --git a/src/cbufpool.c b/src/cbufpool.c new file mode 100644 index 0000000..71d8576 --- /dev/null +++ b/src/cbufpool.c @@ -0,0 +1,10 @@ +/** + * As the initializations of cbufs is complicated and time consuming + * with all this shared memory initialization stuff and each cbuf + * always is the same (at least for this application) we don't free + * them after they are not used anymore. + * Instead we store the in this pool and reuse then the next time + * they are needed. + * + * Well thats the idea of this. + */ From f2565a9b770ccba454ed521b59a3695711397b72 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 11:52:57 +0100 Subject: [PATCH 11/97] fix the new functions so that they compile at least. --- src/utils/memory.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/utils/memory.c b/src/utils/memory.c index ba1b293..8cbe439 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -49,7 +49,7 @@ struct memSegment { size_t size; void * ptr; -} +}; void ** segments = NULL; @@ -64,7 +64,7 @@ static int segmentFindCmp(const void * size_ptr, const void * subject) { - if (*size_ptr < subject->size) + if (*(size_t *)size_ptr < ((struct memSegment *)subject)->size) return -1; return 0; @@ -80,28 +80,21 @@ segmentFindCmp(const void * size_ptr, const void * subject) */ static int -segmentSearchCmd(const void * search, const void * subject) +segmentSearchCmp(const void * search, const void * subject) { - size_t idx = search->size - subject->size; + size_t idx = + ((struct memSegment *)search)->size - + ((struct memSegment *)subject)->size; if (0 == idx) { - return search->ptr - subject->ptr; + return + ((struct memSegment *)search)->ptr - + ((struct memSegment *)subject)->ptr; } return idx; } -/** - * we do NOT ensure that the memory region is zeroed - * because we want the best performance. - * Most times this is not neccessary at all. - */ -struct memSegment * -memCalloc(size_t nmemb, size_t size) -{ - return memMalloc(nmemb * size); -} - struct memSegment * memMalloc(size_t size) @@ -121,6 +114,18 @@ memMalloc(size_t size) return seg; } +/** + * we do NOT ensure that the memory region is zeroed + * because we want the best performance. + * Most times this is not neccessary at all. + */ +struct memSegment * +memCalloc(size_t nmemb, size_t size) +{ + return memMalloc(nmemb * size); +} + + void ffree(void ** data) { From ccc6f9307ebf39f98e202480356d97e99ae1371f Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 11:53:55 +0100 Subject: [PATCH 12/97] more comments regarding cbuf pools. --- include/cbufpool.h | 13 +++++++++++++ include/http/writer.h | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/cbufpool.h b/include/cbufpool.h index 71d8576..a1b911f 100644 --- a/include/cbufpool.h +++ b/include/cbufpool.h @@ -7,4 +7,17 @@ * they are needed. * * Well thats the idea of this. + * + * OK, after review the code...it has been some time since I wrote it, + * I realize that only one cbuf is used right now. + * Each connection holds their unprocessed data in another heap reagion + * and reinitializes the ringbuffer each time with this. + * + * This seems both inefficient and error prone. So I will change this. + * The only question is, how large should our circular buffer be and + * how many connections do we expect in paralell... + * + * We need to have some handling to not accept any more connection + * when we reached the maximum amount for cbuffers and none is left in + * the pool. */ diff --git a/include/http/writer.h b/include/http/writer.h index 78d5a4c..25f641f 100644 --- a/include/http/writer.h +++ b/include/http/writer.h @@ -35,6 +35,29 @@ #include "commons.h" +/* + * the buffer that will be written back to an http client. + * If we have open 1024 paralell connection this will result + * in a memory usage of 128MB. Right now, we don't allow more + * than this amount of paralell connections. + * + * This one and the parser buffer are the hugest memory pools + * we need. The parser buffer is of the same size. + * + * Right now only the ringbuffer is reused for each connection + * resulting in some memory movement between some temporary + * space and the circular buffer. + * + * This behavioru should be kept in place for low memory machines + * running this code. + * + * Anyway, I will build a version which uses two ringbuffers for + * each connection, Resulting in a 256KB memory used for each + * connection. Which in turn means 256MB for 1024 paralell connections. + * + * And as I will also implement a cbuf pool, this memory will not be + * freed before application end. + */ #define WRITER_MAX_BUF 131072 @@ -45,15 +68,15 @@ typedef enum e_HttpWriterState { } HttpWriterState; CLASS(HttpWriter) { - Cbuf buffer; - Bool ourLock; + Cbuf buffer; + Bool ourLock; - Queue queue; - HttpMessage current; + Queue queue; + HttpMessage current; - size_t nheader; - size_t nbody; - size_t written; + size_t nheader; + size_t nbody; + size_t written; HttpWriterState state; }; From 34ff5a42bf914c29183a7675763bd1737bb213e6 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 13:15:17 +0100 Subject: [PATCH 13/97] now ignore log tsr files under tests --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e6bf2fd..d675cd1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,8 @@ coveragereport/ stamp-h1 src/taskrambler /tests/*Test +/tests/*.log +/tests/*.trs gmon.out test-driver + From add2a199044c99472b361771e26ea62a19e4381b Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 13:17:59 +0100 Subject: [PATCH 14/97] first version of Quick Fit memory management --- include/utils/memory.h | 13 ++++++++++++- src/utils/memory.c | 35 +++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/include/utils/memory.h b/include/utils/memory.h index 2e9b65a..1cc1dcd 100644 --- a/include/utils/memory.h +++ b/include/utils/memory.h @@ -25,7 +25,18 @@ #define CSTRA(val) val, sizeof(val)-1 //!< Const STRing Argument -#define FREE(val) (ffree((void**)&(val))) +#define FREE(val) (ffree((void**)&(val))) +#define MEM_FREE(seg) (memFree((struct memSegment **)&(seg))) + +struct memSegment { + size_t size; + void * ptr; +}; + +struct memSegment * memMalloc(size_t); +struct memSegment * memCalloc(size_t, size_t); +void memFree(struct memSegment **); +void memCleanup(); void ffree(void **); diff --git a/src/utils/memory.c b/src/utils/memory.c index 8cbe439..dda9651 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -42,16 +42,13 @@ */ #include +#define _GNU_SOURCE #include #include "utils/memory.h" -struct memSegment { - size_t size; - void * ptr; -}; -void ** segments = NULL; +void * segments = NULL; /** * this will interpret any memory segment that is not smaller @@ -95,11 +92,18 @@ segmentSearchCmp(const void * search, const void * subject) return idx; } +static +void +segmentFree(void * segment) +{ + free(segment); +} + struct memSegment * memMalloc(size_t size) { - struct memSegment * seg = tfind(&size, segments, segmentFindCmp); + struct memSegment * seg = tfind(&size, &segments, segmentFindCmp); if (NULL == seg) { seg = (struct memSegment *)malloc(sizeof(struct memSegment) + size); @@ -107,8 +111,9 @@ memMalloc(size_t size) seg->size = size; seg->ptr = seg + sizeof(struct memSegment); } else { - // remove the found one from the tree. - tdelete((void *)seg, segments, segmentSearchCmp); + // remove the found one from the tree as we use it now. + tdelete((void *)seg, &segments, segmentSearchCmp); + seg = *(struct memSegment **)seg; } return seg; @@ -125,6 +130,20 @@ memCalloc(size_t nmemb, size_t size) return memMalloc(nmemb * size); } +void +memFree(struct memSegment ** seg) +{ + if (NULL != *seg) { + tsearch((void *)*seg, &segments, segmentSearchCmp); + *seg = NULL; + } +} + +void +memCleanup() +{ + tdestroy(segments, segmentFree); +} void ffree(void ** data) From b9f88cf05c5634f5fada40acc476225c88a845f0 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 13:19:31 +0100 Subject: [PATCH 15/97] to test it use Best Fit memory management in logger. --- src/logger/interface/i_logger.c | 18 ++++++++++-------- tests/Makefile.am | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/logger/interface/i_logger.c b/src/logger/interface/i_logger.c index 1ab7c2d..188ec78 100644 --- a/src/logger/interface/i_logger.c +++ b/src/logger/interface/i_logger.c @@ -27,6 +27,8 @@ #include "logger/logger.h" #include "logger/interface/logger.h" +#include "utils/memory.h" + const struct interface i_Logger = { "logger", 1 @@ -37,23 +39,23 @@ loggerLog(void * _object, logger_level level, const char * const fmt, ...) { Logger object = _object; if (level >= object->min_level) { - char * msg = NULL; - size_t msg_size = 0; - va_list params; + struct memSegment * msg = NULL; + size_t msg_size = 0; + va_list params; va_start(params, fmt); - msg_size = vsnprintf(msg, msg_size, fmt, params); + msg_size = vsnprintf(NULL, msg_size, fmt, params); va_end(params); - msg = malloc(msg_size + 1); + msg = memMalloc(msg_size + 1); va_start(params, fmt); - vsnprintf(msg, msg_size + 1, fmt, params); + vsnprintf(msg->ptr, msg_size + 1, fmt, params); va_end(params); - CALL(_object, Logger, log, level, msg); + CALL(_object, Logger, log, level, msg->ptr); - free(msg); + MEM_FREE(msg); } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 7f4a3e3..5902f03 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,6 +15,7 @@ LOGGER = $(CLASS) \ ../src/logger/stderr.c \ ../src/logger/syslog.c \ ../src/logger/interface/i_logger.c \ + ../src/utils/memory.c \ mock/mock_logger.c SOCKET = $(LOGGER) \ @@ -38,7 +39,6 @@ SERVER = $(SOCKET) \ ../src/server/read.c \ ../src/server/write.c \ ../src/utils/signalHandling.c \ - ../src/utils/memory.c \ mock/mock_worker.c classTest_SOURCES = $(CLASS) classTest.c @@ -55,7 +55,7 @@ socketTest_LDFLAGS = -lgcov -pg serverTest_SOURCES = $(SERVER) serverTest.c serverTest_CFLAGS = -Wall -ggdb -O0 -fprofile-arcs -ftest-coverage -pg -I ../include -I .. -I . -serverTest_LDFLAGS = $(STREAM_OBJ) -lgcov -pg +serverTest_LDFLAGS = $(STREAM_OBJ) -lgcov -lcrypto -pg EXTRA_DIST = runtest.h mock/mock_class.h mock/mock_logger.h From 53baa544708663cac1de4c6dd2c9fd6764b84518 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 14:00:43 +0100 Subject: [PATCH 16/97] add quick fit to cbuf --- include/cbuf.h | 2 ++ src/cbuf/cbuf.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/cbuf.h b/include/cbuf.h index dd2de94..12f1da8 100644 --- a/include/cbuf.h +++ b/include/cbuf.h @@ -38,11 +38,13 @@ #include "stream.h" #include "commons.h" +#include "utils/memory.h" #define ECBUFOVFL 100 CLASS(Cbuf) { + struct memSegment * shm_name_seg; char * shm_name; // shared memory identifier char * data; diff --git a/src/cbuf/cbuf.c b/src/cbuf/cbuf.c index 0ee216d..dfed914 100644 --- a/src/cbuf/cbuf.c +++ b/src/cbuf/cbuf.c @@ -53,7 +53,8 @@ cbufCtor(void * _this, va_list * params) int shm; char * data; - this->shm_name = malloc(strlen(shm_name) + 7 + 2); + this->shm_name_seg = memMalloc(strlen(shm_name) + 7 + 2); + this->shm_name = this->shm_name_seg->ptr; sprintf(this->shm_name, "/%06d_%s", getpid(), shm_name); /** @@ -110,7 +111,7 @@ cbufDtor(void * _this) { Cbuf this = _this; - FREE(this->shm_name); + MEM_FREE(this->shm_name_seg); if (NULL != this->data && MAP_FAILED != this->data) { munmap(this->data, this->bsize << 1); From f1f3e146805c167f3757e3633bbceb0829b06715 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 14:01:27 +0100 Subject: [PATCH 17/97] change port for tests --- tests/serverTest.c | 2 +- tests/socketTest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/serverTest.c b/tests/serverTest.c index 83bbd29..81350d2 100644 --- a/tests/serverTest.c +++ b/tests/serverTest.c @@ -14,7 +14,7 @@ #include "mock/mock_worker.h" -#define TEST_PORT 11212 +#define TEST_PORT 11222 #define TEST_DATA "test" diff --git a/tests/socketTest.c b/tests/socketTest.c index 48797f5..f1c6d56 100644 --- a/tests/socketTest.c +++ b/tests/socketTest.c @@ -9,7 +9,7 @@ #include "mock/mock_logger.h" -#define TEST_PORT 11212 +#define TEST_PORT 11222 const char testname[] = "socketTest"; From 8934e864d74f15909debc97cd42c7a5a6811cee4 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 14:36:03 +0100 Subject: [PATCH 18/97] simplified the quick fit interface --- include/cbuf.h | 1 - include/utils/memory.h | 14 +++++------- src/cbuf/cbuf.c | 5 ++--- src/logger/interface/i_logger.c | 10 ++++----- src/utils/memory.c | 39 ++++++++++++++++++++++++++------- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/include/cbuf.h b/include/cbuf.h index 12f1da8..dd3fd87 100644 --- a/include/cbuf.h +++ b/include/cbuf.h @@ -44,7 +44,6 @@ CLASS(Cbuf) { - struct memSegment * shm_name_seg; char * shm_name; // shared memory identifier char * data; diff --git a/include/utils/memory.h b/include/utils/memory.h index 1cc1dcd..6d886e5 100644 --- a/include/utils/memory.h +++ b/include/utils/memory.h @@ -26,17 +26,13 @@ #define CSTRA(val) val, sizeof(val)-1 //!< Const STRing Argument #define FREE(val) (ffree((void**)&(val))) -#define MEM_FREE(seg) (memFree((struct memSegment **)&(seg))) +#define MEM_FREE(seg) (memFree((void **)&(seg))) -struct memSegment { - size_t size; - void * ptr; -}; -struct memSegment * memMalloc(size_t); -struct memSegment * memCalloc(size_t, size_t); -void memFree(struct memSegment **); -void memCleanup(); +void * memMalloc(size_t); +void * memCalloc(size_t, size_t); +void memFree(void **); +void memCleanup(); void ffree(void **); diff --git a/src/cbuf/cbuf.c b/src/cbuf/cbuf.c index dfed914..a2b6e1c 100644 --- a/src/cbuf/cbuf.c +++ b/src/cbuf/cbuf.c @@ -53,8 +53,7 @@ cbufCtor(void * _this, va_list * params) int shm; char * data; - this->shm_name_seg = memMalloc(strlen(shm_name) + 7 + 2); - this->shm_name = this->shm_name_seg->ptr; + this->shm_name = memMalloc(strlen(shm_name) + 7 + 2); sprintf(this->shm_name, "/%06d_%s", getpid(), shm_name); /** @@ -111,7 +110,7 @@ cbufDtor(void * _this) { Cbuf this = _this; - MEM_FREE(this->shm_name_seg); + MEM_FREE(this->shm_name); if (NULL != this->data && MAP_FAILED != this->data) { munmap(this->data, this->bsize << 1); diff --git a/src/logger/interface/i_logger.c b/src/logger/interface/i_logger.c index 188ec78..e1019bc 100644 --- a/src/logger/interface/i_logger.c +++ b/src/logger/interface/i_logger.c @@ -39,9 +39,9 @@ loggerLog(void * _object, logger_level level, const char * const fmt, ...) { Logger object = _object; if (level >= object->min_level) { - struct memSegment * msg = NULL; - size_t msg_size = 0; - va_list params; + char * msg = NULL; + size_t msg_size = 0; + va_list params; va_start(params, fmt); msg_size = vsnprintf(NULL, msg_size, fmt, params); @@ -50,10 +50,10 @@ loggerLog(void * _object, logger_level level, const char * const fmt, ...) { msg = memMalloc(msg_size + 1); va_start(params, fmt); - vsnprintf(msg->ptr, msg_size + 1, fmt, params); + vsnprintf(msg, msg_size + 1, fmt, params); va_end(params); - CALL(_object, Logger, log, level, msg->ptr); + CALL(_object, Logger, log, level, msg); MEM_FREE(msg); } diff --git a/src/utils/memory.c b/src/utils/memory.c index dda9651..a110461 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -47,6 +47,11 @@ #include "utils/memory.h" +struct memSegment { + size_t size; + void * ptr; +}; + void * segments = NULL; @@ -100,7 +105,7 @@ segmentFree(void * segment) } -struct memSegment * +void * memMalloc(size_t size) { struct memSegment * seg = tfind(&size, &segments, segmentFindCmp); @@ -116,7 +121,7 @@ memMalloc(size_t size) seg = *(struct memSegment **)seg; } - return seg; + return seg->ptr; } /** @@ -124,18 +129,36 @@ memMalloc(size_t size) * because we want the best performance. * Most times this is not neccessary at all. */ -struct memSegment * +void * memCalloc(size_t nmemb, size_t size) { - return memMalloc(nmemb * size); + size_t _size = nmemb * size; + size_t _inmemb = (sizeof(struct memSegment) / size) + 1; + struct memSegment * seg = tfind(&_size, &segments, segmentFindCmp); + + if (NULL == seg) { + seg = (struct memSegment *)calloc(nmemb + _inmemb, size); + seg->size = size; + seg->ptr = seg + sizeof(struct memSegment); + } else { + // remove the found one from the tree as we use it now. + tdelete((void *)seg, &segments, segmentSearchCmp); + seg = *(struct memSegment **)seg; + } + + return seg->ptr; } void -memFree(struct memSegment ** seg) +memFree(void ** mem) { - if (NULL != *seg) { - tsearch((void *)*seg, &segments, segmentSearchCmp); - *seg = NULL; + if (NULL != *mem) { + struct memSegment * seg = *(struct memSegment **)mem; + + seg -= sizeof(struct memSegment); + + tsearch((void *)seg, &segments, segmentSearchCmp); + *mem = NULL; } } From fc40342711fa6e1a0444669b388d78a9cba12c21 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 17:02:45 +0100 Subject: [PATCH 19/97] added new memory management to the most fragile part in this matter...the class system...well, the server test gives me a memory corruption, but all other are running now....anyway most likely this is in an unusable state right now. --- src/class/interface/i_class.c | 12 ++++++--- src/logger/interface/i_logger.c | 19 +++++++++++++- src/utils/memory.c | 46 +++++++++++++++------------------ tests/Makefile.am | 2 +- 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/class/interface/i_class.c b/src/class/interface/i_class.c index 0113902..196363d 100644 --- a/src/class/interface/i_class.c +++ b/src/class/interface/i_class.c @@ -27,6 +27,9 @@ #include "class/class.h" #include "class/interface/class.h" +#include "utils/memory.h" + + const struct interface i_Class = { "class", @@ -36,7 +39,7 @@ struct interface i_Class = { void * classNew(class_ptr class, ...) { - void * object = calloc(1, class->object_size + sizeof(void*)); + void * object = memCalloc(1, class->object_size + sizeof(void*)); va_list params; int ret; @@ -58,9 +61,12 @@ void classDelete(void ** object) { if (NULL != *object) { + void * mem; + CALL(*object, Class, dtor); - free(*object - sizeof(void*)); + mem = *object - sizeof(void*); + MEM_FREE(mem); *object = NULL; } } @@ -69,7 +75,7 @@ void * classClone(void * _object) { class_ptr class = GET_CLASS(_object); - void * object = calloc(1, class->object_size + sizeof(void*)); + void * object = memCalloc(1, class->object_size + sizeof(void*)); * (class_ptr *)object = class; object += sizeof(void*); diff --git a/src/logger/interface/i_logger.c b/src/logger/interface/i_logger.c index e1019bc..b1f6158 100644 --- a/src/logger/interface/i_logger.c +++ b/src/logger/interface/i_logger.c @@ -53,7 +53,24 @@ loggerLog(void * _object, logger_level level, const char * const fmt, ...) { vsnprintf(msg, msg_size + 1, fmt, params); va_end(params); - CALL(_object, Logger, log, level, msg); + // ----- DEBUG ------ + do { + struct i_Logger * iface; + + do { + class_ptr class = GET_CLASS(_object); + iface = (struct i_Logger *)IFACE_GET(class, &i_Logger); + while ((NULL == iface || NULL == iface->log) && HAS_PARENT(class)) { + class = class->parent; + iface = (struct i_Logger *)IFACE_GET(class, &i_Logger); + } + assert(NULL != iface->log); + } while(0); + + iface->log(_object, level, msg); + } while(0); + // ----- DEBUG ------ + //CALL(_object, Logger, log, level, msg); MEM_FREE(msg); } diff --git a/src/utils/memory.c b/src/utils/memory.c index a110461..64f34f4 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -42,6 +42,7 @@ */ #include +#include #define _GNU_SOURCE #include @@ -108,56 +109,51 @@ segmentFree(void * segment) void * memMalloc(size_t size) { - struct memSegment * seg = tfind(&size, &segments, segmentFindCmp); + struct memSegment ** seg_ptr = tfind(&size, &segments, segmentFindCmp); + struct memSegment * seg; - if (NULL == seg) { + if (NULL == seg_ptr) { seg = (struct memSegment *)malloc(sizeof(struct memSegment) + size); seg->size = size; - seg->ptr = seg + sizeof(struct memSegment); + seg->ptr = (void *)seg + sizeof(struct memSegment); } else { + seg = *seg_ptr; // remove the found one from the tree as we use it now. tdelete((void *)seg, &segments, segmentSearchCmp); - seg = *(struct memSegment **)seg; } return seg->ptr; } /** - * we do NOT ensure that the memory region is zeroed - * because we want the best performance. - * Most times this is not neccessary at all. + * this is a really memory wasting solution....just to be able to + * use calloc, which might be faster then malloc/memset solution. + * + * Maybe this is a bad idea, as we need to memset the buffer anyway + * if it comes from our tree, which hopefully should be the majority + * of cases. */ void * memCalloc(size_t nmemb, size_t size) { - size_t _size = nmemb * size; - size_t _inmemb = (sizeof(struct memSegment) / size) + 1; - struct memSegment * seg = tfind(&_size, &segments, segmentFindCmp); + size_t _size = nmemb * size; + void * mem = memMalloc(_size); + struct memSegment * seg = + (struct memSegment *)(mem - sizeof(struct memSegment)); - if (NULL == seg) { - seg = (struct memSegment *)calloc(nmemb + _inmemb, size); - seg->size = size; - seg->ptr = seg + sizeof(struct memSegment); - } else { - // remove the found one from the tree as we use it now. - tdelete((void *)seg, &segments, segmentSearchCmp); - seg = *(struct memSegment **)seg; - } + printf("DEBUG %zu : %zu\n", _size, seg->size); - return seg->ptr; + memset(mem, 0, _size); + + return mem; } void memFree(void ** mem) { if (NULL != *mem) { - struct memSegment * seg = *(struct memSegment **)mem; - - seg -= sizeof(struct memSegment); - - tsearch((void *)seg, &segments, segmentSearchCmp); + void * foo = tsearch(*mem - sizeof(struct memSegment), &segments, segmentSearchCmp); *mem = NULL; } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 5902f03..18d5cca 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,7 @@ COMMON = runtest.c CLASS = $(COMMON) \ ../src/class/interface.c \ ../src/class/interface/i_class.c \ + ../src/utils/memory.c \ mock/mock_class.c LOGGER = $(CLASS) \ @@ -15,7 +16,6 @@ LOGGER = $(CLASS) \ ../src/logger/stderr.c \ ../src/logger/syslog.c \ ../src/logger/interface/i_logger.c \ - ../src/utils/memory.c \ mock/mock_logger.c SOCKET = $(LOGGER) \ From b44ec9f22b0e7d227377d6d263c3320174f03fab Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 20:25:57 +0100 Subject: [PATCH 20/97] fix the last issues with using quick fit with the class interface. --- src/logger/interface/i_logger.c | 36 ++++++++++++++++----------------- src/utils/memory.c | 13 +++++------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/logger/interface/i_logger.c b/src/logger/interface/i_logger.c index b1f6158..0f9045f 100644 --- a/src/logger/interface/i_logger.c +++ b/src/logger/interface/i_logger.c @@ -53,24 +53,24 @@ loggerLog(void * _object, logger_level level, const char * const fmt, ...) { vsnprintf(msg, msg_size + 1, fmt, params); va_end(params); - // ----- DEBUG ------ - do { - struct i_Logger * iface; - - do { - class_ptr class = GET_CLASS(_object); - iface = (struct i_Logger *)IFACE_GET(class, &i_Logger); - while ((NULL == iface || NULL == iface->log) && HAS_PARENT(class)) { - class = class->parent; - iface = (struct i_Logger *)IFACE_GET(class, &i_Logger); - } - assert(NULL != iface->log); - } while(0); - - iface->log(_object, level, msg); - } while(0); - // ----- DEBUG ------ - //CALL(_object, Logger, log, level, msg); +// // ----- DEBUG ------ +// do { +// struct i_Logger * iface; +// +// do { +// class_ptr class = GET_CLASS(_object); +// iface = (struct i_Logger *)IFACE_GET(class, &i_Logger); +// while ((NULL == iface || NULL == iface->log) && HAS_PARENT(class)) { +// class = class->parent; +// iface = (struct i_Logger *)IFACE_GET(class, &i_Logger); +// } +// assert(NULL != iface->log); +// } while(0); +// +// iface->log(_object, level, msg); +// } while(0); +// // ----- DEBUG ------ + CALL(_object, Logger, log, level, msg); MEM_FREE(msg); } diff --git a/src/utils/memory.c b/src/utils/memory.c index 64f34f4..3df1962 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -41,9 +41,10 @@ * along with this program. If not, see . */ +#define _GNU_SOURCE + #include #include -#define _GNU_SOURCE #include #include "utils/memory.h" @@ -67,8 +68,8 @@ static int segmentFindCmp(const void * size_ptr, const void * subject) { - if (*(size_t *)size_ptr < ((struct memSegment *)subject)->size) - return -1; + if (*(size_t *)size_ptr > ((struct memSegment *)subject)->size) + return 1; return 0; } @@ -139,10 +140,6 @@ memCalloc(size_t nmemb, size_t size) { size_t _size = nmemb * size; void * mem = memMalloc(_size); - struct memSegment * seg = - (struct memSegment *)(mem - sizeof(struct memSegment)); - - printf("DEBUG %zu : %zu\n", _size, seg->size); memset(mem, 0, _size); @@ -153,7 +150,7 @@ void memFree(void ** mem) { if (NULL != *mem) { - void * foo = tsearch(*mem - sizeof(struct memSegment), &segments, segmentSearchCmp); + tsearch(*mem - sizeof(struct memSegment), &segments, segmentSearchCmp); *mem = NULL; } } From c54dc20cc42737306bd670704416e7c72da27e0e Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 20:44:56 +0100 Subject: [PATCH 21/97] use quick fit approach in message --- src/http/message.c | 6 +++--- src/http/parser/p_header.c | 4 +++- src/http/response/404.c | 2 +- src/http/response/login_form.c | 2 +- src/http/response/randval.c | 2 +- src/http/response/session.c | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/http/message.c b/src/http/message.c index 5786b76..2ee7db4 100644 --- a/src/http/message.c +++ b/src/http/message.c @@ -43,7 +43,7 @@ httpMessageCtor(void * _this, va_list * params) HttpMessage this = _this; char * version = va_arg(* params, char *); - this->version = calloc(1, strlen(version)+1); + this->version = memCalloc(1, strlen(version)+1); strcpy(this->version, version); this->header = new(Hash); @@ -59,11 +59,11 @@ httpMessageDtor(void * _this) delete(this->header); - FREE(this->version); + MEM_FREE(this->version); switch (this->type) { case HTTP_MESSAGE_BUFFERED: - FREE(this->body); + MEM_FREE(this->body); break; case HTTP_MESSAGE_PIPED: diff --git a/src/http/parser/p_header.c b/src/http/parser/p_header.c index 8fce76c..abc8c51 100644 --- a/src/http/parser/p_header.c +++ b/src/http/parser/p_header.c @@ -31,6 +31,8 @@ #include "http/request.h" #include "hash.h" +#include "utils/memory.h" + void httpParserHeader( HttpParser this, @@ -55,7 +57,7 @@ httpParserHeader( if (0 == strncasecmp("content-length", name, nname-1)) { current->nbody = strtoul(value, NULL, 10); if (0 < this->current->nbody) { - current->body = malloc(current->nbody); + current->body = memMalloc(current->nbody); } current->dbody = 0; } diff --git a/src/http/response/404.c b/src/http/response/404.c index 1947de1..cab83ad 100644 --- a/src/http/response/404.c +++ b/src/http/response/404.c @@ -57,7 +57,7 @@ httpResponse404() message->type = HTTP_MESSAGE_BUFFERED; message->nbody = sizeof(RESP_DATA) - 1; - message->body = malloc(sizeof(RESP_DATA)); + message->body = memMalloc(sizeof(RESP_DATA)); memcpy(message->body, RESP_DATA, sizeof(RESP_DATA)); return response; diff --git a/src/http/response/login_form.c b/src/http/response/login_form.c index f01063d..e136e28 100644 --- a/src/http/response/login_form.c +++ b/src/http/response/login_form.c @@ -55,7 +55,7 @@ httpResponseLoginForm() message->type = HTTP_MESSAGE_BUFFERED; message->nbody = sizeof(RESP_DATA)-1; - message->body = malloc(message->nbody); + message->body = memMalloc(message->nbody); memcpy(message->body, RESP_DATA, message->nbody); return response; diff --git a/src/http/response/randval.c b/src/http/response/randval.c index b98449e..39fff37 100644 --- a/src/http/response/randval.c +++ b/src/http/response/randval.c @@ -59,7 +59,7 @@ httpResponseRandval(time_t ctime, int value) nbuf = sprintf(buffer, RESP_DATA, ctime, remaining, value); message->nbody = nbuf; - message->body = malloc(nbuf); + message->body = memMalloc(nbuf); memcpy(message->body, buffer, nbuf); return response; diff --git a/src/http/response/session.c b/src/http/response/session.c index 396b6a6..4d2941e 100644 --- a/src/http/response/session.c +++ b/src/http/response/session.c @@ -61,7 +61,7 @@ httpResponseSession(Session session) (NULL != session)? session->username : ""); message->nbody = nbuf; - message->body = malloc(nbuf); + message->body = memMalloc(nbuf); memcpy(message->body, buffer, nbuf); return response; From 09f92847fbb6c80f323fd2849b640fad9c8c21ab Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 20:50:33 +0100 Subject: [PATCH 22/97] replace calloc in response.c with quick fit approach --- src/http/response.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/response.c b/src/http/response.c index db53354..9a14315 100644 --- a/src/http/response.c +++ b/src/http/response.c @@ -45,7 +45,7 @@ httpResponseCtor(void * _this, va_list * params) this->status = va_arg(* params, unsigned int); reason = va_arg(* params, char *); - this->reason = calloc(1, strlen(reason)+1); + this->reason = memCalloc(1, strlen(reason)+1); strcpy(this->reason, reason); return 0; @@ -57,7 +57,7 @@ httpResponseDtor(void * _this) { HttpResponse this = _this; - FREE(this->reason); + MEM_FREE(this->reason); PARENTCALL(_this, Class, dtor); } From b23ca703e81a30f6d1431422c5b93ec4d8754883 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 20:54:05 +0100 Subject: [PATCH 23/97] replace calloc in server.c with quick fit approach --- src/server/server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/server.c b/src/server/server.c index 8f76a3a..f58fe09 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -61,8 +61,8 @@ serverCtor(void * _this, va_list * params) port = va_arg(* params, int); backlog = va_arg(* params, unsigned int); - this->fds = calloc(sizeof(struct pollfd), this->max_fds); - this->conns = calloc(sizeof(struct conns), this->max_fds); + this->fds = memCalloc(sizeof(struct pollfd), this->max_fds); + this->conns = memCalloc(sizeof(struct conns), this->max_fds); this->sock = new(Sock, this->logger, port); flags = fcntl(this->sock->handle, F_GETFL, 0); @@ -111,8 +111,8 @@ serverDtor(void * _this) } } - FREE(this->fds); - FREE(this->conns); + MEM_FREE(this->fds); + MEM_FREE(this->conns); delete(this->sock); delete(this->sockSSL); From 672515ae85aeb9be03e0171992bfd05efa1d7c63 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 20:58:29 +0100 Subject: [PATCH 24/97] replace calloc in hash/value.c with quick fit approach --- src/hash/value.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hash/value.c b/src/hash/value.c index c32b760..77ffe1e 100644 --- a/src/hash/value.c +++ b/src/hash/value.c @@ -45,14 +45,14 @@ hashValueCtor(void * _this, va_list * params) value = va_arg(* params, void*); this->nvalue = va_arg(* params, size_t); - this->key = malloc(this->nkey + 1); + this->key = memMalloc(this->nkey + 1); this->key[this->nkey] = 0; memcpy(this->key, key, this->nkey); this->hash = sdbm((unsigned char *)this->key, this->nkey); if (NULL != value) { - this->value = malloc(this->nvalue + 1); + this->value = memMalloc(this->nvalue + 1); ((char*)this->value)[this->nvalue] = 0; memcpy(this->value, value, this->nvalue); } @@ -66,8 +66,8 @@ hashValueDtor(void * _this) { HashValue this = _this; - FREE(this->key); - FREE(this->value); + MEM_FREE(this->key); + MEM_FREE(this->value); } static From 4ee52d52765c1766f830a00fac8d6cc008e5300a Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:09:14 +0100 Subject: [PATCH 25/97] replace calloc in http/cookie.c with quick fit approach. It seems that domain and path are never set...have to check this (most likely its not implemented now --- src/http/cookie.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/http/cookie.c b/src/http/cookie.c index 8b0a50b..bc1a520 100644 --- a/src/http/cookie.c +++ b/src/http/cookie.c @@ -46,11 +46,11 @@ httpCookieCtor(void * _this, va_list * params) value = va_arg(* params, char*); this->nvalue = va_arg(* params, size_t); - this->key = malloc(this->nkey + 1); + this->key = memMalloc(this->nkey + 1); this->key[this->nkey] = 0; memcpy(this->key, key, this->nkey); - this->value = malloc(this->nvalue + 1); + this->value = memMalloc(this->nvalue + 1); this->value[this->nvalue] = 0; memcpy(this->value, value, this->nvalue); @@ -65,10 +65,10 @@ httpCookieDtor(void * _this, va_list * params) { HttpCookie this = _this; - FREE(this->key); - FREE(this->value); - FREE(this->domain); - FREE(this->path); + MEM_FREE(this->key); + MEM_FREE(this->value); + MEM_FREE(this->domain); + MEM_FREE(this->path); } static From d738398aab9d64f071c2bc13375451aa0682e1e2 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:17:10 +0100 Subject: [PATCH 26/97] replace calloc in http/cookie.c with quick fit approach. --- src/http/header.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/http/header.c b/src/http/header.c index 42ecfd9..103d024 100644 --- a/src/http/header.c +++ b/src/http/header.c @@ -43,13 +43,13 @@ httpHeaderCtor(void * _this, va_list * params) { value = va_arg(* params, char *); this->nvalue[0] = va_arg(* params, size_t); - this->name = malloc(this->nname + 1); + this->name = memMalloc(this->nname + 1); this->name[this->nname] = 0; memcpy(this->name, name, this->nname); this->hash = sdbm((unsigned char *)name, this->nname); - (this->value)[0] = malloc((this->nvalue)[0] + 1); + (this->value)[0] = memMalloc((this->nvalue)[0] + 1); (this->value)[0][(this->nvalue)[0]] = 0; memcpy((this->value)[0], value, (this->nvalue)[0]); this->cvalue = 1; @@ -65,10 +65,10 @@ httpHeaderDtor(void * _this) HttpHeader this = _this; size_t i; - FREE(this->name); + MEM_FREE(this->name); for (i=0; icvalue; i++) { - FREE(this->value[i]); + MEM_FREE(this->value[i]); } } From 4ccc4b28ed5839c024321d975a074f5f6f656f44 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:20:38 +0100 Subject: [PATCH 27/97] replace calloc auth/ldap.c with quick fit approach. --- src/auth/ldap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/auth/ldap.c b/src/auth/ldap.c index 3ac2cfd..38e95c5 100644 --- a/src/auth/ldap.c +++ b/src/auth/ldap.c @@ -42,7 +42,7 @@ authLdapCtor(void * _this, va_list * params) char * url = va_arg(*params, char*); char * base_dn; - this->url = malloc(strlen(url) + 1); + this->url = memMalloc(strlen(url) + 1); strcpy(this->url, url); this->version = 3; @@ -50,7 +50,7 @@ authLdapCtor(void * _this, va_list * params) base_dn = va_arg(* params, char *); this->nbase_dn = va_arg(* params, size_t); - this->base_dn = malloc(this->nbase_dn + 1); + this->base_dn = memMalloc(this->nbase_dn + 1); this->base_dn[this->nbase_dn] = 0; memcpy(this->base_dn, base_dn, this->nbase_dn); @@ -63,8 +63,8 @@ authLdapDtor(void * _this) { AuthLdap this = _this; - FREE(this->base_dn); - FREE(this->url); + MEM_FREE(this->base_dn); + MEM_FREE(this->url); } static From 62f9b52336ec281c3fbf0c9a736cb53e5104ae33 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:23:31 +0100 Subject: [PATCH 28/97] replace calloc auth/credentials.c with quick fit approach. --- src/auth/credential.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/auth/credential.c b/src/auth/credential.c index f5c3ef1..fb9c306 100644 --- a/src/auth/credential.c +++ b/src/auth/credential.c @@ -48,11 +48,11 @@ credentialCtor(void * _this, va_list * params) pass = va_arg(* params, char*); CRED_PWD(this).npass = va_arg(* params, size_t); - CRED_PWD(this).user = malloc(CRED_PWD(this).nuser + 1); + CRED_PWD(this).user = memMalloc(CRED_PWD(this).nuser + 1); CRED_PWD(this).user[CRED_PWD(this).nuser] = 0; memcpy(CRED_PWD(this).user, user, CRED_PWD(this).nuser); - CRED_PWD(this).pass = malloc(CRED_PWD(this).npass + 1); + CRED_PWD(this).pass = memMalloc(CRED_PWD(this).npass + 1); CRED_PWD(this).pass[CRED_PWD(this).npass] = 0; memcpy(CRED_PWD(this).pass, pass, CRED_PWD(this).npass); } @@ -73,8 +73,8 @@ credentialDtor(void * _this) switch(this->type) { case CRED_PASSWORD: - FREE(CRED_PWD(this).user); - FREE(CRED_PWD(this).pass); + MEM_FREE(CRED_PWD(this).user); + MEM_FREE(CRED_PWD(this).pass); break; } } From 7fe5c487434b04e1cf3f4984fd27347912c61b75 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:29:05 +0100 Subject: [PATCH 29/97] replace calloc http/request.c with quick fit approach. --- src/http/parser/p_request_vars.c | 4 +++- src/http/request.c | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/http/parser/p_request_vars.c b/src/http/parser/p_request_vars.c index fbcf192..464c3a2 100644 --- a/src/http/parser/p_request_vars.c +++ b/src/http/parser/p_request_vars.c @@ -29,6 +29,8 @@ #include "hash.h" #include "class.h" +#include "utils/memory.h" + void httpParserRequestVars(HttpParser this) { @@ -39,7 +41,7 @@ httpParserRequestVars(HttpParser this) delim = request->uri + strlen(request->uri); } - request->path = malloc(delim - request->uri + 1); + request->path = memMalloc(delim - request->uri + 1); request->path[delim - request->uri] = 0; memcpy(request->path, request->uri, delim - request->uri); diff --git a/src/http/request.c b/src/http/request.c index b380301..3054632 100644 --- a/src/http/request.c +++ b/src/http/request.c @@ -48,11 +48,11 @@ httpRequestCtor(void * _this, va_list * params) PARENTCALL(_this, Class, ctor, params); - this->method = malloc(mlen + 1); + this->method = memMalloc(mlen + 1); this->method[mlen] = 0; memcpy(this->method, method, mlen); - this->uri = malloc(ulen + 1); + this->uri = memMalloc(ulen + 1); this->uri[ulen] = 0; memcpy(this->uri, uri, ulen); @@ -73,9 +73,9 @@ httpRequestDtor(void * _this) delete(this->post); delete(this->cookies); - FREE(this->uri); - FREE(this->method); - FREE(this->path); + MEM_FREE(this->uri); + MEM_FREE(this->method); + MEM_FREE(this->path); PARENTCALL(_this, Class, dtor); } From 196e51d294efa984605b575508e681d7c8cd998b Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:31:43 +0100 Subject: [PATCH 30/97] replace calloc http/parser.c with quick fit approach. --- src/http/parser/parse.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/http/parser/parse.c b/src/http/parser/parse.c index ad12b67..b9e7082 100644 --- a/src/http/parser/parse.c +++ b/src/http/parser/parse.c @@ -57,8 +57,7 @@ httpParserParse(void * _this, Stream st) if (NULL != this->incomplete) { cbufSetData(this->buffer, this->incomplete, this->isize); - free(this->incomplete); - this->incomplete = NULL; + MEM_FREE(this->incomplete); } if (0 > (read = cbufRead(this->buffer, st))) { @@ -84,7 +83,7 @@ httpParserParse(void * _this, Stream st) if (NULL == (line = cbufGetLine(this->buffer, &line_end))) { if (! cbufIsEmpty(this->buffer)) { this->isize = this->buffer->bused; - this->incomplete = malloc(this->isize); + this->incomplete = memMalloc(this->isize); memcpy(this->incomplete, cbufGetData(this->buffer, this->isize), this->isize); @@ -110,7 +109,7 @@ httpParserParse(void * _this, Stream st) if (NULL == (line = cbufGetLine(this->buffer, &line_end))) { if (! cbufIsEmpty(this->buffer)) { this->isize = this->buffer->bused; - this->incomplete = malloc(this->isize); + this->incomplete = memMalloc(this->isize); memcpy(this->incomplete, cbufGetData(this->buffer, this->isize), this->isize); From acd20228d3d2022526c3fc3163bfeafe884c44a7 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:33:40 +0100 Subject: [PATCH 31/97] replace calloc http/worker.c with quick fit approach. --- src/http/worker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/worker.c b/src/http/worker.c index b74eb54..6d6293c 100644 --- a/src/http/worker.c +++ b/src/http/worker.c @@ -44,7 +44,7 @@ httpWorkerCtor(void * _this, va_list * params) char * id = va_arg(*params, char *); char cbuf_id[100]; - this->id = malloc(strlen(id) + 1); + this->id = memMalloc(strlen(id) + 1); strcpy(this->id, id); this->val = va_arg(*params, struct randval *); @@ -78,7 +78,7 @@ httpWorkerDtor(void * _this) { HttpWorker this = _this; - FREE(this->id); + MEM_FREE(this->id); delete(this->parser); delete(this->writer); From 57253c950daa5dd6cfa77e593bd832e267addd9d Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:35:04 +0100 Subject: [PATCH 32/97] replace calloc http/worker/process.c with quick fit approach. --- src/http/worker/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http/worker/process.c b/src/http/worker/process.c index 47d1f14..64998f2 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -126,7 +126,7 @@ httpWorkerProcess(HttpWorker this, Stream st) username->value, username->nvalue)); } else { - this->session->username = malloc(username->nvalue + 1); + this->session->username = memMalloc(username->nvalue + 1); this->session->username[username->nvalue] = 0; memcpy(this->session->username, username->value, From dfffcee4439084f9afbdc39ce894cca62804d2c0 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:38:19 +0100 Subject: [PATCH 33/97] replace malloc in session/session.c with quick fit approach. --- src/session/session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/session/session.c b/src/session/session.c index b768da4..512be4b 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -45,7 +45,7 @@ sessionCtor(void * _this, va_list * params) this->livetime = time(NULL) + SESSION_LIVETIME; this->id = sdbm((unsigned char *)uname, nuname) ^ this->livetime; - this->username = malloc(nuname + 1); + this->username = memMalloc(nuname + 1); this->username[nuname] = 0; memcpy(this->username, uname, nuname); @@ -58,7 +58,7 @@ sessionDtor(void * _this) { Session this = _this; - FREE(this->username); + MEM_FREE(this->username); } INIT_IFACE(Class, sessionCtor, sessionDtor, NULL); From 7bcfeba2966c8a209f27196bcafe3d08cd947650 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:38:50 +0100 Subject: [PATCH 34/97] change last FREE to MEM_FREE --- src/http/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http/parser.c b/src/http/parser.c index 0c88d8e..532e985 100644 --- a/src/http/parser.c +++ b/src/http/parser.c @@ -64,7 +64,7 @@ httpParserDtor(void * _this) if (TRUE == this->ourLock) cbufRelease(this->buffer); - FREE(this->incomplete); + MEM_FREE(this->incomplete); delete(this->current); } From d8ad1d7b26e001be688899ef43c84f9cdc90a0d2 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 20 Aug 2013 21:57:34 +0100 Subject: [PATCH 35/97] add memCleanup before process end --- src/taskrambler.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/taskrambler.c b/src/taskrambler.c index 363f7de..22b28a1 100644 --- a/src/taskrambler.c +++ b/src/taskrambler.c @@ -123,6 +123,7 @@ main() sigsuspend(&pause_mask); } + memCleanup(); _exit(EXIT_SUCCESS); } @@ -192,6 +193,8 @@ main() if (NULL != worker) delete(worker); if (NULL != auth) delete(auth); if (NULL != logger) delete(logger); + + memCleanup(); } break; From 3ed7c9489dcdb4e699666864fe48ba26ab28e504 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 21 Aug 2013 12:44:28 +0100 Subject: [PATCH 36/97] code formatting --- src/http/worker/process.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/http/worker/process.c b/src/http/worker/process.c index 64998f2..f495f2d 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -57,8 +57,7 @@ httpWorkerProcess(HttpWorker this, Stream st) if (0 < (size = httpParserParse(this->parser, st))) { while (! queueEmpty(this->parser->queue)) { - HttpRequest request = queueGet( - this->parser->queue); + HttpRequest request = queueGet(this->parser->queue); HttpMessage response = NULL; /** @@ -120,8 +119,8 @@ httpWorkerProcess(HttpWorker this, Stream st) response = new(HttpResponse, "HTTP/1.1", 403, "Forbidden"); } else { if (NULL == this->session) { - this->session = sessionAdd( - this->sroot, + this->session = sessionAdd( + this->sroot, new(Session, username->value, username->nvalue)); From 04b090cf30e7e1472c1dfab636cc8ae45cb5057e Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 21 Aug 2013 12:46:08 +0100 Subject: [PATCH 37/97] probably fixed problem in main look under load. This still has to be tested. --- TODO | 3 +++ src/server/poll.c | 28 +++++++++++++++------------- src/server/read.c | 19 +++++++++++++++---- src/server/run.c | 42 ++++++++++++++++++++---------------------- 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/TODO b/TODO index 6bfe265..a79ee16 100644 --- a/TODO +++ b/TODO @@ -6,3 +6,6 @@ VERY BIG TODO: - handle errors after all system call...especially open, close, etc. - IPV6 support + +- There seem to be a problem in the server under heavy load. Some tests with ab show that at some point it does not accept any more connections. Nor does it seem to answer request. I guess that it might be difficult to find this.... + => might be done... diff --git a/src/server/poll.c b/src/server/poll.c index cf061c8..95bec71 100644 --- a/src/server/poll.c +++ b/src/server/poll.c @@ -58,21 +58,23 @@ serverPoll(Server this) { /* * wait for handles to become ready */ - if (-1 == (events = poll(this->fds, this->nfds, -1))) { - switch (errno) { - default: - case EBADF: - case EINVAL: - case ENOMEM: - doShutdown = 1; - // DROP THROUGH + do { + if (-1 == (events = poll(this->fds, this->nfds, -1))) { + switch (errno) { + default: + case EBADF: + case EINVAL: + case ENOMEM: + doShutdown = 1; + // DROP THROUGH - case EINTR: - loggerLog(this->logger, LOGGER_CRIT, - "poll systemcall failed: [%s] - service terminated", - strerror(errno)); + case EINTR: + loggerLog(this->logger, LOGGER_CRIT, + "poll systemcall failed: [%s] - service terminated", + strerror(errno)); + } } - } + } while (! doShutdown && 0 >= events); return events; } diff --git a/src/server/read.c b/src/server/read.c index a8add3e..4be6eab 100644 --- a/src/server/read.c +++ b/src/server/read.c @@ -20,6 +20,8 @@ * along with this program. If not, see . */ +#include + #include "server.h" #include "logger.h" #include "stream.h" @@ -44,6 +46,16 @@ serverRead(Server this, unsigned int i) (this->conns)[fd].worker, (this->conns)[fd].stream))) { + case -1: + /* + * read failure + */ + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* on EGAIN just try again later. */ + break; + } + // DROP-THROUGH + case -2: /** * normal close: this must be mapped to -2 within the @@ -52,18 +64,17 @@ serverRead(Server this, unsigned int i) * \todo make sure all pending writes will be done before * close. */ - // DROP-THROUGH - case -1: /* - * read failure / close connection + * close connection if not EAGAIN, this would also + * remove the filedescriptor from the poll list. + * Else just return indicate */ loggerLog(this->logger, LOGGER_INFO, "connection[%d] closed...%s", fd, inet_ntoa((((this->conns)[fd].sock)->addr).sin_addr)); serverCloseConn(this, i); - break; case 0: break; diff --git a/src/server/run.c b/src/server/run.c index 3ba416c..b44741f 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -38,20 +38,20 @@ serverRun(Server this) while (!doShutdown) //! until error or signal { - int events; + int events = 0; unsigned int i; - int naccs = 10; - events = serverPoll(this); - if (doShutdown || 0 >= events) break; + if (0 == events) { + events = serverPoll(this); + } /** * handle accept */ if (0 != ((this->fds)[0].revents & POLLIN)) { - events--; - while(-1 != serverHandleAccept(this, 0) && 0 < naccs) { - naccs--; + if (-1 == serverHandleAccept(this, 0)) { + (this->fds)[0].revents |= ~POLLIN; + events--; } } @@ -59,33 +59,31 @@ serverRun(Server this) * handle accept SSL */ if (0 != ((this->fds)[1].revents & POLLIN)) { - events--; - while(-1 != serverHandleAccept(this, 1) && 0 < naccs) { - naccs--; + if (-1 == serverHandleAccept(this, 1)) { + (this->fds)[1].revents |= ~POLLIN; + events--; } } for (i=2; i < this->nfds; i++) { - int nreads = 10, nwrites = 10; - /** * handle reads */ - if (0 != ((this->fds)[i].revents & POLLIN) && 0 < nreads) { - events--; - nreads--; - - serverRead(this, i); + if (0 != ((this->fds)[i].revents & POLLIN)) { + if (0 < serverRead(this, i)) { + (this->fds)[i].revents |= ~POLLIN; + events--; + } } /** * handle writes */ - if (0 != ((this->fds)[i].revents & POLLOUT) && 0 < nwrites) { - events--; - nwrites--; - - serverWrite(this, i); + if (0 != ((this->fds)[i].revents & POLLOUT)) { + if (0 < serverWrite(this, i)) { + (this->fds)[i].revents |= ~POLLOUT; + events--; + } } if (0 > events) From b832eea81c330f857f12f8b68eb13a8f94b255c6 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 21 Aug 2013 16:17:20 +0100 Subject: [PATCH 38/97] change build system to accept CFLAGS --- configure.ac | 2 +- m4/gcov.m4 | 4 ++-- src/Makefile.am | 2 +- src/auth/Makefile.am | 2 +- src/cbuf/Makefile.am | 2 +- src/class/Makefile.am | 2 +- src/hash/Makefile.am | 2 +- src/http/Makefile.am | 2 +- src/logger/Makefile.am | 2 +- src/queue/Makefile.am | 2 +- src/server/Makefile.am | 2 +- src/session/Makefile.am | 2 +- src/socket/Makefile.am | 2 +- src/stream/Makefile.am | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index fff3090..16bb994 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_INIT([taskrambler], [0.0.1], [Georg Hopp ]) LT_INIT AM_INIT_AUTOMAKE #AM_INIT_AUTOMAKE([subdir-objects]) -AM_SILENT_RULES([yes]) +#AM_SILENT_RULES([yes]) AC_COPYRIGHT([Copyright © 2012 Georg Hopp]) AC_REVISION([$Revision: 0.02 $]) AC_CONFIG_SRCDIR([src/taskrambler.c]) diff --git a/m4/gcov.m4 b/m4/gcov.m4 index 1495f86..0f2c580 100644 --- a/m4/gcov.m4 +++ b/m4/gcov.m4 @@ -14,7 +14,7 @@ AC_DEFUN([AC_TDD_GCOV], [use_gcov=$enableval], [use_gcov=no]) AM_CONDITIONAL(HAVE_GCOV, test "x$use_gcov" = "xyes") - # if test "x$use_gcov" = "xyes"; then + if test "x$use_gcov" = "xyes"; then # we need gcc: if test "$GCC" != "yes"; then AC_MSG_ERROR([GCC is required for --enable-gcov]) @@ -72,6 +72,6 @@ AC_DEFUN([AC_TDD_GCOV], COVERAGE_CXXFLAGS="-O0 -fprofile-arcs -ftest-coverage" COVERAGE_LDFLAGS="-lgcov" -#fi +fi ]) # AC_TDD_GCOV diff --git a/src/Makefile.am b/src/Makefile.am index daef328..dbf4342 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,7 +25,7 @@ AM_CFLAGS = -Wall -I ../include/ bin_PROGRAMS = taskrambler taskrambler_SOURCES = taskrambler.c $(IFACE) $(UTILS) -taskrambler_CFLAGS = -Wall -DPWD=\"$(PWD)\" -I ../include/# $(COVERAGE_CFLAGS) +taskrambler_CFLAGS = $(CFLAGS) -Wall -DPWD=\"$(PWD)\" -I ../include/# $(COVERAGE_CFLAGS) taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap #taskrambler_LDFLAGS = $(COVERAGE_LDFLAGS) diff --git a/src/auth/Makefile.am b/src/auth/Makefile.am index f35a61c..4c30e86 100644 --- a/src/auth/Makefile.am +++ b/src/auth/Makefile.am @@ -3,4 +3,4 @@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = libauth.a libauth_a_SOURCES = interface/auth.c credential.c ldap.c -libauth_a_CFLAGS = -Wall -I ../../include/ +libauth_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/cbuf/Makefile.am b/src/cbuf/Makefile.am index c9d9f29..8254eeb 100644 --- a/src/cbuf/Makefile.am +++ b/src/cbuf/Makefile.am @@ -10,4 +10,4 @@ CB = cbuf.c read.c write.c \ noinst_LIBRARIES = libcbuf.a libcbuf_a_SOURCES = $(CB) -libcbuf_a_CFLAGS = -Wall -I ../../include/ +libcbuf_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/class/Makefile.am b/src/class/Makefile.am index 2b5b0ad..435650b 100644 --- a/src/class/Makefile.am +++ b/src/class/Makefile.am @@ -3,4 +3,4 @@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = libclass.a libclass_a_SOURCES = interface.c interface/i_class.c -libclass_a_CFLAGS = -Wall -I ../../include/ +libclass_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/hash/Makefile.am b/src/hash/Makefile.am index 8eb86ff..5fbd9cc 100644 --- a/src/hash/Makefile.am +++ b/src/hash/Makefile.am @@ -6,4 +6,4 @@ HASH = hash.c add.c get.c delete.c each.c value.c \ noinst_LIBRARIES = libhash.a libhash_a_SOURCES = $(HASH) -libhash_a_CFLAGS = -Wall -I ../../include/ +libhash_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/http/Makefile.am b/src/http/Makefile.am index a7ec689..f583d84 100644 --- a/src/http/Makefile.am +++ b/src/http/Makefile.am @@ -37,4 +37,4 @@ noinst_LIBRARIES = libhttp.a libhttp_a_SOURCES = $(MSG) $(REQ) $(RESP) $(PARSER) $(WRITER) \ $(WORKER) $(HEADER) interface/i_http_intro.c -libhttp_a_CFLAGS = -Wall -I ../../include/ +libhttp_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/logger/Makefile.am b/src/logger/Makefile.am index 261a0b9..461499f 100644 --- a/src/logger/Makefile.am +++ b/src/logger/Makefile.am @@ -3,4 +3,4 @@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = liblogger.a liblogger_a_SOURCES = interface/i_logger.c logger.c stderr.c syslog.c -liblogger_a_CFLAGS = -Wall -I ../../include/ +liblogger_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/queue/Makefile.am b/src/queue/Makefile.am index 8a2196a..6fb286c 100644 --- a/src/queue/Makefile.am +++ b/src/queue/Makefile.am @@ -3,4 +3,4 @@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = libqueue.a libqueue_a_SOURCES = queue.c get.c put.c -libqueue_a_CFLAGS = -Wall -I ../../include/ +libqueue_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/server/Makefile.am b/src/server/Makefile.am index a73bb16..4126672 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -6,4 +6,4 @@ SERVER = server.c run.c close_conn.c poll.c \ noinst_LIBRARIES = libserver.a libserver_a_SOURCES = $(SERVER) -libserver_a_CFLAGS = -Wall -I ../../include/ +libserver_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/session/Makefile.am b/src/session/Makefile.am index 7b6d884..2892b01 100644 --- a/src/session/Makefile.am +++ b/src/session/Makefile.am @@ -3,4 +3,4 @@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = libsession.a libsession_a_SOURCES = session.c add.c get.c delete.c -libsession_a_CFLAGS = -Wall -I ../../include/ +libsession_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/socket/Makefile.am b/src/socket/Makefile.am index 89ef4f0..b59bbc7 100644 --- a/src/socket/Makefile.am +++ b/src/socket/Makefile.am @@ -3,4 +3,4 @@ ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = libsocket.a libsocket_a_SOURCES = socket.c accept.c connect.c listen.c -libsocket_a_CFLAGS = -Wall -I ../../include/ +libsocket_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ diff --git a/src/stream/Makefile.am b/src/stream/Makefile.am index bf8134e..073f18e 100644 --- a/src/stream/Makefile.am +++ b/src/stream/Makefile.am @@ -7,4 +7,4 @@ IFACE = interface/reader.c \ noinst_LIBRARIES = libstream.a libstream_a_SOURCES = $(STREAM) $(IFACE) -libstream_a_CFLAGS = -Wall -I ../../include/ +libstream_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ From a8b362f89d8f4891daed63e336677e9b300efa71 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 21 Aug 2013 16:46:52 +0100 Subject: [PATCH 39/97] fix some warnings --- configure.ac | 2 +- src/server/handle_accept.c | 39 +++++++++++++++++++------------------- src/stream/read.c | 1 + src/stream/write.c | 1 + src/taskrambler.c | 6 ++++-- src/utils/daemonize.c | 7 +++++-- tests/loggerTest.c | 4 +++- tests/serverTest.c | 4 +++- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 16bb994..fff3090 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_INIT([taskrambler], [0.0.1], [Georg Hopp ]) LT_INIT AM_INIT_AUTOMAKE #AM_INIT_AUTOMAKE([subdir-objects]) -#AM_SILENT_RULES([yes]) +AM_SILENT_RULES([yes]) AC_COPYRIGHT([Copyright © 2012 Georg Hopp]) AC_REVISION([$Revision: 0.02 $]) AC_CONFIG_SRCDIR([src/taskrambler.c]) diff --git a/src/server/handle_accept.c b/src/server/handle_accept.c index ab0cb83..f7c912b 100644 --- a/src/server/handle_accept.c +++ b/src/server/handle_accept.c @@ -46,25 +46,26 @@ serverHandleAccept(Server this, unsigned int i) acc = socketAccept((0 == i)? this->sock : this->sockSSL, &remoteAddr); if (-1 != acc->handle) { - switch(i) { - case 0: - // no SSL - st = new(Stream, STREAM_FD, acc->handle); - break; - - case 1: - // SSL - { - SSL * ssl = SSL_new(this->ctx); - SSL_set_fd(ssl, acc->handle); - SSL_accept(ssl); - st = new(Stream, STREAM_SSL, ssl); - } - break; - - default: - break; - } + switch(i) { + case 0: + // no SSL + st = new(Stream, STREAM_FD, acc->handle); + break; + + case 1: + // SSL + { + SSL * ssl = SSL_new(this->ctx); + SSL_set_fd(ssl, acc->handle); + SSL_accept(ssl); + st = new(Stream, STREAM_SSL, ssl); + } + break; + + default: + st = NULL; + break; + } // save the socket handle (this->conns)[acc->handle].sock = acc; diff --git a/src/stream/read.c b/src/stream/read.c index 9050e65..f27058d 100644 --- a/src/stream/read.c +++ b/src/stream/read.c @@ -40,6 +40,7 @@ streamRead(Stream this, void * buf, size_t count) break; default: + done = 0; break; } diff --git a/src/stream/write.c b/src/stream/write.c index 540fade..720f5e4 100644 --- a/src/stream/write.c +++ b/src/stream/write.c @@ -40,6 +40,7 @@ streamWrite(Stream this, void * buf, size_t count) break; default: + done = 0; break; } diff --git a/src/taskrambler.c b/src/taskrambler.c index 22b28a1..ec8039c 100644 --- a/src/taskrambler.c +++ b/src/taskrambler.c @@ -74,8 +74,10 @@ main() init_signals(); daemonize(); - shm = shm_open("/fooshm", O_RDWR|O_CREAT, S_IRWXU); - ftruncate(shm, psize); + shm = shm_open("/fooshm", O_RDWR|O_CREAT, S_IRWXU); + if (-1 == ftruncate(shm, psize)) { + doShutdown = 1; + } switch((pid = fork())) { case -1: diff --git a/src/utils/daemonize.c b/src/utils/daemonize.c index 5b1cce3..bab09c8 100644 --- a/src/utils/daemonize.c +++ b/src/utils/daemonize.c @@ -26,6 +26,7 @@ #include // for getopt #include #include +#include #include #include @@ -56,8 +57,10 @@ void daemonize(void) { // set umask and change to working directory to / umask(UMASK); - chdir(PWD); // this should root and assets needs to be found - // via some kind of configuration. + if (-1 == chdir(PWD)) { // this should root and assets needs to be found + perror("daemonize"); // via some kind of configuration. + exit(EXIT_FAILURE); + } // we should close all open filedescriptors now. // But I assume that this function is called at the very start of the diff --git a/tests/loggerTest.c b/tests/loggerTest.c index acf6bff..f018747 100644 --- a/tests/loggerTest.c +++ b/tests/loggerTest.c @@ -80,7 +80,9 @@ testLoggerStderr() { logger = new(LoggerStderr, LOGGER_ERR); - freopen("/dev/null", "w", stderr); + if (NULL == freopen("/dev/null", "w", stderr)) { + return TEST_ERROR; + } loggerLog(logger, LOGGER_ERR, "foo %d %s", 123, "bar"); /** diff --git a/tests/serverTest.c b/tests/serverTest.c index 81350d2..9d3bdd9 100644 --- a/tests/serverTest.c +++ b/tests/serverTest.c @@ -84,7 +84,9 @@ testDummy() con = new(Sock, logger, TEST_PORT); sleep(1); socketConnect(con, "127.0.0.1", &addr); - write(con->handle, TEST_DATA, strlen(TEST_DATA)+1); + if(-1 == write(con->handle, TEST_DATA, strlen(TEST_DATA)+1)) { + exit(EXIT_FAILURE); + } sleep(1); delete(con); __tearDown(); From 3da465a846002ce10a3fc3ac8df99e5921a337cf Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 12:02:20 +0100 Subject: [PATCH 40/97] add first own binary tree testcode. Not ballanced right now. --- src/binarytree.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 src/binarytree.c diff --git a/src/binarytree.c b/src/binarytree.c new file mode 100644 index 0000000..623985a --- /dev/null +++ b/src/binarytree.c @@ -0,0 +1,237 @@ +#include +#include + +struct element +{ + int data; + + struct element * left; + struct element * right; +}; + +struct element * +newElement(int data) +{ + struct element * el = malloc(sizeof(struct element)); + el->data = data; + el->left = NULL; + el->right = NULL; + + return el; +} + +/** + * find element in tree + */ +struct element * +findElement(struct element * tree, int data) +{ + while (NULL != tree) { + if (tree->data == data) { + break; + } + + if (data < tree->data) { + tree = tree->left; + } else { + tree = tree->right; + } + } + + return tree; +} + +/** + * insert element in tree + */ +void +insertElement(struct element ** tree, int data) +{ + struct element ** node = tree; + + if (NULL == *node) { + *node = newElement(data); + return; + } + + while (data != (*node)->data) { + if (data < (*node)->data) { + if (NULL == (*node)->left) { + (*node)->left = newElement(data); + return; + } else { + *node = (*node)->left; + } + } else { + if (NULL == (*node)->right) { + (*node)->right = newElement(data); + return; + } else { + *node = (*node)->right; + } + } + } +} + +/** + * delete element from tree + * here multiple functions are involved.... + * ======================================================================= + */ +/** + * find minimum of the right subtree aka leftmost leaf of right subtree + * aka left in-order successor. + * We return the parent of the element in the out argument parent. + * This can be NULL wenn calling. + */ +struct element * +findInOrderSuccessor(struct element * tree, struct element ** parent) +{ + struct element * node = tree->right; + + *parent = tree; + + while (NULL != node->left) { + *parent = node; + node = node->left; + } + + return node; +} + +void +deleteElement(struct element ** tree, int data) +{ + struct element * parent = NULL; + struct element * node = *tree; + + // find the relevant node and it's parent + while (NULL != node && node->data != data) { + parent = node; + + if (data < node->data) { + node = node->left; + } else { + node = node->right; + } + } + + // element not found + if (NULL == node) { + return; + } + + // distinuish 3 cases, where the resolving of each case leads to the + // precondition of the other. + + // case 1: two children + if (NULL != node->left && NULL != node->right) { + struct element * successor = findInOrderSuccessor(node, &parent); + + node->data = successor->data; + node = successor; + } + + // case 2: one child wither left or right + if (NULL != node->left) { + node->data = node->left->data; + parent = node; + node = parent->left; + } + + if (NULL != node->right) { + node->data = node->right->data; + parent = node; + node = parent->right; + } + + // case 3: we are a leaf + if (NULL != parent) { + if (node == parent->left) { + parent->left = NULL; + } else { + parent->right = NULL; + } + } + + free(node); + if (node == *tree) { + *tree = NULL; + } +} + +/** + * ======================================================================= + */ +int +main(int argc, char * argv[]) +{ + struct element * root = NULL; + + puts ("insert 5:\n"); + insertElement(&root, 5); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("insert 4:\n"); + insertElement(&root, 4); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("insert 5:\n"); + insertElement(&root, 5); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("insert 6:\n"); + insertElement(&root, 6); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("delete 5 (one child on both sides):\n"); + deleteElement(&root, 5); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("delete 6 (one child on the left):\n"); + deleteElement(&root, 6); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("insert 6:\n"); + insertElement(&root, 6); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("delete 6 (a leaf):\n"); + deleteElement(&root, 6); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts ("delete 4 (a leaf and root):\n"); + deleteElement(&root, 4); + printf("R: 0x%p\n", root); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + return 0; +} + +// vim: set et ts=4 sw=4: From 2446a2f29348ad9aae9747e9133f437b5a2b89e2 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 14:42:47 +0100 Subject: [PATCH 41/97] add small example on rbtree insert, just to see what I have to care about when implementing this --- docs/rbinsert.txt | 234 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 docs/rbinsert.txt diff --git a/docs/rbinsert.txt b/docs/rbinsert.txt new file mode 100644 index 0000000..952f9cb --- /dev/null +++ b/docs/rbinsert.txt @@ -0,0 +1,234 @@ +Properties of a rbtree +====================== + +1. A node is either red or black. +2. The root is black. (This rule is sometimes omitted. Since the root can + always be changed from red to black, but not necessarily vice-versa, + this rule has little effect on analysis.) +3. All leaves (NIL) are black. (All leaves are same color as the + root.) +4. Every red node must have two black child nodes. +5. Every simple path from a given node to any of its + descendant leaves contains the same number of black nodes. + + +Assumptions in addition to wikipedia +==================================== + +lets assume that NULL pointer are black B nodes. But we mark them with a (N) + + +Example +======= + +we start with an empty tree.... +------------------------------- + + B(N) + + +case 1 (root): add first element... elements are red R wenn added, add key 13. +------------------------------------------------------------------------------ + + R(13) + + B(N) B(N) + + +but now we violate rule 2 and correct this simply by changing the root to +black. => first rule, if we insert into a root node (the root was null) insert +as black. + + B(13) + + B(N) B(N) + + +case 2 (black parent): add an element 8. +----------------------------------------- + + B(13) + + R(i8) B(N) + + B(N) B(N) + +we violate none of the properties defined. Nothing to be done. + +Now add 16 which is case 2 again + + B(13) + + R(8) R(16) + + B(N) B(N) B(N) B(N) + + +case 3 (red parent and uncle): add 11.... +---------------------------------------- + + B(13) + + R(8) R(16) + + B(N) R(11) B(N) B(N) + + B(N) B(N) + +This violates propert 4 (each red node must have 2 black childs). +=> repaint both to black and the gandparent to red. + + R(13) + + B(8) B(16) + + B(N) R(11) B(N) B(N) + + B(N) B(N) + +This violates now property 2 (The root is black) and it may have +violated property 4 for the gantparent...so we start all over again +with case 1 on the grantparent. +As we now might run into case 4 or 5 where also parent uncle and +grandparent might be needed we should always track + + - grandgrandparent + - granduncle + - grandparent + - parent + - uncle + +For now case 1 occurs again wich gives us the following: + + B(13) + + B(8) B(16) + + B(N) R(11) B(N) B(N) + + B(N) B(N) + + +Perfect, thats ok again. + +Now as preparation of case 4 we add a 3 + + B(13) + + B(8) B(16) + + R(3) R(11) B(N) B(N) + + B(N) B(N) B(N) B(N) + + +and now a 9. + + B(13) + + B(8) B(16) + + R(3) R(11) B(N) B(N) + + B(N) B(N) R(9) B(N) + + B(N) B(N) + + +which again leads to case 3. + + B(13) + + R(8) B(16) + + B(3) B(11) B(N) B(N) + + B(N) B(N) R(9) B(N) + + B(N) B(N) + +and we are fine again. +now add 12... + + B(13) + + R(8) B(16) + + B(3) B(11) B(N) B(N) + + B(N) B(N) R(9) R(12) + + B(N) B(N) B(N) B(N) + +and now add a 10... + + B(13) + + R(8) B(16) + + B(3) B(11) B(N) B(N) + + B(N) B(N) R(9) R(12) + + B(N) R(10) B(N) B(N) + N N + +case 3 again... + + B(13) + + R(8) B(16) + + B(3) R(11) B(N) B(N) + + B(N) B(N) B(9) B(12) + + B(N) R(10) B(N) B(N) + N N + +as case 3 starts again with grandparent as node, which has to be prepared +before starting over again, we have the following: + + node R(11) + parent R(8) + uncle B(16) + grandparent B(13) + + +now property 4 of for our new parnet is violated which brings us to case 4 as +it is not the root. (the cases are taken from wikipedia.) + +so lets do case 4 on our node (which is left rotate on our parent, +the parent of our grandparent). + + B(13) + + R(11) B(16) + + R(8) B(12) B(N) B(N) + + B(3) B(9) B(N) B(N) + + B(N) B(N) B(N) R(10) + N N + +but again we are left in violated state...again property 4 is violated. +This is always the case, so always do case 5 after case 4. + +We can see beside of some subtree changes our node and parent have changed +role. we need to address this by swaping them in our code. + +So, do case 5 (right rotate the grandparent and set grandparent color to red +and parent color to black. + + B(11) + + R(8) B(13) + + B(3) B(9) B(12) B(16) + + B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) + + B(N) B(N) + +# vim: set et ts=4: From 9d19e2028589de61baad57d09c8d096c91c9f462 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 14:48:11 +0100 Subject: [PATCH 42/97] small fix in rbinsert doc --- docs/rbinsert.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rbinsert.txt b/docs/rbinsert.txt index 952f9cb..728d7e1 100644 --- a/docs/rbinsert.txt +++ b/docs/rbinsert.txt @@ -223,7 +223,7 @@ and parent color to black. B(11) - R(8) B(13) + R(8) R(13) B(3) B(9) B(12) B(16) From 94bc5bc41a95bd00d1f05edf5313bea706583322 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 15:39:13 +0100 Subject: [PATCH 43/97] added first exampled for rbtree delete stuff... --- docs/rbdelete.txt | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/rbdelete.txt diff --git a/docs/rbdelete.txt b/docs/rbdelete.txt new file mode 100644 index 0000000..0c1eb6f --- /dev/null +++ b/docs/rbdelete.txt @@ -0,0 +1,107 @@ +Properties of a rbtree +====================== + +1. A node is either red or black. +2. The root is black. (This rule is sometimes omitted. Since the root can + always be changed from red to black, but not necessarily vice-versa, + this rule has little effect on analysis.) +3. All leaves (NIL) are black. (All leaves are same color as the + root.) +4. Every red node must have two black child nodes. +5. Every simple path from a given node to any of its + descendant leaves contains the same number of black nodes. + + +Assumptions in addition to wikipedia +==================================== + +lets assume that NULL pointer are black B nodes. But we mark them with a (N) + + +Example +======= + +we start with the tree from the insert example +---------------------------------------------- + + B(11) + + R(8) R(13) + + B(3) B(9) B(12) B(16) + + B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) + + B(N) B(N) + +we remove R(10) / remove a red node (replace with its child): +wikipedia explains why this can only happen with two leaf children (our B(N)) + + B(11) + + R(8) R(13) + + B(3) B(9) B(12) B(16) + + B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) + + +again start with the insert example result +------------------------------------------ + + B(11) + + R(8) R(13) + + B(3) B(9) B(12) B(16) + + B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) + + B(N) B(N) + +remove B(9) (which is the second simple case described on wikipedia) +M black, C red +After remove just repaint child black. As I do not replace the node, +but the value this is simplified in my case to simply do nothing after +normal delete... :D + + B(11) + + R(8) R(13) + + B(3) B(10) B(12) B(16) + + B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) + + +again start with the insert example result +------------------------------------------ + + B(11) + + R(8) R(13) + + B(3) B(9) B(12) B(16) + + B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) + + B(N) B(N) + +now lets delete B(3)... which is stated on wikipedia as the complicated case +where 6 subcases could be distinguished. + +Wikipedia says we begin with replacing B(3) which one if its childs, in my +case this means, setting r(8)->left to NULL.... + +So, what is called in on Wikipedia is simply a nullpointer for me...hopefully +I don't have to do anything with it. + +Get an overview over our variables now: + + N : Nullpointer set in R(8)->left + P : R(8) + S : B(9) + Sl: Nullpointer + Sr: R(10) + +# vim: set et ts=4: From 5af0f9f2430862f4015e787ebad2931aec8e63f9 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 15:51:58 +0100 Subject: [PATCH 44/97] rbdelete stuff --- docs/rbdelete.txt | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/rbdelete.txt b/docs/rbdelete.txt index 0c1eb6f..21b7a59 100644 --- a/docs/rbdelete.txt +++ b/docs/rbdelete.txt @@ -93,15 +93,48 @@ where 6 subcases could be distinguished. Wikipedia says we begin with replacing B(3) which one if its childs, in my case this means, setting r(8)->left to NULL.... + B(11) + + R(8) R(13) + + B(N) B(9) B(12) B(16) + + B(N) R(10) B(N) B(N) B(N) B(N) + + B(N) B(N) + So, what is called in on Wikipedia is simply a nullpointer for me...hopefully I don't have to do anything with it. Get an overview over our variables now: - N : Nullpointer set in R(8)->left + N : Nullpointer set in R(8)->left (thus N will be black by definition, ever) P : R(8) S : B(9) Sl: Nullpointer Sr: R(10) +we have case 2 described in Wikipedia (reverse colors of P and S) + + B(11) + + R(8) R(13) + + B(N) B(9) B(12) B(16) + + B(N) R(10) B(N) B(N) B(N) B(N) + + B(N) B(N) + +still case 2 rotate left on P + + B(11) + + B(9) R(13) + + B(8) R(10) B(12) B(16) + + B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) + + # vim: set et ts=4: From 868018cd657055c2caf6f4b72d590e666d322663 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 16:38:29 +0100 Subject: [PATCH 45/97] more stuff on rbdelete --- docs/rbdelete.txt | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/rbdelete.txt b/docs/rbdelete.txt index 21b7a59..071d2e4 100644 --- a/docs/rbdelete.txt +++ b/docs/rbdelete.txt @@ -114,27 +114,36 @@ Get an overview over our variables now: Sl: Nullpointer Sr: R(10) -we have case 2 described in Wikipedia (reverse colors of P and S) +cases: + - case 2: S is red => reverse color of P and S, then rotate left at P + - case 3: P, S and S's children are black => repaint S red + - case 4: S and S's children are black, P is red => exchange colors of S and + P + - case 5: S and Sr black, Sl is red N left of P => rotate right at S, exchange + colors of S and Sl + - case 6: S black, Sr is red N left of P => rotate left at P, exchange colors + of P and S and make Sr black + +looks like case 6: + +first rotate left at P B(11) - R(8) R(13) + B(9) R(13) - B(N) B(9) B(12) B(16) + R(8) R(10) B(12) B(16) - B(N) R(10) B(N) B(N) B(N) B(N) + B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) - B(N) B(N) - -still case 2 rotate left on P +exchange colors of P and S and make Sr black. B(11) - B(9) R(13) + R(9) R(13) - B(8) R(10) B(12) B(16) - - B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) + B(8) B(10) B(12) B(16) + B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) # vim: set et ts=4: From 99508f70168660ecebaf752b4daf790670322efe Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 17:56:17 +0100 Subject: [PATCH 46/97] further improvments on the rb examples --- docs/rbdelete.txt | 96 +++++++++++++++++++++++++++++++++++++++++++++++ docs/rbinsert.txt | 5 ++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/docs/rbdelete.txt b/docs/rbdelete.txt index 071d2e4..b0803b6 100644 --- a/docs/rbdelete.txt +++ b/docs/rbdelete.txt @@ -146,4 +146,100 @@ exchange colors of P and S and make Sr black. B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) + + +now for case 2, we delete 16 from the following tree + + B(13) + + R(8) B(16) + + B(3) B(11) B(N) B(N) + + B(N) B(N) R(9) B(N) + + B(N) B(N) + +again first lets see what we have where... + + N : Nullpointer set in R(13)->right (thus N will be black by definition, ever) + P : B(13) + S : R(8) + Sl: B(3) + Sr: B(11) + + B(13)P + + R(8)S B(N)N + + B(3)Sl B(11)Sr + + B(N) B(N) R(9) B(N) + + B(N) B(N) + +revert colors of P and S + + R(13)P + + B(8)S B(N)N + + B(3)Sl B(11)Sr + + B(N) B(N) R(9) B(N) + + B(N) B(N) + +rotate right at P + + B(8)S + + B(3)Sl R(13)P + + B(N) B(N) B(11)Sr B(N)N + + R(9) B(N) + + B(N) B(N) + +relable ... done on wikipedia (don't know if I will need it.) + + B(8) + + B(3) R(13)P + + B(N) B(N) B(11)S B(N)N + + R(9)Sl B(N)Sr + + B(N) B(N) + +ok, not case 3... P is red +nor is it case 4 Sl is red. +kind of case 6 reversed ... lets try what they do in the code not in the description... + +Sl to black + + B(8) + + B(3) R(13)P + + B(N) B(N) B(11)S B(N)N + + B(9)Sl B(N)Sr + + B(N) B(N) + +rotate right on P + + B(8) + + B(3) B(11)S + + B(N) B(N) B(9)Sl R(13)P + + B(N) B(N) B(N)Sr B(N)N + +This result is wrong....the balance is ok, but the color of 9 is wrong. + # vim: set et ts=4: diff --git a/docs/rbinsert.txt b/docs/rbinsert.txt index 728d7e1..12bae66 100644 --- a/docs/rbinsert.txt +++ b/docs/rbinsert.txt @@ -49,12 +49,13 @@ case 2 (black parent): add an element 8. B(13) - R(i8) B(N) + R(8) B(N) B(N) B(N) we violate none of the properties defined. Nothing to be done. + Now add 16 which is case 2 again B(13) @@ -195,7 +196,7 @@ before starting over again, we have the following: grandparent B(13) -now property 4 of for our new parnet is violated which brings us to case 4 as +now property 4 of our new parent is violated which brings us to case 4 as it is not the root. (the cases are taken from wikipedia.) so lets do case 4 on our node (which is left rotate on our parent, From 74a60c72c1256c8a36cbf241d57926ea9a5a5ed2 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 23:24:54 +0100 Subject: [PATCH 47/97] add parent in element and implement an iterative in-order traversal with it. --- src/binarytree.c | 77 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index 623985a..681f3b0 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -5,6 +5,7 @@ struct element { int data; + struct element * parent; struct element * left; struct element * right; }; @@ -13,9 +14,10 @@ struct element * newElement(int data) { struct element * el = malloc(sizeof(struct element)); - el->data = data; - el->left = NULL; - el->right = NULL; + el->data = data; + el->parent = NULL; + el->left = NULL; + el->right = NULL; return el; } @@ -57,14 +59,16 @@ insertElement(struct element ** tree, int data) while (data != (*node)->data) { if (data < (*node)->data) { if (NULL == (*node)->left) { - (*node)->left = newElement(data); + (*node)->left = newElement(data); + (*node)->left->parent = *node; return; } else { *node = (*node)->left; } } else { if (NULL == (*node)->right) { - (*node)->right = newElement(data); + (*node)->right = newElement(data); + (*node)->right->parent = *node; return; } else { *node = (*node)->right; @@ -85,15 +89,12 @@ insertElement(struct element ** tree, int data) * This can be NULL wenn calling. */ struct element * -findInOrderSuccessor(struct element * tree, struct element ** parent) +findInOrderSuccessor(struct element * tree) { struct element * node = tree->right; - *parent = tree; - while (NULL != node->left) { - *parent = node; - node = node->left; + node = node->left; } return node; @@ -126,9 +127,10 @@ deleteElement(struct element ** tree, int data) // case 1: two children if (NULL != node->left && NULL != node->right) { - struct element * successor = findInOrderSuccessor(node, &parent); + struct element * successor = findInOrderSuccessor(node); node->data = successor->data; + parent = successor->parent; node = successor; } @@ -160,6 +162,55 @@ deleteElement(struct element ** tree, int data) } } + +void +traverse(struct element * tree, void (*cb)(int, int)) +{ + struct element * previous = NULL; + struct element * node = tree; + int depth = 1; + + while (tree) { + /* we came from a left node */ + if ((NULL == node->left || previous == node->left) && + previous != node->right) { + + cb(node->data, depth); + previous = node; + + if (NULL != node->right) { + node = node->right; + depth++; + } else { + if (node->parent->right == node) { + break; + } + + node = node->parent; + depth--; + } + } else { + previous = node; + + if (previous == node->left || previous == node->right) { + node = node->parent; + depth--; + } else { + node = node->left; + depth++; + } + } + } +} + +void printElement(int data, int depth) +{ + char format[250]; + + sprintf(format, "%% %dd(%%d)\n", depth * 3); + printf(format, data, depth); +} + /** * ======================================================================= */ @@ -196,6 +247,10 @@ main(int argc, char * argv[]) printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); + puts ("traverse"); + traverse(root, printElement); + puts ("\n"); + puts ("delete 5 (one child on both sides):\n"); deleteElement(&root, 5); printf("R: 0x%p\n", root); From 84451e7de3f9c165fab2208fb013a77887274393 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 23:28:13 +0100 Subject: [PATCH 48/97] remove wrong comment --- src/binarytree.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/binarytree.c b/src/binarytree.c index 681f3b0..43403b9 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -171,7 +171,6 @@ traverse(struct element * tree, void (*cb)(int, int)) int depth = 1; while (tree) { - /* we came from a left node */ if ((NULL == node->left || previous == node->left) && previous != node->right) { From 847b275c865f109cd17d4502c6939ace303b1f22 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 22 Aug 2013 23:43:59 +0100 Subject: [PATCH 49/97] fix insert and make another in-order traverse for checking --- src/binarytree.c | 62 +++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index 43403b9..75fd761 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -49,29 +49,29 @@ findElement(struct element * tree, int data) void insertElement(struct element ** tree, int data) { - struct element ** node = tree; + struct element * node = *tree; - if (NULL == *node) { - *node = newElement(data); + if (NULL == node) { + *tree = newElement(data); return; } - while (data != (*node)->data) { - if (data < (*node)->data) { - if (NULL == (*node)->left) { - (*node)->left = newElement(data); - (*node)->left->parent = *node; + while (data != node->data) { + if (data < node->data) { + if (NULL == node->left) { + node->left = newElement(data); + node->left->parent = node; return; } else { - *node = (*node)->left; + node = node->left; } } else { - if (NULL == (*node)->right) { - (*node)->right = newElement(data); - (*node)->right->parent = *node; + if (NULL == node->right) { + node->right = newElement(data); + node->right->parent = node; return; } else { - *node = (*node)->right; + node = node->right; } } } @@ -218,73 +218,87 @@ main(int argc, char * argv[]) { struct element * root = NULL; - puts ("insert 5:\n"); + puts("insert 5:"); insertElement(&root, 5); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("insert 4:\n"); + puts("insert 4:"); insertElement(&root, 4); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("insert 5:\n"); + puts("insert 5:"); insertElement(&root, 5); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("insert 6:\n"); + puts("insert 6:"); insertElement(&root, 6); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("traverse"); + puts("traverse"); traverse(root, printElement); - puts ("\n"); + puts("\n"); - puts ("delete 5 (one child on both sides):\n"); + puts("delete 5 (one child on both sides):"); deleteElement(&root, 5); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("delete 6 (one child on the left):\n"); + puts("delete 6 (one child on the left):"); deleteElement(&root, 6); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("insert 6:\n"); + puts("insert 6:"); insertElement(&root, 6); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("delete 6 (a leaf):\n"); + puts("delete 6 (a leaf):"); deleteElement(&root, 6); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); - puts ("delete 4 (a leaf and root):\n"); + puts("delete 4 (a leaf and root):"); deleteElement(&root, 4); printf("R: 0x%p\n", root); printf("4: 0x%p\n", findElement(root, 4)); printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); + puts("insert 4:"); + insertElement(&root, 4); + puts("insert 5:"); + insertElement(&root, 5); + puts("insert 6:"); + insertElement(&root, 6); + printf("4: 0x%p\n", findElement(root, 4)); + printf("5: 0x%p\n", findElement(root, 5)); + printf("6: 0x%p\n\n", findElement(root, 6)); + + puts("traverse"); + traverse(root, printElement); + puts("\n"); + return 0; } From e5fa68bf02e55c6bf8a6d147d3b527df4555f0a1 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 00:23:56 +0100 Subject: [PATCH 50/97] now use the parent in element in delete --- src/binarytree.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index 75fd761..84c5dfb 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -1,6 +1,9 @@ #include #include +#include "../include/commons.h" + + struct element { int data; @@ -103,13 +106,10 @@ findInOrderSuccessor(struct element * tree) void deleteElement(struct element ** tree, int data) { - struct element * parent = NULL; struct element * node = *tree; // find the relevant node and it's parent while (NULL != node && node->data != data) { - parent = node; - if (data < node->data) { node = node->left; } else { @@ -130,29 +130,26 @@ deleteElement(struct element ** tree, int data) struct element * successor = findInOrderSuccessor(node); node->data = successor->data; - parent = successor->parent; node = successor; } // case 2: one child wither left or right if (NULL != node->left) { node->data = node->left->data; - parent = node; - node = parent->left; + node = node->left; } if (NULL != node->right) { node->data = node->right->data; - parent = node; - node = parent->right; + node = node->right; } // case 3: we are a leaf - if (NULL != parent) { - if (node == parent->left) { - parent->left = NULL; + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = NULL; } else { - parent->right = NULL; + node->parent->right = NULL; } } From 1f40d1bc4bec67edc2a80d60c30603176586894f Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 01:15:37 +0100 Subject: [PATCH 51/97] alternative approach on delete of single child nodes. This one really exchanges the nodes, thus preventing large copy on big data that might be in the tree...anyway, for small data i think the other approach is faster. --- src/binarytree.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index 84c5dfb..fa0bbfd 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -135,13 +135,29 @@ deleteElement(struct element ** tree, int data) // case 2: one child wither left or right if (NULL != node->left) { - node->data = node->left->data; - node = node->left; + //node->data = node->left->data; + //node = node->left; + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = node->left; + } else { + node->parent->right = node->left; + } + } + node->left->parent = node->parent; } if (NULL != node->right) { - node->data = node->right->data; - node = node->right; + //node->data = node->right->data; + //node = node->right; + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = node->right; + } else { + node->parent->right = node->right; + } + } + node->right->parent = node->parent; } // case 3: we are a leaf @@ -153,10 +169,17 @@ deleteElement(struct element ** tree, int data) } } - free(node); if (node == *tree) { - *tree = NULL; + if (NULL != node->left) { + *tree = node->left; + } else if (NULL != node->right) { + *tree = node->right; + } else { + *tree = NULL; + } } + + free(node); } @@ -178,7 +201,7 @@ traverse(struct element * tree, void (*cb)(int, int)) node = node->right; depth++; } else { - if (node->parent->right == node) { + if (NULL == node->parent || node->parent->right == node) { break; } @@ -254,6 +277,10 @@ main(int argc, char * argv[]) printf("5: 0x%p\n", findElement(root, 5)); printf("6: 0x%p\n\n", findElement(root, 6)); + puts("traverse"); + traverse(root, printElement); + puts("\n"); + puts("delete 6 (one child on the left):"); deleteElement(&root, 6); printf("R: 0x%p\n", root); From ac93db101bb3988db7988f0d4be038d2a76ed423 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 11:23:22 +0100 Subject: [PATCH 52/97] fix traversal --- src/binarytree.c | 172 +++++++++++++++++++---------------------------- 1 file changed, 70 insertions(+), 102 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index fa0bbfd..68b7ad2 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -1,8 +1,6 @@ #include #include -#include "../include/commons.h" - struct element { @@ -186,14 +184,22 @@ deleteElement(struct element ** tree, int data) void traverse(struct element * tree, void (*cb)(int, int)) { - struct element * previous = NULL; + struct element * previous = tree; struct element * node = tree; int depth = 1; - while (tree) { - if ((NULL == node->left || previous == node->left) && - previous != node->right) { + // I think this has something like O(n+log(n)) on a ballanced + // tree because I have to traverse back the rightmost leaf to + // the root to get a break condition. + while (node) { + if (previous == node->right) { + previous = node; + node = node->parent; + depth--; + continue; + } + if ((NULL == node->left || previous == node->left)) { cb(node->data, depth); previous = node; @@ -201,33 +207,23 @@ traverse(struct element * tree, void (*cb)(int, int)) node = node->right; depth++; } else { - if (NULL == node->parent || node->parent->right == node) { - break; - } - node = node->parent; depth--; } } else { previous = node; - - if (previous == node->left || previous == node->right) { - node = node->parent; - depth--; - } else { - node = node->left; - depth++; - } + node = node->left; + depth++; } } } void printElement(int data, int depth) { - char format[250]; + int i; - sprintf(format, "%% %dd(%%d)\n", depth * 3); - printf(format, data, depth); + for (i=0; iparent : 0x0, + element ? element->left : 0x0, + element ? element->right : 0x0); + } puts("traverse"); traverse(root, printElement); - puts("\n"); return 0; } From fafc5af2abd04bd8b7c644c3c9be93ae5e019625 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 11:24:01 +0100 Subject: [PATCH 53/97] cope binarytree to play with an rbtree implementation --- src/rbtree.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 src/rbtree.c diff --git a/src/rbtree.c b/src/rbtree.c new file mode 100644 index 0000000..68b7ad2 --- /dev/null +++ b/src/rbtree.c @@ -0,0 +1,297 @@ +#include +#include + + +struct element +{ + int data; + + struct element * parent; + struct element * left; + struct element * right; +}; + +struct element * +newElement(int data) +{ + struct element * el = malloc(sizeof(struct element)); + el->data = data; + el->parent = NULL; + el->left = NULL; + el->right = NULL; + + return el; +} + +/** + * find element in tree + */ +struct element * +findElement(struct element * tree, int data) +{ + while (NULL != tree) { + if (tree->data == data) { + break; + } + + if (data < tree->data) { + tree = tree->left; + } else { + tree = tree->right; + } + } + + return tree; +} + +/** + * insert element in tree + */ +void +insertElement(struct element ** tree, int data) +{ + struct element * node = *tree; + + if (NULL == node) { + *tree = newElement(data); + return; + } + + while (data != node->data) { + if (data < node->data) { + if (NULL == node->left) { + node->left = newElement(data); + node->left->parent = node; + return; + } else { + node = node->left; + } + } else { + if (NULL == node->right) { + node->right = newElement(data); + node->right->parent = node; + return; + } else { + node = node->right; + } + } + } +} + +/** + * delete element from tree + * here multiple functions are involved.... + * ======================================================================= + */ +/** + * find minimum of the right subtree aka leftmost leaf of right subtree + * aka left in-order successor. + * We return the parent of the element in the out argument parent. + * This can be NULL wenn calling. + */ +struct element * +findInOrderSuccessor(struct element * tree) +{ + struct element * node = tree->right; + + while (NULL != node->left) { + node = node->left; + } + + return node; +} + +void +deleteElement(struct element ** tree, int data) +{ + struct element * node = *tree; + + // find the relevant node and it's parent + while (NULL != node && node->data != data) { + if (data < node->data) { + node = node->left; + } else { + node = node->right; + } + } + + // element not found + if (NULL == node) { + return; + } + + // distinuish 3 cases, where the resolving of each case leads to the + // precondition of the other. + + // case 1: two children + if (NULL != node->left && NULL != node->right) { + struct element * successor = findInOrderSuccessor(node); + + node->data = successor->data; + node = successor; + } + + // case 2: one child wither left or right + if (NULL != node->left) { + //node->data = node->left->data; + //node = node->left; + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = node->left; + } else { + node->parent->right = node->left; + } + } + node->left->parent = node->parent; + } + + if (NULL != node->right) { + //node->data = node->right->data; + //node = node->right; + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = node->right; + } else { + node->parent->right = node->right; + } + } + node->right->parent = node->parent; + } + + // case 3: we are a leaf + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = NULL; + } else { + node->parent->right = NULL; + } + } + + if (node == *tree) { + if (NULL != node->left) { + *tree = node->left; + } else if (NULL != node->right) { + *tree = node->right; + } else { + *tree = NULL; + } + } + + free(node); +} + + +void +traverse(struct element * tree, void (*cb)(int, int)) +{ + struct element * previous = tree; + struct element * node = tree; + int depth = 1; + + // I think this has something like O(n+log(n)) on a ballanced + // tree because I have to traverse back the rightmost leaf to + // the root to get a break condition. + while (node) { + if (previous == node->right) { + previous = node; + node = node->parent; + depth--; + continue; + } + + if ((NULL == node->left || previous == node->left)) { + cb(node->data, depth); + previous = node; + + if (NULL != node->right) { + node = node->right; + depth++; + } else { + node = node->parent; + depth--; + } + } else { + previous = node; + node = node->left; + depth++; + } + } +} + +void printElement(int data, int depth) +{ + int i; + + for (i=0; iparent : 0x0, + element ? element->left : 0x0, + element ? element->right : 0x0); + } + + puts("traverse"); + traverse(root, printElement); + + return 0; +} + +// vim: set et ts=4 sw=4: From 9263007b347e150e3191b8a93f562e2b59e246b0 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 12:08:30 +0100 Subject: [PATCH 54/97] change the way traversed elements are shown and add some comments --- src/binarytree.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index 68b7ad2..652faaf 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -188,10 +188,16 @@ traverse(struct element * tree, void (*cb)(int, int)) struct element * node = tree; int depth = 1; - // I think this has something like O(n+log(n)) on a ballanced - // tree because I have to traverse back the rightmost leaf to - // the root to get a break condition. + /* + * I think this has something like O(n+log(n)) on a ballanced + * tree because I have to traverse back the rightmost leaf to + * the root to get a break condition. + */ while (node) { + /* + * If we come from the right so nothing and go to our + * next parent. + */ if (previous == node->right) { previous = node; node = node->parent; @@ -200,6 +206,10 @@ traverse(struct element * tree, void (*cb)(int, int)) } if ((NULL == node->left || previous == node->left)) { + /* + * If there are no more elements to the left or we + * came from the left, process data. + */ cb(node->data, depth); previous = node; @@ -211,6 +221,9 @@ traverse(struct element * tree, void (*cb)(int, int)) depth--; } } else { + /* + * if there are more elements to the left go there. + */ previous = node; node = node->left; depth++; @@ -222,8 +235,9 @@ void printElement(int data, int depth) { int i; - for (i=0; i Date: Fri, 23 Aug 2013 14:06:34 +0100 Subject: [PATCH 55/97] inserting in red black tree now works as in my example. --- src/rbtree.c | 296 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 259 insertions(+), 37 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index 68b7ad2..204f42e 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -2,10 +2,15 @@ #include +enum rbColor {rbBlack=1, rbRed=2}; + + struct element { int data; + enum rbColor color; + struct element * parent; struct element * left; struct element * right; @@ -14,13 +19,14 @@ struct element struct element * newElement(int data) { - struct element * el = malloc(sizeof(struct element)); - el->data = data; - el->parent = NULL; - el->left = NULL; - el->right = NULL; + struct element * node = malloc(sizeof(struct element)); + node->data = data; + node->color = rbRed; + node->parent = NULL; + node->left = NULL; + node->right = NULL; - return el; + return node; } /** @@ -47,14 +53,14 @@ findElement(struct element * tree, int data) /** * insert element in tree */ -void +struct element * insertElement(struct element ** tree, int data) { struct element * node = *tree; if (NULL == node) { *tree = newElement(data); - return; + return *tree; } while (data != node->data) { @@ -62,7 +68,7 @@ insertElement(struct element ** tree, int data) if (NULL == node->left) { node->left = newElement(data); node->left->parent = node; - return; + return node->left; } else { node = node->left; } @@ -70,12 +76,14 @@ insertElement(struct element ** tree, int data) if (NULL == node->right) { node->right = newElement(data); node->right->parent = node; - return; + return node->right; } else { node = node->right; } } } + + return NULL; } /** @@ -188,10 +196,16 @@ traverse(struct element * tree, void (*cb)(int, int)) struct element * node = tree; int depth = 1; - // I think this has something like O(n+log(n)) on a ballanced - // tree because I have to traverse back the rightmost leaf to - // the root to get a break condition. + /* + * I think this has something like O(n+log(n)) on a ballanced + * tree because I have to traverse back the rightmost leaf to + * the root to get a break condition. + */ while (node) { + /* + * If we come from the right so nothing and go to our + * next parent. + */ if (previous == node->right) { previous = node; node = node->parent; @@ -200,6 +214,10 @@ traverse(struct element * tree, void (*cb)(int, int)) } if ((NULL == node->left || previous == node->left)) { + /* + * If there are no more elements to the left or we + * came from the left, process data. + */ cb(node->data, depth); previous = node; @@ -211,6 +229,9 @@ traverse(struct element * tree, void (*cb)(int, int)) depth--; } } else { + /* + * if there are more elements to the left go there. + */ previous = node; node = node->left; depth++; @@ -222,8 +243,188 @@ void printElement(int data, int depth) { int i; - for (i=0; iparent) { + return node->parent->parent; + } + + return NULL; +} + +struct element * +uncle(struct element * node) +{ + struct element * gp = grandparent(node); + + if (NULL == gp) { + return NULL; + } + + if (node->parent == gp->left) { + return gp->right; + } + + return gp->left; +} + +void +rotateLeft(struct element ** tree, struct element * node) +{ + struct element * rightChild = node->right; + struct element * rcLeftSub = node->right->left; + + rightChild->left = node; + rightChild->parent = node->parent; + node->right = rcLeftSub; + rcLeftSub->parent = node; + + if (node->parent) { + if (node->parent->left == node) { + node->parent->left = rightChild; + } else { + node->parent->right = rightChild; + } + } else { + *tree = rightChild; + } + + node->parent = rightChild; +} + +void +rotateRight(struct element ** tree, struct element * node) +{ + struct element * leftChild = node->left; + struct element * lcRightSub = node->left->right; + + leftChild->right = node; + leftChild->parent = node->parent; + node->left = lcRightSub; + lcRightSub->parent = node; + + if (node->parent) { + if (node->parent->left == node) { + node->parent->left = leftChild; + } else { + node->parent->right = leftChild; + } + } else { + *tree = leftChild; + } + + node->parent = leftChild; +} + +void +insertCase5(struct element ** tree, struct element * node) +{ + struct element *g = grandparent(node); + + node->parent->color = rbBlack; + g->color = rbRed; + + if (node == node->parent->left) { + rotateRight(tree, g); + } else { + rotateLeft(tree, g); + } +} + +void +insertCase4(struct element ** tree, struct element * node) +{ + struct element * g = grandparent(node); + + if ((node == node->parent->right) && (node->parent == g->left)) { + rotateLeft(tree, node->parent); + + /* + * rotate_left can be the below because of already + * having *g = grandparent(n) + * + * struct node *saved_p=g->left, *saved_left_n=n->left; + * g->left=n; + * n->left=saved_p; + * saved_p->right=saved_left_n; + * + * and modify the parent's nodes properly + */ + node = node->left; + + } else if ( + (node == node->parent->left) && + (node->parent == g->right)) { + + rotateRight(tree, node->parent); + + /* + * rotate_right can be the below to take advantage + * of already having *g = grandparent(n) + * + * struct node *saved_p=g->right, *saved_right_n=n->right; + * g->right=n; + * n->right=saved_p; + * saved_p->left=saved_right_n; + * + */ + node = node->right; + } + + insertCase5(tree, node); +} + +void insertCase1(struct element **, struct element *); + +void +insertCase3(struct element ** tree, struct element * node) +{ + struct element * u = uncle(node); + struct element * g; + + if ((u != NULL) && (u->color == rbRed)) { + node->parent->color = rbBlack; + u->color = rbBlack; + g = grandparent(node); + g->color = rbRed; + + insertCase1(tree, g); + } else { + insertCase4(tree, node); + } +} + +void +insertCase2(struct element ** tree, struct element * node) +{ + if (node->parent->color == rbBlack) { + return; + // Tree is still valid ... wow, again we're done... :) + } else { + insertCase3(tree, node); + } +} + +void +insertCase1(struct element ** tree, struct element * node) +{ + if (node->parent == NULL) { + node->color = rbBlack; + // we're done.... :) + } else { + insertCase2(tree, node); + } } /** @@ -232,17 +433,18 @@ void printElement(int data, int depth) int main(int argc, char * argv[]) { - int i; - struct element * root = NULL; - - insertElement(&root, 13); - insertElement(&root, 8); - insertElement(&root, 16); - insertElement(&root, 11); - insertElement(&root, 3); - insertElement(&root, 9); - insertElement(&root, 12); - insertElement(&root, 10); + struct element * root1 = NULL; + struct element * root2 = NULL; + struct element * inserted = NULL; + + insertElement(&root1, 13); + insertElement(&root1, 8); + insertElement(&root1, 16); + insertElement(&root1, 11); + insertElement(&root1, 3); + insertElement(&root1, 9); + insertElement(&root1, 12); + insertElement(&root1, 10); /* * after this I have the following: @@ -277,19 +479,39 @@ main(int argc, char * argv[]) * Looks like the insert works properly. * So the problem is out traversing... */ - puts("elements:"); - for (i=1; i<20; i++) { - struct element * element = findElement(root, i); - printf("Element %02d: n=0x%p p=0x%p l=0x%p r=0x%p\n", - i, - element, - element ? element->parent : 0x0, - element ? element->left : 0x0, - element ? element->right : 0x0); - } + // puts("elements:"); + // for (i=1; i<20; i++) { + // struct element * element = findElement(root, i); + // printf("Element %02d: n=0x%p p=0x%p l=0x%p r=0x%p\n", + // i, + // element, + // element ? element->parent : 0x0, + // element ? element->left : 0x0, + // element ? element->right : 0x0); + // } + + puts("traverse"); + traverse(root1, printElement); + + inserted = insertElement(&root2, 13); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 8); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 16); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 11); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 3); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 9); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 12); + insertCase1(&root2, inserted); + inserted = insertElement(&root2, 10); + insertCase1(&root2, inserted); puts("traverse"); - traverse(root, printElement); + traverse(root2, printElement); return 0; } From c3498917bc2ce7e28be7e94af64b810ff36d8cc6 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 16:07:24 +0100 Subject: [PATCH 56/97] now it seems that rb trees are working now...stiff a lot of optimization work to be done, as this is mostly one 2 one the code from wikipedia, with some modifiations to work with NULL leaf nodes. --- src/rbtree.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 217 insertions(+), 10 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index 204f42e..2228caf 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -109,6 +109,8 @@ findInOrderSuccessor(struct element * tree) return node; } +void deleteOneChild(struct element **, struct element *); + void deleteElement(struct element ** tree, int data) { @@ -139,6 +141,10 @@ deleteElement(struct element ** tree, int data) node = successor; } + /* + * In rb trees we handle the remaining situations differently + */ + /* // case 2: one child wither left or right if (NULL != node->left) { //node->data = node->left->data; @@ -186,6 +192,8 @@ deleteElement(struct element ** tree, int data) } free(node); + */ + deleteOneChild(tree, node); } @@ -279,6 +287,16 @@ uncle(struct element * node) return gp->left; } +struct element * +sibling(struct element * node) +{ + if (node == node->parent->left) + return node->parent->right; + else + return node->parent->left; +} + + void rotateLeft(struct element ** tree, struct element * node) { @@ -427,6 +445,173 @@ insertCase1(struct element ** tree, struct element * node) } } +void +replaceNode(struct element * node1, struct element * node2) +{ + if (NULL != node1->parent) { + if (node1 == node1->parent->left) { + node1->parent->left = node2; + } else { + node1->parent->right = node2; + } + } + + if (NULL != node2) { + node2->parent = node1->parent; + } +} + +void +deleteCase6(struct element ** tree, struct element * node) +{ + struct element * s = sibling(node); + + s->color = node->parent->color; + node->parent->color = rbBlack; + + if (node == node->parent->left) { + s->right->color = rbBlack; + rotateLeft(tree, node->parent); + } else { + s->left->color = rbBlack; + rotateRight(tree, node->parent); + } +} + +void +deleteCase5(struct element ** tree, struct element * node) +{ + struct element * s = sibling(node); + + if (NULL != s && s->color == rbBlack) { + /* + * this if statement is trivial, + * due to case 2 (even though case 2 changed the sibling to a + * sibling's child, + * the sibling's child can't be red, since no red parent can + * have a red child). + */ + /* + * the following statements just force the red to be on the + * left of the left of the parent, + * or right of the right, so case six will rotate correctly. + */ + if ((node == node->parent->left) && + (s->right->color == rbBlack) && + (s->left->color == rbRed)) { + + /* this last test is trivial too due to cases 2-4. */ + s->color = rbRed; + s->left->color = rbBlack; + + rotateRight(tree, s); + } else if ((node == node->parent->right) && + (s->left->color == rbBlack) && + (s->right->color == rbRed)) { + /* + * this last test is trivial too due to cases 2-4. + */ + s->color = rbRed; + s->right->color = rbBlack; + + rotateLeft(tree, s); + } + } + + deleteCase6(tree, node); +} + +void +deleteCase4(struct element ** tree, struct element * node) +{ + struct element * s = sibling(node); + + if ((node->parent->color == rbRed) && + (NULL == s || ((s->color == rbBlack) && + (s->left->color == rbBlack) && + (s->right->color == rbBlack)))) { + if (NULL != s) { + s->color = rbRed; + } + node->parent->color = rbBlack; + } else { + deleteCase5(tree, node); + } +} + +void deleteCase1(struct element **, struct element *); + +void +deleteCase3(struct element ** tree, struct element * node) +{ + struct element * s = sibling(node); + + if ((node->parent->color == rbBlack) && + (NULL == s || ((s->color == rbBlack) && + (s->left->color == rbBlack) && + (s->right->color == rbBlack)))) { + if (NULL != s) { + s->color = rbRed; + } + deleteCase1(tree, node->parent); + } else { + deleteCase4(tree, node); + } +} + +void +deleteCase2(struct element ** tree, struct element * node) +{ + struct element * s = sibling(node); + + if (NULL != s && s->color == rbRed) { + node->parent->color = rbRed; + s->color = rbBlack; + + if (node == node->parent->left) { + rotateLeft(tree, node->parent); + } else { + rotateRight(tree, node->parent); + } + } + + deleteCase3(tree, node); +} + +void +deleteCase1(struct element ** tree, struct element * node) +{ + if (NULL != node && NULL != node->parent) { + deleteCase2(tree, node); + } +} + +void +deleteOneChild(struct element ** tree, struct element * node) +{ + /* + * Precondition: n has at most one non-null child. + */ + struct element * child = (NULL == node->right) ? node->left : node->right; + + replaceNode(node, child); + + if (node->color == rbBlack) { + if (NULL != child && child->color == rbRed) { + child->color = rbBlack; + } else { + deleteCase1(tree, child); + } + } + + if (NULL == node->parent){ + *tree = 0x0; + } + free(node); +} + + + /** * ======================================================================= */ @@ -479,16 +664,6 @@ main(int argc, char * argv[]) * Looks like the insert works properly. * So the problem is out traversing... */ - // puts("elements:"); - // for (i=1; i<20; i++) { - // struct element * element = findElement(root, i); - // printf("Element %02d: n=0x%p p=0x%p l=0x%p r=0x%p\n", - // i, - // element, - // element ? element->parent : 0x0, - // element ? element->left : 0x0, - // element ? element->right : 0x0); - // } puts("traverse"); traverse(root1, printElement); @@ -513,6 +688,38 @@ main(int argc, char * argv[]) puts("traverse"); traverse(root2, printElement); + deleteElement(&root2, 8); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 11); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 13); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 3); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 16); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 10); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 9); + puts("traverse"); + traverse(root2, printElement); + + deleteElement(&root2, 12); + puts("traverse"); + traverse(root2, printElement); + return 0; } From 5ea16b6227b3714be26d4561fe1df75792f43065 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Fri, 23 Aug 2013 16:26:19 +0100 Subject: [PATCH 57/97] now the memory is freed outside the tree delete function.... --- src/rbtree.c | 184 ++++++++++++--------------------------------------- 1 file changed, 43 insertions(+), 141 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index 2228caf..33a2e0c 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -109,9 +109,9 @@ findInOrderSuccessor(struct element * tree) return node; } -void deleteOneChild(struct element **, struct element *); +struct element * deleteOneChild(struct element **, struct element *); -void +struct element * deleteElement(struct element ** tree, int data) { struct element * node = *tree; @@ -127,11 +127,11 @@ deleteElement(struct element ** tree, int data) // element not found if (NULL == node) { - return; + return node; } - // distinuish 3 cases, where the resolving of each case leads to the - // precondition of the other. + // now our cases follows...the first one is the same as with + // simple binary search trees. // case 1: two children if (NULL != node->left && NULL != node->right) { @@ -141,59 +141,7 @@ deleteElement(struct element ** tree, int data) node = successor; } - /* - * In rb trees we handle the remaining situations differently - */ - /* - // case 2: one child wither left or right - if (NULL != node->left) { - //node->data = node->left->data; - //node = node->left; - if (NULL != node->parent) { - if (node == node->parent->left) { - node->parent->left = node->left; - } else { - node->parent->right = node->left; - } - } - node->left->parent = node->parent; - } - - if (NULL != node->right) { - //node->data = node->right->data; - //node = node->right; - if (NULL != node->parent) { - if (node == node->parent->left) { - node->parent->left = node->right; - } else { - node->parent->right = node->right; - } - } - node->right->parent = node->parent; - } - - // case 3: we are a leaf - if (NULL != node->parent) { - if (node == node->parent->left) { - node->parent->left = NULL; - } else { - node->parent->right = NULL; - } - } - - if (node == *tree) { - if (NULL != node->left) { - *tree = node->left; - } else if (NULL != node->right) { - *tree = node->right; - } else { - *tree = NULL; - } - } - - free(node); - */ - deleteOneChild(tree, node); + return deleteOneChild(tree, node); } @@ -586,7 +534,7 @@ deleteCase1(struct element ** tree, struct element * node) } } -void +struct element * deleteOneChild(struct element ** tree, struct element * node) { /* @@ -607,7 +555,8 @@ deleteOneChild(struct element ** tree, struct element * node) if (NULL == node->parent){ *tree = 0x0; } - free(node); + + return node; } @@ -618,107 +567,60 @@ deleteOneChild(struct element ** tree, struct element * node) int main(int argc, char * argv[]) { - struct element * root1 = NULL; - struct element * root2 = NULL; + struct element * root = NULL; struct element * inserted = NULL; - insertElement(&root1, 13); - insertElement(&root1, 8); - insertElement(&root1, 16); - insertElement(&root1, 11); - insertElement(&root1, 3); - insertElement(&root1, 9); - insertElement(&root1, 12); - insertElement(&root1, 10); - - /* - * after this I have the following: - * - * Element 03: n=0x0xcf50d0 p=0x0xcf5040 l=0x(nil) r=0x(nil) - * Element 08: n=0x0xcf5040 p=0x0xcf5010 l=0x0xcf50d0 r=0x0xcf50a0 - * Element 09: n=0x0xcf5100 p=0x0xcf50a0 l=0x(nil) r=0x0xcf5160 - * Element 10: n=0x0xcf5160 p=0x0xcf5100 l=0x(nil) r=0x(nil) - * Element 11: n=0x0xcf50a0 p=0x0xcf5040 l=0x0xcf5100 r=0x0xcf5130 - * Element 12: n=0x0xcf5130 p=0x0xcf50a0 l=0x(nil) r=0x(nil) - * Element 13: n=0x0xcf5010 p=0x(nil) l=0x0xcf5040 r=0x0xcf5070 - * Element 16: n=0x0xcf5070 p=0x0xcf5010 l=0x(nil) r=0x(nil) - * - * which translates to: - * - * 03 has p:08, l:N , R:N - * 08 has p:13, l:03, r:11 - * 09 has p:11, l:N , r:10 - * 10 has p:09, l:N , r:N - * 11 has p:08, l:09, r:12 - * 12 has p:11, l:N , r:N - * 13 has p:N , l:08, r:16 - * 16 has p:13, l:N , r:N - * - * which visualizes as: - * 13 - * 08 16 - * 03 11 0 0 - * 0 0 09 12 - * 0 10 0 0 - * - * Looks like the insert works properly. - * So the problem is out traversing... - */ - - puts("traverse"); - traverse(root1, printElement); - - inserted = insertElement(&root2, 13); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 8); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 16); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 11); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 3); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 9); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 12); - insertCase1(&root2, inserted); - inserted = insertElement(&root2, 10); - insertCase1(&root2, inserted); + inserted = insertElement(&root, 13); + insertCase1(&root, inserted); + inserted = insertElement(&root, 8); + insertCase1(&root, inserted); + inserted = insertElement(&root, 16); + insertCase1(&root, inserted); + inserted = insertElement(&root, 11); + insertCase1(&root, inserted); + inserted = insertElement(&root, 3); + insertCase1(&root, inserted); + inserted = insertElement(&root, 9); + insertCase1(&root, inserted); + inserted = insertElement(&root, 12); + insertCase1(&root, inserted); + inserted = insertElement(&root, 10); + insertCase1(&root, inserted); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 8); + free(deleteElement(&root, 8)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 11); + free(deleteElement(&root, 11)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 13); + free(deleteElement(&root, 13)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 3); + free(deleteElement(&root, 3)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 16); + free(deleteElement(&root, 16)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 10); + free(deleteElement(&root, 10)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 9); + free(deleteElement(&root, 9)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); - deleteElement(&root2, 12); + free(deleteElement(&root, 12)); puts("traverse"); - traverse(root2, printElement); + traverse(root, printElement); return 0; } From a543ed85382869978df97cae6ad2eddd2a79a7a9 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Sat, 24 Aug 2013 08:50:24 +0100 Subject: [PATCH 58/97] all insert cases merged in one insertElement function. --- src/rbtree.c | 408 +++++++++++++++++++++++---------------------------- 1 file changed, 184 insertions(+), 224 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index 33a2e0c..b9d9a4e 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -50,40 +50,195 @@ findElement(struct element * tree, int data) return tree; } +/* + * function to get specific elements needed for + * rb handling, grandparent, uncle and sibbling + */ +struct element * +grandparent(struct element * node) +{ + if (NULL != node && NULL != node->parent) { + return node->parent->parent; + } + + return NULL; +} + +struct element * +uncle(struct element * node) +{ + struct element * gp = grandparent(node); + + if (NULL == gp) { + return NULL; + } + + if (node->parent == gp->left) { + return gp->right; + } + + return gp->left; +} + +struct element * +sibling(struct element * node) +{ + return (node == node->parent->left) ? + node->parent->right : + node->parent->left; +} + +/* + * rotations...also needed for rb handling. + */ +void +rotateLeft(struct element ** tree, struct element * node) +{ + struct element * rightChild = node->right; + struct element * rcLeftSub = node->right->left; + + rightChild->left = node; + rightChild->parent = node->parent; + node->right = rcLeftSub; + rcLeftSub->parent = node; + + if (node->parent) { + if (node->parent->left == node) { + node->parent->left = rightChild; + } else { + node->parent->right = rightChild; + } + } else { + *tree = rightChild; + } + + node->parent = rightChild; +} + +void +rotateRight(struct element ** tree, struct element * node) +{ + struct element * leftChild = node->left; + struct element * lcRightSub = node->left->right; + + leftChild->right = node; + leftChild->parent = node->parent; + node->left = lcRightSub; + lcRightSub->parent = node; + + if (node->parent) { + if (node->parent->left == node) { + node->parent->left = leftChild; + } else { + node->parent->right = leftChild; + } + } else { + *tree = leftChild; + } + + node->parent = leftChild; +} + /** * insert element in tree */ struct element * insertElement(struct element ** tree, int data) { - struct element * node = *tree; + struct element * node = *tree; + struct element * new_node = NULL; + struct element * u; + struct element * g; + // if tree is empty it's simple... :) if (NULL == node) { - *tree = newElement(data); - return *tree; + *tree = node = new_node = newElement(data); + } else { + // normal binary tree add.... + while (data != node->data) { + if (data < node->data) { + if (NULL == node->left) { + node->left = newElement(data); + node->left->parent = node; + new_node = node = node->left; + break; + } else { + node = node->left; + } + } else { + if (NULL == node->right) { + node->right = newElement(data); + node->right->parent = node; + new_node = node = node->right; + break; + } else { + node = node->right; + } + } + } } - while (data != node->data) { - if (data < node->data) { - if (NULL == node->left) { - node->left = newElement(data); - node->left->parent = node; - return node->left; - } else { - node = node->left; + if (NULL != new_node) { + /* + * handle reballancing rb style + */ + while (1) { + // case 1 + if (node->parent == NULL) { + node->color = rbBlack; + // we're done.... :) + break; } - } else { - if (NULL == node->right) { - node->right = newElement(data); - node->right->parent = node; - return node->right; + + // case 2 + if (node->parent->color == rbBlack) { + // Tree is still valid ... wow, again we're done... :) + break; + } + + // case 3 + u = uncle(node); + g = grandparent(node); + + if ((u != NULL) && (u->color == rbRed)) { + node->parent->color = rbBlack; + u->color = rbBlack; + g->color = rbRed; + + node = g; + continue; + } + + // case 4 + if ((node == node->parent->right) && (node->parent == g->left)) { + rotateLeft(tree, node->parent); + node = node->left; + } else if ( + (node == node->parent->left) && + (node->parent == g->right)) { + + rotateRight(tree, node->parent); + node = node->right; + } + + // case 5 + g = grandparent(node); + + node->parent->color = rbBlack; + g->color = rbRed; + + if (node == node->parent->left) { + rotateRight(tree, g); } else { - node = node->right; + rotateLeft(tree, g); } + + // we're done.. + break; } } - return NULL; + return new_node; } /** @@ -205,194 +360,6 @@ void printElement(int data, int depth) } -/* - * rbinsert from wikipedia...see later if this could be - * optiized. - */ -struct element * -grandparent(struct element * node) -{ - if (NULL != node && NULL != node->parent) { - return node->parent->parent; - } - - return NULL; -} - -struct element * -uncle(struct element * node) -{ - struct element * gp = grandparent(node); - - if (NULL == gp) { - return NULL; - } - - if (node->parent == gp->left) { - return gp->right; - } - - return gp->left; -} - -struct element * -sibling(struct element * node) -{ - if (node == node->parent->left) - return node->parent->right; - else - return node->parent->left; -} - - -void -rotateLeft(struct element ** tree, struct element * node) -{ - struct element * rightChild = node->right; - struct element * rcLeftSub = node->right->left; - - rightChild->left = node; - rightChild->parent = node->parent; - node->right = rcLeftSub; - rcLeftSub->parent = node; - - if (node->parent) { - if (node->parent->left == node) { - node->parent->left = rightChild; - } else { - node->parent->right = rightChild; - } - } else { - *tree = rightChild; - } - - node->parent = rightChild; -} - -void -rotateRight(struct element ** tree, struct element * node) -{ - struct element * leftChild = node->left; - struct element * lcRightSub = node->left->right; - - leftChild->right = node; - leftChild->parent = node->parent; - node->left = lcRightSub; - lcRightSub->parent = node; - - if (node->parent) { - if (node->parent->left == node) { - node->parent->left = leftChild; - } else { - node->parent->right = leftChild; - } - } else { - *tree = leftChild; - } - - node->parent = leftChild; -} - -void -insertCase5(struct element ** tree, struct element * node) -{ - struct element *g = grandparent(node); - - node->parent->color = rbBlack; - g->color = rbRed; - - if (node == node->parent->left) { - rotateRight(tree, g); - } else { - rotateLeft(tree, g); - } -} - -void -insertCase4(struct element ** tree, struct element * node) -{ - struct element * g = grandparent(node); - - if ((node == node->parent->right) && (node->parent == g->left)) { - rotateLeft(tree, node->parent); - - /* - * rotate_left can be the below because of already - * having *g = grandparent(n) - * - * struct node *saved_p=g->left, *saved_left_n=n->left; - * g->left=n; - * n->left=saved_p; - * saved_p->right=saved_left_n; - * - * and modify the parent's nodes properly - */ - node = node->left; - - } else if ( - (node == node->parent->left) && - (node->parent == g->right)) { - - rotateRight(tree, node->parent); - - /* - * rotate_right can be the below to take advantage - * of already having *g = grandparent(n) - * - * struct node *saved_p=g->right, *saved_right_n=n->right; - * g->right=n; - * n->right=saved_p; - * saved_p->left=saved_right_n; - * - */ - node = node->right; - } - - insertCase5(tree, node); -} - -void insertCase1(struct element **, struct element *); - -void -insertCase3(struct element ** tree, struct element * node) -{ - struct element * u = uncle(node); - struct element * g; - - if ((u != NULL) && (u->color == rbRed)) { - node->parent->color = rbBlack; - u->color = rbBlack; - g = grandparent(node); - g->color = rbRed; - - insertCase1(tree, g); - } else { - insertCase4(tree, node); - } -} - -void -insertCase2(struct element ** tree, struct element * node) -{ - if (node->parent->color == rbBlack) { - return; - // Tree is still valid ... wow, again we're done... :) - } else { - insertCase3(tree, node); - } -} - -void -insertCase1(struct element ** tree, struct element * node) -{ - if (node->parent == NULL) { - node->color = rbBlack; - // we're done.... :) - } else { - insertCase2(tree, node); - } -} - void replaceNode(struct element * node1, struct element * node2) { @@ -568,28 +535,20 @@ int main(int argc, char * argv[]) { struct element * root = NULL; - struct element * inserted = NULL; - - inserted = insertElement(&root, 13); - insertCase1(&root, inserted); - inserted = insertElement(&root, 8); - insertCase1(&root, inserted); - inserted = insertElement(&root, 16); - insertCase1(&root, inserted); - inserted = insertElement(&root, 11); - insertCase1(&root, inserted); - inserted = insertElement(&root, 3); - insertCase1(&root, inserted); - inserted = insertElement(&root, 9); - insertCase1(&root, inserted); - inserted = insertElement(&root, 12); - insertCase1(&root, inserted); - inserted = insertElement(&root, 10); - insertCase1(&root, inserted); + insertElement(&root, 13); + insertElement(&root, 8); + insertElement(&root, 16); + insertElement(&root, 11); + insertElement(&root, 3); + insertElement(&root, 9); + insertElement(&root, 12); + insertElement(&root, 10); + puts("traverse"); traverse(root, printElement); + /* free(deleteElement(&root, 8)); puts("traverse"); traverse(root, printElement); @@ -621,6 +580,7 @@ main(int argc, char * argv[]) free(deleteElement(&root, 12)); puts("traverse"); traverse(root, printElement); + */ return 0; } From 52755ca9e98ac51375626c1556b89b38de829ee1 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Sat, 24 Aug 2013 12:04:00 +0100 Subject: [PATCH 59/97] realize that delete does not work correct. --- src/binarytree.c | 76 ++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/src/binarytree.c b/src/binarytree.c index 652faaf..ee48666 100644 --- a/src/binarytree.c +++ b/src/binarytree.c @@ -246,7 +246,6 @@ void printElement(int data, int depth) int main(int argc, char * argv[]) { - int i; struct element * root = NULL; insertElement(&root, 13); @@ -259,49 +258,42 @@ main(int argc, char * argv[]) insertElement(&root, 10); /* - * after this I have the following: - * - * Element 03: n=0x0xcf50d0 p=0x0xcf5040 l=0x(nil) r=0x(nil) - * Element 08: n=0x0xcf5040 p=0x0xcf5010 l=0x0xcf50d0 r=0x0xcf50a0 - * Element 09: n=0x0xcf5100 p=0x0xcf50a0 l=0x(nil) r=0x0xcf5160 - * Element 10: n=0x0xcf5160 p=0x0xcf5100 l=0x(nil) r=0x(nil) - * Element 11: n=0x0xcf50a0 p=0x0xcf5040 l=0x0xcf5100 r=0x0xcf5130 - * Element 12: n=0x0xcf5130 p=0x0xcf50a0 l=0x(nil) r=0x(nil) - * Element 13: n=0x0xcf5010 p=0x(nil) l=0x0xcf5040 r=0x0xcf5070 - * Element 16: n=0x0xcf5070 p=0x0xcf5010 l=0x(nil) r=0x(nil) - * - * which translates to: - * - * 03 has p:08, l:N , R:N - * 08 has p:13, l:03, r:11 - * 09 has p:11, l:N , r:10 - * 10 has p:09, l:N , r:N - * 11 has p:08, l:09, r:12 - * 12 has p:11, l:N , r:N - * 13 has p:N , l:08, r:16 - * 16 has p:13, l:N , r:N - * - * which visualizes as: - * 13 - * 08 16 - * 03 11 0 0 - * 0 0 09 12 - * 0 10 0 0 - * - * Looks like the insert works properly. - * So the problem is out traversing... + * delete does not work correctly here.. + * luckily I do not need the simple binary trees anymore + * as I have rbtrees. */ - puts("elements:"); - for (i=1; i<20; i++) { - struct element * element = findElement(root, i); - printf("Element %02d: n=0x%p p=0x%p l=0x%p r=0x%p\n", - i, - element, - element ? element->parent : 0x0, - element ? element->left : 0x0, - element ? element->right : 0x0); - } + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 8); + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 11); + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 13); + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 3); + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 16); + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 10); + puts("traverse"); + traverse(root, printElement); + + deleteElement(&root, 9); + puts("traverse"); + traverse(root, printElement); + deleteElement(&root, 12); puts("traverse"); traverse(root, printElement); From ef6ccfbcbe379737fc4b3d52388f28f8d6192806 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Sat, 24 Aug 2013 12:04:55 +0100 Subject: [PATCH 60/97] rbtree insert and delete now as one function and working as expected...still has to be checked on sideeffects. --- src/rbtree.c | 333 +++++++++++++++++++++++---------------------------- 1 file changed, 153 insertions(+), 180 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index b9d9a4e..54e68ca 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -89,7 +89,7 @@ sibling(struct element * node) } /* - * rotations...also needed for rb handling. + * tree modifications...needed for rb handling. */ void rotateLeft(struct element ** tree, struct element * node) @@ -139,6 +139,23 @@ rotateRight(struct element ** tree, struct element * node) node->parent = leftChild; } +void +replaceNode(struct element * node1, struct element * node2) +{ + if (NULL != node1->parent) { + if (node1 == node1->parent->left) { + node1->parent->left = node2; + } else { + node1->parent->right = node2; + } + } + + if (NULL != node2) { + node2->parent = node1->parent; + } +} + + /** * insert element in tree */ @@ -269,7 +286,10 @@ struct element * deleteOneChild(struct element **, struct element *); struct element * deleteElement(struct element ** tree, int data) { - struct element * node = *tree; + struct element * node = *tree; + struct element * del_node; + struct element * child; + struct element * s; // find the relevant node and it's parent while (NULL != node && node->data != data) { @@ -285,27 +305,150 @@ deleteElement(struct element ** tree, int data) return node; } + del_node = node; + // now our cases follows...the first one is the same as with - // simple binary search trees. + // simple binary search trees. Two non null children. // case 1: two children if (NULL != node->left && NULL != node->right) { struct element * successor = findInOrderSuccessor(node); node->data = successor->data; - node = successor; + del_node = node = successor; + } + + // delete and rb rebalance... + while(1) { + // Precondition: n has at most one non-null child. + child = (NULL == node->right) ? node->left : node->right; + replaceNode(node, child); + + // delete one child case + // TODO this is overly complex as simply derived from the function... + // maybe this can be simplified. Maybe not...check. + if (node->color == rbBlack) { + if (NULL != child && child->color == rbRed) { + child->color = rbBlack; + // done despite modifying tree itself if neccessary.. + break; + } else { + if (NULL == node->parent){ + *tree = 0x0; + } + node = child; + } + } else { + if (NULL == node->parent){ + *tree = 0x0; + } + break; + } + + // case 1 + if (NULL == node || NULL == node->parent) { + // done again + break; + } + + // case 2 + s = sibling(node); + + if (NULL != s && s->color == rbRed) { + node->parent->color = rbRed; + s->color = rbBlack; + + if (node == node->parent->left) { + rotateLeft(tree, node->parent); + } else { + rotateRight(tree, node->parent); + } + } + + // case 3 / 4 + if (NULL == s || ((s->color == rbBlack) && + (s->left->color == rbBlack) && + (s->right->color == rbBlack))) { + + if (NULL != s) { + s->color = rbRed; + } + + if (node->parent->color == rbBlack) { + // case 3 + node = node->parent; + continue; + } else { + // case 4 + node->parent->color = rbBlack; + // and done again... + break; + } + } else { + // done... + break; + } + + + // case 5 + if (NULL != s && s->color == rbBlack) { + // this if statement is trivial, + // due to case 2 (even though case 2 changed the sibling to a + // sibling's child, + // the sibling's child can't be red, since no red parent can + // have a red child). + // + // the following statements just force the red to be on the + // left of the left of the parent, + // or right of the right, so case 6 will rotate correctly. + if ((node == node->parent->left) && + (s->right->color == rbBlack) && + (s->left->color == rbRed)) { + + // this last test is trivial too due to cases 2-4. + s->color = rbRed; + s->left->color = rbBlack; + + rotateRight(tree, s); + } else if ((node == node->parent->right) && + (s->left->color == rbBlack) && + (s->right->color == rbRed)) { + // this last test is trivial too due to cases 2-4. + s->color = rbRed; + s->right->color = rbBlack; + + rotateLeft(tree, s); + } + } + + // case 6 + s->color = node->parent->color; + node->parent->color = rbBlack; + + if (node == node->parent->left) { + s->right->color = rbBlack; + rotateLeft(tree, node->parent); + } else { + s->left->color = rbBlack; + rotateRight(tree, node->parent); + } + + // done... + break; } + + //deleteOneChild(tree, node); - return deleteOneChild(tree, node); + return del_node; } void -traverse(struct element * tree, void (*cb)(int, int)) +traverse(struct element * tree, void (*cb)(int, int, enum rbColor)) { struct element * previous = tree; struct element * node = tree; - int depth = 1; + int depth = 1; /* * I think this has something like O(n+log(n)) on a ballanced @@ -329,7 +472,7 @@ traverse(struct element * tree, void (*cb)(int, int)) * If there are no more elements to the left or we * came from the left, process data. */ - cb(node->data, depth); + cb(node->data, depth, node->color); previous = node; if (NULL != node->right) { @@ -350,184 +493,16 @@ traverse(struct element * tree, void (*cb)(int, int)) } } -void printElement(int data, int depth) +void printElement(int data, int depth, enum rbColor color) { int i; - printf("%02d(%02d)", data, depth); + printf("%s %02d(%02d)", (color==rbRed)?"R":"B", data, depth); for (i=0; iparent) { - if (node1 == node1->parent->left) { - node1->parent->left = node2; - } else { - node1->parent->right = node2; - } - } - - if (NULL != node2) { - node2->parent = node1->parent; - } -} - -void -deleteCase6(struct element ** tree, struct element * node) -{ - struct element * s = sibling(node); - - s->color = node->parent->color; - node->parent->color = rbBlack; - - if (node == node->parent->left) { - s->right->color = rbBlack; - rotateLeft(tree, node->parent); - } else { - s->left->color = rbBlack; - rotateRight(tree, node->parent); - } -} - -void -deleteCase5(struct element ** tree, struct element * node) -{ - struct element * s = sibling(node); - - if (NULL != s && s->color == rbBlack) { - /* - * this if statement is trivial, - * due to case 2 (even though case 2 changed the sibling to a - * sibling's child, - * the sibling's child can't be red, since no red parent can - * have a red child). - */ - /* - * the following statements just force the red to be on the - * left of the left of the parent, - * or right of the right, so case six will rotate correctly. - */ - if ((node == node->parent->left) && - (s->right->color == rbBlack) && - (s->left->color == rbRed)) { - - /* this last test is trivial too due to cases 2-4. */ - s->color = rbRed; - s->left->color = rbBlack; - - rotateRight(tree, s); - } else if ((node == node->parent->right) && - (s->left->color == rbBlack) && - (s->right->color == rbRed)) { - /* - * this last test is trivial too due to cases 2-4. - */ - s->color = rbRed; - s->right->color = rbBlack; - - rotateLeft(tree, s); - } - } - - deleteCase6(tree, node); -} - -void -deleteCase4(struct element ** tree, struct element * node) -{ - struct element * s = sibling(node); - - if ((node->parent->color == rbRed) && - (NULL == s || ((s->color == rbBlack) && - (s->left->color == rbBlack) && - (s->right->color == rbBlack)))) { - if (NULL != s) { - s->color = rbRed; - } - node->parent->color = rbBlack; - } else { - deleteCase5(tree, node); - } -} - -void deleteCase1(struct element **, struct element *); - -void -deleteCase3(struct element ** tree, struct element * node) -{ - struct element * s = sibling(node); - - if ((node->parent->color == rbBlack) && - (NULL == s || ((s->color == rbBlack) && - (s->left->color == rbBlack) && - (s->right->color == rbBlack)))) { - if (NULL != s) { - s->color = rbRed; - } - deleteCase1(tree, node->parent); - } else { - deleteCase4(tree, node); - } -} - -void -deleteCase2(struct element ** tree, struct element * node) -{ - struct element * s = sibling(node); - - if (NULL != s && s->color == rbRed) { - node->parent->color = rbRed; - s->color = rbBlack; - - if (node == node->parent->left) { - rotateLeft(tree, node->parent); - } else { - rotateRight(tree, node->parent); - } - } - - deleteCase3(tree, node); -} - -void -deleteCase1(struct element ** tree, struct element * node) -{ - if (NULL != node && NULL != node->parent) { - deleteCase2(tree, node); - } -} - -struct element * -deleteOneChild(struct element ** tree, struct element * node) -{ - /* - * Precondition: n has at most one non-null child. - */ - struct element * child = (NULL == node->right) ? node->left : node->right; - - replaceNode(node, child); - - if (node->color == rbBlack) { - if (NULL != child && child->color == rbRed) { - child->color = rbBlack; - } else { - deleteCase1(tree, child); - } - } - - if (NULL == node->parent){ - *tree = 0x0; - } - - return node; -} - - - /** * ======================================================================= */ @@ -548,7 +523,6 @@ main(int argc, char * argv[]) puts("traverse"); traverse(root, printElement); - /* free(deleteElement(&root, 8)); puts("traverse"); traverse(root, printElement); @@ -580,7 +554,6 @@ main(int argc, char * argv[]) free(deleteElement(&root, 12)); puts("traverse"); traverse(root, printElement); - */ return 0; } From 06266ef541b61b051000897488efd77e2422773e Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 27 Aug 2013 10:01:46 +0100 Subject: [PATCH 61/97] update todo and make my rbtree implementation use externally allocated elements. --- TODO | 4 +- src/rbtree.c | 259 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 154 insertions(+), 109 deletions(-) diff --git a/TODO b/TODO index a79ee16..0c9bd75 100644 --- a/TODO +++ b/TODO @@ -8,4 +8,6 @@ VERY BIG TODO: - IPV6 support - There seem to be a problem in the server under heavy load. Some tests with ab show that at some point it does not accept any more connections. Nor does it seem to answer request. I guess that it might be difficult to find this.... - => might be done... + => might be done... maybe not completely, I still loose connections under very high load. + +- using tsearch for my memory management was kind of a bad idea. tsearch uses malloc and free upon addition and remove of elements. Resulting again in uncontroolled heap usage. I guess I have to implement my own tree mechanism here, which does not involve further allocation. diff --git a/src/rbtree.c b/src/rbtree.c index 54e68ca..218eaeb 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -1,6 +1,8 @@ #include #include +#include +#define NVALUES 10 enum rbColor {rbBlack=1, rbRed=2}; @@ -19,14 +21,15 @@ struct element struct element * newElement(int data) { - struct element * node = malloc(sizeof(struct element)); - node->data = data; - node->color = rbRed; - node->parent = NULL; - node->left = NULL; - node->right = NULL; + struct element * element = malloc(sizeof(struct element)); - return node; + element->data = data; + element->color = rbRed; + element->parent = NULL; + element->left = NULL; + element->right = NULL; + + return element; } /** @@ -83,9 +86,15 @@ uncle(struct element * node) struct element * sibling(struct element * node) { - return (node == node->parent->left) ? - node->parent->right : - node->parent->left; + if (NULL == node) { + return NULL; + } + + if (NULL == node->parent->left || node == node->parent->left) { + return node->parent->right; + } else { + return node->parent->left; + } } /* @@ -100,7 +109,9 @@ rotateLeft(struct element ** tree, struct element * node) rightChild->left = node; rightChild->parent = node->parent; node->right = rcLeftSub; - rcLeftSub->parent = node; + if (NULL != rcLeftSub) { + rcLeftSub->parent = node; + } if (node->parent) { if (node->parent->left == node) { @@ -124,7 +135,9 @@ rotateRight(struct element ** tree, struct element * node) leftChild->right = node; leftChild->parent = node->parent; node->left = lcRightSub; - lcRightSub->parent = node; + if (NULL != lcRightSub) { + lcRightSub->parent = node; + } if (node->parent) { if (node->parent->left == node) { @@ -140,7 +153,10 @@ rotateRight(struct element ** tree, struct element * node) } void -replaceNode(struct element * node1, struct element * node2) +replaceNode( + struct element ** tree, + struct element * node1, + struct element * node2) { if (NULL != node1->parent) { if (node1 == node1->parent->left) { @@ -148,6 +164,8 @@ replaceNode(struct element * node1, struct element * node2) } else { node1->parent->right = node2; } + } else { + *tree = node2; } if (NULL != node2) { @@ -160,7 +178,7 @@ replaceNode(struct element * node1, struct element * node2) * insert element in tree */ struct element * -insertElement(struct element ** tree, int data) +insertElement(struct element ** tree, struct element * element) { struct element * node = *tree; struct element * new_node = NULL; @@ -169,28 +187,30 @@ insertElement(struct element ** tree, int data) // if tree is empty it's simple... :) if (NULL == node) { - *tree = node = new_node = newElement(data); + *tree = node = new_node = element; } else { // normal binary tree add.... - while (data != node->data) { - if (data < node->data) { + while (element->data != node->data) { + if (element->data < node->data) { if (NULL == node->left) { - node->left = newElement(data); + node->left = element; node->left->parent = node; new_node = node = node->left; break; } else { node = node->left; } - } else { + } else if (element->data > node->data) { if (NULL == node->right) { - node->right = newElement(data); + node->right = element; node->right->parent = node; new_node = node = node->right; break; } else { node = node->right; } + } else { + return node; } } } @@ -217,7 +237,7 @@ insertElement(struct element ** tree, int data) u = uncle(node); g = grandparent(node); - if ((u != NULL) && (u->color == rbRed)) { + if (u != NULL && u->color == rbRed) { node->parent->color = rbBlack; u->color = rbBlack; g->color = rbRed; @@ -227,12 +247,10 @@ insertElement(struct element ** tree, int data) } // case 4 - if ((node == node->parent->right) && (node->parent == g->left)) { + if (node == node->parent->right && node->parent == g->left) { rotateLeft(tree, node->parent); node = node->left; - } else if ( - (node == node->parent->left) && - (node->parent == g->right)) { + } else if (node == node->parent->left && node->parent == g->right) { rotateRight(tree, node->parent); node = node->right; @@ -284,7 +302,7 @@ findInOrderSuccessor(struct element * tree) struct element * deleteOneChild(struct element **, struct element *); struct element * -deleteElement(struct element ** tree, int data) +deleteElement(struct element ** tree, struct element * element) { struct element * node = *tree; struct element * del_node; @@ -292,8 +310,8 @@ deleteElement(struct element ** tree, int data) struct element * s; // find the relevant node and it's parent - while (NULL != node && node->data != data) { - if (data < node->data) { + while (NULL != node && node->data != element->data) { + if (element->data < node->data) { node = node->left; } else { node = node->right; @@ -318,35 +336,35 @@ deleteElement(struct element ** tree, int data) del_node = node = successor; } - // delete and rb rebalance... - while(1) { - // Precondition: n has at most one non-null child. - child = (NULL == node->right) ? node->left : node->right; - replaceNode(node, child); - - // delete one child case - // TODO this is overly complex as simply derived from the function... - // maybe this can be simplified. Maybe not...check. - if (node->color == rbBlack) { - if (NULL != child && child->color == rbRed) { - child->color = rbBlack; - // done despite modifying tree itself if neccessary.. - break; - } else { - if (NULL == node->parent){ - *tree = 0x0; - } - node = child; - } + // Precondition: n has at most one non-null child. + child = (NULL == node->right) ? node->left : node->right; + replaceNode(tree, node, child); + + // delete one child case + // TODO this is overly complex as simply derived from the function... + // maybe this can be simplified. Maybe not...check. + if (node->color == rbBlack) { + if (NULL != child && child->color == rbRed) { + child->color = rbBlack; + // done despite modifying tree itself if neccessary.. + return del_node; } else { - if (NULL == node->parent){ - *tree = 0x0; + if (NULL != child) { + node = child; + } else { + node->color = rbBlack; + node->left = NULL; + node->right = NULL; } - break; } + } else { + return del_node; + } + // delete and rb rebalance... + while(1) { // case 1 - if (NULL == node || NULL == node->parent) { + if (NULL == node->parent) { // done again break; } @@ -358,17 +376,23 @@ deleteElement(struct element ** tree, int data) node->parent->color = rbRed; s->color = rbBlack; - if (node == node->parent->left) { + /* + * detect which child we are...assumption + * if we are not parent->right and parent->right is not + * null we must be left, even if its set to NULL previously + */ + if (NULL != node->parent->right && node != node->parent->right) { rotateLeft(tree, node->parent); } else { rotateRight(tree, node->parent); } } + s = sibling(node); // case 3 / 4 if (NULL == s || ((s->color == rbBlack) && - (s->left->color == rbBlack) && - (s->right->color == rbBlack))) { + (NULL == s->left || s->left->color == rbBlack) && + (NULL == s->right || s->right->color == rbBlack))) { if (NULL != s) { s->color = rbRed; @@ -384,12 +408,8 @@ deleteElement(struct element ** tree, int data) // and done again... break; } - } else { - // done... - break; } - // case 5 if (NULL != s && s->color == rbBlack) { // this if statement is trivial, @@ -402,8 +422,8 @@ deleteElement(struct element ** tree, int data) // left of the left of the parent, // or right of the right, so case 6 will rotate correctly. if ((node == node->parent->left) && - (s->right->color == rbBlack) && - (s->left->color == rbRed)) { + (NULL == s->right || s->right->color == rbBlack) && + (NULL != s->left && s->left->color == rbRed)) { // this last test is trivial too due to cases 2-4. s->color = rbRed; @@ -411,8 +431,8 @@ deleteElement(struct element ** tree, int data) rotateRight(tree, s); } else if ((node == node->parent->right) && - (s->left->color == rbBlack) && - (s->right->color == rbRed)) { + (NULL == s->left || s->left->color == rbBlack) && + (NULL != s->right && s->right->color == rbRed)) { // this last test is trivial too due to cases 2-4. s->color = rbRed; s->right->color = rbBlack; @@ -421,16 +441,31 @@ deleteElement(struct element ** tree, int data) } } + s = sibling(node); // case 6 - s->color = node->parent->color; - node->parent->color = rbBlack; + if (NULL != s) { + s->color = node->parent->color; + } - if (node == node->parent->left) { - s->right->color = rbBlack; - rotateLeft(tree, node->parent); - } else { - s->left->color = rbBlack; - rotateRight(tree, node->parent); + if (NULL != node && NULL != node->parent) { + node->parent->color = rbBlack; + + /* + * detect which child we are...assumption + * if we are not parent->right and parent->right is not + * null we must be left, even if its set to NULL previously + */ + if (NULL != node->parent->right && node != node->parent->right) { + if (NULL != s->right) { + s->right->color = rbBlack; + } + rotateLeft(tree, node->parent); + } else { + if (NULL != s->left) { + s->left->color = rbBlack; + } + rotateRight(tree, node->parent); + } } // done... @@ -509,49 +544,57 @@ void printElement(int data, int depth, enum rbColor color) int main(int argc, char * argv[]) { - struct element * root = NULL; - - insertElement(&root, 13); - insertElement(&root, 8); - insertElement(&root, 16); - insertElement(&root, 11); - insertElement(&root, 3); - insertElement(&root, 9); - insertElement(&root, 12); - insertElement(&root, 10); - - puts("traverse"); - traverse(root, printElement); - - free(deleteElement(&root, 8)); - puts("traverse"); - traverse(root, printElement); - - free(deleteElement(&root, 11)); - puts("traverse"); - traverse(root, printElement); - - free(deleteElement(&root, 13)); - puts("traverse"); - traverse(root, printElement); - - free(deleteElement(&root, 3)); - puts("traverse"); - traverse(root, printElement); + struct element * root = NULL; + int value; + int count; + +// insertElement(&root, newElement(84)); +// insertElement(&root, newElement(87)); +// insertElement(&root, newElement(78)); +// insertElement(&root, newElement(16)); +// insertElement(&root, newElement(94)); +// +// puts("traverse"); +// traverse(root, printElement); +// +// free(deleteElement(&root, findElement(root, 87))); +// puts("traverse"); +// traverse(root, printElement); +// free(deleteElement(&root, findElement(root, 94))); +// puts("traverse"); +// traverse(root, printElement); +// free(deleteElement(&root, findElement(root, 16))); +// puts("traverse"); +// traverse(root, printElement); +// free(deleteElement(&root, findElement(root, 84))); +// puts("traverse"); +// traverse(root, printElement); +// free(deleteElement(&root, findElement(root, 78))); +// puts("traverse"); +// traverse(root, printElement); +// + for (count=0; count Date: Tue, 27 Aug 2013 20:35:14 +0100 Subject: [PATCH 62/97] tree based memory management does not segfault anymore, but reusage does not seem to work, as well as free --- src/rbtree.c | 159 +++++++--- src/utils/memory.c | 745 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 827 insertions(+), 77 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index 218eaeb..64d968d 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -9,7 +9,8 @@ enum rbColor {rbBlack=1, rbRed=2}; struct element { - int data; + size_t size; + void * ptr; enum rbColor color; @@ -19,11 +20,13 @@ struct element }; struct element * -newElement(int data) +newElement(size_t size) { - struct element * element = malloc(sizeof(struct element)); + struct element * element = malloc(size + sizeof(struct element)); + + element->size = size; + element->ptr = element + sizeof(struct element); - element->data = data; element->color = rbRed; element->parent = NULL; element->left = NULL; @@ -36,21 +39,25 @@ newElement(int data) * find element in tree */ struct element * -findElement(struct element * tree, int data) +findElement(struct element * tree, size_t size) { + struct element * fitting = NULL; + while (NULL != tree) { - if (tree->data == data) { + if (tree->size == size) { + fitting = tree; break; } - if (data < tree->data) { - tree = tree->left; - } else { + if (size > tree->size) { tree = tree->right; + } else { + fitting = tree; + tree = tree->left; } } - return tree; + return fitting; } /* @@ -190,8 +197,12 @@ insertElement(struct element ** tree, struct element * element) *tree = node = new_node = element; } else { // normal binary tree add.... - while (element->data != node->data) { - if (element->data < node->data) { + while (element->size != node->size || element->ptr != node->ptr) { + if (element->size < node->size && NULL != node->left) { + node = node->left; + } else if (element->size > node->size && NULL != node->right) { + node = node->right; + } else if (element->ptr < node->ptr) { if (NULL == node->left) { node->left = element; node->left->parent = node; @@ -200,7 +211,7 @@ insertElement(struct element ** tree, struct element * element) } else { node = node->left; } - } else if (element->data > node->data) { + } else if (element->ptr > node->ptr) { if (NULL == node->right) { node->right = element; node->right->parent = node; @@ -286,6 +297,12 @@ insertElement(struct element ** tree, struct element * element) * aka left in-order successor. * We return the parent of the element in the out argument parent. * This can be NULL wenn calling. + * + * 2: *successor = {size = 80, ptr = 0x603ae0, color = rbRed, parent = 0x603160, + * left = 0x0, right = 0x0} + * 1: *node = {size = 70, ptr = 0x603a60, color = rbBlack, parent = 0x603070, + * left = 0x6030e0, right = 0x6031e0} + * */ struct element * findInOrderSuccessor(struct element * tree) @@ -310,8 +327,11 @@ deleteElement(struct element ** tree, struct element * element) struct element * s; // find the relevant node and it's parent - while (NULL != node && node->data != element->data) { - if (element->data < node->data) { + while (NULL != node + && node->size != element->size + && node->ptr != element->ptr) { + + if (element->size < node->size || element->ptr < node->ptr) { node = node->left; } else { node = node->right; @@ -332,8 +352,30 @@ deleteElement(struct element ** tree, struct element * element) if (NULL != node->left && NULL != node->right) { struct element * successor = findInOrderSuccessor(node); - node->data = successor->data; - del_node = node = successor; + enum rbColor tmpcolor = successor->color; + struct element * tmpparent = successor->parent; + struct element * tmpleft = successor->left; + struct element * tmpright = successor->right; + + replaceNode(tree, node, successor); + + successor->color = node->color; + successor->left = node->left; + successor->left->parent = successor; + // the right one might be successor... + if (node->right == successor) { + successor->right = node; + node->parent = successor; + } else { + successor->right = node->right; + node->right->parent = successor; + node->parent = tmpparent; + tmpparent->left = node; + } + + node->color = tmpcolor; + node->left = tmpleft; + node->right = tmpright; } // Precondition: n has at most one non-null child. @@ -479,7 +521,7 @@ deleteElement(struct element ** tree, struct element * element) void -traverse(struct element * tree, void (*cb)(int, int, enum rbColor)) +traverse(struct element * tree, void (*cb)(size_t, void *, int, enum rbColor)) { struct element * previous = tree; struct element * node = tree; @@ -507,7 +549,7 @@ traverse(struct element * tree, void (*cb)(int, int, enum rbColor)) * If there are no more elements to the left or we * came from the left, process data. */ - cb(node->data, depth, node->color); + cb(node->size, node->ptr, depth, node->color); previous = node; if (NULL != node->right) { @@ -528,11 +570,11 @@ traverse(struct element * tree, void (*cb)(int, int, enum rbColor)) } } -void printElement(int data, int depth, enum rbColor color) +void printElement(size_t size, void * ptr, int depth, enum rbColor color) { int i; - printf("%s %02d(%02d)", (color==rbRed)?"R":"B", data, depth); + printf("%s %010zu:0x%p(%02d)", (color==rbRed)?"R":"B", size, ptr, depth); for (i=0; isize, found->ptr, 0, found->color); + } + puts(""); - for (count=0; countsize, found->ptr, 0, found->color); + } + puts(""); - if (NULL != element) { - free(deleteElement(&root, element)); - count++; - } + found = findElement(root, 90); + if (NULL == found) { + printf("can't find segmenet of minimum size: %d\n", 90); + } else { + printElement(found->size, found->ptr, 0, found->color); } + puts(""); + deleteElement(&root, findElement(root, 70)); puts("traverse"); traverse(root, printElement); + puts(""); return 0; } diff --git a/src/utils/memory.c b/src/utils/memory.c index 3df1962..4e2d676 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -22,6 +22,9 @@ * This is not implemented as a class because it will be used in the * process of object creation. * + * The data structure is a balanced tree with size as key. + * Under the size key is a list of elements of the same size. + * * \author Georg Hopp * * \copyright @@ -43,87 +46,721 @@ #define _GNU_SOURCE +#include + #include #include #include #include "utils/memory.h" +enum rbColor {rbBlack=1, rbRed=2}; + +int malloccount = 0; + struct memSegment { size_t size; void * ptr; + + // for address queue + struct memSegment * next; + struct memSegment * last; + + // for rbtree + enum rbColor color; + struct memSegment * parent; + struct memSegment * left; + struct memSegment * right; }; +struct memSegment * +newElement(size_t size) +{ + struct memSegment * element = malloc(size + sizeof(struct memSegment)); + malloccount++; + printf("+"); + + element->size = size; + element->ptr = (void *)element + sizeof(struct memSegment); + + element->next = NULL; + element->last = NULL; -void * segments = NULL; + element->color = rbRed; + element->parent = NULL; + element->left = NULL; + element->right = NULL; + + return element; +} /** - * this will interpret any memory segment that is not smaller - * than the expected size as fitting. - * - * @param void * size_ptr a pointer to a size_t value searched for - * @param void * subject a pointer to the currently analysed tree element + * find element in tree */ -static -int -segmentFindCmp(const void * size_ptr, const void * subject) +struct memSegment * +findElement(struct memSegment * tree, size_t size) { - if (*(size_t *)size_ptr > ((struct memSegment *)subject)->size) - return 1; + struct memSegment * fitting = NULL; + + while (NULL != tree) { + if (tree->size == size) { + fitting = tree; + break; + } - return 0; + if (size > tree->size) { + tree = tree->right; + } else { + fitting = tree; + tree = tree->left; + } + } + + return fitting; } +/* + * function to get specific elements needed for + * rb handling, grandparent, uncle and sibbling + */ +struct memSegment * +grandparent(struct memSegment * node) +{ + if (NULL != node && NULL != node->parent) { + return node->parent->parent; + } + + return NULL; +} + +struct memSegment * +uncle(struct memSegment * node) +{ + struct memSegment * gp = grandparent(node); + + if (NULL == gp) { + return NULL; + } + + if (node->parent == gp->left) { + return gp->right; + } + + return gp->left; +} + +struct memSegment * +sibling(struct memSegment * node) +{ + if (NULL == node) { + return NULL; + } + + if (NULL == node->parent->left || node == node->parent->left) { + return node->parent->right; + } else { + return node->parent->left; + } +} + +/* + * tree modifications...needed for rb handling. + */ +void +rotateLeft(struct memSegment ** tree, struct memSegment * node) +{ + struct memSegment * rightChild = node->right; + struct memSegment * rcLeftSub = node->right->left; + + rightChild->left = node; + rightChild->parent = node->parent; + node->right = rcLeftSub; + if (NULL != rcLeftSub) { + rcLeftSub->parent = node; + } + + if (node->parent) { + if (node->parent->left == node) { + node->parent->left = rightChild; + } else { + node->parent->right = rightChild; + } + } else { + *tree = rightChild; + } + + node->parent = rightChild; +} + +void +rotateRight(struct memSegment ** tree, struct memSegment * node) +{ + struct memSegment * leftChild = node->left; + struct memSegment * lcRightSub = node->left->right; + + leftChild->right = node; + leftChild->parent = node->parent; + node->left = lcRightSub; + if (NULL != lcRightSub) { + lcRightSub->parent = node; + } + + if (node->parent) { + if (node->parent->left == node) { + node->parent->left = leftChild; + } else { + node->parent->right = leftChild; + } + } else { + *tree = leftChild; + } + + node->parent = leftChild; +} + +void +replaceNode( + struct memSegment ** tree, + struct memSegment * node1, + struct memSegment * node2) +{ + if (NULL != node1->parent) { + if (node1 == node1->parent->left) { + node1->parent->left = node2; + } else { + node1->parent->right = node2; + } + } else { + *tree = node2; + } + + if (NULL != node2) { + node2->parent = node1->parent; + } +} + + /** - * this returns exact fits....uhh.....I can't relate solely on - * the size argument as then same sized segments will never - * be stored. - * Maybe a tree is not the best data structure to use to store - * these. - * Anyway, right now take the ptr into account if size if equal. + * insert element in tree */ -static -int -segmentSearchCmp(const void * search, const void * subject) +struct memSegment * +insertElement(struct memSegment ** tree, struct memSegment * element) { - size_t idx = - ((struct memSegment *)search)->size - - ((struct memSegment *)subject)->size; + struct memSegment * node = *tree; + struct memSegment * new_node = NULL; + struct memSegment * u; + struct memSegment * g; - if (0 == idx) { - return - ((struct memSegment *)search)->ptr - - ((struct memSegment *)subject)->ptr; - } + element->color = rbRed; + element->parent = NULL; + element->left = NULL; + element->right = NULL; + element->next = NULL; + element->last = NULL; + + // if tree is empty it's simple... :) + if (NULL == node) { + *tree = node = new_node = element; + } else { + // normal binary tree add.... + while (element->size != node->size) { + if (element->size < node->size) { + if (NULL == node->left) { + node->left = element; + node->left->parent = node; + new_node = node = node->left; + break; + } else { + node = node->left; + } + } else if (element->size > node->size) { + if (NULL == node->right) { + node->right = element; + node->right->parent = node; + new_node = node = node->right; + break; + } else { + node = node->right; + } + } else { + if (NULL == node->next) { + node->next = node->last = element; + } else { + node->last->next = element; + node->last = element; + } + return element; + } + } + } + + if (NULL != new_node) { + /* + * handle reballancing rb style + */ + while (1) { + // case 1 + if (node->parent == NULL) { + node->color = rbBlack; + // we're done.... :) + break; + } + + // case 2 + if (node->parent->color == rbBlack) { + // Tree is still valid ... wow, again we're done... :) + break; + } + + // case 3 + u = uncle(node); + g = grandparent(node); + + if (u != NULL && u->color == rbRed) { + node->parent->color = rbBlack; + u->color = rbBlack; + g->color = rbRed; + + node = g; + continue; + } + + // case 4 + if (node == node->parent->right && node->parent == g->left) { + rotateLeft(tree, node->parent); + node = node->left; + } else if (node == node->parent->left && node->parent == g->right) { + + rotateRight(tree, node->parent); + node = node->right; + } + + // case 5 + g = grandparent(node); + + node->parent->color = rbBlack; + g->color = rbRed; + + if (node == node->parent->left) { + rotateRight(tree, g); + } else { + rotateLeft(tree, g); + } + + // we're done.. + break; + } + } + + return new_node; +} + +/** + * delete element from tree + * here multiple functions are involved.... + * ======================================================================= + */ +/** + * find minimum of the right subtree aka leftmost leaf of right subtree + * aka left in-order successor. + * We return the parent of the element in the out argument parent. + * This can be NULL wenn calling. + */ +struct memSegment * +findInOrderSuccessor(struct memSegment * tree) +{ + struct memSegment * node = tree->right; + + while (NULL != node->left) { + node = node->left; + } - return idx; + return node; } +struct memSegment * deleteOneChild(struct memSegment **, struct memSegment *); + +struct memSegment * +deleteElement(struct memSegment ** tree, struct memSegment * element) +{ + struct memSegment * node = *tree; + struct memSegment * del_node; + struct memSegment * child; + struct memSegment * s; + + // find the relevant node and it's parent + while (NULL != node) { + if (element->size < node->size) { + node = node->left; + } else if (element->size > node->size) { + node = node->right; + } else { + // we know we found our tree element. + if (NULL != node->next) { + // last element. + if (NULL != node->parent) { + if (node->parent->left == node->parent) { + node->parent->left = node->next; + } else { + node->parent->right = node->next; + } + } + + if (NULL != node->left) { + node->left->parent = node->next; + } + + if (NULL != node->right) { + node->right->parent = node->next; + } + + if (node->next == node->last) { + node->next->next = NULL; + node->next->last = NULL; + } else { + node->next->last = node->last; + } + + node->next->parent = node->parent; + node->next->color = node->color; + node->next->left = node->left; + node->next->right = node->right; + + return node; + } + break; + } + } + + // element not found + if (NULL == node) { + return node; + } + + del_node = node; + + // now our cases follows...the first one is the same as with + // simple binary search trees. Two non null children. + + // case 1: two children + if (NULL != node->left && NULL != node->right) { + struct memSegment * successor = findInOrderSuccessor(node); + + // this is a replacement code for simply change value and remove + // successor...I can not do this here because the address of + // the object is part of the information that has to be + // preserved. + enum rbColor tmpcolor = successor->color; + struct memSegment * tmpparent = successor->parent; + struct memSegment * tmpleft = successor->left; + struct memSegment * tmpright = successor->right; + + replaceNode(tree, node, successor); + + successor->color = node->color; + successor->left = node->left; + successor->left->parent = successor; + // the right one might be successor... + if (node->right == successor) { + successor->right = node; + node->parent = successor; + } else { + successor->right = node->right; + node->right->parent = successor; + node->parent = tmpparent; + tmpparent->left = node; + } + + node->color = tmpcolor; + node->left = tmpleft; + node->right = tmpright; + } + + // Precondition: n has at most one non-null child. + child = (NULL == node->right) ? node->left : node->right; + replaceNode(tree, node, child); + + // delete one child case + // TODO this is overly complex as simply derived from the function... + // maybe this can be simplified. Maybe not...check. + if (node->color == rbBlack) { + if (NULL != child && child->color == rbRed) { + child->color = rbBlack; + // done despite modifying tree itself if neccessary.. + return del_node; + } else { + if (NULL != child) { + node = child; + } else { + node->color = rbBlack; + node->left = NULL; + node->right = NULL; + } + } + } else { + return del_node; + } + + // delete and rb rebalance... + while(1) { + // case 1 + if (NULL == node->parent) { + // done again + break; + } + + // case 2 + s = sibling(node); + + if (NULL != s && s->color == rbRed) { + node->parent->color = rbRed; + s->color = rbBlack; + + /* + * detect which child we are...assumption + * if we are not parent->right and parent->right is not + * null we must be left, even if its set to NULL previously + */ + if (NULL != node->parent->right && node != node->parent->right) { + rotateLeft(tree, node->parent); + } else { + rotateRight(tree, node->parent); + } + } + + s = sibling(node); + // case 3 / 4 + if (NULL == s || ((s->color == rbBlack) && + (NULL == s->left || s->left->color == rbBlack) && + (NULL == s->right || s->right->color == rbBlack))) { + + if (NULL != s) { + s->color = rbRed; + } + + if (node->parent->color == rbBlack) { + // case 3 + node = node->parent; + continue; + } else { + // case 4 + node->parent->color = rbBlack; + // and done again... + break; + } + } + + // case 5 + if (NULL != s && s->color == rbBlack) { + // this if statement is trivial, + // due to case 2 (even though case 2 changed the sibling to a + // sibling's child, + // the sibling's child can't be red, since no red parent can + // have a red child). + // + // the following statements just force the red to be on the + // left of the left of the parent, + // or right of the right, so case 6 will rotate correctly. + if ((node == node->parent->left) && + (NULL == s->right || s->right->color == rbBlack) && + (NULL != s->left && s->left->color == rbRed)) { + + // this last test is trivial too due to cases 2-4. + s->color = rbRed; + s->left->color = rbBlack; + + rotateRight(tree, s); + } else if ((node == node->parent->right) && + (NULL == s->left || s->left->color == rbBlack) && + (NULL != s->right && s->right->color == rbRed)) { + // this last test is trivial too due to cases 2-4. + s->color = rbRed; + s->right->color = rbBlack; + + rotateLeft(tree, s); + } + } + + s = sibling(node); + // case 6 + if (NULL != s) { + s->color = node->parent->color; + } + + if (NULL != node && NULL != node->parent) { + node->parent->color = rbBlack; + + /* + * detect which child we are...assumption + * if we are not parent->right and parent->right is not + * null we must be left, even if its set to NULL previously + */ + if (NULL != node->parent->right && node != node->parent->right) { + if (NULL != s->right) { + s->right->color = rbBlack; + } + rotateLeft(tree, node->parent); + } else { + if (NULL != s->left) { + s->left->color = rbBlack; + } + rotateRight(tree, node->parent); + } + } + + // done... + break; + } + + //deleteOneChild(tree, node); + + return del_node; +} + + +void +traverse(struct memSegment * tree, void (*cb)(struct memSegment *, int)) +{ + struct memSegment * previous = tree; + struct memSegment * node = tree; + int depth = 1; + + /* + * I think this has something like O(n+log(n)) on a ballanced + * tree because I have to traverse back the rightmost leaf to + * the root to get a break condition. + */ + while (NULL != node) { + /* + * If we come from the right so nothing and go to our + * next parent. + */ + if (previous == node->right) { + previous = node; + node = node->parent; + depth--; + continue; + } + + if ((NULL == node->left || previous == node->left)) { + /* + * If there are no more elements to the left or we + * came from the left, process data. + */ + cb(node, depth); + previous = node; + + if (NULL != node->right) { + node = node->right; + depth++; + } else { + node = node->parent; + depth--; + } + } else { + /* + * if there are more elements to the left go there. + */ + previous = node; + node = node->left; + depth++; + } + } +} + +void printElement(struct memSegment * node, int depth) +{ + int i; + + printf("%s %010zu:0x%p(%02d)", + (node->color==rbRed)?"R":"B", + node->size, + node->ptr, + depth); + + for (i=0; i ((struct memSegment *)subject)->size) +// return 1; +// +// return 0; +// } +// +// /** +// * this returns exact fits....uhh.....I can't relate solely on +// * the size argument as then same sized segments will never +// * be stored. +// * Maybe a tree is not the best data structure to use to store +// * these. +// * Anyway, right now take the ptr into account if size if equal. +// */ +// static +// int +// segmentSearchCmp(const void * search, const void * subject) +// { +// size_t idx = +// ((struct memSegment *)search)->size - +// ((struct memSegment *)subject)->size; +// +// if (0 == idx) { +// return +// ((struct memSegment *)search)->ptr - +// ((struct memSegment *)subject)->ptr; +// } +// +// return idx; +// } + static void -segmentFree(void * segment) +segmentFree(struct memSegment * segment, int depth) { - free(segment); + while (NULL != segment) { + struct memSegment * next = segment->next; + free(segment); + malloccount--; + printf("-"); + segment = next; + } } void * memMalloc(size_t size) { - struct memSegment ** seg_ptr = tfind(&size, &segments, segmentFindCmp); - struct memSegment * seg; + struct memSegment * seg; + + //printf("MALLOC of size: %zu\n", size); + //traverse(segments, printElement); - if (NULL == seg_ptr) { - seg = (struct memSegment *)malloc(sizeof(struct memSegment) + size); + seg = findElement(segments, size); - seg->size = size; - seg->ptr = (void *)seg + sizeof(struct memSegment); + if (NULL == seg) { + seg = newElement(size); + //printf(" CREATE Segment: 0x%p of size: %zu\n", seg, seg->size); } else { - seg = *seg_ptr; + //printf(" FOUND Segment: 0x%p of size: %zu\n", seg, seg->size); // remove the found one from the tree as we use it now. - tdelete((void *)seg, &segments, segmentSearchCmp); + deleteElement(&segments, seg); } + return seg->ptr; } @@ -150,15 +787,39 @@ void memFree(void ** mem) { if (NULL != *mem) { - tsearch(*mem - sizeof(struct memSegment), &segments, segmentSearchCmp); + insertElement(&segments, (struct memSegment *)(*mem - sizeof(struct memSegment))); + + //printf("FREE of Segment: 0x%p of size: %zu\n", + // *mem - sizeof(struct memSegment), + // ((struct memSegment *)(*mem - sizeof(struct memSegment)))->size); + //traverse(segments, printElement); + *mem = NULL; } } +void +pre_order(struct memSegment * tree, void (*cb)(struct memSegment *, int)) +{ + if (NULL != tree) { + if (NULL != tree->left) { + pre_order(tree->left, cb); + } + + if (NULL != tree->right) { + pre_order(tree->right, cb); + } + + cb(tree, 0); + } +} + void memCleanup() { - tdestroy(segments, segmentFree); + printf("\n"); + pre_order(segments, segmentFree); + printf("\nmalloccount: %d\n", malloccount); } void From 157f48031c9552a877057b8363f3731e5f2fd8d5 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 27 Aug 2013 23:20:42 +0100 Subject: [PATCH 63/97] now valgrind shows no more violations...but cleanup does not work correcly. The memory usage depends now on the amount of paralell connections...ab show approximately 10% to 20% performance improvement / and the code is far from optimal. --- src/rbtree.c | 248 ++++++++++++++++++++++++++++++------------- src/taskrambler.c | 2 +- src/utils/memory.c | 255 +++++++++++++++++++++++++++------------------ 3 files changed, 330 insertions(+), 175 deletions(-) diff --git a/src/rbtree.c b/src/rbtree.c index 64d968d..a73704b 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -14,6 +14,9 @@ struct element enum rbColor color; + struct element * next; + struct element * last; + struct element * parent; struct element * left; struct element * right; @@ -27,6 +30,9 @@ newElement(size_t size) element->size = size; element->ptr = element + sizeof(struct element); + element->next = NULL; + element->last = NULL; + element->color = rbRed; element->parent = NULL; element->left = NULL; @@ -192,17 +198,21 @@ insertElement(struct element ** tree, struct element * element) struct element * u; struct element * g; + element->next = NULL; + element->last = NULL; + + element->color = rbRed; + element->parent = NULL; + element->left = NULL; + element->right = NULL; + // if tree is empty it's simple... :) if (NULL == node) { *tree = node = new_node = element; } else { // normal binary tree add.... - while (element->size != node->size || element->ptr != node->ptr) { - if (element->size < node->size && NULL != node->left) { - node = node->left; - } else if (element->size > node->size && NULL != node->right) { - node = node->right; - } else if (element->ptr < node->ptr) { + while (NULL != node) { + if (element->size < node->size) { if (NULL == node->left) { node->left = element; node->left->parent = node; @@ -211,7 +221,7 @@ insertElement(struct element ** tree, struct element * element) } else { node = node->left; } - } else if (element->ptr > node->ptr) { + } else if (element->size > node->size) { if (NULL == node->right) { node->right = element; node->right->parent = node; @@ -221,6 +231,13 @@ insertElement(struct element ** tree, struct element * element) node = node->right; } } else { + if (NULL == node->next) { + node->next = element; + node->last = element; + } else { + node->last->next = element; + node->last = element; + } return node; } } @@ -327,14 +344,41 @@ deleteElement(struct element ** tree, struct element * element) struct element * s; // find the relevant node and it's parent - while (NULL != node - && node->size != element->size - && node->ptr != element->ptr) { + while (NULL != node) { - if (element->size < node->size || element->ptr < node->ptr) { + if (element->size < node->size) { node = node->left; - } else { + } else if (element->size > node->size) { node = node->right; + } else { + if (NULL != node->next) { + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = node->next; + } else { + node->parent->right = node->next; + } + } else { + *tree = node->next; + } + + if (NULL != node->left) { + node->left->parent = node->next; + } + + if (NULL != node->right) { + node->right->parent = node->next; + } + + node->next->last = node->last; + node->next->color = node->color; + node->next->parent = node->parent; + node->next->left = node->left; + node->next->right = node->right; + + return node; + } + break; } } @@ -521,7 +565,7 @@ deleteElement(struct element ** tree, struct element * element) void -traverse(struct element * tree, void (*cb)(size_t, void *, int, enum rbColor)) +traverse(struct element * tree, void (*cb)(struct element *, int)) { struct element * previous = tree; struct element * node = tree; @@ -549,7 +593,62 @@ traverse(struct element * tree, void (*cb)(size_t, void *, int, enum rbColor)) * If there are no more elements to the left or we * came from the left, process data. */ - cb(node->size, node->ptr, depth, node->color); + cb(node, depth); + previous = node; + + if (NULL != node->right) { + node = node->right; + depth++; + } else { + node = node->parent; + depth--; + } + } else { + /* + * if there are more elements to the left go there. + */ + previous = node; + node = node->left; + depth++; + } + } +} + +void +post(struct element * tree, void (*cb)(struct element *, int)) +{ + struct element * previous = tree; + struct element * node = tree; + int depth = 1; + + /* + * I think this has something like O(n+log(n)) on a ballanced + * tree because I have to traverse back the rightmost leaf to + * the root to get a break condition. + */ + while (node) { + /* + * If we come from the right so nothing and go to our + * next parent. + */ + if ((NULL == node->left && NULL == node->right) + || previous == node->right) { + + struct element * parent = node->parent; + + cb(node, depth); + + previous = node; + node = parent; + depth--; + continue; + } + + if ((NULL == node->left || previous == node->left)) { + /* + * If there are no more elements to the left or we + * came from the left, process data. + */ previous = node; if (NULL != node->right) { @@ -570,15 +669,41 @@ traverse(struct element * tree, void (*cb)(size_t, void *, int, enum rbColor)) } } -void printElement(size_t size, void * ptr, int depth, enum rbColor color) +void printElement(struct element * node, int depth) { int i; - printf("%s %010zu:0x%p(%02d)", (color==rbRed)?"R":"B", size, ptr, depth); + printf("%s %010zu:%p(%02d)", + (node->color==rbRed)?"R":"B", + node->size, + node->ptr, + depth); for (i=0; inext; + while (NULL != node) { + printf(" %s %010zu:%p(%02d)", + (node->color==rbRed)?"R":"B", + node->size, + node->ptr, + depth); + for (i=0; inext; + } } +void cleanup(struct element * node, int depth) +{ + while (NULL != node) { + printf("free node: "); + printElement(node, 0); + struct element * next = node->next; + free(node); + node = next; + } +} /** * ======================================================================= @@ -588,58 +713,6 @@ main(int argc, char * argv[]) { struct element * root = NULL; struct element * found = NULL; - int value; - int count; - -// insertElement(&root, newElement(84)); -// insertElement(&root, newElement(87)); -// insertElement(&root, newElement(78)); -// insertElement(&root, newElement(16)); -// insertElement(&root, newElement(94)); -// -// puts("traverse"); -// traverse(root, printElement); -// -// free(deleteElement(&root, findElement(root, 87))); -// puts("traverse"); -// traverse(root, printElement); -// free(deleteElement(&root, findElement(root, 94))); -// puts("traverse"); -// traverse(root, printElement); -// free(deleteElement(&root, findElement(root, 16))); -// puts("traverse"); -// traverse(root, printElement); -// free(deleteElement(&root, findElement(root, 84))); -// puts("traverse"); -// traverse(root, printElement); -// free(deleteElement(&root, findElement(root, 78))); -// puts("traverse"); -// traverse(root, printElement); -// -// for (count=0; countsize, found->ptr, 0, found->color); + printElement(found, 0); } puts(""); @@ -670,7 +743,7 @@ main(int argc, char * argv[]) if (NULL == found) { printf("can't find segmenet of minimum size: %d\n", 64); } else { - printElement(found->size, found->ptr, 0, found->color); + printElement(found, 0); } puts(""); @@ -678,15 +751,46 @@ main(int argc, char * argv[]) if (NULL == found) { printf("can't find segmenet of minimum size: %d\n", 90); } else { - printElement(found->size, found->ptr, 0, found->color); + printElement(found, 0); } puts(""); - deleteElement(&root, findElement(root, 70)); + free(deleteElement(&root, findElement(root, 70))); + puts("traverse"); + traverse(root, printElement); + puts(""); + + insertElement(&root, newElement(80)); + insertElement(&root, newElement(50)); + insertElement(&root, newElement(80)); + + puts("traverse"); + traverse(root, printElement); + puts(""); + + found = deleteElement(&root, findElement(root, 80)); + printf("up to free: %p\n", found); + free(found); + puts("traverse"); + traverse(root, printElement); + puts(""); + + found = deleteElement(&root, findElement(root, 50)); + printf("up to free: %p\n", found); + free(found); + puts("traverse"); + traverse(root, printElement); + puts(""); + + found = deleteElement(&root, findElement(root, 70)); + printf("up to free: %p\n", found); + free(found); puts("traverse"); traverse(root, printElement); puts(""); + post(root, cleanup); + return 0; } diff --git a/src/taskrambler.c b/src/taskrambler.c index ec8039c..4d0ff83 100644 --- a/src/taskrambler.c +++ b/src/taskrambler.c @@ -72,7 +72,7 @@ main() setrlimit(RLIMIT_NOFILE, &limit); init_signals(); - daemonize(); + //daemonize(); shm = shm_open("/fooshm", O_RDWR|O_CREAT, S_IRWXU); if (-1 == ftruncate(shm, psize)) { diff --git a/src/utils/memory.c b/src/utils/memory.c index 4e2d676..08a31d3 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -56,18 +56,17 @@ enum rbColor {rbBlack=1, rbRed=2}; -int malloccount = 0; -struct memSegment { - size_t size; - void * ptr; - - // for address queue - struct memSegment * next; - struct memSegment * last; +struct memSegment +{ + size_t size; + void * ptr; - // for rbtree enum rbColor color; + + struct memSegment * next; + struct memSegment * last; + struct memSegment * parent; struct memSegment * left; struct memSegment * right; @@ -77,14 +76,12 @@ struct memSegment * newElement(size_t size) { struct memSegment * element = malloc(size + sizeof(struct memSegment)); - malloccount++; - printf("+"); element->size = size; - element->ptr = (void *)element + sizeof(struct memSegment); + element->ptr = (void*)element + sizeof(struct memSegment); - element->next = NULL; - element->last = NULL; + element->next = NULL; + element->last = NULL; element->color = rbRed; element->parent = NULL; @@ -104,7 +101,7 @@ findElement(struct memSegment * tree, size_t size) while (NULL != tree) { if (tree->size == size) { - fitting = tree; + fitting = tree; break; } @@ -251,19 +248,20 @@ insertElement(struct memSegment ** tree, struct memSegment * element) struct memSegment * u; struct memSegment * g; - element->color = rbRed; - element->parent = NULL; - element->left = NULL; - element->right = NULL; - element->next = NULL; - element->last = NULL; + element->next = NULL; + element->last = NULL; + + element->color = rbRed; + element->parent = NULL; + element->left = NULL; + element->right = NULL; // if tree is empty it's simple... :) if (NULL == node) { *tree = node = new_node = element; } else { // normal binary tree add.... - while (element->size != node->size) { + while (NULL != node) { if (element->size < node->size) { if (NULL == node->left) { node->left = element; @@ -283,13 +281,14 @@ insertElement(struct memSegment ** tree, struct memSegment * element) node = node->right; } } else { - if (NULL == node->next) { - node->next = node->last = element; - } else { - node->last->next = element; - node->last = element; - } - return element; + if (NULL == node->next) { + node->next = element; + node->last = element; + } else { + node->last->next = element; + node->last = element; + } + return node; } } } @@ -365,6 +364,12 @@ insertElement(struct memSegment ** tree, struct memSegment * element) * aka left in-order successor. * We return the parent of the element in the out argument parent. * This can be NULL wenn calling. + * + * 2: *successor = {size = 80, ptr = 0x603ae0, color = rbRed, parent = 0x603160, + * left = 0x0, right = 0x0} + * 1: *node = {size = 70, ptr = 0x603a60, color = rbBlack, parent = 0x603070, + * left = 0x6030e0, right = 0x6031e0} + * */ struct memSegment * findInOrderSuccessor(struct memSegment * tree) @@ -390,46 +395,41 @@ deleteElement(struct memSegment ** tree, struct memSegment * element) // find the relevant node and it's parent while (NULL != node) { + if (element->size < node->size) { node = node->left; } else if (element->size > node->size) { node = node->right; } else { - // we know we found our tree element. - if (NULL != node->next) { - // last element. - if (NULL != node->parent) { - if (node->parent->left == node->parent) { - node->parent->left = node->next; - } else { - node->parent->right = node->next; - } - } - - if (NULL != node->left) { - node->left->parent = node->next; - } - - if (NULL != node->right) { - node->right->parent = node->next; - } - - if (node->next == node->last) { - node->next->next = NULL; - node->next->last = NULL; - } else { - node->next->last = node->last; - } - - node->next->parent = node->parent; - node->next->color = node->color; - node->next->left = node->left; - node->next->right = node->right; - - return node; - } - break; - } + if (NULL != node->next) { + if (NULL != node->parent) { + if (node == node->parent->left) { + node->parent->left = node->next; + } else { + node->parent->right = node->next; + } + } else { + *tree = node->next; + } + + if (NULL != node->left) { + node->left->parent = node->next; + } + + if (NULL != node->right) { + node->right->parent = node->next; + } + + node->next->last = node->last; + node->next->color = node->color; + node->next->parent = node->parent; + node->next->left = node->left; + node->next->right = node->right; + + return node; + } + break; + } } // element not found @@ -446,10 +446,6 @@ deleteElement(struct memSegment ** tree, struct memSegment * element) if (NULL != node->left && NULL != node->right) { struct memSegment * successor = findInOrderSuccessor(node); - // this is a replacement code for simply change value and remove - // successor...I can not do this here because the address of - // the object is part of the information that has to be - // preserved. enum rbColor tmpcolor = successor->color; struct memSegment * tmpparent = successor->parent; struct memSegment * tmpleft = successor->left; @@ -630,7 +626,7 @@ traverse(struct memSegment * tree, void (*cb)(struct memSegment *, int)) * tree because I have to traverse back the rightmost leaf to * the root to get a break condition. */ - while (NULL != node) { + while (node) { /* * If we come from the right so nothing and go to our * next parent. @@ -668,20 +664,95 @@ traverse(struct memSegment * tree, void (*cb)(struct memSegment *, int)) } } +void +post(struct memSegment * tree, void (*cb)(struct memSegment *, int)) +{ + struct memSegment * previous = tree; + struct memSegment * node = tree; + int depth = 1; + + /* + * I think this has something like O(n+log(n)) on a ballanced + * tree because I have to traverse back the rightmost leaf to + * the root to get a break condition. + */ + while (node) { + /* + * If we come from the right so nothing and go to our + * next parent. + */ + if ((NULL == node->left && NULL == node->right) + || previous == node->right) { + + struct memSegment * parent = node->parent; + + cb(node, depth); + + previous = node; + node = parent; + depth--; + continue; + } + + if ((NULL == node->left || previous == node->left)) { + /* + * If there are no more elements to the left or we + * came from the left, process data. + */ + previous = node; + + if (NULL != node->right) { + node = node->right; + depth++; + } else { + node = node->parent; + depth--; + } + } else { + /* + * if there are more elements to the left go there. + */ + previous = node; + node = node->left; + depth++; + } + } +} + void printElement(struct memSegment * node, int depth) { int i; - printf("%s %010zu:0x%p(%02d)", - (node->color==rbRed)?"R":"B", - node->size, - node->ptr, - depth); - + printf("%s %010zu:%p(%02d)", + (node->color==rbRed)?"R":"B", + node->size, + node->ptr, + depth); for (i=0; inext; + while (NULL != node) { + printf(" %s %010zu:%p(%02d)", + (node->color==rbRed)?"R":"B", + node->size, + node->ptr, + depth); + for (i=0; inext; + } } +void +cleanup(struct memSegment * node, int depth) +{ + while (NULL != node) { + struct memSegment * next = node->next; + free(node); + node = next; + } +} struct memSegment * segments = NULL; @@ -731,13 +802,11 @@ static void segmentFree(struct memSegment * segment, int depth) { - while (NULL != segment) { - struct memSegment * next = segment->next; - free(segment); - malloccount--; - printf("-"); - segment = next; - } + while (NULL != segment) { + struct memSegment * next = segment->next; + free(segment); + segment = next; + } } @@ -757,7 +826,7 @@ memMalloc(size_t size) } else { //printf(" FOUND Segment: 0x%p of size: %zu\n", seg, seg->size); // remove the found one from the tree as we use it now. - deleteElement(&segments, seg); + seg = deleteElement(&segments, seg); } @@ -798,28 +867,10 @@ memFree(void ** mem) } } -void -pre_order(struct memSegment * tree, void (*cb)(struct memSegment *, int)) -{ - if (NULL != tree) { - if (NULL != tree->left) { - pre_order(tree->left, cb); - } - - if (NULL != tree->right) { - pre_order(tree->right, cb); - } - - cb(tree, 0); - } -} - void memCleanup() { - printf("\n"); - pre_order(segments, segmentFree); - printf("\nmalloccount: %d\n", malloccount); + post(segments, segmentFree); } void From 5c3232910576011df6875cb5bcaf6126a770092b Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 28 Aug 2013 11:46:21 +0100 Subject: [PATCH 64/97] now every file accessible under assets/html will be delivered. --- src/http/message.c | 2 +- src/http/response/asset.c | 15 +++++++++++---- src/http/worker/get_asset.c | 15 +++++++++++---- src/http/worker/process.c | 29 ++++++++++++++++++++--------- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/http/message.c b/src/http/message.c index 2ee7db4..51499ff 100644 --- a/src/http/message.c +++ b/src/http/message.c @@ -67,7 +67,7 @@ httpMessageDtor(void * _this) break; case HTTP_MESSAGE_PIPED: - if (2 < (this->handle->handle).fd) { + if (NULL != this->handle && 2 < (this->handle->handle).fd) { close((this->handle->handle).fd); } delete(this->handle); diff --git a/src/http/response/asset.c b/src/http/response/asset.c index b0c58f2..e09bd26 100644 --- a/src/http/response/asset.c +++ b/src/http/response/asset.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -55,8 +56,12 @@ httpResponseAsset( HttpMessage message; int handle; - handle = open(fname, O_RDONLY); - fstat(handle, &st); + if (-1 == access(fname, O_RDONLY)) { + handle = -1; + } else { + handle = open(fname, O_RDONLY); + fstat(handle, &st); + } tmp = localtime(&(st.st_mtime)); netag = strftime(etag, sizeof(etag), "%s", tmp); @@ -70,8 +75,10 @@ httpResponseAsset( message = (HttpMessage)response; message->type = HTTP_MESSAGE_PIPED; - message->handle = new(Stream, STREAM_FD, handle); - message->nbody = st.st_size; + if (-1 != handle) { + message->handle = new(Stream, STREAM_FD, handle); + message->nbody = st.st_size; + } hashAdd(message->header, new(HttpHeader, CSTRA("Content-Type"), mime, nmime)); diff --git a/src/http/worker/get_asset.c b/src/http/worker/get_asset.c index 36f69ce..3ec9aef 100644 --- a/src/http/worker/get_asset.c +++ b/src/http/worker/get_asset.c @@ -37,9 +37,10 @@ httpWorkerGetAsset( const char * mime, size_t nmime) { - char * match; - size_t nmatch; - HttpHeader header; + char * match; + size_t nmatch; + HttpHeader header; + HttpMessage message; header = hashGet( ((HttpMessage)request)->header, @@ -54,8 +55,14 @@ httpWorkerGetAsset( nmatch = (header->nvalue)[0]; } - return (HttpMessage)httpResponseAsset( + message = (HttpMessage)httpResponseAsset( fname, mime, nmime, match, nmatch); + + if (message->type == HTTP_MESSAGE_PIPED && message->handle == NULL) { + delete(message); + } + + return message; } // vim: set ts=4 sw=4: diff --git a/src/http/worker/process.c b/src/http/worker/process.c index f495f2d..551a669 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -158,11 +158,11 @@ httpWorkerProcess(HttpWorker this, Stream st) CSTRA("text/html")); } - if (0 == strcmp("/sessinfo/", request->path)) { + else if (0 == strcmp("/sessinfo/", request->path)) { response = (HttpMessage)httpResponseSession(this->session); } - if (0 == strcmp("/sess/", request->path)) { + else if (0 == strcmp("/sess/", request->path)) { if (NULL == this->session) { this->session = sessionAdd( this->sroot, @@ -171,7 +171,7 @@ httpWorkerProcess(HttpWorker this, Stream st) response = (HttpMessage)httpResponseSession(this->session); } - if (0 == strcmp("/randval/", request->path)) { + else if (0 == strcmp("/randval/", request->path)) { if (NULL != this->session) { response = (HttpMessage)httpResponseRandval( this->val->timestamp, @@ -181,47 +181,58 @@ httpWorkerProcess(HttpWorker this, Stream st) } } - if (0 == strcmp("/image/me", request->path)) { + else if (0 == strcmp("/image/me", request->path)) { response = httpWorkerGetAsset( request, "./assets/image/waldschrat.jpg", CSTRA("image/jpeg")); } - if (0 == strcmp("/assets/js/jquery", request->path)) { + else if (0 == strcmp("/assets/js/jquery", request->path)) { response = httpWorkerGetAsset( request, "./assets/js/jquery-1.7.1.min.js", CSTRA("text/javascript")); } - if (0 == strcmp("/assets/js/serverval", request->path)) { + else if (0 == strcmp("/assets/js/serverval", request->path)) { response = httpWorkerGetAsset( request, "./assets/js/serverval.js", CSTRA("text/javascript")); } - if (0 == strcmp("/assets/js/session", request->path)) { + else if (0 == strcmp("/assets/js/session", request->path)) { response = httpWorkerGetAsset( request, "./assets/js/session.js", CSTRA("text/javascript")); } - if (0 == strcmp("/assets/js/init", request->path)) { + else if (0 == strcmp("/assets/js/init", request->path)) { response = httpWorkerGetAsset( request, "./assets/js/init.js", CSTRA("text/javascript")); } - if (0 == strcmp("/assets/style/common", request->path)) { + else if (0 == strcmp("/assets/style/common", request->path)) { response = httpWorkerGetAsset( request, "./assets/style/common.css", CSTRA("text/css")); } + + else { + char asset[2048] = "./assets/html"; + + strcat(asset, request->path); + response = httpWorkerGetAsset( + request, + asset, + CSTRA("text/html")); + } + } if (NULL == response) { From 0fdbbfe3c9d14a634f01fa8b2c48745c7a7a5d11 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 28 Aug 2013 13:59:27 +0200 Subject: [PATCH 65/97] add a file with file extension to mime-type mappings --- docs/mime.types | 184 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 docs/mime.types diff --git a/docs/mime.types b/docs/mime.types new file mode 100644 index 0000000..69c067c --- /dev/null +++ b/docs/mime.types @@ -0,0 +1,184 @@ +evy application/envoy +fif application/fractals +spl application/futuresplash +hta application/hta +acx application/internet-property-stream +hqx application/mac-binhex40 +doc application/msword +dot application/msword +* application/octet-stream +oda application/oda +axs application/olescript +pdf application/pdf +prf application/pics-rules +p10 application/pkcs10 +crl application/pkix-crl +ai application/postscript +eps application/postscript +ps application/postscript +rtf application/rtf +setpay application/set-payment-initiation +setreg application/set-registration-initiation +xla application/vnd.ms-excel +xlc application/vnd.ms-excel +xlm application/vnd.ms-excel +xls application/vnd.ms-excel +xlt application/vnd.ms-excel +xlw application/vnd.ms-excel +msg application/vnd.ms-outlook +sst application/vnd.ms-pkicertstore +cat application/vnd.ms-pkiseccat +stl application/vnd.ms-pkistl +pot application/vnd.ms-powerpoint +pps application/vnd.ms-powerpoint +ppt application/vnd.ms-powerpoint +mpp application/vnd.ms-project +wcm application/vnd.ms-works +wdb application/vnd.ms-works +wks application/vnd.ms-works +wps application/vnd.ms-works +hlp application/winhlp +bcpio application/x-bcpio +cdf application/x-cdf +z application/x-compress +tgz application/x-compressed +cpio application/x-cpio +csh application/x-csh +dcr application/x-director +dir application/x-director +dxr application/x-director +dvi application/x-dvi +gtar application/x-gtar +gz application/x-gzip +hdf application/x-hdf +ins application/x-internet-signup +isp application/x-internet-signup +iii application/x-iphone +js application/x-javascript +latex application/x-latex +mdb application/x-msaccess +crd application/x-mscardfile +clp application/x-msclip +dll application/x-msdownload +m13 application/x-msmediaview +m14 application/x-msmediaview +mvb application/x-msmediaview +wmf application/x-msmetafile +mny application/x-msmoney +pub application/x-mspublisher +scd application/x-msschedule +trm application/x-msterminal +wri application/x-mswrite +nc application/x-netcdf +pma application/x-perfmon +pmc application/x-perfmon +pml application/x-perfmon +pmr application/x-perfmon +pmw application/x-perfmon +p12 application/x-pkcs12 +pfx application/x-pkcs12 +p7b application/x-pkcs7-certificates +spc application/x-pkcs7-certificates +p7r application/x-pkcs7-certreqresp +p7c application/x-pkcs7-mime +p7m application/x-pkcs7-mime +p7s application/x-pkcs7-signature +sh application/x-sh +shar application/x-shar +swf application/x-shockwave-flash +sit application/x-stuffit +sv4cpio application/x-sv4cpio +sv4crc application/x-sv4crc +tar application/x-tar +tcl application/x-tcl +tex application/x-tex +texi application/x-texinfo +texinfo application/x-texinfo +roff application/x-troff +t application/x-troff +tr application/x-troff +man application/x-troff-man +me application/x-troff-me +ms application/x-troff-ms +ustar application/x-ustar +src application/x-wais-source +cer application/x-x509-ca-cert +crt application/x-x509-ca-cert +der application/x-x509-ca-cert +pko application/ynd.ms-pkipko +zip application/zip +au audio/basic +snd audio/basic +mid audio/mid +rmi audio/mid +mp3 audio/mpeg +aif audio/x-aiff +aifc audio/x-aiff +aiff audio/x-aiff +m3u audio/x-mpegurl +ra audio/x-pn-realaudio +ram audio/x-pn-realaudio +wav audio/x-wav +bmp image/bmp +cod image/cis-cod +gif image/gif +ief image/ief +jpe image/jpeg +jpeg image/jpeg +jpg image/jpeg +jfif image/pipeg +svg image/svg+xml +tif image/tiff +tiff image/tiff +ras image/x-cmu-raster +cmx image/x-cmx +ico image/x-icon +pnm image/x-portable-anymap +pbm image/x-portable-bitmap +pgm image/x-portable-graymap +ppm image/x-portable-pixmap +rgb image/x-rgb +xbm image/x-xbitmap +xpm image/x-xpixmap +xwd image/x-xwindowdump +mht message/rfc822 +mhtml message/rfc822 +nws message/rfc822 +css text/css +323 text/h323 +htm text/html +html text/html +stm text/html +uls text/iuls +bas text/plain +c text/plain +h text/plain +txt text/plain +rtx text/richtext +sct text/scriptlet +tsv text/tab-separated-values +htt text/webviewhtml +htc text/x-component +etx text/x-setext +vcf text/x-vcard +mp2 video/mpeg +mpa video/mpeg +mpe video/mpeg +mpeg video/mpeg +mpg video/mpeg +mpv2 video/mpeg +mov video/quicktime +qt video/quicktime +lsf video/x-la-asf +lsx video/x-la-asf +asf video/x-ms-asf +asr video/x-ms-asf +asx video/x-ms-asf +avi video/x-msvideo +movie video/x-sgi-movie +flr x-world/x-vrml +vrml x-world/x-vrml +wrl x-world/x-vrml +wrz x-world/x-vrml +xaf x-world/x-vrml +xof x-world/x-vrml From 623a062df7c0c0778ff0ccb1e6d6161bdcdd53af Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 28 Aug 2013 14:18:57 +0100 Subject: [PATCH 66/97] add suppport for file extension based mime type detection. --- assets/html/foo.html | 13 +++ assets/html/robots.txt | 0 config/mime.types | 184 ++++++++++++++++++++++++++++++++ include/http/worker.h | 3 + src/http/Makefile.am | 3 +- src/http/worker.c | 42 ++++++++ src/http/worker/get_mime_type.c | 42 ++++++++ src/http/worker/process.c | 22 +++- 8 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 assets/html/foo.html create mode 100644 assets/html/robots.txt create mode 100644 config/mime.types create mode 100644 src/http/worker/get_mime_type.c diff --git a/assets/html/foo.html b/assets/html/foo.html new file mode 100644 index 0000000..b48b623 --- /dev/null +++ b/assets/html/foo.html @@ -0,0 +1,13 @@ + + + + + This is just foo + + +

A BIG FAT FOO

+ + + + diff --git a/assets/html/robots.txt b/assets/html/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/config/mime.types b/config/mime.types new file mode 100644 index 0000000..69c067c --- /dev/null +++ b/config/mime.types @@ -0,0 +1,184 @@ +evy application/envoy +fif application/fractals +spl application/futuresplash +hta application/hta +acx application/internet-property-stream +hqx application/mac-binhex40 +doc application/msword +dot application/msword +* application/octet-stream +oda application/oda +axs application/olescript +pdf application/pdf +prf application/pics-rules +p10 application/pkcs10 +crl application/pkix-crl +ai application/postscript +eps application/postscript +ps application/postscript +rtf application/rtf +setpay application/set-payment-initiation +setreg application/set-registration-initiation +xla application/vnd.ms-excel +xlc application/vnd.ms-excel +xlm application/vnd.ms-excel +xls application/vnd.ms-excel +xlt application/vnd.ms-excel +xlw application/vnd.ms-excel +msg application/vnd.ms-outlook +sst application/vnd.ms-pkicertstore +cat application/vnd.ms-pkiseccat +stl application/vnd.ms-pkistl +pot application/vnd.ms-powerpoint +pps application/vnd.ms-powerpoint +ppt application/vnd.ms-powerpoint +mpp application/vnd.ms-project +wcm application/vnd.ms-works +wdb application/vnd.ms-works +wks application/vnd.ms-works +wps application/vnd.ms-works +hlp application/winhlp +bcpio application/x-bcpio +cdf application/x-cdf +z application/x-compress +tgz application/x-compressed +cpio application/x-cpio +csh application/x-csh +dcr application/x-director +dir application/x-director +dxr application/x-director +dvi application/x-dvi +gtar application/x-gtar +gz application/x-gzip +hdf application/x-hdf +ins application/x-internet-signup +isp application/x-internet-signup +iii application/x-iphone +js application/x-javascript +latex application/x-latex +mdb application/x-msaccess +crd application/x-mscardfile +clp application/x-msclip +dll application/x-msdownload +m13 application/x-msmediaview +m14 application/x-msmediaview +mvb application/x-msmediaview +wmf application/x-msmetafile +mny application/x-msmoney +pub application/x-mspublisher +scd application/x-msschedule +trm application/x-msterminal +wri application/x-mswrite +nc application/x-netcdf +pma application/x-perfmon +pmc application/x-perfmon +pml application/x-perfmon +pmr application/x-perfmon +pmw application/x-perfmon +p12 application/x-pkcs12 +pfx application/x-pkcs12 +p7b application/x-pkcs7-certificates +spc application/x-pkcs7-certificates +p7r application/x-pkcs7-certreqresp +p7c application/x-pkcs7-mime +p7m application/x-pkcs7-mime +p7s application/x-pkcs7-signature +sh application/x-sh +shar application/x-shar +swf application/x-shockwave-flash +sit application/x-stuffit +sv4cpio application/x-sv4cpio +sv4crc application/x-sv4crc +tar application/x-tar +tcl application/x-tcl +tex application/x-tex +texi application/x-texinfo +texinfo application/x-texinfo +roff application/x-troff +t application/x-troff +tr application/x-troff +man application/x-troff-man +me application/x-troff-me +ms application/x-troff-ms +ustar application/x-ustar +src application/x-wais-source +cer application/x-x509-ca-cert +crt application/x-x509-ca-cert +der application/x-x509-ca-cert +pko application/ynd.ms-pkipko +zip application/zip +au audio/basic +snd audio/basic +mid audio/mid +rmi audio/mid +mp3 audio/mpeg +aif audio/x-aiff +aifc audio/x-aiff +aiff audio/x-aiff +m3u audio/x-mpegurl +ra audio/x-pn-realaudio +ram audio/x-pn-realaudio +wav audio/x-wav +bmp image/bmp +cod image/cis-cod +gif image/gif +ief image/ief +jpe image/jpeg +jpeg image/jpeg +jpg image/jpeg +jfif image/pipeg +svg image/svg+xml +tif image/tiff +tiff image/tiff +ras image/x-cmu-raster +cmx image/x-cmx +ico image/x-icon +pnm image/x-portable-anymap +pbm image/x-portable-bitmap +pgm image/x-portable-graymap +ppm image/x-portable-pixmap +rgb image/x-rgb +xbm image/x-xbitmap +xpm image/x-xpixmap +xwd image/x-xwindowdump +mht message/rfc822 +mhtml message/rfc822 +nws message/rfc822 +css text/css +323 text/h323 +htm text/html +html text/html +stm text/html +uls text/iuls +bas text/plain +c text/plain +h text/plain +txt text/plain +rtx text/richtext +sct text/scriptlet +tsv text/tab-separated-values +htt text/webviewhtml +htc text/x-component +etx text/x-setext +vcf text/x-vcard +mp2 video/mpeg +mpa video/mpeg +mpe video/mpeg +mpeg video/mpeg +mpg video/mpeg +mpv2 video/mpeg +mov video/quicktime +qt video/quicktime +lsf video/x-la-asf +lsx video/x-la-asf +asf video/x-ms-asf +asr video/x-ms-asf +asx video/x-ms-asf +avi video/x-msvideo +movie video/x-sgi-movie +flr x-world/x-vrml +vrml x-world/x-vrml +wrl x-world/x-vrml +wrz x-world/x-vrml +xaf x-world/x-vrml +xof x-world/x-vrml diff --git a/include/http/worker.h b/include/http/worker.h index cfc7255..3af25b4 100644 --- a/include/http/worker.h +++ b/include/http/worker.h @@ -28,6 +28,7 @@ #include #include "class.h" +#include "hash.h" #include "http/parser.h" #include "http/writer.h" #include "cbuf.h" @@ -48,6 +49,8 @@ CLASS(HttpWorker) { Cbuf pbuf; Cbuf wbuf; + Hash mime_types; + HttpParser parser; HttpWriter writer; Session session; diff --git a/src/http/Makefile.am b/src/http/Makefile.am index f583d84..8c88b2f 100644 --- a/src/http/Makefile.am +++ b/src/http/Makefile.am @@ -29,7 +29,8 @@ WORKER = worker.c \ worker/process.c \ worker/answer.c \ worker/get_asset.c \ - worker/add_common_header.c + worker/add_common_header.c \ + worker/get_mime_type.c HEADER = header.c \ header/to_string.c diff --git a/src/http/worker.c b/src/http/worker.c index 6d6293c..f7b62c3 100644 --- a/src/http/worker.c +++ b/src/http/worker.c @@ -24,12 +24,15 @@ #include #include +#include +#include #include #include #include #include "class.h" #include "stream.h" +#include "hash.h" #include "http/worker.h" #include "http/parser.h" #include "http/writer.h" @@ -49,6 +52,42 @@ httpWorkerCtor(void * _this, va_list * params) this->val = va_arg(*params, struct randval *); + /* read all mimetypes in a hash */ + this->mime_types = new(Hash); + if (0 == access("./config/mime.types", O_RDONLY)) { + FILE * handle = fopen("./config/mime.types", "r"); + + if (NULL != handle) { + char buffer[512]; + + while (NULL != fgets(buffer, 512, handle)) { + char * tmp; + char * key = buffer; + char * value; + size_t nkey; + size_t nvalue; + + buffer[511] = '\0'; + tmp = memchr(key, ' ', 512); + + if (NULL != tmp) { + *tmp = '\0'; + } + nkey = tmp - buffer; + + value = tmp + 1; + for (; *value == ' ' && value < buffer+512; value++); + + nvalue = strlen(value); + + hashAdd(this->mime_types, + new(HashValue, key, nkey, value, nvalue)); + } + + fclose(handle); + } + } + sprintf(cbuf_id, "%s_%s", "parser", id); this->pbuf = new(Cbuf, cbuf_id, PARSER_MAX_BUF); @@ -84,6 +123,7 @@ httpWorkerDtor(void * _this) delete(this->writer); if (NULL != this->pbuf) { + delete(this->mime_types); delete(this->pbuf); //!< cloned workers have NULL, so delete won't do anything delete(this->wbuf); //!< cloned workers have NULL, so delete won't do anything tdestroy(*(this->sroot), tDelete); @@ -99,6 +139,8 @@ httpWorkerClone(void * _this, void * _base) this->val = base->val; + this->mime_types = base->mime_types; + this->parser = new(HttpParser, base->pbuf); this->writer = new(HttpWriter, base->wbuf); diff --git a/src/http/worker/get_mime_type.c b/src/http/worker/get_mime_type.c new file mode 100644 index 0000000..cc407b6 --- /dev/null +++ b/src/http/worker/get_mime_type.c @@ -0,0 +1,42 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "http/worker.h" + +#include "utils/memory.h" +#include "hash.h" + +char * +httpWorkerGetMimeType( + HttpWorker this, + const char * extension) +{ + HashValue mime_type; + + mime_type = hashGet(this->mime_types, extension, strlen(extension)); + + return (char *)mime_type->value; +} + +// vim: set ts=4 sw=4: diff --git a/src/http/worker/process.c b/src/http/worker/process.c index 551a669..078ac93 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -47,6 +47,7 @@ HttpMessage httpWorkerGetAsset(HttpRequest, const char *, const char *, size_t); void httpWorkerAddCommonHeader(HttpMessage, HttpMessage); +char * httpWorkerGetMimeType(HttpWorker, const char * extension); ssize_t @@ -68,11 +69,11 @@ httpWorkerProcess(HttpWorker this, Stream st) if (NULL == this->session) { HashValue sidstr = hashGet(request->cookies, CSTRA("sid")); - if (NULL != sidstr) { - unsigned long sid; + if (NULL != sidstr) { + unsigned long sid; sid = strtoul((char*)(sidstr->value), NULL, 10); - this->session = sessionGet(this->sroot, sid); + this->session = sessionGet(this->sroot, sid); } } @@ -225,12 +226,25 @@ httpWorkerProcess(HttpWorker this, Stream st) else { char asset[2048] = "./assets/html"; + char * extension = strrchr(request->path, '.'); + char * mime_type = NULL; + char default_mime[] = "application/octet-stream"; + + if (NULL != extension) { + extension++; + mime_type = httpWorkerGetMimeType(this, extension); + } + + if (NULL == mime_type) { + mime_type = default_mime; + } strcat(asset, request->path); response = httpWorkerGetAsset( request, asset, - CSTRA("text/html")); + mime_type, + strlen(mime_type)); } } From 21abd36396f1bca90f76d041bd91b6da0966cb5a Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 28 Aug 2013 15:23:52 +0100 Subject: [PATCH 67/97] now sending non html data from one of the other folders also works --- assets/other/.keep-me | 0 src/http/worker.c | 11 ++++++++--- src/http/worker/process.c | 11 ++++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 assets/other/.keep-me diff --git a/assets/other/.keep-me b/assets/other/.keep-me new file mode 100644 index 0000000..e69de29 diff --git a/src/http/worker.c b/src/http/worker.c index f7b62c3..9abb59c 100644 --- a/src/http/worker.c +++ b/src/http/worker.c @@ -60,14 +60,15 @@ httpWorkerCtor(void * _this, va_list * params) if (NULL != handle) { char buffer[512]; - while (NULL != fgets(buffer, 512, handle)) { + buffer[511] = '\0'; + + while (NULL != fgets(buffer, 511, handle)) { char * tmp; char * key = buffer; char * value; size_t nkey; size_t nvalue; - buffer[511] = '\0'; tmp = memchr(key, ' ', 512); if (NULL != tmp) { @@ -76,10 +77,14 @@ httpWorkerCtor(void * _this, va_list * params) nkey = tmp - buffer; value = tmp + 1; - for (; *value == ' ' && value < buffer+512; value++); + for (; *value == ' ' && value < buffer+511; value++); nvalue = strlen(value); + if ('\n' == value[nvalue-1]) { + value[nvalue-1] = '\0'; + } + hashAdd(this->mime_types, new(HashValue, key, nkey, value, nvalue)); } diff --git a/src/http/worker/process.c b/src/http/worker/process.c index 078ac93..774a9ea 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -225,16 +225,25 @@ httpWorkerProcess(HttpWorker this, Stream st) } else { - char asset[2048] = "./assets/html"; + char html_asset[2048] = "./assets/html"; + char base_asset[2048] = "./assets"; + char * extension = strrchr(request->path, '.'); char * mime_type = NULL; char default_mime[] = "application/octet-stream"; + char * asset = base_asset; + if (NULL != extension) { extension++; mime_type = httpWorkerGetMimeType(this, extension); } + if (NULL != mime_type && + 0 == memcmp(mime_type, CSTRA("text/html"))) { + asset = html_asset; + } + if (NULL == mime_type) { mime_type = default_mime; } From f8fd49938d7002cf62f44ebd6fff55044ed19221 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 28 Aug 2013 15:39:51 +0100 Subject: [PATCH 68/97] now allocate only a multiple of pagesize --- src/utils/memory.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/utils/memory.c b/src/utils/memory.c index 08a31d3..59db11c 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -51,9 +51,14 @@ #include #include #include +#include #include "utils/memory.h" + +#define PAGE_SIZE = 32 + + enum rbColor {rbBlack=1, rbRed=2}; @@ -75,6 +80,12 @@ struct memSegment struct memSegment * newElement(size_t size) { + long psize = sysconf(_SC_PAGESIZE); + + /* allocate only blocks of a multiple of pagesize, similar to cbuf */ + size = (0 >= size)? 1 : (0 != size%psize)? (size/psize)+1 : size/psize; + size *= psize; + struct memSegment * element = malloc(size + sizeof(struct memSegment)); element->size = size; From 5d2b27de1cd0e276d7dc685ee3159d2d961da185 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 28 Aug 2013 21:15:54 +0100 Subject: [PATCH 69/97] remove specialized asset loadings and use generic one. --- assets/html/main.html | 12 +++---- src/http/worker.c | 3 +- src/http/worker/process.c | 66 ++++++++++----------------------------- 3 files changed, 24 insertions(+), 57 deletions(-) diff --git a/assets/html/main.html b/assets/html/main.html index a61e444..1fad493 100644 --- a/assets/html/main.html +++ b/assets/html/main.html @@ -4,11 +4,11 @@ My own little Web-App - - - - - + + + + +