libgo: update to go1.9
[official-gcc.git] / libgo / go / expvar / expvar.go
blob64dae70c627063e5100315e8d8b2de3f17877dd1
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package expvar provides a standardized interface to public variables, such
6 // as operation counters in servers. It exposes these variables via HTTP at
7 // /debug/vars in JSON format.
8 //
9 // Operations to set or modify these public variables are atomic.
11 // In addition to adding the HTTP handler, this package registers the
12 // following variables:
14 // cmdline os.Args
15 // memstats runtime.Memstats
17 // The package is sometimes only imported for the side effect of
18 // registering its HTTP handler and the above variables. To use it
19 // this way, link this package into your program:
20 // import _ "expvar"
22 package expvar
24 import (
25 "bytes"
26 "encoding/json"
27 "fmt"
28 "log"
29 "math"
30 "net/http"
31 "os"
32 "runtime"
33 "sort"
34 "strconv"
35 "sync"
36 "sync/atomic"
39 // Var is an abstract type for all exported variables.
40 type Var interface {
41 // String returns a valid JSON value for the variable.
42 // Types with String methods that do not return valid JSON
43 // (such as time.Time) must not be used as a Var.
44 String() string
47 // Int is a 64-bit integer variable that satisfies the Var interface.
48 type Int struct {
49 i int64
52 func (v *Int) Value() int64 {
53 return atomic.LoadInt64(&v.i)
56 func (v *Int) String() string {
57 return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
60 func (v *Int) Add(delta int64) {
61 atomic.AddInt64(&v.i, delta)
64 func (v *Int) Set(value int64) {
65 atomic.StoreInt64(&v.i, value)
68 // Float is a 64-bit float variable that satisfies the Var interface.
69 type Float struct {
70 f uint64
73 func (v *Float) Value() float64 {
74 return math.Float64frombits(atomic.LoadUint64(&v.f))
77 func (v *Float) String() string {
78 return strconv.FormatFloat(
79 math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
82 // Add adds delta to v.
83 func (v *Float) Add(delta float64) {
84 for {
85 cur := atomic.LoadUint64(&v.f)
86 curVal := math.Float64frombits(cur)
87 nxtVal := curVal + delta
88 nxt := math.Float64bits(nxtVal)
89 if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
90 return
95 // Set sets v to value.
96 func (v *Float) Set(value float64) {
97 atomic.StoreUint64(&v.f, math.Float64bits(value))
100 // Map is a string-to-Var map variable that satisfies the Var interface.
101 type Map struct {
102 m sync.Map // map[string]Var
103 keysMu sync.RWMutex
104 keys []string // sorted
107 // KeyValue represents a single entry in a Map.
108 type KeyValue struct {
109 Key string
110 Value Var
113 func (v *Map) String() string {
114 var b bytes.Buffer
115 fmt.Fprintf(&b, "{")
116 first := true
117 v.Do(func(kv KeyValue) {
118 if !first {
119 fmt.Fprintf(&b, ", ")
121 fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
122 first = false
124 fmt.Fprintf(&b, "}")
125 return b.String()
128 func (v *Map) Init() *Map { return v }
130 // updateKeys updates the sorted list of keys in v.keys.
131 func (v *Map) addKey(key string) {
132 v.keysMu.Lock()
133 defer v.keysMu.Unlock()
134 v.keys = append(v.keys, key)
135 sort.Strings(v.keys)
138 func (v *Map) Get(key string) Var {
139 i, _ := v.m.Load(key)
140 av, _ := i.(Var)
141 return av
144 func (v *Map) Set(key string, av Var) {
145 // Before we store the value, check to see whether the key is new. Try a Load
146 // before LoadOrStore: LoadOrStore causes the key interface to escape even on
147 // the Load path.
148 if _, ok := v.m.Load(key); !ok {
149 if _, dup := v.m.LoadOrStore(key, av); !dup {
150 v.addKey(key)
151 return
155 v.m.Store(key, av)
158 // Add adds delta to the *Int value stored under the given map key.
159 func (v *Map) Add(key string, delta int64) {
160 i, ok := v.m.Load(key)
161 if !ok {
162 var dup bool
163 i, dup = v.m.LoadOrStore(key, new(Int))
164 if !dup {
165 v.addKey(key)
169 // Add to Int; ignore otherwise.
170 if iv, ok := i.(*Int); ok {
171 iv.Add(delta)
175 // AddFloat adds delta to the *Float value stored under the given map key.
176 func (v *Map) AddFloat(key string, delta float64) {
177 i, ok := v.m.Load(key)
178 if !ok {
179 var dup bool
180 i, dup = v.m.LoadOrStore(key, new(Float))
181 if !dup {
182 v.addKey(key)
186 // Add to Float; ignore otherwise.
187 if iv, ok := i.(*Float); ok {
188 iv.Add(delta)
192 // Do calls f for each entry in the map.
193 // The map is locked during the iteration,
194 // but existing entries may be concurrently updated.
195 func (v *Map) Do(f func(KeyValue)) {
196 v.keysMu.RLock()
197 defer v.keysMu.RUnlock()
198 for _, k := range v.keys {
199 i, _ := v.m.Load(k)
200 f(KeyValue{k, i.(Var)})
204 // String is a string variable, and satisfies the Var interface.
205 type String struct {
206 s atomic.Value // string
209 func (v *String) Value() string {
210 p, _ := v.s.Load().(string)
211 return p
214 // String implements the Val interface. To get the unquoted string
215 // use Value.
216 func (v *String) String() string {
217 s := v.Value()
218 b, _ := json.Marshal(s)
219 return string(b)
222 func (v *String) Set(value string) {
223 v.s.Store(value)
226 // Func implements Var by calling the function
227 // and formatting the returned value using JSON.
228 type Func func() interface{}
230 func (f Func) Value() interface{} {
231 return f()
234 func (f Func) String() string {
235 v, _ := json.Marshal(f())
236 return string(v)
239 // All published variables.
240 var (
241 vars sync.Map // map[string]Var
242 varKeysMu sync.RWMutex
243 varKeys []string // sorted
246 // Publish declares a named exported variable. This should be called from a
247 // package's init function when it creates its Vars. If the name is already
248 // registered then this will log.Panic.
249 func Publish(name string, v Var) {
250 if _, dup := vars.LoadOrStore(name, v); dup {
251 log.Panicln("Reuse of exported var name:", name)
253 varKeysMu.Lock()
254 defer varKeysMu.Unlock()
255 varKeys = append(varKeys, name)
256 sort.Strings(varKeys)
259 // Get retrieves a named exported variable. It returns nil if the name has
260 // not been registered.
261 func Get(name string) Var {
262 i, _ := vars.Load(name)
263 v, _ := i.(Var)
264 return v
267 // Convenience functions for creating new exported variables.
269 func NewInt(name string) *Int {
270 v := new(Int)
271 Publish(name, v)
272 return v
275 func NewFloat(name string) *Float {
276 v := new(Float)
277 Publish(name, v)
278 return v
281 func NewMap(name string) *Map {
282 v := new(Map).Init()
283 Publish(name, v)
284 return v
287 func NewString(name string) *String {
288 v := new(String)
289 Publish(name, v)
290 return v
293 // Do calls f for each exported variable.
294 // The global variable map is locked during the iteration,
295 // but existing entries may be concurrently updated.
296 func Do(f func(KeyValue)) {
297 varKeysMu.RLock()
298 defer varKeysMu.RUnlock()
299 for _, k := range varKeys {
300 val, _ := vars.Load(k)
301 f(KeyValue{k, val.(Var)})
305 func expvarHandler(w http.ResponseWriter, r *http.Request) {
306 w.Header().Set("Content-Type", "application/json; charset=utf-8")
307 fmt.Fprintf(w, "{\n")
308 first := true
309 Do(func(kv KeyValue) {
310 if !first {
311 fmt.Fprintf(w, ",\n")
313 first = false
314 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
316 fmt.Fprintf(w, "\n}\n")
319 // Handler returns the expvar HTTP Handler.
321 // This is only needed to install the handler in a non-standard location.
322 func Handler() http.Handler {
323 return http.HandlerFunc(expvarHandler)
326 func cmdline() interface{} {
327 return os.Args
330 func memstats() interface{} {
331 stats := new(runtime.MemStats)
332 runtime.ReadMemStats(stats)
333 return *stats
336 func init() {
337 http.HandleFunc("/debug/vars", expvarHandler)
338 Publish("cmdline", Func(cmdline))
339 Publish("memstats", Func(memstats))