blob: 5d48464afd98beb0e49ca941b94c746ceca06705 [file] [log] [blame]
Anssi Mannilaf1d0eb62019-12-17 15:29:55 +02001/*
2==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17==================================================================================
18*/
19/*
20Timer takes four parameters:
21 1) strId string 'string format timerMap key'
22 2) nbrId int 'numeric format timerMap key'
23 3) timerDuration time.Duration 'timer duration'
24 4) timerFunction func(string, int) 'function to be executed when timer expires'
25
26 Timer function is put inside in-build time.AfterFunc() Go function, where it is run inside own Go routine
27 when the timer expires. Timer are two key values. Both are used always, but the other one can be left
28 "empty", i.e. strId = "" or nbrId = 0. Fourth parameter, the timer function is bare function name without
29 any function parameters and parenthesis! Filling first parameter strId with related name can improve
30 code readability and robustness, even the numeric Id would be enough from functionality point of view.
31
32 TimerStart() function starts the timer. If TimerStart() function is called again with same key values
33 while earlier started timer is still in the timerMap, i.e. it has not been stopped or the timer has not
34 yet expired, the old timer is deleted and new timer is started with the given time value.
35
36 StopTimer() function stops the timer. There is no need to call StopTimer() function after the timer has
37 expired. Timer is removed automatically from the timeMap. Calling StopTimer() function with key values not
38 existing in the timerMap, has no effect.
39
40 NOTE: Each timer is run in separate Go routine. Therefore, the function that is executed when timer expires
41 MUST be designed to be able run concurrently! Also, function run order of simultaneously expired timers cannot
42 guaranteed anyway!
43
44 If you need to transport more information to the timer function, consider to use another map to store the
45 information with same key value, as the started timer.
46
47 Init timerMap example:
48 timerMap := new(TimerMap)
49 timerMap.Init()
50
51 StartTimer() and StartTimer() function usage examples.
52 1)
53 subReqTime := 2 * time.Second
54 subId := 123
55 timerMap.StartTimer("RIC_SUB_REQ", int(subId), subReqTime, handleSubscriptionRequestTimer)
56 timerMap.StopTimer("RIC_SUB_REQ", int(subId))
57
58 2)
59 subReqTime := 2 * time.Second
60 strId := "1UHSUwNqxiVgUWXvC4zFaatpZFF"
61 timerMap.StartTimer(strId, 0, subReqTime, handleSubscriptionRequestTimer)
62 timerMap.StopTimer(strId, 0)
63
64 3)
65 subReqTime := 2 * time.Second
66 strId := "1UHSUwNqxiVgUWXvC4zFaatpZFF"
67 timerMap.StartTimer(RIC_SUB_REQ_" + strId, 0, subReqTime, handleSubscriptionRequestTimer)
68 timerMap.timerMap.StopTimer("RIC_SUB_REQ_" + strId, 0)
69
70 Timer function example. This is run if any of the above started timer expires.
71 func handleSubscriptionRequestTimer1(strId string, nbrId int) {
72 fmt.Printf("Subscription Request timer expired. Name: %v, SubId: %v\n",strId, nbrId)
73 }
74*/
75
76package control
77
78import (
79 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
80 "sync"
81 "time"
82)
83
84type TimerKey struct {
85 strId string
86 nbrId int
87}
88
89type TimerInfo struct {
90 timerAddress *time.Timer
91 timerFunctionAddress func()
92}
93
94type TimerMap struct {
95 timer map[TimerKey] TimerInfo
96 mutex sync.Mutex
97}
98
99// This method should run as a constructor
100func (t *TimerMap) Init() {
101 t.timer = make(map[TimerKey] TimerInfo)
102}
103
104func (t *TimerMap) StartTimer(strId string, nbrId int, expireAfterTime time.Duration, timerFunction func(srtId string, nbrId int)) bool {
105 t.mutex.Lock()
106 defer t.mutex.Unlock()
107 if (timerFunction == nil) {
108 xapp.Logger.Error("StartTimer() timerFunc == nil\n")
109 return false
110 }
111 timerKey := TimerKey{strId, nbrId}
112 // Stop timer if there is already timer running with the same id
113 if val, ok := t.timer[timerKey]; ok {
114 xapp.Logger.Debug("StartTimer() old timer found")
115 if val.timerAddress != nil {
116 xapp.Logger.Debug("StartTimer() deleting old timer")
117 val.timerAddress.Stop()
118 }
119 delete(t.timer, timerKey)
120 }
121
122 // Store in timerMap in-build Go "timer", timer function executor, and the function to be executed when the timer expires
123 t.timer[timerKey] = TimerInfo{timerAddress: time.AfterFunc(expireAfterTime, func(){t.timerFunctionExecutor(strId,nbrId)}),
124 timerFunctionAddress: func(){timerFunction(strId,nbrId)}}
125 return true
126}
127
128func (t *TimerMap) StopTimer(strId string, nbrId int) bool {
129 t.mutex.Lock()
130 defer t.mutex.Unlock()
131 timerKey := TimerKey{strId, nbrId}
132 if val, ok := t.timer[timerKey]; ok {
133 if val.timerAddress != nil {
134 val.timerAddress.Stop()
135 delete(t.timer, timerKey)
136 return true
137 } else {
138 xapp.Logger.Error("StopTimer() timerAddress == nil")
139 return false
140 }
141 } else {
142 xapp.Logger.Debug("StopTimer() Timer not found. May be expired or stopped already. timerKey.strId: %v, timerKey.strId: %v\n", timerKey.strId, timerKey.nbrId)
143 return false
144 }
145}
146
147func (t *TimerMap) timerFunctionExecutor(strId string, nbrId int) {
148 t.mutex.Lock()
149 timerKey := TimerKey{strId, nbrId}
150 if val, ok := t.timer[timerKey]; ok {
151 if val.timerFunctionAddress != nil {
152 // Take local copy of timer function address
153 f := val.timerFunctionAddress
154 // Delete timer instance from map
155 delete(t.timer, timerKey)
156 t.mutex.Unlock()
157 // Execute the timer function
158 f()
159 return
160 } else {
161 xapp.Logger.Error("timerExecutorFunc() timerFunctionAddress == nil")
162 t.mutex.Unlock()
163 return
164 }
165 } else {
166 xapp.Logger.Error("timerExecutorFunc() Timer is not anymore in map. timerKey.strId: %v, timerKey.strId: %v\n", timerKey.strId, timerKey.nbrId)
167 t.mutex.Unlock()
168 return
169 }
170}