/* called with cs_kmm held */ void kmmint_free_plugin(kmm_plugin_i * pi) { int i; pi->magic = 0; hash_del(hash_plugins, (void *) pi->p.name); kmmint_delist_plugin(pi); for(i=0; i<pi->n_dependants; i++) { kmm_release_plugin(kmm_handle_from_plugin(pi->dependants[i])); pi->dependants[i] = NULL; } if(pi->module) { kmm_release_module(kmm_handle_from_module(pi->module)); } pi->module = NULL; pi->p.module = NULL; if(pi->p.name) PFREE(pi->p.name); pi->p.name = NULL; if(pi->p.description) PFREE(pi->p.description); pi->p.description = NULL; if(pi->p.dependencies) PFREE(pi->p.dependencies); pi->p.dependencies = NULL; PFREE(pi); }
KHMEXP khm_int32 KHMAPI kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin) { kmm_module_i * m; kmm_plugin_i * p; size_t cb_name = 0; size_t cb_desc = 0; size_t cb_dep = 0; m = kmm_module_from_handle(module); /* can only called when handing init_module() */ if(m->state != KMM_MODULE_STATE_INIT) return KHM_ERROR_INVALID_OPERATION; if(!plugin || FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t), &cb_name)) || (plugin->description && FAILED(StringCbLength(plugin->description, KMM_MAXCB_DESC - sizeof(wchar_t), &cb_desc))) || (plugin->dependencies && KHM_FAILED(multi_string_length_cb(plugin->dependencies, KMM_MAXCB_DEPS, &cb_dep)))) { return KHM_ERROR_INVALID_PARAM; } cb_name += sizeof(wchar_t); cb_desc += sizeof(wchar_t); p = kmmint_get_plugin_i(plugin->name); /* released below or in kmmint_init_module() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); if(p->state != KMM_PLUGIN_STATE_NONE && p->state != KMM_PLUGIN_STATE_PLACEHOLDER) { kmm_release_plugin(kmm_handle_from_plugin(p)); return KHM_ERROR_DUPLICATE; } /* released when the plugin quits */ kmm_hold_module(module); p->module = m; p->p.flags = plugin->flags; p->p.msg_proc = plugin->msg_proc; p->p.type = plugin->type; if(plugin->description) { p->p.description = PMALLOC(cb_desc); StringCbCopy(p->p.description, cb_desc, plugin->description); } else p->p.description = NULL; if(plugin->dependencies) { p->p.dependencies = PMALLOC(cb_dep); multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies); } else p->p.dependencies = NULL; p->p.module = p->module->name; p->p.icon = plugin->icon; p->state = KMM_PLUGIN_STATE_REG; kmmint_delist_plugin(p); EnterCriticalSection(&cs_kmm); LPUSH(&(m->plugins), p); p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST; LeaveCriticalSection(&cs_kmm); /* leave the plugin held because it is in the module's plugin list */ return KHM_ERROR_SUCCESS; }
/*! \internal \brief Initialize a plugin \note If kmmint_init_plugin() is called on a plugin, then kmmint_exit_plugin() \b must be called for the plugin. \note Should only be called from the context of the registrar thread */ void kmmint_init_plugin(kmm_plugin_i * p) { DWORD dummy; khm_handle csp_plugin = NULL; khm_handle csp_plugins = NULL; khm_int32 t; /* the following will be undone in kmmint_exit_plugin() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); EnterCriticalSection(&cs_kmm); if(p->state != KMM_PLUGIN_STATE_REG && p->state != KMM_PLUGIN_STATE_HOLD) { LeaveCriticalSection(&cs_kmm); goto _exit; } _begin_task(0); _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name)); _describe(); if(p->state == KMM_PLUGIN_STATE_HOLD) { /* if this plugin was held, then we already had a hold from the initial attempt to start the plugin. Undo the hold we did a few lines earlier. */ kmm_release_plugin(kmm_handle_from_plugin(p)); /* same for the plugin count for the module. */ #ifdef DEBUG assert(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT); #endif p->module->plugin_count--; p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; } p->state = KMM_PLUGIN_STATE_PREINIT; kmmint_delist_plugin(p); kmmint_list_plugin(p); LeaveCriticalSection(&cs_kmm); if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) { _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG); p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN; goto _exit; } if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; goto _exit; } if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; goto _exit; } } if (KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"Disabled", &t)) && t) { p->flags |= KMM_PLUGIN_FLAG_DISABLED; p->state = KMM_PLUGIN_STATE_FAIL_DISABLED; goto _exit; } #if 0 /*TODO: check the failure count and act accordingly */ if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) { } #endif EnterCriticalSection(&cs_kmm); p->n_depends = 0; p->n_unresolved = 0; do { wchar_t * deps = NULL; wchar_t * d; khm_size sz = 0; if(khc_read_multi_string(csp_plugin, L"Dependencies", NULL, &sz) != KHM_ERROR_TOO_LONG) break; deps = PMALLOC(sz); if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", deps, &sz))) { if(deps) PFREE(deps); break; } for(d = deps; d && *d; d = multi_string_next(d)) { kmm_plugin_i * pd; int i; pd = kmmint_get_plugin_i(d); if(pd->state == KMM_PLUGIN_STATE_NONE) { /* the dependant was not previously known */ pd->state = KMM_PLUGIN_STATE_PLACEHOLDER; } for(i=0; i < pd->n_dependants; i++) { if(pd->dependants[i] == p) break; } if(i >= pd->n_dependants) { if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) { /*TODO: handle this gracefully */ RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL); } /* released in kmmint_free_plugin() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); pd->dependants[pd->n_dependants] = p; pd->n_dependants++; } p->n_depends++; if(pd->state != KMM_PLUGIN_STATE_RUNNING) { p->n_unresolved++; } } if(p->n_unresolved > 0) { p->state = KMM_PLUGIN_STATE_HOLD; } PFREE(deps); } while(FALSE); #ifdef DEBUG assert(!(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT)); #endif p->flags |= KMM_PLUGIN_FLAG_IN_MODCOUNT; p->module->plugin_count++; LeaveCriticalSection(&cs_kmm); if(p->state == KMM_PLUGIN_STATE_HOLD) { _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name)); goto _exit_post; } kmmint_add_to_plugin_queue(p); p->ht_thread = CreateThread(NULL, 0, kmmint_plugin_broker, (LPVOID) p, CREATE_SUSPENDED, &dummy); p->state = KMM_PLUGIN_STATE_INIT; ResumeThread(p->ht_thread); _exit_post: if(csp_plugin != NULL) khc_close_space(csp_plugin); if(csp_plugins != NULL) khc_close_space(csp_plugins); _report_mr2(KHERR_INFO, MSG_IP_STATE, _dupstr(p->p.name), _int32(p->state)); _end_task(); return; /* jump here if an error condition happens before the plugin broker thread starts and the plugin should be unloaded */ _exit: if(csp_plugin != NULL) khc_close_space(csp_plugin); if(csp_plugins != NULL) khc_close_space(csp_plugins); _report_mr2(KHERR_WARNING, MSG_IP_EXITING, _dupstr(p->p.name), _int32(p->state)); _end_task(); #ifdef ASYNC_PLUGIN_UNLOAD_ON_FAILURE kmm_hold_plugin(kmm_handle_from_plugin(p)); kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p); #else kmmint_exit_plugin(p); #endif }