blob: 9e9bc49d3714f39c8f4b5f739dd8c05727928b0f [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium 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
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -08005package appcycle
6
7import (
8 "fmt"
9 "os"
10 "sync"
11
Jiri Simsa6ac95222015-02-23 16:11:49 -080012 "v.io/v23"
Todd Wang54feabe2015-04-15 23:38:26 -070013 "v.io/v23/context"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070014 "v.io/v23/rpc"
Ankurd8646812015-03-12 10:48:41 -070015 "v.io/v23/security"
Jiri Simsa337af232015-02-27 14:36:46 -080016 "v.io/x/lib/vlog"
Robin Thellendfb7d5942015-02-11 09:48:10 -080017
Todd Wang94c9d0b2015-04-01 14:27:00 -070018 public "v.io/v23/services/appcycle"
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080019)
20
21type AppCycle struct {
22 sync.RWMutex
23 waiters []chan<- string
Jiri Simsa6ac95222015-02-23 16:11:49 -080024 taskTrackers []chan<- v23.Task
25 task v23.Task
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080026 shutDown bool
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080027 disp *invoker
28}
29
30type invoker struct {
31 ac *AppCycle
32}
33
Bogdan Caprita3e8f9642014-12-05 14:29:40 -080034func New() *AppCycle {
35 ac := new(AppCycle)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080036 ac.disp = &invoker{ac}
37 return ac
38}
39
40func (m *AppCycle) Shutdown() {
41 m.Lock()
42 defer m.Unlock()
43 if m.shutDown {
44 return
45 }
46 m.shutDown = true
47 for _, t := range m.taskTrackers {
48 close(t)
49 }
50 m.taskTrackers = nil
51}
52
53func (m *AppCycle) stop(msg string) {
Bogdan Caprita394af412015-03-04 16:45:13 -080054 vlog.Infof("stop(%v)", msg)
55 defer vlog.Infof("stop(%v) done", msg)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080056 m.RLock()
57 defer m.RUnlock()
58 if len(m.waiters) == 0 {
Bogdan Caprita03cec612015-02-14 19:55:26 -080059 vlog.Infof("Unhandled stop. Exiting.")
Jiri Simsa6ac95222015-02-23 16:11:49 -080060 os.Exit(v23.UnhandledStopExitCode)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080061 }
62 for _, w := range m.waiters {
63 select {
64 case w <- msg:
65 default:
66 }
67 }
68}
69
70func (m *AppCycle) Stop() {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -070071 defer vlog.LogCall()() // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Jiri Simsa6ac95222015-02-23 16:11:49 -080072 m.stop(v23.LocalStop)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080073}
74
75func (*AppCycle) ForceStop() {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -070076 defer vlog.LogCall()() // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Jiri Simsa6ac95222015-02-23 16:11:49 -080077 os.Exit(v23.ForceStopExitCode)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080078}
79
80func (m *AppCycle) WaitForStop(ch chan<- string) {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -070081 defer vlog.LogCallf("ch=")("") // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080082 m.Lock()
83 defer m.Unlock()
84 m.waiters = append(m.waiters, ch)
85}
86
Jiri Simsa6ac95222015-02-23 16:11:49 -080087func (m *AppCycle) TrackTask(ch chan<- v23.Task) {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -070088 defer vlog.LogCallf("ch=")("") // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -080089 m.Lock()
90 defer m.Unlock()
91 if m.shutDown {
92 close(ch)
93 return
94 }
95 m.taskTrackers = append(m.taskTrackers, ch)
96}
97
98func (m *AppCycle) advanceTask(progress, goal int32) {
99 m.Lock()
100 defer m.Unlock()
101 m.task.Goal += goal
102 m.task.Progress += progress
103 for _, t := range m.taskTrackers {
104 select {
105 case t <- m.task:
106 default:
107 // TODO(caprita): Make it such that the latest task
108 // update is always added to the channel even if channel
109 // is full. One way is to pull an element from t and
110 // then re-try the push.
111 }
112 }
113}
114
115func (m *AppCycle) AdvanceGoal(delta int32) {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700116 defer vlog.LogCallf("delta=%v", delta)("") // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800117 if delta <= 0 {
118 return
119 }
120 m.advanceTask(0, delta)
121}
122
123func (m *AppCycle) AdvanceProgress(delta int32) {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700124 defer vlog.LogCallf("delta=%v", delta)("") // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800125 if delta <= 0 {
126 return
127 }
128 m.advanceTask(delta, 0)
129}
130
131func (m *AppCycle) Remote() interface{} {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700132 defer vlog.LogCall()() // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Todd Wang94c9d0b2015-04-01 14:27:00 -0700133 return public.AppCycleServer(m.disp)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800134}
135
Todd Wang54feabe2015-04-15 23:38:26 -0700136func (d *invoker) Stop(ctx *context.T, call public.AppCycleStopServerCall) error {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700137 defer vlog.LogCallf("ctx=,call=")("") // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Todd Wang4264e4b2015-04-16 22:43:40 -0700138 blessings, _ := security.RemoteBlessingNames(ctx, call.Security())
Suharsh Sivakumar31f49852015-03-03 16:13:20 -0800139 vlog.Infof("AppCycle Stop request from %v", blessings)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800140 // The size of the channel should be reasonably sized to expect not to
141 // miss updates while we're waiting for the stream to unblock.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800142 ch := make(chan v23.Task, 10)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800143 d.ac.TrackTask(ch)
144 // TODO(caprita): Include identity of Stop issuer in message.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800145 d.ac.stop(v23.RemoteStop)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800146 for {
147 task, ok := <-ch
148 if !ok {
149 // Channel closed, meaning process shutdown is imminent.
150 break
151 }
Todd Wang94c9d0b2015-04-01 14:27:00 -0700152 actask := public.Task{Progress: task.Progress, Goal: task.Goal}
Robin Thellendfb7d5942015-02-11 09:48:10 -0800153 vlog.Infof("AppCycle Stop progress %d/%d", task.Progress, task.Goal)
Suharsh Sivakumar31f49852015-03-03 16:13:20 -0800154 call.SendStream().Send(actask)
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800155 }
Robin Thellendfb7d5942015-02-11 09:48:10 -0800156 vlog.Infof("AppCycle Stop done")
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800157 return nil
158}
159
Todd Wang54feabe2015-04-15 23:38:26 -0700160func (d *invoker) ForceStop(*context.T, rpc.ServerCall) error {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700161 defer vlog.LogCall()() // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
Cosmos Nicolaou39e3ae52014-11-14 13:30:01 -0800162 d.ac.ForceStop()
163 return fmt.Errorf("ForceStop should not reply as the process should be dead")
164}