* gcc.dg/torture/stackalign/builtin-apply-2.c: Fix skip-if syntax.
[official-gcc.git] / libgo / go / expvar / expvar.go
blob7339fa00b79ee5449e43efe9fe70952bc080d63f
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 mu sync.RWMutex
103 m map[string]Var
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 v.mu.RLock()
115 defer v.mu.RUnlock()
116 var b bytes.Buffer
117 fmt.Fprintf(&b, "{")
118 first := true
119 v.doLocked(func(kv KeyValue) {
120 if !first {
121 fmt.Fprintf(&b, ", ")
123 fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
124 first = false
126 fmt.Fprintf(&b, "}")
127 return b.String()
130 func (v *Map) Init() *Map {
131 v.m = make(map[string]Var)
132 return v
135 // updateKeys updates the sorted list of keys in v.keys.
136 // must be called with v.mu held.
137 func (v *Map) updateKeys() {
138 if len(v.m) == len(v.keys) {
139 // No new key.
140 return
142 v.keys = v.keys[:0]
143 for k := range v.m {
144 v.keys = append(v.keys, k)
146 sort.Strings(v.keys)
149 func (v *Map) Get(key string) Var {
150 v.mu.RLock()
151 defer v.mu.RUnlock()
152 return v.m[key]
155 func (v *Map) Set(key string, av Var) {
156 v.mu.Lock()
157 defer v.mu.Unlock()
158 v.m[key] = av
159 v.updateKeys()
162 func (v *Map) Add(key string, delta int64) {
163 v.mu.RLock()
164 av, ok := v.m[key]
165 v.mu.RUnlock()
166 if !ok {
167 // check again under the write lock
168 v.mu.Lock()
169 av, ok = v.m[key]
170 if !ok {
171 av = new(Int)
172 v.m[key] = av
173 v.updateKeys()
175 v.mu.Unlock()
178 // Add to Int; ignore otherwise.
179 if iv, ok := av.(*Int); ok {
180 iv.Add(delta)
184 // AddFloat adds delta to the *Float value stored under the given map key.
185 func (v *Map) AddFloat(key string, delta float64) {
186 v.mu.RLock()
187 av, ok := v.m[key]
188 v.mu.RUnlock()
189 if !ok {
190 // check again under the write lock
191 v.mu.Lock()
192 av, ok = v.m[key]
193 if !ok {
194 av = new(Float)
195 v.m[key] = av
196 v.updateKeys()
198 v.mu.Unlock()
201 // Add to Float; ignore otherwise.
202 if iv, ok := av.(*Float); ok {
203 iv.Add(delta)
207 // Do calls f for each entry in the map.
208 // The map is locked during the iteration,
209 // but existing entries may be concurrently updated.
210 func (v *Map) Do(f func(KeyValue)) {
211 v.mu.RLock()
212 defer v.mu.RUnlock()
213 v.doLocked(f)
216 // doLocked calls f for each entry in the map.
217 // v.mu must be held for reads.
218 func (v *Map) doLocked(f func(KeyValue)) {
219 for _, k := range v.keys {
220 f(KeyValue{k, v.m[k]})
224 // String is a string variable, and satisfies the Var interface.
225 type String struct {
226 mu sync.RWMutex
227 s string
230 func (v *String) Value() string {
231 v.mu.RLock()
232 defer v.mu.RUnlock()
233 return v.s
236 // String implements the Val interface. To get the unquoted string
237 // use Value.
238 func (v *String) String() string {
239 v.mu.RLock()
240 s := v.s
241 v.mu.RUnlock()
242 b, _ := json.Marshal(s)
243 return string(b)
246 func (v *String) Set(value string) {
247 v.mu.Lock()
248 defer v.mu.Unlock()
249 v.s = value
252 // Func implements Var by calling the function
253 // and formatting the returned value using JSON.
254 type Func func() interface{}
256 func (f Func) Value() interface{} {
257 return f()
260 func (f Func) String() string {
261 v, _ := json.Marshal(f())
262 return string(v)
265 // All published variables.
266 var (
267 mutex sync.RWMutex
268 vars = make(map[string]Var)
269 varKeys []string // sorted
272 // Publish declares a named exported variable. This should be called from a
273 // package's init function when it creates its Vars. If the name is already
274 // registered then this will log.Panic.
275 func Publish(name string, v Var) {
276 mutex.Lock()
277 defer mutex.Unlock()
278 if _, existing := vars[name]; existing {
279 log.Panicln("Reuse of exported var name:", name)
281 vars[name] = v
282 varKeys = append(varKeys, name)
283 sort.Strings(varKeys)
286 // Get retrieves a named exported variable. It returns nil if the name has
287 // not been registered.
288 func Get(name string) Var {
289 mutex.RLock()
290 defer mutex.RUnlock()
291 return vars[name]
294 // Convenience functions for creating new exported variables.
296 func NewInt(name string) *Int {
297 v := new(Int)
298 Publish(name, v)
299 return v
302 func NewFloat(name string) *Float {
303 v := new(Float)
304 Publish(name, v)
305 return v
308 func NewMap(name string) *Map {
309 v := new(Map).Init()
310 Publish(name, v)
311 return v
314 func NewString(name string) *String {
315 v := new(String)
316 Publish(name, v)
317 return v
320 // Do calls f for each exported variable.
321 // The global variable map is locked during the iteration,
322 // but existing entries may be concurrently updated.
323 func Do(f func(KeyValue)) {
324 mutex.RLock()
325 defer mutex.RUnlock()
326 for _, k := range varKeys {
327 f(KeyValue{k, vars[k]})
331 func expvarHandler(w http.ResponseWriter, r *http.Request) {
332 w.Header().Set("Content-Type", "application/json; charset=utf-8")
333 fmt.Fprintf(w, "{\n")
334 first := true
335 Do(func(kv KeyValue) {
336 if !first {
337 fmt.Fprintf(w, ",\n")
339 first = false
340 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
342 fmt.Fprintf(w, "\n}\n")
345 // Handler returns the expvar HTTP Handler.
347 // This is only needed to install the handler in a non-standard location.
348 func Handler() http.Handler {
349 return http.HandlerFunc(expvarHandler)
352 func cmdline() interface{} {
353 return os.Args
356 func memstats() interface{} {
357 stats := new(runtime.MemStats)
358 runtime.ReadMemStats(stats)
359 return *stats
362 func init() {
363 http.HandleFunc("/debug/vars", expvarHandler)
364 Publish("cmdline", Func(cmdline))
365 Publish("memstats", Func(memstats))