Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
Checking mergeability… Don’t worry, you can still create the pull request.
  • 8 commits
  • 10 files changed
  • 0 commit comments
  • 2 contributors
Commits on May 05, 2012
@Whiteknight Whiteknight Enable GC finalize at parrot destroy. Refactor the destroy process to…
… not use at-exit processing, because the at-exit mechanism requires GC stuff to be available (which it isn't if we destroy the interp during at-exit). Tests expect Parrot_interp_destroy() to do nothing, so create a new Parrot_interp_destroy_for_exit which does gc finalization and frees resources
75a6765
@Whiteknight Whiteknight Some small cleanups ab20bd9
@Whiteknight Whiteknight Remove the PARROT_DESTROY_FLAG. That flag was optionally enabling GC …
…finalization. If we're always finalizing, we don't need that flag. This is the --leak-test commandline option
a3f8fc3
Commits on May 06, 2012
@jkeenan jkeenan [codingstd] Add one assert macro. Insert placeholder documentation in…
… two locations.
4b5d336
Commits on May 11, 2012
@Whiteknight Whiteknight Implement 2-pass sweep.
Sweep all generations looking for dead PMCs. Call VTABLE_destroy if necessary and add them to a dead_list. Next, iterate the dead_list, freeing memory. This scheme should completely avoid order-of-destruction issues, because all PMCs are kept alive until all destroy vtables are called. moritz++ for the idea. bacek++ for writing such easy-to-hack GC code.
0f8993b
Commits on May 12, 2012
@Whiteknight Whiteknight Merge branch 'whiteknight/gc_two_stage_sweep' into whiteknight/gc_fin…
…alize
21aaed3
@Whiteknight Whiteknight Merge branch 'master' into whiteknight/gc_finalize 1851d9a
@Whiteknight Whiteknight Merge in, fixing conflicts 0fc3056
Showing with 88 additions and 104 deletions.
  1. +0 −4 docs/embed.pod
  2. +0 −7 frontend/parrot/main.c
  3. +0 −6 frontend/parrot2/main.c
  4. +7 −6 include/parrot/interpreter.h
  5. +1 −2 src/embed/api.c
  6. +1 −1 src/exit.c
  7. +32 −9 src/gc/gc_gms.c
  8. +46 −47 src/interp/api.c
  9. +1 −21 t/run/options.t
  10. +0 −1 t/src/extend.t
View
4 docs/embed.pod
@@ -168,10 +168,6 @@ True if debugging memory management.
True if reusing another interpreters code.
-=item PARROT_DESTROY_FLAG
-
-True if the last interpreter shall cleanup.
-
=item PARROT_IS_THREAD
True if interpreter is a thread.
View
7 frontend/parrot/main.c
@@ -530,7 +530,6 @@ help(void)
" <GC GMS options>\n"
" --gc-nursery-size=percent of sysmem size of gen0 (default 2)\n"
" --gc-debug\n"
- " --leak-test|--destroy-at-end\n"
" -. --wait Read a keystroke before starting\n"
" --runtime-prefix\n"
" <Compiler options>\n"
@@ -585,8 +584,6 @@ Parrot_cmd_options(void)
{ '\0', OPT_GC_DEBUG, (OPTION_flags)0, { "--gc-debug" } },
{ 'V', 'V', (OPTION_flags)0, { "--version" } },
{ 'X', 'X', OPTION_required_FLAG, { "--dynext" } },
- { '\0', OPT_DESTROY_FLAG, (OPTION_flags)0,
- { "--leak-test", "--destroy-at-end" } },
{ 'o', 'o', OPTION_required_FLAG, { "--output" } },
{ '\0', OPT_PBC_OUTPUT, (OPTION_flags)0, { "--output-pbc" } },
{ 'a', 'a', (OPTION_flags)0, { "--pasm" } },
@@ -841,10 +838,6 @@ parseflags(Parrot_PMC interp, int argc, ARGIN(const char *argv[]),
/* Parrot_api_flag(interp, PARROT_GC_DEBUG_FLAG, 1); */
result = Parrot_api_flag(interp, 0x10, 1);
break;
- case OPT_DESTROY_FLAG:
- /* Parrot_api_flag(interp, PARROT_DESTROY_FLAG, 1); */
- result = Parrot_api_flag(interp, 0x200, 1);
- break;
case 'I':
result = Parrot_api_add_include_search_path(interp, opt.opt_arg);
break;
View
6 frontend/parrot2/main.c
@@ -431,8 +431,6 @@ Parrot_cmd_options(void)
{ '\0', OPT_GC_DEBUG, (OPTION_flags)0, { "--gc-debug" } },
{ 'V', 'V', (OPTION_flags)0, { "--version" } },
{ 'X', 'X', OPTION_required_FLAG, { "--dynext" } },
- { '\0', OPT_DESTROY_FLAG, (OPTION_flags)0,
- { "--leak-test", "--destroy-at-end" } },
{ 'o', 'o', OPTION_required_FLAG, { "--output" } },
{ '\0', OPT_PBC_OUTPUT, (OPTION_flags)0, { "--output-pbc" } },
{ 'a', 'a', (OPTION_flags)0, { "--pasm" } },
@@ -645,10 +643,6 @@ parseflags(Parrot_PMC interp, int argc, ARGIN(const char *argv[]),
/* Parrot_api_flag(interp, PARROT_GC_DEBUG_FLAG, 1); */
result = Parrot_api_flag(interp, 0x10, 1);
break;
- case OPT_DESTROY_FLAG:
- /* Parrot_api_flag(interp, PARROT_DESTROY_FLAG, 1); */
- result = Parrot_api_flag(interp, 0x200, 1);
- break;
/* TODO: Can we do these in prt0.pir? */
case 'I':
View
13 include/parrot/interpreter.h
@@ -18,7 +18,6 @@ typedef enum {
PARROT_GC_DEBUG_FLAG = 0x10, /* debugging memory management */
PARROT_EXTERN_CODE_FLAG = 0x100, /* reusing another interp's code */
- PARROT_DESTROY_FLAG = 0x200, /* the last interpreter shall cleanup */
PARROT_IS_THREAD = 0x1000, /* interpreter is a thread */
PARROT_THR_COPY_INTERP = 0x2000, /* thread start copies interp state */
@@ -364,6 +363,10 @@ void Parrot_interp_destroy(PARROT_INTERP)
__attribute__nonnull__(1);
PARROT_EXPORT
+void Parrot_interp_destroy_for_exit(PARROT_INTERP, int exit_code)
+ __attribute__nonnull__(1);
+
+PARROT_EXPORT
PARROT_WARN_UNUSED_RESULT
PARROT_CANNOT_RETURN_NULL
PMC * Parrot_interp_get_compiler(PARROT_INTERP, ARGIN(STRING *type))
@@ -498,9 +501,6 @@ void Parrot_interp_clear_emergency_interpreter(void);
PARROT_CAN_RETURN_NULL
Interp* Parrot_interp_get_emergency_interpreter(void);
-void Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, void *arg)
- __attribute__nonnull__(1);
-
#define ASSERT_ARGS_Parrot_interp_allocate_interpreter \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_Parrot_interp_clear_debug __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -519,6 +519,9 @@ void Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, void *arg)
, PARROT_ASSERT_ARG(code))
#define ASSERT_ARGS_Parrot_interp_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_interp_destroy_for_exit \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_interp_get_compiler __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(type))
@@ -584,8 +587,6 @@ void Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, void *arg)
__attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_Parrot_interp_get_emergency_interpreter \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
-#define ASSERT_ARGS_Parrot_interp_really_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: src/interp/api.c */
View
3 src/embed/api.c
@@ -316,8 +316,7 @@ Parrot_api_destroy_interpreter(Parrot_PMC interp_pmc)
if (_oldtop == NULL)
interp->lo_var_ptr = &_oldtop;
interp->api_jmp_buf = &env;
- Parrot_x_execute_on_exit_handlers(interp, 0);
- Parrot_interp_destroy(interp);
+ Parrot_interp_destroy_for_exit(interp, 0);
return 1;
}
}
View
2 src/exit.c
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2001-2010, Parrot Foundation.
+Copyright (C) 2001-2012, Parrot Foundation.
=head1 NAME
View
41 src/gc/gc_gms.c
@@ -652,7 +652,7 @@ Parrot_gc_gms_init(PARROT_INTERP, ARGIN(Parrot_GC_Init_Args *args))
: GC_DEFAULT_NURSERY_SIZE;
/* We have to transfer ownership of memory to parent interp in threaded parrot */
- interp->gc_sys->finalize_gc_system = NULL; /* gc_gms_finalize; */
+ interp->gc_sys->finalize_gc_system = gc_gms_finalize;
interp->gc_sys->do_gc_mark = gc_gms_mark_and_sweep;
interp->gc_sys->compact_string_pool = gc_gms_compact_memory_pool;
@@ -842,7 +842,7 @@ gc_gms_mark_and_sweep(PARROT_INTERP, UINTVAL flags)
self->gc_mark_block_level--;
/* We swept all dead objects */
- self->num_early_gc_PMCs = 0;
+ self->num_early_gc_PMCs = 0;
/* Don't compact after nursery collection */
if (gen)
@@ -1051,6 +1051,12 @@ gc_gms_sweep_pools(PARROT_INTERP, ARGMOD(MarkSweep_GC *self))
INTVAL i;
+ Parrot_Pointer_Array * const dead_list = Parrot_pa_new(interp);
+
+ /* Sweep over all objects in each generation. For each object, if it's
+ still alive, bump it up to the next generation. Objects in the last
+ generation don't go any higher. For objects which are dead we call
+ VTABLE_destroy if necessary and add it to a sweep list */
for (i = self->gen_to_collect; i >= 0; i--) {
/* Don't move to generation beyond last */
const int move_to_old = (i + 1) != MAX_GENERATIONS;
@@ -1090,15 +1096,32 @@ gc_gms_sweep_pools(PARROT_INTERP, ARGMOD(MarkSweep_GC *self))
if (PObj_custom_destroy_TEST(pmc))
VTABLE_destroy(interp, pmc);
- if (pmc->vtable->attr_size && PMC_data(pmc))
- Parrot_gc_free_pmc_attributes(interp, pmc);
- PMC_data(pmc) = NULL;
+ Parrot_pa_insert(dead_list, item);
+ }
+ );
+ }
- PObj_on_free_list_SET(pmc);
- PObj_gc_CLEAR(pmc);
+ POINTER_ARRAY_ITER(dead_list,
+ pmc_alloc_struct * const item = (pmc_alloc_struct *)ptr;
+ PMC * const pmc = &(item->pmc);
- Parrot_gc_pool_free(interp, self->pmc_allocator, ptr);
- });
+ if (pmc->vtable->attr_size && PMC_data(pmc))
+ Parrot_gc_free_pmc_attributes(interp, pmc);
+ PMC_data(pmc) = NULL;
+
+ PObj_on_free_list_SET(pmc);
+ PObj_gc_CLEAR(pmc);
+
+ Parrot_gc_pool_free(interp, self->pmc_allocator, ptr);
+ );
+ Parrot_pa_destroy(interp, dead_list);
+
+ /* Sweep over all string pools performing the same operation. If alive,
+ bump the string to the next generation up to MAX_GENERATIONS. If
+ dead, reclaim the memory */
+ for (i = self->gen_to_collect; i >= 0; i--) {
+ /* Don't move to generation beyond last */
+ const int move_to_old = (i + 1) != MAX_GENERATIONS;
POINTER_ARRAY_ITER(self->strings[i],
string_alloc_struct * const item = (string_alloc_struct *)ptr;
View
93 src/interp/api.c
@@ -1,5 +1,6 @@
/*
-Copyright (C) 2001-2010, Parrot Foundation.
+
+Copyright (C) 2001-2012, Parrot Foundation.
=head1 NAME
@@ -35,19 +36,27 @@ static Interp* emergency_interp = NULL;
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+static void interp_destroy_core(PARROT_INTERP)
+ __attribute__nonnull__(1);
+
+static void interp_free_resources(PARROT_INTERP)
+ __attribute__nonnull__(1);
+
PARROT_WARN_UNUSED_RESULT
static int Parrot_interp_is_env_var_set(PARROT_INTERP, ARGIN(STRING* var))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
+#define ASSERT_ARGS_interp_destroy_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_interp_free_resources __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_interp_is_env_var_set __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(var))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
-#define ATEXIT_DESTROY
-
/*
=item C<static int Parrot_interp_is_env_var_set(PARROT_INTERP, STRING* var)>
@@ -330,27 +339,19 @@ Parrot_interp_initialize_interpreter(PARROT_INTERP, ARGIN(Parrot_GC_Init_Args *a
Parrot_cx_init_scheduler(interp);
-#ifdef ATEXIT_DESTROY
- /*
- * if this is not a threaded interpreter, push the interpreter
- * destruction.
- * Threaded interpreters are destructed when the thread ends
- */
- if (!Interp_flags_TEST(interp, PARROT_IS_THREAD))
- Parrot_x_on_exit(interp, Parrot_interp_really_destroy, NULL);
-#endif
-
return interp;
}
/*
=item C<void Parrot_interp_destroy(PARROT_INTERP)>
-Does nothing if C<ATEXIT_DESTROY> is defined. Otherwise calls
-C<Parrot_really_destroy()> with exit code 0.
+Destroys the interpreter and frees resources. Not preferred.
+
+=item C<void Parrot_interp_destroy_for_exit(PARROT_INTERP, int exit_code)>
-This function is not currently used.
+Destroys the interpreter and frees resources, calling at-exit handlers first
+with the given return code. This is the preferred function to use.
=cut
@@ -361,30 +362,33 @@ void
Parrot_interp_destroy(PARROT_INTERP)
{
ASSERT_ARGS(Parrot_interp_destroy)
-#ifdef ATEXIT_DESTROY
- UNUSED(interp);
-#else
- Parrot_interp_really_destroy(interp, 0);
-#endif
+ interp_destroy_core(interp);
+}
+
+PARROT_EXPORT
+void
+Parrot_interp_destroy_for_exit(PARROT_INTERP, int exit_code)
+{
+ ASSERT_ARGS(Parrot_interp_destroy_for_exit)
+ Parrot_x_execute_on_exit_handlers(interp, exit_code);
+ interp_destroy_core(interp);
+ interp_free_resources(interp);
}
/*
-=item C<void Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, void
-*arg)>
+=item C<static void interp_destroy_core(PARROT_INTERP)>
-Waits for any threads to complete, then frees all allocated memory, and
-closes any open file handles, etc.
+TK: Whiteknight, please fill in.
=cut
*/
-void
-Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, SHIM(void *arg))
+static void
+interp_destroy_core(PARROT_INTERP)
{
- ASSERT_ARGS(Parrot_interp_really_destroy)
-
+ ASSERT_ARGS(interp_destroy_core)
/* wait for threads to complete if needed; terminate the event loop */
if (!interp->parent_interpreter) {
Parrot_cx_runloop_end(interp);
@@ -434,23 +438,22 @@ Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, SHIM(void *arg))
/* deinit runcores and dynamic op_libs */
if (!interp->parent_interpreter)
Parrot_runcore_destroy(interp);
+}
- /*
- * now all objects that need timely destruction should be finalized
- * so terminate the event loop
- */
- /* if (!interp->parent_interpreter) {
- PIO_internal_shutdown(interp);
- Parrot_kill_event_loop(interp);
- }
- */
+/*
+
+=item C<static void interp_free_resources(PARROT_INTERP)>
+
+TK: Whiteknight please fill in
- /* we destroy all child interpreters and the last one too,
- * if the --leak-test commandline was given */
- if (! (interp->parent_interpreter
- || Interp_flags_TEST(interp, PARROT_DESTROY_FLAG)))
- return;
+=cut
+
+*/
+static void
+interp_free_resources(PARROT_INTERP)
+{
+ ASSERT_ARGS(interp_free_resources)
if (interp->parent_interpreter)
Parrot_gc_destroy_child_interp(interp->parent_interpreter, interp);
@@ -485,7 +488,6 @@ Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, SHIM(void *arg))
mem_internal_free(interp);
}
-
else {
Parrot_vtbl_free_vtables(interp);
@@ -495,7 +497,6 @@ Parrot_interp_really_destroy(PARROT_INTERP, int exit_code, SHIM(void *arg))
}
}
-
/*
=item C<Interp* Parrot_interp_get_emergency_interpreter(void)>
@@ -537,8 +538,6 @@ Parrot_interp_clear_emergency_interpreter(void)
emergency_interp = NULL;
}
-
-
/*
=item C<void Parrot_interp_register_nci_method(PARROT_INTERP, const int type,
View
22 t/run/options.t
@@ -19,7 +19,7 @@ use strict;
use warnings;
use lib qw( lib . ../lib ../../lib );
-use Test::More tests => 35;
+use Test::More tests => 32;
use Parrot::Config;
use File::Temp 0.13 qw/tempfile/;
use File::Spec;
@@ -46,23 +46,6 @@ is( `"$PARROT" "$first_pir_file" "asdf"`, "first\n", 'ignore nonsens
# redirect STDERR to avoid warnings
my $redir = '2>' . File::Spec->devnull();
-# --pre-process-only
-# This is just sanity testing
-my $expected_preprocesses_pir = <<'END_PIR';
-
-.macro
-
-.sub main :main
-
-say "first"
-
-.end
-
-END_PIR
-is( `"$PARROT" -E "$first_pir_file" $redir`, $expected_preprocesses_pir, 'option -E' );
-is( `"$PARROT" --pre-process-only "$first_pir_file" $redir`,
-$expected_preprocesses_pir, 'option --pre-process-only' );
-
# Test the trace option
is( `"$PARROT" -t "$first_pir_file" $redir`, "first\n", 'option -t' );
is( `"$PARROT" --trace "$first_pir_file" $redir`, "first\n", 'option --trace' );
@@ -116,9 +99,6 @@ like( $output, qr/maximum GC nursery size is 50%/,
is( $exit, 0, '... and should not crash' );
-# Test --leak-test
-is( qx{$PARROT --leak-test "$first_pir_file"}, "first\n", '--leak-test' );
-
# clean up temporary files
unlink $first_pir_file;
unlink $second_pir_file;
View
1 t/src/extend.t
@@ -760,7 +760,6 @@ main(int argc, const char *argv[])
fflush(stdout);
interp = Parrot_interp_new(NULL);
if (interp) {
- Parrot_interp_set_flag(interp, PARROT_DESTROY_FLAG);
printf("Destroying interp %d\n", i);
fflush(stdout);

No commit comments for this range

Something went wrong with that request. Please try again.