/// <summary>Process an incoming packet and raise the appropriate events</summary> /// <param name="sender">The sender</param> /// <param name="e">The EventArgs object containing the packet data</param> protected void CoarseLocationHandler(object sender, PacketReceivedEventArgs e) { CoarseLocationUpdatePacket coarse = (CoarseLocationUpdatePacket)e.Packet; // populate a dictionary from the packet, for local use Dictionary <UUID, Vector3> coarseEntries = new Dictionary <UUID, Vector3>(); for (int i = 0; i < coarse.AgentData.Length; i++) { if (coarse.Location.Length > 0) { coarseEntries[coarse.AgentData[i].AgentID] = new Vector3((int)coarse.Location[i].X, (int)coarse.Location[i].Y, (int)coarse.Location[i].Z * 4); } // the friend we are tracking on radar if (i == coarse.Index.Prey) { e.Simulator.preyID = coarse.AgentData[i].AgentID; } } // find stale entries (people who left the sim) List <UUID> removedEntries = e.Simulator.avatarPositions.FindAll(delegate(UUID findID) { return(!coarseEntries.ContainsKey(findID)); }); // anyone who was not listed in the previous update List <UUID> newEntries = new List <UUID>(); lock (e.Simulator.avatarPositions.Dictionary) { // remove stale entries foreach (UUID trackedID in removedEntries) { e.Simulator.avatarPositions.Dictionary.Remove(trackedID); } // add or update tracked info, and record who is new foreach (KeyValuePair <UUID, Vector3> entry in coarseEntries) { if (!e.Simulator.avatarPositions.Dictionary.ContainsKey(entry.Key)) { newEntries.Add(entry.Key); } e.Simulator.avatarPositions.Dictionary[entry.Key] = entry.Value; } } if (m_CoarseLocationUpdate != null) { WorkPool.QueueUserWorkItem(delegate(object o) { OnCoarseLocationUpdate(new CoarseLocationUpdateEventArgs(e.Simulator, newEntries, removedEntries)); }); } }
/// <summary> /// Fire the events registered for this packet type /// </summary> /// <param name="packetType">Incoming packet type</param> /// <param name="packet">Incoming packet</param> /// <param name="simulator">Simulator this packet was received from</param> internal void RaiseEvent(PacketType packetType, Packet packet, Simulator simulator) { PacketCallback callback; // Default handler first, if one exists if (_EventTable.TryGetValue(PacketType.Default, out callback) && callback.Callback != null) { if (callback.IsAsync) { PacketCallbackWrapper wrapper; wrapper.Callback = callback.Callback; wrapper.Packet = packet; wrapper.Simulator = simulator; WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); } else { try { callback.Callback(this, new PacketReceivedEventArgs(packet, simulator)); } catch (Exception ex) { Logger.Log("Default packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } } } if (_EventTable.TryGetValue(packetType, out callback) && callback.Callback != null) { if (callback.IsAsync) { PacketCallbackWrapper wrapper; wrapper.Callback = callback.Callback; wrapper.Packet = packet; wrapper.Simulator = simulator; WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper); } else { try { callback.Callback(this, new PacketReceivedEventArgs(packet, simulator)); } catch (Exception ex) { Logger.Log("Packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } } return; } if (packetType != PacketType.Default && packetType != PacketType.PacketAck) { Logger.DebugLog("No handler registered for packet event " + packetType, Client); } }
/// <summary> /// Executes a foreach loop in which iterations may run in parallel /// </summary> /// <typeparam name="T">Object type that the collection wraps</typeparam> /// <param name="threadCount">The number of concurrent execution threads to run</param> /// <param name="enumerable">An enumerable collection to iterate over</param> /// <param name="body">Method body to run for each object in the collection</param> public static void ForEach <T>(int threadCount, IEnumerable <T> enumerable, Action <T> body) { int counter = threadCount; AutoResetEvent threadFinishEvent = new AutoResetEvent(false); IEnumerator <T> enumerator = enumerable.GetEnumerator(); Exception exception = null; for (int i = 0; i < threadCount; i++) { WorkPool.QueueUserWorkItem( delegate(object o) { int threadIndex = (int)o; while (exception == null) { T entry; lock (enumerator) { if (!enumerator.MoveNext()) { break; } entry = (T)enumerator.Current; // Explicit typecast for Mono's sake } try { body(entry); } catch (Exception ex) { exception = ex; break; } } if (Interlocked.Decrement(ref counter) == 0) { threadFinishEvent.Set(); } }, i ); } threadFinishEvent.WaitOne(); if (exception != null) { throw exception; } }
/// <summary> /// Executes a for loop in which iterations may run in parallel /// </summary> /// <param name="threadCount">The number of concurrent execution threads to run</param> /// <param name="fromInclusive">The loop will be started at this index</param> /// <param name="toExclusive">The loop will be terminated before this index is reached</param> /// <param name="body">Method body to run for each iteration of the loop</param> public static void For(int threadCount, int fromInclusive, int toExclusive, Action <int> body) { int counter = threadCount; AutoResetEvent threadFinishEvent = new AutoResetEvent(false); Exception exception = null; --fromInclusive; for (int i = 0; i < threadCount; i++) { WorkPool.QueueUserWorkItem( delegate(object o) { int threadIndex = (int)o; while (exception == null) { int currentIndex = Interlocked.Increment(ref fromInclusive); if (currentIndex >= toExclusive) { break; } try { body(currentIndex); } catch (Exception ex) { exception = ex; break; } } if (Interlocked.Decrement(ref counter) == 0) { threadFinishEvent.Set(); } }, i ); } threadFinishEvent.WaitOne(); if (exception != null) { throw exception; } }
/// <summary> /// Executes a series of tasks in parallel /// </summary> /// <param name="threadCount">The number of concurrent execution threads to run</param> /// <param name="actions">A series of method bodies to execute</param> public static void Invoke(int threadCount, params Action[] actions) { int counter = threadCount; AutoResetEvent threadFinishEvent = new AutoResetEvent(false); int index = -1; Exception exception = null; for (int i = 0; i < threadCount; i++) { WorkPool.QueueUserWorkItem( delegate(object o) { int threadIndex = (int)o; while (exception == null) { int currentIndex = Interlocked.Increment(ref index); if (currentIndex >= actions.Length) { break; } try { actions[currentIndex](); } catch (Exception ex) { exception = ex; break; } } if (Interlocked.Decrement(ref counter) == 0) { threadFinishEvent.Set(); } }, i ); } threadFinishEvent.WaitOne(); if (exception != null) { throw exception; } }
/// <summary> /// Fire the events registered for this event type asynchronously /// </summary> /// <param name="capsEvent">Capability name</param> /// <param name="message">Decoded event body</param> /// <param name="simulator">Reference to the simulator that /// generated this event</param> internal void BeginRaiseEvent(string capsEvent, IMessage message, Simulator simulator) { bool specialHandler = false; Caps.EventQueueCallback callback; // Default handler first, if one exists if (_EventTable.TryGetValue(String.Empty, out callback)) { if (callback != null) { CapsCallbackWrapper wrapper; wrapper.Callback = callback; wrapper.CapsEvent = capsEvent; wrapper.Message = message; wrapper.Simulator = simulator; WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); } } // Explicit handler next if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null) { CapsCallbackWrapper wrapper; wrapper.Callback = callback; wrapper.CapsEvent = capsEvent; wrapper.Message = message; wrapper.Simulator = simulator; WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); specialHandler = true; } if (!specialHandler) { Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client); } }
/// <summary> /// Master Download Thread, Queues up downloads in the threadpool /// </summary> private void DownloadThread() { int slot; while (_Running) { // find free slots int pending = 0; int active = 0; TaskInfo nextTask = null; lock (_Transfers) { foreach (KeyValuePair <UUID, TaskInfo> request in _Transfers) { if (request.Value.State == TextureRequestState.Pending) { nextTask = request.Value; ++pending; } else if (request.Value.State == TextureRequestState.Progress) { ++active; } } } if (pending > 0 && active <= maxTextureRequests) { slot = -1; // find available slot for reset event lock (lockerObject) { for (int i = 0; i < threadpoolSlots.Length; i++) { if (threadpoolSlots[i] == -1) { // found a free slot threadpoolSlots[i] = 1; slot = i; break; } } } // -1 = slot not available if (slot != -1 && nextTask != null) { nextTask.State = TextureRequestState.Started; nextTask.RequestSlot = slot; //Logger.DebugLog(String.Format("Sending Worker thread new download request {0}", slot)); WorkPool.QueueUserWorkItem(TextureRequestDoWork, nextTask); continue; } } // Queue was empty or all download slots are inuse, let's give up some CPU time Thread.Sleep(500); } Logger.Log("Texture pipeline shutting down", Helpers.LogLevel.Info); }