Issue #320 - Track threads that have not yet run

This allows (thread-join!) to be able to wait on these new threads
This commit is contained in:
Justin Ethier 2019-06-10 13:16:39 -04:00
parent c49c753f9d
commit d1dbd7fae9
4 changed files with 62 additions and 6 deletions

50
gc.c
View file

@ -66,8 +66,11 @@ static int mark_stack_i = 0;
// thread terminates (normally or not). // thread terminates (normally or not).
static gc_thread_data *primordial_thread = NULL; static gc_thread_data *primordial_thread = NULL;
/** Data new mutator threads that are not running yet */
static ck_array_t new_mutators;
/** Data for each individual mutator thread */ /** Data for each individual mutator thread */
ck_array_t Cyc_mutators, old_mutators; static ck_array_t Cyc_mutators;
static ck_array_t old_mutators;
static pthread_mutex_t mutators_lock; static pthread_mutex_t mutators_lock;
static void my_free(void *p, size_t m, bool d) static void my_free(void *p, size_t m, bool d)
@ -214,6 +217,10 @@ void gc_initialize(void)
exit(1); exit(1);
} }
if (ck_array_init(&new_mutators, CK_ARRAY_MODE_SPMC, &my_allocator, 10) == 0) {
fprintf(stderr, "Unable to initialize mutator array\n");
exit(1);
}
if (ck_array_init(&old_mutators, CK_ARRAY_MODE_SPMC, &my_allocator, 10) == 0) { if (ck_array_init(&old_mutators, CK_ARRAY_MODE_SPMC, &my_allocator, 10) == 0) {
fprintf(stderr, "Unable to initialize mutator array\n"); fprintf(stderr, "Unable to initialize mutator array\n");
exit(1); exit(1);
@ -230,7 +237,25 @@ void gc_initialize(void)
} }
/** /**
* @brief Add data for a new mutator * @brief Add data for a new mutator that is not yet scheduled to run.
* This is done so there is a record in the system even if the
* thread is not running, to prevent race conditions for any
* functions (EG: thread-join!) that need to access the thread.
* @param thd Thread data for the mutator
*/
void gc_add_new_unrunning_mutator(gc_thread_data * thd)
{
pthread_mutex_lock(&mutators_lock);
if (ck_array_put_unique(&new_mutators, (void *)thd) < 0) {
fprintf(stderr, "Unable to allocate memory for a new thread, exiting\n");
exit(1);
}
ck_array_commit(&new_mutators);
pthread_mutex_unlock(&mutators_lock);
}
/**
* @brief Add data for a new mutator that is starting to run.
* @param thd Thread data for the mutator * @param thd Thread data for the mutator
*/ */
void gc_add_mutator(gc_thread_data * thd) void gc_add_mutator(gc_thread_data * thd)
@ -246,6 +271,10 @@ void gc_add_mutator(gc_thread_data * thd)
// Main thread is always the first one added // Main thread is always the first one added
if (primordial_thread == NULL) { if (primordial_thread == NULL) {
primordial_thread = thd; primordial_thread = thd;
} else {
// At this point the mutator is running, so remove it from the new list
ck_array_remove(&new_mutators, (void *)thd);
ck_array_commit(&new_mutators);
} }
} }
@ -290,6 +319,23 @@ int gc_is_mutator_active(gc_thread_data *thd)
return 0; return 0;
} }
/**
* @brief Determine if the given mutator is in the list of new threads.
* @param thd Thread data object of the m
* @return A true value if the mutator is found, 0 otherwise.
*/
int gc_is_mutator_new(gc_thread_data *thd)
{
ck_array_iterator_t iterator;
gc_thread_data *m;
CK_ARRAY_FOREACH(&new_mutators, &iterator, &m) {
if (m == thd) {
return 1;
}
}
return 0;
}
/** /**
* @brief Free thread data for all terminated mutators * @brief Free thread data for all terminated mutators
*/ */

View file

@ -349,9 +349,11 @@ struct gc_thread_data_t {
/* GC prototypes */ /* GC prototypes */
void gc_initialize(void); void gc_initialize(void);
void gc_add_new_unrunning_mutator(gc_thread_data * thd);
void gc_add_mutator(gc_thread_data * thd); void gc_add_mutator(gc_thread_data * thd);
void gc_remove_mutator(gc_thread_data * thd); void gc_remove_mutator(gc_thread_data * thd);
int gc_is_mutator_active(gc_thread_data *thd); int gc_is_mutator_active(gc_thread_data *thd);
int gc_is_mutator_new(gc_thread_data *thd);
void gc_sleep_ms(int ms); void gc_sleep_ms(int ms);
gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size, gc_heap *gc_heap_create(int heap_type, size_t size, size_t max_size,
size_t chunk_size, gc_thread_data *thd); size_t chunk_size, gc_thread_data *thd);

View file

@ -33,7 +33,8 @@
(thread-start! t2) (thread-start! t2)
(write (thread? t)) (write (thread? t))
(thread-sleep! 1) (write (thread? t2))
(newline)
;; Main thread - wait for thread to broadcast it is done ;; Main thread - wait for thread to broadcast it is done
(thread-join! t) (thread-join! t)
(thread-join! t2) (thread-join! t2)

View file

@ -71,7 +71,13 @@
;; - name ;; - name
;; - specific ;; - specific
;; - internal ;; - internal
(vector 'cyc-thread-obj thunk #f name-str #f #f))) (vector
'cyc-thread-obj
thunk
(%alloc-thread-data) ;; Internal data for new thread
name-str
#f
#f)))
(define (thread-name t) (vector-ref t 3)) (define (thread-name t) (vector-ref t 3))
(define (thread-specific t) (vector-ref t 4)) (define (thread-specific t) (vector-ref t 4))
@ -100,6 +106,7 @@
(define-c %alloc-thread-data (define-c %alloc-thread-data
"(void *data, int argc, closure _, object k)" "(void *data, int argc, closure _, object k)"
" gc_thread_data *td = malloc(sizeof(gc_thread_data)); " gc_thread_data *td = malloc(sizeof(gc_thread_data));
gc_add_new_unrunning_mutator(td); /* Register this thread */
make_c_opaque(co, td); make_c_opaque(co, td);
return_closcall1(data, k, &co); ") return_closcall1(data, k, &co); ")
@ -112,7 +119,6 @@
(thunk))))) (thunk)))))
(vector-set! t 5 (%get-thread-data)) ;; Temporarily make parent thread (vector-set! t 5 (%get-thread-data)) ;; Temporarily make parent thread
;; data available for child init ;; data available for child init
(vector-set! t 2 (%alloc-thread-data)) ;; Data for new thread
(Cyc-minor-gc) (Cyc-minor-gc)
(Cyc-spawn-thread! thread-params) (Cyc-spawn-thread! thread-params)
)) ))
@ -131,7 +137,8 @@
set_thread_blocked(data, k); set_thread_blocked(data, k);
/* Cannot join to detached thread! pthread_join(td->thread_id, NULL);*/ /* Cannot join to detached thread! pthread_join(td->thread_id, NULL);*/
while (1) { while (1) {
if (!gc_is_mutator_active(td)){ if (!gc_is_mutator_new(td) &&
!gc_is_mutator_active(td)){
break; break;
} }
gc_sleep_ms(250); gc_sleep_ms(250);