File: [Platon] / libco / libco / co_o_default.c (download)
Revision 1.1, Sun Mar 30 10:27:02 2003 UTC (21 years ago) by yenar
add implementation of 'default' object flavour: event handling
stacked on top of 'small' flavour [co_o_default.c, co_o_default.h]
|
/***{{{*******************************************************************
* This file is part of libco - object library for C *
* Copyright (c) 2002 *
* Peter Rockai (yenar) <yenar@host.sk> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, *
* Boston, MA 02111-1307 USA *
*******************************************************************}}}***/
/* {{{ file description */
/**
* @file co_o_default.c
* @brief Implementation of "default" object flavour.
**/
/* }}} */
/* {{{ includes */
#include "co_o_default.h"
#include "co_exception.h"
#include "co_conv.h"
#include "co_util.h"
/* }}} */
#include "co_o_default.cometa"
/* {{{ */
static void co_listen_cleanup (co _o)
/// Clean up listener list (internal).
/**
* This function is called automatically and shouldn't be used directly.
* It cleans up the list of event listeners, so we regain memory and speed
* up lookup in co_ev function.
**/
{
co_o_default o = _o;
co_ev_listen i, in;
CO_DEBUG (3, "removing from head...");
while (o -> listen && o -> listen -> deleted) {
i = o -> listen;
o -> listen = i -> n;
free (i);
}
CO_DEBUG (4, "removing from tail...");
for (i = o -> listen; i && i -> n; i = i -> n) {
if (i -> n -> deleted) {
in = i -> n;
i -> n = in -> n;
free (in);
}
}
}
/* }}} */
/* {{{ */
static void co_o_default_disconnect (co _emit, co listen)
/// Disconnect two objects.
/**
* This removes all references to @a listen from @a _emit. When @a listen
* is being destroyed, this is called automatically.
**/
{
co_o_default emit;
co_ev_listen i;
emit = _emit;
CO_DEBUG (4, "marking items for deletion (_o = %p, dis = %p)...",
emit, listen);
for (i = emit -> listen; i; i = i -> n) {
CO_DEBUG (8, "testing: i = %p, i -> o = %p", i, i -> o);
if (i -> o == listen) {
CO_DEBUG (6, "marked: %p", i);
i -> deleted = 1;
emit -> check_listen = 1;
}
}
}
/* }}} */
/* {{{ */
co_v co_o_default_destroy (co _o, co self, co_id_t message, va_list ap)
/// Destroy object (internal: no checking is done).
/**
* This destroys object without checking the state prior to taking
* actions and without calling object's own destruction handler. Do not
* use or, if absolutely needed, only with extreme caution. Use co_del_f
* for standard but forced destruction or co_del for standard checked
* destruction.
*
* @see co_del, co_del_f
**/
{
co_o_default o = _o;
co_ev_listen i, in;
CO_DEBUG (4, "cleaning o (= %p) -> listen", o);
for (i = o -> listen; i; i = i -> n) {
CO_DEBUG (6, "disconnecting (i = %p, deleted = %d)", i, i -> deleted);
if (i -> ev == COE (disconnect_object) && ! i -> deleted)
co_o_default_disconnect (i -> o, o);
}
for (i = o -> listen; i; i = in) {
in = i -> n;
free (i);
}
return co_o_small_destroy (_o, self, message, ap);
}
/* }}} */
/* {{{ */
co_v co_o_default_delete (co _o, co self, co_id_t message, va_list ap)
{
return co_o_small_delete (_o, self, message, ap);
}
/* }}} */
/* {{{ */
void co_o_default_bless (co _o)
{
co_o_default o = _o;
co_o_small_bless (_o);
o -> listen = 0;
o -> ev_running = 0;
o -> check_listen = 0;
}
/* }}} */
/* {{{ */
co co_o_default_new (void)
{
co_o_default this;
this = new (co_o_default_s);
co_o_default_bless (this);
cox_pop (this);
CO_PUSH (this);
return this;
}
/* }}} */
/* {{{ */
co_v co_o_default_event (co this, co self, co_id_t message, va_list ap)
{
volatile co_ev_listen i;
co_id_t ot;
int erb;
co_o_default o = this;
va_list ap2;
#if DEBUGLVL > 0
int __dbglvl = __co_debug_msg_level;
//char __ev_id [128];
#endif
co_id_t ev = va_arg (ap, co_id_t);
erb = o -> ev_running;
o -> ev_running = 1;
ot = o -> type;
/* {{{ debug *//*
#if DEBUGLVL > 0
__co_debug_msg_level ++;
snprintf (__ev_id, 128, "%s/%s",
__co_type_array [_o -> type] . name, __co_event_array [ev]);
CO_DEBUG2 (2, "---------------------------------------------------"
"-----------------------------\n");
CO_DEBUG2 (2, " BEGIN EVENT | %23s | %p\n", __ev_id, o);
#endif
*//* }}} */
for (i = o -> listen; i; i = i -> n) {
if (ev == i -> ev && ! i -> deleted) {
//CO_DEBUG (2, "match: o = %p, msg = %s", i -> o, __co_action_array [i -> msg]);
CO_DEBUG (2, "match: o = %p, msg = %d", i -> o, i -> msg);
__va_copy (ap2, ap);
// FIXME?
/* if (i -> msg == COM (destroy)) {
i -> deleted = 1;
co_del (i -> o);
} else */ {
if (! erb) {
COX_TRY {
co_m_v (i -> o, i -> o, i -> msg, ap2);
}
COX_CATCH (err) {
o -> ev_running = 0;
#if DEBUGLVL > 0
__co_debug_msg_level = __dbglvl;
#endif
COX_RETHROW (err);
} COX_CATCH_END;
} else {
co_m_v (i -> o, i -> o, i -> msg, ap);
}
}
if (i -> ad) i -> deleted = 1;
}
}
/* {{{ debug *//*
#if DEBUGLVL > 0
CO_DEBUG2 (2, " END EVENT | %23s | %p\n", __ev_id, o);
CO_DEBUG2 (2, "---------------------------------------------------"
"-----------------------------\n");
__co_debug_msg_level --;
#endif
*//* }}} */
o -> ev_running = erb;
if (! erb & o -> check_listen)
co_listen_cleanup (o);
CO_RETURN (int, 0);
} /* }}} */
/* {{{ */
void co_cnt (co emit, co_id_t ev, co listen, co_id_t msg, bool ad)
{
co_ev_listen i, nw;
co_o_default _e = emit;
/* CO_DEBUG (2, "%p (%s) listens to %p (%s))",
listen, __co_type_array [((co_o) listen) -> type] . name,
emit, __co_type_array [_e -> type] . name);
CO_DEBUG (2, "msg = %s, ev = %s",
__co_action_array [msg],
__co_event_array [ev]); */
// do not create two identical connections
for (i = _e -> listen; i; i = i -> n) {
if (i -> ev == ev && listen == i -> o && i -> msg == msg) {
CO_DEBUG (2, "already exists, aborting");
return;
}
}
CO_DEBUG (3, "creating connection data...");
nw = new_p (co_ev_listen_s);
nw -> o = listen;
nw -> ev = ev;
nw -> msg = msg;
nw -> n = 0;
nw -> deleted = 0;
nw -> ad = ad;
CO_DEBUG (3, "embedding data into linked list...");
if (_e -> listen) {
nw -> n = _e -> listen;
}
_e -> listen = nw;
if (emit != listen) {
CO_DEBUG (3, "creating auto-disconnect connection...");
CO_CNT (listen, disconnect_object, emit, disconnect_object);
}
} /* }}} */
/* {{{ */
void co_o_default_copy (co dest, co src)
{
co_o_small_copy (dest, src);
// XXX do our own stuff here
}
/* }}} */
/* {{{ */
co_v co_o_default_clone_min (co this, co self, co_id_t message, va_list ap)
{
co_o_default dest, o = this;
(void) message; (void) self; (void) ap;
CO_DEBUG (2, "called");
dest = co_o_default_new ();
co_o_default_copy (dest, this);
CO_RETURN (co, dest);
}
/* }}} */
/* {{{ */
co_v co_o_default_clone (co this, co self, co_id_t message, va_list ap)
{
co_o_default dest, o = this;
CO_DEBUG (2, "called");
dest = co_o_default_clone_min (this, self, message, ap) . _co;
M (dest, data_copy_from, this);
CO_RETURN (co, dest);
}
/* }}} */
/* {{{ */
co_v co_o_default_clone_deep (co this, co self, co_id_t message, va_list ap)
{
co_o_default dest, o = this;
CO_DEBUG (2, "called");
dest = co_o_default_clone_min (this, self, message, ap) . _co;
M (dest, data_copy_deep_from, this);
CO_RETURN (co, dest);
}
/* }}} */
#if 0
/* {{{ */
void co_ev (co _o, co_id_t ev, ...)
{
volatile co_ev_listen i;
co_id_t ot;
int erb;
co_o_default o = _o;
va_list ap;
#if DEBUGLVL > 0
int __dbglvl = __co_debug_msg_level;
//char __ev_id [128];
#endif
erb = o -> ev_running;
o -> ev_running = 1;
ot = o -> type;
/* {{{ debug *//*
#if DEBUGLVL > 0
__co_debug_msg_level ++;
snprintf (__ev_id, 128, "%s/%s",
__co_type_array [_o -> type] . name, __co_event_array [ev]);
CO_DEBUG2 (2, "---------------------------------------------------"
"-----------------------------\n");
CO_DEBUG2 (2, " BEGIN EVENT | %23s | %p\n", __ev_id, o);
#endif
*//* }}} */
for (i = o -> __co_listen; i; i = i -> n) {
if (ev == i -> ev && ! i -> deleted) {
//CO_DEBUG (2, "match: o = %p, msg = %s", i -> o, __co_action_array [i -> msg]);
va_start (ap, ev);
if (i -> msg == COM (destroy)) {
i -> deleted = 1;
co_del (i -> o);
} else {
if (! erb) {
COX_TRY {
co_m_v (i -> o, i -> o, i -> msg, ap);
}
COX_CATCH (err) {
o -> ev_running = 0;
#if DEBUGLVL > 0
__co_debug_msg_level = __dbglvl;
#endif
COX_RETHROW (err);
} COX_CATCH_END;
} else {
co_m_v (i -> o, i -> o, i -> msg, ap);
}
}
va_end (ap);
if (i -> ad) i -> deleted = 1;
}
}
/* {{{ debug *//*
#if DEBUGLVL > 0
CO_DEBUG2 (2, " END EVENT | %23s | %p\n", __ev_id, o);
CO_DEBUG2 (2, "---------------------------------------------------"
"-----------------------------\n");
__co_debug_msg_level --;
#endif
*//* }}} */
o -> ev_running = erb;
if (! erb & o -> check_listen)
co_listen_cleanup (o);
} /* }}} */
#endif /* 0 */
Platon Group <platon@platon.org> http://platon.org/
|