2 Copyright (C) 2001-2007, 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 */
28 static Parrot_Interp
detach(UINTVAL tid
);
29 PARROT_CAN_RETURN_NULL
30 static Shared_gc_info
* get_pool(PARROT_INTERP
)
31 __attribute__nonnull__(1);
33 PARROT_WARN_UNUSED_RESULT
34 static int is_suspended_for_gc(PARROT_INTERP
)
35 __attribute__nonnull__(1);
37 PARROT_CAN_RETURN_NULL
38 static PMC
* make_local_args_copy(PARROT_INTERP
,
39 ARGIN(Parrot_Interp old_interp
),
40 ARGIN_NULLOK(PMC
*args
))
41 __attribute__nonnull__(1)
42 __attribute__nonnull__(2);
44 PARROT_CAN_RETURN_NULL
45 static PMC
* make_local_copy(PARROT_INTERP
,
46 ARGIN(Parrot_Interp from
),
48 __attribute__nonnull__(1)
49 __attribute__nonnull__(2)
50 __attribute__nonnull__(3);
52 static void mutex_unlock(ARGMOD(void *arg
))
53 __attribute__nonnull__(1)
56 static Parrot_Interp
pt_check_tid(UINTVAL tid
, ARGIN(const char *from
))
57 __attribute__nonnull__(2);
59 static int pt_gc_count_threads(PARROT_INTERP
)
60 __attribute__nonnull__(1);
62 static void pt_gc_wait_for_stage(PARROT_INTERP
,
63 thread_gc_stage_enum from_stage
,
64 thread_gc_stage_enum to_stage
)
65 __attribute__nonnull__(1);
67 static void pt_gc_wakeup_check(PARROT_INTERP
)
68 __attribute__nonnull__(1);
70 static void pt_ns_clone(
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)
80 FUNC_MODIFIES(*dest_ns
);
82 static void pt_suspend_all_for_gc(PARROT_INTERP
)
83 __attribute__nonnull__(1);
85 static void pt_suspend_one_for_gc(PARROT_INTERP
)
86 __attribute__nonnull__(1);
88 static void pt_thread_signal(NOTNULL(Parrot_Interp self
), PARROT_INTERP
)
89 __attribute__nonnull__(1)
90 __attribute__nonnull__(2);
92 static void pt_thread_wait(PARROT_INTERP
)
93 __attribute__nonnull__(1);
95 PARROT_CAN_RETURN_NULL
96 static QUEUE_ENTRY
* remove_queued_suspend_gc(PARROT_INTERP
)
97 __attribute__nonnull__(1);
99 PARROT_CAN_RETURN_NULL
100 static void* thread_func(ARGIN_NULLOK(void *arg
));
102 /* HEADERIZER END: static */
104 #if defined THREAD_DEBUG && THREAD_DEBUG
105 # define DEBUG_ONLY(x) x
107 # define DEBUG_ONLY(x)
110 static int running_threads
;
112 void Parrot_really_destroy(PARROT_INTERP
, int exit_code
, void *arg
);
116 =item C<static PMC * make_local_copy>
118 Create a local copy of the PMC if necessary. (No copy is made if it
119 is marked shared.) This includes workarounds for Parrot_clone() not
120 doing the Right Thing with subroutines (specifically, code segments
121 aren't preserved and it is difficult to do so as long as
122 Parrot_clone() depends on freezing).
128 PARROT_CAN_RETURN_NULL
130 make_local_copy(PARROT_INTERP
, ARGIN(Parrot_Interp from
), ARGIN(PMC
*arg
))
133 STRING
* const _sub
= interp
->vtables
[enum_class_Sub
]->whoami
;
134 STRING
* const _multi_sub
= interp
->vtables
[enum_class_MultiSub
]->whoami
;
136 if (PMC_IS_NULL(arg
)) {
139 else if (PObj_is_PMC_shared_TEST(arg
)) {
142 else if (VTABLE_isa(from
, arg
, _multi_sub
)) {
144 const INTVAL n
= VTABLE_elements(from
, arg
);
145 ret_val
= pmc_new(interp
, enum_class_MultiSub
);
147 for (i
= 0; i
< n
; ++i
) {
148 PMC
*const orig
= VTABLE_get_pmc_keyed_int(from
, arg
, i
);
149 PMC
*const copy
= make_local_copy(interp
, from
, orig
);
150 VTABLE_push_pmc(interp
, ret_val
, copy
);
153 else if (VTABLE_isa(from
, arg
, _sub
)) {
154 /* this is a workaround for cloning subroutines not actually
155 * working as one might expect mainly because the segment is
156 * not correctly copied
158 ret_val
= Parrot_clone(interp
, arg
);
159 PMC_sub(ret_val
)->seg
= PMC_sub(arg
)->seg
;
160 /* Skip vtable overrides and methods. */
161 if (PMC_sub(ret_val
)->vtable_index
== -1
162 && !(PMC_sub(ret_val
)->comp_flags
& SUB_COMP_FLAG_METHOD
)) {
163 Parrot_store_sub_in_namespace(interp
, ret_val
);
167 ret_val
= Parrot_clone(interp
, arg
);
174 =item C<static Shared_gc_info * get_pool>
176 Get the shared gc information. TODO: improve the docs here.
182 PARROT_CAN_RETURN_NULL
183 static Shared_gc_info
*
184 get_pool(PARROT_INTERP
)
186 return shared_gc_info
;
191 =item C<void pt_free_pool>
193 Frees the shared gc information. This clears any global data hen joining all
194 threads at parent interpreter destruction.
201 pt_free_pool(PARROT_INTERP
)
203 if (shared_gc_info
) {
204 COND_DESTROY(shared_gc_info
->gc_cond
);
205 PARROT_ATOMIC_INT_DESTROY(shared_gc_info
->gc_block_level
);
206 mem_sys_free(shared_gc_info
);
207 shared_gc_info
= NULL
;
213 =item C<static PMC * make_local_args_copy>
215 Make a local copy of the corresponding array of arguments.
221 PARROT_CAN_RETURN_NULL
223 make_local_args_copy(PARROT_INTERP
, ARGIN(Parrot_Interp old_interp
), ARGIN_NULLOK(PMC
*args
))
229 if (PMC_IS_NULL(args
))
232 old_size
= VTABLE_get_integer(old_interp
, args
);
234 /* XXX should this be a different type? */
235 ret_val
= pmc_new(interp
, enum_class_FixedPMCArray
);
236 VTABLE_set_integer_native(interp
, ret_val
, old_size
);
238 for (i
= 0; i
< old_size
; ++i
) {
239 PMC
* const copy
= make_local_copy(interp
, old_interp
,
240 VTABLE_get_pmc_keyed_int(old_interp
, args
, i
));
242 VTABLE_set_pmc_keyed_int(interp
, ret_val
, i
, copy
);
250 =item C<PMC * pt_shared_fixup>
252 Fixup a PMC to be sharable. Right now, reassigns the vtable to one
253 owned by some master interpreter, so the PMC can be safely reused
256 In the future the PMC returned might be different than the one
257 passed, e.g., if we need to reallocate the PMC in a different
264 PARROT_CAN_RETURN_NULL
266 pt_shared_fixup(PARROT_INTERP
, ARGMOD(PMC
*pmc
))
268 /* TODO this will need to change for thread pools
269 * XXX should we have a separate interpreter for this?
272 Parrot_Interp master
= interpreter_array
[0];
273 const int is_ro
= pmc
->vtable
->flags
& VTABLE_IS_READONLY_FLAG
;
275 /* This lock is paired with one in objects.c. It is necessary to protect
276 * against the master interpreter adding classes and consequently
277 * resizing its classname->type_id hashtable and/or expanding its vtable
279 * TODO investigate if a read-write lock results in substantially
280 * better performance.
282 LOCK_INTERPRETER(master
);
283 type_num
= pmc
->vtable
->base_type
;
285 if (type_num
== enum_type_undef
) {
286 UNLOCK_INTERPRETER(master
);
287 real_exception(interp
, NULL
, 1, "pt_shared_fixup: unsharable type");
291 pmc
->vtable
= master
->vtables
[type_num
];
293 UNLOCK_INTERPRETER(master
);
296 pmc
->vtable
= pmc
->vtable
->ro_variant_vtable
;
298 add_pmc_sync(interp
, pmc
);
300 PObj_is_PMC_shared_SET(pmc
);
302 /* make sure metadata doesn't go away unexpectedly */
303 if (PMC_metadata(pmc
))
304 PMC_metadata(pmc
) = pt_shared_fixup(interp
, PMC_metadata(pmc
));
311 =item C<static void pt_thread_signal>
313 Wakeup a C<interp> which should have called pt_thread_wait().
320 pt_thread_signal(NOTNULL(Parrot_Interp self
), PARROT_INTERP
)
322 COND_SIGNAL(interp
->thread_data
->interp_cond
);
327 =item C<void pt_thread_wait_with>
329 Wait for this interpreter to be signalled through its condition variable,
330 dealing properly with GC issues. C<*mutex> is assumed locked on entry and
331 will be locked on exit from this function. If a GC run occurs in the middle of
332 this function, then a spurious wakeup may occur.
339 pt_thread_wait_with(PARROT_INTERP
, ARGMOD(Parrot_mutex
*mutex
))
341 LOCK(interpreter_array_mutex
);
342 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
343 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
344 /* fprintf(stderr, "%p: pt_thread_wait, before sleep, doing GC run\n",
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 Wait for us to be signalled. GC matters are handled correctly.
387 C<interpreter_array_mutex> 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_DOD(interp
);
449 Parrot_block_GC(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_DOD(interp
);
473 Parrot_unblock_GC(interp
);
474 ret_val
= Parrot_runops_fromc_args(interp
, sub
, "PF", sub_arg
);
479 LOCK(interpreter_array_mutex
);
480 DEBUG_ONLY(fprintf(stderr
, "marking an thread as finished\n"));
482 interp
->thread_data
->state
|= THREAD_STATE_FINISHED
;
483 tid
= interp
->thread_data
->tid
;
485 if (interp
!= interpreter_array
[tid
]) {
486 UNLOCK(interpreter_array_mutex
);
487 PANIC(interp
, "thread finished: interpreter mismatch");
489 if (interp
->thread_data
->state
& THREAD_STATE_DETACHED
) {
490 interpreter_array
[tid
] = NULL
;
491 DEBUG_ONLY(fprintf(stderr
, "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 Copy/clone 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
)
528 Interp_flags_SET(d
, PARROT_EXTERN_CODE_FLAG
);
530 Parrot_switch_to_cs(d
, s
->code
, 1);
531 Parrot_unblock_DOD(d
);
536 =item C<static void pt_ns_clone>
538 Clone 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 Copy global namespace when cloning new interpreter
594 pt_clone_globals(Parrot_Interp d
, Parrot_Interp s
)
597 pt_ns_clone(d
, d
->root_namespace
, s
, s
->root_namespace
);
598 Parrot_unblock_DOD(d
);
603 =item C<void pt_thread_prepare_for_run>
605 Setup code, and TODO ...
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 create a clone of the sub 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 Run the C<*sub> PMC in a separate thread using interpreter in
657 C<arg> should be an array of arguments for the subroutine.
665 pt_thread_run(PARROT_INTERP
, ARGOUT(PMC
* dest_interp
), ARGIN(PMC
* sub
), ARGIN(PMC
*arg
))
667 PMC
*old_dest_interp
;
669 Interp
* const interpreter
= (Parrot_Interp
)PMC_data(dest_interp
);
671 Parrot_block_GC(interpreter
);
672 Parrot_block_DOD(interpreter
);
673 Parrot_block_GC(interp
);
674 Parrot_block_DOD(interp
);
676 /* make a copy of the ParrotThread PMC so we can use it
677 * to hold parameters to the new thread without it being
678 * garbage collected or otherwise changed by the parent thread.
679 * Also so the new thread's getinterp doesn't return an object
680 * owned by the wrong interpreter -- which would be very bad
681 * if the parent is destroyed before the child.
682 * XXX FIXME move this elsewhere? at least the set_pmc_keyed_int
684 old_dest_interp
= dest_interp
;
685 dest_interp
= pmc_new_noinit(interpreter
, enum_class_ParrotThread
);
687 /* so it's not accidentally deleted */
688 PMC_data(old_dest_interp
) = NULL
;
689 PMC_data(dest_interp
) = interpreter
;
691 VTABLE_set_pmc_keyed_int(interpreter
, interpreter
->iglobals
,
692 (INTVAL
) IGLOBALS_INTERPRETER
, dest_interp
);
694 parent
= VTABLE_get_pmc_keyed_int(interp
, interp
->iglobals
,
695 IGLOBALS_INTERPRETER
);
698 * TODO check if thread flags are consistent
700 if (interp
->flags
& PARROT_THR_COPY_INTERP
)
701 clone_interpreter(interpreter
, (Parrot_Interp
)PMC_data(parent
), PARROT_CLONE_DEFAULT
);
706 pt_thread_prepare_for_run(interpreter
, interp
);
708 PMC_struct_val(dest_interp
) = pt_transfer_sub(interpreter
, interp
, sub
);
709 PMC_pmc_val(dest_interp
) = make_local_args_copy(interpreter
, interp
, arg
);
712 * set regs according to pdd03
714 interpreter
->current_object
= dest_interp
;
716 * create a joinable thread
718 interpreter
->thread_data
->state
= THREAD_STATE_JOINABLE
;
720 Parrot_unblock_GC(interpreter
);
721 Parrot_unblock_DOD(interpreter
);
722 Parrot_unblock_GC(interp
);
723 Parrot_unblock_DOD(interp
);
725 THREAD_CREATE_JOINABLE(interpreter
->thread_data
->thread
,
726 thread_func
, dest_interp
);
728 /* check for pending GC */
729 LOCK(interpreter_array_mutex
);
730 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
)
731 pt_suspend_one_for_gc(interpreter
);
733 UNLOCK(interpreter_array_mutex
);
739 =item C<int pt_thread_run_1>
741 Runs a type 1 thread. Nothing is shared, both interpreters are free
742 running without any communication.
749 pt_thread_run_1(PARROT_INTERP
, ARGOUT(PMC
* dest_interp
), ARGIN(PMC
* sub
), ARGIN(PMC
*arg
))
751 interp
->flags
|= PARROT_THR_TYPE_1
;
752 return pt_thread_run(interp
, dest_interp
, sub
, arg
);
757 =item C<int pt_thread_run_2>
759 Runs a type 2 thread. No shared variables, threads are communicating by
767 pt_thread_run_2(PARROT_INTERP
, ARGOUT(PMC
* dest_interp
), ARGIN(PMC
* sub
), ARGIN(PMC
*arg
))
769 interp
->flags
|= PARROT_THR_TYPE_2
;
770 return pt_thread_run(interp
, dest_interp
, sub
, arg
);
775 =item C<int pt_thread_run_3>
777 Run a type 3 thread. Threads may have shared variables and are managed
785 pt_thread_run_3(PARROT_INTERP
, ARGOUT(PMC
* dest_interp
), ARGIN(PMC
* sub
), ARGIN(PMC
*arg
))
787 interp
->flags
|= PARROT_THR_TYPE_3
;
788 return pt_thread_run(interp
, dest_interp
, sub
, arg
);
793 =item C<void pt_thread_yield>
795 Relinquishes hold on the processor.
802 pt_thread_yield(void)
809 =item C<static Parrot_Interp pt_check_tid>
811 Helper function. Check if C<tid> is valid. The caller holds the mutex.
812 Returns the interpreter for C<tid>.
819 pt_check_tid(UINTVAL tid
, ARGIN(const char *from
))
821 if (tid
>= n_interpreters
) {
822 UNLOCK(interpreter_array_mutex
);
823 internal_exception(1, "%s: illegal thread tid %d", from
, tid
);
826 UNLOCK(interpreter_array_mutex
);
827 internal_exception(1, "%s: illegal thread tid %d (main)", from
, tid
);
829 if (!interpreter_array
[tid
]) {
830 UNLOCK(interpreter_array_mutex
);
831 internal_exception(1, "%s: illegal thread tid %d - empty", from
, tid
);
833 return interpreter_array
[tid
];
838 =item C<static void mutex_unlock>
840 Unlocks the mutex C<*arg>.
847 mutex_unlock(ARGMOD(void *arg
))
849 UNLOCK(*(Parrot_mutex
*) arg
);
854 =item C<static int is_suspended_for_gc>
856 Returns true iff C<interp> is suspended so a global GC can
857 be performed. interpreter_array_mutex must be held.
863 PARROT_WARN_UNUSED_RESULT
865 is_suspended_for_gc(PARROT_INTERP
)
869 else if (interp
->thread_data
->wants_shared_gc
)
871 else if (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)
873 else if ((interp
->thread_data
->state
& THREAD_STATE_FINISHED
) ||
874 (interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
))
882 =item C<static QUEUE_ENTRY * remove_queued_suspend_gc>
884 Remove an event requesting that the interpreter suspend itself for a
885 garbage-collection run from the event queue.
891 PARROT_CAN_RETURN_NULL
893 remove_queued_suspend_gc(PARROT_INTERP
)
895 parrot_event
*ev
= NULL
;
896 QUEUE
*queue
= interp
->task_queue
;
897 QUEUE_ENTRY
*prev
= NULL
;
904 ev
= (parrot_event
*)cur
->data
;
906 if (ev
->type
== EVENT_TYPE_SUSPEND_FOR_GC
)
915 prev
->next
= cur
->next
;
917 queue
->head
= cur
->next
;
919 if (cur
== queue
->tail
)
922 if (cur
== queue
->head
)
923 queue
->head
= cur
->next
;
928 DEBUG_ONLY(fprintf(stderr
, "%p: remove_queued_suspend_gc: got one\n", interp
));
937 =item C<static int pt_gc_count_threads>
939 interpreter_array_mutex must be held
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 RT#48260: Not yet documented!!!
976 pt_gc_wait_for_stage(PARROT_INTERP
, thread_gc_stage_enum from_stage
,
977 thread_gc_stage_enum to_stage
)
979 Shared_gc_info
*info
= shared_gc_info
;
982 DEBUG_ONLY(fprintf(stderr
, "%p: gc_wait_for_stage: %d->%d\n", interp
, from_stage
, to_stage
));
984 /* XXX well-timed thread death can mess this up */
985 LOCK(interpreter_array_mutex
);
987 DEBUG_ONLY(fprintf(stderr
, "%p: got lock\n", interp
));
988 thread_count
= pt_gc_count_threads(interp
);
990 PARROT_ASSERT(info
->gc_stage
== from_stage
);
991 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
));
992 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_FINISHED
));
995 PARROT_ASSERT(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
);
997 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
));
1001 DEBUG_ONLY(fprintf(stderr
, "%p: gc_wait_for_stage: got %d\n", interp
, info
->num_reached
));
1003 if (info
->num_reached
== thread_count
) {
1004 info
->gc_stage
= to_stage
;
1005 info
->num_reached
= 0;
1006 COND_BROADCAST(info
->gc_cond
);
1010 COND_WAIT(info
->gc_cond
, interpreter_array_mutex
);
1011 } while (info
->gc_stage
!= to_stage
);
1013 UNLOCK(interpreter_array_mutex
);
1019 =item C<static void pt_gc_wakeup_check>
1021 Check if we need to wake threads to perform garbage collection.
1022 This is called after thread death.
1023 interpreter_array_mutex is assumed held.
1030 pt_gc_wakeup_check(PARROT_INTERP
)
1032 Shared_gc_info
*info
= shared_gc_info
;
1035 /* XXX: maybe a little hack; see RT #49532 */
1039 thread_count
= pt_gc_count_threads(interp
);
1041 if (info
->num_reached
== thread_count
) {
1042 PARROT_ASSERT(info
->gc_stage
== THREAD_GC_STAGE_NONE
);
1043 info
->gc_stage
= THREAD_GC_STAGE_MARK
;
1044 info
->num_reached
= 0;
1045 COND_BROADCAST(info
->gc_cond
);
1051 =item C<static void pt_suspend_one_for_gc>
1053 Suspend a single interpreter for GC. C<interpreter_array_mutex>
1061 pt_suspend_one_for_gc(PARROT_INTERP
)
1063 DEBUG_ONLY(fprintf(stderr
, "suspend one: %p\n", interp
));
1064 if (is_suspended_for_gc(interp
)) {
1065 DEBUG_ONLY(fprintf(stderr
, "ignoring already suspended\n"));
1069 if (interp
->thread_data
->state
& THREAD_STATE_GC_WAKEUP
) {
1070 DEBUG_ONLY(fprintf(stderr
, "just waking it up\n"));
1071 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1072 COND_SIGNAL(interp
->thread_data
->interp_cond
);
1075 DEBUG_ONLY(fprintf(stderr
, "queuing event\n"));
1076 interp
->thread_data
->state
|= THREAD_STATE_SUSPEND_GC_REQUESTED
;
1077 Parrot_cx_request_suspend_for_gc(interp
);
1083 =item C<static void pt_suspend_all_for_gc>
1085 Get all threads to perform a GC run.
1092 pt_suspend_all_for_gc(PARROT_INTERP
)
1096 DEBUG_ONLY(fprintf(stderr
, "suspend_all_for_gc [interp=%p]\n", interp
));
1098 LOCK(interpreter_array_mutex
);
1099 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1101 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
1102 DEBUG_ONLY(fprintf(stderr
, "found while suspending all\n"));
1103 Parrot_cx_delete_suspend_for_gc(interp
);
1104 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPEND_GC_REQUESTED
;
1105 UNLOCK(interpreter_array_mutex
);
1110 for (i
= 0; i
< n_interpreters
; ++i
) {
1111 Parrot_Interp other_interp
;
1112 other_interp
= interpreter_array
[i
];
1116 if (is_suspended_for_gc(other_interp
) &&
1117 other_interp
!= interp
&&
1118 (other_interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
))
1121 /* this means that someone else already got this far,
1122 * so we have a suspend event in our queue to ignore
1124 /* XXX still reachable? */
1125 DEBUG_ONLY(fprintf(stderr
, "apparently someone else is doing it [%p]\n", other_interp
));
1126 fprintf(stderr
, "??? found later (%p)\n", other_interp
);
1127 successp
= Parrot_cx_delete_suspend_for_gc(interp
);
1128 PARROT_ASSERT(successp
);
1129 UNLOCK(interpreter_array_mutex
);
1135 /* now send all the non-suspended threads to suspend for GC */
1136 for (i
= 0; i
< n_interpreters
; ++i
) {
1137 Parrot_Interp other_interp
= interpreter_array
[i
];
1139 if (interp
== other_interp
)
1142 if (is_suspended_for_gc(other_interp
))
1145 pt_suspend_one_for_gc(other_interp
);
1147 UNLOCK(interpreter_array_mutex
);
1152 =item C<void pt_suspend_self_for_gc>
1154 Suspend this thread for a full GC run.
1156 XXX FIXME -- if GC is blocked, we need to do a GC run as soon
1157 as it becomes unblocked.
1164 pt_suspend_self_for_gc(PARROT_INTERP
)
1166 PARROT_ASSERT(interp
);
1167 PARROT_ASSERT(!interp
->arena_base
->DOD_block_level
);
1168 DEBUG_ONLY(fprintf(stderr
, "%p: suspend_self_for_gc\n", interp
));
1169 /* since we are modifying our own state, we need to lock
1170 * the interpreter_array_mutex.
1172 LOCK(interpreter_array_mutex
);
1173 DEBUG_ONLY(fprintf(stderr
, "%p: got lock\n", interp
));
1175 PARROT_ASSERT(interp
->thread_data
->state
&
1176 (THREAD_STATE_SUSPEND_GC_REQUESTED
| THREAD_STATE_SUSPENDED_GC
));
1178 if (interp
->thread_data
->state
& THREAD_STATE_SUSPEND_GC_REQUESTED
) {
1179 DEBUG_ONLY(fprintf(stderr
, "remove queued request\n"));
1180 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp
)));
1181 DEBUG_ONLY(fprintf(stderr
, "removed all queued requests\n"));
1182 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPEND_GC_REQUESTED
;
1184 if (!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)) {
1185 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1188 DEBUG_ONLY(fprintf(stderr
, "no need to set suspended\n"));
1190 UNLOCK(interpreter_array_mutex
);
1192 /* mark and sweep our world -- later callbacks will keep
1195 Parrot_dod_ms_run(interp
, DOD_trace_stack_FLAG
);
1197 PARROT_ASSERT(!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
));
1202 =item C<PMC* pt_thread_join>
1204 Join (wait for) a joinable thread.
1210 PARROT_CAN_RETURN_NULL
1212 pt_thread_join(NOTNULL(Parrot_Interp parent
), UINTVAL tid
)
1215 Parrot_Interp interp
;
1217 LOCK(interpreter_array_mutex
);
1219 interp
= pt_check_tid(tid
, "join");
1221 if (interp
== parent
)
1222 do_panic(parent
, "Can't join self", __FILE__
, __LINE__
);
1224 if ((!(interp
->thread_data
->state
& (THREAD_STATE_DETACHED
1225 | THREAD_STATE_JOINED
)) &&
1226 !(interp
->thread_data
->state
& THREAD_STATE_NOT_STARTED
)) ||
1227 interp
->thread_data
->state
== THREAD_STATE_FINISHED
) {
1228 void *raw_retval
= NULL
;
1231 interp
->thread_data
->state
|= THREAD_STATE_JOINED
;
1233 while (!(interp
->thread_data
->state
& THREAD_STATE_FINISHED
)) {
1234 interp
->thread_data
->joiner
= parent
;
1235 pt_thread_wait(parent
);
1238 UNLOCK(interpreter_array_mutex
);
1239 JOIN(interp
->thread_data
->thread
, raw_retval
);
1241 retval
= (PMC
*)raw_retval
;
1243 * we need to push a cleanup handler here: if cloning
1244 * of the retval fails (e.g. it's a NULLPMC) this lock
1245 * isn't released until eternity or someone hits ^C
1247 * TODO This is needed for all places holding a lock for
1250 * TODO remove that and replace it with proper exception
1251 * handling, so that a failing clone in the parent
1252 * just stops that thread
1255 LOCK(interpreter_array_mutex
);
1256 CLEANUP_PUSH(mutex_unlock
, &interpreter_array_mutex
);
1261 * clone the PMC into caller, if its not a shared PMC
1262 * the PMC is not in the parents root set nor in the
1263 * stack so block DOD during clone
1264 * XXX should probably acquire the parent's interpreter mutex
1266 Parrot_block_DOD(parent
);
1267 parent_ret
= make_local_copy(parent
, interp
, retval
);
1269 /* this PMC is living only in the stack of this currently
1270 * dying interpreter, so register it in parent's DOD registry
1271 * XXX is this still needed?
1273 dod_register_pmc(parent
, parent_ret
);
1274 Parrot_unblock_DOD(parent
);
1275 retval
= parent_ret
;
1280 interpreter_array
[tid
] = NULL
;
1283 DEBUG_ONLY(fprintf(stderr
, "destroying an interpreter [join]\n"));
1284 if (Interp_debug_TEST(parent
, PARROT_THREAD_DEBUG_FLAG
))
1285 fprintf(stderr
, "running threads %d\n", running_threads
);
1287 /* reparent it so memory pool merging works */
1288 interp
->parent_interpreter
= parent
;
1289 Parrot_really_destroy(interp
, 0, NULL
);
1293 * interpreter destruction is done - unregister the return
1294 * value, caller gets it now
1297 dod_unregister_pmc(parent
, retval
);
1302 * when here thread was in wrong state
1304 state
= interp
->thread_data
->state
;
1305 UNLOCK(interpreter_array_mutex
);
1306 real_exception(interp
, NULL
, 1, "join: illegal thread state %d tid %d",
1313 =item C<void pt_join_threads>
1315 Possibly wait for other running threads. This is called when destroying
1323 pt_join_threads(PARROT_INTERP
)
1326 pt_free_pool(interp
);
1329 * if no threads were started - fine
1331 LOCK(interpreter_array_mutex
);
1332 if (n_interpreters
<= 1) {
1334 UNLOCK(interpreter_array_mutex
);
1338 * only the first interpreter waits for other threads
1340 if (interp
!= interpreter_array
[0]) {
1341 UNLOCK(interpreter_array_mutex
);
1345 for (i
= 1; i
< n_interpreters
; ++i
) {
1346 Parrot_Interp thread_interp
= interpreter_array
[i
];
1347 if (thread_interp
== NULL
)
1349 if (thread_interp
->thread_data
->state
== THREAD_STATE_JOINABLE
||
1350 (thread_interp
->thread_data
->state
& THREAD_STATE_FINISHED
)) {
1352 void *retval
= NULL
;
1353 thread_interp
->thread_data
->state
|= THREAD_STATE_JOINED
;
1354 UNLOCK(interpreter_array_mutex
);
1355 JOIN(thread_interp
->thread_data
->thread
, retval
);
1356 LOCK(interpreter_array_mutex
);
1359 UNLOCK(interpreter_array_mutex
);
1365 =item C<static Parrot_Interp detach>
1367 Helper for detach and kill.
1369 Returns the interpreter, if it didn't finish yet.
1375 static Parrot_Interp
1378 Parrot_Interp interp
;
1380 LOCK(interpreter_array_mutex
);
1381 interp
= pt_check_tid(tid
, "detach");
1383 * if interpreter is joinable, we detach em
1385 if (interp
->thread_data
->state
== THREAD_STATE_JOINABLE
||
1386 interp
->thread_data
->state
== THREAD_STATE_FINISHED
) {
1387 DETACH(interp
->thread_data
->thread
);
1388 interp
->thread_data
->state
|= THREAD_STATE_DETACHED
;
1390 if (interp
->thread_data
->state
& THREAD_STATE_FINISHED
) {
1391 interpreter_array
[tid
] = NULL
;
1392 DEBUG_ONLY(fprintf(stderr
, "destroying an interpreter [detach]\n"));
1393 Parrot_really_destroy(interp
, 0, NULL
);
1397 UNLOCK(interpreter_array_mutex
);
1403 =item C<void pt_thread_detach>
1405 Detaches (make non-joinable) the thread.
1412 pt_thread_detach(UINTVAL tid
)
1419 =item C<void pt_thread_kill>
1428 pt_thread_kill(UINTVAL tid
)
1430 PARROT_INTERP
= detach(tid
);
1432 /* schedule a terminate event for that interpreter */
1434 Parrot_cx_runloop_end(interp
);
1441 =head2 Threaded interpreter book-keeping
1445 =item C<void pt_add_to_interpreters>
1447 All threaded interpreters are stored in an array. Assumes that caller
1455 pt_add_to_interpreters(PARROT_INTERP
, ARGIN_NULLOK(Parrot_Interp new_interp
))
1458 DEBUG_ONLY(fprintf(stderr
, "interp = %p\n", interp
));
1462 * Create an entry for the very first interpreter, event
1465 PARROT_ASSERT(!interpreter_array
);
1466 PARROT_ASSERT(n_interpreters
== 0);
1468 interpreter_array
= mem_allocate_typed(Interp
*);
1469 interpreter_array
[0] = interp
;
1472 shared_gc_info
= (Shared_gc_info
*)mem_sys_allocate_zeroed(sizeof (*shared_gc_info
));
1473 COND_INIT(shared_gc_info
->gc_cond
);
1474 PARROT_ATOMIC_INT_INIT(shared_gc_info
->gc_block_level
);
1475 PARROT_ATOMIC_INT_SET(shared_gc_info
->gc_block_level
, 0);
1477 /* XXX try to defer this until later */
1478 PARROT_ASSERT(interp
== interpreter_array
[0]);
1479 interp
->thread_data
= mem_allocate_zeroed_typed(Thread_data
);
1480 INTERPRETER_LOCK_INIT(interp
);
1481 interp
->thread_data
->tid
= 0;
1487 new_interp
->thread_data
= mem_allocate_zeroed_typed(Thread_data
);
1488 INTERPRETER_LOCK_INIT(new_interp
);
1490 if (Interp_debug_TEST(interp
, PARROT_THREAD_DEBUG_FLAG
))
1491 fprintf(stderr
, "running threads %d\n", running_threads
);
1493 * look for an empty slot
1495 for (i
= 0; i
< n_interpreters
; ++i
) {
1496 if (interpreter_array
[i
] == NULL
) {
1497 interpreter_array
[i
] = new_interp
;
1498 new_interp
->thread_data
->tid
= i
;
1499 new_interp
->thread_data
->state
= THREAD_STATE_NOT_STARTED
;
1504 /* need to resize */
1505 interpreter_array
= (Interp
**)mem_sys_realloc(interpreter_array
,
1506 (n_interpreters
+ 1) * sizeof (Interp
*));
1508 interpreter_array
[n_interpreters
] = new_interp
;
1509 new_interp
->thread_data
->tid
= n_interpreters
;
1510 new_interp
->thread_data
->state
= THREAD_STATE_NOT_STARTED
;
1519 =head2 DOD Synchronization Functions
1523 =item C<void pt_DOD_start_mark>
1525 DOD is going to start the mark phase. In the presence of shared PMCs, we can only
1526 run one DOD run at a time because C<< PMC->next_for_GC >> may be changed.
1528 C<flags> are the DOD flags. We check if we need to collect shared objects or
1531 TODO - Have a count of shared PMCs and check it during DOD.
1533 TODO - Evaluate if a interpreter lock is cheaper when C<dod_mark_ptr> is
1541 pt_DOD_start_mark(PARROT_INTERP
)
1543 Shared_gc_info
*info
;
1546 DEBUG_ONLY(fprintf(stderr
, "%p: pt_DOD_start_mark\n", interp
));
1547 /* if no other threads are running, we are safe */
1548 if (!running_threads
)
1551 info
= get_pool(interp
);
1552 PARROT_ATOMIC_INT_GET(block_level
, info
->gc_block_level
);
1554 DEBUG_ONLY(fprintf(stderr
, "start threaded mark\n"));
1556 * TODO now check, if we are the owner of a shared memory pool
1558 * - suspend all other threads by sending them a suspend event
1559 * (or put a LOCK around updating the mark pointers)
1560 * - return and continue the mark phase
1561 * - then s. comments below
1563 LOCK(interpreter_array_mutex
);
1564 if (interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
) {
1565 PARROT_ASSERT(!(interp
->thread_data
->state
&
1566 THREAD_STATE_SUSPEND_GC_REQUESTED
));
1567 DEBUG_ONLY(fprintf(stderr
, "already suspended...\n"));
1568 UNLOCK(interpreter_array_mutex
);
1570 else if (block_level
) {
1571 /* unthreaded collection */
1572 DEBUG_ONLY(fprintf(stderr
, "... but blocked\n"));
1574 /* holding the lock */
1577 else if (interp
->thread_data
->state
&
1578 THREAD_STATE_SUSPEND_GC_REQUESTED
) {
1579 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp
)));
1581 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPEND_GC_REQUESTED
;
1582 interp
->thread_data
->state
|= THREAD_STATE_SUSPENDED_GC
;
1584 DEBUG_ONLY(fprintf(stderr
, "%p: detected request\n", interp
));
1585 UNLOCK(interpreter_array_mutex
);
1588 /* we need to stop the world */
1589 DEBUG_ONLY(fprintf(stderr
, "stop the world\n"));
1590 UNLOCK(interpreter_array_mutex
);
1592 pt_suspend_all_for_gc(interp
);
1595 DEBUG_ONLY(fprintf(stderr
, "%p: wait for stage\n", interp
));
1596 pt_gc_wait_for_stage(interp
, THREAD_GC_STAGE_NONE
, THREAD_GC_STAGE_MARK
);
1598 DEBUG_ONLY(fprintf(stderr
, "actually mark\n"));
1600 * we can't allow parallel running DODs both would mess with shared PMCs
1601 * next_for_GC pointers
1603 LOCK(interpreter_array_mutex
);
1604 DEBUG_ONLY(fprintf(stderr
, "got marking lock\n"));
1609 =item C<void pt_DOD_mark_root_finished>
1611 DOD is finished for the root set.
1618 pt_DOD_mark_root_finished(PARROT_INTERP
)
1620 if (!running_threads
)
1623 * TODO now check, if we are the owner of a shared memory pool
1625 * - now run DOD_mark on all members of our pool
1626 * - if all shared PMCs are marked by all threads then
1627 * - we can continue to free unused objects
1633 =item C<void pt_DOD_stop_mark>
1635 DOD's mark phase is done.
1642 pt_DOD_stop_mark(PARROT_INTERP
)
1644 if (!running_threads
)
1647 * normal operation can continue now
1648 * - other threads may or not free unused objects then,
1649 * depending on their resource statistics
1651 if (!(interp
->thread_data
->state
& THREAD_STATE_SUSPENDED_GC
)) {
1652 UNLOCK(interpreter_array_mutex
);
1656 PARROT_ASSERT(!(interp
->thread_data
->state
&
1657 THREAD_STATE_SUSPEND_GC_REQUESTED
));
1658 interp
->thread_data
->state
&= ~THREAD_STATE_SUSPENDED_GC
;
1660 while (!PMC_IS_NULL(Parrot_cx_delete_suspend_for_gc(interp
))) {
1661 /* XXX FIXME make this message never trigger */
1662 fprintf(stderr
, "%p: extraneous suspend_gc event\n", (void *)interp
);
1665 DEBUG_ONLY(fprintf(stderr
, "%p: unlock\n", interp
));
1666 UNLOCK(interpreter_array_mutex
);
1667 DEBUG_ONLY(fprintf(stderr
, "wait to sweep\n"));
1669 pt_gc_wait_for_stage(interp
, THREAD_GC_STAGE_MARK
, THREAD_GC_STAGE_SWEEP
);
1674 =item C<void Parrot_shared_DOD_block>
1676 Block stop-the-world DOD runs.
1684 Parrot_shared_DOD_block(PARROT_INTERP
)
1686 Shared_gc_info
* const info
= get_pool(interp
);
1690 PARROT_ATOMIC_INT_INC(level
, info
->gc_block_level
);
1691 PARROT_ASSERT(level
> 0);
1697 =item C<void Parrot_shared_DOD_unblock>
1699 Unblock stop-the-world DOD runs.
1707 Parrot_shared_DOD_unblock(PARROT_INTERP
)
1709 Shared_gc_info
* const info
= get_pool(interp
);
1712 PARROT_ATOMIC_INT_DEC(level
, info
->gc_block_level
);
1713 PARROT_ASSERT(level
>= 0);
1719 * c-file-style: "parrot"
1721 * vim: expandtab shiftwidth=4: