tagged release 0.6.4
[parrot.git] / src / thread.c
blobb413d39a71afe5e60219ab8b7df3295789433b23
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/thread.c - Thread handling stuff
9 =head1 DESCRIPTION
11 Threads are created by creating new C<ParrotInterpreter> objects.
13 =head2 Functions
15 =over 4
17 =cut
21 #include "parrot/parrot.h"
22 #include "parrot/atomic.h"
24 /* HEADERIZER HFILE: include/parrot/thread.h */
26 /* HEADERIZER BEGIN: static */
27 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
29 static Parrot_Interp detach(UINTVAL tid);
30 PARROT_CAN_RETURN_NULL
31 static Shared_gc_info * get_pool(PARROT_INTERP)
32 __attribute__nonnull__(1);
34 PARROT_WARN_UNUSED_RESULT
35 static int is_suspended_for_gc(PARROT_INTERP)
36 __attribute__nonnull__(1);
38 PARROT_CAN_RETURN_NULL
39 static PMC * make_local_args_copy(PARROT_INTERP,
40 ARGIN(Parrot_Interp old_interp),
41 ARGIN_NULLOK(PMC *args))
42 __attribute__nonnull__(1)
43 __attribute__nonnull__(2);
45 PARROT_CAN_RETURN_NULL
46 static PMC * make_local_copy(PARROT_INTERP,
47 ARGIN(Parrot_Interp from),
48 ARGIN(PMC *arg))
49 __attribute__nonnull__(1)
50 __attribute__nonnull__(2)
51 __attribute__nonnull__(3);
53 static void mutex_unlock(ARGMOD(void *arg))
54 __attribute__nonnull__(1)
55 FUNC_MODIFIES(*arg);
57 static Parrot_Interp pt_check_tid(UINTVAL tid, ARGIN(const char *from))
58 __attribute__nonnull__(2);
60 static int pt_gc_count_threads(PARROT_INTERP)
61 __attribute__nonnull__(1);
63 static void pt_gc_wait_for_stage(PARROT_INTERP,
64 thread_gc_stage_enum from_stage,
65 thread_gc_stage_enum to_stage)
66 __attribute__nonnull__(1);
68 static void pt_gc_wakeup_check(PARROT_INTERP)
69 __attribute__nonnull__(1);
71 static void pt_ns_clone(
72 ARGOUT(Parrot_Interp d),
73 ARGOUT(PMC *dest_ns),
74 ARGIN(Parrot_Interp s),
75 ARGIN(PMC *source_ns))
76 __attribute__nonnull__(1)
77 __attribute__nonnull__(2)
78 __attribute__nonnull__(3)
79 __attribute__nonnull__(4)
80 FUNC_MODIFIES(d)
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(NOTNULL(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 QUEUE_ENTRY * remove_queued_suspend_gc(PARROT_INTERP)
98 __attribute__nonnull__(1);
100 PARROT_CAN_RETURN_NULL
101 static void* thread_func(ARGIN_NULLOK(void *arg));
103 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
104 /* HEADERIZER END: static */
106 #if defined THREAD_DEBUG && THREAD_DEBUG
107 # define DEBUG_ONLY(x) (x)
108 #else
109 # define DEBUG_ONLY(x)
110 #endif
112 static int running_threads;
114 void Parrot_really_destroy(PARROT_INTERP, int exit_code, void *arg);
118 =item C<static PMC * make_local_copy>
120 Creates a local copy of the PMC if necessary. (No copy is made if it is marked
121 shared.) This includes workarounds for Parrot_clone() not doing the Right Thing
122 with subroutines (specifically, code segments aren't preserved and it is
123 difficult to do so as long as Parrot_clone() depends on freezing).
125 =cut
129 PARROT_CAN_RETURN_NULL
130 static PMC *
131 make_local_copy(PARROT_INTERP, ARGIN(Parrot_Interp from), ARGIN(PMC *arg))
133 PMC *ret_val;
134 STRING * const _sub = interp->vtables[enum_class_Sub]->whoami;
135 STRING * const _multi_sub = interp->vtables[enum_class_MultiSub]->whoami;
137 if (PMC_IS_NULL(arg)) {
138 ret_val = PMCNULL;
140 else if (PObj_is_PMC_shared_TEST(arg)) {
141 ret_val = arg;
143 else if (VTABLE_isa(from, arg, _multi_sub)) {
144 INTVAL i = 0;
145 const INTVAL n = VTABLE_elements(from, arg);
146 ret_val = pmc_new(interp, enum_class_MultiSub);
148 for (i = 0; i < n; ++i) {
149 PMC *const orig = VTABLE_get_pmc_keyed_int(from, arg, i);
150 PMC *const copy = make_local_copy(interp, from, orig);
151 VTABLE_push_pmc(interp, ret_val, copy);
154 else if (VTABLE_isa(from, arg, _sub)) {
155 /* this is a workaround for cloning subroutines not actually
156 * working as one might expect mainly because the segment is
157 * not correctly copied
159 ret_val = Parrot_clone(interp, arg);
160 PMC_sub(ret_val)->seg = PMC_sub(arg)->seg;
161 /* Skip vtable overrides and methods. */
162 if (PMC_sub(ret_val)->vtable_index == -1
163 && !(PMC_sub(ret_val)->comp_flags & SUB_COMP_FLAG_METHOD)) {
164 Parrot_store_sub_in_namespace(interp, ret_val);
167 else {
168 ret_val = Parrot_clone(interp, arg);
170 return ret_val;
175 =item C<static Shared_gc_info * get_pool>
177 Gets the shared gc information. For now this is global data; ideally it will
178 become something other than a static variable. If everything uses this
179 function, it will be easier to change.
181 =cut
185 PARROT_CAN_RETURN_NULL
186 static Shared_gc_info *
187 get_pool(PARROT_INTERP)
189 return shared_gc_info;
194 =item C<void pt_free_pool>
196 Frees the shared GC information. This clears any global data when joining all
197 threads at parent interpreter destruction.
199 =cut
203 void
204 pt_free_pool(PARROT_INTERP)
206 if (shared_gc_info) {
207 COND_DESTROY(shared_gc_info->gc_cond);
208 PARROT_ATOMIC_INT_DESTROY(shared_gc_info->gc_block_level);
209 mem_sys_free(shared_gc_info);
210 shared_gc_info = NULL;
216 =item C<static PMC * make_local_args_copy>
218 Make a local copy of the corresponding array of arguments.
220 =cut
224 PARROT_CAN_RETURN_NULL
225 static PMC *
226 make_local_args_copy(PARROT_INTERP, ARGIN(Parrot_Interp old_interp), ARGIN_NULLOK(PMC *args))
228 PMC *ret_val;
229 INTVAL old_size;
230 INTVAL i;
232 if (PMC_IS_NULL(args))
233 return PMCNULL;
235 old_size = VTABLE_get_integer(old_interp, args);
237 /* XXX should this be a different type? */
238 ret_val = pmc_new(interp, enum_class_FixedPMCArray);
239 VTABLE_set_integer_native(interp, ret_val, old_size);
241 for (i = 0; i < old_size; ++i) {
242 PMC * const copy = make_local_copy(interp, old_interp,
243 VTABLE_get_pmc_keyed_int(old_interp, args, i));
245 VTABLE_set_pmc_keyed_int(interp, ret_val, i, copy);
248 return ret_val;
253 =item C<PMC * pt_shared_fixup>
255 Modifies a PMC to be sharable. Right now, reassigns the vtable to one
256 owned by some master interpreter, so the PMC can be safely reused
257 after thread death.
259 In the future the PMC returned might be different than the one
260 passed, e.g., if we need to reallocate the PMC in a different
261 interpreter.
263 =cut
267 PARROT_CAN_RETURN_NULL
268 PMC *
269 pt_shared_fixup(PARROT_INTERP, ARGMOD(PMC *pmc))
271 /* TODO this will need to change for thread pools
272 * XXX should we have a separate interpreter for this?
274 INTVAL type_num;
275 Parrot_Interp master = interpreter_array[0];
276 const int is_ro = pmc->vtable->flags & VTABLE_IS_READONLY_FLAG;
278 /* This lock is paired with one in objects.c. It is necessary to protect
279 * against the master interpreter adding classes and consequently
280 * resizing its classname->type_id hashtable and/or expanding its vtable
281 * array.
282 * TODO investigate if a read-write lock results in substantially
283 * better performance.
285 LOCK_INTERPRETER(master);
286 type_num = pmc->vtable->base_type;
288 if (type_num == enum_type_undef) {
289 UNLOCK_INTERPRETER(master);
290 real_exception(interp, NULL, 1, "pt_shared_fixup: unsharable type");
293 pmc->vtable = master->vtables[type_num];
295 UNLOCK_INTERPRETER(master);
297 if (is_ro)
298 pmc->vtable = pmc->vtable->ro_variant_vtable;
300 add_pmc_sync(interp, pmc);
302 PObj_is_PMC_shared_SET(pmc);
304 /* make sure metadata doesn't go away unexpectedly */
305 if (PMC_metadata(pmc))
306 PMC_metadata(pmc) = pt_shared_fixup(interp, PMC_metadata(pmc));
308 return pmc;
313 =item C<static void pt_thread_signal>
315 Wakes up an C<interp> which should have called pt_thread_wait().
317 =cut
321 static void
322 pt_thread_signal(NOTNULL(Parrot_Interp self), PARROT_INTERP)
324 COND_SIGNAL(interp->thread_data->interp_cond);
329 =item C<void pt_thread_wait_with>
331 Waits for this interpreter to be signalled through its condition variable,
332 dealing properly with GC issues. C<*mutex> is assumed locked on entry and
333 will be locked on exit from this function. If a GC run occurs in the middle of
334 this function, then a spurious wakeup may occur.
336 =cut
340 void
341 pt_thread_wait_with(PARROT_INTERP, ARGMOD(Parrot_mutex *mutex))
343 LOCK(interpreter_array_mutex);
344 if (interp->thread_data->state & THREAD_STATE_SUSPEND_GC_REQUESTED) {
345 interp->thread_data->state |= THREAD_STATE_SUSPENDED_GC;
346 UNLOCK(interpreter_array_mutex);
347 UNLOCK(*mutex);
349 pt_suspend_self_for_gc(interp);
351 LOCK(*mutex);
352 /* since we unlocked the mutex something bad may have occured */
353 return;
356 interp->thread_data->state |= THREAD_STATE_GC_WAKEUP;
358 UNLOCK(interpreter_array_mutex);
359 COND_WAIT(interp->thread_data->interp_cond, *mutex);
360 LOCK(interpreter_array_mutex);
362 interp->thread_data->state &= ~THREAD_STATE_GC_WAKEUP;
364 if (interp->thread_data->state & THREAD_STATE_SUSPENDED_GC) {
365 UNLOCK(*mutex);
366 /* XXX loop needed? */
367 do {
368 UNLOCK(interpreter_array_mutex);
369 /* fprintf(stderr, "%p: woken up, doing GC run\n", interp); */
370 pt_suspend_self_for_gc(interp);
371 LOCK(interpreter_array_mutex);
372 } while (interp->thread_data->state & THREAD_STATE_SUSPENDED_GC);
374 UNLOCK(interpreter_array_mutex);
375 LOCK(*mutex);
377 else {
378 UNLOCK(interpreter_array_mutex);
384 =item C<static void pt_thread_wait>
386 Waits for a signal, handling GC matters correctly. C<interpreter_array_mutex>
387 is assumed held. Spurious wakeups may occur.
389 =cut
393 static void
394 pt_thread_wait(PARROT_INTERP)
396 if (interp->thread_data->state & THREAD_STATE_SUSPEND_GC_REQUESTED) {
397 interp->thread_data->state |= THREAD_STATE_SUSPENDED_GC;
398 /* fprintf(stderr, "%p: pt_thread_wait, before sleep, doing GC run\n",
399 * interp); */
401 UNLOCK(interpreter_array_mutex);
402 pt_suspend_self_for_gc(interp);
403 LOCK(interpreter_array_mutex);
405 /* while we were GCing, whatever we were waiting on might have
406 * changed */
407 return;
410 interp->thread_data->state |= THREAD_STATE_GC_WAKEUP;
412 COND_WAIT(interp->thread_data->interp_cond, interpreter_array_mutex);
414 interp->thread_data->state &= ~THREAD_STATE_GC_WAKEUP;
416 while (interp->thread_data->state & THREAD_STATE_SUSPENDED_GC) {
417 UNLOCK(interpreter_array_mutex);
418 /* fprintf(stderr, "%p: woken up, doing GC run\n", interp); */
419 pt_suspend_self_for_gc(interp);
420 LOCK(interpreter_array_mutex);
427 =item C<static void* thread_func>
429 The actual thread function.
431 =cut
435 PARROT_CAN_RETURN_NULL
436 static void*
437 thread_func(ARGIN_NULLOK(void *arg))
439 Parrot_exception exp;
440 int lo_var_ptr;
441 UINTVAL tid;
442 PMC *sub;
443 PMC *sub_arg;
444 PMC * const self = (PMC*) arg;
445 PMC *ret_val = NULL;
446 Parrot_Interp interp = (Parrot_Interp)PMC_data(self);
448 Parrot_block_GC_mark(interp);
449 Parrot_block_GC_sweep(interp);
451 /* need to set it here because argument passing can trigger GC */
452 interp->lo_var_ptr = &lo_var_ptr;
453 sub = (PMC *)PMC_struct_val(self);
454 sub_arg = PMC_pmc_val(self);
456 if (setjmp(exp.destination)) {
457 const Parrot_exception * const except = interp->exceptions;
458 /* caught exception */
459 /* XXX what should we really do here */
460 PIO_eprintf(interp,
461 "Unhandled exception in thread with tid %d "
462 "(message=%Ss, number=%d)\n",
463 interp->thread_data->tid,
464 except->msg,
465 except->error);
467 ret_val = PMCNULL;
469 else {
470 /* run normally */
471 push_new_c_exception_handler(interp, &exp);
472 Parrot_unblock_GC_mark(interp);
473 Parrot_unblock_GC_sweep(interp);
474 ret_val = Parrot_runops_fromc_args(interp, sub, "PF", sub_arg);
477 /* thread is finito */
478 LOCK(interpreter_array_mutex);
479 DEBUG_ONLY(fprintf(stderr, "marking an thread as finished\n"));
481 interp->thread_data->state |= THREAD_STATE_FINISHED;
482 tid = interp->thread_data->tid;
484 if (interp != interpreter_array[tid]) {
485 UNLOCK(interpreter_array_mutex);
486 PANIC(interp, "thread finished: interpreter mismatch");
488 if (interp->thread_data->state & THREAD_STATE_DETACHED) {
489 interpreter_array[tid] = NULL;
490 DEBUG_ONLY(fprintf(stderr,
491 "really destroying an interpreter [exit while detached]\n"));
492 Parrot_really_destroy(interp, 0, NULL);
494 else if (interp->thread_data->state & THREAD_STATE_JOINED) {
495 pt_thread_signal(interp, interp->thread_data->joiner);
498 /* make sure we don't block a GC run */
499 pt_gc_wakeup_check(interp);
500 PARROT_ASSERT(interp->thread_data->state & THREAD_STATE_FINISHED);
502 UNLOCK(interpreter_array_mutex);
504 return ret_val;
509 =back
511 =head2 Helper functions used also for running plain interpreters
513 =over 4
515 =item C<void pt_clone_code>
517 Copies/clones the packfile/code from interpreter C<s> to C<d>. All
518 resources are created in C<d>.
520 =cut
524 void
525 pt_clone_code(Parrot_Interp d, Parrot_Interp s)
527 Parrot_block_GC_mark(d);
528 Interp_flags_SET(d, PARROT_EXTERN_CODE_FLAG);
529 d->code = NULL;
530 Parrot_switch_to_cs(d, s->code, 1);
531 Parrot_unblock_GC_mark(d);
536 =item C<static void pt_ns_clone>
538 Clones all globals from C<s> to C<d>.
540 =cut
544 static void
545 pt_ns_clone(ARGOUT(Parrot_Interp d), ARGOUT(PMC *dest_ns),
546 ARGIN(Parrot_Interp s), ARGIN(PMC *source_ns))
548 PMC * const iter = VTABLE_get_iter(s, source_ns);
549 const INTVAL n = VTABLE_elements(s, source_ns);
550 INTVAL i;
552 for (i = 0; i < n; ++i) {
553 /* XXX what if 'key' is a non-constant-pool string? */
554 STRING * const key = VTABLE_shift_string(s, iter);
555 PMC * const val = VTABLE_get_pmc_keyed_str(s, source_ns, key);
557 if (val->vtable->base_type == enum_class_NameSpace) {
558 PMC *sub_ns = VTABLE_get_pmc_keyed_str(d, dest_ns, key);
559 if (PMC_IS_NULL(sub_ns) || sub_ns->vtable->base_type !=
560 enum_class_NameSpace) {
561 sub_ns = pmc_new(d, enum_class_NameSpace);
562 VTABLE_set_pmc_keyed_str(d, dest_ns, key, sub_ns);
564 pt_ns_clone(d, sub_ns, s, val);
566 else {
567 PMC * const dval = VTABLE_get_pmc_keyed_str(d, dest_ns, key);
569 if (PMC_IS_NULL(dval)) {
570 PMC * const copy = make_local_copy(d, s, val);
572 /* Vtable overrides and methods were already cloned, so don't reclone them. */
573 if (!(val->vtable->base_type == enum_class_Sub
574 && (PMC_sub(val)->vtable_index != -1
575 || PMC_sub(val)->comp_flags & SUB_COMP_FLAG_METHOD))) {
576 VTABLE_set_pmc_keyed_str(d, dest_ns, key, copy);
585 =item C<void pt_clone_globals>
587 Copies the global namespace when cloning a new interpreter.
589 =cut
593 void
594 pt_clone_globals(Parrot_Interp d, Parrot_Interp s)
596 Parrot_block_GC_mark(d);
597 pt_ns_clone(d, d->root_namespace, s, s->root_namespace);
598 Parrot_unblock_GC_mark(d);
603 =item C<void pt_thread_prepare_for_run>
605 Sets up a new thread to run.
607 =cut
611 void
612 pt_thread_prepare_for_run(Parrot_Interp d, Parrot_Interp s)
614 Parrot_setup_event_func_ptrs(d);
619 =back
621 =head2 ParrotThread methods
623 =over 4
625 =cut
631 =item C<PMC * pt_transfer_sub>
633 Clones the sub so that it's suitable for the other interpreter.
635 =cut
639 PARROT_CAN_RETURN_NULL
640 PMC *
641 pt_transfer_sub(ARGOUT(Parrot_Interp d), ARGIN(Parrot_Interp s), ARGIN(PMC *sub))
643 #if defined THREAD_DEBUG && THREAD_DEBUG
644 PIO_eprintf(s, "copying over subroutine [%Ss]\n",
645 Parrot_full_sub_name(s, sub));
646 #endif
647 return make_local_copy(d, s, sub);
652 =item C<int pt_thread_run>
654 Runs the C<*sub> PMC in a separate thread using the interpreter in
655 C<*dest_interp>.
657 C<arg> should be an array of arguments for the subroutine.
659 =cut
664 pt_thread_run(PARROT_INTERP, ARGOUT(PMC *dest_interp), ARGIN(PMC *sub), ARGIN_NULLOK(PMC *arg))
666 PMC *old_dest_interp;
667 PMC *parent;
668 Interp * const interpreter = (Parrot_Interp)PMC_data(dest_interp);
670 Parrot_block_GC_sweep(interpreter);
671 Parrot_block_GC_mark(interpreter);
672 Parrot_block_GC_sweep(interp);
673 Parrot_block_GC_mark(interp);
675 /* make a copy of the ParrotThread PMC so we can use it
676 * to hold parameters to the new thread without it being
677 * garbage collected or otherwise changed by the parent thread.
678 * Also so the new thread's getinterp doesn't return an object
679 * owned by the wrong interpreter -- which would be very bad
680 * if the parent is destroyed before the child.
681 * XXX FIXME move this elsewhere? at least the set_pmc_keyed_int
683 old_dest_interp = dest_interp;
684 dest_interp = pmc_new_noinit(interpreter, enum_class_ParrotThread);
686 /* so it's not accidentally deleted */
687 PMC_data(old_dest_interp) = NULL;
688 PMC_data(dest_interp) = interpreter;
690 VTABLE_set_pmc_keyed_int(interpreter, interpreter->iglobals,
691 (INTVAL) IGLOBALS_INTERPRETER, dest_interp);
693 parent = VTABLE_get_pmc_keyed_int(interp, interp->iglobals,
694 IGLOBALS_INTERPRETER);
697 * TODO check if thread flags are consistent
699 if (interp->flags & PARROT_THR_COPY_INTERP)
700 clone_interpreter(interpreter, (Parrot_Interp)PMC_data(parent), PARROT_CLONE_DEFAULT);
702 * TODO thread pools
705 pt_thread_prepare_for_run(interpreter, interp);
707 PMC_struct_val(dest_interp) = pt_transfer_sub(interpreter, interp, sub);
708 PMC_pmc_val(dest_interp) = make_local_args_copy(interpreter, interp, arg);
711 * set regs according to pdd03
713 interpreter->current_object = dest_interp;
715 * create a joinable thread
717 interpreter->thread_data->state = THREAD_STATE_JOINABLE;
719 Parrot_unblock_GC_mark(interpreter);
720 Parrot_unblock_GC_sweep(interpreter);
721 Parrot_unblock_GC_mark(interp);
722 Parrot_unblock_GC_sweep(interp);
724 THREAD_CREATE_JOINABLE(interpreter->thread_data->thread,
725 thread_func, dest_interp);
727 /* check for pending GC */
728 LOCK(interpreter_array_mutex);
729 if (interp->thread_data->state & THREAD_STATE_SUSPEND_GC_REQUESTED)
730 pt_suspend_one_for_gc(interpreter);
732 UNLOCK(interpreter_array_mutex);
733 return 0;
738 =item C<int pt_thread_run_1>
740 Runs a thread that shares nothing and does not communicate with the other
741 interpreter.
743 =cut
748 pt_thread_run_1(PARROT_INTERP, ARGOUT(PMC* dest_interp), ARGIN(PMC* sub), ARGIN(PMC *arg))
750 interp->flags |= PARROT_THR_TYPE_1;
751 return pt_thread_run(interp, dest_interp, sub, arg);
756 =item C<int pt_thread_run_2>
758 Runs an interpreter in a thread with no shared variables, but which
759 communicates by sending messages.
761 =cut
766 pt_thread_run_2(PARROT_INTERP, ARGOUT(PMC* dest_interp), ARGIN(PMC* sub), ARGIN(PMC *arg))
768 interp->flags |= PARROT_THR_TYPE_2;
769 return pt_thread_run(interp, dest_interp, sub, arg);
774 =item C<int pt_thread_run_3>
776 Runs an interpreter in a thread, allowing shared variables and using a thread
777 pool.
779 =cut
784 pt_thread_run_3(PARROT_INTERP, ARGOUT(PMC* dest_interp), ARGIN(PMC* sub), ARGIN(PMC *arg))
786 interp->flags |= PARROT_THR_TYPE_3;
787 return pt_thread_run(interp, dest_interp, sub, arg);
792 =item C<void pt_thread_yield>
794 Relinquishes hold on the processor.
796 =cut
800 void
801 pt_thread_yield(void)
803 YIELD;
808 =item C<static Parrot_Interp pt_check_tid>
810 Helper function. Checks if the given thread ID is valid. The caller holds the
811 mutex. Returns the interpreter for C<tid>.
813 =cut
817 static Parrot_Interp
818 pt_check_tid(UINTVAL tid, ARGIN(const char *from))
820 if (tid >= n_interpreters) {
821 UNLOCK(interpreter_array_mutex);
822 internal_exception(1, "%s: illegal thread tid %d", from, tid);
824 if (tid == 0) {
825 UNLOCK(interpreter_array_mutex);
826 internal_exception(1, "%s: illegal thread tid %d (main)", from, tid);
828 if (!interpreter_array[tid]) {
829 UNLOCK(interpreter_array_mutex);
830 internal_exception(1, "%s: illegal thread tid %d - empty", from, tid);
832 return interpreter_array[tid];
837 =item C<static void mutex_unlock>
839 Unlocks the mutex C<*arg>.
841 =cut
845 static void
846 mutex_unlock(ARGMOD(void *arg))
848 UNLOCK(*(Parrot_mutex *) arg);
853 =item C<static int is_suspended_for_gc>
855 Returns true iff C<interp> is suspended for a global GC run. Be sure to hold
856 C<interpreter_array_mutex>.
858 =cut
862 PARROT_WARN_UNUSED_RESULT
863 static int
864 is_suspended_for_gc(PARROT_INTERP)
866 if (!interp)
867 return 1;
868 else if (interp->thread_data->wants_shared_gc)
869 return 1;
870 else if (interp->thread_data->state & THREAD_STATE_SUSPENDED_GC)
871 return 1;
872 else if ((interp->thread_data->state & THREAD_STATE_FINISHED) ||
873 (interp->thread_data->state & THREAD_STATE_NOT_STARTED))
874 return 1;
875 else
876 return 0;
881 =item C<static QUEUE_ENTRY * remove_queued_suspend_gc>
883 Removes an event requesting that the interpreter suspend itself for a
884 garbage-collection run from the event queue.
886 =cut
890 PARROT_CAN_RETURN_NULL
891 static QUEUE_ENTRY *
892 remove_queued_suspend_gc(PARROT_INTERP)
894 parrot_event *ev = NULL;
895 QUEUE *queue = interp->task_queue;
896 QUEUE_ENTRY *prev = NULL;
897 QUEUE_ENTRY *cur;
899 queue_lock(queue);
900 cur = queue->head;
902 while (cur) {
903 ev = (parrot_event *)cur->data;
905 if (ev->type == EVENT_TYPE_SUSPEND_FOR_GC)
906 break;
908 prev = cur;
909 cur = cur->next;
912 if (cur) {
913 if (prev)
914 prev->next = cur->next;
915 else
916 queue->head = cur->next;
918 if (cur == queue->tail)
919 queue->tail = prev;
921 if (cur == queue->head)
922 queue->head = cur->next;
924 mem_sys_free(ev);
925 mem_sys_free(cur);
926 cur = NULL;
927 DEBUG_ONLY(fprintf(stderr, "%p: remove_queued_suspend_gc: got one\n", interp));
930 queue_unlock(queue);
931 return cur;
936 =item C<static int pt_gc_count_threads>
938 Returns the number of active threads in the system (running or suspended). Be
939 sure to hold C<interpreter_array_mutex>.
941 =cut
945 static int
946 pt_gc_count_threads(PARROT_INTERP)
948 UINTVAL i;
949 int count = 0;
951 for (i = 0; i < n_interpreters; ++i) {
952 Parrot_Interp cur;
953 cur = interpreter_array[i];
954 if (!cur)
955 continue;
956 if (cur->thread_data->state & (THREAD_STATE_NOT_STARTED |
957 THREAD_STATE_FINISHED))
958 continue;
959 ++count;
961 DEBUG_ONLY(fprintf(stderr, "found %d threads\n", count));
962 return count;
967 =item C<static void pt_gc_wait_for_stage>
969 Waits until all threads have reached the desired stage. Takes an interpreter,
970 starting stage and ending stage as arguments. Updates the thread information.
971 Used in C<pt_DOD_start_mark> and C<pt_DOD_stop_mark>.
973 =cut
977 static void
978 pt_gc_wait_for_stage(PARROT_INTERP, thread_gc_stage_enum from_stage,
979 thread_gc_stage_enum to_stage)
981 Shared_gc_info * const info = shared_gc_info;
982 int thread_count;
984 DEBUG_ONLY(fprintf(stderr, "%p: gc_wait_for_stage: %d->%d\n", interp, from_stage, to_stage));
986 /* XXX well-timed thread death can mess this up */
987 LOCK(interpreter_array_mutex);
989 DEBUG_ONLY(fprintf(stderr, "%p: got lock\n", interp));
990 thread_count = pt_gc_count_threads(interp);
992 PARROT_ASSERT(info->gc_stage == from_stage);
993 PARROT_ASSERT(!(interp->thread_data->state & THREAD_STATE_NOT_STARTED));
994 PARROT_ASSERT(!(interp->thread_data->state & THREAD_STATE_FINISHED));
996 if (from_stage == 0)
997 PARROT_ASSERT(interp->thread_data->state & THREAD_STATE_SUSPENDED_GC);
998 else
999 PARROT_ASSERT(!(interp->thread_data->state & THREAD_STATE_SUSPENDED_GC));
1001 ++info->num_reached;
1003 DEBUG_ONLY(fprintf(stderr, "%p: gc_wait_for_stage: got %d\n", interp, info->num_reached));
1005 if (info->num_reached == thread_count) {
1006 info->gc_stage = to_stage;
1007 info->num_reached = 0;
1008 COND_BROADCAST(info->gc_cond);
1010 else {
1011 do {
1012 COND_WAIT(info->gc_cond, interpreter_array_mutex);
1013 } while (info->gc_stage != to_stage);
1015 UNLOCK(interpreter_array_mutex);
1021 =item C<static void pt_gc_wakeup_check>
1023 Checks if it's necessary to wake threads to perform garbage collection. This
1024 is called after thread death. Be sure to hold C<interpreter_array_mutex>.
1026 =cut
1030 static void
1031 pt_gc_wakeup_check(PARROT_INTERP)
1033 Shared_gc_info * const info = shared_gc_info;
1034 int thread_count;
1036 /* XXX: maybe a little hack; see RT #49532 */
1037 if (!info)
1038 return;
1040 thread_count = pt_gc_count_threads(interp);
1042 if (info->num_reached == thread_count) {
1043 PARROT_ASSERT(info->gc_stage == THREAD_GC_STAGE_NONE);
1044 info->gc_stage = THREAD_GC_STAGE_MARK;
1045 info->num_reached = 0;
1046 COND_BROADCAST(info->gc_cond);
1052 =item C<static void pt_suspend_one_for_gc>
1054 Suspends a single interpreter for GC. Be sure to hold
1055 C<interpreter_array_mutex>.
1057 =cut
1061 static void
1062 pt_suspend_one_for_gc(PARROT_INTERP)
1064 DEBUG_ONLY(fprintf(stderr, "suspend one: %p\n", interp));
1065 if (is_suspended_for_gc(interp)) {
1066 DEBUG_ONLY(fprintf(stderr, "ignoring already suspended\n"));
1067 return;
1070 if (interp->thread_data->state & THREAD_STATE_GC_WAKEUP) {
1071 DEBUG_ONLY(fprintf(stderr, "just waking it up\n"));
1072 interp->thread_data->state |= THREAD_STATE_SUSPENDED_GC;
1073 COND_SIGNAL(interp->thread_data->interp_cond);
1075 else {
1076 DEBUG_ONLY(fprintf(stderr, "queuing event\n"));
1077 interp->thread_data->state |= THREAD_STATE_SUSPEND_GC_REQUESTED;
1078 Parrot_cx_request_suspend_for_gc(interp);
1084 =item C<static void pt_suspend_all_for_gc>
1086 Notifies all threads to perform a GC run.
1088 =cut
1092 static void
1093 pt_suspend_all_for_gc(PARROT_INTERP)
1095 UINTVAL i;
1097 DEBUG_ONLY(fprintf(stderr, "suspend_all_for_gc [interp=%p]\n", interp));
1099 LOCK(interpreter_array_mutex);
1100 interp->thread_data->state |= THREAD_STATE_SUSPENDED_GC;
1102 if (interp->thread_data->state & THREAD_STATE_SUSPEND_GC_REQUESTED) {
1103 DEBUG_ONLY(fprintf(stderr, "found while suspending all\n"));
1104 Parrot_cx_delete_suspend_for_gc(interp);
1105 interp->thread_data->state &= ~THREAD_STATE_SUSPEND_GC_REQUESTED;
1106 UNLOCK(interpreter_array_mutex);
1107 return;
1110 #if 0
1111 for (i = 0; i < n_interpreters; ++i) {
1112 Parrot_Interp other_interp;
1113 other_interp = interpreter_array[i];
1114 if (!other_interp)
1115 continue;
1117 if (is_suspended_for_gc(other_interp) &&
1118 other_interp != interp &&
1119 (other_interp->thread_data->state & THREAD_STATE_SUSPENDED_GC))
1121 PMC *successp;
1122 /* this means that someone else already got this far,
1123 * so we have a suspend event in our queue to ignore
1125 /* XXX still reachable? */
1126 DEBUG_ONLY(fprintf(stderr, "apparently someone else is doing it [%p]\n", other_interp));
1127 fprintf(stderr, "??? found later (%p)\n", other_interp);
1128 successp = Parrot_cx_delete_suspend_for_gc(interp);
1129 PARROT_ASSERT(successp);
1130 UNLOCK(interpreter_array_mutex);
1131 return;
1134 #endif
1136 /* now send all the non-suspended threads to suspend for GC */
1137 for (i = 0; i < n_interpreters; ++i) {
1138 Parrot_Interp other_interp = interpreter_array[i];
1140 if (interp == other_interp)
1141 continue;
1143 if (is_suspended_for_gc(other_interp))
1144 continue;
1146 pt_suspend_one_for_gc(other_interp);
1148 UNLOCK(interpreter_array_mutex);
1153 =item C<void pt_suspend_self_for_gc>
1155 Suspends this thread for a full GC run.
1157 XXX FIXME -- if GC is blocked, we need to do a GC run as soon
1158 as it becomes unblocked.
1160 =cut
1164 void
1165 pt_suspend_self_for_gc(PARROT_INTERP)
1167 PARROT_ASSERT(interp);
1168 PARROT_ASSERT(!interp->arena_base->DOD_block_level);
1169 DEBUG_ONLY(fprintf(stderr, "%p: suspend_self_for_gc\n", interp));
1170 /* since we are modifying our own state, we need to lock
1171 * the interpreter_array_mutex.
1173 LOCK(interpreter_array_mutex);
1174 DEBUG_ONLY(fprintf(stderr, "%p: got lock\n", interp));
1176 PARROT_ASSERT(interp->thread_data->state &
1177 (THREAD_STATE_SUSPEND_GC_REQUESTED | THREAD_STATE_SUSPENDED_GC));
1179 if (interp->thread_data->state & THREAD_STATE_SUSPEND_GC_REQUESTED) {
1180 DEBUG_ONLY(fprintf(stderr, "remove queued request\n"));
1181 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp)));
1182 DEBUG_ONLY(fprintf(stderr, "removed all queued requests\n"));
1183 interp->thread_data->state &= ~THREAD_STATE_SUSPEND_GC_REQUESTED;
1185 if (!(interp->thread_data->state & THREAD_STATE_SUSPENDED_GC)) {
1186 interp->thread_data->state |= THREAD_STATE_SUSPENDED_GC;
1188 else {
1189 DEBUG_ONLY(fprintf(stderr, "no need to set suspended\n"));
1191 UNLOCK(interpreter_array_mutex);
1193 /* mark and sweep our world -- later callbacks will keep
1194 * it sync'd
1196 Parrot_dod_ms_run(interp, GC_trace_stack_FLAG);
1198 PARROT_ASSERT(!(interp->thread_data->state & THREAD_STATE_SUSPENDED_GC));
1203 =item C<PMC* pt_thread_join>
1205 Joins (by waiting for) a joinable thread.
1207 =cut
1211 PARROT_CAN_RETURN_NULL
1212 PMC*
1213 pt_thread_join(NOTNULL(Parrot_Interp parent), UINTVAL tid)
1215 int state;
1216 Parrot_Interp interp;
1218 LOCK(interpreter_array_mutex);
1220 interp = pt_check_tid(tid, "join");
1222 if (interp == parent)
1223 do_panic(parent, "Can't join self", __FILE__, __LINE__);
1225 if ((!(interp->thread_data->state & (THREAD_STATE_DETACHED
1226 | THREAD_STATE_JOINED)) &&
1227 !(interp->thread_data->state & THREAD_STATE_NOT_STARTED)) ||
1228 interp->thread_data->state == THREAD_STATE_FINISHED) {
1229 void *raw_retval = NULL;
1230 PMC *retval;
1232 interp->thread_data->state |= THREAD_STATE_JOINED;
1234 while (!(interp->thread_data->state & THREAD_STATE_FINISHED)) {
1235 interp->thread_data->joiner = parent;
1236 pt_thread_wait(parent);
1239 UNLOCK(interpreter_array_mutex);
1240 JOIN(interp->thread_data->thread, raw_retval);
1242 retval = (PMC *)raw_retval;
1244 * we need to push a cleanup handler here: if cloning
1245 * of the retval fails (e.g. it's a NULLPMC) this lock
1246 * isn't released until eternity or someone hits ^C
1248 * TODO This is needed for all places holding a lock for
1249 * non-trivial tasks
1250 * -leo
1251 * TODO remove that and replace it with proper exception
1252 * handling, so that a failing clone in the parent
1253 * just stops that thread
1254 * -leo
1256 LOCK(interpreter_array_mutex);
1257 CLEANUP_PUSH(mutex_unlock, &interpreter_array_mutex);
1259 if (retval) {
1260 PMC *parent_ret;
1262 * clone the PMC into caller, if its not a shared PMC
1263 * the PMC is not in the parents root set nor in the
1264 * stack so block DOD during clone
1265 * XXX should probably acquire the parent's interpreter mutex
1267 Parrot_block_GC_mark(parent);
1268 parent_ret = make_local_copy(parent, interp, retval);
1270 /* this PMC is living only in the stack of this currently
1271 * dying interpreter, so register it in parent's DOD registry
1272 * XXX is this still needed?
1274 dod_register_pmc(parent, parent_ret);
1275 Parrot_unblock_GC_mark(parent);
1276 retval = parent_ret;
1278 else {
1279 retval = PMCNULL;
1281 interpreter_array[tid] = NULL;
1282 running_threads--;
1284 DEBUG_ONLY(fprintf(stderr, "destroying an interpreter [join]\n"));
1285 if (Interp_debug_TEST(parent, PARROT_THREAD_DEBUG_FLAG))
1286 fprintf(stderr, "running threads %d\n", running_threads);
1288 /* reparent it so memory pool merging works */
1289 interp->parent_interpreter = parent;
1290 Parrot_really_destroy(interp, 0, NULL);
1292 CLEANUP_POP(1);
1294 * interpreter destruction is done - unregister the return
1295 * value, caller gets it now
1297 if (retval)
1298 dod_unregister_pmc(parent, retval);
1300 return retval;
1303 * when here thread was in wrong state
1305 state = interp->thread_data->state;
1306 UNLOCK(interpreter_array_mutex);
1307 real_exception(interp, NULL, 1, "join: illegal thread state %d tid %d",
1308 state, tid);
1313 =item C<void pt_join_threads>
1315 Possibly waits for other running threads. This is called when destroying
1316 C<interp>.
1318 =cut
1322 void
1323 pt_join_threads(PARROT_INTERP)
1325 size_t i;
1326 pt_free_pool(interp);
1328 /* if no threads were started - fine */
1329 LOCK(interpreter_array_mutex);
1330 if (n_interpreters <= 1) {
1331 n_interpreters = 0;
1332 UNLOCK(interpreter_array_mutex);
1333 return;
1336 /* only the first interpreter waits for other threads */
1337 if (interp != interpreter_array[0]) {
1338 UNLOCK(interpreter_array_mutex);
1339 return;
1342 for (i = 1; i < n_interpreters; ++i) {
1343 Parrot_Interp thread_interp = interpreter_array[i];
1344 if (thread_interp == NULL)
1345 continue;
1346 if (thread_interp->thread_data->state == THREAD_STATE_JOINABLE ||
1347 (thread_interp->thread_data->state & THREAD_STATE_FINISHED)) {
1349 void *retval = NULL;
1350 thread_interp->thread_data->state |= THREAD_STATE_JOINED;
1351 UNLOCK(interpreter_array_mutex);
1352 JOIN(thread_interp->thread_data->thread, retval);
1353 LOCK(interpreter_array_mutex);
1356 UNLOCK(interpreter_array_mutex);
1357 return;
1362 =item C<static Parrot_Interp detach>
1364 Helper for detach and kill.
1366 Returns the interpreter, if it didn't finish yet.
1368 =cut
1372 static Parrot_Interp
1373 detach(UINTVAL tid)
1375 Parrot_Interp interp;
1377 LOCK(interpreter_array_mutex);
1378 interp = pt_check_tid(tid, "detach");
1380 * if interpreter is joinable, we detach em
1382 if (interp->thread_data->state == THREAD_STATE_JOINABLE ||
1383 interp->thread_data->state == THREAD_STATE_FINISHED) {
1384 DETACH(interp->thread_data->thread);
1385 interp->thread_data->state |= THREAD_STATE_DETACHED;
1387 if (interp->thread_data->state & THREAD_STATE_FINISHED) {
1388 interpreter_array[tid] = NULL;
1389 DEBUG_ONLY(fprintf(stderr, "destroying an interpreter [detach]\n"));
1390 Parrot_really_destroy(interp, 0, NULL);
1391 interp = NULL;
1394 UNLOCK(interpreter_array_mutex);
1395 return interp;
1400 =item C<void pt_thread_detach>
1402 Detaches the thread, making it non-joinable.
1404 =cut
1408 void
1409 pt_thread_detach(UINTVAL tid)
1411 (void) detach(tid);
1416 =item C<void pt_thread_kill>
1418 Kills the thread.
1420 =cut
1424 void
1425 pt_thread_kill(UINTVAL tid)
1427 PARROT_INTERP = detach(tid);
1429 /* schedule a terminate event for that interpreter */
1430 if (interp)
1431 Parrot_cx_runloop_end(interp);
1436 =back
1438 =head2 Threaded interpreter book-keeping
1440 =over 4
1442 =item C<void pt_add_to_interpreters>
1444 Stores the given interpreter in the array of all interpreters. Be sure to hold
1445 C<interpreter_array_mutex>.
1447 =cut
1451 void
1452 pt_add_to_interpreters(PARROT_INTERP, ARGIN_NULLOK(Parrot_Interp new_interp))
1454 size_t i;
1455 DEBUG_ONLY(fprintf(stderr, "interp = %p\n", interp));
1457 if (!new_interp) {
1459 * Create an entry for the very first interpreter, event
1460 * handling needs it
1462 PARROT_ASSERT(!interpreter_array);
1463 PARROT_ASSERT(n_interpreters == 0);
1465 interpreter_array = mem_allocate_typed(Interp *);
1466 interpreter_array[0] = interp;
1467 n_interpreters = 1;
1469 shared_gc_info = (Shared_gc_info *)mem_sys_allocate_zeroed(sizeof (*shared_gc_info));
1470 COND_INIT(shared_gc_info->gc_cond);
1471 PARROT_ATOMIC_INT_INIT(shared_gc_info->gc_block_level);
1472 PARROT_ATOMIC_INT_SET(shared_gc_info->gc_block_level, 0);
1474 /* XXX try to defer this until later */
1475 PARROT_ASSERT(interp == interpreter_array[0]);
1476 interp->thread_data = mem_allocate_zeroed_typed(Thread_data);
1477 INTERPRETER_LOCK_INIT(interp);
1478 interp->thread_data->tid = 0;
1480 return;
1484 new_interp->thread_data = mem_allocate_zeroed_typed(Thread_data);
1485 INTERPRETER_LOCK_INIT(new_interp);
1486 running_threads++;
1487 if (Interp_debug_TEST(interp, PARROT_THREAD_DEBUG_FLAG))
1488 fprintf(stderr, "running threads %d\n", running_threads);
1490 /* look for an empty slot */
1491 for (i = 0; i < n_interpreters; ++i) {
1492 if (interpreter_array[i] == NULL) {
1493 interpreter_array[i] = new_interp;
1494 new_interp->thread_data->tid = i;
1495 new_interp->thread_data->state = THREAD_STATE_NOT_STARTED;
1496 return;
1500 /* need to resize */
1501 interpreter_array = (Interp **)mem_sys_realloc(interpreter_array,
1502 (n_interpreters + 1) * sizeof (Interp *));
1504 interpreter_array[n_interpreters] = new_interp;
1505 new_interp->thread_data->tid = n_interpreters;
1506 new_interp->thread_data->state = THREAD_STATE_NOT_STARTED;
1508 ++n_interpreters;
1513 =back
1515 =head2 DOD Synchronization Functions
1517 =over 4
1519 =item C<void pt_DOD_start_mark>
1521 Record that the mark phase of DOD is about to begin. In the presence of shared
1522 PMCs, we can only run one DOD run at a time because C<< PMC->next_for_GC >> may
1523 be changed.
1525 C<flags> are the DOD flags. We check if we need to collect shared objects or
1526 not.
1528 TODO - Have a count of shared PMCs and check it during DOD.
1530 TODO - Evaluate if a interpreter lock is cheaper when C<dod_mark_ptr> is
1531 updated.
1533 =cut
1537 void
1538 pt_DOD_start_mark(PARROT_INTERP)
1540 Shared_gc_info *info;
1541 int block_level;
1543 DEBUG_ONLY(fprintf(stderr, "%p: pt_DOD_start_mark\n", interp));
1544 /* if no other threads are running, we are safe */
1545 if (!running_threads)
1546 return;
1548 info = get_pool(interp);
1549 PARROT_ATOMIC_INT_GET(block_level, info->gc_block_level);
1551 DEBUG_ONLY(fprintf(stderr, "start threaded mark\n"));
1553 * TODO now check, if we are the owner of a shared memory pool
1554 * if yes:
1555 * - suspend all other threads by sending them a suspend event
1556 * (or put a LOCK around updating the mark pointers)
1557 * - return and continue the mark phase
1558 * - then s. comments below
1560 LOCK(interpreter_array_mutex);
1561 if (interp->thread_data->state & THREAD_STATE_SUSPENDED_GC) {
1562 PARROT_ASSERT(!(interp->thread_data->state &
1563 THREAD_STATE_SUSPEND_GC_REQUESTED));
1564 DEBUG_ONLY(fprintf(stderr, "already suspended...\n"));
1565 UNLOCK(interpreter_array_mutex);
1567 else if (block_level) {
1568 /* unthreaded collection */
1569 DEBUG_ONLY(fprintf(stderr, "... but blocked\n"));
1571 /* holding the lock */
1572 return;
1574 else if (interp->thread_data->state &
1575 THREAD_STATE_SUSPEND_GC_REQUESTED) {
1576 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp)));
1578 interp->thread_data->state &= ~THREAD_STATE_SUSPEND_GC_REQUESTED;
1579 interp->thread_data->state |= THREAD_STATE_SUSPENDED_GC;
1581 DEBUG_ONLY(fprintf(stderr, "%p: detected request\n", interp));
1582 UNLOCK(interpreter_array_mutex);
1584 else {
1585 /* we need to stop the world */
1586 DEBUG_ONLY(fprintf(stderr, "stop the world\n"));
1587 UNLOCK(interpreter_array_mutex);
1589 pt_suspend_all_for_gc(interp);
1592 DEBUG_ONLY(fprintf(stderr, "%p: wait for stage\n", interp));
1593 pt_gc_wait_for_stage(interp, THREAD_GC_STAGE_NONE, THREAD_GC_STAGE_MARK);
1595 DEBUG_ONLY(fprintf(stderr, "actually mark\n"));
1597 * we can't allow parallel running DODs both would mess with shared PMCs
1598 * next_for_GC pointers
1600 LOCK(interpreter_array_mutex);
1601 DEBUG_ONLY(fprintf(stderr, "got marking lock\n"));
1606 =item C<void pt_DOD_mark_root_finished>
1608 Records that DOD has finished for the root set. UNIMPLEMENTED
1610 =cut
1614 void
1615 pt_DOD_mark_root_finished(PARROT_INTERP)
1617 if (!running_threads)
1618 return;
1620 * TODO now check, if we are the owner of a shared memory pool
1621 * if yes:
1622 * - now run DOD_mark on all members of our pool
1623 * - if all shared PMCs are marked by all threads then
1624 * - we can continue to free unused objects
1630 =item C<void pt_DOD_stop_mark>
1632 Records that the mark phase of DOD has completed.
1634 =cut
1638 void
1639 pt_DOD_stop_mark(PARROT_INTERP)
1641 if (!running_threads)
1642 return;
1644 * normal operation can continue now
1645 * - other threads may or not free unused objects then,
1646 * depending on their resource statistics
1648 if (!(interp->thread_data->state & THREAD_STATE_SUSPENDED_GC)) {
1649 UNLOCK(interpreter_array_mutex);
1650 return;
1653 PARROT_ASSERT(!(interp->thread_data->state &
1654 THREAD_STATE_SUSPEND_GC_REQUESTED));
1655 interp->thread_data->state &= ~THREAD_STATE_SUSPENDED_GC;
1657 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp))) {
1658 /* XXX FIXME make this message never trigger */
1659 fprintf(stderr, "%p: extraneous suspend_gc event\n", (void *)interp);
1662 DEBUG_ONLY(fprintf(stderr, "%p: unlock\n", interp));
1663 UNLOCK(interpreter_array_mutex);
1664 DEBUG_ONLY(fprintf(stderr, "wait to sweep\n"));
1666 pt_gc_wait_for_stage(interp, THREAD_GC_STAGE_MARK, THREAD_GC_STAGE_SWEEP);
1671 =item C<void Parrot_shared_DOD_block>
1673 Blocks stop-the-world DOD runs.
1675 =cut
1679 PARROT_API
1680 void
1681 Parrot_shared_DOD_block(PARROT_INTERP)
1683 Shared_gc_info * const info = get_pool(interp);
1685 if (info) {
1686 int level;
1687 PARROT_ATOMIC_INT_INC(level, info->gc_block_level);
1688 PARROT_ASSERT(level > 0);
1694 =item C<void Parrot_shared_DOD_unblock>
1696 Unblocks stop-the-world DOD runs.
1698 =cut
1702 PARROT_API
1703 void
1704 Parrot_shared_DOD_unblock(PARROT_INTERP)
1706 Shared_gc_info * const info = get_pool(interp);
1707 if (info) {
1708 int level;
1709 PARROT_ATOMIC_INT_DEC(level, info->gc_block_level);
1710 PARROT_ASSERT(level >= 0);
1715 * Local variables:
1716 * c-file-style: "parrot"
1717 * End:
1718 * vim: expandtab shiftwidth=4: