Skip to content

Commit

Permalink
Adds signal termination handling when using control C, ensuring proce…
Browse files Browse the repository at this point in the history
…sses are also terminated
  • Loading branch information
wess committed Nov 29, 2016
1 parent 5fe02b6 commit 403743f
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 22 deletions.
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0.1
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ let package = Package(
Target(name: "watch"),
Target(name: "config", dependencies: ["json"]),
Target(name: "json"),
Target(name: "task"),
Target(name: "task", dependencies: ["signals"]),
Target(name: "env"),
Target(name: "signals"),
],

dependencies: [
Expand Down
2 changes: 1 addition & 1 deletion Sources/overlook/overlook.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import env

public class Overlook {
static let name = "overlook"
static let version = "0.1.1"
static let version = "0.1.2"
static let desc = "File monitoring tool that excutes on change. Used anywhere."

static let dotTemplate:[String:Any] = [
Expand Down
46 changes: 46 additions & 0 deletions Sources/signals/signals.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// signals.swift
// overlook
//
// Created by Wesley Cope on 11/29/16.
//
//

import Foundation
import Darwin

public enum Signal {
case hup
case int
case quit
case abrt
case kill
case alrm
case term
case user(Int)

public static var all:[Signal] = [.hup, .int, .quit, .abrt, .kill, .alrm, .term,]

public var rawValue:Int32 {
switch self {
case .hup: return Int32(SIGHUP)
case .int: return Int32(SIGINT)
case .quit: return Int32(SIGQUIT)
case .abrt: return Int32(SIGABRT)
case .kill: return Int32(SIGKILL)
case .alrm: return Int32(SIGALRM)
case .term: return Int32(SIGTERM)
case .user(let sig): return Int32(sig)
}
}
}

public typealias SignalHandler = @convention(c)(Int32) -> Void

public func signalTrap(_ signal:Signal, handler:SignalHandler) {
var signalAction = sigaction(__sigaction_u: unsafeBitCast(handler, to: __sigaction_u.self), sa_mask: 0, sa_flags: 0)
_ = withUnsafePointer(to: &signalAction) { actionPointer in

Darwin.sigaction(signal.rawValue, actionPointer, nil)
}
}
61 changes: 41 additions & 20 deletions Sources/task/manager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,55 @@
//

import Foundation
import PathKit
import PathKit
import signals

public class TaskManager {
private let defaultPath = "/usr/bin/env"
private var tasks:[Task] = []

private let lock = DispatchSemaphore(value: 1)
private let taskQueue:DispatchQueue = DispatchQueue(label: "com.overlook.queue")


static weak var this:TaskManager? = nil

public init() {}

public func add(_ task:Task) {
sync {
var current = tasks.filter { $0 != task }
current.append(task)

tasks = current
}
}

@discardableResult
public func create(_ arguments:[String], callback: @escaping TaskHandler) -> Task {
let task = Task(arguments: arguments, path: defaultPath, callback: callback)

add(task)

return task
}

public func start(task:Task) {
let filtered = tasks.filter { $0 == task }

for task in filtered {
task.start()
}
}

public func start() {
TaskManager.this = self

signalTrap(.int) { signal in
TaskManager.this?.kill()

exit(signal)
}

for task in tasks {
taskQueue.async(execute: task.workItem)
}
Expand All @@ -53,49 +64,59 @@ public class TaskManager {
public func restart() {
sync {
let current = tasks

for task in current {
while(task.isRunning) {
task.workItem.cancel()
task.stop()
}
}

tasks.removeAll()

tasks = current.map { $0.copy() as! Task }

start()
}
}


public func stop(task:Task) {
sync {
let filtered = tasks.filter { $0 == task }

for task in filtered {
task.workItem.cancel()
task.stop()
}
}
}

public func remove(task:Task) {
sync {
var current = tasks
let filtered = current.filter { $0 == task }

for (index, task) in filtered.enumerated() {
task.workItem.cancel()
task.stop()

current.remove(at: index)
}

tasks = current
}
}


public func kill() {
sync {
for task in tasks {
task.workItem.cancel()
task.stop()
}
}
}

private func sync(block:((Void) -> Void)) {
lock.wait()
block()
Expand Down

0 comments on commit 403743f

Please sign in to comment.