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 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; }
/* This can only be called from the CONSUMER */ int thorium_worker_dequeue_actor(struct thorium_worker *worker, struct thorium_actor **actor) { int value; int name; struct thorium_actor *other_actor; int other_name; int operations; int status; int mailbox_size; operations = 4; other_actor = NULL; /* Move an actor from the ring to the real actor scheduling queue */ while (operations-- && core_fast_ring_pop_from_consumer(&worker->actors_to_schedule, &other_actor)) { #ifdef CORE_DEBUGGER_ENABLE_ASSERT if (other_actor == NULL) { printf("NULL pointer pulled from ring, operations %d ring size %d\n", operations, core_fast_ring_size_from_consumer(&worker->actors_to_schedule)); } #endif CORE_DEBUGGER_ASSERT(other_actor != NULL); other_name = thorium_actor_name(other_actor); #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("ring.DEQUEUE %d\n", other_name); #endif if (core_set_find(&worker->evicted_actors, &other_name)) { #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("ALREADY EVICTED\n"); #endif continue; } if (!core_map_get_value(&worker->actors, &other_name, &status)) { /* Add the actor to the list of actors. * This does nothing if it is already in the list. */ status = STATUS_IDLE; core_map_add_value(&worker->actors, &other_name, &status); core_map_iterator_destroy(&worker->actor_iterator); core_map_iterator_init(&worker->actor_iterator, &worker->actors); } /* If the actor is not queued, queue it */ if (status == STATUS_IDLE) { status = STATUS_QUEUED; core_map_update_value(&worker->actors, &other_name, &status); thorium_scheduler_enqueue(&worker->scheduler, other_actor); } else { #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("SCHEDULER %d already scheduled to run, scheduled: %d\n", other_name, (int)core_set_size(&worker->queued_actors)); #endif } } /* Now, dequeue an actor from the real queue. * If it has more than 1 message, re-enqueue it */ value = thorium_scheduler_dequeue(&worker->scheduler, actor); /* Setting name to nobody; * check_production at the end uses the value and the name; * if value is false, check_production is not using name anyway. */ name = THORIUM_ACTOR_NOBODY; /* an actor is ready to be run and it was dequeued from the scheduling queue. */ if (value) { name = thorium_actor_name(*actor); #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("scheduler.DEQUEUE actor %d, removed from queued actors...\n", name); #endif mailbox_size = thorium_actor_get_mailbox_size(*actor); /* The actor has only one message and it is going to * be processed now. */ if (mailbox_size == 1) { #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("SCHEDULER %d has no message to schedule...\n", name); #endif /* Set the status of the worker to STATUS_IDLE * * TODO: the ring new tail might not be visible too. * That could possibly be a problem... */ status = STATUS_IDLE; core_map_update_value(&worker->actors, &name, &status); /* The actor still has a lot of messages * to process. Keep them coming. */ } else if (mailbox_size >= 2) { /* Add the actor to the scheduling queue if it * still has messages */ #ifdef THORIUM_WORKER_DEBUG_SCHEDULER printf("Scheduling actor %d again, messages: %d\n", name, thorium_actor_get_mailbox_size(*actor)); #endif /* The status is still STATUS_QUEUED */ thorium_scheduler_enqueue(&worker->scheduler, *actor); /* The actor is scheduled to run, but the new tail is not * yet visible apparently. * * Solution, push back the actor in the scheduler queue, it can take a few cycles to see cache changes across cores. (MESIF protocol) * * This is done below. */ } else /* if (mailbox_size == 0) */ { status = STATUS_IDLE; core_map_update_value(&worker->actors, &name, &status); value = 0; } } thorium_worker_check_production(worker, value, name); return value; }