fix CPU leak in network module (I hope for that);

fix GCD initialization;
starting to remove observable from project (because of memory leak);
This commit is contained in:
Serhiy Mytrovtsiy
2020-01-13 00:18:58 +01:00
parent d17614cb49
commit ca1da4ffa2
10 changed files with 96 additions and 67 deletions

View File

@@ -1,6 +1,6 @@
//
// AppDelegate.swift
// Mini Stats
// Stats
//
// Created by Serhiy Mytrovtsiy on 28.05.2019.
// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved.
@@ -10,7 +10,7 @@ import Cocoa
import ServiceManagement
import LaunchAtLogin
let modules: Observable<[Module]> = Observable([CPU(), Memory(), Disk(), Battery(), Network()])
let modules: [Module] = [CPU(), Memory(), Disk(), Battery(), Network()]
let updater = macAppUpdater(user: "exelban", repo: "stats")
let popover = NSPopover()
var menuBar: MenuBar?
@@ -67,8 +67,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func applicationWillTerminate(_ aNotification: Notification) {
if modules.value.count != 0 {
for module in modules.value{
if modules.count != 0 {
for module in modules {
module.stop()
}
}

View File

@@ -18,7 +18,7 @@ class MenuBar {
self.menuBarItem = menuBarItem
self.menuBarButton = menuBarButton
for module in modules.value {
for module in modules {
module.active.subscribe(observer: self) { (value, _) in
if !value {
let emptyWidget = Empty()
@@ -37,7 +37,7 @@ class MenuBar {
}
public func updateWidget(name: String) {
let newViewList = modules.value.filter{ $0.name == name }
let newViewList = modules.filter{ $0.name == name }
if newViewList.isEmpty {
return
}
@@ -56,7 +56,7 @@ class MenuBar {
private func updateWidth() {
var WIDTH: CGFloat = 0
for module in modules.value {
for module in modules {
if module.active.value && module.available.value {
WIDTH = WIDTH + module.view.frame.size.width
}
@@ -82,7 +82,7 @@ class MenuBar {
self.stackView = stackView
var WIDTH: CGFloat = 0
for module in modules.value {
for module in modules {
if module.available.value {
if module.active.value {
module.initWidget()

View File

@@ -58,6 +58,10 @@ class BatteryReader: Reader {
if self.available {
self.read()
}
self.timer = Repeater.init(interval: .seconds(1), observer: { _ in
self.read()
})
}
func start() {
@@ -184,6 +188,6 @@ class BatteryReader: Reader {
}
self.updateInterval = value
self.timer?.reset(.seconds(Double(value)))
self.timer?.reset(.seconds(Double(value)), restart: false)
}
}

View File

@@ -59,12 +59,12 @@ class CPUReader: Reader {
self.read()
}
self.timer = Repeater.every(.seconds(1)) { timer in
self.timer = Repeater.init(interval: .seconds(1), observer: { _ in
self.read()
}
self.additionalTimer = Repeater.every(.seconds(1)) { timer in
})
self.additionalTimer = Repeater.init(interval: .seconds(1), observer: { _ in
self.readAdditional()
}
})
}
func start() {
@@ -142,7 +142,7 @@ class CPUReader: Reader {
var numCPUsU: natural_t = 0
let err: kern_return_t = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo);
let usage = getUsage()
//
if err == KERN_SUCCESS {
CPUUsageLock.lock()
@@ -251,8 +251,8 @@ class CPUReader: Reader {
}
self.updateInterval = value
self.timer?.reset(.seconds(Double(value)))
self.additionalTimer?.reset(.seconds(Double(value)))
self.timer?.reset(.seconds(Double(value)), restart: false)
self.additionalTimer?.reset(.seconds(Double(value)), restart: false)
}
}

View File

@@ -21,6 +21,10 @@ class DiskReader: Reader {
if self.available {
self.read()
}
self.timer = Repeater.init(interval: .seconds(1), observer: { _ in
self.read()
})
}
func start() {
@@ -70,6 +74,6 @@ class DiskReader: Reader {
}
self.updateInterval = value
self.timer?.reset(.seconds(Double(value)))
self.timer?.reset(.seconds(Double(value)), restart: false)
}
}

View File

@@ -49,12 +49,12 @@ class MemoryReader: Reader {
self.read()
}
self.timer = Repeater.every(.seconds(1)) { timer in
self.timer = Repeater.init(interval: .seconds(1), observer: { _ in
self.read()
}
self.additionalTimer = Repeater.every(.seconds(1)) { timer in
})
self.additionalTimer = Repeater.init(interval: .seconds(1), observer: { _ in
self.readAdditional()
}
})
}
func start() {
@@ -165,7 +165,7 @@ class MemoryReader: Reader {
}
self.updateInterval = value
self.timer?.reset(.seconds(Double(value)))
self.additionalTimer?.reset(.seconds(Double(value)))
self.timer?.reset(.seconds(Double(value)), restart: false)
self.additionalTimer?.reset(.seconds(Double(value)), restart: false)
}
}

View File

@@ -14,59 +14,80 @@ class NetworkReader: Reader {
public var availableAdditional: Bool = false
public var updateInterval: Int = 0
private var netProcess: Process = Process()
private var pipe: Pipe = Pipe()
private var timer: Repeater?
private var uploadValue: Int64 = 0
private var downloadValue: Int64 = 0
init() {
self.value = Observable([])
netProcess.launchPath = "/usr/bin/env"
netProcess.arguments = ["netstat", "-w1", "-l", "en0"]
netProcess.standardOutput = pipe
if self.available {
self.read()
}
self.timer = Repeater.init(interval: .seconds(1), observer: { _ in
self.read()
})
}
func start() {
if netProcess.isRunning {
return
}
self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: self.pipe.fileHandleForReading , queue: nil) { _ -> Void in
defer {
self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
}
let output = self.pipe.fileHandleForReading.availableData
if output.isEmpty {
return
}
let outputString = String(data: output, encoding: String.Encoding.utf8) ?? ""
let arr = outputString.condenseWhitespace().split(separator: " ")
if !arr.isEmpty && Int64(arr[0]) != nil {
guard let download = Int64(arr[2]), let upload = Int64(arr[5]) else {
return
}
self.value << [Double(download), Double(upload)]
}
}
do {
try netProcess.run()
} catch let error {
print(error)
read()
if self.timer != nil && self.timer!.state.isRunning == false {
self.timer!.start()
}
}
func stop() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSFileHandleDataAvailable, object: nil)
self.timer?.pause()
}
func read() {}
func read() {
var interfaceAddresses: UnsafeMutablePointer<ifaddrs>? = nil
var upload: Int64 = 0
var download: Int64 = 0
guard getifaddrs(&interfaceAddresses) == 0 else { return }
var pointer = interfaceAddresses
while pointer != nil {
guard let info = getDataUsageInfo(from: pointer!) else {
pointer = pointer!.pointee.ifa_next
continue
}
pointer = pointer!.pointee.ifa_next
upload = info[0]
download = info[1]
}
freeifaddrs(interfaceAddresses)
let lastUpload = self.uploadValue
let lastDownload = self.downloadValue
if lastUpload != 0 && lastDownload != 0 {
DispatchQueue.main.async(execute: {
self.value << [Double(download - lastDownload), Double(upload - lastUpload)]
})
}
self.uploadValue = upload
self.downloadValue = download
}
func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> [Int64]? {
let pointer = infoPointer
let name: String! = String(cString: infoPointer.pointee.ifa_name)
let addr = pointer.pointee.ifa_addr.pointee
guard addr.sa_family == UInt8(AF_LINK) else { return nil }
var networkData: UnsafeMutablePointer<if_data>? = nil
if name.hasPrefix("en") {
networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
return [Int64(networkData?.pointee.ifi_obytes ?? 0), Int64(networkData?.pointee.ifi_ibytes ?? 0)] // upload, download
}
return nil
}
func setInterval(value: Int) {}
}

View File

@@ -38,7 +38,7 @@ class MainViewController: NSViewController {
makeHeader()
for module in modules.value {
for module in modules {
module.active.subscribe(observer: self) { (value, _) in
for tab in self.tabView.tabViewItems {
self.tabView.removeTabViewItem(tab)
@@ -53,7 +53,7 @@ class MainViewController: NSViewController {
}
override func viewWillAppear() {
for module in modules.value {
for module in modules {
if module.tabAvailable && module.available.value && module.active.value && module.reader.availableAdditional {
module.reader.startAdditional()
}
@@ -61,7 +61,7 @@ class MainViewController: NSViewController {
}
override func viewWillDisappear() {
for module in modules.value {
for module in modules {
if module.tabAvailable && module.available.value && module.active.value && module.reader.availableAdditional {
module.reader.stopAdditional()
}
@@ -70,7 +70,7 @@ class MainViewController: NSViewController {
func makeHeader() {
var list: [String] = []
for module in modules.value {
for module in modules {
if module.tabAvailable && module.available.value && module.active.value {
list.append(module.name)
@@ -124,7 +124,7 @@ class MainViewController: NSViewController {
func buildSettings() -> NSMenu {
let menu = NSMenu()
for module in modules.value {
for module in modules {
if module.available.value {
menu.addItem(module.menu)
}

View File

@@ -1,6 +1,6 @@
//
// Extensions.swift
// Mini Stats
// Stats
//
// Created by Serhiy Mytrovtsiy on 29/05/2019.
// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved.

View File

@@ -1,6 +1,6 @@
//
// Observable.swift
// Mini Stats
// Stats
//
// Created by Serhiy Mytrovtsiy on 29/05/2019.
// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved.