2 * deployment.cpp: Deployment Class support
4 * Copyright 2008 Novell, Inc. (http://www.novell.com)
6 * See the LICENSE file included with the distribution for details.
13 #include "downloader.h"
14 #include "deployment.h"
18 #include "namescope.h"
22 #include <mono/jit/jit.h>
23 #include <mono/metadata/debug-helpers.h>
25 /* because this header sucks */
26 #include <mono/metadata/mono-debug.h>
28 #include <mono/metadata/mono-config.h>
29 #include <mono/metadata/mono-gc.h>
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/profiler.h>
33 #include <mono/metadata/appdomain.h>
39 gboolean
Deployment::initialized
= FALSE
;
40 pthread_key_t
Deployment::tls_key
= 0;
41 pthread_mutex_t
Deployment::hash_mutex
;
42 GHashTable
* Deployment::current_hash
= NULL
;
43 MonoDomain
* Deployment::root_domain
= NULL
;
44 Deployment
*Deployment::desktop_deployment
= NULL
;
45 gint32
Deployment::deployment_count
= 0;
47 class IDownloaderNode
: public List::Node
{
50 IDownloaderNode (IDownloader
*dl
)
54 virtual ~IDownloaderNode ()
56 if (dl
&& !dl
->IsAborted ())
62 class StringNode
: public List::Node
{
66 StringNode (char *str
) {
67 this->str
= g_strdup (str
);
72 find_string (List::Node
*node
, void *data
)
74 StringNode
*tp
= (StringNode
*)node
;
75 char *p
= (char*)data
;
77 return !strcmp (tp
->str
, p
);
81 Deployment::Initialize (const char *platform_dir
, bool create_root_domain
)
88 current_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
89 pthread_key_create (&tls_key
, NULL
);
90 pthread_mutex_init (&hash_mutex
, NULL
);
92 enable_vm_stack_trace ();
94 #if MONO_ENABLE_APP_DOMAIN_CONTROL
95 if (create_root_domain
) {
96 const gchar
*trace_options
;
97 const gchar
*moon_path
;
98 const gchar
*profiler
;
101 // Install signal handlers for crash reporting
102 // Note that this only works if mono hasn't been
103 // initialized yet (i.e. this must not be done
105 moonlight_install_signal_handlers ();
109 printf ("Moonlight: Enabling MONO_DEBUG=keep-delegates.\n");
110 g_setenv ("MONO_DEBUG", "keep-delegates", false);
113 mono_config_parse (NULL
);
115 /* if a platform directory is provided then we're running inside the browser and CoreCLR should be enabled */
117 security_enable_coreclr (platform_dir
);
119 /* XXX confine mono itself to the platform directory XXX incomplete */
120 g_setenv ("MONO_PATH", platform_dir
, true);
121 g_unsetenv ("MONO_GAC_PREFIX");
123 moon_path
= g_getenv ("MOON_PATH");
124 if (moon_path
!= NULL
&& moon_path
[0] != 0) {
125 printf ("Setting moonlight root directory to: %s\n", moon_path
);
126 mono_assembly_setrootdir (moon_path
);
130 trace_options
= g_getenv ("MOON_TRACE");
131 if (trace_options
!= NULL
){
132 printf ("Setting trace options to: %s\n", trace_options
);
133 mono_jit_set_trace_options (trace_options
);
136 profiler
= g_getenv ("MOON_PROFILER");
137 if (profiler
!= NULL
) {
138 printf ("Setting profiler to: %s\n", profiler
);
139 mono_profiler_load (profiler
);
142 mono_set_signal_chaining (true);
143 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
145 root_domain
= mono_jit_init_version ("Moonlight Root Domain", "moonlight");
147 LOG_DEPLOYMENT ("Deployment::Initialize (): Root domain is %p\n", root_domain
);
151 root_domain
= mono_domain_get ();
153 Deployment::desktop_deployment
= new Deployment (root_domain
);
154 Deployment::SetCurrent (Deployment::desktop_deployment
);
156 Application
*desktop_app
= new Application ();
157 desktop_deployment
->SetCurrentApplication (desktop_app
);
158 desktop_app
->unref ();
159 #if MONO_ENABLE_APP_DOMAIN_CONTROL
167 Deployment::RegisterThread (Deployment
*deployment
)
169 LOG_DEPLOYMENT ("Deployment::RegisterThread (): Deployment: %p Domain: %p\n", deployment
, deployment
->domain
);
170 mono_thread_attach (deployment
->domain
);
174 Deployment::GetCurrent()
176 Deployment
*deployment
= (Deployment
*) pthread_getspecific (tls_key
);
177 MonoDomain
*current_domain
= mono_domain_get ();
180 * If we dont have a Deployment* in the TLS slot then we are in a thread created
181 * by mono. In this case we look up in the hsah table the deployment against
182 * the current appdomain
184 if (deployment
== NULL
&& current_domain
!= NULL
) {
185 if (current_domain
!= NULL
) {
186 pthread_mutex_lock (&hash_mutex
);
187 deployment
= (Deployment
*) g_hash_table_lookup (current_hash
, current_domain
);
188 pthread_mutex_unlock (&hash_mutex
);
189 pthread_setspecific (tls_key
, deployment
);
190 LOG_DEPLOYMENT ("Deployment::GetCurrent (): Couldn't find deployment in our tls, searched current domain %p and found: %p\n", current_domain
, deployment
);
195 * If we have a domain mismatch, we likely got here from managed land and need
196 * to get the deployment tied to this domain
200 if (current_domain
== NULL
) {
201 /* this may happen for threads which are not registered with managed code (audio threads for instance). Everything ok. */
203 } else if (current_domain
== root_domain
) {
204 if (deployment
->domain
== NULL
) {
205 /* we're in a deployment whose domain has been unloaded (but we're in the right deployment) */
208 /* something is very wrong, I can't see how this can happen */
209 g_warning ("Deployment::GetCurrent (): Domain mismatch, but the current domain is the root domain?\n");
213 if (deployment
->domain
== NULL
) {
214 /* we switched from a deployment whose domain has been unloaded to a normal deployment */
216 } else if (deployment
->domain
!= current_domain
) {
217 /* we're in the wrong deployment: our tls entry is wrong, most likely because we got here on a managed thread */
226 LOG_DEPLOYMENT ("Deployment::GetCurrent (): Domain mismatch, thread %u, (tls) deployment: %p, deployment->domain: %p, (mono_domain_get) current_domain: %p, root_domain: %p, hash deployment: %p\n",
227 (int) pthread_self (), deployment
, deployment
->domain
, current_domain
, root_domain
, g_hash_table_lookup (current_hash
, current_domain
));
228 pthread_mutex_lock (&hash_mutex
);
229 deployment
= (Deployment
*) g_hash_table_lookup (current_hash
, current_domain
);
230 pthread_mutex_unlock (&hash_mutex
);
232 /* Fixup our tls entry */
233 if (deployment
!= NULL
) {
234 pthread_setspecific (tls_key
, deployment
);
239 if (deployment
== NULL
) {
240 // Currently this happens because we end up here during libmoon initialization.
241 // The fix is to not create objects as default values for our static dependency properties.
242 LOG_DEPLOYMENT ("Deployment::GetCurrent (): Didn't find a deployment. This should never happen.\n");
249 Deployment::SetCurrent (Deployment
* deployment
)
251 SetCurrent (deployment
, true);
255 Deployment::SetCurrent (Deployment
* deployment
, bool domain
)
258 if (deployment
&& mono_domain_get () != deployment
->domain
) {
259 LOG_DEPLOYMENT ("Deployment::SetCurrent (%p), thread: %i domain mismatch, is: %p\n", deployment
, (int) pthread_self (), mono_domain_get ());
260 } else if (pthread_getspecific (tls_key
) != deployment
) {
261 LOG_DEPLOYMENT ("Deployment::SetCurrent (%p), thread: %i deployment mismatch, is: %p\n", deployment
, (int) pthread_self (), pthread_getspecific (tls_key
));
266 if (deployment
!= NULL
&& deployment
->domain
!= NULL
) {
267 mono_domain_set (deployment
->domain
, TRUE
);
269 mono_domain_set (root_domain
, TRUE
);
272 pthread_setspecific (tls_key
, deployment
);
275 Deployment::Deployment (MonoDomain
*domain
)
276 : DependencyObject (this, Type::DEPLOYMENT
)
278 this->domain
= domain
;
282 Deployment::Deployment()
283 : DependencyObject (this, Type::DEPLOYMENT
)
285 MonoDomain
*current
= mono_domain_get ();
286 #if MONO_ENABLE_APP_DOMAIN_CONTROL
287 char *domain_name
= g_strdup_printf ("moonlight-%p", this);
288 mono_domain_set (root_domain
, FALSE
);
289 domain
= mono_domain_create_appdomain (domain_name
, NULL
);
290 g_free (domain_name
);
292 LOG_DEPLOYMENT ("Deployment::Deployment (): Created domain %p for deployment %p\n", domain
, this);
294 mono_domain_set (domain
, FALSE
);
300 mono_domain_set (current
, FALSE
);
304 Deployment::InnerConstructor ()
307 is_shutting_down
= false;
309 appdomain_unloaded
= false;
310 system_windows_assembly
= NULL
;
311 system_windows_deployment
= NULL
;
312 deployment_shutdown
= NULL
;
313 shutdown_state
= Running
; /* 0 */
314 is_loaded_from_xap
= false;
317 pending_unrefs
= NULL
;
319 objects_destroyed
= 0;
324 objects_alive
= NULL
;
325 pthread_mutex_init (&objects_alive_mutex
, NULL
);
328 pthread_setspecific (tls_key
, this);
330 pthread_mutex_lock (&hash_mutex
);
331 g_hash_table_insert (current_hash
, domain
, this);
332 pthread_mutex_unlock (&hash_mutex
);
334 font_manager
= new FontManager ();
335 types
= new Types ();
336 types
->Initialize ();
341 IdComparer (gconstpointer base1
, gconstpointer base2
)
343 int id1
= (*(EventObject
**) base1
)->GetId ();
344 int id2
= (*(EventObject
**) base2
)->GetId ();
346 int iddiff
= id1
- id2
;
357 accumulate_last_n (gpointer key
,
361 GPtrArray
*last_n
= (GPtrArray
*)user_data
;
363 g_ptr_array_insert_sorted (last_n
, IdComparer
, key
);
367 Deployment::~Deployment()
369 g_free (xap_location
);
373 LOG_DEPLOYMENT ("Deployment::~Deployment (): %p\n", this);
376 if (pending_unrefs
!= NULL
)
377 g_warning ("Deployment::~Deployment (): There are still pending unrefs.\n");
379 g_warning ("Deployment::~Deployment (): There are still medias waiting to get disposed.\n");
383 printf ("Deployment destroyed, with %i leaked EventObjects.\n", objects_created
- objects_destroyed
);
384 if (objects_created
!= objects_destroyed
)
387 if (objects_created
!= objects_destroyed
) {
388 printf ("Deployment destroyed, with %i leaked EventObjects.\n", objects_created
- objects_destroyed
);
393 pthread_mutex_destroy (&objects_alive_mutex
);
394 g_hash_table_destroy (objects_alive
);
398 types
->DeleteProperties ();
408 Deployment::ReportLeaks ()
410 printf ("Deployment leak report:\n");
411 if (objects_created
== objects_destroyed
) {
412 printf ("\tno leaked objects.\n");
414 printf ("\tObjects created: %i\n", objects_created
);
415 printf ("\tObjects destroyed: %i\n", objects_destroyed
);
416 printf ("\tDifference: %i (%.1f%%)\n", objects_created
- objects_destroyed
, (100.0 * objects_destroyed
) / objects_created
);
418 GPtrArray
* last_n
= g_ptr_array_new ();
420 pthread_mutex_lock (&objects_alive_mutex
);
421 g_hash_table_foreach (objects_alive
, accumulate_last_n
, last_n
);
422 pthread_mutex_unlock (&objects_alive_mutex
);
425 counter
= MIN(counter
, last_n
->len
);
427 printf ("\tOldest %d objects alive:\n", counter
);
428 for (uint i
= 0; i
< MIN (counter
, last_n
->len
); i
++) {
429 EventObject
* obj
= (EventObject
*) last_n
->pdata
[i
];
430 printf ("\t\t%p\t%i = %s, refcount: %i\n", obj
, obj
->GetId (), obj
->GetTypeName (), obj
->GetRefCount ());
434 g_ptr_array_free (last_n
, true);
440 Deployment::Reinitialize ()
442 downloaders
.Clear (true);
443 AssemblyPartCollection
* parts
= new AssemblyPartCollection ();
449 Deployment::IsShuttingDown ()
452 return is_shutting_down
;
456 Deployment::Dispose ()
458 LOG_DEPLOYMENT ("Deployment::Dispose (): %p\n", this);
460 DependencyObject::Dispose ();
464 Deployment::Shutdown (MonoImage
*system_windows_assembly
)
466 LOG_DEPLOYMENT ("Deployment::Shutdown ()\n");
469 * Shutting down is a complicated process with quite a few pitfalls.
470 * The current process is as follows:
471 * - Abort all downloaders. Firefox has a habit of calling into our
472 * downloader callbacks in bad moments, aborting all downloaders
473 * will prevent this from happening.
474 * - Ensure nothing is executed on the media threadpool threads and
476 * - Unload our appdomain. We still have code executing on separate
477 * threads (user code can have threads, and there is always the
479 * - The browser plugin is freed (the plugin needs to go away after
480 * after the appdomain, since managed code has lots of pointers
481 * to the plugin instance).
482 * - By now everything should have gotten unreffed, and the final object
483 * to be deleted is the deployment (every other object references the
484 * deployment to ensure this).
487 is_shutting_down
= true;
489 g_return_if_fail (!IsDisposed ());
491 Emit (ShuttingDownEvent
);
493 AbortAllDownloaders ();
495 * Dispose all Media instances so that we can be sure nothing is executed
496 * on the media threadpool threads after this point.
497 * This will also stop all media from playing, so there should be no audio
498 * threads doing anything either (note that there might be both media
499 * threadpool threads and audio threads still alive, just not executing
500 * anything related to this deployment).
504 if (current_app
!= NULL
) {
505 current_app
->Dispose ();
506 current_app
->unref ();
511 while ((node
= (StringNode
*) paths
.First ())) {
512 RemoveDir (node
->str
);
520 if (GetValue (NameScope::NameScopeProperty
))
521 SetValue (NameScope::NameScopeProperty
, NULL
);
523 #if MONO_ENABLE_APP_DOMAIN_CONTROL
524 if (system_windows_assembly
== NULL
) {
525 /* this can happen if initialization fails, i.e. xap downloading fails for instance */
526 shutdown_state
= DisposeDeployment
; /* skip managed shutdown entirely, since managed code wasn't initialized */
528 shutdown_state
= CallManagedShutdown
;
529 this->system_windows_assembly
= system_windows_assembly
;
531 this->ref (); /* timemanager is dead, so we need to add timeouts directly to glib */
532 g_timeout_add_full (G_PRIORITY_DEFAULT
, 1, ShutdownManagedCallback
, this, NULL
);
539 #if MONO_ENABLE_APP_DOMAIN_CONTROL
541 Deployment::ShutdownManagedCallback (gpointer user_data
)
543 return ((Deployment
*) user_data
)->ShutdownManaged ();
547 Deployment::ShutdownManaged ()
549 if (domain
== root_domain
) {
550 fprintf (stderr
, "Moonlight: Can't unload the root domain!\n");
551 this->unref (); /* the ref taken in Shutdown */
558 * Managed shutdown is complicated, with a few gotchas:
559 * - managed finalizers are run on a separate thread (multi-threaded issues)
560 * - after the appdomain has unloaded, we can't call into it anymore (for
561 * instance using function pointers into managed delegates).
563 * To do have a safe shutdown we have two different approaches:
565 * 1) Protect the function pointers in native code with mutex, both during
566 * callbacks and when setting them. This has the drawback of having a
567 * mutex locked during a potentially long time (the mutex is always
568 * locked while executing the callback), and the advantage that the
569 * callbacks can be executed from any thread and the cleanup can be done
570 * directly in the managed dtor.
571 * ExternalDemuxer uses this approach.
573 * 2) If the callbacks will only be executed on the main thread, we can
574 * avoid the native locks ensuring that everything related to the
575 * callbacks will be done on the main thread by doing the following:
576 * - During execution we keep a list in managed code of cleanup actions
577 * to execute upon shutdown. If a managed object is finalized during
578 * normal execution, it removes any applicable actions from the list.
579 * This list is protected with a lock, so it can be accessed from all
580 * threads (main thread + finalizer thread).
581 * - When shutdown is requested, we set a flag to disallow further
582 * additions to the list, and execute all the cleanup actions.
583 * There are two cases where the managed finalizer is executed:
584 * a) Normal execution, in this case the native object has one ref left
585 * (the one ToggleRef has), so it is guaranteed that nobody can call
586 * the callbacks anymore -> no cleanup is needed in the managed dtor.
587 * b) Shutdown, in this case the cleanup code has already been executed
588 * (by Deployment.Shutdown), which again means that no cleanup is
589 * needed in the managed dtor.
590 * This approach only works if the callbacks are only called on the main
591 * thread (since otherwise there is a race condition between calling the
592 * callbacks and cleaning them up). It also only works for ToggleReffed/
593 * refcounted objects.
594 * MultiScaleTileSource uses this approach.
597 LOG_DEPLOYMENT ("Deployment::ShutdownManaged (): shutdown_state: %i, appdomain: %p, deployment: %p\n", shutdown_state
, domain
, this);
599 Deployment::SetCurrent (this, true);
601 switch (shutdown_state
) {
602 case Running
: /* 0 */
603 /* this shouldn't happen */
604 case ShutdownFailed
: /* -1 */ {
605 /* There has been an error during shutdown and we can't continue shutting down */
606 fprintf (stderr
, "Moonlight: Shutdown aborted due to unexpected error(s)\n");
607 this->unref (); /* the ref taken in Shutdown */
610 case CallManagedShutdown
: /* 1 */{
611 /* Call the managed System.Windows.Deployment:Shutdown method */
613 MonoObject
*exc
= NULL
;
616 if (system_windows_assembly
== NULL
) {
617 shutdown_state
= ShutdownFailed
;
618 fprintf (stderr
, "Moonlight: Can't find the System.Windows.Deployment's assembly.\n");
622 if (system_windows_deployment
== NULL
) {
623 system_windows_deployment
= mono_class_from_name (system_windows_assembly
, "System.Windows", "Deployment");
624 if (system_windows_deployment
== NULL
) {
625 shutdown_state
= ShutdownFailed
;
626 fprintf (stderr
, "Moonlight: Can't find the System.Windows.Deployment class.\n");
631 if (deployment_shutdown
== NULL
) {
632 deployment_shutdown
= mono_class_get_method_from_name (system_windows_deployment
, "Shutdown", 0);
633 if (deployment_shutdown
== NULL
) {
634 shutdown_state
= ShutdownFailed
;
635 fprintf (stderr
, "Moonlight: Can't find the System.Windows.Deployment:Shutdown method.\n");
640 ret
= mono_runtime_invoke (deployment_shutdown
, NULL
, NULL
, &exc
);
643 shutdown_state
= ShutdownFailed
;
644 fprintf (stderr
, "Moonlight: Exception while cleaning up managed code.\n"); // TODO: print exception message/details
648 result
= (bool) (*(MonoBoolean
*) mono_object_unbox (ret
));
651 /* Managed code isn't ready to shutdown quite yet, try again later */
655 /* Managed shutdown successfully completed */
656 LOG_DEPLOYMENT ("Deployment::ShutdownManaged (): managed call to Deployment:Shutdown () on domain %p succeeded.\n", domain
);
658 shutdown_state
= UnloadDomain
;
661 case UnloadDomain
: /* 2 */ {
662 MonoException
*exc
= NULL
;
665 * When unloading an appdomain, all threads in that appdomain are aborted.
666 * This includes the main thread. According to Paolo it's safe if we first
667 * switch to the root domain (and there are no managed frames on the stack,
668 * which is guaranteed since we're in a glib timeout).
670 mono_domain_set (root_domain
, TRUE
);
672 /* Unload the domain */
673 mono_domain_try_unload (domain
, (MonoObject
**) &exc
);
675 /* Set back to our current domain while emitting AppDomainUnloadedEvent */
676 mono_domain_set (domain
, TRUE
);
677 appdomain_unloaded
= true;
678 Emit (Deployment::AppDomainUnloadedEvent
);
680 /* Remove the domain from the hash table (since from now on the same ptr may get reused in subsquent calls to mono_domain_create_appdomain) */
681 pthread_mutex_lock (&hash_mutex
);
682 g_hash_table_remove (current_hash
, domain
);
683 pthread_mutex_unlock (&hash_mutex
);
685 /* Since the domain ptr may get reused we have to leave the root domain as the current domain */
686 mono_domain_set (root_domain
, TRUE
);
688 /* Clear out the domain ptr to detect any illegal uses asap */
689 /* CHECK: do we need to call mono_domain_free? */
693 shutdown_state
= ShutdownFailed
;
694 fprintf (stderr
, "Moonlight: Exception while unloading appdomain.\n"); // TODO: print exception message/details
698 /* AppDomain successfully unloaded */
699 LOG_DEPLOYMENT ("Deployment::ShutdownManaged (): appdomain successfully unloaded.\n");
701 shutdown_state
= DisposeDeployment
;
704 case DisposeDeployment
: /* 3 */{
705 LOG_DEPLOYMENT ("Deployment::ShutdownManaged (): managed code has shutdown successfully, calling Dispose.\n");
707 this->unref (); /* the ref taken in Shutdown */
712 return true; /* repeat the callback, we're not done yet */
717 Deployment::GetTypes ()
723 Deployment::GetFontManager ()
729 Deployment::GetCurrentApplication ()
735 Deployment::SetCurrentApplication (Application
* value
)
737 if (current_app
== value
)
741 current_app
->unref ();
750 Deployment::RegisterDownloader (IDownloader
*dl
)
752 downloaders
.Append (new IDownloaderNode (dl
));
756 Deployment::UnregisterDownloader (IDownloader
*dl
)
758 IDownloaderNode
*node
= (IDownloaderNode
*) downloaders
.First ();
759 while (node
!= NULL
) {
760 if (node
->dl
== dl
) {
762 downloaders
.Remove (node
);
765 node
= (IDownloaderNode
*) node
->next
;
770 Deployment::AbortAllDownloaders ()
772 downloaders
.Clear (true);
775 class MediaNode
: public List::Node
{
780 MediaNode (Media
*media
)
785 void Clear (bool dispose
)
789 media
->DisposeObject (media
);
794 virtual ~MediaNode ()
798 Media
*GetMedia () { return media
; }
802 Deployment::RegisterMedia (EventObject
*media
)
806 LOG_DEPLOYMENT ("Deployment::RegisterMedia (%p)\n", media
);
808 medias_mutex
.Lock ();
809 if (is_shutting_down
) {
813 medias
= new List ();
814 medias
->Append (new MediaNode ((Media
*) media
));
817 medias_mutex
.Unlock ();
823 Deployment::UnregisterMedia (EventObject
*media
)
825 MediaNode
*node
= NULL
;
827 LOG_DEPLOYMENT ("Deployment::UnregisterMedia (%p)\n", media
);
829 medias_mutex
.Lock ();
830 if (medias
!= NULL
) {
831 node
= (MediaNode
*) medias
->First ();
832 while (node
!= NULL
) {
833 if (node
->GetMedia () == media
) {
834 medias
->Unlink (node
);
837 node
= (MediaNode
*) node
->next
;
840 medias_mutex
.Unlock ();
842 /* Don't delete with the lock held, it may reenter and dead-lock */
850 Deployment::DisposeAllMedias ()
854 medias_mutex
.Lock ();
857 medias_mutex
.Unlock ();
859 /* Don't delete with the lock held, it may reenter and dead-lock */
860 delete medias
; /* the node destructor calls Dispose on the media */
862 MediaThreadPool::WaitForCompletion (this);
871 Deployment::DrainUnrefs (gpointer context
)
873 Deployment
*deployment
= (Deployment
*) context
;
874 Deployment::SetCurrent (deployment
);
875 deployment
->DrainUnrefs ();
876 deployment
->unref ();
877 Deployment::SetCurrent (NULL
);
882 Deployment::DrainUnrefs ()
887 // Get the list of objects to unref.
889 list
= (UnrefData
*) g_atomic_pointer_get (&pending_unrefs
);
894 } while (!g_atomic_pointer_compare_and_exchange (&pending_unrefs
, list
, NULL
));
896 // Loop over all the objects in the list and unref them.
897 while (list
!= NULL
) {
905 if (IsDisposed () && g_atomic_pointer_get (&pending_unrefs
) == NULL
&& objects_destroyed
!= objects_created
) {
906 printf ("Moonlight: the current deployment (%p) has detected that probably no more objects will get freed on this deployment.\n", this);
913 Deployment::UnrefDelayed (EventObject
*obj
)
919 if (Deployment::GetCurrent () != this)
920 g_warning ("Deployment::UnrefDelayed (%p): The current deployment (%p) should be %p.\n", obj
, Deployment::GetCurrent (), this);
921 if (obj
->GetObjectType () != Type::DEPLOYMENT
&& obj
->GetUnsafeDeployment () != this && obj
->GetUnsafeDeployment () != NULL
)
922 g_warning ("Deployment::UnrefDelayed (%p): obj's deployment %p should be %p. type: %s\n", obj
, obj
->GetUnsafeDeployment (), this, obj
->GetTypeName ());
925 // Create the new list item
926 item
= (UnrefData
*) g_malloc (sizeof (UnrefData
));
929 // Prepend the list item into the list
931 list
= (UnrefData
*) g_atomic_pointer_get (&pending_unrefs
);
933 } while (!g_atomic_pointer_compare_and_exchange (&pending_unrefs
, list
, item
));
935 // If we created a new list instead of prepending to an existing one, add a idle tick call.
936 if (list
== NULL
) { // don't look at item->next, item might have gotten freed already.
937 g_idle_add (DrainUnrefs
, this);
938 ref (); // keep us alive until we've processed the unrefs.
943 Deployment::TrackObjectCreated (EventObject
*obj
)
945 g_atomic_int_inc (&objects_created
);
948 pthread_mutex_lock (&objects_alive_mutex
);
949 if (objects_alive
== NULL
)
950 objects_alive
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
951 g_hash_table_insert (objects_alive
, obj
, GINT_TO_POINTER (1));
952 pthread_mutex_unlock (&objects_alive_mutex
);
957 Deployment::TrackObjectDestroyed (EventObject
*obj
)
959 g_atomic_int_inc (&objects_destroyed
);
962 pthread_mutex_lock (&objects_alive_mutex
);
963 g_hash_table_remove (objects_alive
, obj
);
964 pthread_mutex_unlock (&objects_alive_mutex
);
966 Track ("Destroyed", "");
971 Deployment::IsLoadedFromXap ()
973 return is_loaded_from_xap
;
977 Deployment::SetIsLoadedFromXap (bool flag
)
979 is_loaded_from_xap
= flag
;
983 Deployment::SetXapLocation (const char *location
)
985 g_free (xap_location
);
986 xap_location
= g_strdup (location
);
990 Deployment::GetXapLocation ()
996 Deployment::TrackPath (char *path
)
998 paths
.Append (new StringNode (path
));
1002 Deployment::UntrackPath (char *path
)
1004 StringNode
* node
= (StringNode
*) paths
.Find (find_string
, path
);
1007 paths
.Remove (node
);
1013 Deployment::GetDeploymentCount ()
1015 return deployment_count
;
1022 AssemblyPart::AssemblyPart ()
1024 SetObjectType (Type::ASSEMBLYPART
);
1027 AssemblyPart::~AssemblyPart ()
1031 AssemblyPartCollection::AssemblyPartCollection ()
1033 SetObjectType (Type::ASSEMBLYPART_COLLECTION
);
1036 AssemblyPartCollection::~AssemblyPartCollection ()
1044 ExtensionPart::ExtensionPart ()
1046 SetObjectType (Type::EXTENSIONPART
);
1049 ExtensionPart::~ExtensionPart ()
1053 ExternalPart::ExternalPart ()
1055 SetObjectType (Type::EXTERNALPART
);
1058 ExternalPart::~ExternalPart ()
1062 ExternalPartCollection::ExternalPartCollection ()
1064 SetObjectType (Type::EXTERNALPART_COLLECTION
);
1067 ExternalPartCollection::~ExternalPartCollection ()
1071 /* OutOfBrowserSettings */
1072 OutOfBrowserSettings::OutOfBrowserSettings ()
1074 SetObjectType (Type::OUTOFBROWSERSETTINGS
);
1077 OutOfBrowserSettings::~OutOfBrowserSettings ()