libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] [PATCH V2] Configurable cache size


From: Dave Watson
Subject: [Libunwind-devel] [PATCH V2] Configurable cache size
Date: Mon, 5 Dec 2016 15:39:37 -0800
User-agent: Mutt/1.6.0 (2016-04-01)

V3:

* Add documentation

* Fix indentation

* size 0 means largest or resizeable cache

* fix return code

V2:

This is a re-spin of Milian's last patch:
http://lists.nongnu.org/archive/html/libunwind-devel/2014-10/msg00006.html

* Use item size and round up to nearest power of 2.

* Initial cache still exists in BSS.  Without this, it means we would fail
  backtrace when out of memory.  The test-mem test fails without this

* Drop the threading changes.  Unfortunately, in glibc, neither __thread
  (tls_get_addr) nor pthread_setspecific are async-signal-safe.  We've
  actually had issues with the Gtrace code because of this, and in some
  cases have to fallback to unw_step.  It could be made to only work
  in PER_THREAD caching case as a non-default, but it still seems
  like it's against the spirit of async-signal-safe code.

Alternativly to threading, a simple rw-lock would help, or even better,
a lock-free or RCU style cache.
---
 doc/Makefile.am                |  2 +
 doc/libunwind.man              | 13 +++++--
 doc/libunwind.tex              |  6 ++-
 doc/unw_flush_cache.man        |  5 ++-
 doc/unw_flush_cache.tex        |  1 +
 doc/unw_set_cache_size.man     | 86 ++++++++++++++++++++++++++++++++++++++++++
 doc/unw_set_cache_size.tex     | 60 +++++++++++++++++++++++++++++
 doc/unw_set_caching_policy.man |  5 ++-
 doc/unw_set_caching_policy.tex |  1 +
 include/dwarf.h                | 21 ++++++++---
 include/libunwind-common.h.in  |  2 +
 src/Makefile.am                |  6 ++-
 src/dwarf/Gparser.c            | 62 ++++++++++++++++++++++--------
 src/mi/Gset_cache_size.c       | 68 +++++++++++++++++++++++++++++++++
 src/mi/Lset_cache_size.c       |  5 +++
 tests/check-namespace.sh.in    |  2 +
 tests/test-flush-cache.c       |  1 +
 tests/test-static-link-gen.c   |  1 +
 tests/test-static-link-loc.c   |  1 +
 19 files changed, 316 insertions(+), 32 deletions(-)
 create mode 100644 doc/unw_set_cache_size.man
 create mode 100644 doc/unw_set_cache_size.tex
 create mode 100644 src/mi/Gset_cache_size.c
 create mode 100644 src/mi/Lset_cache_size.c

diff --git a/doc/Makefile.am b/doc/Makefile.am
index 2534066..577310c 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -17,6 +17,7 @@ man3_MANS = libunwind.man libunwind-dynamic.man 
libunwind-ia64.man    \
        unw_destroy_addr_space.man                                      \
        unw_regname.man unw_resume.man                                  \
        unw_set_caching_policy.man                                      \
+       unw_set_cache_size.man                                          \
        unw_set_fpreg.man                                               \
        unw_set_reg.man                                                 \
        unw_step.man                                                    \
@@ -41,6 +42,7 @@ EXTRA_DIST = NOTES libunwind.trans                            
        \
        unw_is_signal_frame.tex                                         \
        unw_create_addr_space.tex unw_destroy_addr_space.tex            \
        unw_regname.tex unw_resume.tex unw_set_caching_policy.tex       \
+       unw_set_cache_size.tex                                          \
        unw_set_fpreg.tex                                               \
        unw_set_reg.tex                                                 \
        unw_step.tex                                                    \
diff --git a/doc/libunwind.man b/doc/libunwind.man
index c6046e2..948bcac 100644
--- a/doc/libunwind.man
+++ b/doc/libunwind.man
@@ -1,5 +1,5 @@
 '\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:43 MDT 2007
+.\" Manual page created with latex2man on Fri Dec  2 15:07:07 PST 2016
 .\" NOTE: This file is generated, DO NOT EDIT.
 .de Vb
 .ft CW
@@ -10,7 +10,7 @@
 
 .fi
 ..
-.TH "LIBUNWIND" "3" "16 August 2007" "Programming Library " "Programming 
Library "
+.TH "LIBUNWIND" "3" "02 December 2016" "Programming Library " "Programming 
Library "
 .SH NAME
 libunwind
 \-\- a (mostly) platform\-independent unwind API 
@@ -82,6 +82,10 @@ int
 unw_set_caching_policy(unw_addr_space_t,
 unw_caching_policy_t);
 .br
+int
+unw_set_cache_size(unw_addr_space_t,
+size_t);
+.br
 .PP
 const char *unw_regname(unw_regnum_t);
 .br
@@ -428,7 +432,9 @@ UNW_CACHE_NONE,
 it is possible to turn off caching 
 completely, therefore eliminating the risk of stale data alltogether 
 (at the cost of slower execution). By default, caching is enabled for 
-local unwinding only. 
+local unwinding only. The cache size can be dynamically changed with 
+unw_set_cache_size(),
+which also fluches the current cache. 
 .PP
 .SH FILES
 
@@ -482,6 +488,7 @@ unw_is_signal_frame(3),
 unw_regname(3),
 unw_resume(3),
 unw_set_caching_policy(3),
+unw_set_cache_size(3),
 unw_set_fpreg(3),
 unw_set_reg(3),
 unw_step(3),
diff --git a/doc/libunwind.tex b/doc/libunwind.tex
index 534bd4d..1b907a6 100644
--- a/doc/libunwind.tex
+++ b/doc/libunwind.tex
@@ -43,6 +43,8 @@
 \Type{void} \Func{unw\_flush\_cache}(\Type{unw\_addr\_space\_t}, 
\Type{unw\_word\_t}, \Type{unw\_word\_t});\\
 \noindent
 \Type{int} \Func{unw\_set\_caching\_policy}(\Type{unw\_addr\_space\_t}, 
\Type{unw\_caching\_policy\_t});\\
+\noindent
+\Type{int} \Func{unw\_set\_cache\_size}(\Type{unw\_addr\_space\_t}, 
\Type{size\_t});\\
 
 \noindent
 \Type{const char *}\Func{unw\_regname}(\Type{unw\_regnum\_t});\\
@@ -293,7 +295,8 @@ object.  In particular, by selecting the policy
 \Const{UNW\_CACHE\_NONE}, it is possible to turn off caching
 completely, therefore eliminating the risk of stale data alltogether
 (at the cost of slower execution).  By default, caching is enabled for
-local unwinding only.
+local unwinding only.  The cache size can be dynamically changed with
+\Func{unw\_set\_cache\_size}(), which also fluches the current cache.
 
 
 \section{Files}
@@ -337,6 +340,7 @@ local unwinding only.
 \SeeAlso{unw\_regname(3)},
 \SeeAlso{unw\_resume(3)},
 \SeeAlso{unw\_set\_caching\_policy(3)},
+\SeeAlso{unw\_set\_cache\_size(3)},
 \SeeAlso{unw\_set\_fpreg(3)},
 \SeeAlso{unw\_set\_reg(3)},
 \SeeAlso{unw\_step(3)},
diff --git a/doc/unw_flush_cache.man b/doc/unw_flush_cache.man
index 2c05bc2..627449e 100644
--- a/doc/unw_flush_cache.man
+++ b/doc/unw_flush_cache.man
@@ -1,5 +1,5 @@
 '\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007
+.\" Manual page created with latex2man on Fri Dec  2 16:09:33 PST 2016
 .\" NOTE: This file is generated, DO NOT EDIT.
 .de Vb
 .ft CW
@@ -10,7 +10,7 @@
 
 .fi
 ..
-.TH "UNW\\_FLUSH\\_CACHE" "3" "16 August 2007" "Programming Library " 
"Programming Library "
+.TH "UNW\\_FLUSH\\_CACHE" "3" "02 December 2016" "Programming Library " 
"Programming Library "
 .SH NAME
 unw_flush_cache
 \-\- flush cached info 
@@ -80,6 +80,7 @@ use from a signal handler.
 .PP
 libunwind(3),
 unw_set_caching_policy(3)
+unw_set_cache_size(3)
 .PP
 .SH AUTHOR
 
diff --git a/doc/unw_flush_cache.tex b/doc/unw_flush_cache.tex
index 9b61dfc..32319db 100644
--- a/doc/unw_flush_cache.tex
+++ b/doc/unw_flush_cache.tex
@@ -45,6 +45,7 @@ use from a signal handler.
 
 \SeeAlso{libunwind(3)},
 \SeeAlso{unw\_set\_caching\_policy(3)}
+\SeeAlso{unw\_set\_cache\_size(3)}
 
 \section{Author}
 
diff --git a/doc/unw_set_cache_size.man b/doc/unw_set_cache_size.man
new file mode 100644
index 0000000..dc1ed2d
--- /dev/null
+++ b/doc/unw_set_cache_size.man
@@ -0,0 +1,86 @@
+'\" t
+.\" Manual page created with latex2man on Fri Dec  2 16:16:50 PST 2016
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "UNW\\_SET\\_CACHE\\_SIZE" "3" "02 December 2016" "Programming Library " 
"Programming Library "
+.SH NAME
+unw_set_cache_size
+\-\- set unwind cache size 
+.PP
+.SH SYNOPSIS
+
+.PP
+#include <libunwind.h>
+.br
+.PP
+int
+unw_set_cache_size(unw_addr_space_t
+as,
+size_t
+size);
+.br
+.PP
+.SH DESCRIPTION
+
+.PP
+The unw_set_cache_size()
+routine sets the cache size of 
+address space as
+to hold at least as many items as given by 
+argument size\&.
+It may hold more items as determined by the 
+implementation. A size of 0 indicates the cache may grow as 
+necessary, if supported. To disable caching, call 
+unw_set_caching_policy)
+with a policy of 
+UNW_CACHE_NONE\&.
+.PP
+.SH RETURN VALUE
+
+.PP
+On successful completion, unw_set_cache_size()
+returns 0. 
+Otherwise the negative value of one of the error\-codes below is 
+returned. 
+.PP
+.SH THREAD AND SIGNAL SAFETY
+
+.PP
+unw_set_cache_size()
+is thread\-safe but \fInot\fP
+safe 
+to use from a signal handler. 
+.PP
+.SH ERRORS
+
+.PP
+.TP
+UNW_ENOMEM
+ The desired cache size could not be 
+established because the application is out of memory. 
+.PP
+.SH SEE ALSO
+
+.PP
+libunwind(3),
+unw_create_addr_space(3),
+unw_set_caching_policy(3),
+unw_flush_cache(3)
+.PP
+.SH AUTHOR
+
+.PP
+Dave Watson
+.br
+Email: address@hidden
+.br
+WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&;.
+.\" NOTE: This file is generated, DO NOT EDIT.
diff --git a/doc/unw_set_cache_size.tex b/doc/unw_set_cache_size.tex
new file mode 100644
index 0000000..1c3b3f6
--- /dev/null
+++ b/doc/unw_set_cache_size.tex
@@ -0,0 +1,60 @@
+\documentclass{article}
+\usepackage[fancyhdr,pdf]{latex2man}
+
+\input{common.tex}
+
+\begin{document}
+
+\begin{Name}{3}{unw\_set\_cache\_size}{Dave Watson}{Programming 
Library}{unw\_set\_cache\_size}unw\_set\_cache\_size -- set unwind cache size
+\end{Name}
+
+\section{Synopsis}
+
+\File{\#include $<$libunwind.h$>$}\\
+
+\Type{int} \Func{unw\_set\_cache\_size}(\Type{unw\_addr\_space\_t} \Var{as}, 
\Type{size\_t} \Var{size});\\
+
+\section{Description}
+
+The \Func{unw\_set\_cache\_size}() routine sets the cache size of
+address space \Var{as} to hold at least as many items as given by
+argument \Var{size}.  It may hold more items as determined by the
+implementation.  A size of 0 indicates the cache may grow as
+necessary, if supported.  To disable caching, call
+\Func{unw\_set\_caching\_policy}) with a policy of
+\Const{UNW\_CACHE\_NONE}.
+
+\section{Return Value}
+
+On successful completion, \Func{unw\_set\_cache\_size}() returns 0.
+Otherwise the negative value of one of the error-codes below is
+returned.
+
+\section{Thread and Signal Safety}
+
+\Func{unw\_set\_cache\_size}() is thread-safe but \emph{not} safe
+to use from a signal handler.
+
+\section{Errors}
+
+\begin{Description}
+\item[\Const{UNW\_ENOMEM}] The desired cache size could not be
+  established because the application is out of memory.
+\end{Description}
+
+\section{See Also}
+
+\SeeAlso{libunwind(3)},
+\SeeAlso{unw\_create\_addr\_space(3)},
+\SeeAlso{unw\_set\_caching\_policy(3)},
+\SeeAlso{unw\_flush\_cache(3)}
+
+\section{Author}
+
+\noindent
+Dave Watson\\
+Email: address@hidden
+WWW: \URL{http://www.nongnu.org/libunwind/}.
+\LatexManEnd
+
+\end{document}
diff --git a/doc/unw_set_caching_policy.man b/doc/unw_set_caching_policy.man
index a21d84a..4862ea5 100644
--- a/doc/unw_set_caching_policy.man
+++ b/doc/unw_set_caching_policy.man
@@ -1,5 +1,5 @@
 '\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007
+.\" Manual page created with latex2man on Fri Dec  2 16:09:33 PST 2016
 .\" NOTE: This file is generated, DO NOT EDIT.
 .de Vb
 .ft CW
@@ -10,7 +10,7 @@
 
 .fi
 ..
-.TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "16 August 2007" "Programming Library " 
"Programming Library "
+.TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "02 December 2016" "Programming Library 
" "Programming Library "
 .SH NAME
 unw_set_caching_policy
 \-\- set unwind caching policy 
@@ -105,6 +105,7 @@ established because the application is out of memory.
 .PP
 libunwind(3),
 unw_create_addr_space(3),
+unw_set_cache_size(3),
 unw_flush_cache(3)
 .PP
 .SH AUTHOR
diff --git a/doc/unw_set_caching_policy.tex b/doc/unw_set_caching_policy.tex
index a84e020..3a4b07e 100644
--- a/doc/unw_set_caching_policy.tex
+++ b/doc/unw_set_caching_policy.tex
@@ -67,6 +67,7 @@ to use from a signal handler.
 
 \SeeAlso{libunwind(3)},
 \SeeAlso{unw\_create\_addr\_space(3)},
+\SeeAlso{unw\_set\_cache\_size(3)},
 \SeeAlso{unw\_flush\_cache(3)}
 
 \section{Author}
diff --git a/include/dwarf.h b/include/dwarf.h
index 633868b..615c8a9 100644
--- a/include/dwarf.h
+++ b/include/dwarf.h
@@ -325,11 +325,11 @@ typedef struct dwarf_cursor
   }
 dwarf_cursor_t;
 
-#define DWARF_LOG_UNW_CACHE_SIZE        7
-#define DWARF_UNW_CACHE_SIZE    (1 << DWARF_LOG_UNW_CACHE_SIZE)
+#define DWARF_DEFAULT_LOG_UNW_CACHE_SIZE        7
+#define DWARF_DEFAULT_UNW_CACHE_SIZE    (1 << DWARF_DEFAULT_LOG_UNW_CACHE_SIZE)
 
-#define DWARF_LOG_UNW_HASH_SIZE (DWARF_LOG_UNW_CACHE_SIZE + 1)
-#define DWARF_UNW_HASH_SIZE     (1 << DWARF_LOG_UNW_HASH_SIZE)
+#define DWARF_DEFAULT_LOG_UNW_HASH_SIZE (DWARF_DEFAULT_LOG_UNW_CACHE_SIZE + 1)
+#define DWARF_DEFAULT_UNW_HASH_SIZE     (1 << DWARF_DEFAULT_LOG_UNW_HASH_SIZE)
 
 typedef unsigned char unw_hash_index_t;
 
@@ -339,13 +339,20 @@ struct dwarf_rs_cache
     unsigned short lru_head;    /* index of lead-recently used rs */
     unsigned short lru_tail;    /* index of most-recently used rs */
 
+    unsigned short log_size;
+    unsigned short prev_log_size;
+
     /* hash table that maps instruction pointer to rs index: */
-    unsigned short hash[DWARF_UNW_HASH_SIZE];
+    unsigned short *hash;
 
     uint32_t generation;        /* generation number */
 
     /* rs cache: */
-    dwarf_reg_state_t buckets[DWARF_UNW_CACHE_SIZE];
+    dwarf_reg_state_t *buckets;
+
+    /* default memory, loaded in BSS segment */
+    unsigned short default_hash[DWARF_DEFAULT_UNW_HASH_SIZE];
+    dwarf_reg_state_t default_buckets[DWARF_DEFAULT_UNW_CACHE_SIZE];
   };
 
 /* A list of descriptors for loaded .debug_frame sections.  */
@@ -394,6 +401,7 @@ struct dwarf_callback_data
 #define dwarf_make_proc_info            UNW_OBJ (dwarf_make_proc_info)
 #define dwarf_read_encoded_pointer      UNW_OBJ (dwarf_read_encoded_pointer)
 #define dwarf_step                      UNW_OBJ (dwarf_step)
+#define dwarf_flush_rs_cache            UNW_OBJ (dwarf_flush_rs_cache)
 
 extern int dwarf_init (void);
 #ifndef UNW_REMOTE_ONLY
@@ -438,5 +446,6 @@ extern int dwarf_read_encoded_pointer (unw_addr_space_t as,
                                        const unw_proc_info_t *pi,
                                        unw_word_t *valp, void *arg);
 extern int dwarf_step (struct dwarf_cursor *c);
+extern int dwarf_flush_rs_cache (struct dwarf_rs_cache *cache);
 
 #endif /* dwarf_h */
diff --git a/include/libunwind-common.h.in b/include/libunwind-common.h.in
index fa753ba..97a799a 100644
--- a/include/libunwind-common.h.in
+++ b/include/libunwind-common.h.in
@@ -225,6 +225,7 @@ unw_save_loc_t;
 #define unw_handle_signal_frame        UNW_OBJ(handle_signal_frame)
 #define unw_get_proc_name      UNW_OBJ(get_proc_name)
 #define unw_set_caching_policy UNW_OBJ(set_caching_policy)
+#define unw_set_cache_size     UNW_OBJ(set_cache_size)
 #define unw_regname            UNW_ARCH_OBJ(regname)
 #define unw_flush_cache                UNW_ARCH_OBJ(flush_cache)
 #define unw_strerror           UNW_ARCH_OBJ(strerror)
@@ -234,6 +235,7 @@ extern void unw_destroy_addr_space (unw_addr_space_t);
 extern unw_accessors_t *unw_get_accessors (unw_addr_space_t);
 extern void unw_flush_cache (unw_addr_space_t, unw_word_t, unw_word_t);
 extern int unw_set_caching_policy (unw_addr_space_t, unw_caching_policy_t);
+extern int unw_set_cache_size (unw_addr_space_t, size_t);
 extern const char *unw_regname (unw_regnum_t);
 
 extern int unw_init_local (unw_cursor_t *, unw_context_t *);
diff --git a/src/Makefile.am b/src/Makefile.am
index 5d87475..bcdb01f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -109,7 +109,8 @@ libunwind_la_SOURCES_generic =                              
                \
        mi/Gput_dynamic_unwind_info.c mi/Gdestroy_addr_space.c          \
        mi/Gget_reg.c mi/Gset_reg.c                                     \
        mi/Gget_fpreg.c mi/Gset_fpreg.c                                 \
-       mi/Gset_caching_policy.c
+       mi/Gset_caching_policy.c                                        \
+       mi/Gset_cache_size.c
 
 if SUPPORT_CXX_EXCEPTIONS
 libunwind_la_SOURCES_local_unwind =                                    \
@@ -137,7 +138,8 @@ libunwind_la_SOURCES_local_nounwind =                       
                \
        mi/Lput_dynamic_unwind_info.c mi/Ldestroy_addr_space.c          \
        mi/Lget_reg.c   mi/Lset_reg.c                                   \
        mi/Lget_fpreg.c mi/Lset_fpreg.c                                 \
-       mi/Lset_caching_policy.c
+       mi/Lset_caching_policy.c                                        \
+       mi/Lset_cache_size.c
 
 libunwind_la_SOURCES_local =                                           \
        $(libunwind_la_SOURCES_local_nounwind)                          \
diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index 3a47255..a705f79 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -23,13 +23,17 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
-#include <stddef.h>
 #include "dwarf_i.h"
 #include "libunwind_i.h"
+#include <stddef.h>
+#include <limits.h>
 
 #define alloc_reg_state()       (mempool_alloc (&dwarf_reg_state_pool))
 #define free_reg_state(rs)      (mempool_free (&dwarf_reg_state_pool, rs))
 
+#define DWARF_UNW_CACHE_SIZE(log_size)   (1 << log_size)
+#define DWARF_UNW_HASH_SIZE(log_size)    (1 << (log_size + 1))
+
 static inline int
 read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
              unw_word_t *valp, void *arg)
@@ -508,15 +512,37 @@ parse_fde (struct dwarf_cursor *c, unw_word_t ip, 
dwarf_state_record_t *sr)
   return 0;
 }
 
-static inline void
-flush_rs_cache (struct dwarf_rs_cache *cache)
+HIDDEN int
+dwarf_flush_rs_cache (struct dwarf_rs_cache *cache)
 {
   int i;
 
-  cache->lru_head = DWARF_UNW_CACHE_SIZE - 1;
+  if (cache->log_size == DWARF_DEFAULT_LOG_UNW_CACHE_SIZE
+      || !cache->hash) {
+    cache->hash = cache->default_hash;
+    cache->buckets = cache->default_buckets;
+    cache->log_size = DWARF_DEFAULT_LOG_UNW_CACHE_SIZE;
+  } else {
+    if (cache->hash && cache->hash != cache->default_hash)
+      munmap(cache->hash, DWARF_UNW_HASH_SIZE(cache->prev_log_size));
+    if (cache->buckets && cache->buckets != cache->default_buckets)
+      munmap(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->prev_log_size));
+    GET_MEMORY(cache->hash, DWARF_UNW_HASH_SIZE(cache->log_size)
+                             * sizeof (cache->hash[0]));
+    GET_MEMORY(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->log_size)
+                                * sizeof (cache->buckets[0]));
+    if (!cache->hash || !cache->buckets)
+      {
+        Debug (1, "Unable to allocate cache memory");
+        return -UNW_ENOMEM;
+      }
+    cache->prev_log_size = cache->log_size;
+  }
+
+  cache->lru_head = DWARF_UNW_CACHE_SIZE(cache->log_size) - 1;
   cache->lru_tail = 0;
 
-  for (i = 0; i < DWARF_UNW_CACHE_SIZE; ++i)
+  for (i = 0; i < DWARF_UNW_CACHE_SIZE(cache->log_size); ++i)
     {
       if (i > 0)
         cache->buckets[i].lru_chain = (i - 1);
@@ -524,8 +550,10 @@ flush_rs_cache (struct dwarf_rs_cache *cache)
       cache->buckets[i].ip = 0;
       cache->buckets[i].valid = 0;
     }
-  for (i = 0; i<DWARF_UNW_HASH_SIZE; ++i)
+  for (i = 0; i< DWARF_UNW_HASH_SIZE(cache->log_size); ++i)
     cache->hash[i] = -1;
+
+  return 0;
 }
 
 static inline struct dwarf_rs_cache *
@@ -543,9 +571,11 @@ get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
       lock_acquire (&cache->lock, *saved_maskp);
     }
 
-  if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
+  if ((atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
+       || !cache->hash)
     {
-      flush_rs_cache (cache);
+      if (dwarf_flush_rs_cache (cache) < 0)
+        return NULL;
       cache->generation = as->cache_generation;
     }
 
@@ -564,12 +594,12 @@ put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache 
*cache,
 }
 
 static inline unw_hash_index_t CONST_ATTR
-hash (unw_word_t ip)
+hash (unw_word_t ip, unsigned short log_size)
 {
   /* based on (sqrt(5)/2-1)*2^64 */
 # define magic  ((unw_word_t) 0x9e3779b97f4a7c16ULL)
 
-  return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE);
+  return ip * magic >> ((sizeof(unw_word_t) * 8) - (log_size + 1));
 }
 
 static inline long
@@ -592,8 +622,8 @@ rs_lookup (struct dwarf_rs_cache *cache, struct 
dwarf_cursor *c)
   if (cache_match (rs, ip))
     return rs;
 
-  index = cache->hash[hash (ip)];
-  if (index >= DWARF_UNW_CACHE_SIZE)
+  index = cache->hash[hash (ip, cache->log_size)];
+  if (index >= DWARF_UNW_CACHE_SIZE(cache->log_size))
     return NULL;
 
   rs = cache->buckets + index;
@@ -606,7 +636,7 @@ rs_lookup (struct dwarf_rs_cache *cache, struct 
dwarf_cursor *c)
             (rs - cache->buckets);
           return rs;
         }
-      if (rs->coll_chain >= DWARF_UNW_HASH_SIZE)
+      if (rs->coll_chain >= DWARF_UNW_HASH_SIZE(cache->log_size))
         return NULL;
       rs = cache->buckets + rs->coll_chain;
     }
@@ -630,7 +660,7 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * 
c)
   /* remove the old rs from the hash table (if it's there): */
   if (rs->ip)
     {
-      index = hash (rs->ip);
+      index = hash (rs->ip, cache->log_size);
       tmp = cache->buckets + cache->hash[index];
       prev = NULL;
       while (1)
@@ -645,7 +675,7 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * 
c)
             }
           else
             prev = tmp;
-          if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE)
+          if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE(cache->log_size))
             /* old rs wasn't in the hash-table */
             break;
           tmp = cache->buckets + tmp->coll_chain;
@@ -653,7 +683,7 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * 
c)
     }
 
   /* enter new rs in the hash table */
-  index = hash (c->ip);
+  index = hash (c->ip, cache->log_size);
   rs->coll_chain = cache->hash[index];
   cache->hash[index] = rs - cache->buckets;
 
diff --git a/src/mi/Gset_cache_size.c b/src/mi/Gset_cache_size.c
new file mode 100644
index 0000000..567404d
--- /dev/null
+++ b/src/mi/Gset_cache_size.c
@@ -0,0 +1,68 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2014
+        Contributed by Milian Wolff <address@hidden>
+                   and Dave Watson <address@hidden>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "libunwind_i.h"
+
+PROTECTED int
+unw_set_cache_size (unw_addr_space_t as, size_t size)
+{
+  size_t power = 1;
+  unsigned short log_size = 0;
+
+  if (!tdep_init_done)
+    tdep_init ();
+
+  if (size == 0)
+    {
+      log_size = 15; /* max supported size */
+    }
+  else
+    {
+      /* Round up to next power of two, slowly but portably */
+      while(power < size)
+        {
+          power *= 2;
+          log_size++;
+          /* Largest size currently supported by rs_cache */
+          if (log_size >= 15)
+            break;
+        }
+    }
+
+  if (log_size == as->global_cache.log_size)
+    return 0;   /* no change */
+
+  as->global_cache.log_size = log_size;
+
+  /* Ensure caches are empty (and initialized).  */
+  unw_flush_cache (as, 0, 0);
+#ifdef __ia64__
+  return 0;
+#else
+  /* Synchronously purge cache, to ensure memory is allocated */
+  return dwarf_flush_rs_cache(&as->global_cache);
+#endif
+}
diff --git a/src/mi/Lset_cache_size.c b/src/mi/Lset_cache_size.c
new file mode 100644
index 0000000..670f64d
--- /dev/null
+++ b/src/mi/Lset_cache_size.c
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gset_cache_size.c"
+#endif
diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in
index 1ef74ab..1ae8121 100644
--- a/tests/check-namespace.sh.in
+++ b/tests/check-namespace.sh.in
@@ -103,6 +103,7 @@ check_local_unw_abi () {
     match _UL${plat}_local_addr_space
     match _UL${plat}_resume
     match _UL${plat}_set_caching_policy
+    match _UL${plat}_set_cache_size
     match _UL${plat}_set_reg
     match _UL${plat}_set_fpreg
     match _UL${plat}_step
@@ -199,6 +200,7 @@ check_generic_unw_abi () {
     match _U${plat}_regname
     match _U${plat}_resume
     match _U${plat}_set_caching_policy
+    match _U${plat}_set_cache_size
     match _U${plat}_set_fpreg
     match _U${plat}_set_reg
     match _U${plat}_step
diff --git a/tests/test-flush-cache.c b/tests/test-flush-cache.c
index 592162c..5a24fee 100644
--- a/tests/test-flush-cache.c
+++ b/tests/test-flush-cache.c
@@ -46,6 +46,7 @@ f257 (void)
     for (i = 0; i < n; ++i)
       printf ("[%d] ip=%p\n", i, buffer[i]);
 
+  unw_set_cache_size (unw_local_addr_space, 1023);
   unw_flush_cache (unw_local_addr_space, 0, 0);
 
   if (verbose)
diff --git a/tests/test-static-link-gen.c b/tests/test-static-link-gen.c
index 3246416..d61e7a5 100644
--- a/tests/test-static-link-gen.c
+++ b/tests/test-static-link-gen.c
@@ -43,6 +43,7 @@ static void *funcs[] =
     (void *) &unw_get_accessors,
     (void *) &unw_flush_cache,
     (void *) &unw_set_caching_policy,
+    (void *) &unw_set_cache_size,
     (void *) &unw_regname,
     (void *) &unw_get_proc_info,
     (void *) &unw_get_save_loc,
diff --git a/tests/test-static-link-loc.c b/tests/test-static-link-loc.c
index 4e47e45..1c7aa03 100644
--- a/tests/test-static-link-loc.c
+++ b/tests/test-static-link-loc.c
@@ -61,6 +61,7 @@ static void *funcs[] =
     (void *) &unw_get_accessors,
     (void *) &unw_flush_cache,
     (void *) &unw_set_caching_policy,
+    (void *) &unw_set_cache_size,
     (void *) &unw_regname,
     (void *) &unw_get_proc_info,
     (void *) &unw_get_save_loc,
-- 
2.8.0-rc2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]