[m-rev.] For review: Make improvements to stack segments code.
Paul Bone
pbone at csse.unimelb.edu.au
Thu May 27 11:47:04 AEST 2010
For review by anyone.
There are other changes I intend to make to the stack segments code that arn't
included here.
Make improvements to stack segments code.
The main benefits of these changes are:
Stack segments (and other memory zones) are cached when they are released
and can be re-used.
Some thread softy-fixes have been added.
All stack segments are now the same size, including the first segment.
The first segment no-longer has a redzone.
Hard zones on all memory zones have been set to the minimum of one page
rather than one MR_unit which is usually two pages.
Other changes include corrections in code comments, clearer function names and
a documentation fix.
runtime/mercury_memory_zones.h:
runtime/mercury_memory_zones.c:
Re-write a lot of the code that managed the zone lists. The old code did
not re-used previously allocated but saved zones. The changes ensure that
MR_create_or_reuse_zone (formerly MR_create_zone) checks for a free zone
of at least the required size before allocating a new one. When zones are
released they are put on the free list. Garbage collection of free zones
is not yet implemented.
As above MR_create_zone is now MR_create_or_reuse_zone,
MR_unget_zone is now MR_release_zone.
MR_construct_zone has been removed.
Not all zones are added to the used list for the benifit of the memory
error handlers.
Do better locking on the free_memory_zones and used_memory_zones lists.
Make sure that list modification makes memory writes in a clear order so
that the lists are always well formed.
Rename MR_get_used_memory_zones() to MR_get_used_memory_zones_readonly()
and document that the zone lists may be incomplete.
Make the MR_zone_next field of the MR_MemoryZone_Struct structure volatile.
Remove MAX_ZONES, it wasn't being used anywhere.
Insert some calls to MR_debug_log_message to help with debugging.
runtime/mercury_stacks.c:
Conform to changes in mercury_memory_zones.c.
Use MR_GC_NEW rather than MR_GC_malloc_uncollectable for the list or
previous stack segments associated with a context. The context is heap
allocated so the list need not be uncollectable.
Use MR_debug_log_message for printf-style debugging rather than printf.
runtime/mercury_wrapper.h:
runtime/mercury_wrapper.c:
Remove support for the smaller sized stacks in grades with stack segments.
Disable redzones when using stack segments. The settings here apply to
the first segment on every stack.
Conform to changes in runtime/mercury_memory_zones.h.
runtime/mercury_context.h:
runtime/mercury_context.c:
Removed an extra declaration for MR_init_context_maybe_generator
Conform to changes in runtime/mercury_memory_zones.h.
Conform to changes in runtime/mercury_wrapper.h.
runtime/mercury_memory.c:
Adjust the defintion of MR_unit. It is now gaurenteed to be a multiple of
the page size which is required by it's use in mercury_memory_zones.c
Conform to changes in mercury_wrapper.h.
runtime/mercury_engine.c:
runtime/mercury_memory_handlers.c:
runtime/mercury_trail.c:
Conform to changes in runtime/mercury_memory_zones.h.
runtime/mercury_misc.c:
Print out the meaning of errno if it is nonzero in MR_fatal_error.
runtime/mercury_atomic_ops.h:
Define MR_THREADSAFE_VOLATILE to expand to volatile when MR_THREADSAFE is
defined. Otherwise it expands to nothing.
doc/user_guide.texi:
Corrected the default detstack size.
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.608
diff -u -p -b -r1.608 user_guide.texi
--- doc/user_guide.texi 6 Apr 2010 17:23:02 -0000 1.608
+++ doc/user_guide.texi 26 May 2010 07:54:44 -0000
@@ -431,7 +431,7 @@ The most useful of these are the options
@c XXX FIXME This is wrong for the case when --high-level-code is enabled.
The det stack and the nondet stack
are allocated fixed sizes at program start-up.
-The default size is 1024k times the word size (in bytes) for the det stack
+The default size is 4096k times the word size (in bytes) for the det stack
and 64k times the word size (in bytes) for the nondet stack,
but these can be overridden with the
@samp{--detstack-size} and @samp{--nondetstack-size} options,
Index: runtime/mercury_atomic_ops.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_atomic_ops.h,v
retrieving revision 1.15
diff -u -p -b -r1.15 mercury_atomic_ops.h
--- runtime/mercury_atomic_ops.h 20 Mar 2010 10:15:51 -0000 1.15
+++ runtime/mercury_atomic_ops.h 26 May 2010 07:54:44 -0000
@@ -19,6 +19,15 @@
/*---------------------------------------------------------------------------*/
+/*
+** Use this to make some storage volatile only when using a threadsafe grade.
+*/
+#ifdef MR_THREAD_SAFE
+#define MR_THREADSAFE_VOLATILE volatile
+#else
+#define MR_THREADSAFE_VOLATILE
+#endif
+
#if defined(MR_LL_PARALLEL_CONJ)
/*
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.c,v
retrieving revision 1.80
diff -u -p -b -r1.80 mercury_context.c
--- runtime/mercury_context.c 26 May 2010 07:45:48 -0000 1.80
+++ runtime/mercury_context.c 26 May 2010 07:54:44 -0000
@@ -139,7 +139,9 @@ allocate_context_id(void);
** MR_MemoryZones.
*/
static MR_Context *free_context_list = NULL;
+#ifndef MR_STACK_SEGMENTS
static MR_Context *free_small_context_list = NULL;
+#endif
#ifdef MR_THREAD_SAFE
static MercuryLock free_context_list_lock;
#endif
@@ -160,10 +162,6 @@ static MR_Integer MR_victim_counte
/*---------------------------------------------------------------------------*/
-static void
-MR_init_context_maybe_generator(MR_Context *c, const char *id,
- MR_GeneratorPtr gen);
-
/*
** Write out the profiling data that we collect during execution.
*/
@@ -500,22 +498,24 @@ MR_init_context_maybe_generator(MR_Conte
detstack_size = MR_detstack_size;
nondetstack_size = MR_nondetstack_size;
break;
+#ifndef MR_STACK_SEGMENTS
case MR_CONTEXT_SIZE_SMALL:
detstack_name = "small_detstack";
nondetstack_name = "small_nondetstack";
detstack_size = MR_small_detstack_size;
nondetstack_size = MR_small_nondetstack_size;
break;
+#endif
}
if (c->MR_ctxt_detstack_zone == NULL) {
if (gen != NULL) {
- c->MR_ctxt_detstack_zone = MR_create_zone("gen_detstack",
- 0, MR_gen_detstack_size, MR_next_offset(),
+ c->MR_ctxt_detstack_zone = MR_create_or_reuse_zone("gen_detstack",
+ MR_gen_detstack_size, MR_next_offset(),
MR_gen_detstack_zone_size, MR_default_handler);
} else {
- c->MR_ctxt_detstack_zone = MR_create_zone(detstack_name,
- 0, detstack_size, MR_next_offset(),
+ c->MR_ctxt_detstack_zone = MR_create_or_reuse_zone(detstack_name,
+ detstack_size, MR_next_offset(),
MR_detstack_zone_size, MR_default_handler);
}
@@ -532,12 +532,12 @@ MR_init_context_maybe_generator(MR_Conte
if (c->MR_ctxt_nondetstack_zone == NULL) {
if (gen != NULL) {
- c->MR_ctxt_nondetstack_zone = MR_create_zone("gen_nondetstack",
- 0, MR_gen_nondetstack_size, MR_next_offset(),
+ c->MR_ctxt_nondetstack_zone = MR_create_or_reuse_zone("gen_nondetstack",
+ MR_gen_nondetstack_size, MR_next_offset(),
MR_gen_nondetstack_zone_size, MR_default_handler);
} else {
- c->MR_ctxt_nondetstack_zone = MR_create_zone(nondetstack_name,
- 0, nondetstack_size, MR_next_offset(),
+ c->MR_ctxt_nondetstack_zone = MR_create_or_reuse_zone(nondetstack_name,
+ nondetstack_size, MR_next_offset(),
MR_nondetstack_zone_size, MR_default_handler);
}
@@ -575,21 +575,21 @@ MR_init_context_maybe_generator(MR_Conte
}
if (c->MR_ctxt_genstack_zone == NULL) {
- c->MR_ctxt_genstack_zone = MR_create_zone("genstack", 0,
+ c->MR_ctxt_genstack_zone = MR_create_or_reuse_zone("genstack",
MR_genstack_size, MR_next_offset(),
MR_genstack_zone_size, MR_default_handler);
}
c->MR_ctxt_gen_next = 0;
if (c->MR_ctxt_cutstack_zone == NULL) {
- c->MR_ctxt_cutstack_zone = MR_create_zone("cutstack", 0,
+ c->MR_ctxt_cutstack_zone = MR_create_or_reuse_zone("cutstack",
MR_cutstack_size, MR_next_offset(),
MR_cutstack_zone_size, MR_default_handler);
}
c->MR_ctxt_cut_next = 0;
if (c->MR_ctxt_pnegstack_zone == NULL) {
- c->MR_ctxt_pnegstack_zone = MR_create_zone("pnegstack", 0,
+ c->MR_ctxt_pnegstack_zone = MR_create_or_reuse_zone("pnegstack",
MR_pnegstack_size, MR_next_offset(),
MR_pnegstack_zone_size, MR_default_handler);
}
@@ -615,7 +615,7 @@ MR_init_context_maybe_generator(MR_Conte
}
if (c->MR_ctxt_trail_zone == NULL) {
- c->MR_ctxt_trail_zone = MR_create_zone("trail", 0,
+ c->MR_ctxt_trail_zone = MR_create_or_reuse_zone("trail",
MR_trail_size, MR_next_offset(),
MR_trail_zone_size, MR_default_handler);
}
@@ -652,7 +652,7 @@ MR_init_context_maybe_generator(MR_Conte
MR_Context *
MR_create_context(const char *id, MR_ContextSize ctxt_size, MR_Generator *gen)
{
- MR_Context *c;
+ MR_Context *c = NULL;
MR_LOCK(&free_context_list_lock, "create_context");
@@ -666,6 +666,7 @@ MR_create_context(const char *id, MR_Con
** so we can return a regular context in place of a small context
** if one is already available.
*/
+#ifndef MR_STACK_SEGMENTS
if (ctxt_size == MR_CONTEXT_SIZE_SMALL && free_small_context_list) {
c = free_small_context_list;
free_small_context_list = c->MR_ctxt_next;
@@ -674,7 +675,9 @@ MR_create_context(const char *id, MR_Con
MR_profile_parallel_small_context_reused++;
}
#endif
- } else if (free_context_list != NULL) {
+ }
+#endif
+ if (c == NULL && free_context_list != NULL) {
c = free_context_list;
free_context_list = c->MR_ctxt_next;
#ifdef MR_PROFILE_PARALLEL_EXECUTION_SUPPORT
@@ -682,8 +685,6 @@ MR_create_context(const char *id, MR_Con
MR_profile_parallel_regular_context_reused++;
}
#endif
- } else {
- c = NULL;
}
MR_UNLOCK(&free_context_list_lock, "create_context i");
@@ -766,6 +767,7 @@ MR_destroy_context(MR_Context *c)
}
#endif
break;
+#ifndef MR_STACK_SEGMENTS
case MR_CONTEXT_SIZE_SMALL:
c->MR_ctxt_next = free_small_context_list;
free_small_context_list = c;
@@ -775,6 +777,7 @@ MR_destroy_context(MR_Context *c)
}
#endif
break;
+#endif
}
MR_UNLOCK(&free_context_list_lock, "destroy_context");
}
@@ -1266,7 +1269,7 @@ MR_define_entry(MR_do_runnext);
/* Grab a new context if we haven't got one then begin execution. */
if (MR_ENGINE(MR_eng_this_context) == NULL) {
MR_ENGINE(MR_eng_this_context) = MR_create_context("from spark",
- MR_CONTEXT_SIZE_SMALL, NULL);
+ MR_CONTEXT_SIZE_FOR_SPARK, NULL);
#ifdef MR_THREADSCOPE
MR_threadscope_post_create_context_for_spark(MR_ENGINE(MR_eng_this_context));
#endif
Index: runtime/mercury_context.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.h,v
retrieving revision 1.60
diff -u -p -b -r1.60 mercury_context.h
--- runtime/mercury_context.h 20 Mar 2010 10:15:51 -0000 1.60
+++ runtime/mercury_context.h 26 May 2010 07:54:44 -0000
@@ -206,9 +206,20 @@ typedef struct MR_Context_Struct
typedef enum {
MR_CONTEXT_SIZE_REGULAR,
+/*
+** Stack segment grades don't need differently sized contexts.
+*/
+#ifndef MR_STACK_SEGMENTS
MR_CONTEXT_SIZE_SMALL
+#endif
} MR_ContextSize;
+#ifdef MR_STACK_SEGMENTS
+#define MR_CONTEXT_SIZE_FOR_SPARK MR_CONTEXT_SIZE_REGULAR
+#else
+#define MR_CONTEXT_SIZE_FOR_SPARK MR_CONTEXT_SIZE_SMALL
+#endif
+
#ifdef MR_THREAD_SAFE
typedef struct MR_SavedOwner_Struct MR_SavedOwner;
Index: runtime/mercury_engine.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_engine.c,v
retrieving revision 1.61
diff -u -p -b -r1.61 mercury_engine.c
--- runtime/mercury_engine.c 26 May 2010 07:45:48 -0000 1.61
+++ runtime/mercury_engine.c 26 May 2010 07:54:44 -0000
@@ -121,28 +121,28 @@ MR_init_engine(MercuryEngine *eng)
*/
#ifndef MR_CONSERVATIVE_GC
- eng->MR_eng_heap_zone = MR_create_zone("heap", 1,
+ eng->MR_eng_heap_zone = MR_create_or_reuse_zone("heap",
MR_heap_size, MR_next_offset(), MR_heap_zone_size, MR_default_handler);
eng->MR_eng_hp = eng->MR_eng_heap_zone->MR_zone_min;
#ifdef MR_NATIVE_GC
- eng->MR_eng_heap_zone2 = MR_create_zone("heap2", 1,
+ eng->MR_eng_heap_zone2 = MR_create_or_reuse_zone("heap2",
MR_heap_size, MR_next_offset(), MR_heap_zone_size, MR_default_handler);
#ifdef MR_DEBUG_AGC_PRINT_VARS
- eng->MR_eng_debug_heap_zone = MR_create_zone("debug_heap", 1,
+ eng->MR_eng_debug_heap_zone = MR_create_or_reuse_zone("debug_heap",
MR_debug_heap_size, MR_next_offset(),
MR_debug_heap_zone_size, MR_default_handler);
#endif
#endif /* MR_NATIVE_GC */
#ifdef MR_MIGHT_RECLAIM_HP_ON_FAILURE
- eng->MR_eng_solutions_heap_zone = MR_create_zone("solutions_heap", 1,
+ eng->MR_eng_solutions_heap_zone = MR_create_or_reuse_zone("solutions_heap",
MR_solutions_heap_size, MR_next_offset(),
MR_solutions_heap_zone_size, MR_default_handler);
eng->MR_eng_sol_hp = eng->MR_eng_solutions_heap_zone->MR_zone_min;
- eng->MR_eng_global_heap_zone = MR_create_zone("global_heap", 1,
+ eng->MR_eng_global_heap_zone = MR_create_or_reuse_zone("global_heap",
MR_global_heap_size, MR_next_offset(),
MR_global_heap_zone_size, MR_default_handler);
eng->MR_eng_global_hp = eng->MR_eng_global_heap_zone->MR_zone_min;
Index: runtime/mercury_memory.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory.c,v
retrieving revision 1.40
diff -u -p -b -r1.40 mercury_memory.c
--- runtime/mercury_memory.c 5 Dec 2008 07:18:05 -0000 1.40
+++ runtime/mercury_memory.c 27 May 2010 01:26:20 -0000
@@ -127,11 +127,12 @@ MR_init_memory(void)
/*
** Convert all the sizes are from kilobytes to bytes and
- ** make sure they are multiples of the page and cache sizes.
+ ** make sure they are multiples of the page size and at least as big as the
+ ** cache size.
*/
MR_page_size = getpagesize();
- MR_unit = MR_max(MR_page_size, MR_pcache_size);
+ MR_unit = MR_round_up(MR_max(MR_page_size, MR_pcache_size), MR_page_size);
#ifdef MR_CONSERVATIVE_GC
MR_heap_size = 0;
@@ -156,10 +157,14 @@ MR_init_memory(void)
MR_heap_margin_size = MR_heap_margin_size * 1024;
#endif
MR_kilobytes_to_bytes_and_round_up(MR_detstack_size);
+#ifndef MR_STACK_SEGMENTS
MR_kilobytes_to_bytes_and_round_up(MR_small_detstack_size);
+#endif
MR_kilobytes_to_bytes_and_round_up(MR_detstack_zone_size);
MR_kilobytes_to_bytes_and_round_up(MR_nondetstack_size);
+#ifndef MR_STACK_SEGMENTS
MR_kilobytes_to_bytes_and_round_up(MR_small_nondetstack_size);
+#endif
MR_kilobytes_to_bytes_and_round_up(MR_nondetstack_zone_size);
#ifdef MR_USE_MINIMAL_MODEL_STACK_COPY
MR_kilobytes_to_bytes_and_round_up(MR_genstack_size);
Index: runtime/mercury_memory_handlers.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_handlers.c,v
retrieving revision 1.34
diff -u -p -b -r1.34 mercury_memory_handlers.c
--- runtime/mercury_memory_handlers.c 26 May 2010 07:45:48 -0000 1.34
+++ runtime/mercury_memory_handlers.c 26 May 2010 07:54:44 -0000
@@ -132,7 +132,7 @@ MR_try_munprotect(void *addr, void *cont
fault_addr = (MR_Word *) addr;
- zone = MR_get_used_memory_zones();
+ zone = MR_get_used_memory_zones_readonly();
if (MR_memdebug) {
fprintf(stderr, "caught fault at %p\n", (void *)addr);
Index: runtime/mercury_memory_zones.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.c,v
retrieving revision 1.36
diff -u -p -b -r1.36 mercury_memory_zones.c
--- runtime/mercury_memory_zones.c 13 Feb 2010 07:29:10 -0000 1.36
+++ runtime/mercury_memory_zones.c 27 May 2010 01:31:04 -0000
@@ -63,8 +63,14 @@
#ifdef MR_THREAD_SAFE
#include "mercury_thread.h"
+ #include "mercury_atomic_ops.h"
#endif
+#include "mercury_memory_handlers.h"
+
+/*
+** Why is this included here and not above with the other system includes?
+*/
#ifdef MR_WIN32_VIRTUAL_ALLOC
#include <windows.h>
#endif
@@ -339,19 +345,25 @@ MR_dealloc_zone_memory(void *base, size_
/*---------------------------------------------------------------------------*/
-#define MAX_ZONES 16
+static void MR_init_offsets(void);
-/* Enables a workaround in MR_unget_zone(). */
-#define MEMORY_ZONE_FREELIST_WORKAROUND 1
+static MR_MemoryZone* MR_get_free_zone(size_t size);
+static void MR_add_zone_to_used_list(MR_MemoryZone *zone);
+static void MR_remove_zone_from_used_list(MR_MemoryZone *zone);
+static void MR_return_zone_to_free_list(MR_MemoryZone *zone);
+/*
+static void MR_gc_zones();
+*/
+static void MR_free_zone(MR_MemoryZone *zone);
+static size_t get_zone_alloc_size(MR_MemoryZone *zone);
-static MR_MemoryZone *used_memory_zones = NULL;
-static MR_MemoryZone *free_memory_zones = NULL;
-#ifdef MR_THREAD_SAFE
- static MercuryLock free_memory_zones_lock;
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+static void
+MR_configure_redzone_size(MR_MemoryZone *zone, size_t new_redsize);
#endif
-static void MR_init_offsets(void);
-static MR_MemoryZone *MR_get_zone(void);
+static MR_MemoryZone *
+MR_create_new_zone(size_t desired_size, size_t redzone_size);
/*
** We manage the handing out of offsets through the cache by
@@ -367,11 +379,42 @@ static size_t *offset_vector;
static int offset_counter;
extern size_t next_offset(void);
+
+MR_THREADSAFE_VOLATILE MR_Unsigned MR_context_id_counter = 0;
+
+/*
+** This list contains used zones that need a signal handler, for example those
+** that have redzones. Other used zones may exist that arn't on this list
+** because:
+**
+** 1) They don't have a readzone.
+**
+** 2) Putting them on this list in a threadsafe grade requires extra
+** synchronisation.
+*/
+static MR_MemoryZone * volatile used_memory_zones = NULL;
+static MR_MemoryZonesFree * volatile free_memory_zones = NULL;
+#ifdef MR_THREAD_SAFE
+ /*
+ ** You must take this lock to write to either of the zone lists. Or to read
+ ** the complete zone lists. Reading a zone list without taking the lock is
+ ** also supported _iff_ partial information is okay. Ane code that writes
+ ** the list must gaurentee that memory writes occur in the correct order so
+ ** that the list is always well formed from the POV of a reader.
+ **
+ ** This is necessary so that signal handlers can read the list without taking
+ ** a lock. They may not take a lock because pthread_mutex_lock cannot be
+ ** used safely within a signal handler.
+ */
+ static MercuryLock memory_zones_lock;
+#endif
+
+
void
MR_init_zones()
{
#ifdef MR_THREAD_SAFE
- pthread_mutex_init(&free_memory_zones_lock, MR_MUTEX_ATTR);
+ pthread_mutex_init(&memory_zones_lock, MR_MUTEX_ATTR);
#endif
MR_init_offsets();
@@ -397,54 +440,94 @@ MR_init_offsets()
}
static MR_MemoryZone *
-MR_get_zone(void)
+MR_get_free_zone(size_t size)
{
MR_MemoryZone *zone;
+ MR_MemoryZonesFree *zones_list;
+ MR_MemoryZonesFree *zones_list_prev;
/*
** Unlink the first zone on the free-list, link it onto the used-list
** and return it.
*/
- MR_LOCK(&free_memory_zones_lock, "get_zone");
- if (free_memory_zones == NULL) {
- zone = MR_GC_NEW(MR_MemoryZone);
+ MR_LOCK(&memory_zones_lock, "get_zone");
+
+ zones_list = free_memory_zones;
+ zones_list_prev = NULL;
+ while (zones_list) {
+ if (zones_list->MR_zonesfree_size <= size) {
+ /*
+ * A zone on this list will fit our needs.
+ */
+ break;
+ }
+ zones_list_prev = zones_list;
+ zones_list = zones_list->MR_zonesfree_tail;
+ }
+
+ if (zones_list) {
+ zone = zones_list->MR_zonesfree_head;
+ if (zone->MR_zone_next) {
+ zones_list->MR_zonesfree_head = zone->MR_zone_next;
} else {
- zone = free_memory_zones;
- free_memory_zones = free_memory_zones->MR_zone_next;
+ /*
+ ** This minor list is now empty, we should remove it from the major
+ ** list.
+ */
+ if (zones_list_prev) {
+ zones_list_prev->MR_zonesfree_tail = zones_list->MR_zonesfree_tail;
+ } else {
+ free_memory_zones = zones_list->MR_zonesfree_tail;
+ }
+ }
+ } else {
+ zone = NULL;
}
- zone->MR_zone_next = used_memory_zones;
- used_memory_zones = zone;
- MR_UNLOCK(&free_memory_zones_lock, "get_zone");
+ MR_UNLOCK(&memory_zones_lock, "get_zone");
return zone;
}
-void
-MR_unget_zone(MR_MemoryZone *zone)
+static void
+MR_add_zone_to_used_list(MR_MemoryZone *zone)
{
-#ifdef MEMORY_ZONE_FREELIST_WORKAROUND
+ MR_LOCK(&memory_zones_lock, "get_zone");
+
+ zone->MR_zone_next = used_memory_zones;
/*
- ** XXX MR_construct_zone() does not yet reuse previously allocated memory
- ** zones properly and simply leaks memory when it tries to do so. As a
- ** workaround, we never put memory zones on the free list and deallocate
- ** them immediately here.
+ ** This change must occur before we replace the head of the list.
*/
- #ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+#ifdef MR_THREAD_SAFE
+ MR_CPU_SFENCE;
+#endif
+ used_memory_zones = zone;
+
+ MR_UNLOCK(&memory_zones_lock, "get_zone");
+}
+
+static void
+MR_free_zone(MR_MemoryZone *zone)
+{
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
size_t redsize;
int res;
redsize = zone->MR_zone_redzone_size;
res = MR_protect_pages((char *) zone->MR_zone_redzone,
- redsize + MR_unit, NORMAL_PROT);
- assert(res == 0);
- #endif
+ redsize + MR_page_size, NORMAL_PROT);
+ if (res) {
+ MR_fatal_error("Couldn't unprotect memory pages in MR_free_zone");
+ }
+#endif
MR_dealloc_zone_memory(zone->MR_zone_bottom,
((char *) zone->MR_zone_top) - ((char *) zone->MR_zone_bottom));
+}
-#else /* !MEMORY_ZONE_FREELIST_WORKAROUND */
-
+static void
+MR_remove_zone_from_used_list(MR_MemoryZone *zone)
+{
MR_MemoryZone *prev;
MR_MemoryZone *tmp;
@@ -453,11 +536,12 @@ MR_unget_zone(MR_MemoryZone *zone)
** then link it onto the start of the free-list.
*/
- MR_LOCK(&free_memory_zones_lock, "unget_zone");
- for(prev = NULL, tmp = used_memory_zones; tmp != NULL && tmp != zone;
- prev = tmp, tmp = tmp->MR_zone_next)
- {
- /* VOID */
+ MR_LOCK(&memory_zones_lock, "remove_zone_from_used_list");
+ prev = NULL;
+ tmp = used_memory_zones;
+ while (tmp != NULL && tmp != zone) {
+ prev = tmp;
+ tmp = tmp->MR_zone_next;
}
if (tmp == NULL) {
@@ -469,12 +553,92 @@ MR_unget_zone(MR_MemoryZone *zone)
} else {
prev->MR_zone_next = tmp->MR_zone_next;
}
+ MR_UNLOCK(&memory_zones_lock, "remove_zone_frm_used_list");
+}
+
+static void
+MR_return_zone_to_free_list(MR_MemoryZone *zone)
+{
+ MR_MemoryZonesFree *tmp_list;
+ size_t size;
+
+ size = get_zone_alloc_size(zone);
+
+ MR_LOCK(&memory_zones_lock, "ireturn_zone_to_free_list");
+
+ tmp_list = free_memory_zones;
+ while (tmp_list) {
+ if (tmp_list->MR_zonesfree_size == size)
+ {
+ /*
+ ** We found the correct zone list.
+ */
+ break;
+ }
+ /*
+ ** Test to see if we can exit the loop early.
+ */
+ else if (tmp_list->MR_zonesfree_size > size)
+ {
+ /*
+ ** Set this to null to represent our failure to find a zone list of
+ ** the right size.
+ */
+ tmp_list = NULL;
+ break;
+ }
+ tmp_list = tmp_list->MR_zonesfree_tail;
+ }
- zone->MR_zone_next = free_memory_zones;
- free_memory_zones = zone;
- MR_UNLOCK(&free_memory_zones_lock, "unget_zone");
+ if (tmp_list == NULL) {
+ MR_MemoryZonesFree *new_list, *prev_list;
+
+ new_list = MR_GC_NEW(MR_MemoryZonesFree);
+ new_list->MR_zonesfree_size = size;
+ new_list->MR_zonesfree_head = NULL;
+ tmp_list = free_memory_zones;
+ prev_list = NULL;
+ while (tmp_list) {
+ if (tmp_list->MR_zonesfree_size > size) {
+ /*
+ ** We've just passed the position where this list item belongs.
+ */
+ break;
+ }
+ prev_list = tmp_list;
+ tmp_list = tmp_list->MR_zonesfree_tail;
+ }
+ /*
+ ** Insert it between prev_list and tmp_list.
+ */
+ new_list->MR_zonesfree_tail = tmp_list;
+ if (prev_list) {
+ prev_list->MR_zonesfree_tail = new_list;
+ } else {
+ free_memory_zones = new_list;
+ }
-#endif /* MEMORY_ZONE_FREELIST_WORKAROUND */
+ /*
+ ** Reset tmp_list so that it is pointing at the correct magor list item
+ ** regardless of whether this branch was executed or not.
+ */
+ tmp_list = new_list;
+ }
+
+ zone->MR_zone_next = tmp_list->MR_zonesfree_head;
+ tmp_list->MR_zonesfree_head = zone;
+
+ MR_UNLOCK(&memory_zones_lock, "ireturn_zone_to_free_list");
+}
+
+static size_t
+get_zone_alloc_size(MR_MemoryZone *zone)
+{
+#ifdef MR_PROTECTPAGE
+ return (size_t)((char *)zone->MR_zone_hardmax - (char *)zone->MR_zone_min);
+#else
+ return (size_t)((char *)zone->MR_zone_top - (char *)zone->MR_zone_min);
+#endif
}
/*
@@ -501,71 +665,109 @@ MR_next_offset(void)
}
MR_MemoryZone *
-MR_create_zone(const char *name, int id, size_t size, size_t offset,
+MR_create_or_reuse_zone(const char *name, size_t size, size_t offset,
size_t redsize, MR_ZoneHandler handler)
{
MR_Word *base;
size_t total_size;
+ MR_MemoryZone *zone;
+ MR_bool is_new_zone;
+ zone = MR_get_free_zone(size + redsize);
+ if (zone) {
+#ifdef MR_DEBUG_STACK_SEGMENTS
+ MR_debug_log_message("re-using existing zone");
+#endif
+ is_new_zone = MR_FALSE;
+ zone->MR_zone_desired_size = size;
+ } else {
+#ifdef MR_DEBUG_STACK_SEGMENTS
+ MR_debug_log_message("allocating new zone");
+#endif
+ is_new_zone = MR_TRUE;
+ zone = MR_create_new_zone(size, redsize);
+ }
+
+ zone->MR_zone_name = name;
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+ zone->MR_zone_handler = handler;
+ if (!is_new_zone && (redsize != zone->MR_zone_redzone_size)) {
/*
- ** total allocation is:
- ** unit (roundup to page boundary)
- ** size (including redzone)
- ** unit (an extra page for protection if mprotect is being used)
+ ** The redzone must be reconfigured.
*/
-#ifdef MR_PROTECTPAGE
- total_size = size + 2 * MR_unit;
+ MR_configure_redzone_size(zone, redsize);
+ MR_reset_redzone(zone);
+ }
#else
- total_size = size + MR_unit;
+ if (!is_new_zone) {
+ zone->MR_zone_redzone_size = redsize;
+ }
#endif
- base = (MR_Word *) MR_alloc_zone_memory(total_size);
- if (base == NULL) {
- char buf[2560];
- sprintf(buf, "unable allocate memory zone: %s#%d", name, id);
- MR_fatal_error(buf);
+ if (redsize || (handler != MR_null_handler)) {
+ /*
+ ** Any zone with a redzone or a non-default handler must be
+ ** added the the used zones list.
+ */
+ MR_add_zone_to_used_list(zone);
}
- return MR_construct_zone(name, id, base, size, offset, redsize, handler);
+ return zone;
}
-MR_MemoryZone *
-MR_construct_zone(const char *name, int id, MR_Word *base,
- size_t size, size_t offset, size_t redsize, MR_ZoneHandler handler)
+static MR_MemoryZone *
+MR_create_new_zone(size_t desired_size, size_t redzone_size)
{
+ size_t offset;
MR_MemoryZone *zone;
+ MR_Word *base;
size_t total_size;
+ offset = MR_next_offset();
+ /*
+ ** Ignore the offset if it is at least half the desired size of the zone.
+ ** This should only happen for very small zones.
+ */
+ if ((offset * 2) > desired_size) {
+ offset = 0;
+ }
+
+ /*
+ ** The redzone must be page aligned and page multiple.
+ */
+ redzone_size = MR_round_up(redzone_size, MR_page_size);
+ /*
+ ** Include an extra page size for the hardzone.
+ */
+ total_size = desired_size + redzone_size + MR_page_size;
+ /*
+ ** The total size must also be rounded to a page boundary, so that it can
+ ** be allocated from mmap if we're using accurate GC.
+ */
+ total_size = MR_round_up(total_size, MR_page_size);
+
+ base = (MR_Word *) MR_alloc_zone_memory(total_size);
if (base == NULL) {
- MR_fatal_error("MR_construct_zone called with NULL pointer");
+ MR_fatal_error("Unable to allocate memory for zone");
}
- zone = MR_get_zone();
+ zone = MR_GC_NEW(MR_MemoryZone);
- zone->MR_zone_name = name;
- zone->MR_zone_id = id;
- zone->MR_zone_desired_size = size;
- zone->MR_zone_redzone_size = redsize;
+ zone->MR_zone_name = NULL;
+#ifdef MR_THREAD_SAFE
+ zone->MR_zone_id = MR_atomic_add_and_fetch_uint(&MR_context_id_counter, 1);
+#else
+ zone->MR_zone_id = ++MR_context_id_counter;
+#endif
+ zone->MR_zone_desired_size = desired_size;
+ zone->MR_zone_redzone_size = redzone_size;
#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
- zone->MR_zone_handler = handler;
+ zone->MR_zone_handler = NULL;
#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
- /*
- ** XXX If `zone' is pulled off the free-list (rather than newly allocated)
- ** then zone->MR_zone_bottom will be pointing to a previously allocated
- ** memory region. Setting it to point to `base' therefore causes a memory
- ** leak. `base' should not be allocated in the first place if `zone' is
- ** to be reused. See also the workaround in MR_unget_zone().
- */
zone->MR_zone_bottom = base;
-#ifdef MR_PROTECTPAGE
- total_size = size + MR_unit;
-#else
- total_size = size;
-#endif /* MR_PROTECTPAGE */
-
zone->MR_zone_top = (MR_Word *) ((char *) base + total_size);
zone->MR_zone_min = (MR_Word *) ((char *) base + offset);
#ifdef MR_LOWLEVEL_DEBUG
@@ -593,6 +795,9 @@ MR_extend_zone(MR_MemoryZone *zone, size
MR_fatal_error("MR_extend_zone called with NULL pointer");
}
+ /*
+ ** Why use this value for new_total_size?
+ */
#ifdef MR_PROTECTPAGE
new_total_size = new_size + 2 * MR_unit;
#else
@@ -645,25 +850,34 @@ MR_extend_zone(MR_MemoryZone *zone, size
return base_incr;
}
-static void
-MR_setup_redzones(MR_MemoryZone *zone)
-{
- size_t size;
- size_t redsize;
- int res;
+void
+MR_release_zone(MR_MemoryZone *zone) {
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+ if (zone->MR_zone_redzone_size || (zone->MR_zone_handler != MR_null_handler)) {
+ MR_remove_zone_from_used_list(zone);
+ }
+#endif
+ MR_return_zone_to_free_list(zone);
- size = zone->MR_zone_desired_size;
- redsize = zone->MR_zone_redzone_size;
+ /*
+ ** TODO: after implmenting MR_gc_zones() work out how often we should call it.
- assert(size > redsize);
+ if (should_gc_zones) {
+ MR_gc_zones();
+ }
- /*
- ** setup the redzone
*/
+}
+
#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+static void
+MR_configure_redzone_size(MR_MemoryZone *zone, size_t redsize)
+{
+ size_t size = zone->MR_zone_desired_size;
+
zone->MR_zone_redzone = (MR_Word *)
MR_round_up((MR_Unsigned) zone->MR_zone_bottom + size - redsize,
- MR_unit);
+ MR_page_size);
zone->MR_zone_redzone_base = zone->MR_zone_redzone;
/*
@@ -674,7 +888,31 @@ MR_setup_redzones(MR_MemoryZone *zone)
zone->MR_zone_min = zone->MR_zone_bottom;
}
- res = MR_protect_pages((char *) zone->MR_zone_redzone, redsize + MR_unit,
+ MR_assert(zone->MR_zone_redzone < zone->MR_zone_top);
+ MR_assert(((MR_Unsigned)zone->MR_zone_redzone + redsize) <
+ (MR_Unsigned)zone->MR_zone_top);
+}
+#endif
+
+static void
+MR_setup_redzones(MR_MemoryZone *zone)
+{
+ size_t size;
+ size_t redsize;
+ int res;
+
+ size = zone->MR_zone_desired_size;
+ redsize = zone->MR_zone_redzone_size;
+
+ assert(size > redsize);
+
+ /*
+ ** setup the redzone
+ */
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+ MR_configure_redzone_size(zone, redsize);
+
+ res = MR_protect_pages((char *) zone->MR_zone_redzone, redsize + MR_page_size,
REDZONE_PROT);
if (res < 0) {
char buf[2560];
@@ -689,9 +927,8 @@ MR_setup_redzones(MR_MemoryZone *zone)
** setup the hardzone
*/
#if defined(MR_PROTECTPAGE)
- zone->MR_zone_hardmax = (MR_Word *)
- MR_round_up((MR_Unsigned) zone->MR_zone_top - MR_unit, MR_unit);
- res = MR_protect_pages((char *) zone->MR_zone_hardmax, MR_unit,
+ zone->MR_zone_hardmax = (MR_Word *)((MR_Unsigned)zone->MR_zone_top - MR_page_size);
+ res = MR_protect_pages((char *) zone->MR_zone_hardmax, MR_page_size,
REDZONE_PROT);
if (res < 0) {
char buf[2560];
@@ -753,7 +990,7 @@ MR_reset_redzone(MR_MemoryZone *zone)
}
MR_MemoryZone *
-MR_get_used_memory_zones(void)
+MR_get_used_memory_zones_readonly(void)
{
return used_memory_zones;
}
@@ -782,9 +1019,11 @@ MR_debug_memory(FILE *fp)
(void *) MR_fake_reg, (long) MR_fake_reg & (MR_unit-1));
fprintf(fp, "\n");
+ MR_LOCK(&memory_zones_lock, "MR_debug_memory");
for (zone = used_memory_zones; zone; zone = zone->MR_zone_next) {
MR_debug_memory_zone(fp, zone);
}
+ MR_UNLOCK(&memory_zones_lock, "MR_debug_memory");
}
void
@@ -820,15 +1059,9 @@ MR_debug_memory_zone(FILE *fp, MR_Memory
fprintf(fp, "%-16s#%d-hardmax = %p\n",
zone->MR_zone_name, zone->MR_zone_id,
(void *) zone->MR_zone_hardmax);
+#endif
fprintf(fp, "%-16s#%d-size = %lu\n",
zone->MR_zone_name, zone->MR_zone_id,
- (unsigned long) ((char *) zone->MR_zone_hardmax
- - (char *) zone->MR_zone_min));
-#else
- fprintf(fp, "%-16s#%d-size = %lu\n",
- zone->MR_zone_name, zone->MR_zone_id,
- (unsigned long) ((char *) zone->MR_zone_top
- - (char *) zone->MR_zone_min));
-#endif /* MR_PROTECTPAGE */
+ get_zone_alloc_size(zone));
fprintf(fp, "\n");
}
Index: runtime/mercury_memory_zones.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.h,v
retrieving revision 1.20
diff -u -p -b -r1.20 mercury_memory_zones.h
--- runtime/mercury_memory_zones.h 5 Sep 2008 11:19:33 -0000 1.20
+++ runtime/mercury_memory_zones.h 26 May 2010 07:54:44 -0000
@@ -24,6 +24,7 @@
#include "mercury_types.h" /* for MR_Word */
#include "mercury_std.h" /* for MR_bool */
+#include "mercury_atomic_ops.h" /* for MR_THREADSAFE_VOLATILE */
typedef struct MR_MemoryZone_Struct MR_MemoryZone;
@@ -98,9 +99,9 @@ typedef MR_bool MR_ZoneHandler(MR_Word *
*/
struct MR_MemoryZone_Struct {
- MR_MemoryZone *MR_zone_next;
+ MR_MemoryZone * MR_THREADSAFE_VOLATILE MR_zone_next;
const char *MR_zone_name;
- int MR_zone_id;
+ MR_Unsigned MR_zone_id;
size_t MR_zone_desired_size;
size_t MR_zone_redzone_size;
MR_Word *MR_zone_bottom;
@@ -134,6 +135,22 @@ struct MR_MemoryZones_Struct {
MR_MemoryZones *MR_zones_tail;
};
+/*
+** Free memory zones are arranged in a list of lists, The outer list (below)
+** associates a size of the zones in each inner list. It is to be kept in
+** sorted order from smallest to largest. So that a traversal of this list
+** returns the zones that are the 'best fit' as the 'first fit'. The inner
+** lists (using the MR_zone_next field of the zones contain zones of all the
+** same size.
+*/
+typedef struct MR_MemoryZonesFree_Struct MR_MemoryZonesFree;
+
+struct MR_MemoryZonesFree_Struct {
+ size_t MR_zonesfree_size;
+ MR_MemoryZone *MR_zonesfree_head;
+ MR_MemoryZonesFree *MR_zonesfree_tail;
+};
+
/*
** MR_zone_end specifies the end of the area accessible without
** a page fault. It is used by MR_clear_zone_for_GC().
@@ -198,28 +215,16 @@ extern void MR_init_zones(void);
** If it fails to allocate or protect the zone, then it exits.
** If MR_CHECK_OVERFLOW_VIA_MPROTECT is unavailable, then the last two
** arguments are ignored.
+**
+** This may re-use previously allocated memory but will re-configure the
+** name, readzone and handler.
*/
-extern MR_MemoryZone *MR_create_zone(const char *name, int id,
+extern MR_MemoryZone *MR_create_or_reuse_zone(const char *name,
size_t size, size_t offset, size_t redsize,
MR_ZoneHandler *handler);
-/*
-** MR_construct_zone(Name, Id, Base, Size, Offset, RedZoneSize, FaultHandler)
-** has the same behaviour as MR_create_zone, except instead of allocating
-** the memory, it takes a pointer to a region of memory that must be at
-** least Size + MR_unit[*] bytes, or if MR_PROTECTPAGE is defined, then it
-** must be at least Size + 2 * MR_unit[*] bytes.
-** If it fails to protect the redzone then it exits.
-** If MR_CHECK_OVERFLOW_VIA_MPROTECT is unavailable, then the last two
-** arguments are ignored.
-**
-** [*] MR_unit is a global variable containing the page size in bytes
-*/
-
-extern MR_MemoryZone *MR_construct_zone(const char *name, int Id,
- MR_Word *base, size_t size, size_t offset,
- size_t redsize, MR_ZoneHandler *handler);
+extern void MR_release_zone(MR_MemoryZone *zone);
/*
** MR_extend_zone(Zone, NewSize) extends Zone to increase its size to NewSize,
@@ -232,18 +237,20 @@ extern MR_Integer MR_extend_zone(MR_Memo
/*
** MR_reset_redzone(Zone) resets the redzone on the given MR_MemoryZone to the
-** original zone specified in the call to {create,construct}_zone() if
+** original zone specified in the call to create_or_reuse_zone() if
** MR_CHECK_OVERFLOW_VIA_MPROTECT is defined. Otherwise it does nothing.
*/
extern void MR_reset_redzone(MR_MemoryZone *zone);
/*
-** MR_get_used_memory_zones() returns a pointer to the linked list of
-** used memory zones.
+** MR_get_used_memory_zones_readonly() returns a pointer to the linked list of
+** used memory zones. The list should be considered read only and may not be
+** complete. This is suitable for use where locking is impossible but
+** incomplete data is okay.
*/
-extern MR_MemoryZone *MR_get_used_memory_zones(void);
+extern MR_MemoryZone *MR_get_used_memory_zones_readonly(void);
/*
** Returns true iff ptr is the given zone.
@@ -267,12 +274,6 @@ extern void MR_debug_memory(FILE *fp);
extern void MR_debug_memory_zone(FILE *fp, MR_MemoryZone *zone);
/*
-** Return the given zone to the list of free zones.
-*/
-
-extern void MR_unget_zone(MR_MemoryZone *zone);
-
-/*
** MR_next_offset() returns sucessive offsets across the primary cache. Useful
** when calling {create,construct}_zone().
*/
Index: runtime/mercury_misc.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_misc.c,v
retrieving revision 1.28
diff -u -p -b -r1.28 mercury_misc.c
--- runtime/mercury_misc.c 14 Nov 2006 00:15:40 -0000 1.28
+++ runtime/mercury_misc.c 26 May 2010 07:54:44 -0000
@@ -88,9 +88,13 @@ void
MR_fatal_error(const char *fmt, ...)
{
va_list args;
+ int error = errno;
fflush(stdout); /* in case stdout and stderr are the same */
+ if (error != 0) {
+ fprintf(stderr, "Errno: %s\n", strerror(error));
+ }
fprintf(stderr, "Mercury runtime: ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
Index: runtime/mercury_stacks.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stacks.c,v
retrieving revision 1.20
diff -u -p -b -r1.20 mercury_stacks.c
--- runtime/mercury_stacks.c 25 Jan 2010 06:08:06 -0000 1.20
+++ runtime/mercury_stacks.c 26 May 2010 07:54:44 -0000
@@ -40,6 +40,8 @@ ENDINIT
#include "mercury_imp.h"
#include "mercury_runtime_util.h"
#include "mercury_memory_handlers.h" /* for MR_default_handler */
+#include "mercury_context.h"
+
#include <stdio.h>
/***************************************************************************/
@@ -212,18 +214,15 @@ MR_Word *MR_new_detstack_segment(MR_Word
old_sp = sp;
/* We perform explicit overflow checks so redzones just waste space. */
- new_zone = MR_create_zone("detstack_segment", 0, MR_detstack_size, 0,
+ new_zone = MR_create_or_reuse_zone("detstack_segment", MR_detstack_size, 0,
0, MR_default_handler);
- list = MR_GC_malloc_uncollectable(sizeof(MR_MemoryZones));
+ list = MR_GC_malloc(sizeof(MR_MemoryZones));
#ifdef MR_DEBUG_STACK_SEGMENTS
- printf("create new det segment: old zone: %p, old sp %p\n",
- MR_CONTEXT(MR_ctxt_detstack_zone), old_sp);
- printf("old sp: ");
- MR_printdetstack(stdout, old_sp);
- printf(", old succip: ");
- MR_printlabel(stdout, MR_succip);
+ MR_debug_log_message(
+ "create new det segment: old zone: %p, old sp %p, old succip %p",
+ MR_CONTEXT(MR_ctxt_detstack_zone), old_sp, MR_succip);
#endif
list->MR_zones_head = MR_CONTEXT(MR_ctxt_detstack_zone);
@@ -241,12 +240,10 @@ MR_Word *MR_new_detstack_segment(MR_Word
MR_incr_sp_leaf(n);
#ifdef MR_DEBUG_STACK_SEGMENTS
- printf("create new det segment: new zone: %p, new sp %p\n",
- MR_CONTEXT(MR_ctxt_detstack_zone), MR_sp);
- printf("new sp: ");
- MR_printdetstack(stdout, MR_sp);
- printf(", new succip: ");
- MR_printlabel(stdout, MR_ENTRY(MR_pop_detstack_segment));
+ MR_debug_log_message(
+ "create new det segment: new zone: %p, new sp %p new succip: %p",
+ MR_CONTEXT(MR_ctxt_detstack_zone), MR_sp,
+ MR_ENTRY(MR_pop_detstack_segment));
#endif
return MR_sp;
@@ -274,14 +271,14 @@ MR_nondetstack_segment_extend_slow_path(
{
MR_maxfr_word = (MR_Word) new_maxfr;
if (new_zone != NULL) {
- MR_unget_zone(new_zone);
+ MR_release_zone(new_zone);
}
return;
}
if (new_zone == NULL) {
/* We perform explicit overflow checks so redzones just waste space. */
- new_zone = MR_create_zone("nondetstack_segment", 0,
+ new_zone = MR_create_or_reuse_zone("nondetstack_segment",
MR_nondetstack_size, 0, 0, MR_default_handler);
}
@@ -335,7 +332,7 @@ MR_rewind_nondetstack_segments(MR_Word *
if (reusable_zone == NULL) {
reusable_zone = zone;
} else {
- MR_unget_zone(zone);
+ MR_release_zone(zone);
}
list = MR_CONTEXT(MR_ctxt_prev_nondetstack_zones);
@@ -367,29 +364,24 @@ MR_define_entry(MR_pop_detstack_segment)
orig_succip = (MR_Code *) MR_stackvar(2);
#ifdef MR_DEBUG_STACK_SEGMENTS
- printf("restore old det segment: old zone %p, old sp %p\n",
- MR_CONTEXT(MR_ctxt_detstack_zone), MR_sp);
- printf("old sp: ");
- MR_printdetstack(stdout, MR_sp);
- printf(", old succip: ");
- MR_printlabel(stdout, MR_succip);
+ MR_debug_log_message(
+ "restore old det segment: old zone %p, old sp %p old succip: %p",
+ MR_CONTEXT(MR_ctxt_detstack_zone), MR_sp, MR_succip);
#endif
- MR_unget_zone(MR_CONTEXT(MR_ctxt_detstack_zone));
+ MR_release_zone(MR_CONTEXT(MR_ctxt_detstack_zone));
list = MR_CONTEXT(MR_ctxt_prev_detstack_zones);
MR_CONTEXT(MR_ctxt_detstack_zone) = list->MR_zones_head;
MR_CONTEXT(MR_ctxt_prev_detstack_zones) = list->MR_zones_tail;
MR_CONTEXT(MR_ctxt_sp) = orig_sp;
+ /* XXX: GC will get this */
MR_GC_free(list);
#ifdef MR_DEBUG_STACK_SEGMENTS
- printf("restore old det segment: new zone %p, new sp %p\n",
- MR_CONTEXT(MR_ctxt_detstack_zone), orig_sp);
- printf("new sp: ");
- MR_printdetstack(stdout, orig_sp);
- printf(", new succip: ");
- MR_printlabel(stdout, orig_succip);
+ MR_debug_log_message(
+ "restore old det segment: new zone %p, new sp %p new succip: %p",
+ MR_CONTEXT(MR_ctxt_detstack_zone), orig_sp, orig_succip);
#endif
MR_sp_word = (MR_Word) orig_sp;
Index: runtime/mercury_trail.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trail.c,v
retrieving revision 1.19
diff -u -p -b -r1.19 mercury_trail.c
--- runtime/mercury_trail.c 26 Sep 2008 00:24:46 -0000 1.19
+++ runtime/mercury_trail.c 26 May 2010 07:54:44 -0000
@@ -225,7 +225,7 @@ MR_new_trail_segment(void)
/*
** We perform explicit overflow checks so redzones just waste space.
*/
- new_zone = MR_create_zone("trail_segment", 0, MR_trail_size, 0,
+ new_zone = MR_create_or_reuse_zone("trail_segment", MR_trail_size, 0,
0, MR_default_handler);
list = MR_GC_malloc_uncollectable(sizeof(MR_MemoryZones));
@@ -258,7 +258,7 @@ MR_pop_trail_segment(void)
MR_TRAIL_ZONE, MR_trail_ptr);
#endif
- MR_unget_zone(MR_TRAIL_ZONE);
+ MR_release_zone(MR_TRAIL_ZONE);
list = MR_PREV_TRAIL_ZONES;
MR_TRAIL_ZONE = list->MR_zones_head;
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.209
diff -u -p -b -r1.209 mercury_wrapper.c
--- runtime/mercury_wrapper.c 26 May 2010 07:45:49 -0000 1.209
+++ runtime/mercury_wrapper.c 26 May 2010 07:54:44 -0000
@@ -77,7 +77,8 @@ ENDINIT
/*
** Sizes of data areas (including redzones), in kilobytes
-** (but we later multiply by 1024 to convert to bytes).
+** (but we later multiply by 1024 to convert to bytes, then make sure they're
+** at least as big as the primary cache size then round up to the page size).
**
** Note that it is OK to allocate a large heap, since we will only touch
** the part of it that we use; we're really only allocating address space,
@@ -103,8 +104,6 @@ ENDINIT
#ifdef MR_STACK_SEGMENTS
size_t MR_detstack_size = 64 * sizeof(MR_Word);
size_t MR_nondetstack_size = 16 * sizeof(MR_Word);
-size_t MR_small_detstack_size = 8 * sizeof(MR_Word);
-size_t MR_small_nondetstack_size = 8 * sizeof(MR_Word);
#else
size_t MR_detstack_size = 4096 * sizeof(MR_Word);
size_t MR_nondetstack_size = 64 * sizeof(MR_Word);
@@ -144,8 +143,16 @@ size_t MR_gen_nondetstack_size =
#else
size_t MR_heap_zone_size = 4 * sizeof(MR_Word);
#endif
+#ifdef MR_STACK_SEGMENTS
+/*
+** We don't use redzones with stack segments.
+*/
+size_t MR_detstack_zone_size = 0;
+size_t MR_nondetstack_zone_size = 0;
+#else
size_t MR_detstack_zone_size = 4 * sizeof(MR_Word);
size_t MR_nondetstack_zone_size = 4 * sizeof(MR_Word);
+#endif
size_t MR_solutions_heap_zone_size = 4 * sizeof(MR_Word);
size_t MR_global_heap_zone_size = 4 * sizeof(MR_Word);
size_t MR_trail_zone_size = 4 * sizeof(MR_Word);
@@ -619,7 +626,7 @@ mercury_runtime_init(int argc, char **ar
MR_init_memory();
#ifdef MR_USE_TRAIL
/* initialize the trail */
- MR_trail_zone = MR_create_zone("trail", 0,
+ MR_trail_zone = MR_create_or_reuse_zone("trail",
MR_trail_size, MR_next_offset(),
MR_trail_zone_size, MR_default_handler);
MR_trail_ptr = (MR_TrailEntry *) MR_trail_zone->min;
@@ -1479,7 +1486,9 @@ MR_process_options(int argc, char **argv
MR_usage();
}
+#ifndef MR_STACK_SEGMENTS
MR_small_detstack_size = size;
+#endif
break;
case MR_SMALL_DETSTACK_SIZE_KWORDS:
@@ -1487,7 +1496,9 @@ MR_process_options(int argc, char **argv
MR_usage();
}
+#ifndef MR_STACK_SEGMENTS
MR_small_detstack_size = size * sizeof(MR_Word);
+#endif
break;
case MR_SMALL_NONDETSTACK_SIZE:
@@ -1495,15 +1506,18 @@ MR_process_options(int argc, char **argv
MR_usage();
}
+#ifndef MR_STACK_SEGMENTS
MR_small_nondetstack_size = size;
+#endif
break;
case MR_SMALL_NONDETSTACK_SIZE_KWORDS:
if (sscanf(MR_optarg, "%lu", &size) != 1) {
MR_usage();
}
-
+#ifndef MR_STACK_SEGMENTS
MR_small_nondetstack_size = size * sizeof(MR_Word);
+#endif
break;
case MR_SOLUTIONS_HEAP_SIZE:
@@ -2302,7 +2316,8 @@ MR_process_options(int argc, char **argv
exit(1);
}
-#if !defined(MR_HIGHLEVEL_CODE) && defined(MR_THREAD_SAFE)
+#if !defined(MR_HIGHLEVEL_CODE) && defined(MR_THREAD_SAFE) && \
+ !defined(MR_STACK_SEGMENTS)
if (MR_small_detstack_size > MR_detstack_size) {
printf("The small detstack size must be smaller than the "
"regular detstack size.\n");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 489 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20100527/89ecb85f/attachment.sig>
More information about the reviews
mailing list