aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/events_libevent.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/events_libevent.c')
-rw-r--r--protocols/events_libevent.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/protocols/events_libevent.c b/protocols/events_libevent.c
index bcfb3b45..d4767348 100644
--- a/protocols/events_libevent.c
+++ b/protocols/events_libevent.c
@@ -38,6 +38,13 @@
static guint id_next;
static GHashTable *id_hash;
+/* Since libevent doesn't handle two event handlers for one fd-condition
+ very well (which happens sometimes when BitlBee changes event handlers
+ for a combination), let's buid some indexes so we can delete them here
+ already, just in time. */
+static GHashTable *read_hash;
+static GHashTable *write_hash;
+
struct b_event_data
{
guint id;
@@ -52,6 +59,8 @@ void b_main_init()
id_next = 1;
id_hash = g_hash_table_new( g_int_hash, g_int_equal );
+ read_hash = g_hash_table_new( g_int_hash, g_int_equal );
+ write_hash = g_hash_table_new( g_int_hash, g_int_equal );
}
void b_main_run()
@@ -96,26 +105,49 @@ static void b_event_passthrough( int fd, short event, void *data )
gint b_input_add( gint fd, b_input_condition condition, b_event_handler function, gpointer data )
{
- struct b_event_data *b_ev = g_new0( struct b_event_data, 1 );
- GIOCondition out_cond;
-
- b_ev->id = id_next++;
- b_ev->function = function;
- b_ev->data = data;
+ struct b_event_data *b_ev;
- out_cond = EV_PERSIST;
- if( condition & GAIM_INPUT_READ )
- out_cond |= EV_READ;
- if( condition & GAIM_INPUT_WRITE )
- out_cond |= EV_WRITE;
+ event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data );
- event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev );
- event_add( &b_ev->evinfo, NULL );
-
- event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d\n", fd, condition, function, data, b_ev->id );
+ if( ( condition & GAIM_INPUT_READ && ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) ||
+ ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) )
+ {
+ /* We'll stick with this libevent entry, but give it a new BitlBee id. */
+ g_hash_table_remove( id_hash, &b_ev->id );
+
+ event_debug( "(replacing old handler (id = %d)) = %d\n", b_ev->id, id_next );
+
+ b_ev->id = id_next++;
+ b_ev->function = function;
+ b_ev->data = data;
+ }
+ else
+ {
+ GIOCondition out_cond;
+
+ event_debug( "(new) = %d\n", id_next );
+
+ b_ev = g_new0( struct b_event_data, 1 );
+ b_ev->id = id_next++;
+ b_ev->function = function;
+ b_ev->data = data;
+
+ out_cond = EV_PERSIST;
+ if( condition & GAIM_INPUT_READ )
+ out_cond |= EV_READ;
+ if( condition & GAIM_INPUT_WRITE )
+ out_cond |= EV_WRITE;
+
+ event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev );
+ event_add( &b_ev->evinfo, NULL );
+
+ if( out_cond & EV_READ )
+ g_hash_table_insert( read_hash, &b_ev->evinfo.ev_fd, b_ev );
+ if( out_cond & EV_WRITE )
+ g_hash_table_insert( write_hash, &b_ev->evinfo.ev_fd, b_ev );
+ }
g_hash_table_insert( id_hash, &b_ev->id, b_ev );
-
return b_ev->id;
}
@@ -135,7 +167,7 @@ gint b_timeout_add( gint timeout, b_event_handler function, gpointer data )
evtimer_set( &b_ev->evinfo, b_event_passthrough, b_ev );
evtimer_add( &b_ev->evinfo, &tv );
- event_debug( "b_timeout_add( %d, %d, 0x%x ) = %d\n", timeout, function, data, b_ev->id );
+ event_debug( "b_timeout_add( %d, 0x%x, 0x%x ) = %d\n", timeout, function, data, b_ev->id );
g_hash_table_insert( id_hash, &b_ev->id, b_ev );
@@ -149,13 +181,21 @@ void b_event_remove( gint id )
event_debug( "b_event_remove( %d )\n", id );
if( b_ev )
{
- event_del( &b_ev->evinfo );
g_hash_table_remove( id_hash, &b_ev->id );
+ if( b_ev->evinfo.ev_fd >= 0 )
+ {
+ if( b_ev->evinfo.ev_events & EV_READ )
+ g_hash_table_remove( read_hash, &b_ev->evinfo.ev_fd );
+ if( b_ev->evinfo.ev_events & EV_WRITE )
+ g_hash_table_remove( write_hash, &b_ev->evinfo.ev_fd );
+ }
+
+ event_del( &b_ev->evinfo );
g_free( b_ev );
}
else
{
- event_debug( "Double remove?\n" );
+ event_debug( "Already removed?\n" );
}
}