2 Copyright (C) 2001-2008, The Perl 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/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
),
49 __attribute__nonnull__(1)
50 __attribute__nonnull__(2)
51 __attribute__nonnull__(3);
53 static void mutex_unlock(ARGMOD(void *arg
))
54 __attribute__nonnull__(1)
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
),
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)
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)
109 # define DEBUG_ONLY(x)
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).
129 PARROT_CAN_RETURN_NULL
131 make_local_copy(PARROT_INTERP
, ARGIN(Parrot_Interp from
), ARGIN(PMC
*arg
))
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
)) {
140 else if (PObj_is_PMC_shared_TEST(arg
)) {
143 else if (VTABLE_isa(from
, arg
, _multi_sub
)) {
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
);
168 ret_val
= Parrot_clone(interp
, arg
);
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.
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.
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.
224 PARROT_CAN_RETURN_NULL
226 make_local_args_copy(PARROT_INTERP
, ARGIN(Parrot_Interp old_interp
), ARGIN_NULLOK(PMC
*args
))
232 if (PMC_IS_NULL(args
))
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
);
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
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
267 PARROT_CAN_RETURN_NULL
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?
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
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
);
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
));
313 =item C<static void pt_thread_signal>
315 Wakes up an C<interp> which should have called pt_thread_wait().
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.
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
);
349 pt_suspend_self_for_gc(interp
);
352 /* since we unlocked the mutex something bad may have occured */
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
) {
366 /* XXX loop needed? */
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
);
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.
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",
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
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.
435 PARROT_CAN_RETURN_NULL
437 thread_func(ARGIN_NULLOK(void *arg
))
439 Parrot_exception exp
;
444 PMC
* const self
= (PMC
*) arg
;
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 */
461 "Unhandled exception in thread with tid %d "
462 "(message=%Ss, number=%d)\n",
463 interp
->thread_data
->tid
,
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
);
511 =head2 Helper functions used also for running plain interpreters
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>.
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
);
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>.
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
);
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
);
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.
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.
612 pt_thread_prepare_for_run(Parrot_Interp d
, Parrot_Interp s
)
614 Parrot_setup_event_func_ptrs(d
);
621 =head2 ParrotThread methods
631 =item C<PMC * pt_transfer_sub>
633 Clones the sub so that it's suitable for the other interpreter.
639 PARROT_CAN_RETURN_NULL
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
));
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
657 C<arg> should be an array of arguments for the subroutine.
664 pt_thread_run(PARROT_INTERP
, ARGOUT(PMC
*dest_interp
), ARGIN(PMC
*sub
), ARGIN_NULLOK(PMC
*arg
))
666 PMC
*old_dest_interp
;
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
);
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
);
738 =item C<int pt_thread_run_1>
740 Runs a thread that shares nothing and does not communicate with the other
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.
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
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.
801 pt_thread_yield(void)
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>.
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
);
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>.
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>.
862 PARROT_WARN_UNUSED_RESULT
864 is_suspended_for_gc(PARROT_INTERP
)
868 else if (interp
->thread_data
->wants_shared_gc
)
870 else if (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)
872 else if ((interp
->thread_data
->state
& THREAD_STATE_FINISHED
) ||
873 (interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
))
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.
890 PARROT_CAN_RETURN_NULL
892 remove_queued_suspend_gc(PARROT_INTERP
)
894 parrot_event
*ev
= NULL
;
895 QUEUE
*queue
= interp
->task_queue
;
896 QUEUE_ENTRY
*prev
= NULL
;
903 ev
= (parrot_event
*)cur
->data
;
905 if (ev
->type
== EVENT_TYPE_SUSPEND_FOR_GC
)
914 prev
->next
= cur
->next
;
916 queue
->head
= cur
->next
;
918 if (cur
== queue
->tail
)
921 if (cur
== queue
->head
)
922 queue
->head
= cur
->next
;
927 DEBUG_ONLY(fprintf(stderr
, "%p: remove_queued_suspend_gc: got one\n", interp
));
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>.
946 pt_gc_count_threads(PARROT_INTERP
)
951 for (i
= 0; i
< n_interpreters
; ++i
) {
953 cur
= interpreter_array
[i
];
956 if (cur
->thread_data
->state
& (THREAD_STATE_NOT_STARTED
|
957 THREAD_STATE_FINISHED
))
961 DEBUG_ONLY(fprintf(stderr
, "found %d threads\n", 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>.
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
;
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
));
997 PARROT_ASSERT(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
);
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
);
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>.
1031 pt_gc_wakeup_check(PARROT_INTERP
)
1033 Shared_gc_info
* const info
= shared_gc_info
;
1036 /* XXX: maybe a little hack; see RT #49532 */
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>.
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"));
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
);
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.
1093 pt_suspend_all_for_gc(PARROT_INTERP
)
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
);
1111 for (i
= 0; i
< n_interpreters
; ++i
) {
1112 Parrot_Interp other_interp
;
1113 other_interp
= interpreter_array
[i
];
1117 if (is_suspended_for_gc(other_interp
) &&
1118 other_interp
!= interp
&&
1119 (other_interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
))
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
);
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
)
1143 if (is_suspended_for_gc(other_interp
))
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.
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
;
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
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.
1211 PARROT_CAN_RETURN_NULL
1213 pt_thread_join(NOTNULL(Parrot_Interp parent
), UINTVAL tid
)
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
;
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
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
1256 LOCK(interpreter_array_mutex
);
1257 CLEANUP_PUSH(mutex_unlock
, &interpreter_array_mutex
);
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
;
1281 interpreter_array
[tid
] = NULL
;
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
);
1294 * interpreter destruction is done - unregister the return
1295 * value, caller gets it now
1298 dod_unregister_pmc(parent
, 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",
1313 =item C<void pt_join_threads>
1315 Possibly waits for other running threads. This is called when destroying
1323 pt_join_threads(PARROT_INTERP
)
1326 pt_free_pool(interp
);
1328 /* if no threads were started - fine */
1329 LOCK(interpreter_array_mutex
);
1330 if (n_interpreters
<= 1) {
1332 UNLOCK(interpreter_array_mutex
);
1336 /* only the first interpreter waits for other threads */
1337 if (interp
!= interpreter_array
[0]) {
1338 UNLOCK(interpreter_array_mutex
);
1342 for (i
= 1; i
< n_interpreters
; ++i
) {
1343 Parrot_Interp thread_interp
= interpreter_array
[i
];
1344 if (thread_interp
== NULL
)
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
);
1362 =item C<static Parrot_Interp detach>
1364 Helper for detach and kill.
1366 Returns the interpreter, if it didn't finish yet.
1372 static Parrot_Interp
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
);
1394 UNLOCK(interpreter_array_mutex
);
1400 =item C<void pt_thread_detach>
1402 Detaches the thread, making it non-joinable.
1409 pt_thread_detach(UINTVAL tid
)
1416 =item C<void pt_thread_kill>
1425 pt_thread_kill(UINTVAL tid
)
1427 PARROT_INTERP
= detach(tid
);
1429 /* schedule a terminate event for that interpreter */
1431 Parrot_cx_runloop_end(interp
);
1438 =head2 Threaded interpreter book-keeping
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>.
1452 pt_add_to_interpreters(PARROT_INTERP
, ARGIN_NULLOK(Parrot_Interp new_interp
))
1455 DEBUG_ONLY(fprintf(stderr
, "interp = %p\n", interp
));
1459 * Create an entry for the very first interpreter, event
1462 PARROT_ASSERT(!interpreter_array
);
1463 PARROT_ASSERT(n_interpreters
== 0);
1465 interpreter_array
= mem_allocate_typed(Interp
*);
1466 interpreter_array
[0] = interp
;
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;
1484 new_interp
->thread_data
= mem_allocate_zeroed_typed(Thread_data
);
1485 INTERPRETER_LOCK_INIT(new_interp
);
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
;
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
;
1515 =head2 DOD Synchronization Functions
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
1525 C<flags> are the DOD flags. We check if we need to collect shared objects or
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
1538 pt_DOD_start_mark(PARROT_INTERP
)
1540 Shared_gc_info
*info
;
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
)
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
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 */
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
);
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
1615 pt_DOD_mark_root_finished(PARROT_INTERP
)
1617 if (!running_threads
)
1620 * TODO now check, if we are the owner of a shared memory pool
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.
1639 pt_DOD_stop_mark(PARROT_INTERP
)
1641 if (!running_threads
)
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
);
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.
1681 Parrot_shared_DOD_block(PARROT_INTERP
)
1683 Shared_gc_info
* const info
= get_pool(interp
);
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.
1704 Parrot_shared_DOD_unblock(PARROT_INTERP
)
1706 Shared_gc_info
* const info
= get_pool(interp
);
1709 PARROT_ATOMIC_INT_DEC(level
, info
->gc_block_level
);
1710 PARROT_ASSERT(level
>= 0);
1716 * c-file-style: "parrot"
1718 * vim: expandtab shiftwidth=4: