1// Copyright 2016 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.
4
5package context_test
6
7import (
8	"context"
9	"errors"
10	"fmt"
11	"net"
12	"sync"
13	"time"
14)
15
16var neverReady = make(chan struct{}) // never closed
17
18// This example demonstrates the use of a cancelable context to prevent a
19// goroutine leak. By the end of the example function, the goroutine started
20// by gen will return without leaking.
21func ExampleWithCancel() {
22	// gen generates integers in a separate goroutine and
23	// sends them to the returned channel.
24	// The callers of gen need to cancel the context once
25	// they are done consuming generated integers not to leak
26	// the internal goroutine started by gen.
27	gen := func(ctx context.Context) <-chan int {
28		dst := make(chan int)
29		n := 1
30		go func() {
31			for {
32				select {
33				case <-ctx.Done():
34					return // returning not to leak the goroutine
35				case dst <- n:
36					n++
37				}
38			}
39		}()
40		return dst
41	}
42
43	ctx, cancel := context.WithCancel(context.Background())
44	defer cancel() // cancel when we are finished consuming integers
45
46	for n := range gen(ctx) {
47		fmt.Println(n)
48		if n == 5 {
49			break
50		}
51	}
52	// Output:
53	// 1
54	// 2
55	// 3
56	// 4
57	// 5
58}
59
60// This example passes a context with an arbitrary deadline to tell a blocking
61// function that it should abandon its work as soon as it gets to it.
62func ExampleWithDeadline() {
63	d := time.Now().Add(shortDuration)
64	ctx, cancel := context.WithDeadline(context.Background(), d)
65
66	// Even though ctx will be expired, it is good practice to call its
67	// cancellation function in any case. Failure to do so may keep the
68	// context and its parent alive longer than necessary.
69	defer cancel()
70
71	select {
72	case <-neverReady:
73		fmt.Println("ready")
74	case <-ctx.Done():
75		fmt.Println(ctx.Err())
76	}
77
78	// Output:
79	// context deadline exceeded
80}
81
82// This example passes a context with a timeout to tell a blocking function that
83// it should abandon its work after the timeout elapses.
84func ExampleWithTimeout() {
85	// Pass a context with a timeout to tell a blocking function that it
86	// should abandon its work after the timeout elapses.
87	ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
88	defer cancel()
89
90	select {
91	case <-neverReady:
92		fmt.Println("ready")
93	case <-ctx.Done():
94		fmt.Println(ctx.Err()) // prints "context deadline exceeded"
95	}
96
97	// Output:
98	// context deadline exceeded
99}
100
101// This example demonstrates how a value can be passed to the context
102// and also how to retrieve it if it exists.
103func ExampleWithValue() {
104	type favContextKey string
105
106	f := func(ctx context.Context, k favContextKey) {
107		if v := ctx.Value(k); v != nil {
108			fmt.Println("found value:", v)
109			return
110		}
111		fmt.Println("key not found:", k)
112	}
113
114	k := favContextKey("language")
115	ctx := context.WithValue(context.Background(), k, "Go")
116
117	f(ctx, k)
118	f(ctx, favContextKey("color"))
119
120	// Output:
121	// found value: Go
122	// key not found: color
123}
124
125// This example uses AfterFunc to define a function which waits on a sync.Cond,
126// stopping the wait when a context is canceled.
127func ExampleAfterFunc_cond() {
128	waitOnCond := func(ctx context.Context, cond *sync.Cond, conditionMet func() bool) error {
129		stopf := context.AfterFunc(ctx, func() {
130			// We need to acquire cond.L here to be sure that the Broadcast
131			// below won't occur before the call to Wait, which would result
132			// in a missed signal (and deadlock).
133			cond.L.Lock()
134			defer cond.L.Unlock()
135
136			// If multiple goroutines are waiting on cond simultaneously,
137			// we need to make sure we wake up exactly this one.
138			// That means that we need to Broadcast to all of the goroutines,
139			// which will wake them all up.
140			//
141			// If there are N concurrent calls to waitOnCond, each of the goroutines
142			// will spuriously wake up O(N) other goroutines that aren't ready yet,
143			// so this will cause the overall CPU cost to be O(N²).
144			cond.Broadcast()
145		})
146		defer stopf()
147
148		// Since the wakeups are using Broadcast instead of Signal, this call to
149		// Wait may unblock due to some other goroutine's context becoming done,
150		// so to be sure that ctx is actually done we need to check it in a loop.
151		for !conditionMet() {
152			cond.Wait()
153			if ctx.Err() != nil {
154				return ctx.Err()
155			}
156		}
157
158		return nil
159	}
160
161	cond := sync.NewCond(new(sync.Mutex))
162
163	var wg sync.WaitGroup
164	for i := 0; i < 4; i++ {
165		wg.Add(1)
166		go func() {
167			defer wg.Done()
168
169			ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
170			defer cancel()
171
172			cond.L.Lock()
173			defer cond.L.Unlock()
174
175			err := waitOnCond(ctx, cond, func() bool { return false })
176			fmt.Println(err)
177		}()
178	}
179	wg.Wait()
180
181	// Output:
182	// context deadline exceeded
183	// context deadline exceeded
184	// context deadline exceeded
185	// context deadline exceeded
186}
187
188// This example uses AfterFunc to define a function which reads from a net.Conn,
189// stopping the read when a context is canceled.
190func ExampleAfterFunc_connection() {
191	readFromConn := func(ctx context.Context, conn net.Conn, b []byte) (n int, err error) {
192		stopc := make(chan struct{})
193		stop := context.AfterFunc(ctx, func() {
194			conn.SetReadDeadline(time.Now())
195			close(stopc)
196		})
197		n, err = conn.Read(b)
198		if !stop() {
199			// The AfterFunc was started.
200			// Wait for it to complete, and reset the Conn's deadline.
201			<-stopc
202			conn.SetReadDeadline(time.Time{})
203			return n, ctx.Err()
204		}
205		return n, err
206	}
207
208	listener, err := net.Listen("tcp", ":0")
209	if err != nil {
210		fmt.Println(err)
211		return
212	}
213	defer listener.Close()
214
215	conn, err := net.Dial(listener.Addr().Network(), listener.Addr().String())
216	if err != nil {
217		fmt.Println(err)
218		return
219	}
220	defer conn.Close()
221
222	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
223	defer cancel()
224
225	b := make([]byte, 1024)
226	_, err = readFromConn(ctx, conn, b)
227	fmt.Println(err)
228
229	// Output:
230	// context deadline exceeded
231}
232
233// This example uses AfterFunc to define a function which combines
234// the cancellation signals of two Contexts.
235func ExampleAfterFunc_merge() {
236	// mergeCancel returns a context that contains the values of ctx,
237	// and which is canceled when either ctx or cancelCtx is canceled.
238	mergeCancel := func(ctx, cancelCtx context.Context) (context.Context, context.CancelFunc) {
239		ctx, cancel := context.WithCancelCause(ctx)
240		stop := context.AfterFunc(cancelCtx, func() {
241			cancel(context.Cause(cancelCtx))
242		})
243		return ctx, func() {
244			stop()
245			cancel(context.Canceled)
246		}
247	}
248
249	ctx1, cancel1 := context.WithCancelCause(context.Background())
250	defer cancel1(errors.New("ctx1 canceled"))
251
252	ctx2, cancel2 := context.WithCancelCause(context.Background())
253
254	mergedCtx, mergedCancel := mergeCancel(ctx1, ctx2)
255	defer mergedCancel()
256
257	cancel2(errors.New("ctx2 canceled"))
258	<-mergedCtx.Done()
259	fmt.Println(context.Cause(mergedCtx))
260
261	// Output:
262	// ctx2 canceled
263}
264