/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /** * bonobo-running-context.c: A global running interface * * Author: * Michael Meeks (michael@helixcode.com) * * Copyright (C) 2000, Ximian, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #define PARENT_TYPE BONOBO_TYPE_OBJECT /* you may debug by adding item "running" to BONOBO_DEBUG_FLAGS environment variable. */ static BonoboObjectClass *bonobo_running_context_parent_class = NULL; typedef struct { gboolean emitted_last_unref; GHashTable *objects; GHashTable *keys; } BonoboRunningInfo; static BonoboRunningInfo *bonobo_running_info = NULL; static BonoboObject *bonobo_running_context = NULL; static BonoboEventSource *bonobo_running_event_source = NULL; enum { LAST_UNREF, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; static void key_free (gpointer name, gpointer dummy1, gpointer user_data) { g_free (name); } #ifdef G_ENABLE_DEBUG static void bonobo_ri_debug_foreach (gpointer key, gpointer value, gpointer user_data) { CORBA_Object *o = value; bonobo_debug_print ("", "[%p]:CORBA_Object still running", o); } #endif void bonobo_running_context_shutdown (void) { if (bonobo_running_info) { BonoboRunningInfo *ri = bonobo_running_info; #ifdef G_ENABLE_DEBUG if(_bonobo_debug_flags & BONOBO_DEBUG_RUNNING) { bonobo_debug_print ("rinfo-start", "-------------------------------------------------"); bonobo_debug_print ("running-objects", "%d running objects", g_hash_table_size (ri->objects)); g_hash_table_foreach (ri->objects, bonobo_ri_debug_foreach, NULL); bonobo_debug_print ("rinfo-end", "-------------------------------------------------"); } #endif /* G_ENABLE_DEBUG */ if (ri->objects) g_hash_table_destroy (ri->objects); ri->objects = NULL; if (ri->keys) { g_hash_table_foreach_remove ( ri->keys, (GHRFunc) key_free, NULL); g_hash_table_destroy (ri->keys); ri->keys = NULL; } g_free (ri); } bonobo_running_info = NULL; bonobo_running_context = NULL; bonobo_running_event_source = NULL; } static void check_destroy (GObject *object) { bonobo_running_context = NULL; bonobo_running_event_source = NULL; } static BonoboRunningInfo * get_running_info_T (gboolean create) { if (!bonobo_running_info && create) { bonobo_running_info = g_new (BonoboRunningInfo, 1); bonobo_running_info->objects = g_hash_table_new (NULL, NULL); bonobo_running_info->keys = g_hash_table_new (g_str_hash, g_str_equal); bonobo_running_info->emitted_last_unref = FALSE; } return bonobo_running_info; } static void check_empty_T (void) { BonoboRunningInfo *ri = get_running_info_T (FALSE); if (!ri || !bonobo_running_context) return; if (!ri->emitted_last_unref && (g_hash_table_size (ri->objects) == 0) && (g_hash_table_size (ri->keys) == 0)) { ri->emitted_last_unref = TRUE; BONOBO_UNLOCK (); g_signal_emit (G_OBJECT (bonobo_running_context), signals [LAST_UNREF], 0); g_return_if_fail (bonobo_running_event_source != NULL); bonobo_event_source_notify_listeners ( bonobo_running_event_source, "bonobo:last_unref", NULL, NULL); BONOBO_LOCK (); } } #ifndef bonobo_running_context_add_object_T void bonobo_running_context_add_object_T (CORBA_Object object) { #ifdef G_ENABLE_DEBUG if(_bonobo_debug_flags & BONOBO_DEBUG_RUNNING) bonobo_running_context_trace_objects_T (object, "local", 0, 0); else #endif /* G_ENABLE_DEBUG */ { BonoboRunningInfo *ri = get_running_info_T (TRUE); ri->emitted_last_unref = FALSE; g_hash_table_insert (ri->objects, object, object); } } #endif #ifndef bonobo_running_context_remove_object_T void bonobo_running_context_remove_object_T (CORBA_Object object) { #ifdef G_ENABLE_DEBUG if(_bonobo_debug_flags & BONOBO_DEBUG_RUNNING) bonobo_running_context_trace_objects_T (object, "local", 0, 1); else #endif /* G_ENABLE_DEBUG */ { BonoboRunningInfo *ri = get_running_info_T (FALSE); if (ri) { g_hash_table_remove (ri->objects, object); check_empty_T (); } } } #endif #ifndef bonobo_running_context_ignore_object void bonobo_running_context_ignore_object (CORBA_Object object) { BONOBO_LOCK (); #ifdef G_ENABLE_DEBUG if(_bonobo_debug_flags & BONOBO_DEBUG_RUNNING) bonobo_running_context_trace_objects_T (object, "local", 0, 2); else #endif /* G_ENABLE_DEBUG */ { BonoboRunningInfo *ri = get_running_info_T (FALSE); if (ri) g_hash_table_remove (ri->objects, object); } BONOBO_UNLOCK (); } #endif #ifdef G_ENABLE_DEBUG static void _running_context_list_objects (gpointer key, gpointer value, gpointer user_data) { CORBA_Object object = (CORBA_Object) value; CORBA_char *type_id; CORBA_Environment ev; CORBA_exception_init (&ev); type_id = ORBit_small_get_type_id (object, &ev); if (ev._major != CORBA_NO_EXCEPTION) type_id = CORBA_string_dup ( ""); CORBA_exception_free (&ev); bonobo_debug_print ("Alive: ", "[%p]: %s", object, type_id); CORBA_free (type_id); } #endif void bonobo_running_context_trace_objects_T (CORBA_Object object, const char *fn, int line, int mode) { BonoboRunningInfo *ri; #ifdef G_ENABLE_DEBUG static const char cmode[][14] = { "add_object", "remove_object", "ignore_object" }; #endif ri = get_running_info_T (mode == 0); if (ri) { switch (mode) { case 0: g_hash_table_insert (ri->objects, object, object); ri->emitted_last_unref = FALSE; break; case 1: g_hash_table_remove (ri->objects, object); check_empty_T (); break; case 2: g_hash_table_remove (ri->objects, object); break; } #ifdef G_ENABLE_DEBUG if(_bonobo_debug_flags & BONOBO_DEBUG_RUNNING) { const char *mode_string = cmode[mode]; bonobo_debug_print (mode_string, "[%p]:CORBA_Object %d running objects at %s:%d", object, g_hash_table_size (ri->objects), fn, line); g_hash_table_foreach (ri->objects, _running_context_list_objects, NULL); } #endif /* G_ENABLE_DEBUG */ } } static void impl_Bonobo_RunningContext_addObject (PortableServer_Servant servant, const CORBA_Object object, CORBA_Environment *ev) { BONOBO_LOCK (); bonobo_running_context_add_object_T (object); BONOBO_UNLOCK (); } static void impl_Bonobo_RunningContext_removeObject (PortableServer_Servant servant, const CORBA_Object object, CORBA_Environment *ev) { BONOBO_LOCK (); bonobo_running_context_remove_object_T (object); BONOBO_UNLOCK (); } static void impl_Bonobo_RunningContext_addKey (PortableServer_Servant servant, const CORBA_char *key, CORBA_Environment *ev) { char *key_copy, *old_key; BonoboRunningInfo *ri; BONOBO_LOCK (); ri = get_running_info_T (TRUE); old_key = g_hash_table_lookup (ri->keys, key); if (old_key) { g_free (old_key); g_hash_table_remove (ri->keys, key); } key_copy = g_strdup (key); g_hash_table_insert (ri->keys, key_copy, key_copy); BONOBO_UNLOCK (); } static void impl_Bonobo_RunningContext_removeKey (PortableServer_Servant servant, const CORBA_char *key, CORBA_Environment *ev) { BonoboRunningInfo *ri; char *old_key; BONOBO_LOCK (); ri = get_running_info_T (FALSE); if (ri) { old_key = g_hash_table_lookup (ri->keys, key); g_free (old_key); g_hash_table_remove (ri->keys, key); check_empty_T (); } BONOBO_UNLOCK (); } static void impl_Bonobo_RunningContext_atExitUnref (PortableServer_Servant servant, const CORBA_Object object, CORBA_Environment *ev) { bonobo_running_context_at_exit_unref (object); } static void bonobo_running_context_class_init (BonoboRunningContextClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; POA_Bonobo_RunningContext__epv *epv = &klass->epv; bonobo_running_context_parent_class = g_type_class_peek_parent (klass); ((BonoboRunningContextClass *)klass)->last_unref = NULL; signals [LAST_UNREF] = g_signal_new ( "last_unref", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (BonoboRunningContextClass, last_unref), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); epv->addObject = impl_Bonobo_RunningContext_addObject; epv->removeObject = impl_Bonobo_RunningContext_removeObject; epv->addKey = impl_Bonobo_RunningContext_addKey; epv->removeKey = impl_Bonobo_RunningContext_removeKey; epv->atExitUnref = impl_Bonobo_RunningContext_atExitUnref; } static void bonobo_running_context_init (GObject *object) { /* nothing to do */ } BONOBO_TYPE_FUNC_FULL (BonoboRunningContext, Bonobo_RunningContext, PARENT_TYPE, bonobo_running_context) BonoboObject * bonobo_running_context_new (void) { if (bonobo_running_context) { bonobo_object_ref (bonobo_running_context); return bonobo_running_context; } bonobo_running_context = g_object_new ( bonobo_running_context_get_type (), NULL); bonobo_running_event_source = bonobo_event_source_new (); bonobo_running_context_ignore_object ( BONOBO_OBJREF (bonobo_running_event_source)); bonobo_event_source_ignore_listeners (bonobo_running_event_source); bonobo_object_add_interface (BONOBO_OBJECT (bonobo_running_context), BONOBO_OBJECT (bonobo_running_event_source)); g_signal_connect (G_OBJECT (bonobo_running_context), "destroy", G_CALLBACK (check_destroy), NULL); return bonobo_running_context; } BonoboObject * bonobo_context_running_get (void) { return bonobo_running_context_new (); } static void last_unref_cb (gpointer context, CORBA_Object object) { bonobo_object_release_unref (object, NULL); } void bonobo_running_context_at_exit_unref (CORBA_Object object) { CORBA_Environment ev; CORBA_Object obj_dup; CORBA_exception_init (&ev); obj_dup = CORBA_Object_duplicate (object, &ev); bonobo_running_context_ignore_object (obj_dup); if (bonobo_running_context) g_signal_connect (G_OBJECT (bonobo_running_context), "last_unref", G_CALLBACK (last_unref_cb), obj_dup); CORBA_exception_free (&ev); } static void last_unref_exit_cb (gpointer context, BonoboObject *object) { bonobo_object_unref (object); bonobo_main_quit (); } void bonobo_running_context_auto_exit_unref (BonoboObject *object) { g_return_if_fail (object != NULL); g_return_if_fail (BONOBO_IS_OBJECT (object)); bonobo_running_context_ignore_object (BONOBO_OBJREF (object)); if (bonobo_running_context) g_signal_connect (G_OBJECT (bonobo_running_context), "last_unref", G_CALLBACK (last_unref_exit_cb), object); }