Skip to content

Commit 8354596

Browse files
committed
use atomic.Pointer instead of unsafe.Pointer atomics
1 parent da26d58 commit 8354596

6 files changed

Lines changed: 46 additions & 57 deletions

File tree

‎logger.go‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -474,16 +474,16 @@ type timeHeader struct {
474474
}
475475

476476
var timeHeaderPointers struct {
477-
utc unsafe.Pointer
478-
local unsafe.Pointer
477+
utc atomic.Pointer[timeHeader]
478+
local atomic.Pointer[timeHeader]
479479
}
480480

481481
type timestampCache struct {
482482
sec int64
483483
nsec int32
484484
}
485485

486-
var timestampCachePointer unsafe.Pointer // *timestampCache
486+
var timestampCachePointer atomic.Pointer[timestampCache]
487487
var timestampCacheMu sync.Mutex
488488
var timestampCacheStop, timestampCacheDone chan struct{}
489489

@@ -511,10 +511,10 @@ func EnableTimeCache(interval time.Duration) {
511511
if tc.sec == 0 {
512512
tc.sec, tc.nsec, _ = now()
513513
}
514-
atomic.StorePointer(&timestampCachePointer, unsafe.Pointer(&tc))
514+
timestampCachePointer.Store(&tc)
515515
go func() {
516516
defer close(done)
517-
defer atomic.StorePointer(&timestampCachePointer, nil)
517+
defer timestampCachePointer.Store(nil)
518518
defer ticker.Stop()
519519
for {
520520
select {
@@ -526,7 +526,7 @@ func EnableTimeCache(interval time.Duration) {
526526
if tc.sec == 0 {
527527
tc.sec, tc.nsec, _ = now()
528528
}
529-
atomic.StorePointer(&timestampCachePointer, unsafe.Pointer(&tc))
529+
timestampCachePointer.Store(&tc)
530530
}
531531
}
532532
}()
@@ -563,8 +563,7 @@ func (l *Logger) header(level Level) *Entry {
563563
format = "2006-01-02T15:04:05.000Z07:00"
564564
}
565565
var now time.Time
566-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
567-
tt := (*timestampCache)(p)
566+
if tt := timestampCachePointer.Load(); tt != nil {
568567
now = time.Unix(tt.sec, int64(tt.nsec))
569568
} else {
570569
now = Now()
@@ -579,8 +578,7 @@ func (l *Logger) header(level Level) *Entry {
579578
case "", time.RFC3339, time.RFC3339Nano:
580579
var sec int64
581580
var nsec int32
582-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
583-
tt := (*timestampCache)(p)
581+
if tt := timestampCachePointer.Load(); tt != nil {
584582
sec, nsec = tt.sec, tt.nsec
585583
}
586584
if sec == 0 {
@@ -589,15 +587,15 @@ func (l *Logger) header(level Level) *Entry {
589587
if sec == 0 {
590588
sec, nsec, _ = now()
591589
}
592-
var tp *unsafe.Pointer
590+
var tp *atomic.Pointer[timeHeader]
593591
if offset == 0 {
594592
tp = &timeHeaderPointers.utc
595593
} else {
596594
tp = &timeHeaderPointers.local
597595
}
598596
var tmp [40]byte // up to 37 bytes, e.g. "2006-01-02T15:04:05.999999999Z07:00"
599597
tmp[0] = '"'
600-
if c := (*timeHeader)(atomic.LoadPointer(tp)); c != nil && c.sec == sec {
598+
if c := tp.Load(); c != nil && c.sec == sec {
601599
copy(tmp[1:20], c.b[:])
602600
} else {
603601
// date time
@@ -638,7 +636,7 @@ func (l *Logger) header(level Level) *Entry {
638636
nc.b[18] = smallsString[second+1]
639637
// publish for the next line
640638
copy(tmp[1:20], nc.b[:])
641-
atomic.StorePointer(tp, unsafe.Pointer(nc))
639+
tp.Store(nc)
642640
}
643641
// fractional seconds and timezone, which differ between formats
644642
i := 20
@@ -704,8 +702,8 @@ func (l *Logger) header(level Level) *Entry {
704702
e.buf = append(e.buf, tmp[:i]...)
705703
case TimeFormatUnix:
706704
var sec int64
707-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
708-
sec = (*timestampCache)(p).sec
705+
if tt := timestampCachePointer.Load(); tt != nil {
706+
sec = tt.sec
709707
}
710708
if sec == 0 {
711709
sec, _ = walltime()
@@ -740,8 +738,7 @@ func (l *Logger) header(level Level) *Entry {
740738
case TimeFormatUnixMs:
741739
var sec int64
742740
var nsec int32
743-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
744-
tt := (*timestampCache)(p)
741+
if tt := timestampCachePointer.Load(); tt != nil {
745742
sec, nsec = tt.sec, tt.nsec
746743
}
747744
if sec == 0 {
@@ -783,8 +780,7 @@ func (l *Logger) header(level Level) *Entry {
783780
case TimeFormatUnixWithMs:
784781
var sec int64
785782
var nsec int32
786-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
787-
tt := (*timestampCache)(p)
783+
if tt := timestampCachePointer.Load(); tt != nil {
788784
sec, nsec = tt.sec, tt.nsec
789785
}
790786
if sec == 0 {
@@ -826,8 +822,7 @@ func (l *Logger) header(level Level) *Entry {
826822
e.buf = append(e.buf, tmp[:]...)
827823
default:
828824
var now time.Time
829-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
830-
tt := (*timestampCache)(p)
825+
if tt := timestampCachePointer.Load(); tt != nil {
831826
now = time.Unix(tt.sec, int64(tt.nsec))
832827
} else {
833828
now = Now()

‎logger_std_slog.go‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"os"
77
"sync/atomic"
88
"time"
9-
"unsafe"
109
)
1110

1211
func stdSlogAttrEval(e *Entry, a slog.Attr) *Entry {
@@ -74,8 +73,8 @@ type stdSlogTimeHeader struct {
7473
}
7574

7675
var stdSlogTimeHeaderPointers struct {
77-
utc unsafe.Pointer
78-
local unsafe.Pointer
76+
utc atomic.Pointer[stdSlogTimeHeader]
77+
local atomic.Pointer[stdSlogTimeHeader]
7978
}
8079

8180
func (h stdSlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
@@ -151,7 +150,7 @@ func (h *stdSlogHandler) header(now time.Time) *Entry {
151150
switch h.logger.TimeFormat {
152151
case "":
153152
sec, nsec := now.Unix(), now.Nanosecond()
154-
var tp *unsafe.Pointer
153+
var tp *atomic.Pointer[stdSlogTimeHeader]
155154
var tmp [32]byte
156155
var buf []byte
157156
if timeOffset == 0 {
@@ -173,7 +172,7 @@ func (h *stdSlogHandler) header(now time.Time) *Entry {
173172
buf = tmp[:31]
174173
}
175174
tmp[0] = '"'
176-
if c := (*stdSlogTimeHeader)(atomic.LoadPointer(tp)); c != nil && c.sec == sec {
175+
if c := tp.Load(); c != nil && c.sec == sec {
177176
copy(tmp[1:21], c.b[:])
178177
} else {
179178
// date time
@@ -215,7 +214,7 @@ func (h *stdSlogHandler) header(now time.Time) *Entry {
215214
nc.b[19] = '.'
216215
// publish for the next line
217216
copy(tmp[1:21], nc.b[:])
218-
atomic.StorePointer(tp, unsafe.Pointer(nc))
217+
tp.Store(nc)
219218
}
220219
// milli seconds
221220
ms := uint32(nsec) / 1000000

‎logger_test.go‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ import (
1313
"net/netip"
1414
"os"
1515
"strings"
16-
"sync/atomic"
1716
"testing"
1817
"time"
19-
"unsafe"
2018
)
2119

2220
// TestAppendFloat checks that appendFloat writes the same bytes as
@@ -866,7 +864,7 @@ func TestLoggerTimeFormatHeader(t *testing.T) {
866864
// to check the fractional digits of every cached format against time.Format,
867865
// including the boundary values a live clock rarely hits.
868866
func TestLoggerTimeFormatHeaderDigits(t *testing.T) {
869-
defer atomic.StorePointer(&timestampCachePointer, nil)
867+
defer timestampCachePointer.Store(nil)
870868
nsecs := []int32{0, 1, 9, 10, 99, 100, 999999, 1000000, 99999, 100000, 100001, 120000000, 123456789, 500000000, 999999999}
871869
for i := 0; i < 20000; i++ {
872870
nsecs = append(nsecs, rand.Int31n(1e9))
@@ -883,7 +881,7 @@ func TestLoggerTimeFormatHeaderDigits(t *testing.T) {
883881
var buf bytes.Buffer
884882
logger := Logger{TimeFormat: c.format, TimeLocation: time.UTC, Writer: IOWriter{&buf}}
885883
for _, nsec := range nsecs {
886-
atomic.StorePointer(&timestampCachePointer, unsafe.Pointer(&timestampCache{sec: sec, nsec: nsec}))
884+
timestampCachePointer.Store(&timestampCache{sec: sec, nsec: nsec})
887885
buf.Reset()
888886
logger.Info().Msg("")
889887
want := `{"` + TimeKey + `":"` + time.Unix(sec, int64(nsec)).UTC().Format(c.layout) + `"`

‎slog.go‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"strings"
99
"sync/atomic"
1010
"time"
11-
"unsafe"
1211
)
1312

1413
func slogJSONAttrEval(e *Entry, a slog.Attr) *Entry {
@@ -118,8 +117,8 @@ type slogTimeHeader struct {
118117
}
119118

120119
var slogTimeHeaderPointers struct {
121-
utc unsafe.Pointer
122-
local unsafe.Pointer
120+
utc atomic.Pointer[slogTimeHeader]
121+
local atomic.Pointer[slogTimeHeader]
123122
}
124123

125124
func (h *slogJSONHandler) Handle(_ context.Context, r slog.Record) error {
@@ -135,7 +134,7 @@ func (h *slogJSONHandler) Handle(_ context.Context, r slog.Record) error {
135134
e.buf = append(e.buf, `":"`...)
136135
if timeOffset == 0 || r.Time.Location() == time.Local {
137136
sec, nsec := r.Time.Unix(), r.Time.Nanosecond()
138-
var tp *unsafe.Pointer
137+
var tp *atomic.Pointer[slogTimeHeader]
139138
var tmp [35]byte
140139
var buf []byte
141140
if timeOffset == 0 {
@@ -154,7 +153,7 @@ func (h *slogJSONHandler) Handle(_ context.Context, r slog.Record) error {
154153
tmp[29] = timeZone[0]
155154
buf = tmp[:35]
156155
}
157-
if c := (*slogTimeHeader)(atomic.LoadPointer(tp)); c != nil && c.sec == sec {
156+
if c := tp.Load(); c != nil && c.sec == sec {
158157
copy(tmp[:20], c.b[:])
159158
} else {
160159
// date time
@@ -196,7 +195,7 @@ func (h *slogJSONHandler) Handle(_ context.Context, r slog.Record) error {
196195
// publish for the next line
197196
nc := &slogTimeHeader{sec: sec}
198197
copy(nc.b[:], tmp[:20])
199-
atomic.StorePointer(tp, unsafe.Pointer(nc))
198+
tp.Store(nc)
200199
}
201200
// nano seconds
202201
// unsigned, so the divisions by constants need no sign fixups

‎syslog.go‎

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"sync"
77
"sync/atomic"
88
"time"
9-
"unsafe"
109
)
1110

1211
// SyslogWriter is an Writer that writes logs to a syslog server..
@@ -30,7 +29,7 @@ type SyslogWriter struct {
3029
Dial func(network, addr string) (net.Conn, error)
3130

3231
mu sync.Mutex
33-
conn *net.Conn
32+
conn atomic.Pointer[net.Conn]
3433
local bool
3534
}
3635

@@ -39,19 +38,19 @@ func (w *SyslogWriter) Close() (err error) {
3938
w.mu.Lock()
4039
defer w.mu.Unlock()
4140

42-
if w.conn != nil {
43-
err = (*w.conn).Close()
44-
w.conn = nil
41+
if c := w.conn.Load(); c != nil {
42+
err = (*c).Close()
43+
w.conn.Store(nil)
4544
return
4645
}
4746
return
4847
}
4948

5049
// connect makes a connection to the syslog server.
5150
func (w *SyslogWriter) connect() (err error) {
52-
if w.conn != nil {
53-
(*w.conn).Close()
54-
w.conn = nil
51+
if c := w.conn.Load(); c != nil {
52+
(*c).Close()
53+
w.conn.Store(nil)
5554
}
5655

5756
var dial = w.Dial
@@ -64,15 +63,15 @@ func (w *SyslogWriter) connect() (err error) {
6463
if err != nil {
6564
return
6665
}
67-
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&w.conn)), unsafe.Pointer(&conn))
66+
w.conn.Store(&conn)
6867

6968
w.local = w.Address != "" && w.Address[0] == '/'
7069

7170
if w.Hostname == "" {
7271
if w.local {
7372
w.Hostname = hostname
7473
} else {
75-
w.Hostname, _, _ = net.SplitHostPort((*w.conn).LocalAddr().String())
74+
w.Hostname, _, _ = net.SplitHostPort(conn.LocalAddr().String())
7675
}
7776
}
7877

@@ -81,9 +80,9 @@ func (w *SyslogWriter) connect() (err error) {
8180

8281
// WriteEntry implements Writer, sends logs with priority to the syslog server.
8382
func (w *SyslogWriter) WriteEntry(e *Entry) (n int, err error) {
84-
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&w.conn))) == nil {
83+
if w.conn.Load() == nil {
8584
w.mu.Lock()
86-
if w.conn == nil {
85+
if w.conn.Load() == nil {
8786
err = w.connect()
8887
if err != nil {
8988
w.mu.Unlock()
@@ -144,15 +143,16 @@ func (w *SyslogWriter) WriteEntry(e *Entry) (n int, err error) {
144143
w.mu.Lock()
145144
defer w.mu.Unlock()
146145

147-
if w.conn != nil {
148-
if n, err := (*w.conn).Write(e1.buf); err == nil {
146+
if c := w.conn.Load(); c != nil {
147+
if n, err := (*c).Write(e1.buf); err == nil {
149148
return n, err
150149
}
151150
}
152151
if err := w.connect(); err != nil {
153152
return 0, err
154153
}
155-
return (*w.conn).Write(e1.buf)
154+
c := w.conn.Load()
155+
return (*c).Write(e1.buf)
156156
}
157157

158158
var _ Writer = (*SyslogWriter)(nil)

‎tsv.go‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"os"
88
"strconv"
99
"sync"
10-
"sync/atomic"
1110
)
1211

1312
// TSVLogger represents an active logging object that generates lines of TSV output to an io.Writer.
@@ -49,8 +48,8 @@ func (l *TSVLogger) New() (e *TSVEntry) {
4948
func (e *TSVEntry) Timestamp() *TSVEntry {
5049
var tmp [11]byte
5150
var sec int64
52-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
53-
sec = (*timestampCache)(p).sec
51+
if tt := timestampCachePointer.Load(); tt != nil {
52+
sec = tt.sec
5453
}
5554
if sec == 0 {
5655
sec, _ = walltime()
@@ -90,8 +89,7 @@ func (e *TSVEntry) TimestampMS() *TSVEntry {
9089
var tmp [14]byte
9190
var sec int64
9291
var nsec int32
93-
if p := atomic.LoadPointer(&timestampCachePointer); p != nil {
94-
tt := (*timestampCache)(p)
92+
if tt := timestampCachePointer.Load(); tt != nil {
9593
sec, nsec = tt.sec, tt.nsec
9694
}
9795
if sec == 0 {

0 commit comments

Comments
 (0)