/*! \internal \brief Uninitialize a plugin In addition to terminating the thread, and removing p from the linked list and hashtable, it also frees up p. \note Should only be called from the context of the registrar thread. */ void kmmint_exit_plugin(kmm_plugin_i * p) { int np; khm_boolean release_plugin = TRUE; if(p->state == KMM_PLUGIN_STATE_RUNNING || p->state == KMM_PLUGIN_STATE_INIT) { kmq_post_thread_quit_message(p->tid_thread, 0, NULL); /* when we post the quit message to the plugin thread, the plugin broker terminates the plugin and posts a EXIT_PLUGIN message, which calls this function again. We just exit here because the EXIT_PLUGIN message will end up calling us again momentarily */ return; } if(p->ht_thread) { /* wait for the thread to terminate */ WaitForSingleObject(p->ht_thread, INFINITE); p->ht_thread = NULL; } EnterCriticalSection(&cs_kmm); /* undo reference count done in kmmint_init_plugin() */ if(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT) { np = --(p->module->plugin_count); p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; } else { /* the plugin was not included in the module's plugin_count. We can't base a decision to unload the module based on this plugin exiting. */ np = TRUE; } /* The plugin is in an error state. We need to keep the plugin record intact so that the failure information is kept around. Also, we shouldn't release the plugin if it appears that kmmint_init_plugin() was never called for it. */ if (p->state < KMM_PLUGIN_STATE_HOLD) { release_plugin = FALSE; } LeaveCriticalSection(&cs_kmm); if(!np) { /* if this is the last plugin to exit, then notify the registrar that the module should be removed as well */ kmm_hold_module(kmm_handle_from_module(p->module)); kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module); } /* release the hold obtained in kmmint_init_plugin() */ if (release_plugin) kmm_release_plugin(kmm_handle_from_plugin(p)); }
/*! \internal \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs */ KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message(kmq_thread_id thread, khm_ui_4 uparam) { kmq_call c; khm_int32 rv = KHM_ERROR_SUCCESS; rv = kmq_post_thread_quit_message(thread, uparam, &c); if(KHM_FAILED(rv)) return rv; rv = kmq_wait(c, INFINITE); kmq_free_call(c); return rv; }
KHMEXP void KHMAPI kmm_exit(void) { kmm_module_i * m; kmm_plugin_i * p; EnterCriticalSection(&cs_kmm); p = kmm_listed_plugins; while(p) { kmm_plugin_i * pn; pn = LNEXT(p); /* plugins that were never resolved should be kicked off the list. Flipping the refcount will do that if no other references exist for the plugin. The plugins that were waiting for unresolved dependencies will automatically get freed when the placeholders and other plugins get freed. */ if(p->state == KMM_PLUGIN_STATE_PLACEHOLDER) { kmm_hold_plugin(kmm_handle_from_plugin(p)); kmm_release_plugin(kmm_handle_from_plugin(p)); } p = pn; } m = kmm_all_modules; while(m) { kmm_unload_module(kmm_handle_from_module(m)); m = LNEXT(m); } LeaveCriticalSection(&cs_kmm); WaitForSingleObject(evt_exit, INFINITE); EnterCriticalSection(&cs_kmm); kmq_post_thread_quit_message(tid_registrar, 0, NULL); hash_del_hashtable(hash_plugins); hash_del_hashtable(hash_modules); LeaveCriticalSection(&cs_kmm); TlsFree(tls_kmm); tls_kmm = 0; }