Implement swap handler with atomic pointer operations

This is a fix for the comment made by @edsrzf on https://github.com/inconshreveable/log15/commit/da1a931cd91766297e8e10a5df4c826ab3156270

Instead of using a R/W lock to synchronize access to the swappable handler, instead we use atomic load/store pointer operations which are much faster. Benchmarks are also included to demonstrate the speedup:

Before:
    inconshreveable [~/src/log15] ♡ : go test -run nil -bench Descendant
    PASS
    BenchmarkDescendant1	 2000000	       841 ns/op
    BenchmarkDescendant2	 2000000	       955 ns/op
    BenchmarkDescendant4	 1000000	      1052 ns/op
    BenchmarkDescendant8	 1000000	      1346 ns/op

After:
    inconshreveable [~/src/log15] ♡ : go test -run nil -bench Descendant
    PASS
    BenchmarkDescendant1	 5000000	       710 ns/op
    BenchmarkDescendant2	 5000000	       742 ns/op
    BenchmarkDescendant4	 2000000	       723 ns/op
    BenchmarkDescendant8	 2000000	       804 ns/op

Base logging overhead is now dominated by the manipulation of the context values (which I think I have another fix for) and by the overhead of runtime.Callers.

1.4 makes this easier with atomic.Value, but I don't think it's worth the extra code to have a separate 1.4 file.

Please review @ChrisHines @edsrzf