blob: a0a70767fa49853e38afe7d58d4ee7c992a66d62 [file] [log] [blame]
/** @file
A brief file description
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*****************************************************************************
* Filename: EventCallback.cc
* Purpose: Generic module that deals with callbacks and a callback table
* Created: 01/08/01
* Created by: lant
*
***************************************************************************/
#include "tscore/ink_config.h"
#include "tscore/ink_memory.h"
#include "EventCallback.h"
#include "CoreAPIShared.h"
/**********************************************************************
* create_event_callback
*
* purpose: allocates and initializes members of EventCallbackT
* input: None
* output: EventCallbackT
* notes: None
**********************************************************************/
EventCallbackT *
create_event_callback(TSEventSignalFunc func, void *data)
{
EventCallbackT *event_cb = static_cast<EventCallbackT *>(ats_malloc(sizeof(EventCallbackT)));
event_cb->func = func;
event_cb->data = data;
return event_cb;
}
/**********************************************************************
* delete_event_callback
*
* purpose:frees EventCallbackT
* input: None
* output: EventCallbackT
* notes: also frees memory for the data passed in; ASSUMES data was
* dynamically allocated
**********************************************************************/
void
delete_event_callback(EventCallbackT *event_cb)
{
ats_free(event_cb);
return;
}
/**********************************************************************
* create_callback_table
*
* purpose: initializes the structures used to deal with events
* input: None
* output: TS_ERR_xx
* notes: None
**********************************************************************/
CallbackTable *
create_callback_table(const char *)
{
CallbackTable *cb_table = static_cast<CallbackTable *>(ats_malloc(sizeof(CallbackTable)));
for (auto &i : cb_table->event_callback_l) {
i = nullptr;
}
// initialize the mutex
ink_mutex_init(&cb_table->event_callback_lock);
return cb_table;
}
/**********************************************************************
* delete_callback_table
*
* purpose: frees the memory allocated for a CallbackTable; also
* destroys the lock
* input: None
* output: None
* notes: doesn't free pointers to functions
**********************************************************************/
void
delete_callback_table(CallbackTable *cb_table)
{
EventCallbackT *event_cb;
// get lock
ink_mutex_acquire(&cb_table->event_callback_lock);
// for each event
for (auto &i : cb_table->event_callback_l) {
if (i) {
// remove and delete each EventCallbackT for that event
while (!queue_is_empty(i)) {
event_cb = static_cast<EventCallbackT *>(dequeue(i));
delete_event_callback(event_cb);
}
delete_queue(i);
}
}
// release lock
ink_mutex_release(&cb_table->event_callback_lock);
// destroy lock
ink_mutex_destroy(&cb_table->event_callback_lock);
ats_free(cb_table);
return;
}
/**********************************************************************
* get_events_with_callbacks
*
* purpose: returns a list of the event_id's that have at least
* one callback registered for that event
* input: cb_list - the table of callbacks to check
* output: returns a list of event_ids with at least one callback fun;
* returns NULL if all the events have a registered callback
* notes:
**********************************************************************/
LLQ *
get_events_with_callbacks(CallbackTable *cb_table)
{
LLQ *cb_ev_list;
bool all_events = true; // set to false if at least one event doesn't have registered callback
cb_ev_list = create_queue();
for (int i = 0; i < NUM_EVENTS; i++) {
if (!cb_table->event_callback_l[i]) {
all_events = false;
continue; // no callbacks registered
}
enqueue(cb_ev_list, &i);
}
if (all_events) {
delete_queue(cb_ev_list);
return nullptr;
}
return cb_ev_list;
}
/**********************************************************************
* cb_table_register
*
* purpose: Registers the specified function for the specified event in
* the specified callback list
* input: cb_list - the table of callbacks to store the callback fn
* event_name - the event to store the callback for (if NULL, register for all events)
* func - the callback function
* first_cb - true only if this is the event's first callback
* output: TS_ERR_xx
* notes:
**********************************************************************/
TSMgmtError
cb_table_register(CallbackTable *cb_table, const char *event_name, TSEventSignalFunc func, void *data, bool *first_cb)
{
bool first_time = false;
EventCallbackT *event_cb; // create new EventCallbackT EACH TIME enqueue
// the data and event_name can be NULL
if (func == nullptr || !cb_table) {
return TS_ERR_PARAMS;
}
ink_mutex_acquire(&(cb_table->event_callback_lock));
// got lock, add it
if (event_name == nullptr) { // register for all alarms
// printf("[EventSignalCbRegister] Register callback for all alarms\n");
for (auto &i : cb_table->event_callback_l) {
if (!i) {
i = create_queue();
first_time = true;
}
if (!i) {
ink_mutex_release(&cb_table->event_callback_lock);
return TS_ERR_SYS_CALL;
}
event_cb = create_event_callback(func, data);
enqueue(i, event_cb);
}
} else { // register callback for specific alarm
int id = get_event_id(event_name);
if (id != -1) {
if (!cb_table->event_callback_l[id]) {
cb_table->event_callback_l[id] = create_queue();
first_time = true;
}
if (!cb_table->event_callback_l[id]) {
ink_mutex_release(&cb_table->event_callback_lock);
return TS_ERR_SYS_CALL;
}
// now add to list
event_cb = create_event_callback(func, data);
enqueue(cb_table->event_callback_l[id], event_cb);
}
}
// release lock on callback table
ink_mutex_release(&cb_table->event_callback_lock);
if (first_cb) {
*first_cb = first_time;
}
return TS_ERR_OKAY;
}
/**********************************************************************
* cb_table_unregister
*
* purpose: Unregisters the specified function for the specified event in
* the specified callback list
* input: cb_table - the table of callbacks to store the callback fn
* event_name - the event to store the callback for (if NULL, register for all events)
* func - the callback function
* first_cb - true only if this is the event's first callback
* output: TS_ERR_xx
* notes:
**********************************************************************/
TSMgmtError
cb_table_unregister(CallbackTable *cb_table, const char *event_name, TSEventSignalFunc func)
{
TSEventSignalFunc cb_fun;
EventCallbackT *event_cb;
ink_mutex_acquire(&cb_table->event_callback_lock);
// got lock, add it
if (event_name == nullptr) { // unregister the callback for ALL EVENTS
// for each event
for (auto &i : cb_table->event_callback_l) {
if (!i) { // this event has no callbacks
continue;
}
// func == NULL means unregister all functions associated with alarm
if (func == nullptr) {
while (!queue_is_empty(i)) {
event_cb = static_cast<EventCallbackT *>(dequeue(i));
delete_event_callback(event_cb);
}
// clean up queue and set to NULL
delete_queue(i);
i = nullptr;
} else { // only remove the func passed in
int queue_depth;
queue_depth = queue_len(i);
// remove this function
for (int j = 0; j < queue_depth; j++) {
event_cb = static_cast<EventCallbackT *>(dequeue(i));
cb_fun = event_cb->func;
// the pointers are the same so don't enqueue the fn back on
if (*cb_fun == *func) {
delete_event_callback(event_cb);
continue;
}
enqueue(i, event_cb);
}
// is queue empty now? then clean up
if (queue_is_empty(i)) {
delete_queue(i);
i = nullptr;
}
}
} // end for (int i = 0; i < NUM_EVENTS; i++)
} else {
// unregister for specific event
int id = get_event_id(event_name);
if (id != -1) {
if (cb_table->event_callback_l[id]) {
int queue_depth;
queue_depth = queue_len(cb_table->event_callback_l[id]);
// func == NULL means unregister all functions associated with alarm
if (func == nullptr) {
while (!queue_is_empty(cb_table->event_callback_l[id])) {
event_cb = static_cast<EventCallbackT *>(dequeue(cb_table->event_callback_l[id]));
delete_event_callback(event_cb);
}
// clean up queue and set to NULL
delete_queue(cb_table->event_callback_l[id]);
cb_table->event_callback_l[id] = nullptr;
} else {
// remove this function
for (int j = 0; j < queue_depth; j++) {
event_cb = static_cast<EventCallbackT *>(dequeue(cb_table->event_callback_l[id]));
cb_fun = event_cb->func;
// the pointers are the same
if (*cb_fun == *func) {
delete_event_callback(event_cb);
continue;
}
enqueue(cb_table->event_callback_l[id], event_cb);
}
// is queue empty now?
if (queue_is_empty(cb_table->event_callback_l[id])) {
delete_queue(cb_table->event_callback_l[id]);
cb_table->event_callback_l[id] = nullptr;
}
} // end if NULL else
}
}
}
ink_mutex_release(&cb_table->event_callback_lock);
return TS_ERR_OKAY;
}