]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
cleanup and unit test for alloc, also lock protection statements.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Mar 2007 13:37:57 +0000 (13:37 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Mar 2007 13:37:57 +0000 (13:37 +0000)
git-svn-id: file:///svn/unbound/trunk@168 be551aaa-1e26-0410-a405-d3ace91eadb9

13 files changed:
daemon/daemon.c
daemon/daemon.h
daemon/worker.c
daemon/worker.h
doc/Changelog
testcode/checklocks.c
testcode/checklocks.h
testcode/unitmain.c
util/alloc.c
util/alloc.h
util/locks.h
util/log.c
util/log.h

index 2b32e26afc55f5b5a9b4e7f193048566b4bfc832..e6e396135d120087bfaf345c7259b52250f67713 100644 (file)
@@ -114,8 +114,9 @@ daemon_init()
        if(!daemon)
                return NULL;
        signal_handling_record();
-       lock_basic_init(&daemon->lock);
+       checklock_start();
        daemon->need_to_exit = 0;
+       alloc_init(&daemon->superalloc, NULL);
        return daemon;  
 }
 
@@ -302,8 +303,9 @@ daemon_delete(struct daemon* daemon)
        if(!daemon)
                return;
        listening_ports_free(daemon->ports);
-       lock_basic_destroy(&daemon->lock);
+       alloc_clear(&daemon->superalloc);
        free(daemon->cwd);
        free(daemon->pidfile);
        free(daemon);
+       checklock_stop();
 }
index 46edecaa4dfef022b50786a2f20f0256c4516aab..c5f26871fadd1e84897172ac63c92ad454d732cf 100644 (file)
@@ -43,6 +43,7 @@
 #define DAEMON_H
 
 #include "util/locks.h"
+#include "util/alloc.h"
 struct config_file;
 struct worker;
 struct listen_port;
@@ -52,8 +53,6 @@ struct listen_port;
  * Holds globally visible information.
  */
 struct daemon {
-       /** mutex for exclusive access to this structure. */
-       lock_basic_t lock;
        /** The config settings */
        struct config_file* cfg;
        /** current working directory */
@@ -70,6 +69,8 @@ struct daemon {
        struct worker** workers;
        /** do we need to exit unbound (or is it only a reload?) */
        int need_to_exit;
+       /** master allocation cache */
+       struct alloc_cache superalloc;
 };
 
 /**
index 6e68902fb731ad29b24502eae3beb178c63b3e9e..e1c380286ede7ad6fb3fc273166df119c036cf6f 100644 (file)
@@ -44,6 +44,7 @@
 #include "util/net_help.h"
 #include "util/random.h"
 #include "daemon/worker.h"
+#include "daemon/daemon.h"
 #include "util/netevent.h"
 #include "util/config_file.h"
 #include "services/listen_dnsport.h"
@@ -387,6 +388,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
                        fatal_exit("could not set forwarder address");
                }
        }
+       alloc_init(&worker->alloc, &worker->daemon->superalloc);
        return 1;
 }
 
@@ -416,6 +418,7 @@ worker_delete(struct worker* worker)
        if(worker->cmd_recv_fd != -1)
                close(worker->cmd_recv_fd);
        worker->cmd_recv_fd = -1;
+       alloc_clear(&worker->alloc);
        free(worker);
 }
 
index 5121bdc0d533caf0ea0bd18ed94ae8349880641e..5a8cef2a53d7f00adfa195a9d6908e7d7722c43d 100644 (file)
@@ -46,6 +46,7 @@
 #include "config.h"
 #include "util/netevent.h"
 #include "util/locks.h"
+#include "util/alloc.h"
 struct listen_dnsport;
 struct outside_network;
 struct config_file;
@@ -105,6 +106,8 @@ struct worker {
        struct ub_randstate* rndstate;
        /** do we need to restart (instead of exit) ? */
        int need_to_restart;
+       /** allocation cache for this thread */
+       struct alloc_cache alloc;
 };
 
 /**
index 83e4785a0d38c8471f9e97ee15741057ae9f2564..8e3666bfe1e0f0f0893be5265d3d722c0ab4d59f 100644 (file)
@@ -2,6 +2,9 @@
        - added rwlock writelock checking.
          So it will keep track of the writelock, and readlocks are enforced
          to not change protected memory areas.
+       - log_hex function to dump hex strings to the logfile.
+       - checklocks zeroes its destroyed lock after checking memory areas.
+       - unit test for alloc.
 
 8 March 2007: Wouter
        - Reviewed checklock code.
index 4ca4128113c3e1ae127afb3fc8b86475853e2dfe..2e8de0f203df4260aa8dd1edad04ce77270334c6 100644 (file)
@@ -71,7 +71,8 @@ static void lock_error(struct checked_lock* lock,
        log_err("At %s %s:%d", func, file, line);
        log_err("Error for %s lock: %s",
                (lock->type==check_lock_mutex)?"mutex": (
-               (lock->type==check_lock_spinlock)?"spinlock": "rwlock"), err);
+               (lock->type==check_lock_spinlock)?"spinlock": (
+               (lock->type==check_lock_rwlock)?"rwlock": "badtype")), err);
        fatal_exit("bailing out");
 }
 
@@ -111,8 +112,9 @@ acquire_locklock(struct checked_lock* lock,
 
 /** add protected region */
 void 
-lock_protect(struct checked_lock* lock, void* area, size_t size)
+lock_protect(void *p, void* area, size_t size)
 {
+       struct checked_lock* lock = *(struct checked_lock**)p;
        struct protected_area* e = (struct protected_area*)malloc(
                sizeof(struct protected_area));
        if(!e)
@@ -144,6 +146,8 @@ prot_check(struct checked_lock* lock,
        struct protected_area* p = lock->prot;
        while(p) {
                if(memcmp(p->hold, p->region, p->size) != 0) {
+                       log_hex("memory prev", p->hold, p->size);
+                       log_hex("memory here", p->region, p->size);
                        lock_error(lock, func, file, line, 
                                "protected area modified");
                }
@@ -211,6 +215,9 @@ static void
 checktype(enum check_lock_type type, struct checked_lock* lock,
         const char* func, const char* file, int line)
 {
+       if(!lock) 
+               fatal_exit("use of null/deleted lock at %s %s:%d", 
+                       func, file, line);
        if(type != lock->type) {
                lock_error(lock, func, file, line, "wrong lock type");
        }
@@ -232,12 +239,12 @@ checklock_destroy(enum check_lock_type type, struct checked_lock** lock,
 
        /* check if delete is OK */
        acquire_locklock(e, func, file, line);
-       *lock = NULL; /* use after free will fail */
        if(e->hold_count != 0)
                lock_error(e, func, file, line, "delete while locked.");
        if(e->wait_count != 0)
                lock_error(e, func, file, line, "delete while waited on.");
        prot_check(e, func, file, line);
+       *lock = NULL; /* use after free will fail */
        LOCKRET(pthread_mutex_unlock(&e->lock));
 
        /* contention */
@@ -521,6 +528,7 @@ static void* checklock_main(void* arg)
        thr->id = pthread_self();
        /* Hack to get same numbers as in log file */
        thr->num = *(int*)(thr->arg);
+       log_assert(thr->num < THRDEBUG_MAX_THREADS);
        log_assert(thread_infos[thr->num] == NULL);
        thread_infos[thr->num] = thr;
        LOCKRET(pthread_setspecific(thr_debug_key, thr));
@@ -530,14 +538,9 @@ static void* checklock_main(void* arg)
        return ret;
 }
 
-/** allocate debug info and create thread */
-void 
-checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg)
+/** init the main thread */
+void checklock_start()
 {
-       struct thr_check* thr = (struct thr_check*)calloc(1, 
-               sizeof(struct thr_check));
-       if(!thr)
-               fatal_exit("thrcreate: out of memory");
        if(!key_created) {
                struct thr_check* thisthr = (struct thr_check*)calloc(1, 
                        sizeof(struct thr_check));
@@ -548,6 +551,34 @@ checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg)
                LOCKRET(pthread_setspecific(thr_debug_key, thisthr));
                thread_infos[0] = thisthr;
        }
+}
+
+/** stop checklocks */
+void checklock_stop()
+{
+       if(key_created) {
+               int i;
+               free(thread_infos[0]);
+               thread_infos[0] = NULL;
+               for(i = 0; i < THRDEBUG_MAX_THREADS; i++)
+                       log_assert(thread_infos[i] == NULL);
+                       /* should have been cleaned up. */
+               LOCKRET(pthread_key_delete(thr_debug_key));
+               key_created = 0;
+       }
+}
+
+/** allocate debug info and create thread */
+void 
+checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg)
+{
+       struct thr_check* thr = (struct thr_check*)calloc(1, 
+               sizeof(struct thr_check));
+       if(!thr)
+               fatal_exit("thrcreate: out of memory");
+       if(!key_created) {
+               checklock_start();
+       }
        thr->func = func;
        thr->arg = arg;
        LOCKRET(pthread_create(id, NULL, checklock_main, thr));
index 44f17160cb4bdf80c3df93822bf1b11b0edd9a86..8170e1333ba08a8b117fdb77bb3ab20261c46e5b 100644 (file)
@@ -171,7 +171,8 @@ struct checked_lock {
 /**
  * Additional call for the user to specify what areas are protected
  * @param lock: the lock that protects the area. It can be inside the area.
- *     The lock must be inited.
+ *     The lock must be inited. Call with user lock. (any type).
+ *     It demangles the lock itself (struct checked_lock**).
  * @param area: ptr to mem.
  * @param size: length of area.
  * You can call it multiple times with the same lock to give several areas.
@@ -179,7 +180,17 @@ struct checked_lock {
  * at this time and protected right away against unauthorised changes until 
  * the next lock() call is done.
  */
-void lock_protect(struct checked_lock* lock, void* area, size_t size);
+void lock_protect(void* lock, void* area, size_t size);
+
+/**
+ * Initialise checklock. Sets up internal debug structures.
+ */
+void checklock_start();
+
+/**
+ * Cleanup internal debug state.
+ */
+void checklock_stop();
 
 /**
  * Init locks.
index 5dd045c8779c040fb5f34e84a351f63dbb0619c1..cf658aa1df0593cd2d975c9febe58e118a6b3df0 100644 (file)
@@ -47,6 +47,46 @@ int testcount = 0;
 /** test bool x, exits on failure, increases testcount. */
 #define unit_assert(x) testcount++; log_assert(x);
 
+#include "util/alloc.h"
+/** test alloc code */
+static void
+alloc_test() {
+       alloc_special_t *t1, *t2;
+       struct alloc_cache major, minor1, minor2;
+       int i;
+
+       checklock_start();
+       alloc_init(&major, NULL);
+       alloc_init(&minor1, &major);
+       alloc_init(&minor2, &major);
+
+       t1 = alloc_special_obtain(&minor1);
+       alloc_clear(&minor1);
+
+       alloc_special_release(&minor2, t1);
+       t2 = alloc_special_obtain(&minor2);
+       unit_assert( t1 == t2 ); /* reused */
+       alloc_special_release(&minor2, t1);
+
+       for(i=0; i<100; i++) {
+               t1 = alloc_special_obtain(&minor1);
+               alloc_special_release(&minor2, t1);
+       }
+       if(0) {
+               alloc_stats(&minor1);
+               alloc_stats(&minor2);
+               alloc_stats(&major);
+       }
+       /* reuse happened */
+       unit_assert(minor1.num_quar + minor2.num_quar + major.num_quar == 11);
+
+       alloc_clear(&minor1);
+       alloc_clear(&minor2);
+       unit_assert(major.num_quar == 11);
+       alloc_clear(&major);
+       checklock_stop();
+}
+
 #include "util/net_help.h"
 /** test net code */
 static void 
@@ -78,6 +118,7 @@ main(int argc, char* argv[])
        }
        printf("Start of %s unit test.\n", PACKAGE_STRING);
        net_test();
+       alloc_test();
        printf("%d tests succeeded\n", testcount);
        return 0;
 }
index ff0fc95285ac61663b84fe7b7f9c13e3ef0276c0..7f6ad7566bda9df8a7e39e884f256bb559baef60 100644 (file)
@@ -65,16 +65,20 @@ alloc_init(struct alloc_cache* alloc, struct alloc_cache* super)
 {
        memset(alloc, 0, sizeof(*alloc));
        alloc->super = super;
-       lock_quick_init(&alloc->lock);
+       if(!alloc->super) {
+               lock_quick_init(&alloc->lock);
+               lock_protect(&alloc->lock, alloc, sizeof(*alloc));
+       }
 }
 
 void 
-alloc_delete(struct alloc_cache* alloc)
+alloc_clear(struct alloc_cache* alloc)
 {
        alloc_special_t* p, *np;
        if(!alloc)
                return;
-       lock_quick_destroy(&alloc->lock);
+       if(!alloc->super)
+               lock_quick_destroy(&alloc->lock);
        if(alloc->super && alloc->quar) {
                /* push entire list into super */
                p = alloc->quar;
@@ -108,7 +112,6 @@ alloc_special_obtain(struct alloc_cache* alloc)
                p = alloc->quar;
                alloc->quar = alloc_special_next(p);
                alloc->num_quar--;
-               alloc->special_allocated++;
                alloc_special_clean(p);
                return p;
        }
@@ -123,7 +126,6 @@ alloc_special_obtain(struct alloc_cache* alloc)
                }
                lock_quick_unlock(&alloc->super->lock);
                if(p) {
-                       alloc->special_allocated++;
                        alloc_special_clean(p);
                        return p;
                }
@@ -132,7 +134,6 @@ alloc_special_obtain(struct alloc_cache* alloc)
        prealloc(alloc);
        if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t))))
                fatal_exit("alloc_special_obtain: out of memory");
-       alloc->special_allocated++;
        alloc_special_clean(p);
        return p;
 }
@@ -172,7 +173,6 @@ alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem)
        alloc_special_clean(mem);
        if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) {
                /* push it to the super structure */
-               alloc->special_allocated --;
                pushintosuper(alloc, mem);
                return;
        }
@@ -180,12 +180,11 @@ alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem)
        alloc_special_next(mem) = alloc->quar;
        alloc->quar = mem;
        alloc->num_quar++;
-       alloc->special_allocated--;
 }
 
 void 
 alloc_stats(struct alloc_cache* alloc)
 {
-       log_info("%salloc: %d allocated, %d in cache.", alloc->super?"":"sup",
-               (int)alloc->special_allocated, (int)alloc->num_quar);
+       log_info("%salloc: %d in cache.", alloc->super?"":"sup",
+               (int)alloc->num_quar);
 }
index 05f7930f9b09d1c5147f7ce9738eb776af81ff8f..d261b6147af1f52d4348a427ddba2257096b916b 100644 (file)
@@ -73,9 +73,6 @@ struct alloc_cache {
        alloc_special_t* quar;
        /** number of items in quarantine. */
        size_t num_quar;
-
-       /** number of special type allocated */
-       size_t special_allocated;
 };
 
 /**
@@ -92,7 +89,7 @@ void alloc_init(struct alloc_cache* alloc, struct alloc_cache* super);
  * Does not free the alloc struct itself (it was also allocated by caller).
  * @param alloc: is almost zeroed on exit (except some stats).
  */
-void alloc_delete(struct alloc_cache* alloc);
+void alloc_clear(struct alloc_cache* alloc);
 
 /**
  * Get a new special_t element.
index 408f14a33a849cd48ed4dce375c69570319fd3a9..fb99a79db2c77dd85c2557ef67f0c038f035f117 100644 (file)
@@ -77,6 +77,8 @@
 
 #else /* USE_THREAD_DEBUG */
 #define lock_protect(lock, area, size) /* nop */
+#define checklock_start() /* nop */
+#define checklock_stop() /* nop */
 
 #ifdef HAVE_PTHREAD
 #include <pthread.h>
index 81784df89f17ee64fa653334ba11e0ab495c3e62..146fa8fa72577618b62d62f26dc31fa701af6610 100644 (file)
@@ -166,3 +166,18 @@ verbose(enum verbosity_value level, const char* format, ...)
        va_end(args);
 }
 
+void 
+log_hex(const char* msg, void* data, size_t length)
+{
+       size_t i;
+       uint8_t* data8 = (uint8_t*)data;
+       const char const* hexchar = "0123456789ABCDEF";
+       char* buf = malloc(length*2 + 1); /* alloc hex chars + \0 */
+       for(i=0; i<length; i++) {
+               buf[i*2] = hexchar[ data8[i] >> 4 ];
+               buf[i*2 + 1] = hexchar[ data8[i] & 0xF ];
+       }
+       buf[length*2] = 0;
+       log_info("%s[%d] %s", msg, length, buf);
+       free(buf);
+}
index 5b58f4c749bfd2ab8e33c795d0d7b244420a90bf..c6fd5abf563d877ca93a0742c84f88e1ae3f01a3 100644 (file)
@@ -109,6 +109,15 @@ void log_err(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
  */
 void log_warn(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
 
+/**
+ * Log a hex-string to the log. Can be any length.
+ * performs mallocs to do so, slow. But debug useful.
+ * @param msg: string desc to accompany the hexdump.
+ * @param data: data to dump in hex format.
+ * @param length: length of data.
+ */
+void log_hex(const char* msg, void* data, size_t length);
+
 /**
  * Log fatal error message, and exit the current process.
  * Pass printf formatted arguments. No trailing newline is needed.