async void DelayedNetworkConnectedUpdate(bool available, bool delayed = true) { // delay output, but output immediately if internet becomes available... if (!Atomic.Lock(ref DelayedNetworkUpdateLimiter)) { return; } await Task.Delay(0).ConfigureAwait(false); // asyncify try { if (available) { CheckInet(); if (InternetAvailable) { needUpdate = true; return; } } if (netAntiFlicker && delayed) { const int delay = 15; int sleep = Convert.ToInt32(DateTime.Now.TimeTo(lastnetworkchange.AddSeconds(delay)).TotalSeconds * 1000) + 250; await Task.Delay(sleep.Constrain(1000, 16000)); if (DateTime.Now.TimeSince(lastnetworkchange).TotalSeconds < delay) { if (Taskmaster.DebugNet) { Log.Verbose("<Net> Delaying network status testing again: {Delay}<{Wait} is too soon", string.Format("{0:N0}s", DateTime.Now.TimeSince(lastnetworkchange).TotalSeconds), delay); } DelayedNetworkConnectedUpdate(NetworkAvailable); return; } else { netAntiFlicker = false; } } Log.Information("<Network> Status changed: " + (available ? "Connected" : "Disconnected")); netAntiFlicker = true; if (NetworkAvailable) { needUpdate = true; } } catch { throw; } // for finally block finally { Atomic.Unlock(ref DelayedNetworkUpdateLimiter); } }
//async void TimerCheck(object state) async void TimerCheck(object sender, EventArgs ev) { // skip if already running... // happens sometimes when the timer keeps running but not the code here if (!Atomic.Lock(ref HealthCheck_lock)) { return; } try { try { await CheckErrors().ConfigureAwait(false); await CheckLogs().ConfigureAwait(false); await CheckMemory().ConfigureAwait(false); await CheckNVM().ConfigureAwait(false); } catch (Exception ex) { Logging.Stacktrace(ex); } } catch { throw; } finally { Atomic.Unlock(ref HealthCheck_lock); } }
void RestoreMainWindow(object sender, EventArgs e) { if (!Atomic.Lock(ref restoremainwindow_lock)) { return; // already being done } try { Taskmaster.ShowMainWindow(); if (Taskmaster.Trace) { Log.Verbose("RestoreMainWindow done!"); } } catch (Exception ex) { Logging.Stacktrace(ex); throw; } finally { Atomic.Unlock(ref restoremainwindow_lock); } }
public void Tick(object state) { if (!Atomic.Lock(ref CallbackLimiter)) { return; } try { var time = System.Diagnostics.Stopwatch.StartNew(); long oldmem = GC.GetTotalMemory(false); System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true); GC.WaitForPendingFinalizers(); long newmem = GC.GetTotalMemory(true); Log.Debug("<Self-Maintenance> Done, saved {kBytes} kB.", (oldmem - newmem) / 1000); if (Taskmaster.Trace) { Log.Verbose("Running periodic cleanup"); } // TODO: This starts getting weird if cleanup interval is smaller than total delay of testing all items. // (15*60) / 2 = item limit, and -1 or -2 for safety margin. Unlikely, but should probably be covered anyway. if (Taskmaster.Components.processmanager != null) { Taskmaster.processmanager.Cleanup(); } Taskmaster.Config.Flush(); time.Stop(); Statistics.MaintenanceCount++; Statistics.MaintenanceTime += time.Elapsed.TotalSeconds; if (Taskmaster.Trace) { Log.Verbose("Maintenance took: {Time}s", string.Format("{0:N2}", time.Elapsed.TotalSeconds)); } } catch (Exception ex) { Logging.Stacktrace(ex); timer.Dispose(); throw; } finally { Atomic.Unlock(ref CallbackLimiter); } }
void RecordDeviceState(bool online_state, bool address_changed) { if (!Atomic.Lock(ref DeviceStateRecordLimiter)) { return; } try { if (online_state != lastOnlineState) { lastOnlineState = online_state; if (online_state) { lastUptimeStart = DateTime.Now; Task.Delay(new TimeSpan(0, 5, 0)).ContinueWith(x => ReportCurrentUpstate()); } else // went offline { lock (uptime_lock) { var newUptime = (DateTime.Now - lastUptimeStart).TotalMinutes; upTime.Add(newUptime); uptimeTotal += newUptime; uptimeSamples += 1; if (uptimeSamples > 20) { uptimeTotal -= upTime[0]; uptimeSamples -= 1; upTime.RemoveAt(0); } } ReportUptime(); } return; } else if (address_changed) { // same state but address change was detected Console.WriteLine("<Network> DEBUG: Address changed but internet connectivity unaffected."); } } catch (Exception ex) { Logging.Stacktrace(ex); throw; } finally { Atomic.Unlock(ref DeviceStateRecordLimiter); } }
public async Task ScanTemp() { if (!Atomic.Lock(ref scantemp_lock)) { return; } try { await Task.Delay(0); var dst = new DirectoryStats { Files = 0, Dirs = 0, Size = 0 }; ReScanBurden = 0; Log.Information("Temp folders scanning initiated..."); onTempScan?.Invoke(null, new DiskEventArgs { State = ScanState.Start, Stats = dst }); DirectorySize(new System.IO.DirectoryInfo(systemTemp), ref dst); if (systemTemp != userTemp) { onTempScan?.Invoke(null, new DiskEventArgs { State = ScanState.Segment, Stats = dst }); DirectorySize(new System.IO.DirectoryInfo(userTemp), ref dst); } onTempScan?.Invoke(null, new DiskEventArgs { State = ScanState.End, Stats = dst }); Log.Information("Temp contents: {Files} files, {Dirs} dirs, {Size} MBs", dst.Files, dst.Dirs, string.Format("{0:N2}", dst.Size / 1000f / 1000f)); } catch { throw; } // for finally block finally { Atomic.Unlock(ref scantemp_lock); } }
protected override void WndProc(ref Message m) { if (m.Msg == NativeMethods.WM_HOTKEY) { //Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); //NativeMethods.KeyModifier modifier = (NativeMethods.KeyModifier)((int)m.LParam & 0xFFFF); int id = m.WParam.ToInt32(); // registered hotkey id if (Atomic.Lock(ref hotkeyinprogress)) { if (Taskmaster.Trace) { Log.Verbose("<Tray> Hotkey ctrl-alt-shift-m detected!!!"); } Task.Run(new Action(async() => { try { int ignorepid = Taskmaster.activeappmonitor?.Foreground ?? -1; Log.Information("<Tray> Hotkey detected, freeing memory while ignoring foreground{Ign} if possible.", ignorepid > 4 ? string.Format(" (#{0})", ignorepid) : string.Empty); await processmanager.FreeMemory(ignorepid).ConfigureAwait(false); } catch (Exception ex) { Logging.Stacktrace(ex); } finally { Atomic.Unlock(ref hotkeyinprogress); } })); } } base.WndProc(ref m); // is this necessary? }
public async void EnsureVisible() { if (!Atomic.Lock(ref ensuringvisibility)) { return; } try { Enable(); int attempts = 0; while (!Tray.Visible) { Log.Debug("<Tray> Not visible, fixing..."); RefreshVisibility(); await Task.Delay(15 * 1000).ConfigureAwait(true); if (++attempts >= 5) { Log.Fatal("<Tray> Failure to become visible after 5 attempts. Exiting to avoid ghost status."); Taskmaster.UnifiedExit(); } } } catch (Exception ex) { Logging.Stacktrace(ex); } finally { Atomic.Unlock(ref ensuringvisibility); } }
static int correcting; // = 0; async void VolumeChangedHandler(NAudio.CoreAudioApi.AudioVolumeNotificationData data) { var oldVol = Volume; double newVol = data.MasterVolume * 100; if (Math.Abs(newVol - Target) <= SmallVolumeHysterisis) { if (Taskmaster.ShowInaction) { Log.Verbose("<Microphone> Volume change too small ({VolumeChange:N1}%) to act on.", Math.Abs(newVol - Target)); } return; } if (Taskmaster.Trace) { Log.Verbose("<Microphone> Volume changed from {OldVolume:N1}% to {NewVolume:N1}%", oldVol, newVol); } // This is a light HYSTERISIS limiter in case someone is sliding a volume bar around, // we act on it only once every [AdjustDelay] ms. // HOPEFULLY there are no edge cases with this triggering just before last adjustment // and the notification for the last adjustment coming slightly before. Seems super unlikely tho. // TODO: Delay this even more if volume is changed ~2 seconds before we try to do so. if (Math.Abs(newVol - Target) >= VolumeHysterisis) // Volume != Target for double { if (Taskmaster.Trace) { Log.Verbose("<Microphone> DEBUG: Volume changed = [{OldVolume:N1} -> {NewVolume:N1}], Off.Target: {VolumeOffset:N1}", oldVol, newVol, Math.Abs(newVol - Target)); } if (Atomic.Lock(ref correcting)) { try { await System.Threading.Tasks.Task.Delay(AdjustDelay); // actual hysterisis, this should be cancellable oldVol = Control.Percent; Log.Information("<Microphone> Correcting volume from {OldVolume:N1} to {NewVolume:N1}", oldVol, Target); Volume = Target; Corrections += 1; micstatsdirty = true; VolumeChanged?.Invoke(this, new VolumeChangedEventArgs { Old = oldVol, New = Target, Corrections = Corrections }); } catch { throw; } // required for finally to be guaranteed finally { Atomic.Unlock(ref correcting); } } else { if (Taskmaster.Trace) { Log.Verbose("<Microphone> DEBUG CorrectionAlreadyQueued"); } } } else { if (Taskmaster.Trace) { Log.Verbose("<Microphone> DEBUG NotCorrected"); } } }
public void UpdateInterfaces() { if (!Atomic.Lock(ref InterfaceUpdateLimiter)) { return; } needUpdate = false; try { // TODO: Rate limit if (Taskmaster.DebugNet) { Log.Verbose("<Network> Enumerating network interfaces..."); } var ifacelistt = new List <NetDevice>(); // var ifacelist = new List<string[]>(); var index = 0; NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface dev in adapters) { var ti = index++; if (dev.NetworkInterfaceType == NetworkInterfaceType.Loopback || dev.NetworkInterfaceType == NetworkInterfaceType.Tunnel) { continue; } var stats = dev.GetIPStatistics(); IPAddress _ipv4 = IPAddress.None, _ipv6 = IPAddress.None; foreach (UnicastIPAddressInformation ip in dev.GetIPProperties().UnicastAddresses) { // TODO: Maybe figure out better way and early bailout from the foreach switch (ip.Address.AddressFamily) { case System.Net.Sockets.AddressFamily.InterNetwork: _ipv4 = ip.Address; break; case System.Net.Sockets.AddressFamily.InterNetworkV6: _ipv6 = ip.Address; break; } } var devi = new NetDevice { Index = ti, Name = dev.Name, Type = dev.NetworkInterfaceType, Status = dev.OperationalStatus, Speed = dev.Speed, IPv4Address = _ipv4, IPv6Address = _ipv6, }; devi.Incoming.From(stats, true); devi.Outgoing.From(stats, false); // devi.PrintStats(); ifacelistt.Add(devi); if (Taskmaster.DebugNet) { Log.Verbose("<Network> Interface: {InterfaceName}", dev.Name); } } lock (interfaces_lock) CurrentInterfaceList = ifacelistt; } finally { Atomic.Unlock(ref InterfaceUpdateLimiter); } }
int InetCheckLimiter; // = 0; bool CheckInet(bool address_changed = false) { // TODO: Figure out how to get Actual start time of internet connectivity. if (!Atomic.Lock(ref InetCheckLimiter)) { return(InternetAvailable); } if (Taskmaster.Trace) { Log.Verbose("<Network> Checking internet connectivity..."); } try { var oldInetAvailable = InternetAvailable; if (NetworkAvailable) { try { Dns.GetHostEntry(dnstestaddress); // FIXME: There should be some other method than DNS testing InternetAvailable = true; Notified = false; // TODO: Don't rely on DNS? } catch (System.Net.Sockets.SocketException ex) { InternetAvailable = false; switch (ex.SocketErrorCode) { case System.Net.Sockets.SocketError.AccessDenied: case System.Net.Sockets.SocketError.SystemNotReady: break; case System.Net.Sockets.SocketError.TryAgain: case System.Net.Sockets.SocketError.TimedOut: default: Log.Information("<Network> Internet availability test inconclusive, assuming connected."); InternetAvailable = true; return(InternetAvailable); case System.Net.Sockets.SocketError.SocketError: case System.Net.Sockets.SocketError.Interrupted: case System.Net.Sockets.SocketError.Fault: if (!Notified) { Log.Warning("<Network> Internet check interrupted. Potential hardware/driver issues."); Notified = true; } break; case System.Net.Sockets.SocketError.HostUnreachable: case System.Net.Sockets.SocketError.HostNotFound: case System.Net.Sockets.SocketError.HostDown: if (!Notified) { Log.Warning("<Network> DNS test failed, test host unreachable. Test host may be down."); Notified = true; } break; case System.Net.Sockets.SocketError.NetworkDown: case System.Net.Sockets.SocketError.NetworkReset: case System.Net.Sockets.SocketError.NetworkUnreachable: break; } } } else { InternetAvailable = false; } RecordDeviceState(InternetAvailable, address_changed); if (oldInetAvailable != InternetAvailable) { string status = "All OK"; if (NetworkAvailable && !InternetAvailable) { status = "ISP/route problems"; } else if (!NetworkAvailable) { status = "Cable unplugged or router/modem down"; } Log.Information("<Network> Status: {NetworkAvailable}, Internet: {InternetAvailable} – {Status}", (NetworkAvailable ? "Up" : "Down"), (InternetAvailable ? "Connected" : "Disconnected"), status); } else { if (Taskmaster.Trace) { Log.Verbose("<Network> Connectivity unchanged."); } } } finally { Atomic.Unlock(ref InetCheckLimiter); } InternetStatusChange?.Invoke(this, new InternetStatus { Available = InternetAvailable, Start = lastUptimeStart, Uptime = Uptime }); return(InternetAvailable); }
void AnalyzeTrafficBehaviour() { Debug.Assert(CurrentInterfaceList != null); if (!Atomic.Lock(ref TrafficAnalysisLimiter)) { return; } try { PacketWarning.Leak(); var oldifaces = CurrentInterfaceList; UpdateInterfaces(); // force refresh var ifaces = CurrentInterfaceList; if (ifaces == null) { return; // no interfaces, just quit } for (int index = 0; index < ifaces.Count; index++) { outgoing = ifaces[index].Outgoing; incoming = ifaces[index].Incoming; oldoutgoing = oldifaces[index].Outgoing; oldincoming = oldifaces[index].Incoming; long totalerrors = outgoing.Errors + incoming.Errors; long totaldiscards = outgoing.Errors + incoming.Errors; long totalunicast = outgoing.Errors + incoming.Errors; long errors = (incoming.Errors - oldincoming.Errors) + (outgoing.Errors - oldoutgoing.Errors); long discards = (incoming.Discards - oldincoming.Discards) + (outgoing.Discards - oldoutgoing.Discards); long packets = (incoming.Unicast - oldincoming.Unicast) + (outgoing.Unicast - oldoutgoing.Unicast); // Console.WriteLine("{0} : Packets(+{1}), Errors(+{2}), Discarded(+{3})", ifaces[index].Name, packets, errors, discards); if (errors > 0 && // only if errors Taskmaster.ShowNetworkErrors && // user wants to see this !ErrorReports.Peaked && // we're not waiting for report counter to go down ErrorReports.Pump()) // error reporting not full { Log.Warning("<Network> {Device} is suffering from traffic errors! (+{Rate} since last sample)", ifaces[index].Name, errors); } else { ErrorReports.Leak(); } onSampling?.Invoke(this, new NetDeviceTrafficEventArgs { Traffic = new NetDeviceTraffic { Index = index, Delta = new NetTraffic { Unicast = packets, Errors = errors, Discards = discards }, Total = new NetTraffic { Unicast = totalunicast, Errors = totalerrors, Discards = totaldiscards, Bytes = incoming.Bytes + outgoing.Bytes }, } }); } } catch (Exception ex) { Logging.Stacktrace(ex); } finally { Atomic.Unlock(ref TrafficAnalysisLimiter); } }
/// <summary> /// Prune cache. /// </summary> void Prune() { if (!Atomic.Lock(ref prune_in_progress)) { return; // only one instance. } try { if (Items.Count <= MinCache) { return; // just don't bother } if (Items.Count <= MaxCache && CacheEvictStrategy == EvictStrategy.LeastUsed) { return; } lock (cache_lock) { var list = Items.Values.ToList(); // would be nice to cache this list list.Sort(delegate(CacheItem <K1, K2, T> x, CacheItem <K1, K2, T> y) { if (CacheEvictStrategy == EvictStrategy.LeastRecent) { if (x.Access < y.Access) { return(-1); } if (x.Access > y.Access) { return(1); } // Both have equal at this point if (x.Desirability < y.Desirability) { return(-1); } if (x.Desirability > y.Desirability) { return(1); } } else { if (x.Desirability < y.Desirability) { return(-1); } if (x.Desirability > y.Desirability) { return(1); } // Both have equal at this point if (x.Access < y.Access) { return(-1); } if (x.Access > y.Access) { return(1); } } return(0); }); // Log.Debug("CACHE STATE: FIRST({First}) LAST({LAST})", list.First().Access, list.Last().Access); // Log.Debug("CACHE ITEMS BEFORE PRUNE: {Items}", Items.Count); while (Items.Count > MaxCache) { var bu = list.ElementAt(0); var key = bu.AccessKey; // Log.Debug("--- REMOVING: Key:{Key}, Last Access: {Date}, Desirability: {Value}", // key, bu.Access, bu.Desirability); Items.Remove(key); list.RemoveAt(0); } // Log.Debug("CACHE ITEMS AFTER PRUNE: {Items}", Items.Count); double bi = double.NaN; var deleteItem = new Action <K1>( (K1 key) => { if (Taskmaster.Trace) { Log.Verbose("Removing {time} min old item.", string.Format("{0:N1}", bi)); } Items.Remove(key); list.RemoveAt(0); } ); var now = DateTime.Now; while (list.Count > 0) { var bu = list.ElementAt(0); bi = now.TimeSince(bu.Access).TotalMinutes; if (CacheEvictStrategy == EvictStrategy.LeastRecent) { if (bi > MaxAge) { deleteItem(bu.AccessKey); } else { break; } } else // .LeastUsed, TM is never going to reach this. { if (bi > MinAge) { deleteItem(bu.AccessKey); } else { break; } } } } } finally { Atomic.Unlock(ref prune_in_progress); } }