xref: /trafficserver/mgmt/api/EventCallback.cc (revision 4cfd5a73)
1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /*****************************************************************************
25  * Filename: EventCallback.cc
26  * Purpose: Generic module that deals with callbacks and a callback table
27  * Created: 01/08/01
28  * Created by: lant
29  *
30  ***************************************************************************/
31 
32 #include "tscore/ink_config.h"
33 #include "tscore/ink_memory.h"
34 
35 #include "EventCallback.h"
36 #include "CoreAPIShared.h"
37 
38 /**********************************************************************
39  * create_event_callback
40  *
41  * purpose: allocates and initializes members of EventCallbackT
42  * input: None
43  * output: EventCallbackT
44  * notes: None
45  **********************************************************************/
46 EventCallbackT *
create_event_callback(TSEventSignalFunc func,void * data)47 create_event_callback(TSEventSignalFunc func, void *data)
48 {
49   EventCallbackT *event_cb = static_cast<EventCallbackT *>(ats_malloc(sizeof(EventCallbackT)));
50 
51   event_cb->func = func;
52   event_cb->data = data;
53 
54   return event_cb;
55 }
56 
57 /**********************************************************************
58  * delete_event_callback
59  *
60  * purpose:frees EventCallbackT
61  * input: None
62  * output: EventCallbackT
63  * notes: also frees memory for the data passed in; ASSUMES data was
64  *        dynamically allocated
65  **********************************************************************/
66 void
delete_event_callback(EventCallbackT * event_cb)67 delete_event_callback(EventCallbackT *event_cb)
68 {
69   ats_free(event_cb);
70   return;
71 }
72 
73 /**********************************************************************
74  * create_callback_table
75  *
76  * purpose: initializes the structures used to deal with events
77  * input: None
78  * output: TS_ERR_xx
79  * notes: None
80  **********************************************************************/
81 CallbackTable *
create_callback_table(const char *)82 create_callback_table(const char *)
83 {
84   CallbackTable *cb_table = static_cast<CallbackTable *>(ats_malloc(sizeof(CallbackTable)));
85 
86   for (auto &i : cb_table->event_callback_l) {
87     i = nullptr;
88   }
89 
90   // initialize the mutex
91   ink_mutex_init(&cb_table->event_callback_lock);
92   return cb_table;
93 }
94 
95 /**********************************************************************
96  * delete_callback_table
97  *
98  * purpose: frees the memory allocated for a CallbackTable; also
99  *          destroys the lock
100  * input: None
101  * output: None
102  * notes: doesn't free pointers to functions
103  **********************************************************************/
104 void
delete_callback_table(CallbackTable * cb_table)105 delete_callback_table(CallbackTable *cb_table)
106 {
107   EventCallbackT *event_cb;
108 
109   // get lock
110   ink_mutex_acquire(&cb_table->event_callback_lock);
111 
112   // for each event
113   for (auto &i : cb_table->event_callback_l) {
114     if (i) {
115       // remove and delete each EventCallbackT for that event
116       while (!queue_is_empty(i)) {
117         event_cb = static_cast<EventCallbackT *>(dequeue(i));
118         delete_event_callback(event_cb);
119       }
120 
121       delete_queue(i);
122     }
123   }
124 
125   // release lock
126   ink_mutex_release(&cb_table->event_callback_lock);
127 
128   // destroy lock
129   ink_mutex_destroy(&cb_table->event_callback_lock);
130 
131   ats_free(cb_table);
132 
133   return;
134 }
135 
136 /**********************************************************************
137  * get_events_with_callbacks
138  *
139  * purpose:  returns a list of the event_id's that have at least
140  *           one callback registered for that event
141  * input: cb_list - the table of callbacks to check
142  * output: returns a list of event_ids with at least one callback fun;
143  *         returns NULL if all the events have a registered callback
144  * notes:
145  **********************************************************************/
146 LLQ *
get_events_with_callbacks(CallbackTable * cb_table)147 get_events_with_callbacks(CallbackTable *cb_table)
148 {
149   LLQ *cb_ev_list;
150   bool all_events = true; // set to false if at least one event doesn't have registered callback
151 
152   cb_ev_list = create_queue();
153   for (int i = 0; i < NUM_EVENTS; i++) {
154     if (!cb_table->event_callback_l[i]) {
155       all_events = false;
156       continue; // no callbacks registered
157     }
158 
159     enqueue(cb_ev_list, &i);
160   }
161 
162   if (all_events) {
163     delete_queue(cb_ev_list);
164     return nullptr;
165   }
166 
167   return cb_ev_list;
168 }
169 
170 /**********************************************************************
171  * cb_table_register
172  *
173  * purpose: Registers the specified function for the specified event in
174  *          the specified callback list
175  * input: cb_list - the table of callbacks to store the callback fn
176  *        event_name - the event to store the callback for (if NULL, register for all events)
177  *        func - the callback function
178  *        first_cb - true only if this is the event's first callback
179  * output: TS_ERR_xx
180  * notes:
181  **********************************************************************/
182 TSMgmtError
cb_table_register(CallbackTable * cb_table,const char * event_name,TSEventSignalFunc func,void * data,bool * first_cb)183 cb_table_register(CallbackTable *cb_table, const char *event_name, TSEventSignalFunc func, void *data, bool *first_cb)
184 {
185   bool first_time = false;
186   EventCallbackT *event_cb; // create new EventCallbackT EACH TIME enqueue
187 
188   // the data and event_name can be NULL
189   if (func == nullptr || !cb_table) {
190     return TS_ERR_PARAMS;
191   }
192 
193   ink_mutex_acquire(&(cb_table->event_callback_lock));
194 
195   // got lock, add it
196   if (event_name == nullptr) { // register for all alarms
197     // printf("[EventSignalCbRegister] Register callback for all alarms\n");
198     for (auto &i : cb_table->event_callback_l) {
199       if (!i) {
200         i          = create_queue();
201         first_time = true;
202       }
203 
204       if (!i) {
205         ink_mutex_release(&cb_table->event_callback_lock);
206         return TS_ERR_SYS_CALL;
207       }
208 
209       event_cb = create_event_callback(func, data);
210       enqueue(i, event_cb);
211     }
212   } else { // register callback for specific alarm
213     int id = get_event_id(event_name);
214     if (id != -1) {
215       if (!cb_table->event_callback_l[id]) {
216         cb_table->event_callback_l[id] = create_queue();
217         first_time                     = true;
218       }
219 
220       if (!cb_table->event_callback_l[id]) {
221         ink_mutex_release(&cb_table->event_callback_lock);
222         return TS_ERR_SYS_CALL;
223       }
224       // now add to list
225       event_cb = create_event_callback(func, data);
226       enqueue(cb_table->event_callback_l[id], event_cb);
227     }
228   }
229 
230   // release lock on callback table
231   ink_mutex_release(&cb_table->event_callback_lock);
232 
233   if (first_cb) {
234     *first_cb = first_time;
235   }
236 
237   return TS_ERR_OKAY;
238 }
239 
240 /**********************************************************************
241  * cb_table_unregister
242  *
243  * purpose: Unregisters the specified function for the specified event in
244  *          the specified callback list
245  * input: cb_table - the table of callbacks to store the callback fn
246  *        event_name - the event to store the callback for (if NULL, register for all events)
247  *        func - the callback function
248  *        first_cb - true only if this is the event's first callback
249  * output: TS_ERR_xx
250  * notes:
251  **********************************************************************/
252 TSMgmtError
cb_table_unregister(CallbackTable * cb_table,const char * event_name,TSEventSignalFunc func)253 cb_table_unregister(CallbackTable *cb_table, const char *event_name, TSEventSignalFunc func)
254 {
255   TSEventSignalFunc cb_fun;
256   EventCallbackT *event_cb;
257 
258   ink_mutex_acquire(&cb_table->event_callback_lock);
259 
260   // got lock, add it
261   if (event_name == nullptr) { // unregister the callback for ALL EVENTS
262     // for each event
263     for (auto &i : cb_table->event_callback_l) {
264       if (!i) { // this event has no callbacks
265         continue;
266       }
267 
268       // func == NULL means unregister all functions associated with alarm
269       if (func == nullptr) {
270         while (!queue_is_empty(i)) {
271           event_cb = static_cast<EventCallbackT *>(dequeue(i));
272           delete_event_callback(event_cb);
273         }
274         // clean up queue and set to NULL
275         delete_queue(i);
276         i = nullptr;
277       } else { // only remove the func passed in
278         int queue_depth;
279 
280         queue_depth = queue_len(i);
281         // remove this function
282         for (int j = 0; j < queue_depth; j++) {
283           event_cb = static_cast<EventCallbackT *>(dequeue(i));
284           cb_fun   = event_cb->func;
285 
286           // the pointers are the same so don't enqueue the fn back on
287           if (*cb_fun == *func) {
288             delete_event_callback(event_cb);
289             continue;
290           }
291 
292           enqueue(i, event_cb);
293         }
294 
295         // is queue empty now? then clean up
296         if (queue_is_empty(i)) {
297           delete_queue(i);
298           i = nullptr;
299         }
300       }
301     } // end for (int i = 0; i < NUM_EVENTS; i++)
302   } else {
303     // unregister for specific event
304     int id = get_event_id(event_name);
305     if (id != -1) {
306       if (cb_table->event_callback_l[id]) {
307         int queue_depth;
308 
309         queue_depth = queue_len(cb_table->event_callback_l[id]);
310         // func == NULL means unregister all functions associated with alarm
311         if (func == nullptr) {
312           while (!queue_is_empty(cb_table->event_callback_l[id])) {
313             event_cb = static_cast<EventCallbackT *>(dequeue(cb_table->event_callback_l[id]));
314             delete_event_callback(event_cb);
315           }
316 
317           // clean up queue and set to NULL
318           delete_queue(cb_table->event_callback_l[id]);
319           cb_table->event_callback_l[id] = nullptr;
320         } else {
321           // remove this function
322           for (int j = 0; j < queue_depth; j++) {
323             event_cb = static_cast<EventCallbackT *>(dequeue(cb_table->event_callback_l[id]));
324             cb_fun   = event_cb->func;
325 
326             // the pointers are the same
327             if (*cb_fun == *func) {
328               delete_event_callback(event_cb);
329               continue;
330             }
331 
332             enqueue(cb_table->event_callback_l[id], event_cb);
333           }
334 
335           // is queue empty now?
336           if (queue_is_empty(cb_table->event_callback_l[id])) {
337             delete_queue(cb_table->event_callback_l[id]);
338             cb_table->event_callback_l[id] = nullptr;
339           }
340         } // end if NULL else
341       }
342     }
343   }
344 
345   ink_mutex_release(&cb_table->event_callback_lock);
346 
347   return TS_ERR_OKAY;
348 }
349