summaryrefslogtreecommitdiff
path: root/src/libstrongswan/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r--src/libstrongswan/utils/backtrace.c183
-rw-r--r--src/libstrongswan/utils/backtrace.h63
-rw-r--r--src/libstrongswan/utils/host.c139
-rw-r--r--src/libstrongswan/utils/host.h6
-rw-r--r--src/libstrongswan/utils/iterator.h57
-rw-r--r--src/libstrongswan/utils/leak_detective.c155
-rw-r--r--src/libstrongswan/utils/leak_detective.h5
-rw-r--r--src/libstrongswan/utils/linked_list.c113
-rw-r--r--src/libstrongswan/utils/linked_list.h29
-rw-r--r--src/libstrongswan/utils/mutex.c280
-rw-r--r--src/libstrongswan/utils/mutex.h53
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_ @}*/