diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-12-05 16:44:41 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-12-05 16:44:41 +0000 |
commit | 2db1ef4ac8928944958712923b9c89c263a337d2 (patch) | |
tree | 700043d9d97b7e7ba344b448918728af0a8be8d1 /src/libstrongswan/utils | |
parent | 5dc75410286b0e3a16845b44dd696ba0f40df573 (diff) | |
download | vyos-strongswan-2db1ef4ac8928944958712923b9c89c263a337d2.tar.gz vyos-strongswan-2db1ef4ac8928944958712923b9c89c263a337d2.zip |
- Updated to new upstream.
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r-- | src/libstrongswan/utils/backtrace.c | 183 | ||||
-rw-r--r-- | src/libstrongswan/utils/backtrace.h | 63 | ||||
-rw-r--r-- | src/libstrongswan/utils/host.c | 139 | ||||
-rw-r--r-- | src/libstrongswan/utils/host.h | 6 | ||||
-rw-r--r-- | src/libstrongswan/utils/iterator.h | 57 | ||||
-rw-r--r-- | src/libstrongswan/utils/leak_detective.c | 155 | ||||
-rw-r--r-- | src/libstrongswan/utils/leak_detective.h | 5 | ||||
-rw-r--r-- | src/libstrongswan/utils/linked_list.c | 113 | ||||
-rw-r--r-- | src/libstrongswan/utils/linked_list.h | 29 | ||||
-rw-r--r-- | src/libstrongswan/utils/mutex.c | 280 | ||||
-rw-r--r-- | src/libstrongswan/utils/mutex.h | 53 |
11 files changed, 688 insertions, 395 deletions
diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c new file mode 100644 index 000000000..3caafdc38 --- /dev/null +++ b/src/libstrongswan/utils/backtrace.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + * + * $Id$ + */ + +#define _GNU_SOURCE + +#ifdef HAVE_DLADDR +# include <dlfcn.h> +#endif /* HAVE_DLADDR */ + +#ifdef HAVE_BACKTRACE +# include <execinfo.h> +#endif /* HAVE_BACKTRACE */ + +#include "backtrace.h" + +typedef struct private_backtrace_t private_backtrace_t; + +/** + * Private data of an backtrace_t object. + */ +struct private_backtrace_t { + + /** + * Public backtrace_t interface. + */ + backtrace_t public; + + /** + * Number of stacks frames obtained in stack_frames + */ + int frame_count; + + /** + * Recorded stack frames. + */ + void *frames[]; +}; + +/** + * Implementation of backtrace_t.log + */ +static void log_(private_backtrace_t *this, FILE *file) +{ +#ifdef HAVE_BACKTRACE + size_t i; + char **strings; + + strings = backtrace_symbols(this->frames, this->frame_count); + + fprintf(file, " dumping %d stack frame addresses:\n", this->frame_count); + for (i = 0; i < this->frame_count; i++) + { +#ifdef HAVE_DLADDR + Dl_info info; + + if (dladdr(this->frames[i], &info)) + { + char cmd[1024]; + FILE *output; + char c; + void *ptr = this->frames[i]; + + if (strstr(info.dli_fname, ".so")) + { + ptr = (void*)(this->frames[i] - info.dli_fbase); + } + snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr); + if (info.dli_sname) + { + fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n", + info.dli_fname, info.dli_fbase, info.dli_sname, + this->frames[i] - info.dli_saddr, this->frames[i]); + } + else + { + fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname, + info.dli_fbase, this->frames[i]); + } + fprintf(file, " -> \e[32m"); + output = popen(cmd, "r"); + if (output) + { + while (TRUE) + { + c = getc(output); + if (c == '\n' || c == EOF) + { + break; + } + fputc(c, file); + } + pclose(output); + } + else + { +#endif /* HAVE_DLADDR */ + fprintf(file, " %s\n", strings[i]); +#ifdef HAVE_DLADDR + } + fprintf(file, "\n\e[0m"); + } + else + { + fprintf(file, " %s\n", strings[i]); + } +#endif /* HAVE_DLADDR */ + } + free (strings); +#else /* !HAVE_BACKTRACE */ + fprintf(file, "C library does not support backtrace().\n"); +#endif /* HAVE_BACKTRACE */ +} + +/** + * Implementation of backtrace_t.contains_function + */ +static bool contains_function(private_backtrace_t *this, char *function) +{ +#ifdef HAVE_DLADDR + int i; + + for (i = 0; i< this->frame_count; i++) + { + Dl_info info; + + if (dladdr(this->frames[i], &info) && info.dli_sname) + { + if (streq(info.dli_sname, function)) + { + return TRUE; + } + } + } +#endif /* HAVE_DLADDR */ + return FALSE; +} + +/** + * Implementation of backtrace_t.destroy. + */ +static void destroy(private_backtrace_t *this) +{ + free(this); +} + +/** + * See header + */ +backtrace_t *backtrace_create(int skip) +{ + private_backtrace_t *this; + void *frames[50]; + int frame_count = 0; + +#ifdef HAVE_BACKTRACE + frame_count = backtrace(frames, countof(frames)); +#endif /* HAVE_BACKTRACE */ + frame_count = max(frame_count - skip, 0); + this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*)); + memcpy(this->frames, frames + skip, frame_count * sizeof(void*)); + this->frame_count = frame_count; + + this->public.log = (void(*)(backtrace_t*,FILE*))log_; + this->public.contains_function = (bool(*)(backtrace_t*, char *function))contains_function; + this->public.destroy = (void(*)(backtrace_t*))destroy; + + return &this->public; +} + diff --git a/src/libstrongswan/utils/backtrace.h b/src/libstrongswan/utils/backtrace.h new file mode 100644 index 000000000..72effd01e --- /dev/null +++ b/src/libstrongswan/utils/backtrace.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +/** + * @defgroup backtrace backtrace + * @{ @ingroup utils + */ + +#ifndef BACKTRACE_H_ +#define BACKTRACE_H_ + +#include <stdio.h> + +#include <library.h> + +typedef struct backtrace_t backtrace_t; + +/** + * A backtrace registers the frames on the stack during creation. + */ +struct backtrace_t { + + /** + * Log the backtrace to a FILE stream. + */ + void (*log)(backtrace_t *this, FILE *file); + + /** + * Check if the backtrace contains a frame in a specific function. + * + * @param function name + * @return TRUE if function is in the stack + */ + bool (*contains_function)(backtrace_t *this, char *function); + + /** + * Destroy a backtrace instance. + */ + void (*destroy)(backtrace_t *this); +}; + +/** + * Create a backtrace of the current stack. + * + * @param skip how many of the innerst frames to skip + * @return backtrace + */ +backtrace_t *backtrace_create(int skip); + +#endif /* BACKTRACE_H_ @}*/ + diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c index eb87f27bc..4702222e8 100644 --- a/src/libstrongswan/utils/host.c +++ b/src/libstrongswan/utils/host.c @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: host.c 4056 2008-06-11 07:44:23Z martin $ + * $Id: host.c 4639 2008-11-12 15:09:24Z martin $ */ #define _GNU_SOURCE @@ -27,6 +27,9 @@ #include <debug.h> +#define IPV4_LEN 4 +#define IPV6_LEN 16 + typedef struct private_host_t private_host_t; /** @@ -83,17 +86,17 @@ static bool is_anyaddr(private_host_t *this) { case AF_INET: { - u_int8_t default_route[4]; - memset(default_route, 0, sizeof(default_route)); - return memeq(default_route, &(this->address4.sin_addr.s_addr), - sizeof(default_route)); + u_int8_t zeroes[IPV4_LEN]; + + memset(zeroes, 0, IPV4_LEN); + return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN); } case AF_INET6: { - u_int8_t default_route[16]; - memset(default_route, 0, sizeof(default_route)); - return memeq(default_route, &(this->address6.sin6_addr.s6_addr), - sizeof(default_route)); + u_int8_t zeroes[IPV6_LEN]; + + memset(zeroes, 0, IPV6_LEN); + return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN); } default: { @@ -196,13 +199,13 @@ static chunk_t get_address(private_host_t *this) case AF_INET: { address.ptr = (char*)&(this->address4.sin_addr.s_addr); - address.len = 4; + address.len = IPV4_LEN; return address; } case AF_INET6: { address.ptr = (char*)&(this->address6.sin6_addr.s6_addr); - address.len = 16; + address.len = IPV6_LEN; return address; } default: @@ -285,33 +288,21 @@ static bool ip_equals(private_host_t *this, private_host_t *other) { if (this->address.sa_family != other->address.sa_family) { - /* 0.0.0.0 and ::0 are equal */ - if (is_anyaddr(this) && is_anyaddr(other)) - { - return TRUE; - } - - return FALSE; + /* 0.0.0.0 and 0::0 are equal */ + return (is_anyaddr(this) && is_anyaddr(other)); } switch (this->address.sa_family) { case AF_INET: { - if (memeq(&this->address4.sin_addr, &other->address4.sin_addr, - sizeof(this->address4.sin_addr))) - { - return TRUE; - } - break; + return memeq(&this->address4.sin_addr, &other->address4.sin_addr, + sizeof(this->address4.sin_addr)); } case AF_INET6: { - if (memeq(&this->address6.sin6_addr, &other->address6.sin6_addr, - sizeof(this->address6.sin6_addr))) - { - return TRUE; - } + return memeq(&this->address6.sin6_addr, &other->address6.sin6_addr, + sizeof(this->address6.sin6_addr)); } default: break; @@ -340,7 +331,7 @@ static host_diff_t get_differences(host_t *this, host_t *other) } /** - * Impelements host_t.equals + * Implements host_t.equals */ static bool equals(private_host_t *this, private_host_t *other) { @@ -353,19 +344,11 @@ static bool equals(private_host_t *this, private_host_t *other) { case AF_INET: { - if (this->address4.sin_port == other->address4.sin_port) - { - return TRUE; - } - break; + return (this->address4.sin_port == other->address4.sin_port); } case AF_INET6: { - if (this->address6.sin6_port == other->address6.sin6_port) - { - return TRUE; - } - break; + return (this->address6.sin6_port == other->address6.sin6_port); } default: break; @@ -409,8 +392,14 @@ static private_host_t *host_create_empty(void) */ host_t *host_create_from_string(char *string, u_int16_t port) { - private_host_t *this = host_create_empty(); + private_host_t *this; + if (streq(string, "%any")) + { + return host_create_any(AF_INET); + } + + this = host_create_empty(); if (strchr(string, '.')) { this->address.sa_family = AF_INET; @@ -419,7 +408,6 @@ host_t *host_create_from_string(char *string, u_int16_t port) { this->address.sa_family = AF_INET6; } - switch (this->address.sa_family) { case AF_INET: @@ -460,9 +448,14 @@ host_t *host_create_from_dns(char *string, int af, u_int16_t port) struct hostent host, *ptr; char buf[512]; int err, ret; - - if (strchr(string, ':')) - { /* gethostbyname does not like IPv6 addresses, fallback */ + + if (streq(string, "%any")) + { + return host_create_any(af ? af : AF_INET); + } + else if (strchr(string, ':')) + { + /* gethostbyname does not like IPv6 addresses - fallback */ return host_create_from_string(string, port); } @@ -511,38 +504,56 @@ host_t *host_create_from_dns(char *string, int af, u_int16_t port) */ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) { - private_host_t *this = host_create_empty(); + private_host_t *this; - this->address.sa_family = family; switch (family) { case AF_INET: - { - if (address.len != 4) + if (address.len < IPV4_LEN) { - break; + return NULL; } - memcpy(&(this->address4.sin_addr.s_addr), address.ptr,4); - this->address4.sin_port = htons(port); - this->socklen = sizeof(struct sockaddr_in); - return &(this->public); - } + address.len = IPV4_LEN; + break; case AF_INET6: - { - if (address.len != 16) + if (address.len < IPV6_LEN) { - break; + return NULL; + } + address.len = IPV6_LEN; + break; + case AF_UNSPEC: + switch (address.len) + { + case IPV4_LEN: + family = AF_INET; + break; + case IPV6_LEN: + family = AF_INET6; + break; + default: + return NULL; } - memcpy(&(this->address6.sin6_addr.s6_addr), address.ptr, 16); + break; + default: + return NULL; + } + this = host_create_empty(); + this->address.sa_family = family; + switch (family) + { + case AF_INET: + memcpy(&this->address4.sin_addr.s_addr, address.ptr, address.len); + this->address4.sin_port = htons(port); + this->socklen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + memcpy(&this->address6.sin6_addr.s6_addr, address.ptr, address.len); this->address6.sin6_port = htons(port); this->socklen = sizeof(struct sockaddr_in6); - return &this->public; - } - default: break; } - free(this); - return NULL; + return &this->public; } /* diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h index 6a1d824c6..667cc6bcc 100644 --- a/src/libstrongswan/utils/host.h +++ b/src/libstrongswan/utils/host.h @@ -170,10 +170,12 @@ host_t *host_create_from_string(char *string, u_int16_t port); host_t *host_create_from_dns(char *string, int family, u_int16_t port); /** - * Constructor to create a host_t object from an address chunk + * Constructor to create a host_t object from an address chunk. + * + * If family is AF_UNSPEC, it is guessed using address.len. * * @param family Address family, such as AF_INET or AF_INET6 - * @param address address as chunk_t in networ order + * @param address address as chunk_t in network order * @param port port number * @return host_t, NULL if family not supported/chunk invalid */ diff --git a/src/libstrongswan/utils/iterator.h b/src/libstrongswan/utils/iterator.h index a1bdad1d6..28ee74cd6 100644 --- a/src/libstrongswan/utils/iterator.h +++ b/src/libstrongswan/utils/iterator.h @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: iterator.h 3589 2008-03-13 14:14:44Z martin $ + * $Id: iterator.h 4577 2008-11-05 08:37:09Z martin $ */ /** @@ -26,43 +26,6 @@ #include <library.h> -typedef enum hook_result_t hook_result_t; - -/** - * Return value of an iterator hook. - * - * Returning HOOK_AGAIN is useful to "inject" additional elements in an - * iteration, HOOK_NEXT is the normal iterator behavior, and HOOK_SKIP may - * be used to filter elements out. - */ -enum hook_result_t { - - /** - * A value was placed in out, hook is called again with the same "in" - */ - HOOK_AGAIN, - - /** - * A value was placed in out, hook is called again with next "in" (if any) - */ - HOOK_NEXT, - - /** - * No value in out, call again with next "in" (if any) - */ - HOOK_SKIP, -}; - -/** - * Iterator hook function prototype. - * - * @param param user supplied parameter - * @param in the value the hook receives from the iterator - * @param out the value supplied as a result to the iterator - * @return a hook_result_t - */ -typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out); - typedef struct iterator_t iterator_t; @@ -94,24 +57,6 @@ struct iterator_t { bool (*iterate) (iterator_t *this, void** value); /** - * Hook a function into the iterator. - * - * Sometimes it is useful to hook in an iterator. The hook function is - * called before any successful return of iterate(). It takes the - * iterator value, may manipulate it (or the references object), and returns - * the value that the iterate() function returns. Depending on the hook - * return value, the hook is called again, called with next, or skipped. - * A value of NULL deactivates the iterator hook. - * If an iterator is hooked, only the iterate() method is valid, - * all other methods behave undefined. - * - * @param hook iterator hook which manipulates the iterated value - * @param param user supplied parameter to pass back to the hook - */ - void (*set_iterator_hook) (iterator_t *this, iterator_hook_t *hook, - void *param); - - /** * Inserts a new item before the given iterator position. * * The iterator position is not changed after inserting diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index bc7f56ebd..73409158d 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -12,13 +12,8 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: leak_detective.c 4311 2008-08-28 16:27:48Z martin $ + * $Id: leak_detective.c 4609 2008-11-10 16:44:27Z martin $ */ - -#ifdef HAVE_DLADDR -# define _GNU_SOURCE -# include <dlfcn.h> -#endif /* HAVE_DLADDR */ #include <stddef.h> #include <string.h> @@ -28,21 +23,18 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <dlfcn.h> #include <unistd.h> #include <syslog.h> #include <pthread.h> #include <netdb.h> #include <printf.h> #include <locale.h> -#ifdef HAVE_BACKTRACE -# include <execinfo.h> -#endif /* HAVE_BACKTRACE */ #include "leak_detective.h" #include <library.h> #include <debug.h> +#include <utils/backtrace.h> typedef struct private_leak_detective_t private_leak_detective_t; @@ -106,16 +98,6 @@ struct memory_header_t { u_int bytes; /** - * Stack frames at the time of allocation - */ - void *stack_frames[STACK_FRAMES_COUNT]; - - /** - * Number of stacks frames obtained in stack_frames - */ - int stack_frame_count; - - /** * Pointer to previous entry in linked list */ memory_header_t *previous; @@ -126,6 +108,11 @@ struct memory_header_t { memory_header_t *next; /** + * backtrace taken during (re-)allocation + */ + backtrace_t *backtrace; + + /** * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC */ u_int32_t magic; @@ -151,7 +138,7 @@ struct memory_tail_t { static memory_header_t first_header = { magic: MEMORY_HEADER_MAGIC, bytes: 0, - stack_frame_count: 0, + backtrace: NULL, previous: NULL, next: NULL }; @@ -162,88 +149,21 @@ static memory_header_t first_header = { static bool installed = FALSE; /** - * log stack frames queried by backtrace() - * TODO: Dump symbols of static functions. This could be done with - * the addr2line utility or the GNU BFD Library... - */ -static void log_stack_frames(void **stack_frames, int stack_frame_count) -{ -#ifdef HAVE_BACKTRACE - size_t i; - char **strings; - - strings = backtrace_symbols(stack_frames, stack_frame_count); - - fprintf(stderr, " dumping %d stack frame addresses:\n", stack_frame_count); - for (i = 0; i < stack_frame_count; i++) - { -#ifdef HAVE_DLADDR - Dl_info info; - - if (dladdr(stack_frames[i], &info)) - { - char cmd[1024]; - FILE *output; - char c; - void *ptr = stack_frames[i]; - - if (strstr(info.dli_fname, ".so")) - { - ptr = (void*)(stack_frames[i] - info.dli_fbase); - } - snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr); - if (info.dli_sname) - { - fprintf(stderr, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n", - info.dli_fname, info.dli_fbase, info.dli_sname, - stack_frames[i] - info.dli_saddr, stack_frames[i]); - } - else - { - fprintf(stderr, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname, - info.dli_fbase, stack_frames[i]); - } - fprintf(stderr, " -> \e[32m"); - output = popen(cmd, "r"); - if (output) - { - while (TRUE) - { - c = getc(output); - if (c == '\n' || c == EOF) - { - break; - } - fputc(c, stderr); - } - } - else - { -#endif /* HAVE_DLADDR */ - fprintf(stderr, " %s\n", strings[i]); -#ifdef HAVE_DLADDR - } - fprintf(stderr, "\n\e[0m"); - } -#endif /* HAVE_DLADDR */ - } - free (strings); -#endif /* HAVE_BACKTRACE */ -} - -/** * Leak report white list * * List of functions using static allocation buffers or should be suppressed * otherwise on leak report. */ char *whitelist[] = { + /* backtraces, including own */ + "backtrace_create", /* pthread stuff */ "pthread_create", "pthread_setspecific", /* glibc functions */ "mktime", "__gmtime_r", + "localtime_r", "tzset", "inet_ntoa", "strerror", @@ -284,27 +204,16 @@ char *whitelist[] = { /** * check if a stack frame contains functions listed above */ -static bool is_whitelisted(void **stack_frames, int stack_frame_count) +static bool is_whitelisted(backtrace_t *backtrace) { - int i, j; - -#ifdef HAVE_DLADDR - for (i=0; i< stack_frame_count; i++) + int i; + for (i = 0; i < sizeof(whitelist)/sizeof(char*); i++) { - Dl_info info; - - if (dladdr(stack_frames[i], &info) && info.dli_sname) - { - for (j = 0; j < sizeof(whitelist)/sizeof(char*); j++) - { - if (streq(info.dli_sname, whitelist[j])) - { - return TRUE; - } - } + if (backtrace->contains_function(backtrace, whitelist[i])) + { + return TRUE; } } -#endif /* HAVE_DLADDR */ return FALSE; } @@ -318,7 +227,7 @@ void report_leaks() for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) { - if (is_whitelisted(hdr->stack_frames, hdr->stack_frame_count)) + if (is_whitelisted(hdr->backtrace)) { whitelisted++; } @@ -326,7 +235,7 @@ void report_leaks() { fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1); /* skip the first frame, contains leak detective logic */ - log_stack_frames(hdr->stack_frames + 1, hdr->stack_frame_count - 1); + hdr->backtrace->log(hdr->backtrace, stderr); leaks++; } } @@ -403,7 +312,7 @@ void *malloc_hook(size_t bytes, const void *caller) hdr->magic = MEMORY_HEADER_MAGIC; hdr->bytes = bytes; - hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT); + hdr->backtrace = backtrace_create(3); tail->magic = MEMORY_TAIL_MAGIC; install_hooks(); @@ -426,10 +335,9 @@ void *malloc_hook(size_t bytes, const void *caller) */ void free_hook(void *ptr, const void *caller) { - void *stack_frames[STACK_FRAMES_COUNT]; - int stack_frame_count; memory_header_t *hdr; memory_tail_t *tail; + backtrace_t *backtrace; pthread_t thread_id = pthread_self(); int oldpolicy; struct sched_param oldparams, params; @@ -455,8 +363,9 @@ void free_hook(void *ptr, const void *caller) fprintf(stderr, "freeing invalid memory (%p): " "header magic 0x%x, tail magic 0x%x:\n", ptr, hdr->magic, tail->magic); - stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); - log_stack_frames(stack_frames, stack_frame_count); + backtrace = backtrace_create(3); + backtrace->log(backtrace, stderr); + backtrace->destroy(backtrace); } else { @@ -466,10 +375,11 @@ void free_hook(void *ptr, const void *caller) hdr->next->previous = hdr->previous; } hdr->previous->next = hdr->next; - + hdr->backtrace->destroy(hdr->backtrace); + /* clear MAGIC, set mem to something remarkable */ memset(hdr, MEMORY_FREE_PATTERN, hdr->bytes + sizeof(memory_header_t)); - + free(hdr); } @@ -483,9 +393,8 @@ void free_hook(void *ptr, const void *caller) void *realloc_hook(void *old, size_t bytes, const void *caller) { memory_header_t *hdr; - void *stack_frames[STACK_FRAMES_COUNT]; - int stack_frame_count; memory_tail_t *tail; + backtrace_t *backtrace; pthread_t thread_id = pthread_self(); int oldpolicy; struct sched_param oldparams, params; @@ -512,8 +421,9 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) fprintf(stderr, "reallocating invalid memory (%p): " "header magic 0x%x, tail magic 0x%x:\n", old, hdr->magic, tail->magic); - stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); - log_stack_frames(stack_frames, stack_frame_count); + backtrace = backtrace_create(3); + backtrace->log(backtrace, stderr); + backtrace->destroy(backtrace); } /* clear tail magic, allocate, set tail magic */ memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic)); @@ -523,7 +433,8 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) /* update statistics */ hdr->bytes = bytes; - hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT); + hdr->backtrace->destroy(hdr->backtrace); + hdr->backtrace = backtrace_create(3); /* update header of linked list neighbours */ if (hdr->next) diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h index 763814726..3773fb8e5 100644 --- a/src/libstrongswan/utils/leak_detective.h +++ b/src/libstrongswan/utils/leak_detective.h @@ -21,11 +21,6 @@ #ifndef LEAK_DETECTIVE_H_ #define LEAK_DETECTIVE_H_ -/** - * Maximum depth stack frames to register - */ -#define STACK_FRAMES_COUNT 20 - typedef struct leak_detective_t leak_detective_t; /** diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c index 80c4e6f9f..068d13f99 100644 --- a/src/libstrongswan/utils/linked_list.c +++ b/src/libstrongswan/utils/linked_list.c @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: linked_list.c 3841 2008-04-18 11:48:53Z tobias $ + * $Id: linked_list.c 4580 2008-11-05 11:55:17Z martin $ */ #include <stdlib.h> @@ -119,21 +119,6 @@ struct private_iterator_t { * Direction of iterator. */ bool forward; - - /** - * Mutex to use to synchronize access - */ - pthread_mutex_t *mutex; - - /** - * iteration hook - */ - iterator_hook_t *hook; - - /** - * user parameter for iterator hook - */ - void *hook_param; }; typedef struct private_enumerator_t private_enumerator_t; @@ -208,75 +193,23 @@ static int get_list_count(private_iterator_t *this) } /** - * default iterator hook which does nothing - */ -static hook_result_t iterator_hook(void *param, void *in, void **out) -{ - *out = in; - return HOOK_NEXT; -} - -/** - * Implementation of iterator_t.set_iterator_hook. + * Implementation of iterator_t.iterate. */ -static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook, - void* param) +static bool iterate(private_iterator_t *this, void** value) { - if (hook == NULL) + if (this->forward) { - this->hook = iterator_hook; - this->hook_param = NULL; + this->current = this->current ? this->current->next : this->list->first; } else { - this->hook = hook; - this->hook_param = param; + this->current = this->current ? this->current->previous : this->list->last; } -} - -/** - * Implementation of iterator_t.iterate. - */ -static bool iterate(private_iterator_t *this, void** value) -{ - while (TRUE) + if (this->current == NULL) { - if (this->forward) - { - this->current = this->current ? this->current->next : this->list->first; - } - else - { - this->current = this->current ? this->current->previous : this->list->last; - } - - if (this->current == NULL) - { - return FALSE; - } - - switch (this->hook(this->hook_param, this->current->value, value)) - { - case HOOK_AGAIN: - /* rewind */ - if (this->forward) - { - this->current = this->current->previous; - } - else - { - this->current = this->current->next; - } - break; - case HOOK_NEXT: - /* normal iteration */ - break; - case HOOK_SKIP: - /* advance */ - continue; - } - break; + return FALSE; } + *value = this->current->value; return TRUE; } @@ -428,10 +361,6 @@ static void insert_after(private_iterator_t *iterator, void *item) */ static void iterator_destroy(private_iterator_t *this) { - if (this->mutex) - { - pthread_mutex_unlock(this->mutex); - } free(this); } @@ -632,7 +561,8 @@ static status_t find_first(private_linked_list_t *this, linked_list_match_t matc while (current) { - if (match(current->value, d1, d2, d3, d4, d5)) + if ((match && match(current->value, d1, d2, d3, d4, d5)) || + (!match && item && current->value == *item)) { if (item != NULL) { @@ -655,7 +585,8 @@ static status_t find_last(private_linked_list_t *this, linked_list_match_t match while (current) { - if (match(current->value, d1, d2, d3, d4, d5)) + if ((match && match(current->value, d1, d2, d3, d4, d5)) || + (!match && item && current->value == *item)) { if (item != NULL) { @@ -793,7 +724,6 @@ static iterator_t *create_iterator(private_linked_list_t *linked_list, bool forw this->public.get_count = (int (*) (iterator_t*)) get_list_count; this->public.iterate = (bool (*) (iterator_t*, void **value)) iterate; - this->public.set_iterator_hook = (void(*)(iterator_t*, iterator_hook_t*, void*))set_iterator_hook; this->public.insert_before = (void (*) (iterator_t*, void *item)) insert_before; this->public.insert_after = (void (*) (iterator_t*, void *item)) insert_after; this->public.replace = (status_t (*) (iterator_t*, void **, void *)) replace; @@ -804,22 +734,6 @@ static iterator_t *create_iterator(private_linked_list_t *linked_list, bool forw this->forward = forward; this->current = NULL; this->list = linked_list; - this->mutex = NULL; - this->hook = iterator_hook; - - return &this->public; -} - -/** - * Implementation of linked_list_t.create_iterator_locked. - */ -static iterator_t *create_iterator_locked(private_linked_list_t *linked_list, - pthread_mutex_t *mutex) -{ - private_iterator_t *this = (private_iterator_t*)create_iterator(linked_list, TRUE); - this->mutex = mutex; - - pthread_mutex_lock(mutex); return &this->public; } @@ -833,7 +747,6 @@ linked_list_t *linked_list_create() this->public.get_count = (int (*) (linked_list_t *)) get_count; this->public.create_iterator = (iterator_t * (*) (linked_list_t *,bool))create_iterator; - this->public.create_iterator_locked = (iterator_t * (*) (linked_list_t *,pthread_mutex_t*))create_iterator_locked; this->public.create_enumerator = (enumerator_t*(*)(linked_list_t*))create_enumerator; this->public.get_first = (status_t (*) (linked_list_t *, void **item))get_first; this->public.get_last = (status_t (*) (linked_list_t *, void **item))get_last; diff --git a/src/libstrongswan/utils/linked_list.h b/src/libstrongswan/utils/linked_list.h index 310e91e3c..ba47e7dfb 100644 --- a/src/libstrongswan/utils/linked_list.h +++ b/src/libstrongswan/utils/linked_list.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2008 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: linked_list.h 3841 2008-04-18 11:48:53Z tobias $ + * $Id: linked_list.h 4576 2008-11-05 08:32:38Z martin $ */ /** @@ -27,13 +27,10 @@ typedef struct linked_list_t linked_list_t; -#include <pthread.h> - #include <library.h> #include <utils/iterator.h> #include <utils/enumerator.h> - /** * Method to match elements in a linked list (used in find_* functions) * @@ -81,18 +78,6 @@ struct linked_list_t { iterator_t *(*create_iterator) (linked_list_t *this, bool forward); /** - * Creates a iterator, locking a mutex. - * - * The supplied mutex is acquired immediately, and released - * when the iterator gets destroyed. - * - * @param mutex mutex to use for exclusive access - * @return new iterator_t object - */ - iterator_t *(*create_iterator_locked) (linked_list_t *this, - pthread_mutex_t *mutex); - - /** * Create an enumerator over the list. * * The enumerator is a "lightweight" iterator. It only has two methods @@ -130,7 +115,7 @@ struct linked_list_t { * If a compare function is given, it is called for each item, where * the first parameter is the current list item and the second parameter * is the supplied item parameter. - * If compare is NULL, compare is is done by pointer. + * If compare is NULL, compare is done by pointer. * * @param item item to remove/pass to comparator * @param compare compare function, or NULL @@ -179,10 +164,12 @@ struct linked_list_t { * If the supplied function returns TRUE this function returns SUCCESS, and * the current object is returned in the third parameter, otherwise, * the next item is checked. + * + * If match is NULL, *item and the current object are compared. * * @warning Only use pointers as user supplied data. * - * @param match comparison function to call on each object + * @param match comparison function to call on each object, or NULL * @param item the list item, if found * @param ... user data to supply to match function (limited to 5 arguments) * @return SUCCESS if found, NOT_FOUND otherwise @@ -198,9 +185,11 @@ struct linked_list_t { * the current object is returned in the third parameter, otherwise, * the next item is checked. * + * If match is NULL, *item and the current object are compared. + * * @warning Only use pointers as user supplied data. * - * @param match comparison function to call on each object + * @param match comparison function to call on each object, or NULL * @param item the list item, if found * @param ... user data to supply to match function (limited to 5 arguments) * @return SUCCESS if found, NOT_FOUND otherwise diff --git a/src/libstrongswan/utils/mutex.c b/src/libstrongswan/utils/mutex.c index 425389b4f..ddb0d2df6 100644 --- a/src/libstrongswan/utils/mutex.c +++ b/src/libstrongswan/utils/mutex.c @@ -12,24 +12,92 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: mutex.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: mutex.c 4591 2008-11-05 16:12:54Z martin $ */ -#include "mutex.h" - -#include <library.h> -#include <debug.h> - +#define _GNU_SOURCE #include <pthread.h> #include <sys/time.h> +#include <stdint.h> #include <time.h> #include <errno.h> +#include "mutex.h" + +#include <library.h> +#include <debug.h> typedef struct private_mutex_t private_mutex_t; -typedef struct private_n_mutex_t private_n_mutex_t; typedef struct private_r_mutex_t private_r_mutex_t; typedef struct private_condvar_t private_condvar_t; +typedef struct private_rwlock_t private_rwlock_t; + +#ifdef LOCK_PROFILER + +/** + * Do not report mutexes with an overall waiting time smaller than this (in us) + */ +#define PROFILE_TRESHHOLD 1000 + +#include <utils/backtrace.h> + +typedef struct lock_profile_t lock_profile_t; + +struct lock_profile_t { + + /** + * how long threads have waited for the lock in this mutex so far + */ + struct timeval waited; + + /** + * backtrace where mutex has been created + */ + backtrace_t *backtrace; +}; + +/** + * Print and cleanup mutex profiler + */ +static void profiler_cleanup(lock_profile_t *profile) +{ + if (profile->waited.tv_sec > 0 || + profile->waited.tv_usec > PROFILE_TRESHHOLD) + { + fprintf(stderr, "%d.%06ds in lock created at:", + profile->waited.tv_sec, profile->waited.tv_usec); + profile->backtrace->log(profile->backtrace, stderr); + } + profile->backtrace->destroy(profile->backtrace); +} + +/** + * Initialize mutex profiler + */ +static void profiler_init(lock_profile_t *profile) +{ + profile->backtrace = backtrace_create(3); + timerclear(&profile->waited); +} + +#define profiler_start(profile) { \ + struct timeval _start, _end, _diff; \ + gettimeofday(&_start, NULL); + +#define profiler_end(profile) \ + gettimeofday(&_end, NULL); \ + timersub(&_end, &_start, &_diff); \ + timeradd(&(profile)->waited, &_diff, &(profile)->waited); } + +#else /* !LOCK_PROFILER */ + +#define lock_profile_t struct {} +#define profiler_cleanup(...) {} +#define profiler_init(...) {} +#define profiler_start(...) {} +#define profiler_end(...) {} + +#endif /* LOCK_PROFILER */ /** * private data of mutex @@ -45,6 +113,16 @@ struct private_mutex_t { * wrapped pthread mutex */ pthread_mutex_t mutex; + + /** + * is this a recursiv emutex, implementing private_r_mutex_t? + */ + bool recursive; + + /** + * profiling info, if enabled + */ + lock_profile_t profile; }; /** @@ -53,7 +131,7 @@ struct private_mutex_t { struct private_r_mutex_t { /** - * public functions + * Extends private_mutex_t */ private_mutex_t generic; @@ -63,9 +141,9 @@ struct private_r_mutex_t { pthread_t thread; /** - * times we have locked the lock + * times we have locked the lock, stored per thread */ - int times; + pthread_key_t times; }; /** @@ -85,14 +163,37 @@ struct private_condvar_t { }; /** + * private data of rwlock + */ +struct private_rwlock_t { + + /** + * public functions + */ + rwlock_t public; + + /** + * wrapped pthread rwlock + */ + pthread_rwlock_t rwlock; + + /** + * profiling info, if enabled + */ + lock_profile_t profile; +}; + +/** * Implementation of mutex_t.lock. */ static void lock(private_mutex_t *this) { + profiler_start(&this->profile); if (pthread_mutex_lock(&this->mutex)) { DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", ""); } + profiler_end(&this->profile); } /** @@ -115,12 +216,19 @@ static void lock_r(private_r_mutex_t *this) if (this->thread == self) { - this->times++; - return; + uintptr_t times; + + /* times++ */ + times = (uintptr_t)pthread_getspecific(this->times); + pthread_setspecific(this->times, (void*)times + 1); + } + else + { + lock(&this->generic); + this->thread = self; + /* times = 1 */ + pthread_setspecific(this->times, (void*)1); } - lock(&this->generic); - this->thread = self; - this->times = 1; } /** @@ -128,7 +236,13 @@ static void lock_r(private_r_mutex_t *this) */ static void unlock_r(private_r_mutex_t *this) { - if (--this->times == 0) + uintptr_t times; + + /* times-- */ + times = (uintptr_t)pthread_getspecific(this->times); + pthread_setspecific(this->times, (void*)--times); + + if (times == 0) { this->thread = 0; unlock(&this->generic); @@ -140,10 +254,22 @@ static void unlock_r(private_r_mutex_t *this) */ static void mutex_destroy(private_mutex_t *this) { + profiler_cleanup(&this->profile); pthread_mutex_destroy(&this->mutex); free(this); } +/** + * Implementation of mutex_t.destroy for recursive mutex' + */ +static void mutex_destroy_r(private_r_mutex_t *this) +{ + profiler_cleanup(&this->generic.profile); + pthread_mutex_destroy(&this->generic.mutex); + pthread_key_delete(this->times); + free(this); +} + /* * see header file */ @@ -154,15 +280,17 @@ mutex_t *mutex_create(mutex_type_t type) case MUTEX_RECURSIVE: { private_r_mutex_t *this = malloc_thing(private_r_mutex_t); - + this->generic.public.lock = (void(*)(mutex_t*))lock_r; this->generic.public.unlock = (void(*)(mutex_t*))unlock_r; - this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy; - + this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy_r; + pthread_mutex_init(&this->generic.mutex, NULL); + pthread_key_create(&this->times, NULL); + this->generic.recursive = TRUE; + profiler_init(&this->generic.profile); this->thread = 0; - this->times = 0; - + return &this->generic.public; } case MUTEX_DEFAULT: @@ -173,9 +301,11 @@ mutex_t *mutex_create(mutex_type_t type) this->public.lock = (void(*)(mutex_t*))lock; this->public.unlock = (void(*)(mutex_t*))unlock; this->public.destroy = (void(*)(mutex_t*))mutex_destroy; - + pthread_mutex_init(&this->mutex, NULL); - + this->recursive = FALSE; + profiler_init(&this->profile); + return &this->public; } } @@ -186,7 +316,19 @@ mutex_t *mutex_create(mutex_type_t type) */ static void wait(private_condvar_t *this, private_mutex_t *mutex) { - pthread_cond_wait(&this->condvar, &mutex->mutex); + if (mutex->recursive) + { + private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; + + /* mutex owner gets cleared during condvar wait */ + recursive->thread = 0; + pthread_cond_wait(&this->condvar, &mutex->mutex); + recursive->thread = pthread_self(); + } + else + { + pthread_cond_wait(&this->condvar, &mutex->mutex); + } } /** @@ -198,6 +340,7 @@ static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex, struct timespec ts; struct timeval tv; u_int s, ms; + bool timed_out; gettimeofday(&tv, NULL); @@ -211,8 +354,21 @@ static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex, ts.tv_nsec -= 1000000000; ts.tv_sec++; } - return (pthread_cond_timedwait(&this->condvar, &mutex->mutex, - &ts) == ETIMEDOUT); + if (mutex->recursive) + { + private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; + + recursive->thread = 0; + timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex, + &ts) == ETIMEDOUT; + recursive->thread = pthread_self(); + } + else + { + timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex, + &ts) == ETIMEDOUT; + } + return timed_out; } /** @@ -265,3 +421,75 @@ condvar_t *condvar_create(condvar_type_t type) } } +/** + * Implementation of rwlock_t.read_lock + */ +static void read_lock(private_rwlock_t *this) +{ + profiler_start(&this->profile); + pthread_rwlock_rdlock(&this->rwlock); + profiler_end(&this->profile); +} + +/** + * Implementation of rwlock_t.write_lock + */ +static void write_lock(private_rwlock_t *this) +{ + profiler_start(&this->profile); + pthread_rwlock_wrlock(&this->rwlock); + profiler_end(&this->profile); +} + +/** + * Implementation of rwlock_t.try_write_lock + */ +static bool try_write_lock(private_rwlock_t *this) +{ + return pthread_rwlock_trywrlock(&this->rwlock) == 0; +} + +/** + * Implementation of rwlock_t.unlock + */ +static void rw_unlock(private_rwlock_t *this) +{ + pthread_rwlock_unlock(&this->rwlock); +} + +/** + * Implementation of rwlock_t.destroy + */ +static void rw_destroy(private_rwlock_t *this) +{ + pthread_rwlock_destroy(&this->rwlock); + profiler_cleanup(&this->profile); + free(this); +} + +/* + * see header file + */ +rwlock_t *rwlock_create(rwlock_type_t type) +{ + switch (type) + { + case RWLOCK_DEFAULT: + default: + { + private_rwlock_t *this = malloc_thing(private_rwlock_t); + + this->public.read_lock = (void(*)(rwlock_t*))read_lock; + this->public.write_lock = (void(*)(rwlock_t*))write_lock; + this->public.try_write_lock = (bool(*)(rwlock_t*))try_write_lock; + this->public.unlock = (void(*)(rwlock_t*))rw_unlock; + this->public.destroy = (void(*)(rwlock_t*))rw_destroy; + + pthread_rwlock_init(&this->rwlock, NULL); + profiler_init(&this->profile); + + return &this->public; + } + } +} + diff --git a/src/libstrongswan/utils/mutex.h b/src/libstrongswan/utils/mutex.h index cf557c35c..a0a198024 100644 --- a/src/libstrongswan/utils/mutex.h +++ b/src/libstrongswan/utils/mutex.h @@ -23,8 +23,10 @@ typedef struct mutex_t mutex_t; typedef struct condvar_t condvar_t; +typedef struct rwlock_t rwlock_t; typedef enum mutex_type_t mutex_type_t; typedef enum condvar_type_t condvar_type_t; +typedef enum rwlock_type_t rwlock_type_t; #include <library.h> @@ -47,6 +49,14 @@ enum condvar_type_t { }; /** + * Type of read-write lock. + */ +enum rwlock_type_t { + /** default condvar */ + RWLOCK_DEFAULT = 0, +}; + +/** * Mutex wrapper implements simple, portable and advanced mutex functions. */ struct mutex_t { @@ -105,6 +115,41 @@ struct condvar_t { }; /** + * Read-Write lock wrapper. + */ +struct rwlock_t { + + /** + * Acquire the read lock. + */ + void (*read_lock)(rwlock_t *this); + + /** + * Acquire the write lock. + */ + void (*write_lock)(rwlock_t *this); + + /** + * Try to acquire the write lock. + * + * Never blocks, but returns FALSE if the lock was already occupied. + * + * @return TRUE if lock acquired + */ + bool (*try_write_lock)(rwlock_t *this); + + /** + * Release any acquired lock. + */ + void (*unlock)(rwlock_t *this); + + /** + * Destroy the read-write lock. + */ + void (*destroy)(rwlock_t *this); +}; + +/** * Create a mutex instance. * * @param type type of mutex to create @@ -120,4 +165,12 @@ mutex_t *mutex_create(mutex_type_t type); */ condvar_t *condvar_create(condvar_type_t type); +/** + * Create a read-write lock instance. + * + * @param type type of rwlock to create + * @return unlocked rwlock instance + */ +rwlock_t *rwlock_create(rwlock_type_t type); + #endif /* MUTEX_H_ @}*/ |