c/src/core/event.c (311 lines of code) (raw):
/*
*
* 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.
*
*/
#include <proton/object.h>
#include <proton/event.h>
#include "core/fixed_string.h"
#include "core/object_private.h"
#include <assert.h>
#include <stdio.h>
struct pn_collector_t {
pn_list_t *pool;
pn_event_t *head;
pn_event_t *tail;
pn_event_t *prev; /* event returned by previous call to pn_collector_next() */
bool freed;
};
struct pn_event_t {
pn_list_t *pool;
const pn_class_t *clazz;
void *context; // depends on clazz
pn_record_t *attachments;
pn_event_t *next;
pn_event_type_t type;
};
static void pn_event_initialize(void *object);
static void pn_event_finalize(void *object);
static void pn_event_inspect(void *object, pn_fixed_string_t *string);
#define pn_event_hashcode NULL
#define pn_event_compare NULL
static const pn_class_t PN_CLASSCLASS(pn_event) = PN_CLASS(pn_event);
static void pn_collector_initialize(void* object)
{
pn_collector_t *collector = (pn_collector_t *)object;
collector->pool = pn_list(&PN_CLASSCLASS(pn_event), 0);
collector->head = NULL;
collector->tail = NULL;
collector->prev = NULL;
collector->freed = false;
}
void pn_collector_drain(pn_collector_t *collector)
{
assert(collector);
while (pn_collector_next(collector))
;
assert(!collector->head);
assert(!collector->tail);
}
static void pn_collector_shrink(pn_collector_t *collector)
{
assert(collector);
pn_list_clear(collector->pool);
}
static void pn_collector_finalize(void *object)
{
pn_collector_t *collector = (pn_collector_t *)object;
pn_collector_drain(collector);
pn_decref(collector->pool);
}
static void pn_collector_inspect(void *object, pn_fixed_string_t *dst)
{
pn_collector_t *collector = (pn_collector_t *)object;
assert(collector);
pn_fixed_string_addf(dst, "EVENTS[");
pn_event_t *event = collector->head;
bool first = true;
while (event) {
if (first) {
first = false;
} else {
pn_fixed_string_addf(dst, ", ");
}
pn_finspect(event, dst);
event = event->next;
}
pn_fixed_string_addf(dst, "]");
return;
}
#define pn_collector_hashcode NULL
#define pn_collector_compare NULL
pn_collector_t *pn_collector(void)
{
static const pn_class_t clazz = PN_CLASS(pn_collector);
return (pn_collector_t *) pn_class_new(&clazz, sizeof(pn_collector_t));
}
void pn_collector_free(pn_collector_t *collector)
{
assert(collector);
pn_collector_release(collector);
pn_decref(collector);
}
void pn_collector_release(pn_collector_t *collector)
{
assert(collector);
if (!collector->freed) {
collector->freed = true;
pn_collector_drain(collector);
pn_collector_shrink(collector);
}
}
pn_event_t *pn_event(void);
pn_event_t *pn_collector_put(pn_collector_t *collector,
const pn_class_t *clazz, void *context,
pn_event_type_t type)
{
if (!collector) {
return NULL;
}
assert(context);
if (collector->freed) {
return NULL;
}
pn_event_t *tail = collector->tail;
if (tail && tail->type == type && tail->context == context) {
return NULL;
}
pn_event_t *event = (pn_event_t *) pn_list_pop(collector->pool);
if (!event) {
event = pn_event();
}
event->pool = collector->pool;
pn_incref(event->pool);
if (tail) {
tail->next = event;
collector->tail = event;
} else {
collector->tail = event;
collector->head = event;
}
event->clazz = clazz;
event->context = context;
event->type = type;
pn_class_incref(clazz, event->context);
return event;
}
pn_event_t *pn_collector_put_object(pn_collector_t *collector, void *object, pn_event_type_t type)
{
const pn_class_t *clazz = pn_class(object);
return pn_collector_put(collector, clazz, object, type);
}
pn_event_t *pn_collector_peek(pn_collector_t *collector)
{
return collector->head;
}
// Advance head pointer for pop or next, return the old head.
static pn_event_t *pop_internal(pn_collector_t *collector) {
pn_event_t *event = collector->head;
if (event) {
collector->head = event->next;
if (!collector->head) {
collector->tail = NULL;
}
}
return event;
}
bool pn_collector_pop(pn_collector_t *collector) {
pn_event_t *event = pop_internal(collector);
if (event) {
pn_decref(event);
}
return event;
}
pn_event_t *pn_collector_next(pn_collector_t *collector) {
if (collector->prev) {
pn_decref(collector->prev);
}
collector->prev = pop_internal(collector);
return collector->prev;
}
pn_event_t *pn_collector_prev(pn_collector_t *collector) {
return collector->prev;
}
bool pn_collector_more(pn_collector_t *collector)
{
assert(collector);
return collector->head && collector->head->next;
}
static void pn_event_initialize(void *object)
{
pn_event_t *event = (pn_event_t *)object;
event->pool = NULL;
event->type = PN_EVENT_NONE;
event->clazz = NULL;
event->context = NULL;
event->next = NULL;
event->attachments = pn_record();
}
static void pn_event_finalize(void *object) {
pn_event_t *event = (pn_event_t *)object;
// decref before adding to the free list
if (event->clazz && event->context) {
pn_class_decref(event->clazz, event->context);
}
pn_list_t *pool = event->pool;
if (pool && pn_refcount(pool) > 1) {
event->pool = NULL;
event->type = PN_EVENT_NONE;
event->clazz = NULL;
event->context = NULL;
event->next = NULL;
pn_record_clear(event->attachments);
pn_list_add(pool, event);
} else {
pn_decref(event->attachments);
}
pn_decref(pool);
}
static void pn_event_inspect(void *object, pn_fixed_string_t *dst)
{
pn_event_t *event = (pn_event_t *)object;
assert(event);
assert(dst);
const char *name = pn_event_type_name(event->type);
if (name) {
pn_fixed_string_addf(dst, "(%s", pn_event_type_name(event->type));
} else {
pn_fixed_string_addf(dst, "(<%u>", (unsigned int) event->type);
}
if (event->context) {
pn_fixed_string_addf(dst, ", ");
pn_class_inspect(event->clazz, event->context, dst);
}
pn_fixed_string_addf(dst, ")");
return;
}
pn_event_t *pn_event(void)
{
return pn_class_new(&PN_CLASSCLASS(pn_event), sizeof(pn_event_t));
}
pn_event_type_t pn_event_type(pn_event_t *event)
{
return event ? event->type : PN_EVENT_NONE;
}
const pn_class_t *pn_event_class(pn_event_t *event)
{
assert(event);
return event->clazz;
}
void *pn_event_context(pn_event_t *event)
{
assert(event);
return event->context;
}
pn_record_t *pn_event_attachments(pn_event_t *event)
{
assert(event);
return event->attachments;
}
const char *pn_event_type_name(pn_event_type_t type)
{
#define CASE(X) case X: return #X
switch (type) {
CASE(PN_EVENT_NONE);
CASE(PN_REACTOR_INIT);
CASE(PN_REACTOR_QUIESCED);
CASE(PN_REACTOR_FINAL);
CASE(PN_TIMER_TASK);
CASE(PN_CONNECTION_INIT);
CASE(PN_CONNECTION_BOUND);
CASE(PN_CONNECTION_UNBOUND);
CASE(PN_CONNECTION_REMOTE_OPEN);
CASE(PN_CONNECTION_LOCAL_OPEN);
CASE(PN_CONNECTION_REMOTE_CLOSE);
CASE(PN_CONNECTION_LOCAL_CLOSE);
CASE(PN_CONNECTION_FINAL);
CASE(PN_SESSION_INIT);
CASE(PN_SESSION_REMOTE_OPEN);
CASE(PN_SESSION_LOCAL_OPEN);
CASE(PN_SESSION_REMOTE_CLOSE);
CASE(PN_SESSION_LOCAL_CLOSE);
CASE(PN_SESSION_FINAL);
CASE(PN_LINK_INIT);
CASE(PN_LINK_REMOTE_OPEN);
CASE(PN_LINK_LOCAL_OPEN);
CASE(PN_LINK_REMOTE_CLOSE);
CASE(PN_LINK_LOCAL_DETACH);
CASE(PN_LINK_REMOTE_DETACH);
CASE(PN_LINK_LOCAL_CLOSE);
CASE(PN_LINK_FLOW);
CASE(PN_LINK_FINAL);
CASE(PN_DELIVERY);
CASE(PN_TRANSPORT);
CASE(PN_TRANSPORT_AUTHENTICATED);
CASE(PN_TRANSPORT_ERROR);
CASE(PN_TRANSPORT_HEAD_CLOSED);
CASE(PN_TRANSPORT_TAIL_CLOSED);
CASE(PN_TRANSPORT_CLOSED);
CASE(PN_SELECTABLE_INIT);
CASE(PN_SELECTABLE_UPDATED);
CASE(PN_SELECTABLE_READABLE);
CASE(PN_SELECTABLE_WRITABLE);
CASE(PN_SELECTABLE_ERROR);
CASE(PN_SELECTABLE_EXPIRED);
CASE(PN_SELECTABLE_FINAL);
CASE(PN_CONNECTION_WAKE);
CASE(PN_LISTENER_ACCEPT);
CASE(PN_LISTENER_CLOSE);
CASE(PN_PROACTOR_INTERRUPT);
CASE(PN_PROACTOR_TIMEOUT);
CASE(PN_PROACTOR_INACTIVE);
CASE(PN_LISTENER_OPEN);
CASE(PN_RAW_CONNECTION_CONNECTED);
CASE(PN_RAW_CONNECTION_DISCONNECTED);
CASE(PN_RAW_CONNECTION_CLOSED_READ);
CASE(PN_RAW_CONNECTION_CLOSED_WRITE);
CASE(PN_RAW_CONNECTION_NEED_READ_BUFFERS);
CASE(PN_RAW_CONNECTION_NEED_WRITE_BUFFERS);
CASE(PN_RAW_CONNECTION_READ);
CASE(PN_RAW_CONNECTION_WRITTEN);
CASE(PN_RAW_CONNECTION_WAKE);
CASE(PN_RAW_CONNECTION_DRAIN_BUFFERS);
default:
return "PN_UNKNOWN";
}
return NULL;
#undef CASE
}