/* This can only be called from the PRODUCER */ int thorium_worker_enqueue_actor(struct thorium_worker *worker, struct thorium_actor *actor) { int value; CORE_DEBUGGER_ASSERT(actor != NULL); value = core_fast_ring_push_from_producer(&worker->actors_to_schedule, &actor); #ifdef SHOW_FULL_RING_WARNINGS if (!value) { printf("thorium_worker: Warning: ring is full, actors_to_schedule\n"); } #endif /* * Do a wake up if necessary when scheduling an actor in * the scheduling queue. */ if (value && worker->waiting_is_enabled) { /* * This call checks if the thread is currently waiting. * If it is currently waiting, then a signal is sent * to tell the operating system to wake up the thread so that * it continues its good work for the actor computation in thorium. */ thorium_worker_signal(worker); } return value; }
int thorium_worker_enqueue_message_for_triage(struct thorium_worker *worker, struct thorium_message *message) { #ifdef THORIUM_WORKER_DEBUG_INJECTION int worker_name; #endif CORE_DEBUGGER_ASSERT(thorium_message_buffer(message) != NULL); if (!core_fast_ring_push_from_producer(&worker->clean_message_ring_for_triage, message)) { #ifdef SHOW_FULL_RING_WARNINGS printf("thorium_worker: Warning: ring is full, clean_message_ring_for_triage action= %x\n", thorium_message_action(message)); #endif core_fast_queue_enqueue(&worker->clean_message_queue_for_triage, message); #ifdef THORIUM_WORKER_DEBUG_INJECTION } else { /* * Update software counters. */ worker_name = thorium_message_worker(message); if (worker_name >= 0) { ++worker->counter_injected_outbound_buffers_other_local_workers; } else { ++worker->counter_injected_inbound_buffers_from_thorium_core; } #endif } return 1; }
void thorium_worker_evict_actor(struct thorium_worker *worker, int actor_name) { struct thorium_actor *actor; int name; struct core_fast_queue saved_actors; int count; int value; core_set_add(&worker->evicted_actors, &actor_name); core_map_delete(&worker->actors, &actor_name); core_fast_queue_init(&saved_actors, sizeof(struct thorium_actor *)); /* evict the actor from the scheduling queue */ while (thorium_scheduler_dequeue(&worker->scheduler, &actor)) { name = thorium_actor_name(actor); if (name != actor_name) { core_fast_queue_enqueue(&saved_actors, &actor); } } while (core_fast_queue_dequeue(&saved_actors, &actor)) { thorium_scheduler_enqueue(&worker->scheduler, actor); } core_fast_queue_destroy(&saved_actors); /* Evict the actor from the ring */ count = core_fast_ring_size_from_consumer(&worker->actors_to_schedule); while (count-- && core_fast_ring_pop_from_consumer(&worker->actors_to_schedule, &actor)) { name = thorium_actor_name(actor); if (name != actor_name) { /* * This can not fail logically. */ value = core_fast_ring_push_from_producer(&worker->actors_to_schedule, &actor); CORE_DEBUGGER_ASSERT(value); } } core_map_iterator_destroy(&worker->actor_iterator); core_map_iterator_init(&worker->actor_iterator, &worker->actors); }
int thorium_worker_inject_clean_outbound_buffer(struct thorium_worker *self, void *buffer) { int value; value = core_fast_ring_push_from_producer(&self->injected_clean_outbound_buffers, &buffer); #ifdef SHOW_FULL_RING_WARNINGS if (!value) { printf("thorium_worker: Warning: ring is full, injected_clean_outbound_buffers\n"); } #endif return value; }
int thorium_worker_enqueue_message(struct thorium_worker *worker, struct thorium_message *message) { /* Try to push the message in the output ring */ if (!core_fast_ring_push_from_producer(&worker->outbound_message_queue, message)) { #ifdef SHOW_FULL_RING_WARNINGS printf("thorium_worker: Warning: ring is full, outbound_message_queue\n"); #endif /* If that does not work, push the message in the queue buffer. */ core_fast_queue_enqueue(&worker->outbound_message_queue_buffer, message); } return 1; }
int main(int argc, char **argv) { BEGIN_TESTS(); struct core_fast_ring ring; int capacity = 64; int i; int value; int elements; elements = 0; #if 0 printf("Required %d\n", capacity); #endif core_fast_ring_init(&ring, capacity, sizeof(int)); capacity = core_fast_ring_capacity(&ring); #if 0 printf("Provided %d\n", capacity); #endif TEST_BOOLEAN_EQUALS(core_fast_ring_is_empty_from_consumer(&ring), 1); for (i = 0; i < capacity; i++) { TEST_BOOLEAN_EQUALS(core_fast_ring_push_from_producer(&ring, &i), 1); elements++; TEST_INT_EQUALS(core_fast_ring_size_from_producer(&ring), elements); TEST_INT_EQUALS(core_fast_ring_size_from_consumer(&ring), elements); } TEST_BOOLEAN_EQUALS(core_fast_ring_is_full_from_producer(&ring), 1); for (i = 0; i < capacity; i++) { TEST_BOOLEAN_EQUALS(core_fast_ring_pop_from_consumer(&ring, &value), 1); elements--; TEST_INT_EQUALS(value, i); TEST_INT_EQUALS(core_fast_ring_size_from_producer(&ring), elements); TEST_INT_EQUALS(core_fast_ring_size_from_consumer(&ring), elements); } core_fast_ring_destroy(&ring); { struct core_fast_ring ring; int capacity = 64; struct thorium_message message; int action; int count; void *buffer; int inserted; int pulled; action = 1234; count = 0; buffer = NULL; thorium_message_init(&message, action, count, buffer); core_fast_ring_init(&ring, capacity, sizeof(struct thorium_message)); core_fast_ring_use_multiple_producers(&ring); inserted = 0; while (core_fast_ring_push_from_producer(&ring, &message)) { ++inserted; } /* * 64 + 1 = 65, 128 is the next power of 2 for the mask. */ /* TEST_INT_EQUALS(inserted, capacity); */ pulled = 0; while (core_fast_ring_pop_from_consumer(&ring, &message)) { ++pulled; } TEST_INT_EQUALS(inserted, pulled); core_fast_ring_destroy(&ring); thorium_message_destroy(&message); } END_TESTS(); return 0; }
void thorium_worker_run(struct thorium_worker *worker) { struct thorium_actor *actor; struct thorium_message other_message; #ifdef THORIUM_NODE_INJECT_CLEAN_WORKER_BUFFERS void *buffer; #endif #ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION time_t current_time; int elapsed; int period; uint64_t current_nanoseconds; uint64_t elapsed_nanoseconds; #endif #ifdef THORIUM_WORKER_DEBUG int tag; int destination; struct thorium_message *message; #endif #ifdef THORIUM_WORKER_ENABLE_LOCK thorium_worker_lock(worker); #endif #ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION period = THORIUM_NODE_LOAD_PERIOD; current_time = time(NULL); elapsed = current_time - worker->last_report; if (elapsed >= period) { current_nanoseconds = core_timer_get_nanoseconds(&worker->timer); #ifdef THORIUM_WORKER_DEBUG_LOAD printf("DEBUG Updating load report\n"); #endif elapsed_nanoseconds = current_nanoseconds - worker->epoch_start_in_nanoseconds; if (elapsed_nanoseconds > 0) { worker->epoch_load = (0.0 + worker->epoch_used_nanoseconds) / elapsed_nanoseconds; worker->epoch_used_nanoseconds = 0; worker->last_wake_up_count = core_thread_get_wake_up_count(&worker->thread); /* \see http://stackoverflow.com/questions/9657993/negative-zero-in-c */ if (worker->epoch_load == 0) { worker->epoch_load = 0; } worker->epoch_start_in_nanoseconds = current_nanoseconds; worker->last_report = current_time; } #ifdef THORIUM_WORKER_PRINT_SCHEDULING_QUEUE /* if (thorium_node_name(worker->node) == 0 && worker->name == 0) { */ thorium_scheduler_print(&worker->scheduler, thorium_node_name(worker->node), worker->name); /* } */ #endif if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG_ACTORS)) { thorium_worker_print_actors(worker, NULL); } } #endif #ifdef THORIUM_WORKER_DEBUG if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG)) { printf("DEBUG worker/%d thorium_worker_run\n", thorium_worker_name(worker)); } #endif /* check for messages in inbound FIFO */ if (thorium_worker_dequeue_actor(worker, &actor)) { #ifdef THORIUM_WORKER_DEBUG message = biosal_work_message(&work); tag = thorium_message_action(message); destination = thorium_message_destination(message); if (tag == ACTION_ASK_TO_STOP) { printf("DEBUG pulled ACTION_ASK_TO_STOP for %d\n", destination); } #endif /* * Update the priority of the actor * before starting the timer because this is part of the * runtime system (RTS). */ #ifdef THORIUM_UPDATE_SCHEDULING_PRIORITIES thorium_priority_assigner_update(&worker->scheduler, actor); #endif #ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION core_timer_start(&worker->timer); #endif core_bitmap_set_bit_uint32_t(&worker->flags, FLAG_BUSY); /* * Dispatch message to a worker */ thorium_worker_work(worker, actor); core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_BUSY); #ifdef THORIUM_NODE_ENABLE_INSTRUMENTATION core_timer_stop(&worker->timer); elapsed_nanoseconds = core_timer_get_elapsed_nanoseconds(&worker->timer); if (elapsed_nanoseconds >= THORIUM_GRANULARITY_WARNING_THRESHOLD) { } worker->epoch_used_nanoseconds += elapsed_nanoseconds; worker->loop_used_nanoseconds += elapsed_nanoseconds; worker->scheduling_epoch_used_nanoseconds += elapsed_nanoseconds; worker->last_elapsed_nanoseconds = elapsed_nanoseconds; #endif } /* queue buffered message */ if (core_fast_queue_dequeue(&worker->outbound_message_queue_buffer, &other_message)) { if (!core_fast_ring_push_from_producer(&worker->outbound_message_queue, &other_message)) { #ifdef SHOW_FULL_RING_WARNINGS printf("thorium_worker: Warning: ring is full => outbound_message_queue\n"); #endif core_fast_queue_enqueue(&worker->outbound_message_queue_buffer, &other_message); } } #ifdef THORIUM_NODE_INJECT_CLEAN_WORKER_BUFFERS /* * Free outbound buffers, if any */ if (thorium_worker_fetch_clean_outbound_buffer(worker, &buffer)) { core_memory_pool_free(&worker->outbound_message_memory_pool, buffer); #ifdef THORIUM_WORKER_DEBUG_INJECTION ++worker->counter_freed_outbound_buffers_from_other_workers; #endif } #endif /* * Transfer messages for triage */ if (core_fast_queue_dequeue(&worker->clean_message_queue_for_triage, &other_message)) { CORE_DEBUGGER_ASSERT(thorium_message_buffer(&other_message) != NULL); thorium_worker_enqueue_message_for_triage(worker, &other_message); } #ifdef THORIUM_WORKER_ENABLE_LOCK thorium_worker_unlock(worker); #endif }