void thorium_worker_pool_delete_workers(struct thorium_worker_pool *pool) { int i = 0; struct thorium_worker *worker; if (pool->worker_count <= 0) { return; } for (i = 0; i < pool->worker_count; i++) { worker = thorium_worker_pool_get_worker(pool, i); #if 0 printf("worker/%d loop_load %f\n", thorium_worker_name(worker), thorium_worker_get_loop_load(worker)); #endif thorium_worker_destroy(worker); } core_vector_destroy(&pool->worker_array); #ifdef THORIUM_WORKER_POOL_USE_COUNT_CACHE core_vector_destroy(&pool->message_count_cache); #endif }
void thorium_message_multiplexer_set_worker(struct thorium_message_multiplexer *self, struct thorium_worker *worker) { struct core_memory_pool *pool; self->worker = worker; pool = thorium_worker_get_memory_pool(self->worker, MEMORY_POOL_NAME_WORKER_PERSISTENT); #ifdef THORIUM_MULTIPLEXER_USE_TREE core_red_black_tree_init(&self->timeline, sizeof(uint64_t), sizeof(int), pool); core_red_black_tree_use_uint64_t_keys(&self->timeline); #elif defined(THORIUM_MULTIPLEXER_USE_HEAP) core_binary_heap_init(&self->timeline, sizeof(uint64_t), sizeof(int), CORE_BINARY_HEAP_MIN | CORE_BINARY_HEAP_UINT64_T_KEYS); core_binary_heap_set_memory_pool(&self->timeline, pool); #elif defined(THORIUM_MULTIPLEXER_USE_QUEUE) core_queue_init(&self->timeline, sizeof(int)); #endif if (thorium_node_name(self->node) == 0 && thorium_worker_name(self->worker) == 0 && thorium_node_must_print_data(self->node)) { thorium_printf("[thorium] message_multiplexer: disabled=%d buffer_size_in_bytes=%d timeout_in_nanoseconds=%d\n", CORE_BITMAP_GET_FLAG(self->flags, FLAG_DISABLED), self->buffer_size_in_bytes, self->timeout_in_nanoseconds); } }
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); }
void thorium_message_multiplexer_flush(struct thorium_message_multiplexer *self, int index, int force) { char *buffer; struct thorium_message message; int tag; int count; int current_size; int maximum_size; struct thorium_multiplexed_buffer *multiplexed_buffer; int destination_node; /* int elapsed; int message_count; */ if (CORE_BITMAP_GET_FLAG(self->flags, FLAG_DISABLED)) { return; } #ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT #ifdef CORE_DEBUGGER_ASSERT_ENABLED if (!(core_set_find(&self->buffers_with_content, &index))) { multiplexed_buffer = core_vector_at(&self->buffers, index); thorium_printf("index %d has no content\n", index); thorium_multiplexed_buffer_print(multiplexed_buffer); } #endif CORE_DEBUGGER_ASSERT(core_set_find(&self->buffers_with_content, &index)); #endif multiplexed_buffer = core_vector_at(&self->buffers, index); current_size = thorium_multiplexed_buffer_current_size(multiplexed_buffer); maximum_size = thorium_multiplexed_buffer_maximum_size(multiplexed_buffer); /* * The buffer was still in the timeline, but it was flushed elsewhere. */ if (current_size == 0) { return; /* if (force == FORCE_NO && current_size < maximum_size) { return; } else if (force == FORCE_YES_TIME) { elapsed = core_timer_get_nanoseconds(&self->timer) - multiplexed_buffer->timestamp_; if (elapsed < self->timeout_in_nanoseconds) { return; } } else if (force == FORCE_YES_DOA) { message_count = multiplexed_buffer->message_count_; if (message_count < self->degree_of_aggregation_limit) { return; } */ } #ifdef CORE_DEBUGGER_ASSERT_ENABLED if (current_size <= 0) thorium_printf("current_size %d maximum_size %d\n", current_size, maximum_size); #endif CORE_DEBUGGER_ASSERT(current_size > 0); buffer = thorium_multiplexed_buffer_buffer(multiplexed_buffer); count = current_size + THORIUM_MESSAGE_METADATA_SIZE; tag = ACTION_MULTIPLEXER_MESSAGE; /* * This count does not include metadata for the final big message. * * Avoid this copy by using an array of pointers in the first place. */ destination_node = index; thorium_message_init(&message, tag, count, buffer); thorium_message_set_destination(&message, destination_node); thorium_message_set_source(&message, thorium_node_name(self->node)); /* * Mark the message so that the buffer is eventually sent back here * for recycling. */ thorium_message_set_worker(&message, thorium_worker_name(self->worker)); thorium_message_write_metadata(&message); #ifdef DEBUG_MULTIPLEXER_FLUSH thorium_printf("DEBUG_MULTIPLEXER thorium_message_multiplexer_flush index %d buffer %p force %d current_size %d maximum_size %d" " destination_node %d\n", index, buffer, force, current_size, maximum_size, thorium_message_destination_node(&message)); thorium_printf("message in flush\n"); thorium_multiplexed_buffer_print(multiplexed_buffer); thorium_message_print(&message); #endif CORE_DEBUGGER_ASSERT_NOT_NULL(self->worker); /* * Make a copy of the buffer because the multiplexer does not have communication buffers. */ thorium_worker_enqueue_outbound_message(self->worker, &message); /* thorium_printf("MULTIPLEXER FLUSH\n"); */ ++self->real_message_count; thorium_message_destroy(&message); thorium_multiplexed_buffer_reset(multiplexed_buffer); #ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT core_set_delete(&self->buffers_with_content, &index); #endif }
/* * Returns 1 if the message was demultiplexed. * * This is O(1) in regard to the number of thorium nodes. */ int thorium_message_multiplexer_demultiplex(struct thorium_message_multiplexer *self, struct thorium_message *message) { /* * Algorithm: * * get tag. * if tag is ACTION_MULTIPLEXER_MESSAGE * for every enclosed message * call thorium_node_prepare_received_message * call thorium_node_dispatch_message() * return 1 * * return 0 */ int count; char *buffer; struct thorium_message new_message; int new_count; void *new_buffer; int position; struct core_memory_pool *pool; int messages; int tag; int source_node; int destination_node; int current_node; int routing_destination; #ifdef DEBUG_MULTIPLEXER thorium_printf("demultiplex message\n"); thorium_message_print(message); #endif if (CORE_BITMAP_GET_FLAG(self->flags, FLAG_DISABLED)) { return 0; } tag = thorium_message_action(message); if (tag != ACTION_MULTIPLEXER_MESSAGE) { return 0; } /* thorium_printf("MULTIPLEXER demultiplex\n"); */ messages = 0; tracepoint(thorium_node, demultiplex_enter, self->node->name, self->node->tick, messages); source_node = thorium_message_source_node(message); destination_node = thorium_message_destination_node(message); /* * Remove the metadata from the count. */ thorium_message_remove_metadata_from_count(message); count = thorium_message_count(message); buffer = thorium_message_buffer(message); pool = thorium_worker_get_outbound_message_memory_pool(self->worker); position = 0; /* * Inject a message for each enclosed message. */ while (position < count) { core_memory_copy(&new_count, buffer + position, sizeof(new_count)); position += sizeof(new_count); new_buffer = core_memory_pool_allocate(pool, new_count); core_memory_copy(new_buffer, buffer + position, new_count); thorium_message_init_with_nodes(&new_message, new_count, new_buffer, source_node, destination_node); thorium_node_prepare_received_message(self->node, &new_message); /* * For these demultiplexed messages, there are 2 outcomes: * * 1) the message must be delivered locally; * 2) the message must be forward because this is a middle node in * the route. */ /* thorium_printf("demultiplex: \n"); thorium_message_print(&new_message); thorium_printf("\n"); */ /* * Mark the message for recycling. */ thorium_message_set_worker(&new_message, thorium_worker_name(self->worker)); #ifdef CORE_DEBUGGER_ASSERT_ENABLED if (thorium_message_action(&new_message) == ACTION_INVALID) { thorium_printf("Error invalid action DEMUL Multiplexer position %d count %d new_count %d\n", position, count, new_count); thorium_message_print(&new_message); } #endif CORE_DEBUGGER_ASSERT(thorium_message_action(&new_message) != ACTION_INVALID); /* thorium_printf("DEMULTIPLEX_MESSAGE\n"); */ /* thorium_printf("demultiplex, local delivery: \n"); thorium_message_print(&new_message); */ current_node = self->node->name; routing_destination = new_message.routing_destination; CORE_DEBUGGER_ASSERT(routing_destination >= 0); /* * This is a local delivery, nothing to see here. */ if (routing_destination == current_node) { thorium_worker_send_local_delivery(self->worker, &new_message); /* * Otherwise, get the next node in the route and send the * payload there since we can not do anything with it here. */ } else { /* * Export the message to another node. * To do this, use an exporter worker. */ thorium_worker_send_for_multiplexer(self->worker, &new_message); } /* thorium_message_destroy(&new_message); */ position += new_count; ++messages; } CORE_DEBUGGER_ASSERT(messages > 0); #ifdef DEBUG_MULTIPLEXER thorium_printf("thorium_message_multiplexer_demultiplex %d messages\n", messages); #endif tracepoint(thorium_node, demultiplex_exit, self->node->name, self->node->tick, messages); return 1; }
void thorium_message_multiplexer_destroy(struct thorium_message_multiplexer *self) { int i; int size; struct thorium_multiplexed_buffer *multiplexed_buffer; float ratio; if (thorium_node_must_print_data(self->node)) { ratio = 0.0; if (self->original_message_count != 0) { ratio = self->real_message_count / (0.0 + self->original_message_count); /* * Jack M. Nilles * "Traffic reduction by telecommuting: A status review and selected bibliography" * Transportation Research Part A: General * Volume 22, Issue 4, July 1988, Pages 301–317. * * @see http://www.sciencedirect.com/science/article/pii/0191260788900088 * @see http://ww2.cityofpasadena.net/councilagendas/2007%20agendas/feb_26_07/pasadena%20traffic%20reduction%20strategies%2011-20-06%20draft.pdf */ thorium_printf("[thorium] node %d worker %d message_multiplexer:" " original_message_count %d real_message_count %d (traffic reduction: %.2f%%)\n", thorium_node_name(self->node), thorium_worker_name(self->worker), self->original_message_count, self->real_message_count, (1.0 - ratio) * 100); thorium_message_multiplexer_print_traffic_reduction(self); } } #ifdef CORE_DEBUGGER_ASSERT_ENABLED #endif size = core_vector_size(&self->buffers); #ifdef THORIUM_MULTIPLEXER_TRACK_BUFFERS_WITH_CONTENT /* * There can be no messages that are not flushed already. */ CORE_DEBUGGER_ASSERT(core_set_empty(&self->buffers_with_content)); core_set_destroy(&self->buffers_with_content); #endif for (i = 0; i < size; ++i) { multiplexed_buffer = core_vector_at(&self->buffers, i); CORE_DEBUGGER_ASSERT(thorium_multiplexed_buffer_current_size(multiplexed_buffer) == 0); thorium_multiplexed_buffer_destroy(multiplexed_buffer); } core_vector_destroy(&self->buffers); self->node = NULL; self->buffer_size_in_bytes = -1; self->timeout_in_nanoseconds = -1; core_timer_destroy(&self->timer); #ifdef THORIUM_MULTIPLEXER_USE_TREE core_red_black_tree_destroy(&self->timeline); #elif defined(THORIUM_MULTIPLEXER_USE_HEAP) core_binary_heap_destroy(&self->timeline); #elif defined(THORIUM_MULTIPLEXER_USE_QUEUE) core_queue_destroy(&self->timeline); #endif thorium_decision_maker_destroy(&self->decision_maker); thorium_router_destroy(&self->router); }
void thorium_worker_init(struct thorium_worker *worker, int name, struct thorium_node *node) { int capacity; int ephemeral_memory_block_size; int injected_buffer_ring_size; int argc; char **argv; worker->tick_count = 0; thorium_load_profiler_init(&worker->profiler); argc = thorium_node_argc(node); argv = thorium_node_argv(node); #ifdef THORIUM_WORKER_DEBUG_INJECTION worker->counter_allocated_outbound_buffers = 0; worker->counter_freed_outbound_buffers_from_self = 0; worker->counter_freed_outbound_buffers_from_other_workers = 0; worker->counter_injected_outbound_buffers_other_local_workers= 0; worker->counter_injected_inbound_buffers_from_thorium_core = 0; #endif core_map_init(&worker->actor_received_messages, sizeof(int), sizeof(int)); worker->waiting_is_enabled = 0; worker->waiting_start_time = 0; core_timer_init(&worker->timer); capacity = THORIUM_WORKER_RING_CAPACITY; /*worker->work_queue = work_queue;*/ worker->node = node; worker->name = name; core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_DEAD); worker->last_warning = 0; worker->last_wake_up_count = 0; /*worker->work_queue = &worker->works;*/ /* There are two options: * 1. enable atomic operations for change visibility * 2. Use volatile head and tail. */ core_fast_ring_init(&worker->actors_to_schedule, capacity, sizeof(struct thorium_actor *)); #ifdef THORIUM_NODE_INJECT_CLEAN_WORKER_BUFFERS injected_buffer_ring_size = capacity; core_fast_ring_init(&worker->injected_clean_outbound_buffers, injected_buffer_ring_size, sizeof(void *)); core_fast_ring_init(&worker->clean_message_ring_for_triage, injected_buffer_ring_size, sizeof(struct thorium_message)); core_fast_queue_init(&worker->clean_message_queue_for_triage, sizeof(struct thorium_message)); #endif thorium_scheduler_init(&worker->scheduler, thorium_node_name(worker->node), worker->name); core_map_init(&worker->actors, sizeof(int), sizeof(int)); core_map_iterator_init(&worker->actor_iterator, &worker->actors); core_fast_ring_init(&worker->outbound_message_queue, capacity, sizeof(struct thorium_message)); core_fast_queue_init(&worker->outbound_message_queue_buffer, sizeof(struct thorium_message)); core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_DEBUG); core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_BUSY); core_bitmap_clear_bit_uint32_t(&node->flags, FLAG_ENABLE_ACTOR_LOAD_PROFILER); worker->flags = 0; core_bitmap_clear_bit_uint32_t(&worker->flags, FLAG_DEBUG_ACTORS); if (core_command_has_argument(argc, argv, DEBUG_WORKER_OPTION)) { #if 0 printf("DEBUG has option %s\n", DEBUG_WORKER_OPTION); #endif if (thorium_node_name(worker->node) == 0 && thorium_worker_name(worker) == 0) { #if 0 printf("DEBUG setting bit FLAG_DEBUG_ACTORS because %s\n", DEBUG_WORKER_OPTION); #endif core_bitmap_set_bit_uint32_t(&worker->flags, FLAG_DEBUG_ACTORS); } } worker->epoch_used_nanoseconds = 0; worker->loop_used_nanoseconds = 0; worker->scheduling_epoch_used_nanoseconds = 0; worker->started_in_thread = 0; /* 2 MiB is the default size for Linux huge pages. * \see https://wiki.debian.org/Hugepages * \see http://lwn.net/Articles/376606/ */ /* * 8 MiB */ ephemeral_memory_block_size = 8388608; /*ephemeral_memory_block_size = 16777216;*/ core_memory_pool_init(&worker->ephemeral_memory, ephemeral_memory_block_size, MEMORY_POOL_NAME_WORKER_EPHEMERAL); core_memory_pool_disable_tracking(&worker->ephemeral_memory); core_memory_pool_enable_ephemeral_mode(&worker->ephemeral_memory); #ifdef THORIUM_WORKER_ENABLE_LOCK core_lock_init(&worker->lock); #endif core_set_init(&worker->evicted_actors, sizeof(int)); core_memory_pool_init(&worker->outbound_message_memory_pool, CORE_MEMORY_POOL_MESSAGE_BUFFER_BLOCK_SIZE, MEMORY_POOL_NAME_WORKER_OUTBOUND); /* * Disable the pool so that it uses allocate and free * directly. */ #ifdef CORE_MEMORY_POOL_DISABLE_MESSAGE_BUFFER_POOL core_memory_pool_disable(&worker->outbound_message_memory_pool); #endif /* * Transport message buffers are fancy objects. */ core_memory_pool_enable_normalization(&worker->outbound_message_memory_pool); core_memory_pool_enable_alignment(&worker->outbound_message_memory_pool); worker->ticks_without_production = 0; thorium_priority_assigner_init(&worker->assigner, thorium_worker_name(worker)); /* * This variables should be set in * thorium_worker_start, but when running on 1 process with 1 thread, * thorium_worker_start is never called... */ worker->last_report = time(NULL); worker->epoch_start_in_nanoseconds = core_timer_get_nanoseconds(&worker->timer); worker->loop_start_in_nanoseconds = worker->epoch_start_in_nanoseconds; worker->loop_end_in_nanoseconds = worker->loop_start_in_nanoseconds; worker->scheduling_epoch_start_in_nanoseconds = worker->epoch_start_in_nanoseconds; /* * Avoid valgrind warnings. */ worker->epoch_load = 0; }
void thorium_worker_display(struct thorium_worker *worker) { printf("[thorium_worker_main] node %i worker %i\n", thorium_node_name(worker->node), thorium_worker_name(worker)); }
void thorium_worker_work(struct thorium_worker *worker, struct thorium_actor *actor) { int dead; int actor_name; #ifdef THORIUM_WORKER_DEBUG int tag; int destination; #endif actor_name = thorium_actor_name(actor); #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("WORK actor %d\n", actor_name); #endif /* the actor died while the work was queued. */ if (thorium_actor_dead(actor)) { printf("NOTICE actor is dead already (thorium_worker_work)\n"); return; } #ifdef THORIUM_DISABLE_LOCKLESS_ACTORS /* lock the actor to prevent another worker from making work * on the same actor at the same time */ if (thorium_actor_trylock(actor) != CORE_LOCK_SUCCESS) { #ifdef SHOW_FULL_RING_WARNINGS printf("Warning: CONTENTION worker %d could not lock actor %d, returning the message...\n", thorium_worker_name(worker), actor_name); #endif return; } #endif /* the actor died while this worker was waiting for the lock */ if (thorium_actor_dead(actor)) { printf("DEBUG thorium_worker_work actor died while the worker was waiting for the lock.\n"); #ifdef THORIUM_WORKER_DEBUG #endif /*thorium_actor_unlock(actor);*/ return; } /* call the actor receive code */ thorium_actor_set_worker(actor, worker); thorium_actor_work(actor); /* Free ephemeral memory */ core_memory_pool_free_all(&worker->ephemeral_memory); dead = thorium_actor_dead(actor); if (dead) { core_map_delete(&worker->actors, &actor_name); if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_ENABLE_ACTOR_LOAD_PROFILER)) { thorium_actor_write_profile(actor, &worker->load_profile_writer); } thorium_node_notify_death(worker->node, actor); } thorium_actor_set_worker(actor, NULL); #ifdef THORIUM_WORKER_DEBUG_20140601 if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG)) { printf("DEBUG worker/%d after dead call\n", thorium_worker_name(worker)); } #endif #ifdef THORIUM_DISABLE_LOCKLESS_ACTORS /* Unlock the actor. * This does not do anything if a death notification * was sent to the node */ thorium_actor_unlock(actor); #endif #ifdef THORIUM_WORKER_DEBUG printf("thorium_worker_work Freeing buffer %p %i tag %i\n", buffer, thorium_message_count(message), thorium_message_action(message)); #endif #ifdef THORIUM_WORKER_DEBUG_20140601 if (core_bitmap_get_bit_uint32_t(&worker->flags, FLAG_DEBUG)) { printf("DEBUG worker/%d exiting thorium_worker_work\n", thorium_worker_name(worker)); } #endif }
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 }