0001 #if os(Linux) 0002 import Glibc 0003 private let system_fork = Glibc.fork 0004 #else 0005 import Darwin.C 0006 @_silgen_name("fork") private func system_fork() -> Int32 0007 #endif 0008 0009 import Nest 0010 0011 0012 public enum Address
Arbiter.swift:256 let pid = system_fork(): CustomStringConvertible { 0013 case IP
Configuration.swift:2 public var addresses: [Address] = []Curassow.swift:12 extension Address : ArgumentConvertible {Curassow.swift:88 MultiOption("bind", [Address.IP(hostname: "0.0.0.0", port: 8000)], description: "The address to bind sockets."),(hostname: String, port: UInt16) 0014 case UNIX
Arbiter.swift:18 case let IP(hostname, port):Arbiter.swift:38 case let IP(hostname, port):(path: String) 0015 0016 func socket
Arbiter.swift:24 case let UNIX(path):Arbiter.swift:40 case let UNIX(path):(backlog: Int32) throws -> Socket { 0017 switch self { 0018 case let IP(hostname, port): 0019 let socket = try Socket() 0020 try socket.bind(hostname, port: port) 0021 try socket.listen(backlog) 0022 // TODO: Set socket non blocking 0023 return socket 0024 case let UNIX(path): 0025 // Delete old file if exists 0026 unlink(path) 0027 0028 let socket = try Socket(family: AF_UNIX) 0029 try socket.bind(path) 0030 try socket.listen(backlog) 0031 // TODO: Set socket non blocking 0032 return socket 0033 } 0034 } 0035 0036 public var description: String { 0037 switch self { 0038 case let IP(hostname, port): 0039 return "\(hostname):\(port)" 0040 case let UNIX(path): 0041 return "unix:\(path)" 0042 } 0043 } 0044 } 0045 0046 0047 /// Arbiter maintains the worker processes 0048 public final class Arbiter<Worker
Arbiter.swift:68 listeners.append(try address.socket(configuration.backlog)): WorkerType> { 0049 let configuration
Arbiter.swift:254 let worker = Worker(configuration: configuration, logger: logger, listeners: listeners, notify: workerProcess.notify, application: application): Configuration 0050 let logger
Arbiter.swift:67 for address in configuration.addresses {Arbiter.swift:68 listeners.append(try address.socket(configuration.backlog))Arbiter.swift:129 if configuration.timeout > 0 {Arbiter.swift:130 timeout = timeval(tv_sec: configuration.timeout, tv_usec: 0)Arbiter.swift:206 if configuration.timeout == 0 { return }Arbiter.swift:214 if lastUpdate >= configuration.timeout {= Logger() 0051 var listeners
Arbiter.swift:69 logger.info("Listening at http://\(address) (\(getpid()))")Arbiter.swift:121 logger.info("Shutting down")Arbiter.swift:222 logger.critical("Worker timeout (pid: \(pid))")Arbiter.swift:264 logger.info("Worker exiting (pid: \(workerPid))"): [Socket] = [] 0052 var workers
Arbiter.swift:68 listeners.append(try address.socket(configuration.backlog))Arbiter.swift:108 listeners.forEach { $0.close() }: [pid_t: WorkerProcess] = [:] 0053 0054 var numberOfWorkers
Arbiter.swift:180 workers.removeValueForKey(pid)Arbiter.swift:196 let neededWorkers = numberOfWorkers - workers.countArbiter.swift:211 for (pid, worker) in workers {Arbiter.swift:217 workers.removeValueForKey(pid)Arbiter.swift:225 workers.removeValueForKey(pid)Arbiter.swift:234 let killCount = workers.count - numberOfWorkersArbiter.swift:237 if let (pid, _) = workers.popFirst() {Arbiter.swift:246 for pid in workers.keys {Arbiter.swift:258 workers[pid] = workerProcess: Int 0055 0056 let application: RequestType -> ResponseType 0057 0058 var signalHandler
Arbiter.swift:160 numberOfWorkers += 1Arbiter.swift:166 if numberOfWorkers > 1 {Arbiter.swift:167 numberOfWorkers -= 1Arbiter.swift:196 let neededWorkers = numberOfWorkers - workers.countArbiter.swift:234 let killCount = workers.count - numberOfWorkers: SignalHandler! 0059 0060 public init(configuration: Configuration, workers: Int, application: Application) { 0061 self.configuration = configuration 0062 self.numberOfWorkers = workers 0063 self.application = application 0064 } 0065 0066 func createSockets
Arbiter.swift:74 signalHandler = try SignalHandler()Arbiter.swift:75 signalHandler.register(.Interrupt, handleINT)Arbiter.swift:76 signalHandler.register(.Quit, handleQUIT)Arbiter.swift:77 signalHandler.register(.Terminate, handleTerminate)Arbiter.swift:78 signalHandler.register(.TTIN, handleTTIN)Arbiter.swift:79 signalHandler.register(.TTOU, handleTTOU)Arbiter.swift:80 signalHandler.register(.Child, handleChild)Arbiter.swift:81 sharedHandler = signalHandlerArbiter.swift:97 if !signalHandler.process() {Arbiter.swift:135 let (read, _, _) = select([signalHandler.pipe[0]], [], [], timeout: timeout)Arbiter.swift:139 while try signalHandler.pipe[0].read(1).count > 0 {}() throws { 0067 for address in configuration.addresses { 0068 listeners.append(try address.socket(configuration.backlog)) 0069 logger.info("Listening at http://\(address) (\(getpid()))") 0070 } 0071 } 0072 0073 func registerSignals
Arbiter.swift:92 try createSockets()() throws { 0074 signalHandler = try SignalHandler() 0075 signalHandler.register(.Interrupt, handleINT) 0076 signalHandler.register(.Quit, handleQUIT) 0077 signalHandler.register(.Terminate, handleTerminate) 0078 signalHandler.register(.TTIN, handleTTIN) 0079 signalHandler.register(.TTOU, handleTTOU) 0080 signalHandler.register(.Child, handleChild) 0081 sharedHandler = signalHandler 0082 SignalHandler.registerSignals() 0083 } 0084 0085 var running
Arbiter.swift:91 try registerSignals()= false 0086 0087 // Main run loop for the master process 0088 public func run() throws { 0089 running = true 0090 0091 try registerSignals() 0092 try createSockets() 0093 0094 manageWorkers() 0095 0096 while running { 0097 if !signalHandler.process() { 0098 sleep() 0099 murderWorkers() 0100 manageWorkers() 0101 } 0102 } 0103 0104 halt() 0105 } 0106 0107 func stop
Arbiter.swift:89 running = trueArbiter.swift:96 while running {Arbiter.swift:116 running = falseArbiter.swift:155 running = false(graceful: Bool = true) { 0108 listeners.forEach { $0.close() } 0109 0110 if graceful { 0111 killWorkers(SIGTERM) 0112 } else { 0113 killWorkers(SIGQUIT) 0114 } 0115 0116 running = false 0117 } 0118 0119 func halt
Arbiter.swift:120 stop()Arbiter.swift:147 stop(false)Arbiter.swift:151 stop(false)(exitStatus: Int32 = 0) { 0120 stop() 0121 logger.info("Shutting down") 0122 exit(exitStatus) 0123 } 0124 0125 /// Sleep, waiting for stuff to happen on our signal pipe 0126 func sleep
Arbiter.swift:104 halt()() { 0127 let timeout: timeval 0128 0129 if configuration.timeout > 0 { 0130 timeout = timeval(tv_sec: configuration.timeout, tv_usec: 0) 0131 } else { 0132 timeout = timeval(tv_sec: 30, tv_usec: 0) 0133 } 0134 0135 let (read, _, _) = select([signalHandler.pipe[0]], [], [], timeout: timeout) 0136 0137 if !read.isEmpty { 0138 do { 0139 while try signalHandler.pipe[0].read(1).count > 0 {} 0140 } catch {} 0141 } 0142 } 0143 0144 // MARK: Handle Signals 0145 0146 func handleINT
Arbiter.swift:98 sleep()() { 0147 stop(false) 0148 } 0149 0150 func handleQUIT
Arbiter.swift:75 signalHandler.register(.Interrupt, handleINT)() { 0151 stop(false) 0152 } 0153 0154 func handleTerminate
Arbiter.swift:76 signalHandler.register(.Quit, handleQUIT)() { 0155 running = false 0156 } 0157 0158 /// Increases the amount of workers by one 0159 func handleTTIN
Arbiter.swift:77 signalHandler.register(.Terminate, handleTerminate)() { 0160 numberOfWorkers += 1 0161 manageWorkers() 0162 } 0163 0164 /// Decreases the amount of workers by one 0165 func handleTTOU
Arbiter.swift:78 signalHandler.register(.TTIN, handleTTIN)() { 0166 if numberOfWorkers > 1 { 0167 numberOfWorkers -= 1 0168 manageWorkers() 0169 } 0170 } 0171 0172 func handleChild
Arbiter.swift:79 signalHandler.register(.TTOU, handleTTOU)() { 0173 while true { 0174 var stat: Int32 = 0 0175 let pid = waitpid(-1, &stat, WNOHANG) 0176 if pid == -1 { 0177 break 0178 } 0179 0180 workers.removeValueForKey(pid) 0181 } 0182 0183 manageWorkers() 0184 } 0185 0186 // MARK: Worker 0187 0188 // Maintain number of workers by spawning or killing as required. 0189 func manageWorkers
Arbiter.swift:80 signalHandler.register(.Child, handleChild)() { 0190 spawnWorkers() 0191 murderExcessWorkers() 0192 } 0193 0194 // Spawn workers until we have enough 0195 func spawnWorkers
Arbiter.swift:94 manageWorkers()Arbiter.swift:100 manageWorkers()Arbiter.swift:161 manageWorkers()Arbiter.swift:168 manageWorkers()Arbiter.swift:183 manageWorkers()() { 0196 let neededWorkers = numberOfWorkers - workers.count 0197 if neededWorkers > 0 { 0198 for _ in 0..<neededWorkers { 0199 spawnWorker() 0200 } 0201 } 0202 } 0203 0204 // Murder workers that have timed out 0205 func murderWorkers
Arbiter.swift:190 spawnWorkers()() { 0206 if configuration.timeout == 0 { return } 0207 0208 var currentTime = timeval() 0209 gettimeofday(¤tTime, nil) 0210 0211 for (pid, worker) in workers { 0212 let lastUpdate = currentTime.tv_sec - worker.temp.lastUpdate.tv_sec 0213 0214 if lastUpdate >= configuration.timeout { 0215 if worker.aborted { 0216 if kill(pid, SIGKILL) == ESRCH { 0217 workers.removeValueForKey(pid) 0218 } 0219 } else { 0220 worker.aborted = true 0221 0222 logger.critical("Worker timeout (pid: \(pid))") 0223 0224 if kill(pid, SIGABRT) == ESRCH { 0225 workers.removeValueForKey(pid) 0226 } 0227 } 0228 } 0229 } 0230 } 0231 0232 // Murder unused workers, oldest first 0233 func murderExcessWorkers
Arbiter.swift:99 murderWorkers()() { 0234 let killCount = workers.count - numberOfWorkers 0235 if killCount > 0 { 0236 for _ in 0..<killCount { 0237 if let (pid, _) = workers.popFirst() { 0238 kill(pid, SIGKILL) 0239 } 0240 } 0241 } 0242 } 0243 0244 // Kill all workers with given signal 0245 func killWorkers
Arbiter.swift:191 murderExcessWorkers()(signal: Int32) { 0246 for pid in workers.keys { 0247 kill(pid, signal) 0248 } 0249 } 0250 0251 // Spawns a new worker process 0252 func spawnWorker
Arbiter.swift:111 killWorkers(SIGTERM)Arbiter.swift:113 killWorkers(SIGQUIT)() { 0253 let workerProcess = WorkerProcess() 0254 let worker = Worker(configuration: configuration, logger: logger, listeners: listeners, notify: workerProcess.notify, application: application) 0255 0256 let pid = system_fork() 0257 if pid != 0 { 0258 workers[pid] = workerProcess 0259 return 0260 } 0261 0262 let workerPid = getpid() 0263 worker.run() 0264 logger.info("Worker exiting (pid: \(workerPid))") 0265 exit(0) 0266 } 0267 } 0268
Arbiter.swift:199 spawnWorker()