Commit 02c9eb7f authored by Philipp Schafft's avatar Philipp Schafft 🦁

Feature: Added fast event API

parent 8cf3da1a
......@@ -14,8 +14,201 @@
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "common/thread/thread.h"
#include "fastevent.h"
#include "logging.h"
#define CATMODULE "fastevent"
#ifdef FASTEVENT_ENABLED
struct registration {
refobject_base_t __base;
fastevent_type_t type;
fastevent_cb_t cb;
fastevent_freecb_t freecb;
void *userdata;
};
struct eventrow {
size_t length;
size_t used;
struct registration **registrations;
};
static struct eventrow fastevent_registrations[FASTEVENT_TYPE__END];
static rwlock_t fastevent_lock;
static inline struct eventrow * __get_row(fastevent_type_t type)
{
size_t idx = type;
if (idx >= FASTEVENT_TYPE__END)
return NULL;
return &(fastevent_registrations[idx]);
}
static int __add_to_row(struct eventrow * row, struct registration *registration)
{
struct registration **n;
if (row == NULL)
return -1;
/* Check if we need to reallocate row space */
if (row->length == row->used) {
n = realloc(row->registrations, sizeof(*n)*(row->length + 4));
if (n == NULL) {
ICECAST_LOG_ERROR("Can not allocate row space.");
return -1;
}
row->registrations = n;
row->length += 4;
}
row->registrations[row->used++] = registration;
return 0;
}
static int __remove_from_row(struct eventrow * row, struct registration *registration)
{
size_t i;
if (row == NULL)
return -1;
for (i = 0; i < row->used; i++) {
if (row->registrations[i] == registration) {
memmove(&(row->registrations[i]), &(row->registrations[i+1]), sizeof(*(row->registrations))*(row->used - i - 1));
row->used--;
return 0;
}
}
return -1;
}
static void __unregister(refobject_t self, void **userdata)
{
struct registration *registration = REFOBJECT_TO_TYPE(self, struct registration *);
struct eventrow * row;
(void)userdata;
thread_rwlock_wlock(&fastevent_lock);
row = __get_row(registration->type);
if (__remove_from_row(row, registration) != 0) {
ICECAST_LOG_ERROR("Can not remove fast event from row. BUG.");
}
thread_rwlock_unlock(&fastevent_lock);
if (registration->freecb)
registration->freecb(&(registration->userdata));
if (registration->userdata != NULL)
free(registration->userdata);
}
int fastevent_initialize(void)
{
thread_rwlock_create(&fastevent_lock);
return 0;
}
int fastevent_shutdown(void)
{
size_t i;
thread_rwlock_wlock(&fastevent_lock);
for (i = 0; i < FASTEVENT_TYPE__END; i++) {
if (fastevent_registrations[i].used) {
ICECAST_LOG_ERROR("Subsystem shutdown but elements still in use. BUG.");
continue;
}
free(fastevent_registrations[i].registrations);
fastevent_registrations[i].registrations = NULL;
}
thread_rwlock_unlock(&fastevent_lock);
thread_rwlock_destroy(&fastevent_lock);
return 0;
}
refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata)
{
struct eventrow * row;
struct registration *registration;
refobject_t ret;
if (cb == NULL)
return REFOBJECT_NULL;
thread_rwlock_wlock(&fastevent_lock);
row = __get_row(type);
if (row == NULL) {
thread_rwlock_unlock(&fastevent_lock);
return REFOBJECT_NULL;
}
ret = refobject_new(sizeof(struct registration), __unregister, NULL, NULL, NULL);
if (REFOBJECT_IS_NULL(ret)) {
thread_rwlock_unlock(&fastevent_lock);
return REFOBJECT_NULL;
}
registration = REFOBJECT_TO_TYPE(ret, struct registration *);
registration->type = type;
registration->cb = cb;
registration->freecb = freecb;
registration->userdata = userdata;
if (__add_to_row(row, registration) != 0) {
thread_rwlock_unlock(&fastevent_lock);
refobject_unref(ret);
return REFOBJECT_NULL;
}
thread_rwlock_unlock(&fastevent_lock);
return ret;
}
void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...)
{
struct eventrow * row;
va_list ap, apx;
size_t i;
ICECAST_LOG_DEBUG("event: type=%i, flags=%i, datatype=%i, ...", (int)type, (int)flags, (int)datatype);
thread_rwlock_rlock(&fastevent_lock);
row = __get_row(type);
if (row == NULL || row->used == 0) {
thread_rwlock_unlock(&fastevent_lock);
return;
}
va_start(ap, datatype);
for (i = 0; i < row->used; i++) {
va_copy(apx, ap);
row->registrations[i]->cb(row->registrations[i]->userdata, type, flags, datatype, apx);
va_end(apx);
}
thread_rwlock_unlock(&fastevent_lock);
va_end(ap);
}
#endif
......@@ -9,4 +9,43 @@
#ifndef __FASTEVENT_H__
#define __FASTEVENT_H__
/* Add all conditions when to enable fast events here. */
#if 1
#define FASTEVENT_ENABLED
#endif
#include <stdarg.h>
#include <refobject.h>
typedef enum {
FASTEVENT_TYPE_SLOWEVENT = 0,
FASTEVENT_TYPE__END /* must be last element */
} fastevent_type_t;
typedef enum {
FASTEVENT_DATATYPE_NONE = 0,
FASTEVENT_DATATYPE_EVENT,
FASTEVENT_DATATYPE_CLIENT,
FASTEVENT_DATATYPE_CONNECTION
} fastevent_datatype_t;
typedef int fastevent_flag_t;
#define FASTEVENT_FLAG_NONE ((fastevent_flag_t)0x0000)
#define FASTEVENT_FLAG_MODIFICATION_ALLOWED ((fastevent_flag_t)0x0001)
typedef void (*fastevent_cb_t)(const void *userdata, fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, va_list ap);
typedef void (*fastevent_freecb_t)(void **userdata);
#ifdef FASTEVENT_ENABLED
int fastevent_initialize(void);
int fastevent_shutdown(void);
refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata);
void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...);
#else
#define fastevent_initialize() 0
#define fastevent_shutdown() 0
#define fastevent_register(type,cb,freecb,userdata) REFOBJECT_NULL
#define fastevent_emit(type,flags,datatype,...)
#endif
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment