Exemple #1
0
void core_vector_swap(struct core_vector *self,
                int64_t index1, int64_t index2)
{
    void *value1;
    void *value2;
    int i;
    char saved;
    int element_size;

    value1 = core_vector_at(self, index1);
    value2 = core_vector_at(self, index2);

    if (value1 == NULL || value2 == NULL) {
        return;
    }

    element_size = core_vector_element_size(self);

    /* swap 2 elements, byte by byte.
     */
    for (i = 0; i < element_size; i++) {
        saved = ((char *)value1)[i];
        ((char *)value1)[i] = ((char *)value2)[i];
        ((char *)value2)[i] = saved;
    }
}
Exemple #2
0
int64_t core_vector_select_pivot(struct core_vector *self,
                int64_t first, int64_t last, core_compare_fn_t compare)
{

    int64_t middle;

    void *first_value;
    void *last_value;
    void *middle_value;

    middle = first + (last - first) / 2;

    first_value = core_vector_at(self, first);
    last_value = core_vector_at(self, last);
    middle_value = core_vector_at(self, middle);

    if (compare(first_value, middle_value) <= 0 && compare(middle_value, last_value) <= 0) {
        return middle;

    } else if (compare(middle_value, first_value) <= 0 && compare(first_value, last_value) <= 0) {
        return first;
    }

    return last;
}
Exemple #3
0
/**
 * \see http://en.wikipedia.org/wiki/Quicksort
 */
int64_t core_vector_partition(struct core_vector *self,
                int64_t first, int64_t last, core_compare_fn_t compare,
                void *saved_pivot_value)
{
    int64_t pivot_index;
    void *pivot_value;
    int64_t store_index;
    void *other_value;
    int64_t i;
    int element_size;

    pivot_index = core_vector_select_pivot(self, first, last, compare);
    pivot_value = core_vector_at(self, pivot_index);
    element_size = core_vector_element_size(self);
    core_memory_copy(saved_pivot_value, pivot_value, element_size);

#ifdef CORE_VECTOR_HELPER_DEBUG
    printf("DEBUG ENTER partition first %d last %d pivot_index %d pivot_value %d ", (int)first, (int)last, (int)pivot_index,
                    *(int *)pivot_value);
    core_vector_print_int(self);
    printf("\n");
#endif

#ifdef CORE_VECTOR_HELPER_DEBUG
    printf("pivot_index %d pivot_value %d\n",
                    pivot_index, *(int *)pivot_value);
#endif

    core_vector_swap(self, pivot_index, last);

    store_index = first;

    for (i = first; i <= last - 1; i++) {

        other_value = core_vector_at(self, i);

        if (compare(other_value, saved_pivot_value) <= 0) {

            core_vector_swap(self, i, store_index);
            store_index = store_index + 1;
        }
    }

    core_vector_swap(self, store_index, last);

    pivot_index = store_index;

#ifdef CORE_VECTOR_HELPER_DEBUG
    printf("DEBUG EXIT partition first %d last %d pivot_index %d pivot_value %d ", (int)first, (int)last, (int)pivot_index,
                    *(int *)pivot_value);
    core_vector_print_int(self);
    printf("\n");
#endif

    return pivot_index;
}
Exemple #4
0
void core_vector_set(struct core_vector *self, int64_t index, void *data)
{
    void *bucket;

    bucket = core_vector_at(self, index);
    core_memory_copy(bucket, data, self->element_size);
}
Exemple #5
0
void biosal_input_controller_get_node_worker_count_reply(struct thorium_actor *actor, struct thorium_message *message)
{
    int tag;
    int source;
    void *buffer;
    int count;
    int index;
    struct biosal_input_controller *concrete_actor;
    int spawner;
    int worker_count;
    int *bucket;

    concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor);

    thorium_message_get_all(message, &tag, &count, &buffer, &source);
    spawner = source;
    thorium_message_unpack_int(message, 0, &worker_count);

    index = core_vector_index_of(&concrete_actor->spawners, &spawner);
    bucket = core_vector_at(&concrete_actor->stores_per_spawner, index);
    *bucket = worker_count * concrete_actor->stores_per_worker_per_spawner;

    printf("DEBUG spawner %d (node %d) is on a node that has %d workers\n", spawner,
                    index, worker_count);

    thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_CREATE_STORES);
}
Exemple #6
0
void thorium_actor_send_range_loop(struct thorium_actor *actor, struct core_vector *actors,
                int first, int last,
                struct thorium_message *message)
{
    int i;
    int the_actor;

#ifdef THORIUM_ACTOR_DEBUG1
    printf("DEBUG thorium_actor_send_range_default%i-%i\n",
                    first, last);
#endif

    i = first;

    while (i <= last) {

#ifdef THORIUM_ACTOR_DEBUG_20140601_1
        printf("DEBUG sending %d to %d\n",
                       thorium_message_action(message), i);
#endif
        the_actor = *(int *)core_vector_at(actors, i);

#ifdef DEBUG_BINOMIAL_TREE
        printf("send_range_loop, sending to %d\n", the_actor);
        thorium_message_print(message);
#endif

        thorium_actor_send(actor, the_actor, message);
        i++;
    }
}
void biosal_assembly_arc_classifier_verify_counters(struct thorium_actor *self)
{
    struct biosal_assembly_arc_classifier *concrete_self;

    concrete_self = (struct biosal_assembly_arc_classifier *)thorium_actor_concrete_actor(self);

#if 0
    size = core_vector_size(&concrete_self->consumers);
#endif

    /*
     * Don't do anything if the producer is not waiting anyway.
     */
    if (!concrete_self->producer_is_waiting) {
        return;
    }

    if (concrete_self->consumer_count_above_threshold > 0) {
        return;
    }

    /*
     * Make sure that we have enough memory available.
     * This verification is not performed if there are 0 active
     * requests.
     */
    /*
     * The code here is to make sure that there is enough memory.
     */

    if (concrete_self->active_requests > 0
            && !core_memory_has_enough_bytes()) {
        return;
    }

#if 0
    /*
     * Abort if at least one counter is above the threshold.
     */
    for (i = 0; i < size; i++) {
        bucket = core_vector_at(&concrete_self->pending_requests, i);
        active_count = *bucket;

        if (active_count > concrete_self->maximum_pending_request_count) {

            return;
        }
    }
#endif

    /*
     * Trigger an actor event now.
     */
    thorium_actor_send_empty(self, concrete_self->source,
             ACTION_ASSEMBLY_PUSH_ARC_BLOCK_REPLY);

    concrete_self->producer_is_waiting = 0;
}
Exemple #8
0
void core_vector_copy_range(struct core_vector *self, int64_t first, int64_t last, struct core_vector *destination)
{
    int64_t i;

    for (i = first; i <= last; i++) {

        core_vector_push_back(destination, core_vector_at(self, i));
    }
}
Exemple #9
0
void biosal_input_controller_receive_store_entry_counts(struct thorium_actor *actor, struct thorium_message *message)
{
    struct biosal_input_controller *concrete_actor;
    struct core_vector store_entries;
    void *buffer;
    int i;
    int store;
    uint64_t entries;
    struct thorium_message new_message;
    int name;

    core_vector_init(&store_entries, sizeof(uint64_t));

    concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor);
    buffer = thorium_message_buffer(message);
    name = thorium_actor_name(actor);
    concrete_actor->ready_consumers = 0;

#ifdef BIOSAL_INPUT_CONTROLLER_DEBUG
    printf("DEBUG biosal_input_controller_receive_store_entry_counts unpacking entries\n");
#endif

    core_vector_init(&store_entries, 0);
    core_vector_unpack(&store_entries, buffer);

    for (i = 0; i < core_vector_size(&store_entries); i++) {
        store = *(int *)core_vector_at(&concrete_actor->consumers, i);
        entries = *(uint64_t *)core_vector_at(&store_entries, i);

        printf("DEBUG controller/%d tells consumer/%d to reserve %" PRIu64 " buckets\n",
                        name, store, entries);

        thorium_message_init(&new_message, ACTION_RESERVE,
                        sizeof(entries), &entries);
        thorium_actor_send(actor, store, &new_message);
    }

#ifdef BIOSAL_INPUT_CONTROLLER_DEBUG
    printf("DEBUG biosal_input_controller_receive_store_entry_counts will wait for replies\n");
#endif

    core_vector_destroy(&store_entries);
}
void biosal_assembly_arc_classifier_receive(struct thorium_actor *self, struct thorium_message *message)
{
    int tag;
    void *buffer;
    struct biosal_assembly_arc_classifier *concrete_self;
    int size;
    int i;
    int *bucket;
    int source;
    int source_index;

    if (thorium_actor_take_action(self, message)) {
        return;
    }

    concrete_self = (struct biosal_assembly_arc_classifier *)thorium_actor_concrete_actor(self);
    tag = thorium_message_action(message);
    buffer = thorium_message_buffer(message);
    source = thorium_message_source(message);

    if (tag == ACTION_SET_CONSUMERS) {

        core_vector_unpack(&concrete_self->consumers, buffer);

        size = core_vector_size(&concrete_self->consumers);
        core_vector_resize(&concrete_self->pending_requests, size);

        for (i = 0; i < size; i++) {
            core_vector_set_int(&concrete_self->pending_requests, i, 0);
        }

        thorium_actor_send_reply_empty(self, ACTION_SET_CONSUMERS_REPLY);

    } else if (tag == ACTION_ASSEMBLY_PUSH_ARC_BLOCK_REPLY){

        /*
         * Decrease counter now.
         */
        source_index = core_vector_index_of(&concrete_self->consumers, &source);
        bucket = core_vector_at(&concrete_self->pending_requests, source_index);
        --(*bucket);
        --concrete_self->active_requests;

        /*
         * The previous value was maximum_pending_request_count + 1
         */
        if (*bucket == concrete_self->maximum_pending_request_count) {

            --concrete_self->consumer_count_above_threshold;
        }

        biosal_assembly_arc_classifier_verify_counters(self);
    }
}
Exemple #11
0
struct thorium_worker *thorium_worker_pool_select_worker_for_message_round_robin(struct thorium_worker_pool *self)
{
    struct thorium_worker *worker;

    worker = core_vector_at(&self->worker_array, self->worker_for_message);
    ++self->worker_for_message;
    if (self->worker_for_message == self->worker_count)
        self->worker_for_message = 0;

    return worker;
}
Exemple #12
0
void *core_vector_at_as_void_pointer(struct core_vector *self, int64_t index)
{
    void **bucket;

    bucket = (void **)core_vector_at(self, index);

    if (bucket == NULL) {
        return NULL;
    }

    return *bucket;
}
Exemple #13
0
float core_vector_at_as_float(struct core_vector *self, int64_t index)
{
    float *bucket;

    bucket = (float *)core_vector_at(self, index);

    if (bucket == NULL) {
        return -1;
    }

    return *bucket;
}
Exemple #14
0
char core_vector_at_as_char(struct core_vector *self, int64_t index)
{
    char *bucket;

    bucket = NULL;
    bucket = (char *)core_vector_at(self, index);

    if (bucket == NULL) {
        return -1;
    }

    return *bucket;
}
Exemple #15
0
/*
#define CORE_VECTOR_HELPER_DEBUG
*/
int core_vector_at_as_int(struct core_vector *self, int64_t index)
{
    int *bucket;

    bucket = NULL;
    bucket = (int *)core_vector_at(self, index);

    if (bucket != NULL) {
        return *bucket;
    }

    return -1;
}
Exemple #16
0
uint64_t core_vector_at_as_uint64_t(struct core_vector *self, int64_t index)
{
    uint64_t *bucket;

    bucket = NULL;
    bucket = (uint64_t *)core_vector_at(self, index);

    if (bucket == NULL) {
        return 0;
    }

    return *bucket;
}
Exemple #17
0
void biosal_input_controller_set_offset_reply(struct thorium_actor *self, struct thorium_message *message)
{
    int stream_index;
    int acquaintance_index;
    int source;
    int block_index;
    struct biosal_mega_block *block;
    struct biosal_input_controller *concrete_actor;
    int file_index;
    char *file_name;
    struct thorium_message new_message;

    source = thorium_message_source(message);
    acquaintance_index = source;
    concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(self);
    stream_index = core_vector_index_of(&concrete_actor->reading_streams, &acquaintance_index);

    block_index = core_map_get_int(&concrete_actor->assigned_blocks, &stream_index);

#ifdef BIOSAL_INPUT_CONTROLLER_DEBUG_READING_STREAMS
    printf("DEBUG got reply from stream/%d for offset, stream_index %d block_index %d\n", source,
                    stream_index, block_index);
#endif

    block = (struct biosal_mega_block *)core_vector_at(&concrete_actor->mega_block_vector,
                    block_index);

    file_index = biosal_mega_block_get_file(block);
    file_name = *(char **)core_vector_at(&concrete_actor->files, file_index);

    printf("DEBUG send ACTION_INPUT_OPEN %s\n", file_name);

    thorium_message_init(&new_message, ACTION_INPUT_OPEN, strlen(file_name) + 1, file_name);

    thorium_actor_send_reply(self, &new_message);

    thorium_message_destroy(&new_message);
}
Exemple #18
0
void thorium_worker_pool_create_workers(struct thorium_worker_pool *pool)
{
    int i;
    struct thorium_worker *worker;

    if (pool->worker_count <= 0) {
        return;
    }

    core_vector_init(&pool->worker_array, sizeof(struct thorium_worker));
#ifdef THORIUM_WORKER_POOL_USE_COUNT_CACHE
    core_vector_init(&pool->message_count_cache, sizeof(int));
#endif

    core_vector_resize(&pool->worker_array, pool->worker_count);
#ifdef THORIUM_WORKER_POOL_USE_COUNT_CACHE
    core_vector_resize(&pool->message_count_cache, pool->worker_count);
#endif

    pool->worker_cache = (struct thorium_worker *)core_vector_at(&pool->worker_array, 0);
#ifdef THORIUM_WORKER_POOL_USE_COUNT_CACHE
    pool->message_cache = (int *)core_vector_at(&pool->message_count_cache, 0);
#endif

    for (i = 0; i < pool->worker_count; i++) {

        worker = thorium_worker_pool_get_worker(pool, i);
        thorium_worker_init(worker, i, pool->node);

        if (pool->waiting_is_enabled) {
            thorium_worker_enable_waiting(worker);
        }

#ifdef THORIUM_WORKER_POOL_USE_COUNT_CACHE
        core_vector_set_int(&pool->message_count_cache, i, 0);
#endif
    }
}
Exemple #19
0
int core_vector_get_value(struct core_vector *self, int64_t index, void *value)
{
    void *bucket;

    bucket = core_vector_at(self, index);

    if (bucket == NULL) {
        return 0;
    }

    core_memory_copy(value, bucket, self->element_size);

    return 1;
}
Exemple #20
0
int64_t core_vector_index_of(struct core_vector *self, void *data)
{
    int64_t i;
    int64_t last;

    last = core_vector_size(self) - 1;

    for (i = 0; i <= last; i++) {
        if (memcmp(core_vector_at(self, i), data, self->element_size) == 0) {
            return i;
        }
    }

    return -1;
}
Exemple #21
0
void core_vector_update(struct core_vector *self, void *old_item, void *new_item)
{
    int64_t i;
    int64_t last;
    void *bucket;

    last = core_vector_size(self) - 1;

    for (i = 0; i <= last; i++) {
        bucket = core_vector_at(self, i);
        if (memcmp(bucket, old_item, self->element_size) == 0) {

            core_vector_set(self, i, new_item);
        }
    }
}
Exemple #22
0
void biosal_input_controller_destroy(struct thorium_actor *actor)
{
    struct biosal_input_controller *concrete_actor;
    int i;
    char *pointer;
    struct core_map_iterator iterator;
    struct core_vector *vector;

    concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor);

    core_timer_destroy(&concrete_actor->input_timer);
    core_timer_destroy(&concrete_actor->counting_timer);
    core_timer_destroy(&concrete_actor->distribution_timer);

    biosal_dna_codec_destroy(&concrete_actor->codec);

    for (i = 0; i < core_vector_size(&concrete_actor->files); i++) {
        pointer = *(char **)core_vector_at(&concrete_actor->files, i);
        core_memory_free(pointer, MEMORY_CONTROLLER);
    }

    core_vector_destroy(&concrete_actor->mega_block_vector);
    core_vector_destroy(&concrete_actor->counting_streams);
    core_vector_destroy(&concrete_actor->reading_streams);
    core_vector_destroy(&concrete_actor->partition_commands);
    core_vector_destroy(&concrete_actor->consumer_active_requests);
    core_vector_destroy(&concrete_actor->stream_consumers);
    core_vector_destroy(&concrete_actor->files);
    core_vector_destroy(&concrete_actor->spawners);
    core_vector_destroy(&concrete_actor->counts);
    core_vector_destroy(&concrete_actor->consumers);
    core_vector_destroy(&concrete_actor->stores_per_spawner);
    core_queue_destroy(&concrete_actor->unprepared_spawners);

    core_map_iterator_init(&iterator, &concrete_actor->mega_blocks);
    while (core_map_iterator_has_next(&iterator)) {
        core_map_iterator_next(&iterator, NULL, (void **)&vector);

        core_vector_destroy(vector);
    }
    core_map_iterator_destroy(&iterator);
    core_map_destroy(&concrete_actor->mega_blocks);
    core_map_destroy(&concrete_actor->assigned_blocks);
}
Exemple #23
0
void thorium_message_multiplexer_print_traffic_reduction(struct thorium_message_multiplexer *self)
{
    char buffer[1024];
    int position;
    int i;
    int size;
    struct thorium_multiplexed_buffer *multiplexed_buffer;
    int original_message_count;
    int real_message_count;
    float reduction;

    position = 0;

    position += sprintf(buffer + position, "[thorium] node %d worker %d multiplexer channels",
                    thorium_node_name(self->node), thorium_worker_name(self->worker));

    size = core_vector_size(&self->buffers);
    for (i = 0; i < size; ++i) {
        multiplexed_buffer = core_vector_at(&self->buffers, i);

        original_message_count = thorium_multiplexed_buffer_original_message_count(multiplexed_buffer);
        real_message_count = thorium_multiplexed_buffer_real_message_count(multiplexed_buffer);

        if (original_message_count == 0)
            continue;

        reduction = (0.0 + original_message_count - real_message_count) / original_message_count;
        reduction *= 100.0;

        position += sprintf(buffer + position, " [%d: %d %d %.2f%%]",
                        i, original_message_count, real_message_count,
                        reduction);
    }

    position += sprintf(buffer + position, "\n");

    thorium_printf("%s", buffer);
}
Exemple #24
0
void biosal_input_stream_open_reply(struct thorium_actor *self, struct thorium_message *message)
{
    struct biosal_input_stream *concrete_self;
    int i;
    int size;
    struct core_vector *vector;

    concrete_self = (struct biosal_input_stream *)thorium_actor_concrete_actor(self);

    ++concrete_self->finished_parallel_stream_count;

#if 0
    printf("DEBUG open_reply\n");
#endif

    if (concrete_self->finished_parallel_stream_count ==
                    core_vector_size(&concrete_self->parallel_streams)) {

        concrete_self->finished_parallel_stream_count = 0;

        size = core_vector_size(&concrete_self->parallel_streams);

        core_vector_resize(&concrete_self->parallel_mega_blocks,
                       size);

        for (i = 0; i < size; i++) {

            vector = core_vector_at(&concrete_self->parallel_mega_blocks, i);

            core_vector_init(vector, sizeof(struct biosal_mega_block));
        }

        thorium_actor_send_range_empty(self, &concrete_self->parallel_streams,
                        ACTION_INPUT_COUNT);
    }
}
Exemple #25
0
void core_vector_push_back(struct core_vector *self, void *data)
{
    int64_t index;
    int64_t new_maximum_size;
    void *bucket;

    CORE_DEBUGGER_ASSERT(data != NULL);

#ifdef CORE_VECTOR_DEBUG
    printf("DEBUG core_vector_push_back size %d max %d\n",
                    (int)self->size, (int)self->maximum_size);
#endif

    if (self->size + 1 > self->maximum_size) {

        new_maximum_size = 2 * self->maximum_size;

        if (new_maximum_size == 0) {
            new_maximum_size = CORE_VECTOR_INITIAL_BUCKET_COUNT;
        }

        core_vector_reserve(self, new_maximum_size);
        core_vector_push_back(self, data);
        return;
    }

    index = self->size;
    self->size++;
    bucket = core_vector_at(self, index);
    core_memory_copy(bucket, data, self->element_size);

#ifdef CORE_VECTOR_DEBUG
    printf("DEBUG core_vector_push_back new_size is %d, pushed in bucket %d, value in bucket %d\n",
                    self->size, index, *(int *)bucket);
#endif
}
Exemple #26
0
void biosal_input_controller_add_store(struct thorium_actor *actor, struct thorium_message *message)
{
    int source;
    int store;
    int index;
    struct biosal_input_controller *concrete_actor;
    int *bucket;

    /*
    printf("DEBUG biosal_input_controller_add_store\n");
    */

    concrete_actor = (struct biosal_input_controller *)thorium_actor_concrete_actor(actor);
    source = thorium_message_source(message);
    thorium_message_unpack_int(message, 0, &store);

    index = core_vector_index_of(&concrete_actor->spawners, &source);

    /*
    printf("DEBUG biosal_input_controller_add_store index %d\n", index);
    */

    bucket = core_vector_at(&concrete_actor->stores_per_spawner, index);

    /* the content of the bucket is initially the total number of
     * stores that are desired for this spawner.
     */
    *bucket = (*bucket - 1);
    core_vector_push_back(&concrete_actor->consumers, &store);

    thorium_actor_send_to_self_empty(actor, ACTION_INPUT_CONTROLLER_CREATE_STORES);

    /*
    printf("DEBUG remaining to spawn: %d (before returning)\n", *bucket);
    */
}
Exemple #27
0
void *core_vector_at_last(struct core_vector *self)
{
    return core_vector_at(self, core_vector_size(self) / 2);
}
Exemple #28
0
void *core_vector_at_middle(struct core_vector *self)
{
    return core_vector_at(self, core_vector_size(self) - 1);
}
Exemple #29
0
void *core_vector_at_first(struct core_vector *self)
{
    return core_vector_at(self, 0);
}
Exemple #30
0
void table_receive(struct thorium_actor *actor, struct thorium_message *message)
{
    int tag;
    int source;
    int name;
    int remote;
    struct thorium_message spawn_message;
    int script;
    int new_actor;
    void *buffer;
    struct table *table1;

    table1 = (struct table *)thorium_actor_concrete_actor(actor);
    source = thorium_message_source(message);
    tag = thorium_message_action(message);
    name = thorium_actor_name(actor);
    buffer = thorium_message_buffer(message);

    if (tag == ACTION_START) {
        printf("Actor %i receives ACTION_START from actor %i\n",
               name,  source);

        core_vector_init(&table1->spawners, 0);
        core_vector_unpack(&table1->spawners, buffer);

        remote = core_vector_index_of(&table1->spawners, &name) + 1;
        remote %= core_vector_size(&table1->spawners);

        script = SCRIPT_TABLE;
        thorium_message_init(&spawn_message, ACTION_SPAWN, sizeof(script), &script);
        thorium_actor_send(actor, *(int *)core_vector_at(&table1->spawners, remote), &spawn_message);

        /*
        printf("sending notification\n");
        thorium_message_init(message, ACTION_TABLE_NOTIFY, 0, NULL);
        thorium_actor_send(actor, 0, message);
        */
    } else if (tag == ACTION_SPAWN_REPLY) {

        new_actor= *(int *)buffer;

        printf("Actor %i receives ACTION_SPAWN_REPLY from actor %i,"
               " new actor is %d\n",
               name,  source, new_actor);

        thorium_message_init(message, ACTION_TABLE_DIE2, 0, NULL);
        thorium_actor_send(actor, new_actor, message);

        thorium_message_init(message, ACTION_TABLE_NOTIFY, 0, NULL);
        thorium_actor_send(actor, core_vector_at_as_int(&table1->spawners, 0), message);

    } else if (tag == ACTION_TABLE_DIE2) {

        printf("Actor %i receives ACTION_TABLE_DIE2 from actor %i\n",
               name,  source);

        if (name < core_vector_size(&table1->spawners)) {
            return;
        }

        thorium_message_init(message, ACTION_STOP, 0, NULL);
        thorium_actor_send(actor, name, message);

    } else if (tag == ACTION_TABLE_DIE) {

        printf("Actor %i receives ACTION_TABLE_DIE from actor %i\n",
               name,  source);

        thorium_message_init(message, ACTION_STOP, 0, NULL);
        thorium_actor_send(actor, name, message);

    } else if (tag == ACTION_TABLE_NOTIFY) {

        printf("Actor %i receives ACTION_TABLE_NOTIFY from actor %i\n",
               name,  source);

        table1->done++;

        if (table1->done == core_vector_size(&table1->spawners)) {
            printf("actor %d kills %d to %d\n",
                   name, 0, (int)core_vector_size(&table1->spawners) - 1);
            thorium_message_init(message, ACTION_TABLE_DIE, 0, NULL);
            thorium_actor_send_range(actor, &table1->spawners, message);
        }
    }
}