2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/thread.c - Thread handling stuff
11 Threads are created by creating new C<ParrotInterpreter> objects.
21 #include "parrot/parrot.h"
22 #include "parrot/extend.h"
23 #include "parrot/atomic.h"
24 #include "parrot/runcore_api.h"
25 #include "pmc/pmc_sub.h"
26 #include "pmc/pmc_parrotinterpreter.h"
28 /* HEADERIZER HFILE: include/parrot/thread.h */
30 /* HEADERIZER BEGIN: static */
31 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
33 static Parrot_Interp
detach(UINTVAL tid
);
34 PARROT_CAN_RETURN_NULL
35 static Shared_gc_info
* get_pool(void);
37 PARROT_WARN_UNUSED_RESULT
38 static int is_suspended_for_gc(PARROT_INTERP
)
39 __attribute__nonnull__(1);
41 PARROT_CAN_RETURN_NULL
42 static PMC
* make_local_args_copy(PARROT_INTERP
,
43 ARGIN(Parrot_Interp old_interp
),
44 ARGIN_NULLOK(PMC
*args
))
45 __attribute__nonnull__(1)
46 __attribute__nonnull__(2);
48 PARROT_CAN_RETURN_NULL
49 static PMC
* make_local_copy(PARROT_INTERP
,
50 ARGIN(Parrot_Interp from
),
52 __attribute__nonnull__(1)
53 __attribute__nonnull__(2)
54 __attribute__nonnull__(3);
56 static void mutex_unlock(ARGMOD(void *arg
))
57 __attribute__nonnull__(1)
60 static Parrot_Interp
pt_check_tid(UINTVAL tid
, ARGIN(const char *from
))
61 __attribute__nonnull__(2);
63 static int pt_gc_count_threads(void);
64 static void pt_gc_wait_for_stage(PARROT_INTERP
,
65 thread_gc_stage_enum from_stage
,
66 thread_gc_stage_enum to_stage
)
67 __attribute__nonnull__(1);
69 static void pt_gc_wakeup_check(void);
70 static void pt_ns_clone(PARROT_INTERP
,
71 ARGOUT(Parrot_Interp d
),
73 ARGIN(Parrot_Interp s
),
74 ARGIN(PMC
*source_ns
))
75 __attribute__nonnull__(1)
76 __attribute__nonnull__(2)
77 __attribute__nonnull__(3)
78 __attribute__nonnull__(4)
79 __attribute__nonnull__(5)
81 FUNC_MODIFIES(*dest_ns
);
83 static void pt_suspend_all_for_gc(PARROT_INTERP
)
84 __attribute__nonnull__(1);
86 static void pt_suspend_one_for_gc(PARROT_INTERP
)
87 __attribute__nonnull__(1);
89 static void pt_thread_signal(ARGIN(Parrot_Interp self
), PARROT_INTERP
)
90 __attribute__nonnull__(1)
91 __attribute__nonnull__(2);
93 static void pt_thread_wait(PARROT_INTERP
)
94 __attribute__nonnull__(1);
96 PARROT_CAN_RETURN_NULL
97 static void* thread_func(ARGIN_NULLOK(void *arg
));
99 #define ASSERT_ARGS_detach __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
100 #define ASSERT_ARGS_get_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
101 #define ASSERT_ARGS_is_suspended_for_gc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
102 PARROT_ASSERT_ARG(interp))
103 #define ASSERT_ARGS_make_local_args_copy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
104 PARROT_ASSERT_ARG(interp) \
105 , PARROT_ASSERT_ARG(old_interp))
106 #define ASSERT_ARGS_make_local_copy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
107 PARROT_ASSERT_ARG(interp) \
108 , PARROT_ASSERT_ARG(from) \
109 , PARROT_ASSERT_ARG(arg))
110 #define ASSERT_ARGS_mutex_unlock __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
111 PARROT_ASSERT_ARG(arg))
112 #define ASSERT_ARGS_pt_check_tid __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
113 PARROT_ASSERT_ARG(from))
114 #define ASSERT_ARGS_pt_gc_count_threads __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
115 #define ASSERT_ARGS_pt_gc_wait_for_stage __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
116 PARROT_ASSERT_ARG(interp))
117 #define ASSERT_ARGS_pt_gc_wakeup_check __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
118 #define ASSERT_ARGS_pt_ns_clone __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
119 PARROT_ASSERT_ARG(interp) \
120 , PARROT_ASSERT_ARG(d) \
121 , PARROT_ASSERT_ARG(dest_ns) \
122 , PARROT_ASSERT_ARG(s) \
123 , PARROT_ASSERT_ARG(source_ns))
124 #define ASSERT_ARGS_pt_suspend_all_for_gc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
125 PARROT_ASSERT_ARG(interp))
126 #define ASSERT_ARGS_pt_suspend_one_for_gc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
127 PARROT_ASSERT_ARG(interp))
128 #define ASSERT_ARGS_pt_thread_signal __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
129 PARROT_ASSERT_ARG(self) \
130 , PARROT_ASSERT_ARG(interp))
131 #define ASSERT_ARGS_pt_thread_wait __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
132 PARROT_ASSERT_ARG(interp))
133 #define ASSERT_ARGS_thread_func __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
134 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
135 /* HEADERIZER END: static */
137 #if defined THREAD_DEBUG && THREAD_DEBUG
138 # define DEBUG_ONLY(x) (x)
140 # define DEBUG_ONLY(x)
143 static int running_threads
;
145 void Parrot_really_destroy(PARROT_INTERP
, int exit_code
, void *arg
);
149 =item C<static PMC * make_local_copy(PARROT_INTERP, Parrot_Interp from, PMC
152 Creates a local copy of the PMC if necessary. (No copy is made if it is marked
153 shared.) This includes workarounds for Parrot_clone() not doing the Right Thing
154 with subroutines (specifically, code segments aren't preserved and it is
155 difficult to do so as long as Parrot_clone() depends on freezing).
161 PARROT_CAN_RETURN_NULL
163 make_local_copy(PARROT_INTERP
, ARGIN(Parrot_Interp from
), ARGIN(PMC
*arg
))
165 ASSERT_ARGS(make_local_copy
)
167 STRING
* const _sub
= interp
->vtables
[enum_class_Sub
]->whoami
;
168 STRING
* const _multi_sub
= interp
->vtables
[enum_class_MultiSub
]->whoami
;
170 if (PMC_IS_NULL(arg
)) {
173 else if (PObj_is_PMC_shared_TEST(arg
)) {
176 else if (VTABLE_isa(from
, arg
, _multi_sub
)) {
178 const INTVAL n
= VTABLE_elements(from
, arg
);
179 ret_val
= Parrot_pmc_new(interp
, enum_class_MultiSub
);
181 for (i
= 0; i
< n
; ++i
) {
182 PMC
*const orig
= VTABLE_get_pmc_keyed_int(from
, arg
, i
);
183 PMC
*const copy
= make_local_copy(interp
, from
, orig
);
184 VTABLE_push_pmc(interp
, ret_val
, copy
);
187 else if (VTABLE_isa(from
, arg
, _sub
)) {
188 /* this is a workaround for cloning subroutines not actually
189 * working as one might expect mainly because the segment is
190 * not correctly copied
192 Parrot_Sub_attributes
*ret_val_sub
, *arg_sub
;
194 ret_val
= Parrot_clone(interp
, arg
);
195 PMC_get_sub(interp
, ret_val
, ret_val_sub
);
196 PMC_get_sub(interp
, arg
, arg_sub
);
197 ret_val_sub
->seg
= arg_sub
->seg
;
198 /* Skip vtable overrides and methods. */
199 if (ret_val_sub
->vtable_index
== -1
200 && !(ret_val_sub
->comp_flags
& SUB_COMP_FLAG_METHOD
)) {
201 Parrot_ns_store_sub(interp
, ret_val
);
205 ret_val
= Parrot_clone(interp
, arg
);
212 =item C<static Shared_gc_info * get_pool(void)>
214 Gets the shared gc information. For now this is global data; ideally it will
215 become something other than a static variable. If everything uses this
216 function, it will be easier to change.
222 PARROT_CAN_RETURN_NULL
223 static Shared_gc_info
*
226 ASSERT_ARGS(get_pool
)
227 return shared_gc_info
;
232 =item C<void pt_free_pool(PARROT_INTERP)>
234 Frees the shared GC information. This clears any global data when joining all
235 threads at parent interpreter destruction.
242 pt_free_pool(PARROT_INTERP
)
244 ASSERT_ARGS(pt_free_pool
)
245 if (shared_gc_info
) {
246 COND_DESTROY(shared_gc_info
->gc_cond
);
247 PARROT_ATOMIC_INT_DESTROY(shared_gc_info
->gc_block_level
);
248 mem_internal_free(shared_gc_info
);
249 shared_gc_info
= NULL
;
255 =item C<static PMC * make_local_args_copy(PARROT_INTERP, Parrot_Interp
256 old_interp, PMC *args)>
258 Make a local copy of the corresponding array of arguments.
264 PARROT_CAN_RETURN_NULL
266 make_local_args_copy(PARROT_INTERP
, ARGIN(Parrot_Interp old_interp
), ARGIN_NULLOK(PMC
*args
))
268 ASSERT_ARGS(make_local_args_copy
)
273 if (PMC_IS_NULL(args
))
276 old_size
= VTABLE_get_integer(old_interp
, args
);
278 /* XXX should this be a different type? */
279 ret_val
= Parrot_pmc_new(interp
, enum_class_FixedPMCArray
);
280 VTABLE_set_integer_native(interp
, ret_val
, old_size
);
282 for (i
= 0; i
< old_size
; ++i
) {
283 PMC
* const copy
= make_local_copy(interp
, old_interp
,
284 VTABLE_get_pmc_keyed_int(old_interp
, args
, i
));
286 VTABLE_set_pmc_keyed_int(interp
, ret_val
, i
, copy
);
294 =item C<PMC * pt_shared_fixup(PARROT_INTERP, PMC *pmc)>
296 Modifies a PMC to be sharable. Right now, reassigns the vtable to one
297 owned by some master interpreter, so the PMC can be safely reused
300 In the future the PMC returned might be different than the one
301 passed, e.g., if we need to reallocate the PMC in a different
308 PARROT_CAN_RETURN_NULL
310 pt_shared_fixup(PARROT_INTERP
, ARGMOD(PMC
*pmc
))
312 ASSERT_ARGS(pt_shared_fixup
)
313 /* TODO this will need to change for thread pools
314 * XXX should we have a separate interpreter for this?
317 Parrot_Interp master
= interpreter_array
[0];
318 const int is_ro
= pmc
->vtable
->flags
& VTABLE_IS_READONLY_FLAG
;
320 /* This lock is paired with one in objects.c. It is necessary to protect
321 * against the master interpreter adding classes and consequently
322 * resizing its classname->type_id hashtable and/or expanding its vtable
324 * TODO investigate if a read-write lock results in substantially
325 * better performance.
327 LOCK_INTERPRETER(master
);
328 type_num
= pmc
->vtable
->base_type
;
330 if (type_num
== enum_type_undef
) {
331 UNLOCK_INTERPRETER(master
);
332 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
333 "pt_shared_fixup: unsharable type");
336 pmc
->vtable
= master
->vtables
[type_num
];
338 UNLOCK_INTERPRETER(master
);
341 pmc
->vtable
= pmc
->vtable
->ro_variant_vtable
;
343 PObj_is_PMC_shared_SET(pmc
);
345 /* make sure metadata doesn't go away unexpectedly */
346 if (PMC_metadata(pmc
))
347 PMC_metadata(pmc
) = pt_shared_fixup(interp
, PMC_metadata(pmc
));
354 =item C<static void pt_thread_signal(Parrot_Interp self, PARROT_INTERP)>
356 Wakes up an C<interp> which should have called pt_thread_wait().
363 pt_thread_signal(ARGIN(Parrot_Interp self
), PARROT_INTERP
)
365 ASSERT_ARGS(pt_thread_signal
)
366 COND_SIGNAL(interp
->thread_data
->interp_cond
);
371 =item C<void pt_thread_wait_with(PARROT_INTERP, Parrot_mutex *mutex)>
373 Waits for this interpreter to be signalled through its condition variable,
374 dealing properly with GC issues. C<*mutex> is assumed locked on entry and
375 will be locked on exit from this function. If a GC run occurs in the middle of
376 this function, then a spurious wakeup may occur.
383 pt_thread_wait_with(PARROT_INTERP
, ARGMOD(Parrot_mutex
*mutex
))
385 ASSERT_ARGS(pt_thread_wait_with
)
386 LOCK(interpreter_array_mutex
);
387 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
388 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
389 UNLOCK(interpreter_array_mutex
);
392 pt_suspend_self_for_gc(interp
);
395 /* since we unlocked the mutex something bad may have occured */
399 interp
->thread_data
->state
|= THREAD_STATE_GC_WAKEUP
;
401 UNLOCK(interpreter_array_mutex
);
402 COND_WAIT(interp
->thread_data
->interp_cond
, *mutex
);
403 LOCK(interpreter_array_mutex
);
405 interp
->thread_data
->state
&= ~THREAD_STATE_GC_WAKEUP
;
407 if (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
) {
409 /* XXX loop needed? */
411 UNLOCK(interpreter_array_mutex
);
412 /* fprintf(stderr, "%p: woken up, doing GC run\n", interp); */
413 pt_suspend_self_for_gc(interp
);
414 LOCK(interpreter_array_mutex
);
415 } while (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
);
417 UNLOCK(interpreter_array_mutex
);
421 UNLOCK(interpreter_array_mutex
);
427 =item C<static void pt_thread_wait(PARROT_INTERP)>
429 Waits for a signal, handling GC matters correctly. C<interpreter_array_mutex>
430 is assumed held. Spurious wakeups may occur.
437 pt_thread_wait(PARROT_INTERP
)
439 ASSERT_ARGS(pt_thread_wait
)
440 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
441 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
442 /* fprintf(stderr, "%p: pt_thread_wait, before sleep, doing GC run\n",
445 UNLOCK(interpreter_array_mutex
);
446 pt_suspend_self_for_gc(interp
);
447 LOCK(interpreter_array_mutex
);
449 /* while we were GCing, whatever we were waiting on might have
454 interp
->thread_data
->state
|= THREAD_STATE_GC_WAKEUP
;
456 COND_WAIT(interp
->thread_data
->interp_cond
, interpreter_array_mutex
);
458 interp
->thread_data
->state
&= ~THREAD_STATE_GC_WAKEUP
;
460 while (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
) {
461 UNLOCK(interpreter_array_mutex
);
462 /* fprintf(stderr, "%p: woken up, doing GC run\n", interp); */
463 pt_suspend_self_for_gc(interp
);
464 LOCK(interpreter_array_mutex
);
471 =item C<static void* thread_func(void *arg)>
473 The actual thread function.
479 PARROT_CAN_RETURN_NULL
481 thread_func(ARGIN_NULLOK(void *arg
))
483 ASSERT_ARGS(thread_func
)
484 Parrot_runloop jump_point
;
487 PMC
* volatile sub_pmc
;
489 PMC
* const self
= (PMC
*) arg
;
490 PMC
*ret_val
= PMCNULL
;
491 Parrot_Interp interp
=
492 (Parrot_Interp
)((Parrot_ParrotInterpreter_attributes
*)PMC_data(self
))->interp
;
494 Parrot_block_GC_mark(interp
);
495 Parrot_block_GC_sweep(interp
);
497 /* need to set it here because argument passing can trigger GC */
498 interp
->lo_var_ptr
= &lo_var_ptr
;
499 GETATTR_ParrotInterpreter_sub(interp
, self
, sub_pmc
);
500 sub_arg
= VTABLE_get_pmc(interp
, self
);
502 if (setjmp(jump_point
.resume
)) {
503 /* caught exception */
504 /* XXX what should we really do here */
505 /* PMC *exception = Parrot_cx_peek_task(interp);
506 Parrot_io_eprintf(interp,
507 "Unhandled exception in thread with tid %d "
508 "(message=%Ss, number=%d)\n",
509 interp->thread_data->tid,
510 VTABLE_get_string(interp, exception),
511 VTABLE_get_integer_keyed_str(interp, exception,
512 Parrot_str_new_constant(interp, "type"))); */
516 Parrot_ex_add_c_handler(interp
, &jump_point
);
517 Parrot_unblock_GC_mark(interp
);
518 Parrot_unblock_GC_sweep(interp
);
519 Parrot_ext_call(interp
, sub_pmc
, "Pf->P", sub_arg
, &ret_val
);
522 /* thread is finito */
523 LOCK(interpreter_array_mutex
);
524 DEBUG_ONLY(fprintf(stderr
, "marking an thread as finished\n"));
526 interp
->thread_data
->state
|= THREAD_STATE_FINISHED
;
527 tid
= interp
->thread_data
->tid
;
529 if (interp
!= interpreter_array
[tid
]) {
530 UNLOCK(interpreter_array_mutex
);
531 PANIC(interp
, "thread finished: interpreter mismatch");
533 if (interp
->thread_data
->state
& THREAD_STATE_DETACHED
) {
534 interpreter_array
[tid
] = NULL
;
535 DEBUG_ONLY(fprintf(stderr
,
536 "really destroying an interpreter [exit while detached]\n"));
537 Parrot_really_destroy(interp
, 0, NULL
);
539 else if (interp
->thread_data
->state
& THREAD_STATE_JOINED
) {
540 pt_thread_signal(interp
, interp
->thread_data
->joiner
);
543 /* make sure we don't block a GC run */
544 pt_gc_wakeup_check();
545 PARROT_ASSERT(interp
->thread_data
->state
& THREAD_STATE_FINISHED
);
547 UNLOCK(interpreter_array_mutex
);
556 =head2 Helper functions used also for running plain interpreters
560 =item C<void pt_clone_code(Parrot_Interp d, Parrot_Interp s)>
562 Copies/clones the packfile/code from interpreter C<s> to C<d>. All
563 resources are created in C<d>.
570 pt_clone_code(Parrot_Interp d
, Parrot_Interp s
)
572 ASSERT_ARGS(pt_clone_code
)
573 Parrot_block_GC_mark(d
);
574 Interp_flags_SET(d
, PARROT_EXTERN_CODE_FLAG
);
576 Parrot_switch_to_cs(d
, s
->code
, 1);
577 Parrot_unblock_GC_mark(d
);
582 =item C<static void pt_ns_clone(PARROT_INTERP, Parrot_Interp d, PMC *dest_ns,
583 Parrot_Interp s, PMC *source_ns)>
585 Clones all globals from C<s> to C<d>.
592 pt_ns_clone(PARROT_INTERP
, ARGOUT(Parrot_Interp d
), ARGOUT(PMC
*dest_ns
),
593 ARGIN(Parrot_Interp s
), ARGIN(PMC
*source_ns
))
595 ASSERT_ARGS(pt_ns_clone
)
596 PMC
* const iter
= VTABLE_get_iter(s
, source_ns
);
597 const INTVAL n
= VTABLE_elements(s
, source_ns
);
600 for (i
= 0; i
< n
; ++i
) {
601 /* XXX what if 'key' is a non-constant-pool string? */
602 STRING
* const key
= VTABLE_shift_string(s
, iter
);
603 PMC
* const val
= VTABLE_get_pmc_keyed_str(s
, source_ns
, key
);
605 if (val
->vtable
->base_type
== enum_class_NameSpace
) {
606 PMC
*sub_ns
= VTABLE_get_pmc_keyed_str(d
, dest_ns
, key
);
607 if (PMC_IS_NULL(sub_ns
) || sub_ns
->vtable
->base_type
!=
608 enum_class_NameSpace
) {
609 sub_ns
= Parrot_pmc_new(d
, enum_class_NameSpace
);
610 VTABLE_set_pmc_keyed_str(d
, dest_ns
, key
, sub_ns
);
612 pt_ns_clone(s
, d
, sub_ns
, s
, val
);
615 PMC
* const dval
= VTABLE_get_pmc_keyed_str(d
, dest_ns
, key
);
617 if (PMC_IS_NULL(dval
)) {
618 PMC
* const copy
= make_local_copy(d
, s
, val
);
619 Parrot_Sub_attributes
*val_sub
;
621 if (val
->vtable
->base_type
== enum_class_Sub
)
622 PMC_get_sub(interp
, val
, val_sub
);
624 /* Vtable overrides and methods were already cloned, so don't reclone them. */
625 if (! (val
->vtable
->base_type
== enum_class_Sub
626 && (val_sub
->vtable_index
!= -1
627 || val_sub
->comp_flags
& SUB_COMP_FLAG_METHOD
))) {
628 VTABLE_set_pmc_keyed_str(d
, dest_ns
, key
, copy
);
637 =item C<void pt_clone_globals(Parrot_Interp d, Parrot_Interp s)>
639 Copies the global namespace when cloning a new interpreter.
646 pt_clone_globals(Parrot_Interp d
, Parrot_Interp s
)
648 ASSERT_ARGS(pt_clone_globals
)
649 Parrot_block_GC_mark(d
);
650 pt_ns_clone(s
, d
, d
->root_namespace
, s
, s
->root_namespace
);
651 Parrot_unblock_GC_mark(d
);
656 =item C<void pt_thread_prepare_for_run(Parrot_Interp d, Parrot_Interp s)>
658 Sets up a new thread to run.
665 pt_thread_prepare_for_run(Parrot_Interp d
, SHIM(Parrot_Interp s
))
667 ASSERT_ARGS(pt_thread_prepare_for_run
)
674 =head2 ParrotThread methods
684 =item C<PMC * pt_transfer_sub(Parrot_Interp d, Parrot_Interp s, PMC *sub)>
686 Clones the sub so that it's suitable for the other interpreter.
692 PARROT_CAN_RETURN_NULL
694 pt_transfer_sub(ARGOUT(Parrot_Interp d
), ARGIN(Parrot_Interp s
), ARGIN(PMC
*sub
))
696 ASSERT_ARGS(pt_transfer_sub
)
697 #if defined THREAD_DEBUG && THREAD_DEBUG
698 Parrot_io_eprintf(s
, "copying over subroutine [%Ss]\n",
699 Parrot_full_sub_name(s
, sub
));
701 return make_local_copy(d
, s
, sub
);
706 =item C<PMC * pt_thread_create(PARROT_INTERP, INTVAL type, INTVAL clone_flags)>
715 PARROT_CANNOT_RETURN_NULL
716 PARROT_WARN_UNUSED_RESULT
718 pt_thread_create(PARROT_INTERP
, INTVAL type
, INTVAL clone_flags
)
720 ASSERT_ARGS(pt_thread_create
)
721 PMC
* const new_interp_pmc
= pmc_new(interp
, type
);
722 Interp
* const new_interp
= (Interp
*)VTABLE_get_pointer(interp
, new_interp_pmc
);
724 clone_interpreter(new_interp
, interp
, clone_flags
);
725 pt_thread_prepare_for_run(new_interp
, interp
);
727 return new_interp_pmc
;
732 =item C<int pt_thread_run(PARROT_INTERP, PMC *thread_interp_pmc, PMC *sub, PMC
742 pt_thread_run(PARROT_INTERP
, ARGMOD(PMC
*thread_interp_pmc
), ARGIN(PMC
*sub
),
743 ARGIN_NULLOK(PMC
*arg
))
745 ASSERT_ARGS(pt_thread_run
)
746 Interp
* const thread_interp
= (Interp
*)VTABLE_get_pointer(interp
, thread_interp_pmc
);
748 SETATTR_ParrotInterpreter_sub(interp
,
749 thread_interp_pmc
, pt_transfer_sub(thread_interp
, interp
, sub
));
750 VTABLE_set_pmc(interp
, thread_interp_pmc
, make_local_args_copy(thread_interp
, interp
, arg
));
751 thread_interp
->thread_data
->state
= THREAD_STATE_JOINABLE
;
753 THREAD_CREATE_JOINABLE(thread_interp
->thread_data
->thread
, thread_func
, thread_interp_pmc
);
755 /* check for pending GC */
757 * can't do multi-threaded GC yet
758 * XXX a quick hack to pass the few tests
760 LOCK(interpreter_array_mutex);
761 if (interp->thread_data->state & THREAD_STATE_SUSPEND_GC_REQUESTED)
762 pt_suspend_one_for_gc(new_interp);
763 UNLOCK(interpreter_array_mutex);
767 return thread_interp
->thread_data
->tid
;
772 =item C<int pt_thread_create_run(PARROT_INTERP, INTVAL type, INTVAL clone_flags,
775 create a pt_thread run
782 pt_thread_create_run(PARROT_INTERP
,
783 INTVAL type
, INTVAL clone_flags
, ARGIN(PMC
*sub
), ARGIN_NULLOK(PMC
*arg
))
785 ASSERT_ARGS(pt_thread_create_run
)
786 PMC
*thread_interp_pmc
= pt_thread_create(interp
, type
, clone_flags
);
787 return pt_thread_run(interp
, thread_interp_pmc
, sub
, arg
);
793 =item C<void pt_thread_yield(void)>
795 Relinquishes hold on the processor.
802 pt_thread_yield(void)
804 ASSERT_ARGS(pt_thread_yield
)
810 =item C<static Parrot_Interp pt_check_tid(UINTVAL tid, const char *from)>
812 Helper function. Checks if the given thread ID is valid. The caller holds the
813 mutex. Returns the interpreter for C<tid>.
820 pt_check_tid(UINTVAL tid
, ARGIN(const char *from
))
822 ASSERT_ARGS(pt_check_tid
)
823 if (tid
>= n_interpreters
) {
824 UNLOCK(interpreter_array_mutex
);
825 exit_fatal(1, "%s: illegal thread tid %d", from
, tid
);
828 UNLOCK(interpreter_array_mutex
);
829 exit_fatal(1, "%s: illegal thread tid %d (main)", from
, tid
);
831 if (!interpreter_array
[tid
]) {
832 UNLOCK(interpreter_array_mutex
);
833 exit_fatal(1, "%s: illegal thread tid %d - empty", from
, tid
);
835 return interpreter_array
[tid
];
840 =item C<static void mutex_unlock(void *arg)>
842 Unlocks the mutex C<*arg>.
849 mutex_unlock(ARGMOD(void *arg
))
851 ASSERT_ARGS(mutex_unlock
)
852 UNLOCK(*(Parrot_mutex
*) arg
);
857 =item C<static int is_suspended_for_gc(PARROT_INTERP)>
859 Returns true iff C<interp> is suspended for a global GC run. Be sure to hold
860 C<interpreter_array_mutex>.
866 PARROT_WARN_UNUSED_RESULT
868 is_suspended_for_gc(PARROT_INTERP
)
870 ASSERT_ARGS(is_suspended_for_gc
)
873 else if (interp
->thread_data
->wants_shared_gc
)
875 else if (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)
877 else if ((interp
->thread_data
->state
& THREAD_STATE_FINISHED
) ||
878 (interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
))
886 =item C<static int pt_gc_count_threads(void)>
888 Returns the number of active threads in the system (running or suspended). Be
889 sure to hold C<interpreter_array_mutex>.
896 pt_gc_count_threads(void)
898 ASSERT_ARGS(pt_gc_count_threads
)
902 for (i
= 0; i
< n_interpreters
; ++i
) {
904 cur
= interpreter_array
[i
];
907 if (cur
->thread_data
->state
& (THREAD_STATE_NOT_STARTED
|
908 THREAD_STATE_FINISHED
))
912 DEBUG_ONLY(fprintf(stderr
, "found %d threads\n", count
));
918 =item C<static void pt_gc_wait_for_stage(PARROT_INTERP, thread_gc_stage_enum
919 from_stage, thread_gc_stage_enum to_stage)>
921 Waits until all threads have reached the desired stage. Takes an interpreter,
922 starting stage and ending stage as arguments. Updates the thread information.
923 Used in C<pt_gc_start_mark> and C<pt_gc_stop_mark>.
930 pt_gc_wait_for_stage(PARROT_INTERP
, thread_gc_stage_enum from_stage
,
931 thread_gc_stage_enum to_stage
)
933 ASSERT_ARGS(pt_gc_wait_for_stage
)
934 Shared_gc_info
* const info
= shared_gc_info
;
937 DEBUG_ONLY(fprintf(stderr
, "%p: gc_wait_for_stage: %d->%d\n", interp
, from_stage
, to_stage
));
939 /* XXX well-timed thread death can mess this up */
940 LOCK(interpreter_array_mutex
);
942 DEBUG_ONLY(fprintf(stderr
, "%p: got lock\n", interp
));
943 thread_count
= pt_gc_count_threads();
945 PARROT_ASSERT(info
->gc_stage
== from_stage
);
946 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
));
947 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_FINISHED
));
950 PARROT_ASSERT(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
);
952 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
));
956 DEBUG_ONLY(fprintf(stderr
, "%p: gc_wait_for_stage: got %d\n", interp
, info
->num_reached
));
958 if (info
->num_reached
== thread_count
) {
959 info
->gc_stage
= to_stage
;
960 info
->num_reached
= 0;
961 COND_BROADCAST(info
->gc_cond
);
965 COND_WAIT(info
->gc_cond
, interpreter_array_mutex
);
966 } while (info
->gc_stage
!= to_stage
);
968 UNLOCK(interpreter_array_mutex
);
974 =item C<static void pt_gc_wakeup_check(void)>
976 Checks if it's necessary to wake threads to perform garbage collection. This
977 is called after thread death. Be sure to hold C<interpreter_array_mutex>.
984 pt_gc_wakeup_check(void)
986 ASSERT_ARGS(pt_gc_wakeup_check
)
987 Shared_gc_info
* const info
= shared_gc_info
;
993 thread_count
= pt_gc_count_threads();
995 if (info
->num_reached
== thread_count
) {
996 PARROT_ASSERT(info
->gc_stage
== THREAD_GC_STAGE_NONE
);
997 info
->gc_stage
= THREAD_GC_STAGE_MARK
;
998 info
->num_reached
= 0;
999 COND_BROADCAST(info
->gc_cond
);
1005 =item C<static void pt_suspend_one_for_gc(PARROT_INTERP)>
1007 Suspends a single interpreter for GC. Be sure to hold
1008 C<interpreter_array_mutex>.
1015 pt_suspend_one_for_gc(PARROT_INTERP
)
1017 ASSERT_ARGS(pt_suspend_one_for_gc
)
1018 DEBUG_ONLY(fprintf(stderr
, "suspend one: %p\n", interp
));
1019 if (is_suspended_for_gc(interp
)) {
1020 DEBUG_ONLY(fprintf(stderr
, "ignoring already suspended\n"));
1024 if (interp
->thread_data
->state
& THREAD_STATE_GC_WAKEUP
) {
1025 DEBUG_ONLY(fprintf(stderr
, "just waking it up\n"));
1026 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1027 COND_SIGNAL(interp
->thread_data
->interp_cond
);
1030 DEBUG_ONLY(fprintf(stderr
, "queuing event\n"));
1031 interp
->thread_data
->state
|= THREAD_STATE_SUSPEND_GC_REQUESTED
;
1032 Parrot_cx_request_suspend_for_gc(interp
);
1038 =item C<static void pt_suspend_all_for_gc(PARROT_INTERP)>
1040 Notifies all threads to perform a GC run.
1047 pt_suspend_all_for_gc(PARROT_INTERP
)
1049 ASSERT_ARGS(pt_suspend_all_for_gc
)
1052 DEBUG_ONLY(fprintf(stderr
, "suspend_all_for_gc [interp=%p]\n", interp
));
1054 LOCK(interpreter_array_mutex
);
1055 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1057 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
1058 DEBUG_ONLY(fprintf(stderr
, "found while suspending all\n"));
1059 Parrot_cx_delete_suspend_for_gc(interp
);
1060 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPEND_GC_REQUESTED
;
1061 UNLOCK(interpreter_array_mutex
);
1065 /* now send all the non-suspended threads to suspend for GC */
1066 for (i
= 0; i
< n_interpreters
; ++i
) {
1067 Parrot_Interp other_interp
= interpreter_array
[i
];
1069 if (interp
== other_interp
)
1072 if (is_suspended_for_gc(other_interp
))
1075 pt_suspend_one_for_gc(other_interp
);
1077 UNLOCK(interpreter_array_mutex
);
1082 =item C<void pt_suspend_self_for_gc(PARROT_INTERP)>
1084 Suspends this thread for a full GC run.
1086 XXX FIXME -- if GC is blocked, we need to do a GC run as soon
1087 as it becomes unblocked.
1094 pt_suspend_self_for_gc(PARROT_INTERP
)
1096 ASSERT_ARGS(pt_suspend_self_for_gc
)
1097 PARROT_ASSERT(interp
);
1098 PARROT_ASSERT(!Parrot_is_blocked_GC_mark(interp
));
1099 DEBUG_ONLY(fprintf(stderr
, "%p: suspend_self_for_gc\n", interp
));
1100 /* since we are modifying our own state, we need to lock
1101 * the interpreter_array_mutex.
1103 LOCK(interpreter_array_mutex
);
1104 DEBUG_ONLY(fprintf(stderr
, "%p: got lock\n", interp
));
1106 PARROT_ASSERT(interp
->thread_data
->state
&
1107 (THREAD_STATE_SUSPEND_GC_REQUESTED
| THREAD_STATE_SUSPENDED_GC
));
1109 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
1110 DEBUG_ONLY(fprintf(stderr
, "remove queued request\n"));
1111 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp
))) {/*Empty body*/};
1112 DEBUG_ONLY(fprintf(stderr
, "removed all queued requests\n"));
1113 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPEND_GC_REQUESTED
;
1115 if (!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)) {
1116 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1119 DEBUG_ONLY(fprintf(stderr
, "no need to set suspended\n"));
1121 UNLOCK(interpreter_array_mutex
);
1123 /* mark and sweep our world -- later callbacks will keep
1126 Parrot_gc_mark_and_sweep(interp
, GC_trace_stack_FLAG
);
1128 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
));
1133 =item C<PMC* pt_thread_join(Parrot_Interp parent, UINTVAL tid)>
1135 Joins (by waiting for) a joinable thread.
1141 PARROT_CAN_RETURN_NULL
1143 pt_thread_join(ARGIN(Parrot_Interp parent
), UINTVAL tid
)
1145 ASSERT_ARGS(pt_thread_join
)
1147 Parrot_Interp interp
;
1149 LOCK(interpreter_array_mutex
);
1151 interp
= pt_check_tid(tid
, "join");
1153 if (interp
== parent
)
1154 do_panic(parent
, "Can't join self", __FILE__
, __LINE__
);
1156 if ((!(interp
->thread_data
->state
& (THREAD_STATE_DETACHED
1157 | THREAD_STATE_JOINED
)) &&
1158 !(interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
)) ||
1159 interp
->thread_data
->state
== THREAD_STATE_FINISHED
) {
1160 void *raw_retval
= NULL
;
1163 interp
->thread_data
->state
|= THREAD_STATE_JOINED
;
1165 while (!(interp
->thread_data
->state
& THREAD_STATE_FINISHED
)) {
1166 interp
->thread_data
->joiner
= parent
;
1167 pt_thread_wait(parent
);
1170 UNLOCK(interpreter_array_mutex
);
1171 JOIN(interp
->thread_data
->thread
, raw_retval
);
1173 retval
= (PMC
*)raw_retval
;
1175 * we need to push a cleanup handler here: if cloning
1176 * of the retval fails (e.g. it's a NULLPMC) this lock
1177 * isn't released until eternity or someone hits ^C
1179 * TODO This is needed for all places holding a lock for
1182 * TODO remove that and replace it with proper exception
1183 * handling, so that a failing clone in the parent
1184 * just stops that thread
1187 LOCK(interpreter_array_mutex
);
1188 CLEANUP_PUSH(mutex_unlock
, &interpreter_array_mutex
);
1193 * clone the PMC into caller, if it's not a shared PMC
1194 * the PMC is not in the parents root set nor in the
1195 * stack so block GC during clone
1196 * XXX should probably acquire the parent's interpreter mutex
1198 Parrot_block_GC_mark(parent
);
1199 parent_ret
= make_local_copy(parent
, interp
, retval
);
1201 /* this PMC is living only in the stack of this currently
1202 * dying interpreter, so register it in parent's GC registry
1203 * XXX is this still needed?
1205 Parrot_pmc_gc_register(parent
, parent_ret
);
1206 Parrot_unblock_GC_mark(parent
);
1207 retval
= parent_ret
;
1212 interpreter_array
[tid
] = NULL
;
1215 DEBUG_ONLY(fprintf(stderr
, "destroying an interpreter [join]\n"));
1216 if (Interp_debug_TEST(parent
, PARROT_THREAD_DEBUG_FLAG
))
1217 fprintf(stderr
, "running threads %d\n", running_threads
);
1219 /* reparent it so memory pool merging works */
1220 interp
->parent_interpreter
= parent
;
1221 Parrot_really_destroy(interp
, 0, NULL
);
1225 * interpreter destruction is done - unregister the return
1226 * value, caller gets it now
1229 Parrot_pmc_gc_unregister(parent
, retval
);
1234 * when here thread was in wrong state
1236 state
= interp
->thread_data
->state
;
1237 UNLOCK(interpreter_array_mutex
);
1238 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
1239 "join: illegal thread state %d tid %d", state
, tid
);
1244 =item C<void pt_join_threads(PARROT_INTERP)>
1246 Possibly waits for other running threads. This is called when destroying
1254 pt_join_threads(PARROT_INTERP
)
1256 ASSERT_ARGS(pt_join_threads
)
1258 pt_free_pool(interp
);
1260 /* if no threads were started - fine */
1261 LOCK(interpreter_array_mutex
);
1262 if (n_interpreters
<= 1) {
1264 UNLOCK(interpreter_array_mutex
);
1268 /* only the first interpreter waits for other threads */
1269 if (interp
!= interpreter_array
[0]) {
1270 UNLOCK(interpreter_array_mutex
);
1274 for (i
= 1; i
< n_interpreters
; ++i
) {
1275 Parrot_Interp thread_interp
= interpreter_array
[i
];
1276 if (thread_interp
== NULL
)
1278 if (thread_interp
->thread_data
->state
== THREAD_STATE_JOINABLE
||
1279 (thread_interp
->thread_data
->state
& THREAD_STATE_FINISHED
)) {
1281 void *retval
= NULL
;
1282 thread_interp
->thread_data
->state
|= THREAD_STATE_JOINED
;
1283 UNLOCK(interpreter_array_mutex
);
1284 JOIN(thread_interp
->thread_data
->thread
, retval
);
1285 LOCK(interpreter_array_mutex
);
1288 UNLOCK(interpreter_array_mutex
);
1294 =item C<static Parrot_Interp detach(UINTVAL tid)>
1296 Helper for detach and kill.
1298 Returns the interpreter, if it didn't finish yet.
1304 static Parrot_Interp
1308 Parrot_Interp interp
;
1310 LOCK(interpreter_array_mutex
);
1311 interp
= pt_check_tid(tid
, "detach");
1313 * if interpreter is joinable, we detach em
1315 if (interp
->thread_data
->state
== THREAD_STATE_JOINABLE
||
1316 interp
->thread_data
->state
== THREAD_STATE_FINISHED
) {
1317 DETACH(interp
->thread_data
->thread
);
1318 interp
->thread_data
->state
|= THREAD_STATE_DETACHED
;
1320 if (interp
->thread_data
->state
& THREAD_STATE_FINISHED
) {
1321 interpreter_array
[tid
] = NULL
;
1322 DEBUG_ONLY(fprintf(stderr
, "destroying an interpreter [detach]\n"));
1323 Parrot_really_destroy(interp
, 0, NULL
);
1327 UNLOCK(interpreter_array_mutex
);
1333 =item C<void pt_thread_detach(UINTVAL tid)>
1335 Detaches the thread, making it non-joinable.
1342 pt_thread_detach(UINTVAL tid
)
1344 ASSERT_ARGS(pt_thread_detach
)
1350 =item C<void pt_thread_kill(UINTVAL tid)>
1359 pt_thread_kill(UINTVAL tid
)
1361 ASSERT_ARGS(pt_thread_kill
)
1362 PARROT_INTERP
= detach(tid
);
1364 /* schedule a terminate event for that interpreter */
1366 Parrot_cx_runloop_end(interp
);
1373 =head2 Threaded interpreter book-keeping
1377 =item C<void pt_add_to_interpreters(PARROT_INTERP, Parrot_Interp new_interp)>
1379 Stores the given interpreter in the array of all interpreters. Be sure to hold
1380 C<interpreter_array_mutex>.
1387 pt_add_to_interpreters(PARROT_INTERP
, ARGIN_NULLOK(Parrot_Interp new_interp
))
1389 ASSERT_ARGS(pt_add_to_interpreters
)
1391 DEBUG_ONLY(fprintf(stderr
, "interp = %p\n", interp
));
1395 * Create an entry for the very first interpreter, event
1398 PARROT_ASSERT(!interpreter_array
);
1399 PARROT_ASSERT(n_interpreters
== 0);
1401 interpreter_array
= mem_internal_allocate_typed(Interp
*);
1402 interpreter_array
[0] = interp
;
1405 shared_gc_info
= (Shared_gc_info
*)mem_internal_allocate_zeroed(sizeof (*shared_gc_info
));
1406 COND_INIT(shared_gc_info
->gc_cond
);
1407 PARROT_ATOMIC_INT_INIT(shared_gc_info
->gc_block_level
);
1408 PARROT_ATOMIC_INT_SET(shared_gc_info
->gc_block_level
, 0);
1410 /* XXX try to defer this until later */
1411 PARROT_ASSERT(interp
== interpreter_array
[0]);
1412 interp
->thread_data
= mem_internal_allocate_zeroed_typed(Thread_data
);
1413 INTERPRETER_LOCK_INIT(interp
);
1414 interp
->thread_data
->tid
= 0;
1420 new_interp
->thread_data
= mem_internal_allocate_zeroed_typed(Thread_data
);
1421 INTERPRETER_LOCK_INIT(new_interp
);
1423 if (Interp_debug_TEST(interp
, PARROT_THREAD_DEBUG_FLAG
))
1424 fprintf(stderr
, "running threads %d\n", running_threads
);
1426 /* look for an empty slot */
1427 for (i
= 0; i
< n_interpreters
; ++i
) {
1428 if (interpreter_array
[i
] == NULL
) {
1429 interpreter_array
[i
] = new_interp
;
1430 new_interp
->thread_data
->tid
= i
;
1431 new_interp
->thread_data
->state
= THREAD_STATE_NOT_STARTED
;
1436 /* need to resize */
1437 interpreter_array
= (Interp
**)mem_internal_realloc(interpreter_array
,
1438 (n_interpreters
+ 1) * sizeof (Interp
*));
1440 interpreter_array
[n_interpreters
] = new_interp
;
1441 new_interp
->thread_data
->tid
= n_interpreters
;
1442 new_interp
->thread_data
->state
= THREAD_STATE_NOT_STARTED
;
1451 =head2 GC Synchronization Functions
1455 =item C<void pt_gc_start_mark(PARROT_INTERP)>
1457 Record that the mark phase of GC is about to begin. In the presence of shared
1458 PMCs, we can only run one GC run at a time.
1460 C<flags> are the GC flags. We check if we need to collect shared objects or
1463 TODO - Have a count of shared PMCs and check it during GC.
1465 TODO - Evaluate if a interpreter lock is cheaper when C<gc_mark_ptr> is
1473 pt_gc_start_mark(PARROT_INTERP
)
1475 ASSERT_ARGS(pt_gc_start_mark
)
1476 Shared_gc_info
*info
;
1479 DEBUG_ONLY(fprintf(stderr
, "%p: pt_gc_start_mark\n", interp
));
1480 /* if no other threads are running, we are safe */
1481 if (!running_threads
)
1485 PARROT_ATOMIC_INT_GET(block_level
, info
->gc_block_level
);
1487 DEBUG_ONLY(fprintf(stderr
, "start threaded mark\n"));
1489 * TODO now check, if we are the owner of a shared memory pool
1491 * - suspend all other threads by sending them a suspend event
1492 * (or put a LOCK around updating the mark pointers)
1493 * - return and continue the mark phase
1494 * - then s. comments below
1496 LOCK(interpreter_array_mutex
);
1497 if (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
) {
1498 PARROT_ASSERT(!(interp
->thread_data
->state
&
1499 THREAD_STATE_SUSPEND_GC_REQUESTED
));
1500 DEBUG_ONLY(fprintf(stderr
, "already suspended...\n"));
1501 UNLOCK(interpreter_array_mutex
);
1503 else if (block_level
) {
1504 /* unthreaded collection */
1505 DEBUG_ONLY(fprintf(stderr
, "... but blocked\n"));
1507 /* holding the lock */
1510 else if (interp
->thread_data
->state
&
1511 THREAD_STATE_SUSPEND_GC_REQUESTED
) {
1512 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp
))) {/*Empty body*/};
1514 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPEND_GC_REQUESTED
;
1515 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1517 DEBUG_ONLY(fprintf(stderr
, "%p: detected request\n", interp
));
1518 UNLOCK(interpreter_array_mutex
);
1521 /* we need to stop the world */
1522 DEBUG_ONLY(fprintf(stderr
, "stop the world\n"));
1523 UNLOCK(interpreter_array_mutex
);
1525 pt_suspend_all_for_gc(interp
);
1528 DEBUG_ONLY(fprintf(stderr
, "%p: wait for stage\n", interp
));
1529 pt_gc_wait_for_stage(interp
, THREAD_GC_STAGE_NONE
, THREAD_GC_STAGE_MARK
);
1531 DEBUG_ONLY(fprintf(stderr
, "actually mark\n"));
1533 * We can't allow parallel running GCs.
1535 LOCK(interpreter_array_mutex
);
1536 DEBUG_ONLY(fprintf(stderr
, "got marking lock\n"));
1541 =item C<void pt_gc_mark_root_finished(PARROT_INTERP)>
1543 Records that GC has finished for the root set. EXCEPTION_UNIMPLEMENTED
1550 pt_gc_mark_root_finished(PARROT_INTERP
)
1552 ASSERT_ARGS(pt_gc_mark_root_finished
)
1553 if (!running_threads
)
1556 * TODO now check, if we are the owner of a shared memory pool
1558 * - now mark all members of our pool
1559 * - if all shared PMCs are marked by all threads then
1560 * - we can continue to free unused objects
1566 =item C<void pt_gc_stop_mark(PARROT_INTERP)>
1568 Records that the mark phase of GC has completed.
1575 pt_gc_stop_mark(PARROT_INTERP
)
1577 ASSERT_ARGS(pt_gc_stop_mark
)
1578 if (!running_threads
)
1581 * normal operation can continue now
1582 * - other threads may or not free unused objects then,
1583 * depending on their resource statistics
1585 if (!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)) {
1586 UNLOCK(interpreter_array_mutex
);
1590 PARROT_ASSERT(!(interp
->thread_data
->state
&
1591 THREAD_STATE_SUSPEND_GC_REQUESTED
));
1592 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPENDED_GC
;
1594 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp
))) {
1595 /* XXX FIXME make this message never trigger */
1596 fprintf(stderr
, "%p: extraneous suspend_gc event\n", (void *)interp
);
1599 DEBUG_ONLY(fprintf(stderr
, "%p: unlock\n", interp
));
1600 UNLOCK(interpreter_array_mutex
);
1601 DEBUG_ONLY(fprintf(stderr
, "wait to sweep\n"));
1603 pt_gc_wait_for_stage(interp
, THREAD_GC_STAGE_MARK
, THREAD_GC_STAGE_SWEEP
);
1608 =item C<void Parrot_shared_gc_block(PARROT_INTERP)>
1610 Blocks stop-the-world GC runs.
1618 Parrot_shared_gc_block(PARROT_INTERP
)
1620 ASSERT_ARGS(Parrot_shared_gc_block
)
1621 Shared_gc_info
* const info
= get_pool();
1625 PARROT_ATOMIC_INT_INC(level
, info
->gc_block_level
);
1626 PARROT_ASSERT(level
> 0);
1632 =item C<void Parrot_shared_gc_unblock(PARROT_INTERP)>
1634 Unblocks stop-the-world GC runs.
1642 Parrot_shared_gc_unblock(PARROT_INTERP
)
1644 ASSERT_ARGS(Parrot_shared_gc_unblock
)
1645 Shared_gc_info
* const info
= get_pool();
1648 PARROT_ATOMIC_INT_DEC(level
, info
->gc_block_level
);
1649 PARROT_ASSERT(level
>= 0);
1655 * c-file-style: "parrot"
1657 * vim: expandtab shiftwidth=4: