Skip to content

Instantly share code, notes, and snippets.

@cstorey
Last active December 17, 2015 12:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cstorey/5608451 to your computer and use it in GitHub Desktop.
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
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
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