2 * Copyright (c) 2005 Massachusetts Institute of Technology
\r
4 * Permission is hereby granted, free of charge, to any person
\r
5 * obtaining a copy of this software and associated documentation
\r
6 * files (the "Software"), to deal in the Software without
\r
7 * restriction, including without limitation the rights to use, copy,
\r
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
\r
9 * of the Software, and to permit persons to whom the Software is
\r
10 * furnished to do so, subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be
\r
13 * included in all copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
27 #include<kmminternal.h>
\r
29 static LONG pending_modules = 0;
\r
30 static LONG pending_plugins = 0;
\r
31 static LONG startup_signal = 0;
\r
32 static BOOL load_done = FALSE;
\r
35 kmmint_check_completion(void) {
\r
36 if (pending_modules == 0 &&
\r
37 pending_plugins == 0 &&
\r
38 InterlockedIncrement(&startup_signal) == 1) {
\r
42 /* TODO: check for orphaned plugins */
\r
44 kmq_post_message(KMSG_KMM, KMSG_KMM_I_DONE, 0, 0);
\r
49 kmmint_add_to_module_queue(void) {
\r
50 InterlockedIncrement(&pending_modules);
\r
54 kmmint_remove_from_module_queue(void) {
\r
56 InterlockedDecrement(&pending_modules);
\r
58 kmmint_check_completion();
\r
62 kmmint_add_to_plugin_queue(void) {
\r
63 InterlockedIncrement(&pending_plugins);
\r
67 kmmint_remove_from_plugin_queue(void) {
\r
68 InterlockedDecrement(&pending_plugins);
\r
70 kmmint_check_completion();
\r
73 KHMEXP khm_boolean KHMAPI
\r
74 kmm_load_pending(void) {
\r
79 \brief Message handler for the registrar thread. */
\r
80 khm_boolean KHMAPI kmm_reg_cb(
\r
81 khm_int32 msg_type,
\r
82 khm_int32 msg_sub_type,
\r
86 /* we should only be getting <KMSG_KMM,KMSG_KMM_I_REG> anyway */
\r
87 if(msg_type != KMSG_KMM || msg_sub_type != KMSG_KMM_I_REG)
\r
91 case KMM_REG_INIT_MODULE:
\r
92 kmm_init_module((kmm_module_i *) vparam);
\r
93 kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam));
\r
96 case KMM_REG_EXIT_MODULE:
\r
97 kmm_exit_module((kmm_module_i *) vparam);
\r
98 kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam));
\r
101 case KMM_REG_INIT_PLUGIN:
\r
102 kmm_init_plugin((kmm_plugin_i *) vparam);
\r
103 kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam));
\r
106 case KMM_REG_EXIT_PLUGIN:
\r
107 kmm_exit_plugin((kmm_plugin_i *) vparam);
\r
108 kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam));
\r
115 \brief The registrar thread.
\r
117 The only thing this function does is to dispatch messages to the
\r
118 callback routine ( kmm_reg_cb() ) */
\r
119 DWORD WINAPI kmm_registrar(
\r
123 tid_registrar = GetCurrentThreadId();
\r
125 kmq_subscribe(KMSG_KMM, kmm_reg_cb);
\r
126 kmq_subscribe(KMSG_SYSTEM, kmm_reg_cb);
\r
128 SetEvent(evt_startup);
\r
130 while(KHM_SUCCEEDED(kmq_dispatch(INFINITE)));
\r
138 \brief Manages a plugin message thread.
\r
140 Each plugin gets its own plugin thread which is used to dispatch
\r
141 messages to the plugin. This acts as the thread function for the
\r
143 DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter)
\r
146 kmm_plugin_i * p = (kmm_plugin_i *) lpParameter;
\r
148 TlsSetValue(tls_kmm, (LPVOID) p);
\r
150 kmm_hold_plugin(kmm_handle_from_plugin(p));
\r
152 p->tid_thread = GetCurrentThreadId();
\r
154 if (IsBadCodePtr(p->p.msg_proc)) {
\r
155 rv = KHM_ERROR_INVALID_PARAM;
\r
157 rv = (p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_INIT,
\r
158 0, (void *) &(p->p)));
\r
161 /* if it fails to initialize, we exit the plugin */
\r
162 if(KHM_FAILED(rv)) {
\r
163 kmmint_remove_from_plugin_queue();
\r
168 /* subscribe to default message classes by plugin type */
\r
169 if(p->p.type == KHM_PITYPE_CRED) {
\r
170 kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc);
\r
171 kmq_subscribe(KMSG_KCDB, p->p.msg_proc);
\r
172 kmq_subscribe(KMSG_CRED, p->p.msg_proc);
\r
173 } else if(p->p.type == KHM_PITYPE_IDENT) {
\r
174 khm_handle h = NULL;
\r
176 kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc);
\r
177 kmq_subscribe(KMSG_KCDB, p->p.msg_proc);
\r
179 kmq_create_subscription(p->p.msg_proc, &h);
\r
180 kcdb_identity_set_provider(h);
\r
181 /* kcdb deletes the subscription when it's done with it */
\r
182 } else if(p->p.type == KHM_PITYPE_CONFIG) {
\r
183 /*TODO: subscribe to configuration provider messages here */
\r
186 p->state = KMM_PLUGIN_STATE_RUNNING;
\r
188 /* if there were any plugins that were waiting for this one to
\r
189 start, we should start them too */
\r
190 EnterCriticalSection(&cs_kmm);
\r
195 for(i=0; i < p->n_dependants; i++) {
\r
196 pd = p->dependants[i];
\r
198 pd->n_unresolved--;
\r
200 if(pd->n_unresolved == 0) {
\r
201 kmm_hold_plugin(kmm_handle_from_plugin(pd));
\r
202 kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_INIT_PLUGIN, (void *) pd);
\r
206 LeaveCriticalSection(&cs_kmm);
\r
208 kmmint_remove_from_plugin_queue();
\r
210 /* main message loop */
\r
211 while(KHM_SUCCEEDED(kmq_dispatch(INFINITE)));
\r
213 /* unsubscribe from default message classes by plugin type */
\r
214 if(p->p.type == KHM_PITYPE_CRED) {
\r
215 kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc);
\r
216 kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc);
\r
217 kmq_unsubscribe(KMSG_CRED, p->p.msg_proc);
\r
218 } else if (p->p.type == KHM_PITYPE_IDENT) {
\r
219 kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc);
\r
220 kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc);
\r
221 kcdb_identity_set_provider(NULL);
\r
222 } else if(p->p.type == KHM_PITYPE_CONFIG) {
\r
223 /*TODO: unsubscribe from configuration provider messages here */
\r
226 p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p));
\r
229 p->state = KMM_PLUGIN_STATE_EXITED;
\r
231 /* the following call will automatically release the plugin */
\r
232 kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG,
\r
233 KMM_REG_EXIT_PLUGIN, (void *) p);
\r
235 TlsSetValue(tls_kmm, (LPVOID) 0);
\r
244 \brief Initialize a plugin
\r
246 \note If kmm_init_plugin() is called on a plugin, then kmm_exit_plugin()
\r
247 \b must be called for the plugin.
\r
249 \note Should only be called from the context of the registrar thread */
\r
250 void kmm_init_plugin(kmm_plugin_i * p) {
\r
252 khm_handle csp_plugin = NULL;
\r
253 khm_handle csp_plugins = NULL;
\r
256 /* the following will be undone in kmm_exit_plugin() */
\r
257 kmm_hold_plugin(kmm_handle_from_plugin(p));
\r
259 EnterCriticalSection(&cs_kmm);
\r
260 if(p->state != KMM_PLUGIN_STATE_REG &&
\r
261 p->state != KMM_PLUGIN_STATE_HOLD)
\r
263 LeaveCriticalSection(&cs_kmm);
\r
268 _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name));
\r
271 if(p->state == KMM_PLUGIN_STATE_HOLD) {
\r
272 /* if this plugin was held, then we already had a hold
\r
273 from the initial attempt to start the plugin. Undo
\r
274 the hold we did a few lines earlier. */
\r
275 kmm_release_plugin(kmm_handle_from_plugin(p));
\r
276 /* same for the plugin count for the module. */
\r
277 p->module->plugin_count--;
\r
280 p->state = KMM_PLUGIN_STATE_PREINIT;
\r
281 LeaveCriticalSection(&cs_kmm);
\r
283 if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) {
\r
284 _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG);
\r
286 p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN;
\r
290 if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin)) ||
\r
291 KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) {
\r
292 if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) {
\r
293 _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);
\r
295 p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;
\r
299 if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) {
\r
300 _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);
\r
302 p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;
\r
306 if(KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) {
\r
307 _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);
\r
309 p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;
\r
314 if(t & KMM_PLUGIN_FLAG_DISABLED) {
\r
315 _report_mr0(KHERR_ERROR, MSG_IP_DISABLED);
\r
317 p->state = KMM_PLUGIN_STATE_FAIL_DISABLED;
\r
322 /*TODO: check the failure count and act accordingly */
\r
323 if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) {
\r
327 EnterCriticalSection(&cs_kmm);
\r
330 p->n_unresolved = 0;
\r
333 wchar_t * deps = NULL;
\r
337 if(khc_read_multi_string(csp_plugin, L"Dependencies",
\r
338 NULL, &sz) != KHM_ERROR_TOO_LONG)
\r
341 deps = PMALLOC(sz);
\r
342 if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies",
\r
349 for(d = deps; d && *d; d = multi_string_next(d)) {
\r
353 pd = kmmint_get_plugin_i(d);
\r
355 if(pd->state == KMM_PLUGIN_STATE_NONE) {
\r
356 /* the dependant was not previously known */
\r
357 pd->state = KMM_PLUGIN_STATE_PLACEHOLDER;
\r
360 for(i=0; i < pd->n_dependants; i++) {
\r
361 if(pd->dependants[i] == p)
\r
365 if(i >= pd->n_dependants) {
\r
366 if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) {
\r
367 /*TODO: handle this gracefully */
\r
368 RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL);
\r
371 /* released in kmmint_free_plugin() */
\r
372 kmm_hold_plugin(kmm_handle_from_plugin(p));
\r
373 pd->dependants[pd->n_dependants] = p;
\r
374 pd->n_dependants++;
\r
379 if(pd->state != KMM_PLUGIN_STATE_RUNNING) {
\r
384 if(p->n_unresolved > 0) {
\r
385 p->state = KMM_PLUGIN_STATE_HOLD;
\r
391 LeaveCriticalSection(&cs_kmm);
\r
393 EnterCriticalSection(&cs_kmm);
\r
394 p->module->plugin_count++;
\r
395 kmmint_delist_plugin(p);
\r
396 kmmint_list_plugin(p);
\r
397 LeaveCriticalSection(&cs_kmm);
\r
399 if(p->state == KMM_PLUGIN_STATE_HOLD) {
\r
400 _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name));
\r
405 kmmint_add_to_plugin_queue();
\r
407 p->ht_thread = CreateThread(NULL,
\r
414 p->state = KMM_PLUGIN_STATE_INIT;
\r
416 ResumeThread(p->ht_thread);
\r
419 if(csp_plugin != NULL)
\r
420 khc_close_space(csp_plugin);
\r
422 if(csp_plugins != NULL)
\r
423 khc_close_space(csp_plugins);
\r
425 _report_mr2(KHERR_INFO, MSG_IP_STATE,
\r
426 _dupstr(p->p.name), _int32(p->state));
\r
432 /* jump here if an error condition happens before the plugin
\r
433 broker thread starts and the plugin should be unloaded */
\r
436 if(csp_plugin != NULL)
\r
437 khc_close_space(csp_plugin);
\r
438 if(csp_plugins != NULL)
\r
439 khc_close_space(csp_plugins);
\r
441 _report_mr2(KHERR_WARNING, MSG_IP_EXITING,
\r
442 _dupstr(p->p.name), _int32(p->state));
\r
445 kmm_hold_plugin(kmm_handle_from_plugin(p));
\r
447 kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p);
\r
451 \brief Uninitialize a plugin
\r
453 In addition to terminating the thread, and removing p from the
\r
454 linked list and hashtable, it also frees up p.
\r
456 \note Should only be called from the context of the registrar thread. */
\r
457 void kmm_exit_plugin(kmm_plugin_i * p) {
\r
460 if(p->state == KMM_PLUGIN_STATE_RUNNING ||
\r
461 p->state == KMM_PLUGIN_STATE_INIT)
\r
463 kmq_post_thread_quit_message(p->tid_thread, 0, NULL);
\r
464 /* when we post the quit message to the plugin thread, the plugin
\r
465 broker terminates the plugin and posts a EXIT_PLUGIN message,
\r
466 which calls this function again. We just exit here because
\r
467 the EXIT_PLUGIN message will end up calling us again momentarily */
\r
472 /* wait for the thread to terminate */
\r
473 WaitForSingleObject(p->ht_thread, INFINITE);
\r
474 p->ht_thread = NULL;
\r
477 EnterCriticalSection(&cs_kmm);
\r
479 /* undo reference count done in kmm_init_plugin() */
\r
480 if(p->state == KMM_PLUGIN_STATE_EXITED ||
\r
481 p->state == KMM_PLUGIN_STATE_HOLD)
\r
483 np = --(p->module->plugin_count);
\r
485 /* the plugin was never active. We can't base a module unload
\r
489 LeaveCriticalSection(&cs_kmm);
\r
492 /* if this is the last plugin to exit, then notify the
\r
493 registrar that the module should be removed as well */
\r
494 kmm_hold_module(kmm_handle_from_module(p->module));
\r
495 kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module);
\r
498 /* release the hold obtained in kmm_init_plugin() */
\r
499 kmm_release_plugin(kmm_handle_from_plugin(p));
\r
503 \brief Initialize a module
\r
505 \a m is not in the linked list yet.
\r
507 \note Should only be called from the context of the registrar thread. */
\r
508 void kmm_init_module(kmm_module_i * m) {
\r
510 init_module_t p_init_module;
\r
513 khm_handle csp_mod = NULL;
\r
514 khm_handle csp_mods = NULL;
\r
518 /* error condition handling */
\r
519 BOOL exit_module = FALSE;
\r
520 BOOL release_module = TRUE;
\r
521 BOOL record_failure = FALSE;
\r
523 /* failure handling */
\r
524 khm_int32 max_fail_count = 0;
\r
525 khm_int64 fail_reset_time = 0;
\r
528 _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name));
\r
531 kmm_hold_module(kmm_handle_from_module(m));
\r
533 if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) {
\r
534 _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG);
\r
535 _location(L"kmm_get_modules_config()");
\r
537 m->state = KMM_MODULE_STATE_FAIL_UNKNOWN;
\r
541 khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count);
\r
542 khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time);
\r
544 /* If the module is not in the pre-init state, we can't
\r
546 if(m->state != KMM_MODULE_STATE_PREINIT) {
\r
547 _report_mr1(KHERR_WARNING, MSG_IM_NOT_PREINIT, _int32(m->state));
\r
551 if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) {
\r
552 _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED);
\r
554 m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED;
\r
558 if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Flags", &i)) &&
\r
559 (i & KMM_MODULE_FLAG_DISABLED)) {
\r
561 _report_mr0(KHERR_ERROR, MSG_IM_DISABLED);
\r
563 m->state = KMM_MODULE_STATE_FAIL_DISABLED;
\r
567 if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) {
\r
570 khm_int32 last_reason = 0;
\r
572 /* reset the failure count if the failure count reset time
\r
573 period has elapsed */
\r
575 khc_read_int64(csp_mod, L"FailureTime", &tm);
\r
576 GetSystemTimeAsFileTime((LPFILETIME) &ct);
\r
580 FtIntervalToSeconds((LPFILETIME) &ct) > fail_reset_time) {
\r
583 khc_write_int32(csp_mod, L"FailureCount", 0);
\r
584 khc_write_int64(csp_mod, L"FailureTime", 0);
\r
588 khc_read_int32(csp_mod, L"FailureReason", &last_reason);
\r
590 /* did we exceed the max failure count? However, we ignore
\r
591 the max failure count if the reason why it didn't load the
\r
592 last time was because the module wasn't found. */
\r
593 if(i > max_fail_count &&
\r
594 last_reason != KMM_MODULE_STATE_FAIL_NOT_FOUND) {
\r
595 /* failed too many times */
\r
596 _report_mr0(KHERR_ERROR, MSG_IM_MAX_FAIL);
\r
598 m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE;
\r
603 if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) ==
\r
604 KHM_ERROR_TOO_LONG) {
\r
607 m->path = PMALLOC(sz);
\r
608 khc_read_string(csp_mod, L"ImagePath", m->path, &sz);
\r
610 _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED);
\r
612 m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED;
\r
616 rv = kmmint_read_module_info(m);
\r
618 if (KHM_FAILED(rv)) {
\r
619 if (rv == KHM_ERROR_INCOMPATIBLE) {
\r
620 _report_mr0(KHERR_ERROR, MSG_IM_INCOMPATIBLE);
\r
622 m->state = KMM_MODULE_STATE_FAIL_INCOMPAT;
\r
623 } else if (rv == KHM_ERROR_NOT_FOUND) {
\r
624 _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path));
\r
626 m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND;
\r
628 _report_mr0(KHERR_ERROR, MSG_IM_INVALID_MODULE);
\r
630 m->state = KMM_MODULE_STATE_FAIL_INV_MODULE;
\r
636 if(m->state != KMM_MODULE_STATE_PREINIT) {
\r
637 _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT);
\r
642 /* from this point on, we must record any failure codes */
\r
643 record_failure = TRUE;
\r
645 hm = LoadLibrary(m->path);
\r
647 m->h_module = NULL;
\r
648 m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND;
\r
650 _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path));
\r
655 /* from this point on, we need to discard the module through
\r
657 release_module = FALSE;
\r
658 exit_module = TRUE;
\r
660 m->flags |= KMM_MODULE_FLAG_LOADED;
\r
663 /* TODO: check signatures */
\r
665 p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE);
\r
667 if(!p_init_module) {
\r
668 _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE));
\r
670 m->state = KMM_MODULE_STATE_FAIL_INVALID;
\r
674 m->state = KMM_MODULE_STATE_INIT;
\r
676 /* call init_module() */
\r
677 rv = (*p_init_module)(kmm_handle_from_module(m));
\r
679 m->flags |= KMM_MODULE_FLAG_INITP;
\r
681 if(KHM_FAILED(rv)) {
\r
682 _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv));
\r
684 m->state = KMM_MODULE_STATE_FAIL_LOAD;
\r
689 _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS);
\r
691 m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS;
\r
692 record_failure = FALSE;
\r
696 m->state = KMM_MODULE_STATE_INITPLUG;
\r
699 LPOP(&(m->plugins), &pi);
\r
701 pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST;
\r
702 kmm_init_plugin(pi);
\r
704 /* release the hold obtained in kmm_provide_plugin() */
\r
705 kmm_release_plugin(kmm_handle_from_plugin(pi));
\r
709 if(!m->plugin_count) {
\r
710 _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS);
\r
712 m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS;
\r
713 record_failure = FALSE;
\r
717 m->state = KMM_MODULE_STATE_RUNNING;
\r
719 exit_module = FALSE;
\r
720 record_failure = FALSE;
\r
722 ResetEvent(evt_exit);
\r
726 if(record_failure) {
\r
730 khc_read_int32(csp_mod, L"FailureCount", &i);
\r
732 khc_write_int32(csp_mod, L"FailureCount", i);
\r
734 if(i==1) { /* first fault */
\r
735 GetSystemTimeAsFileTime((LPFILETIME) &ct);
\r
736 khc_write_int64(csp_mod, L"FailureTime", ct);
\r
739 khc_write_int32(csp_mod, L"FailureReason", m->state);
\r
741 khc_close_space(csp_mod);
\r
745 khc_close_space(csp_mods);
\r
747 _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE,
\r
748 _dupstr(m->name), _int32(m->state));
\r
750 kmmint_remove_from_module_queue();
\r
752 /* if something went wrong after init_module was called on the
\r
753 module code, we need to call exit_module */
\r
755 kmm_exit_module(m);
\r
758 kmm_release_module(kmm_handle_from_module(m));
\r
760 if (kherr_is_error()) {
\r
762 kherr_event * err_e = NULL;
\r
763 kherr_event * warn_e = NULL;
\r
766 c = kherr_peek_context();
\r
767 err_e = kherr_get_err_event(c);
\r
768 for(e = kherr_get_first_event(c);
\r
770 e = kherr_get_next_event(e)) {
\r
772 e->severity == KHERR_WARNING) {
\r
778 kherr_evaluate_event(err_e);
\r
780 kherr_evaluate_event(warn_e);
\r
782 kherr_clear_error();
\r
784 e = kherr_report(KHERR_ERROR,
\r
785 (wchar_t *) MSG_IMERR_TITLE,
\r
789 ((warn_e)? (wchar_t *)MSG_IMERR_SUGGEST: NULL),
\r
791 KHERR_SUGGEST_NONE,
\r
793 ((warn_e)? _cstr(warn_e->long_desc):0),
\r
795 KHERR_RF_MSG_SHORT_DESC |
\r
796 ((warn_e)? KHERR_RF_MSG_SUGGEST: 0),
\r
799 kherr_evaluate_event(e);
\r
801 kherr_release_context(c);
\r
809 \brief Uninitializes a module
\r
811 \note Should only be called from the context of the registrar
\r
813 void kmm_exit_module(kmm_module_i * m) {
\r
816 /* exiting a module happens in two stages.
\r
818 If the module state is running (there are active plugins) then
\r
819 those plugins must be exited. This has to be done from the
\r
820 plugin threads. The signal for the plugins to exit must be
\r
821 issued from the registrar. Therefore, we post messages to the
\r
822 registrar for each plugin we want to remove and exit
\r
825 When the last plugin is exited, the plugin management code
\r
826 automatically signalls the registrar to remove the module.
\r
827 kmm_exit_module() gets called again. This is the second
\r
828 stage, where we call exit_module() for the module and start
\r
829 unloading everything.
\r
832 EnterCriticalSection(&cs_kmm);
\r
834 /* get rid of any dangling uninitialized plugins */
\r
835 LPOP(&(m->plugins), &p);
\r
837 p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST;
\r
838 kmm_exit_plugin(p);
\r
840 /* release hold from kmm_provide_plugin() */
\r
841 kmm_release_plugin(kmm_handle_from_plugin(p));
\r
843 LPOP(&(m->plugins), &p);
\r
846 if(m->state == KMM_MODULE_STATE_RUNNING) {
\r
849 m->state = KMM_MODULE_STATE_EXITPLUG;
\r
851 p = kmm_listed_plugins;
\r
854 if(p->module == m) {
\r
855 kmm_hold_plugin(kmm_handle_from_plugin(p));
\r
856 kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG,
\r
857 KMM_REG_EXIT_PLUGIN, (void *) p);
\r
865 /* we have to go back and wait for the plugins to exit.
\r
866 when the last plugin exits, it automatically posts
\r
867 EXIT_MODULE. We can pick up from there when this
\r
869 LeaveCriticalSection(&cs_kmm);
\r
874 if(m->flags & KMM_MODULE_FLAG_INITP)
\r
876 exit_module_t p_exit_module;
\r
879 m->state = KMM_MODULE_STATE_EXIT;
\r
882 (exit_module_t) GetProcAddress(m->h_module,
\r
884 if(p_exit_module) {
\r
885 LeaveCriticalSection(&cs_kmm);
\r
886 p_exit_module(kmm_handle_from_module(m));
\r
887 EnterCriticalSection(&cs_kmm);
\r
891 LeaveCriticalSection(&cs_kmm);
\r
894 m->state = KMM_MODULE_STATE_EXITED;
\r
897 FreeLibrary(m->h_module);
\r
900 if(m->h_resource && (m->h_resource != m->h_module)) {
\r
901 FreeLibrary(m->h_resource);
\r
904 m->h_module = NULL;
\r
905 m->h_resource = NULL;
\r
908 /* release the hold obtained in kmm_init_module() */
\r
909 kmm_release_module(kmm_handle_from_module(m));
\r