void networkinterface_wantsSend(NetworkInterface* interface, Socket* socket) { MAGIC_ASSERT(interface); /* track the new socket for sending if not already tracking */ switch(interface->qdisc) { case NIQ_RR: { if(!g_queue_find(interface->rrQueue, socket)) { descriptor_ref(socket); g_queue_push_tail(interface->rrQueue, socket); } break; } case NIQ_FIFO: default: { if(!priorityqueue_find(interface->fifoQueue, socket)) { descriptor_ref(socket); priorityqueue_push(interface->fifoQueue, socket); } break; } } /* trigger a send if we are currently idle */ if(!(interface->flags & NIF_SENDING)) { _networkinterface_scheduleNextSend(interface); } }
gboolean asyncpriorityqueue_push(AsyncPriorityQueue *q, gpointer data) { g_assert(q); g_mutex_lock(&(q->lock)); gboolean returnVal = priorityqueue_push(q->pq, data); g_mutex_unlock(&(q->lock)); return returnVal; }
static void _schedulerpolicyhoststeal_push(SchedulerPolicy* policy, Event* event, Host* srcHost, Host* dstHost, SimulationTime barrier) { MAGIC_ASSERT(policy); HostStealPolicyData* data = policy->data; /* non-local events must be properly delayed so the event wont show up at another host * before the next scheduling interval. if the thread scheduler guaranteed to always run * the minimum time event accross all of its assigned hosts, then we would only need to * do the time adjustment if the srcThread and dstThread are not identical. however, * the logic of this policy allows a thread to run all events from a given host before * moving on to the next host, so we must adjust the time whenever the srcHost and * dstHost are not the same. */ SimulationTime eventTime = event_getTime(event); if(srcHost != dstHost && eventTime < barrier) { event_setTime(event, barrier); info("Inter-host event time %"G_GUINT64_FORMAT" changed to %"G_GUINT64_FORMAT" " "to ensure event causality", eventTime, barrier); } g_rw_lock_reader_lock(&data->lock); /* we want to track how long this thread spends idle waiting to push the event */ HostStealThreadData* tdata = g_hash_table_lookup(data->threadToThreadDataMap, GUINT_TO_POINTER(pthread_self())); /* get the queue for the destination */ HostStealQueueData* qdata = g_hash_table_lookup(data->hostToQueueDataMap, dstHost); g_rw_lock_reader_unlock(&data->lock); utility_assert(qdata); /* tracking idle time spent waiting for the destination queue lock */ if(tdata) { g_timer_continue(tdata->pushIdleTime); g_mutex_lock(&(tdata->lock)); } g_mutex_lock(&(qdata->lock)); if(tdata) { g_timer_stop(tdata->pushIdleTime); } /* 'deliver' the event to the destination queue */ priorityqueue_push(qdata->pq, event); qdata->nPushed++; /* release the destination queue lock */ g_mutex_unlock(&(qdata->lock)); if(tdata) { g_mutex_unlock(&(tdata->lock)); } }
/* first-in-first-out queuing discipline ($ man tc)*/ static Packet* _networkinterface_selectFirstInFirstOut(NetworkInterface* interface, gint* socketHandle) { /* use packet priority field to select based on application ordering. * this is really a simplification of prioritizing on timestamps. */ Packet* packet = NULL; while(!packet && !priorityqueue_isEmpty(interface->fifoQueue)) { /* do fifo to get the next packet from the next socket */ Socket* socket = priorityqueue_pop(interface->fifoQueue); packet = socket_pullOutPacket(socket); *socketHandle = *descriptor_getHandleReference((Descriptor*)socket); if(socket_peekNextPacket(socket)) { /* socket has more packets, and is still reffed from before */ priorityqueue_push(interface->fifoQueue, socket); } else { /* socket has no more packets, unref it from the sendable queue */ descriptor_unref((Descriptor*) socket); } } return packet; }