diff --git a/include/valgrind.h b/include/valgrind.h index a0dce0384..266e03fea 100644 --- a/include/valgrind.h +++ b/include/valgrind.h @@ -2288,6 +2288,7 @@ typedef VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_FREE = 0x1306, + VG_USERREQ__MEMPOOL_TRIM = 0x1307, /* Allow printfs to valgrind log. */ VG_USERREQ__PRINTF = 0x1401, @@ -2499,6 +2500,14 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...) pool, addr, 0, 0, 0); \ } +/* Disassociate any pieces outside a particular range. */ +#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_TRIM, \ + pool, addr, size, 0, 0); \ + } + /* Mark a piece of memory as being a stack. Returns a stack id. */ #define VALGRIND_STACK_REGISTER(start, end) \ ({unsigned int _qzz_res; \ diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h index 36dc3ead6..4fa50d243 100644 --- a/memcheck/mc_include.h +++ b/memcheck/mc_include.h @@ -86,6 +86,7 @@ extern void MC_(destroy_mempool) ( Addr pool ); extern void MC_(mempool_alloc) ( ThreadId tid, Addr pool, Addr addr, SizeT size ); extern void MC_(mempool_free) ( Addr pool, Addr addr ); +extern void MC_(mempool_trim) ( Addr pool, Addr addr, SizeT size ); extern MC_Chunk* MC_(get_freed_list_head)( void ); diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c index 0e3096f98..026356b67 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -4053,7 +4053,8 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret ) && VG_USERREQ__CREATE_MEMPOOL != arg[0] && VG_USERREQ__DESTROY_MEMPOOL != arg[0] && VG_USERREQ__MEMPOOL_ALLOC != arg[0] - && VG_USERREQ__MEMPOOL_FREE != arg[0]) + && VG_USERREQ__MEMPOOL_FREE != arg[0] + && VG_USERREQ__MEMPOOL_TRIM != arg[0]) return False; switch (arg[0]) { @@ -4219,6 +4220,15 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret ) return True; } + case VG_USERREQ__MEMPOOL_TRIM: { + Addr pool = (Addr)arg[1]; + Addr addr = (Addr)arg[2]; + UInt size = arg[3]; + + MC_(mempool_trim) ( pool, addr, size ); + return True; + } + default: VG_(message)(Vg_UserMsg, "Warning: unknown memcheck client request code %llx", diff --git a/memcheck/mc_malloc_wrappers.c b/memcheck/mc_malloc_wrappers.c index 657901299..736bc01d1 100644 --- a/memcheck/mc_malloc_wrappers.c +++ b/memcheck/mc_malloc_wrappers.c @@ -469,6 +469,86 @@ void MC_(mempool_free)(Addr pool, Addr addr) die_and_free_mem ( tid, mc, mp->rzB ); } + +void MC_(mempool_trim)(Addr pool, Addr addr, SizeT size) +{ + MC_Mempool* mp; + MC_Chunk* mc; + ThreadId tid = VG_(get_running_tid)(); + UInt n_shadows, i; + VgHashNode** chunks; + + mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool); + if (mp == NULL) { + MC_(record_illegal_mempool_error)(tid, pool); + return; + } + + chunks = VG_(HT_to_array) ( mp->chunks, &n_shadows ); + if (n_shadows == 0) { + tl_assert(chunks == NULL); + return; + } + + tl_assert(chunks != NULL); + for (i = 0; i < n_shadows; ++i) { + mc = (MC_Chunk*) chunks[i]; + + if (mc->size == 0) + continue; + +#define EXTENT_CONTAINS(x) ((addr <= (x)) && ((x) < addr + size)) + + if (EXTENT_CONTAINS(mc->data) && + EXTENT_CONTAINS(mc->data + mc->size - 1)) { + + /* The current chunk is entirely within the trim extent: keep + it. */ + + continue; + + } else if ( (! EXTENT_CONTAINS(mc->data)) && + (! EXTENT_CONTAINS(mc->data + mc->size - 1)) ) { + + /* The current chunk is entirely outside the trim extent: + delete it. */ + + if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) == NULL) { + MC_(record_free_error)(tid, (Addr)mc->data); + VG_(free)(chunks); + return; + } + die_and_free_mem ( tid, mc, mp->rzB ); + + } else { + + /* The current chunk intersects the trim extent: remove, + trim, and reinsert it. */ + + Addr lo, hi; + tl_assert(EXTENT_CONTAINS(mc->data) || + EXTENT_CONTAINS(mc->data + mc->size - 1)); + if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) == NULL) { + MC_(record_free_error)(tid, (Addr)mc->data); + VG_(free)(chunks); + return; + } + + lo = mc->data > addr ? mc->data : addr; + hi = mc->data + mc->size < addr + size ? mc->data + mc->size : addr + size; + + tl_assert(lo < hi); + mc->data = lo; + mc->size = (UInt) (hi - lo); + VG_(HT_add_node)( mp->chunks, mc ); + } + +#undef EXTENT_CONTAINS + + } + VG_(free)(chunks); +} + /*------------------------------------------------------------*/ /*--- Statistics printing ---*/ /*------------------------------------------------------------*/