-
Notifications
You must be signed in to change notification settings - Fork 9
/
context.go
129 lines (112 loc) · 3.02 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package gtkui
import (
"context"
"sync"
)
// ContextPack keeps cancellable context with its cancel function.
type ContextPack struct {
Context context.Context
Cancel func()
}
// ForkContext create child context from the parent.
func ForkContext(parent context.Context) *ContextPack {
child, cancel := context.WithCancel(parent)
v := &ContextPack{Context: child, Cancel: cancel}
return v
}
// RunningContexts keeps all contexts of currently started services,
// preliminary added to the list, which we would like to control,
// tracking and managing their states.
// All methods of RunningContexts type are thread-safe.
type RunningContexts struct {
sync.RWMutex
running []*ContextPack
}
// AddContext add new service to track.
func (v *RunningContexts) AddContext(pack *ContextPack) {
v.Lock()
defer v.Unlock()
v.running = append(v.running, pack)
}
func (v *RunningContexts) findIndex(ctx context.Context) int {
index := -1
for i, item := range v.running {
if item.Context == ctx {
index = i
break
}
}
return index
}
// RemoveContext remove service from the list.
func (v *RunningContexts) RemoveContext(ctx context.Context) {
v.Lock()
defer v.Unlock()
index := v.findIndex(ctx)
if index != -1 {
v.running = append(v.running[:index], v.running[index+1:]...)
}
}
// CancelContext cancel service from the list.
func (v *RunningContexts) CancelContext(ctx context.Context) {
v.Lock()
defer v.Unlock()
index := v.findIndex(ctx)
if index != -1 {
v.running[index].Cancel()
v.running = append(v.running[:index], v.running[:index+1]...)
}
}
// CancelAll cancel all services in the list.
func (v *RunningContexts) CancelAll() {
v.Lock()
defer v.Unlock()
for _, item := range v.running {
item.Cancel()
}
v.running = []*ContextPack{}
}
// FindContext finds service by context object.
func (v *RunningContexts) FindContext(ctx context.Context) *ContextPack {
v.RLock()
defer v.RUnlock()
index := v.findIndex(ctx)
if index != -1 {
return v.running[index]
}
return nil
}
// GetCount returns number of services in the list to control.
func (v *RunningContexts) GetCount() int {
v.RLock()
defer v.RUnlock()
return len(v.running)
}
// BackupSessionStatus keeps contexts - live multi-thread processes,
// which life cycle should be controlled.
type BackupSessionStatus struct {
parent context.Context
running RunningContexts
}
func NewBackupSessionStatus(parent context.Context) *BackupSessionStatus {
v := &BackupSessionStatus{parent: parent}
return v
}
// Start forks new context for parent thread.
func (v *BackupSessionStatus) Start() *ContextPack {
pack := ForkContext(v.parent)
v.running.AddContext(pack)
return pack
}
// IsRunning checks if any children threads are alive.
func (v *BackupSessionStatus) IsRunning() bool {
return v.running.GetCount() > 0
}
// Stop terminates all live thread's contexts.
func (v *BackupSessionStatus) Stop() {
v.running.CancelAll()
}
// Done removes context from the pool of controlled threads.
func (v *BackupSessionStatus) Done(ctx context.Context) {
v.running.RemoveContext(ctx)
}