Last active
December 17, 2015 12:19
-
-
Save cstorey/5608451 to your computer and use it in GitHub Desktop.
Lock free Proxy class for the ruby stdlib Logger that can be used from within a signal handler. Not 100% ready for production use, as it cannot currently recover from failures of the logger thread. Lock free queue implementation based on http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative 'mpsc' | |
class LoggerProxy | |
def initialize target | |
@target = target | |
@queue = MpscQueue.new | |
end | |
def start! | |
@reader, @writer = IO.pipe | |
@thread ||= Thread.new { consume } | |
end | |
def error *args | |
send [:error] + args | |
end | |
def warn *args | |
send [:warn] + args | |
end | |
def info *args | |
send [:info] + args | |
end | |
def debug *args | |
send [:debug] + args | |
end | |
def close | |
send :close | |
@thread.join | |
end | |
private | |
def send message | |
@queue.push message | |
@writer.write('!') | |
end | |
def consume | |
while true | |
@reader.read(1) | |
message = @queue.pop | |
return if message == :close | |
@target.send(*message) | |
end | |
rescue => e | |
$stderr.puts e, e.backtrace | |
end | |
end | |
if __FILE__ == $0 | |
require 'logger' | |
log = LoggerProxy.new(Logger.new('test.log', 10, 400)) | |
log.start! | |
Signal.trap('USR1') { |*args| log.info "Signal handler called with: #{args.inspect}" } | |
10.times do | |
log.info("Signalling self") | |
Process.kill('USR1', Process.pid) | |
end | |
# This is so that all of the signals have a chance to be delivered. | |
sleep 0.1 | |
log.close | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'atomic' | |
class MpscNode < Struct.new :next_el, :state | |
end | |
class MpscQueue < Struct.new :head, :tail | |
def initialize | |
self.head = Atomic.new(MpscNode.new) | |
self.tail = head.get | |
end | |
def push val | |
n = MpscNode.new(nil, val) | |
prev = head.swap(n) | |
prev.next_el = n | |
end | |
def pop | |
tl = self.tail | |
nxt = tl.next_el | |
if nxt | |
self.tail = nxt | |
ret = nxt.state | |
end | |
return ret | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment