1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include "provmgr.h"
26 #include "context.h"
|
27 krisbash 1.4 #include "AggregationContext.h"
28 #include "LifecycleContext.h"
29 #include "SubMgr.h"
30 #include "nioproc.h"
|
31 mike 1.1 #include <base/log.h>
|
32 krisbash 1.4 #include <pal/strings.h>
33 #include <pal/atomic.h>
|
34 mike 1.1 #include <base/paths.h>
|
35 krisbash 1.4 #include <pal/sleep.h>
36 #include <base/class.h>
|
37 mike 1.1 #include <wql/wql.h>
|
38 krisbash 1.4 #include <wsman/wsbuf.h>
39 #include <pal/format.h>
40 #include <indication/common/indilog.h>
41 #include <indication/common/indicommon.h>
42 #include <omi_error/errorutil.h>
43 #include <provreg/provreg.h>
|
44 mike 1.1
45 #if defined(CONFIG_POSIX)
46 # include <unistd.h>
47 #endif
48
49 /* ATTN: libraryName is key (switch to module name) */
50 /* ATTN: implement module provider Unload() methods */
51 /* ATTN: implement propertySet */
52
|
53 krisbash 1.4 /* Suppress cast error from 'void*' to 'MI_Main' */
|
54 mike 1.1 #if defined(_MSC_VER)
55 # pragma warning(disable : 4055)
56 #endif
57
58 /*
59 **=============================================================================
60 **
61 ** Local defintions
62 **
63 **=============================================================================
64 */
65
66 extern MI_ContextFT __mi_contextFT;
67
68 static MI_Result MI_CALL _Server_GetVersion(MI_Uint32* version)
69 {
70 if (!version)
71 return MI_RESULT_INVALID_PARAMETER;
72
73 *version = MI_VERSION;
74 return MI_RESULT_OK;
75 mike 1.1 }
76
|
77 krisbash 1.4 static MI_Result MI_CALL _Server_GetSystemName(const ZChar** systemName)
|
78 mike 1.1 {
79 #if defined(CONFIG_OS_WINDOWS)
80 *systemName = MI_T("unknown");
81 return MI_RESULT_OK;
82 #else
83 static char buf[256];
84
85 if (buf[0] == '\0')
86 {
87 if (gethostname(buf, sizeof(buf)) != 0)
88 return MI_RESULT_FAILED;
89 }
90
|
91 krisbash 1.4 #if (MI_CHAR_TYPE == 1)
|
92 mike 1.1 *systemName = buf;
|
93 krisbash 1.4 #else
94 {
95 static ZChar wbuf[sizeof(buf)];
96 TcsStrlcpy(wbuf, buf, MI_COUNT(wbuf));
97 *systemName = wbuf;
98 }
99 #endif
100
|
101 mike 1.1 return MI_RESULT_OK;
102 #endif
103 }
104
105 #if 0
106 static MI_ServerFT _serverFT =
107 {
108 _Server_GetVersion,
109 _Server_GetSystemName,
110 };
111 #endif
112
113 typedef struct InternalFT
114 {
115 ProvMgrFT provMgrFT;
116 MI_ServerFT serverFT;
117 }
118 InternalFT;
119
120 /* warning C4054: 'type cast': from function pointer to void* */
121 #if defined(_MSC_VER)
122 mike 1.1 # pragma warning(disable : 4054)
123 #endif
124
125 static void* _FindSymbol(const char* name)
126 {
|
127 krisbash 1.4 if (strcmp(name, "OMI_GetPath") == 0)
128 return (void*)&OMI_GetPath;
|
129 mike 1.1
130 /* Not found */
131 return NULL;
132 }
133
134 static InternalFT _internalFT =
135 {
136 { PROVMGRFT_MAGIC, _FindSymbol },
137 {
138 _Server_GetVersion,
139 _Server_GetSystemName
140 },
141 };
142
143 static MI_Server _server =
144 {
145 &_internalFT.serverFT,
146 &__mi_contextFT,
147 &__mi_instanceFT,
148 NULL, /* MI_PropertySetFT */
149 NULL, /* MI_FilterFT */
150 mike 1.1 };
151
|
152 krisbash 1.4 /*
153 * Try to find specific library and open it if not found,
154 * this function is not thread-safely operate the library list
155 */
156 static Library* MI_CALL _OpenLibraryInternal(
|
157 mike 1.1 ProvMgr* self,
|
158 krisbash 1.4 _In_ const ProvRegEntry* proventry)
|
159 mike 1.1 {
160 Library* p;
161
162 /* Search cache first */
163 for (p = self->head; p; p = p->next)
164 {
|
165 krisbash 1.4 if (strcmp(p->libraryName, proventry->libraryName) == 0)
|
166 mike 1.1 {
167 return p;
168 }
169 }
170
171 /* Allocate new libray object */
|
172 krisbash 1.4 p = (Library*)PAL_Calloc(1, sizeof(Library));
|
173 mike 1.1
174 if (!p)
175 return NULL;
176
177 /* Library.refs */
178 p->provmgr = self;
179 /* Open the library */
180 {
|
181 krisbash 1.4 TChar path[PAL_MAX_PATH_SIZE];
182 path[0] = '\0';
183 Shlib_Format(path, self->providerDir, proventry->libraryName);
184 p->handle = Shlib_Open(path);
|
185 mike 1.1
186 if (!p->handle)
187 {
|
188 krisbash 1.4 TChar Tpath[PAL_MAX_PATH_SIZE];
189
190 if (TcsStrlcpy(Tpath, proventry->libraryName, PAL_MAX_PATH_SIZE) >= PAL_MAX_PATH_SIZE)
191 {
192 trace_SharedLib_CannotOpen(scs(proventry->libraryName));
193 PAL_Free(p);
194 return NULL;
195 }
196
197 trace_SharedLib_CannotOpenFirstTry(tcs(path), tcs(Shlib_Err()));
198
199 // here we are ignoring error from Shlib_Open on first attempt
200 NitsIgnoringError();
201
202 /* Try again */
203
204 p->handle = Shlib_Open(Tpath);
|
205 mike 1.1
|
206 krisbash 1.4 if (!p->handle)
207 {
208 trace_SharedLib_CannotOpenSecondTry(scs(proventry->libraryName), tcs(Shlib_Err()));
209 PAL_Free(p);
210 return NULL;
211 }
|
212 mike 1.1 }
213 }
214
215 /* Lib_Open.libraryName */
|
216 krisbash 1.4 Strlcpy(p->libraryName, proventry->libraryName, sizeof(p->libraryName));
217 p->instanceLifetimeContext = proventry->instanceLifetimeContext;
|
218 mike 1.1
219 /* Invoke MI_Main() entry point */
220 {
|
221 krisbash 1.4 MI_MainFunction statikMain;
|
222 mike 1.1
223 /* Lookup symbol */
224 {
|
225 krisbash 1.4 void* ptr = Shlib_Sym(p->handle, "MI_Main");
|
226 mike 1.1
|
227 krisbash 1.4 statikMain = (MI_MainFunction)ptr;
|
228 mike 1.1
229 if (!statikMain)
230 {
|
231 krisbash 1.4 PAL_Free(p);
232 trace_SharedLibrary_CannotFindSymbol(scs(proventry->libraryName), scs("MI_Main"));
|
233 mike 1.1 return NULL;
234 }
235 }
236
237 /* Call MI_Main */
238 {
239 p->module = (*statikMain)(&_server);
|
240 krisbash 1.4 if (!p->module)
241 {
242 PAL_Free(p);
243 trace_Provmgr_NullModulePointer(scs(proventry->libraryName), scs("MI_Main"));
244 return NULL;
245 }
246 if (p->module->version > MI_VERSION)
247 {
248 MI_Uint32 v = p->module->version;
249 PAL_Free(p);
250 trace_Provmgr_FailedToLoadProvider(scs(proventry->libraryName), MI_VERSION_GET_MAJOR(v), MI_VERSION_GET_MINOR(v), MI_VERSION_GET_REVISION(v), MI_MAJOR, MI_MINOR, MI_REVISION);
251 return NULL;
252 }
|
253 mike 1.1 }
254 }
255
256 /* Invoke the module initialize function */
257 if (p->module->Load)
258 {
259 Context ctx;
|
260 krisbash 1.4 MI_Result r = MI_RESULT_OK;
261
262 Context_Init(&ctx, NULL, NULL);
263 ctx.result = &r;
264
|
265 mike 1.1 (p->module->Load)(&p->self, (MI_Context*)&ctx);
|
266 krisbash 1.4
267 if (ctx.magic != 0xFFFFFFFF)
268 {
269 trace_ModuleLoad_FailedPostResult();
270 }
271
272 if (MI_RESULT_OK != r)
273 {
274 trace_FailedCallModuleLoad(r, scs(proventry->libraryName));
275 return NULL;
276 }
|
277 mike 1.1 }
278
|
279 krisbash 1.4 Lock_Init( &p->provlock );
280
|
281 mike 1.1 /* Add library to the list */
282 List_Prepend(
283 (ListElem**)&self->head,
284 (ListElem**)&self->tail,
285 (ListElem*)p);
286
287 return p;
288 }
289
|
290 krisbash 1.4 /*
291 * Try to find specific library and open it if not found,
292 * this function ensure thread-safe use of the library list
293 */
294 static Library* MI_CALL _OpenLibrary(
295 ProvMgr* self,
296 _In_ const ProvRegEntry* proventry)
297 {
298 Library* lib;
299 Lock_Acquire( & self->liblock );
300 lib = _OpenLibraryInternal( self, proventry );
301 Lock_Release( & self->liblock );
302 return lib;
303 }
304
305 /*
306 * Try to find specific provider (class) and open it if not found,
307 * this function is NOT thread-safe
308 */
309 static Provider* MI_CALL _OpenProviderInternal(
|
310 mike 1.1 Library* self,
|
311 krisbash 1.4 const ZChar* className,
312 Message* request)
|
313 mike 1.1 {
314 Provider* p;
|
315 krisbash 1.4 size_t psize = sizeof(Provider);
|
316 mike 1.1
317 /* Search cache first */
318 for (p = self->head; p; p = p->next)
319 {
|
320 krisbash 1.4 if (Tcscasecmp(p->classDecl->name, className) == 0)
|
321 mike 1.1 {
|
322 krisbash 1.4 Provider_Addref(p);
|
323 mike 1.1 return p;
324 }
325 }
326
|
327 krisbash 1.4 #ifndef DISABLE_INDICATION
328 /* Allocate SubscriptionManager along with Provider */
329 psize += sizeof( SubscriptionManager );
330 #endif
331
|
332 mike 1.1 /* New Provider */
|
333 krisbash 1.4 p = (Provider*)PAL_Calloc(1, psize);
|
334 mike 1.1
335 if (!p)
336 {
|
337 krisbash 1.4 LOGD_ALLOC_OOM;
|
338 mike 1.1 return NULL;
339 }
340
341 /* Provider.refs */
342 p->refCounter = 1;
343 p->lib = self;
344
345 /* Provider.classDecl */
346 {
347 p->classDecl = SchemaDecl_FindClassDecl(self->module->schemaDecl,
348 className);
349
|
350 krisbash 1.4 if (!p->classDecl || (request->tag != GetClassReqTag && !p->classDecl->providerFT))
|
351 mike 1.1 {
|
352 krisbash 1.4 PAL_Free(p);
|
353 mike 1.1 return NULL;
354 }
355 }
356
|
357 krisbash 1.4 #ifndef DISABLE_INDICATION
358 /*
359 * Following picture explains memory layout of provider,
360 * provider and submgr are sitting side by side, while
361 * provider.submgr sets to the submgr's memory address
362 *
363 * |---------|
364 * | Provider|
365 * | ... |
366 * | submgr* |---|
367 * |---------|<--|
368 * | submgr |
369 * | |
370 * |---------|
371 */
372 p->subMgr = (SubscriptionManager*)(p + 1);
373 SubMgr_Init(p->subMgr, p);
374 #endif
|
375 mike 1.1
|
376 krisbash 1.4 if(p->classDecl->providerFT)
|
377 mike 1.1 {
|
378 krisbash 1.4 /* Call provider Load() method */
379 if (p->classDecl->providerFT->Load)
380 {
381 Context ctx;
382 MI_Result r = MI_RESULT_OK;
|
383 mike 1.1
|
384 krisbash 1.4 Context_Init(&ctx, p, NULL);
385 ctx.result = &r;
386 ctx.loadRequest = request;
387 Message_AddRef(ctx.loadRequest);
|
388 mike 1.1
|
389 krisbash 1.4 (*p->classDecl->providerFT->Load)(&p->self, self->self, &ctx.base);
|
390 mike 1.1
|
391 krisbash 1.4 if (ctx.magic != 0xFFFFFFFF)
392 {
393 trace_ProviderLoad_DidnotPostResult();
394 }
|
395 mike 1.1
|
396 krisbash 1.4 if (MI_RESULT_OK != r)
397 {
398 trace_FailedProviderLoad(r, tcs(className));
399 PAL_Free(p);
400 return NULL;
401 }
|
402 mike 1.1 }
403 }
404
405 /* Prepend to list */
406 List_Prepend(
407 (ListElem**)&self->head,
408 (ListElem**)&self->tail,
409 (ListElem*)p);
410
411 return p;
412 }
413
|
414 krisbash 1.4 /*
415 * Try to find specific provider (class) and open it if not found,
416 * this function is thread-safely operate the provider list
417 */
418 static Provider* MI_CALL _OpenProvider(
419 Library* self,
420 const ZChar* className,
421 Message* request)
422 {
423 Provider* prov;
424 Lock_Acquire( & self->provlock );
425 prov = _OpenProviderInternal( self, className, request );
426 Lock_Release( & self->provlock );
427 return prov;
428 }
429
430 static MI_Result MI_CALL _GetProviderByClassName(
431 _In_ ProvMgr* self,
432 _In_ const ProvRegEntry* proventry,
433 _In_ MI_ConstString cn,
434 _In_ Message* request,
435 krisbash 1.4 _Out_ Provider** provOut)
|
436 mike 1.1 {
437 Library* lib;
438 Provider* prov;
439
|
440 krisbash 1.4 trace_GetProviderByClassName(tcs(cn));
441
|
442 mike 1.1 /* Open the library */
443 {
|
444 krisbash 1.4 lib = _OpenLibrary(self, proventry);
|
445 mike 1.1
446 if (!lib)
447 {
|
448 krisbash 1.4 trace_OpenProviderLib_Failed(scs(proventry->libraryName));
|
449 mike 1.1 return MI_RESULT_FAILED;
450 }
451 }
452
453 /* Open the provider */
454 {
|
455 krisbash 1.4 prov = _OpenProvider(lib, cn, request);
|
456 mike 1.1
457 if (!prov)
458 {
|
459 krisbash 1.4 trace_OpenProvider_FailedForClass(proventry->libraryName, tcs(cn));
|
460 mike 1.1 return MI_RESULT_FAILED;
461 }
462 }
463
464 *provOut = prov;
465 return MI_RESULT_OK;
466 }
467
468 static MI_Result _Instance_InitConvert_FromBatch(
469 Batch* batch,
470 const MI_ClassDecl* cd,
471 const MI_SchemaDecl* sd,
472 MI_Instance* inst_in,
473 MI_Boolean keys_only,
474 MI_Boolean allow_keyless_inst,
|
475 krisbash 1.4 MI_Instance** instOut,
476 MI_Uint32 flags
|
477 mike 1.1 )
478 {
479 MI_Instance* inst;
480 MI_Result r;
481
482 MI_UNUSED(sd);
483
484 /* Allocate the instance for the provider */
485 inst = (MI_Instance*)Batch_GetClear(batch, cd->size);
486
487 if (!inst)
488 {
|
489 krisbash 1.4 trace_ProvMgr_AllocFailed();
|
490 mike 1.1 return MI_RESULT_FAILED;
491 }
492
|
493 krisbash 1.4 /* Convert instance name to provider's format (borrow storage) */
494 r = Instance_InitConvert(inst, cd, inst_in, keys_only, allow_keyless_inst, MI_FALSE,
495 batch, flags);
496
497 if (r != MI_RESULT_OK)
498 {
499 trace_InstanceConversionFailed(tcs(cd->name), r);
500 return r;
501 }
502
503 *instOut = inst;
504 return MI_RESULT_OK;
505 }
506
507 #ifndef DISABLE_INDICATION
508
509 /*
510 * Internal helper function for _Provider_InvokeSubscribe that expects all
511 * validation to be done beforehand.
512 */
513 MI_Result _Provider_InvokeEnable(
514 krisbash 1.4 _Inout_ Provider* provider,
515 _In_ SubscribeReq* msg )
516 {
517 SubscriptionManager* subMgr = provider->subMgr;
518 AggregationContext* aggrContext;
519
520 trace_EnablingIndicationsForClass(provider->classDecl->name, provider);
521
522 aggrContext = SubMgr_CreateAggrContext( subMgr );
523 if ( !aggrContext )
524 {
525 trace_AggregationContext_InitFailed();
526 return MI_RESULT_SERVER_LIMITS_EXCEEDED;
527 }
528
529 /*
530 * Set enabled to true, which will be set to false if
531 * posting result during EnableIndications call
532 *
533 */
534 SubMgr_SetEnabled( subMgr, MI_TRUE );
535 krisbash 1.4
536 (*provider->classDecl->providerFT->EnableIndications)(
537 provider->self,
538 &aggrContext->baseCtx.base,
539 msg->nameSpace,
540 msg->className);
541
542 if ( MI_FALSE == SubMgr_IsEnabled(subMgr) )
543 {
544 /*
545 * provider posted a final result during EnableIndications call,
546 * Clean up already occurred during Post handling, return here
547 *
548 */
549 trace_ProviderEnableIndication_Failed();
550 return MI_RESULT_FAILED;
551 }
552
553 return MI_RESULT_OK;
554 }
555
556 krisbash 1.4 /*
557 * Internal helper function for _Provider_RemoveSubscription that expects all
558 * validation to be done beforehand.
559 */
560 _Use_decl_annotations_
561 MI_Result Provider_InvokeDisable(
562 Provider* provider)
563 {
564 MI_Result result = MI_RESULT_OK;
565 SubscriptionManager* subMgr;
566 MI_Boolean locked;
567
568 DEBUG_ASSERT( provider );
569
570 subMgr = provider->subMgr;
571
572 trace_Provider_InvokeDisable_Start( UintThreadID(), provider->classDecl->name, provider);
573
574 locked = SubMgr_AcquireEnableLock( subMgr, AcquireFromDisable );
575
576 if ( MI_TRUE == locked )
577 krisbash 1.4 {
578 MI_Boolean wasEnabled = MI_FALSE;
579 if ( MI_TRUE == SubMgr_IsEnabled(subMgr) )
580 {
581 wasEnabled = MI_TRUE;
582 SubMgr_SetEnabled(subMgr, MI_FALSE);
583 }
584
585 if ( provider->classDecl->flags & MI_FLAG_INDICATION )
586 {
587 AggregationContext* aggrContext = SubMgr_RemoveAggrContext( subMgr );
588
589 if ( MI_FALSE == SubMgr_IsTerminating( subMgr ) )
590 {
591 DEBUG_ASSERT( (MI_TRUE == wasEnabled) ? (NULL != aggrContext) : (NULL == aggrContext) );
592
593 if ( aggrContext && ( MI_TRUE == wasEnabled ) )
594 {
595 provider->classDecl->providerFT->DisableIndications(
596 provider->self,
597 &aggrContext->baseCtx.base,
598 krisbash 1.4 NULL, // TODO: Set this based on the initial SubscribeReq, but copy the value so its lifetime matches the context
599 provider->classDecl->name );
600 }
601 }
602 // else don't need to invoke DisableIndications
603
604 if ( aggrContext )
605 AggrContext_Delete( aggrContext );
606 }
607 else
608 {
609 // TODO: release lifecycle context
610 }
611 }
612 else
613 {
614 /* active subscription(s) added right before acquire the lock */
615 trace_Provider_InvokeDisable_AbandonSinceNewSubscriptionAdded( UintThreadID(), provider->classDecl->name, provider);
616 return MI_RESULT_OK;
617 }
618
619 krisbash 1.4 /*
620 * Disabled the provider, reset flags,
621 * new subscribe request will success.
622 */
623 SubMgr_SetTerminating( subMgr, MI_FALSE );
624 SubMgr_SetAllCancelledSafe( subMgr, MI_FALSE );
625 SubMgr_ReleaseEnableLock( subMgr );
626
627 trace_Provider_InvokeDisable_Complete( UintThreadID(), provider->classDecl->name, provider);
628 return result;
629 }
630
631 void _Provider_SubscribeFail(
632 _In_ SubscriptionContext* subscrContext,
633 _In_ SubscribeReq* msg,
634 _In_ MI_Result result )
635 {
636 // TODO: Replace this whole func with Cancel and propagate the result to the subscription context
637 PostResultMsg* finalmsg = PostResultMsg_NewAndSerialize(&msg->base.base, NULL, NULL, MI_RESULT_TYPE_MI, result);
638 if (finalmsg)
639 {
640 krisbash 1.4 Strand_SchedulePost(&subscrContext->baseCtx.strand,&finalmsg->base);
641 PostResultMsg_Release(finalmsg);
642 /*
643 * subscribe failed and directly send final result to left side strand,
644 * thus context.c:Context_PostMessageLeft won't be called,
645 * so release the ref count added by SubscriptionContext.c:SubscrContext_Init
646 */
647 SubMgrSubscription_Release( subscrContext->subscription );
648 }
649 else
|
650 mike 1.2 {
|
651 krisbash 1.4 trace_OutOfMemory();
652 Strand_ScheduleCancel(&subscrContext->baseCtx.strand);
653 }
654 }
655
656 _Use_decl_annotations_
657 void Provider_InvokeSubscribe(
658 Provider* provider,
659 SubscribeReq* msg,
660 SubscriptionContext* subscrContext )
661 {
662 MI_Result result = MI_RESULT_OK;
663 SubscriptionManager* subMgr;
664 MI_Boolean locked;
665 SubscriptionTargetType subType;
666 SubMgrSubscription* subscription = NULL;
667
668 DEBUG_ASSERT ( provider && subscrContext );
669 DEBUG_ASSERT( provider->subMgr );
670 STRAND_ASSERTONSTRAND(&subscrContext->baseCtx.strand);
671
672 krisbash 1.4 if( subscrContext->baseCtx.strand.canceled )
673 {
674 // abort creating subscription
675 Strand_Leave( &subscrContext->baseCtx.strand );
676 return;
|
677 mike 1.2 }
|
678 krisbash 1.4
679 subMgr = provider->subMgr;
680 subType = (SubscriptionTargetType)msg->targetType;
681
682 do
683 {
684 trace_ProviderInvokeSubscribe_Begin(UintThreadID(), provider, msg, msg->base.base.tag, subscrContext );
685
686 /* To ensure enable/cancel thread safe */
687 locked = SubMgr_AcquireEnableLock( subMgr, AcquireFromSubscribe );
688 if ( MI_FALSE == locked )
689 {
690 result = MI_RESULT_FAILED;
691 Strand_Leave( &subscrContext->baseCtx.strand );
692 break;
693 }
694
695 /*
696 * Sanity checks of the request prior to initializing the context and
697 * completing the interaction open.
698 *
699 krisbash 1.4 * These checks can return immediate failure without clean up
700 */
701 if (SUBSCRIP_TARGET_DEFAULT == subType )
702 {
703 /*
704 * if class is not indication class, then indication manager has a bug
705 */
706 DEBUG_ASSERT (provider->classDecl->flags & MI_FLAG_INDICATION);
707 /*
708 * if classdecl is not valid, then omireg tool has a bug
709 */
710 DEBUG_ASSERT (
711 provider->classDecl->providerFT->EnableIndications &&
712 provider->classDecl->providerFT->Subscribe);
713 }
714 else if (SubscriptionTargetType_IsLifecycle( subType ))
715 {
716 // lifecycleCtx should have been initialized during provider Load().
717 if ( ! subMgr->lifecycleCtx )
718 {
719 trace_LifecycleSubscription_ContextNotInitialized(provider->classDecl->name);
720 krisbash 1.4 result = MI_RESULT_FAILED;
721 break;
722 }
723
724 if ( ! LifeContext_IsTypeSupported(subMgr->lifecycleCtx, msg->targetType) )
725 {
726 trace_LifecycleSubscription_UnsupportedTargetType(
727 provider->classDecl->name, msg->targetType, subMgr->lifecycleCtx->supportedTypesFromProv);
728 result = MI_RESULT_NOT_SUPPORTED;
729 Strand_Leave( &subscrContext->baseCtx.strand );
730 break;
731 }
732 }
733 else
734 {
735 trace_InvokeSubscribeWithInvalidTargetType( subType );
736 result = MI_RESULT_FAILED;
737 Strand_Leave( &subscrContext->baseCtx.strand );
738 break;
739 }
740
741 krisbash 1.4 subscription = subscrContext->subscription;
742 SubscriptionList_AddSubscription( &subMgr->subscrList, subscription );
743
744 /*
745 * Upon SubscriptionContext was initialized successfull,
746 * it hold one refcount of msg, which will be released
747 * inside _Context_Destory;
748 *
749 * SubscriptionContext was initialized successfully,
750 * following logic should report error through
751 * interaction interface then.
752 */
753
754 /*
755 * Acquire post lock, so post indication and result from provider's thread
756 * will be blocked until Enable/Subscribe call finished
757 *
758 */
759 SubMgrSubscription_Addref( subscription );
760 SubMgrSubscription_AcuquirePostLock( subscription );
761
762 krisbash 1.4 /* Alert indication setup */
763 if (SUBSCRIP_TARGET_DEFAULT == msg->targetType )
764 {
765 SubMgr_SetEnableThread( subMgr );
766
767 Strand_Leave( &subscrContext->baseCtx.strand );
768 /*
769 * EnableIndications must be called for each provider
770 * prior to the first Subscribe call for alert indication
771 */
772 if ( MI_FALSE == SubMgr_IsEnabled( subMgr ) )
773 {
774 result = _Provider_InvokeEnable( provider, msg );
775 if (MI_RESULT_OK != result)
776 {
777 trace_EnableIndication_Failed(provider->classDecl->name);
778 result = MI_RESULT_OK;
779 break;
780 }
781 }
782
783 krisbash 1.4 DEBUG_ASSERT (SubMgr_IsEnabled( subMgr ));
784
785 SubMgrSubscription_SetState(subscription, SubscriptionState_Subscribed);
786
787 /*
788 * Invoke Subscribe with dummpy context
789 * provider cannot postinstance or indication to this context
790 */
791 {
792 Context ctx;
793 MI_Result r = MI_RESULT_OK;
794 Subunsub_Context_Init(&ctx, &r, &msg->base);
795 (*provider->classDecl->providerFT->Subscribe)(
796 provider->self,
797 &ctx.base,
798 msg->nameSpace,
799 msg->className,
800 &subscrContext->subscription->filter->base,
801 msg->bookmark,
802 msg->subscriptionID,
803 (void**)&subscrContext->subself);
804 krisbash 1.4 Context_Close(&ctx);
805 }
806
807 if (SubscriptionState_Subscribed == subscrContext->subscription->state)
808 {
809 trace_Provider_InvokeSubscribe(subscrContext->subscription);
810
811 /*
812 * Subscribe succeeded, send subscribe response,
813 * otherwise finalresult already sent within Subscribe call
814 */
815 SubscrContext_SendSubscribeResponseMsg( subscrContext );
816
817 #if defined(_MSC_VER)
818 trace_SubscrForEvents_Succeeded_MSC(provider->classDecl->name, msg->subscriptionID);
819 #else
820 trace_SubscrForEvents_Succeeded(provider->classDecl->name, msg->subscriptionID);
|
821 mike 1.2 #endif
|
822 krisbash 1.4 result = MI_RESULT_OK;
823 break;
824 }
825 }
826 /*
827 * Lifecycle indication setup
828 */
829 else if (SubscriptionTargetType_IsLifecycle( (SubscriptionTargetType)msg->targetType ))
830 {
831 if ( MI_FALSE == SubMgr_IsEnabled( subMgr ) )
832 SubMgr_SetEnabled( subMgr, MI_TRUE );
833
834 SubMgrSubscription_SetState( subscrContext->subscription, SubscriptionState_Subscribed );
835
836 LifeContext_UpdateSupportedTypes( subMgr->lifecycleCtx );
837
838 Strand_Leave( &subscrContext->baseCtx.strand );
839 SubscrContext_SendSubscribeResponseMsg( subscrContext );
840
841 #if defined(_MSC_VER)
842 trace_SubscrForLifecycle_Succeeded_MSC(provider->classDecl->name, msg->subscriptionID);
843 krisbash 1.4 #else
844 trace_SubscrForLifecycle_Succeeded(provider->classDecl->name, msg->subscriptionID);
845 #endif
846 result = MI_RESULT_OK;
847 break;
848 }
849 }
850 while( 0 );
851
852 if ( subscription )
853 {
854 /*
855 * Release post lock, so indication and result
856 * posted from provider will go through
857 */
858 SubMgrSubscription_ReleasePostLock( subscription );
859 SubMgrSubscription_Release( subscription );
860 }
861
862 /*
863 * Now release lock to allow Disable/other subscribe reqeuest to conitune
864 krisbash 1.4 */
865 if ( MI_TRUE == locked )
866 SubMgr_ReleaseEnableLock( subMgr );
867
868 trace_ProviderInvokeSubscribe_End(UintThreadID(), provider, result);
869
870 /*
871 * Once the SubscrContext has been initialized, the interactions is "Open"
872 * and must be shut down using the appropriate Strand calls. Those calls
873 * will handle clean up. This must return MI_RESULT_OK for that to happen.
874 */
875 if ( result != MI_RESULT_OK )
876 {
877 _Provider_SubscribeFail( subscrContext, msg, result );
878 }
879 }
880
881 /*
882 * Invoke EnableIndication if not called yet;
883 * and invoke Subscribe call to provider;
884 *
885 krisbash 1.4 * To ensure enable/disable thread-safe, and since
886 * OMI has single IO thread, this function has to be scheduled
887 * on separate thread for OMI.
888 * TODO: remove separate thread if have multi-IO threads implemented
889 */
890 MI_Result _Provider_InvokeSubscribeWrapper(
891 _In_ Provider* provider,
892 _Inout_ InteractionOpenParams* interactionParams )
893 {
894 SubscriptionContext* subscrContext;
895 MI_Result result;
896
897 result = SubMgr_CreateSubscription( provider->subMgr, provider, interactionParams, &subscrContext );
898 if ( MI_RESULT_OK != result )
899 {
900 trace_FailedToAddSubscrMgr();
901 return result;
902 }
903
904 //#if defined(_MSC_VER)
905 // Strand_ScheduleAux( &(subscrContext->baseCtx.strand), CONTEXT_STRANDAUX_INVOKESUBSCRIBE );
906 krisbash 1.4 //#else
907 result = Schedule_SubscribeRequest( provider, (SubscribeReq*)interactionParams->msg, subscrContext );
908 if( MI_RESULT_OK != result )
909 {
910 _Provider_SubscribeFail( subscrContext, (SubscribeReq*)interactionParams->msg, result );
911 /*
912 * schedule failed so CONTEXT_STRANDAUX_INVOKESUBSCRIBE won't be called,
913 * so release the ref count added by _SubMgrSubscription_New
914 */
915 SubMgrSubscription_Release( subscrContext->subscription );
916 }
917 //#endif
|
918 mike 1.2
|
919 krisbash 1.4 return MI_RESULT_OK;
920 }
921
922 _Use_decl_annotations_
923 MI_Result Provider_RemoveSubscription(
924 Provider* provider,
925 MI_Uint64 subscriptionID)
926 {
927 SubMgrSubscription* subscription = NULL;
928 SubscriptionManager* subMgr;
929 MI_Result result = MI_RESULT_OK;
930
931 DEBUG_ASSERT (provider && provider->subMgr);
932 subMgr = provider->subMgr;
933
934 #if defined(_MSC_VER)
935 trace_RemovingSubscriptionForClass_MSC(subscriptionID, provider->classDecl->name);
936 #else
937 trace_RemovingSubscriptionForClass(subscriptionID, provider->classDecl->name);
938 #endif
939
940 krisbash 1.4 subscription = SubMgr_GetSubscription( subMgr, subscriptionID );
941 if (NULL == subscription)
942 {
943 /* Not present or not found means that there is nothing to do. */
944 return MI_RESULT_OK;
945 }
946
947 SubMgrSubscription_SetState(subscription, SubscriptionState_Unsubscribed);
948
949 result = SubMgr_DeleteSubscription( subMgr, subscription);
|
950 mike 1.1
|
951 krisbash 1.4 /* check if the subscription list was empty or not */
952 if ( MI_TRUE == SubMgr_IsSubListEmpty( subMgr ) )
|
953 mike 1.1 {
|
954 krisbash 1.4 /*
955 * The specified subscription is the LAST one for its
956 * SubscriptionManager. Indications should be disabled for this
957 * provider. There is separate cleanup for Lifecycle and "normal"
958 * indications. SubscriptionManager will be cleaned up once the
959 * provider processes the Disable call.
960 */
961 result = Provider_InvokeDisable ( provider );
|
962 mike 1.1 }
963
|
964 krisbash 1.4 return result;
965 }
966
967 _Use_decl_annotations_
968 MI_Result Provider_TerminateIndication(
969 Provider* provider,
970 MI_Result result,
971 const ZChar* errorMessage,
972 const MI_Instance* cimError )
973 {
974 SubscriptionManager* subMgr;
975 MI_Boolean locked;
976 DEBUG_ASSERT (provider && provider->subMgr);
977
978 trace_Provider_TerminateIndication_Start( UintThreadID(), provider->classDecl->name, provider);
979
980 Provider_Addref( provider );
981
982 subMgr = provider->subMgr;
983
984 /*
985 krisbash 1.4 * SubMgr_AcquireEnableLock cancel all subscriptions if have any,
986 * internally it call Provider_InvokeDisable if no subscription;
987 * otherwise just return;
988 * Provider_InvokeDisable releases the aggregation context;
989 */
990 locked = SubMgr_AcquireEnableLock( subMgr, AcquireFromTerminate );
991 DEBUG_ASSERT( MI_TRUE == locked );
992 SubMgr_ReleaseEnableLock( subMgr );
993
994 trace_Provider_TerminateIndication_Complete( UintThreadID(), provider->classDecl->name, provider);
995
996 Provider_Release( provider );
997
|
998 mike 1.1 return MI_RESULT_OK;
999 }
1000
|
1001 krisbash 1.4 #endif /* ifndef DISABLE_INDICATION */
1002
|
1003 mike 1.1 static MI_Result _HandleGetInstanceReq(
|
1004 krisbash 1.4 _In_ ProvMgr* self,
1005 _In_ const ProvRegEntry* proventry,
1006 _Inout_ InteractionOpenParams* interactionParams,
1007 _Out_ Provider** prov)
|
1008 mike 1.1 {
1009 MI_Instance* inst;
1010 MI_Result r;
|
1011 krisbash 1.4 const ZChar* className;
1012 GetInstanceReq* msg = (GetInstanceReq*)interactionParams->msg;
|
1013 mike 1.1
1014 /* Get classname from instance */
1015 r = __MI_Instance_GetClassName(msg->instanceName, &className);
1016
1017 if (r != MI_RESULT_OK)
1018 return r;
1019
1020 /* find provider */
|
1021 krisbash 1.4 r = _GetProviderByClassName(
1022 self,
1023 proventry,
1024 className,
1025 &msg->base.base,
1026 prov);
|
1027 mike 1.1
1028 if ( MI_RESULT_OK != r )
1029 return r;
1030
1031 /* Allocate the instance for the provider */
1032 r = _Instance_InitConvert_FromBatch(
|
1033 krisbash 1.4 msg->base.base.batch,
|
1034 mike 1.1 (*prov)->classDecl,
1035 (*prov)->lib->module->schemaDecl,
1036 msg->instanceName,
1037 MI_TRUE,
1038 MI_FALSE,
|
1039 krisbash 1.4 &inst,
1040 msg->base.base.flags);
|
1041 mike 1.1
1042 if (MI_RESULT_OK != r)
1043 return r;
1044
1045 #if 0
1046 /* Print instance */
|
1047 krisbash 1.4 Instance_Print(inst, stdout, 0, MI_FALSE, MI_FALSE);
|
1048 mike 1.1 #endif
1049
1050 /* If provider's GetInstance method null, use EnumerateInstances */
1051 if ((*prov)->classDecl->providerFT->GetInstance == NULL)
1052 {
1053 Context* ctx;
1054
1055 if ((*prov)->classDecl->providerFT->EnumerateInstances == NULL)
1056 return MI_RESULT_INVALID_CLASS;
1057
1058 /* Create context */
|
1059 krisbash 1.4 ctx = (Context*)Batch_GetClear(msg->base.base.batch, sizeof(Context));;
1060 r = Context_Init(ctx, (*prov), interactionParams);
1061 if( MI_RESULT_OK != r )
1062 return r;
|
1063 mike 1.1
1064 /* _PostInstance() filters by this if not null */
1065 ctx->instanceName = inst;
1066
1067 /* Invoke provider */
1068 (*(*prov)->classDecl->providerFT->EnumerateInstances)(
1069 (*prov)->self,
1070 &ctx->base,
1071 msg->nameSpace,
1072 className,
1073 NULL, /* propertSet */
1074 MI_FALSE, /* keysOnly */
1075 NULL); /* filter */
1076 }
1077 else
1078 {
1079 Context* ctx;
1080
1081 /* Create context */
|
1082 krisbash 1.4 ctx = (Context*)Batch_GetClear(msg->base.base.batch, sizeof(Context));;
1083 r = Context_Init(ctx, (*prov), interactionParams);
1084 if( MI_RESULT_OK != r )
1085 return r;
|
1086 mike 1.1
1087 /* Invoke provider */
1088 (*(*prov)->classDecl->providerFT->GetInstance)(
1089 (*prov)->self,
1090 &ctx->base,
1091 msg->nameSpace,
1092 className,
1093 inst,
1094 NULL);
1095 }
1096
1097 return MI_RESULT_OK;
1098 }
1099
|
1100 krisbash 1.4 static void _PostClassToCallback(
1101 Context* self,
1102 InteractionOpenParams* params,
1103 const MI_Class* schema)
1104 {
1105 MI_Result result = MI_RESULT_OK;
1106 PostSchemaMsg* resp = PostSchemaMsg_New(self->request->base.operationId);
1107
1108 if (!resp)
1109 {
1110 trace_PostSchemaMsg_Failed();
1111 result = MI_RESULT_FAILED;
1112 goto End;
1113 }
1114
1115 if (self->request->base.flags & WSMANFlag)
1116 {
1117 result = WSBuf_ClassToBuf(
1118 schema,
1119 self->request->base.flags,
1120 resp->base.batch,
1121 krisbash 1.4 &resp->packedSchemaWsmanPtr,
1122 &resp->packedSchemaWsmanSize);
1123
1124 trace_ProvMgr_PostingSchemaInWsmanToCallback();
1125
1126 if(result != MI_RESULT_OK)
1127 {
1128 trace_SchemaConversion_ToCimXmlFailed(result);
1129 goto End;
1130 }
1131
1132 resp->base.flags |= self->request->base.flags;
1133 }
1134 else
1135 {
1136 result = Instance_New(&resp->schemaInstance, schema->classDecl, resp->base.batch);
1137 if (result != MI_RESULT_OK)
1138 {
1139 trace_SchemaConversion_ToInstanceFailed(result);
1140 goto End;
1141 }
1142 krisbash 1.4
1143 result = InstanceToBatch(
1144 resp->schemaInstance,
1145 NULL,
1146 NULL,
1147 resp->base.batch,
1148 &resp->packedSchemaInstancePtr,
1149 &resp->packedSchemaInstanceSize);
1150 if (result != MI_RESULT_OK)
1151 {
1152 trace_SchemaInstancePackaging_Failed(result);
1153 goto End;
1154 }
1155
1156 resp->base.flags |= BinaryProtocolFlag;
1157 }
1158
1159 Context_CompleteOpen( self, params, MI_RESULT_OK );
1160 Context_PostSchema( self, &resp->base);
1161 {
1162 PostResultMsg* msg = PostResultMsg_New( self->request->base.operationId );
1163 krisbash 1.4 if (msg)
1164 {
1165 Context_PostMessageLeft( self, &msg->base );
1166 PostResultMsg_Release( msg );
1167 }
1168 }
1169
1170 Strand_ScheduleClose(&self->strand);
1171 End:
1172 if(resp)
1173 {
1174 PostSchemaMsg_Release(resp);
1175 }
1176
1177 if( MI_RESULT_OK != result )
1178 {
1179 Context_CompleteOpen( self, params, result );
1180 }
1181 }
1182
1183
1184 krisbash 1.4 static MI_Result _HandleGetClassReq(
1185 _In_ ProvMgr* self,
1186 _In_ const ProvRegEntry* proventry,
1187 _Inout_ InteractionOpenParams* interactionParams,
1188 _Out_ Provider** prov)
1189 {
1190 MI_Result r;
1191 MI_Class resultClass;
1192 Context* ctx = NULL;
1193 GetClassReq* msg = (GetClassReq*)interactionParams->msg;
1194
1195 trace_ProvMgr_GetClassReq(tcs(msg->className), tcs(msg->nameSpace));
1196
1197 memset(&resultClass, 0, sizeof(MI_Class));
1198
1199 /* find provider */
1200 r = _GetProviderByClassName(
1201 self,
1202 proventry,
1203 msg->className,
1204 &msg->base.base,
1205 krisbash 1.4 prov);
1206
1207 if ( MI_RESULT_OK != r )
1208 return r;
1209
1210 ctx = (Context*)Batch_GetClear(msg->base.base.batch,
1211 sizeof(Context));;
1212 r = Context_PartialInit(ctx, (*prov), interactionParams);
1213 if( MI_RESULT_OK != r )
1214 return r;
1215
1216 // by default serializer will use the function tables to access resultClass as a wrapper to MI_ClassDecl
1217 // this place will be modified in future to fill in the appropriate extended function tables
1218 // providing access to schema in form of instance of cimclass
1219 Class_Construct(&resultClass, (*prov)->classDecl);
1220
1221 _PostClassToCallback(ctx, interactionParams, &resultClass);
1222 return MI_RESULT_OK;
1223 }
1224
|
1225 mike 1.1 static MI_Result _HandleCreateInstanceReq(
|
1226 krisbash 1.4 _In_ ProvMgr* self,
1227 _In_ const ProvRegEntry* proventry,
1228 _Inout_ InteractionOpenParams* interactionParams,
1229 _Out_ Provider** prov)
|
1230 mike 1.1 {
1231 MI_Instance* inst;
1232 MI_Result r;
|
1233 krisbash 1.4 const ZChar* className;
1234 CreateInstanceReq* msg = (CreateInstanceReq*)interactionParams->msg;
|
1235 mike 1.1
1236 /* Get classname from instance */
1237 r = __MI_Instance_GetClassName(msg->instance, &className);
1238
1239 if (r != MI_RESULT_OK)
1240 return r;
1241
1242 /* find provider */
|
1243 krisbash 1.4 r = _GetProviderByClassName(
1244 self,
1245 proventry,
1246 className,
1247 &msg->base.base,
1248 prov);
|
1249 mike 1.1
1250 if ( MI_RESULT_OK != r )
1251 return r;
1252
1253 /* Allocate the instance for the provider */
1254 r = _Instance_InitConvert_FromBatch(
|
1255 krisbash 1.4 msg->base.base.batch,
|
1256 mike 1.1 (*prov)->classDecl,
1257 (*prov)->lib->module->schemaDecl,
1258 msg->instance,
1259 MI_FALSE,
1260 MI_TRUE,
|
1261 krisbash 1.4 &inst,
1262 msg->base.base.flags);
|
1263 mike 1.1
1264 if (MI_RESULT_OK != r)
1265 return r;
1266
1267 /* Invoke provider */
1268 if (!(*prov)->classDecl->providerFT->CreateInstance)
1269 return MI_RESULT_INVALID_CLASS;
1270
1271 {
|
1272 krisbash 1.4 Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch,
|
1273 mike 1.1 sizeof(Context));;
|
1274 krisbash 1.4 Context_Init(ctx, (*prov), interactionParams);
1275 if( MI_RESULT_OK != r )
1276 return r;
1277
|
1278 mike 1.1 /* message will be freed in context release*/
1279 (*(*prov)->classDecl->providerFT->CreateInstance)((*prov)->self, &ctx->base,
1280 msg->nameSpace, className, inst);
1281 }
1282
1283 return MI_RESULT_OK;
1284 }
1285
1286 static MI_Result _HandleModifyInstanceReq(
|
1287 krisbash 1.4 _In_ ProvMgr* self,
1288 _In_ const ProvRegEntry* proventry,
1289 _Inout_ InteractionOpenParams* interactionParams,
1290 _Out_ Provider** prov)
|
1291 mike 1.1 {
1292 MI_Instance* inst;
1293 MI_Result r;
|
1294 krisbash 1.4 const ZChar* className;
1295 ModifyInstanceReq* msg = (ModifyInstanceReq*)interactionParams->msg;
|
1296 mike 1.1
1297 /* Get classname from instance */
1298 r = __MI_Instance_GetClassName(msg->instance, &className);
1299
1300 if (r != MI_RESULT_OK)
1301 return r;
1302
1303 /* find provider */
|
1304 krisbash 1.4 r = _GetProviderByClassName(
1305 self,
1306 proventry,
1307 className,
1308 &msg->base.base,
1309 prov);
|
1310 mike 1.1
1311 if ( MI_RESULT_OK != r )
1312 return r;
1313
1314 /* Allocate the instance for the provider */
1315 r = _Instance_InitConvert_FromBatch(
|
1316 krisbash 1.4 msg->base.base.batch,
|
1317 mike 1.1 (*prov)->classDecl,
1318 (*prov)->lib->module->schemaDecl,
1319 msg->instance,
1320 MI_FALSE,
1321 MI_FALSE,
|
1322 krisbash 1.4 &inst,
1323 msg->base.base.flags);
|
1324 mike 1.1
1325 if (MI_RESULT_OK != r)
1326 return r;
1327
1328 /* Invoke provider */
1329 if (!(*prov)->classDecl->providerFT->ModifyInstance)
1330 return MI_RESULT_INVALID_CLASS;
1331
1332 {
|
1333 krisbash 1.4 Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch,
|
1334 mike 1.1 sizeof(Context));;
|
1335 krisbash 1.4 r = Context_Init(ctx, (*prov), interactionParams);
1336 if( MI_RESULT_OK != r )
1337 return r;
1338
1339 /* Need to store instance in case we need to call GetInstance */
1340 ctx->keyInstance = inst;
1341
|
1342 mike 1.1 /* message will be freed in context release*/
1343 (*(*prov)->classDecl->providerFT->ModifyInstance)((*prov)->self, &ctx->base,
1344 msg->nameSpace, className, inst, NULL);
1345 }
1346
1347 return MI_RESULT_OK;
1348 }
1349
1350 static MI_Result _HandleDeleteInstanceReq(
|
1351 krisbash 1.4 _In_ ProvMgr* self,
1352 _In_ const ProvRegEntry* proventry,
1353 _Inout_ InteractionOpenParams* interactionParams,
1354 _Out_ Provider** prov)
|
1355 mike 1.1 {
1356 MI_Instance* inst;
1357 MI_Result r;
|
1358 krisbash 1.4 const ZChar* className;
1359 DeleteInstanceReq* msg = (DeleteInstanceReq*)interactionParams->msg;
|
1360 mike 1.1
1361 /* Get classname from instance */
1362 r = __MI_Instance_GetClassName(msg->instanceName, &className);
1363
1364 if (r != MI_RESULT_OK)
1365 return r;
1366
1367 /* find provider */
|
1368 krisbash 1.4 r = _GetProviderByClassName(
1369 self,
1370 proventry,
1371 className,
1372 &msg->base.base,
1373 prov);
|
1374 mike 1.1
1375 if ( MI_RESULT_OK != r )
1376 return r;
1377
1378 /* Allocate the instance for the provider */
1379 r = _Instance_InitConvert_FromBatch(
|
1380 krisbash 1.4 msg->base.base.batch,
|
1381 mike 1.1 (*prov)->classDecl,
1382 (*prov)->lib->module->schemaDecl,
1383 msg->instanceName,
1384 MI_TRUE,
1385 MI_FALSE,
|
1386 krisbash 1.4 &inst,
1387 msg->base.base.flags);
|
1388 mike 1.1
1389 if (MI_RESULT_OK != r)
1390 return r;
1391
1392 /* Invoke provider */
1393 if (!(*prov)->classDecl->providerFT->DeleteInstance)
1394 return MI_RESULT_INVALID_CLASS;
1395
1396 {
|
1397 krisbash 1.4 Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch,
|
1398 mike 1.1 sizeof(Context));;
|
1399 krisbash 1.4 r = Context_Init(ctx, (*prov), interactionParams);
1400 if( MI_RESULT_OK != r )
1401 return r;
1402
|
1403 mike 1.1 /* message will be freed in context release*/
1404 (*(*prov)->classDecl->providerFT->DeleteInstance)((*prov)->self, &ctx->base,
1405 msg->nameSpace, className, inst);
1406 }
1407
1408 return MI_RESULT_OK;
1409 }
1410
|
1411 krisbash 1.4 #ifndef DISABLE_INDICATION
1412
1413 /*
1414 * Behaves conditionally depending on whether or not indications were
1415 * compiled into the product.
1416 */
|
1417 mike 1.1 static MI_Result _HandleSubscribeReq(
|
1418 krisbash 1.4 _In_ ProvMgr* self,
1419 _In_ const ProvRegEntry* proventry,
1420 _Inout_ InteractionOpenParams* interactionParams,
1421 _Out_ Provider** prov)
|
1422 mike 1.1 {
1423 MI_Result r;
|
1424 krisbash 1.4 SubscribeReq* msg = (SubscribeReq*)interactionParams->msg;
1425
1426 *prov = NULL;
|
1427 mike 1.1
1428 /* find provider */
|
1429 krisbash 1.4 r = _GetProviderByClassName(
1430 self,
1431 proventry,
1432 msg->className,
1433 &msg->base.base,
1434 prov);
|
1435 mike 1.1
1436 if ( MI_RESULT_OK != r )
|
1437 krisbash 1.4 {
1438 trace_ProvMgr_ClassNotFound( tcs(msg->className) );
|
1439 mike 1.1 return r;
1440 }
1441
|
1442 krisbash 1.4 return _Provider_InvokeSubscribeWrapper( *prov, interactionParams );
1443 }
|
1444 mike 1.1
|
1445 krisbash 1.4 #endif /* ifndef DISABLE_INDICATION */
|
1446 mike 1.1
1447 static MI_Result _HandleInvokeReq(
|
1448 krisbash 1.4 _In_ ProvMgr* self,
1449 _In_ const ProvRegEntry* proventry,
1450 _Inout_ InteractionOpenParams* interactionParams,
1451 _Out_ Provider** prov)
|
1452 mike 1.1 {
1453 MI_Instance* inst = 0;
1454 MI_Instance* instParams = 0;
1455 MI_Result r;
1456 MI_ConstString cn = 0;
1457 MI_MethodDecl* md = 0;
|
1458 krisbash 1.4 InvokeReq* msg = (InvokeReq*)interactionParams->msg;
1459
1460 #if 0
1461 MessagePrint(&msg->base, stdout);
1462 #endif
|
1463 mike 1.1
1464 /* parameter validation */
1465 if (!msg || !msg->function)
1466 return MI_RESULT_INVALID_PARAMETER;
1467
1468 if (msg->className)
1469 cn = msg->className;
1470 else if (msg->instance)
1471 cn = ((Instance*) msg->instance)->classDecl->name;
1472
1473 if (!cn)
1474 return MI_RESULT_INVALID_CLASS;
1475
1476 /* find provider */
|
1477 krisbash 1.4 r = _GetProviderByClassName(
1478 self,
1479 proventry,
1480 cn,
1481 &msg->base.base,
1482 prov);
|
1483 mike 1.1
1484 if ( MI_RESULT_OK != r )
1485 return r;
1486
1487 /* find method declaration */
1488 md = SchemaDecl_FindMethodDecl( (*prov)->classDecl, msg->function );
1489
1490 if (!md)
1491 return MI_RESULT_FAILED;
1492
1493 /* if method is not static, instance must be provided */
1494 if (!msg->instance && (md->flags & MI_FLAG_STATIC) != MI_FLAG_STATIC)
1495 return MI_RESULT_INVALID_PARAMETER;
1496
1497 if (msg->instance)
1498 {
1499
1500 r = _Instance_InitConvert_FromBatch(
|
1501 krisbash 1.4 msg->base.base.batch,
|
1502 mike 1.1 (*prov)->classDecl,
1503 (*prov)->lib->module->schemaDecl,
1504 msg->instance,
1505 MI_TRUE,
1506 MI_FALSE,
|
1507 krisbash 1.4 &inst,
1508 msg->base.base.flags);
|
1509 mike 1.1
1510 if (MI_RESULT_OK != r)
1511 return r;
1512 }
1513
1514 if (msg->instanceParams)
1515 {
1516 /* paramters (if any) */
1517 r = _Instance_InitConvert_FromBatch(
|
1518 krisbash 1.4 msg->base.base.batch,
|
1519 mike 1.1 (const MI_ClassDecl*)md,
1520 (*prov)->lib->module->schemaDecl,
1521 msg->instanceParams,
1522 MI_FALSE,
1523 MI_TRUE,
|
1524 krisbash 1.4 &instParams,
1525 msg->base.base.flags);
|
1526 mike 1.1
1527 if (MI_RESULT_OK != r)
1528 return r;
1529 }
1530
1531 #if 0
1532 /* Print instance */
|
1533 krisbash 1.4 Instance_Print(inst, stdout, 0, 0, 0);
|
1534 mike 1.1 #endif
1535
1536 /* Invoke provider */
1537 if (!md->function)
1538 return MI_RESULT_INVALID_CLASS;
1539
1540 {
|
1541 krisbash 1.4 Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch, sizeof(Context));
1542 r = Context_Init(ctx, (*prov), interactionParams);
1543 if( MI_RESULT_OK != r )
1544 return r;
|
1545 mike 1.1
1546 /* call get first if fn is non-static */
1547 /*if (inst && (*prov)->classDecl->providerFT->GetInstance)
1548 {
|
1549 krisbash 1.4 ctx->ctxType = CTX_TYPE_INVOKE_WITH_INSTANCE;
|
1550 mike 1.1 ctx->inst = inst;
1551 ctx->instParams = instParams;
1552 ctx->md = md;
1553 ctx->prov_self = (*prov)->self;
1554
1555 (*(*prov)->classDecl->providerFT->GetInstance)((*prov)->self, &ctx->base,
1556 __nameSpace, __className, inst, NULL);
1557 }
1558 else */ /* for static - call invoke directly */
1559 (*md->function)((*prov)->self, &ctx->base,
1560 msg->nameSpace, cn, msg->function, inst, instParams);
1561 }
1562
1563 return MI_RESULT_OK;
1564 }
1565
1566 static MI_Result _HandleEnumerateInstancesReq(
|
1567 krisbash 1.4 _In_ ProvMgr* self,
1568 _In_ const ProvRegEntry* proventry,
1569 _Inout_ InteractionOpenParams* interactionParams,
1570 _Out_ Provider** prov)
|
1571 mike 1.1 {
|
1572 krisbash 1.4 Context* ctx;
|
1573 mike 1.1 MI_Result r;
|
1574 krisbash 1.4 EnumerateInstancesReq* msg = (EnumerateInstancesReq*)interactionParams->msg;
1575 InstanceFilter* instanceFilter = NULL;
1576 MI_Filter* filter = NULL;
1577
1578 #if 0
1579 MessagePrint(&msg->base, stdout);
1580 #endif
|
1581 mike 1.1
1582 /* find provider */
|
1583 krisbash 1.4 r = _GetProviderByClassName(
1584 self,
1585 proventry,
1586 msg->className,
1587 &msg->base.base,
1588 prov);
|
1589 mike 1.1
1590 if ( MI_RESULT_OK != r )
1591 return r;
1592
|
1593 krisbash 1.4 DEBUG_ASSERT(msg->wql == NULL);
1594
1595 /* Get WQL query, if any */
1596 if (msg->queryLanguage != NULL && msg->queryExpression != NULL)
1597 {
1598 /* Create filter then Get WQL query */
1599 instanceFilter = InstanceFilter_New( &(msg->base.base) );
1600
1601 if (instanceFilter == NULL)
1602 {
1603 trace_InstanceFilter_AllocFailed();
1604 return MI_RESULT_INVALID_QUERY;
1605 }
1606
1607 filter = &(instanceFilter->base);
1608
1609 msg->wql = InstanceFilter_GetWQL(instanceFilter);
1610 }
1611
|
1612 mike 1.1 /* Validate WQL query (if any) against provider's class declaration */
1613 if (msg->wql)
1614 {
1615 if (WQL_Validate(msg->wql, (*prov)->classDecl) != 0)
1616 {
|
1617 krisbash 1.4 trace_QueryValidationFailed(tcs(msg->wql->text));
|
1618 mike 1.1 return MI_RESULT_INVALID_QUERY;
1619 }
1620 }
1621
1622 /* Invoke provider */
1623 if (!(*prov)->classDecl->providerFT->EnumerateInstances)
1624 return MI_RESULT_NOT_SUPPORTED;
1625
1626 /* Create the context object */
1627 {
1628 ctx = (Context*)Batch_GetClear(
|
1629 krisbash 1.4 msg->base.base.batch, sizeof(Context));;
|
1630 mike 1.1
1631 if (!ctx)
1632 {
|
1633 krisbash 1.4 trace_ProvMgr_AllocFailed();
|
1634 mike 1.1 return MI_RESULT_FAILED;
1635 }
1636
|
1637 krisbash 1.4 r = Context_Init(ctx, (*prov), interactionParams);
1638
1639 if( MI_RESULT_OK != r )
1640 return r;
|
1641 mike 1.1 }
1642
|
1643 krisbash 1.4 trace_ProvMgr_EnumerateInstancesOfClass( tcs(msg->className) );
|
1644 mike 1.1
1645 (*(*prov)->classDecl->providerFT->EnumerateInstances)(
|
1646 krisbash 1.4 (*prov)->self, &ctx->base,
1647 msg->nameSpace, msg->className, NULL, MI_FALSE, filter);
|
1648 mike 1.1
1649 return MI_RESULT_OK;
1650 }
1651
|
1652 krisbash 1.4 static MI_Result MI_CALL _HandleAssociatorsOfReq(
1653 _In_ ProvMgr* self,
1654 _In_ const ProvRegEntry* proventry,
1655 _Inout_ InteractionOpenParams* interactionParams,
1656 _Out_ Provider** prov)
|
1657 mike 1.1 {
1658 Context* ctx;
1659 MI_Result r;
1660 MI_Instance* inst = 0;
|
1661 krisbash 1.4 AssociationsOfReq* msg = (AssociationsOfReq*)interactionParams->msg;
|
1662 mike 1.1
1663 /* find provider */
|
1664 krisbash 1.4 r = _GetProviderByClassName(
1665 self,
1666 proventry,
1667 msg->className,
1668 &msg->base.base,
1669 prov);
|
1670 mike 1.1
1671 if ( MI_RESULT_OK != r )
1672 return r;
1673
1674 /* Invoke provider */
1675 if (!(*prov)->classDecl->providerFT->AssociatorInstances)
1676 return MI_RESULT_NOT_SUPPORTED;
1677
1678 if (!msg->instance)
1679 return MI_RESULT_INVALID_PARAMETER;
1680
1681 {
1682 Provider* provInst = 0;
1683
|
1684 krisbash 1.4 r = _GetProviderByClassName(
1685 self,
1686 proventry,
1687 ((Instance*) msg->instance)->classDecl->name,
1688 &msg->base.base,
1689 &provInst );
|
1690 mike 1.1
1691 if ( MI_RESULT_OK != r )
1692 return r;
1693
1694 r = _Instance_InitConvert_FromBatch(
|
1695 krisbash 1.4 msg->base.base.batch,
|
1696 mike 1.1 provInst->classDecl,
1697 (*prov)->lib->module->schemaDecl,
1698 msg->instance,
1699 MI_TRUE,
1700 MI_FALSE,
|
1701 krisbash 1.4 &inst,
1702 msg->base.base.flags);
|
1703 mike 1.1
1704 Provider_Release(provInst);
1705
1706 if (MI_RESULT_OK != r)
1707 return r;
1708 }
1709
1710 ctx = (Context*)Batch_GetClear(
|
1711 krisbash 1.4 msg->base.base.batch, sizeof(Context));;
|
1712 mike 1.1
1713 if (!ctx)
1714 {
|
1715 krisbash 1.4 trace_ProvMgr_AllocFailed();
|
1716 mike 1.1 return MI_RESULT_FAILED;
1717 }
1718
|
1719 krisbash 1.4 r = Context_Init(ctx, (*prov), interactionParams);
1720 if( MI_RESULT_OK != r )
1721 return r;
|
1722 mike 1.1
1723 /* message will be freed in context release */
1724 (*(*prov)->classDecl->providerFT->AssociatorInstances)(
1725 (*prov)->self,
1726 &ctx->base,
1727 msg->nameSpace,
1728 msg->className,
1729 inst,
1730 msg->resultClass,
1731 msg->role,
1732 msg->resultRole,
1733 NULL, MI_FALSE, NULL);
1734
1735 return MI_RESULT_OK;
1736 }
1737
1738 static MI_Result _HandleReferencesOfReq(
|
1739 krisbash 1.4 _In_ ProvMgr* self,
1740 _In_ const ProvRegEntry* proventry,
1741 _Inout_ InteractionOpenParams* interactionParams,
1742 _Out_ Provider** prov)
|
1743 mike 1.1 {
1744 Context* ctx;
1745 MI_Result r;
1746 MI_Instance* inst = 0;
|
1747 krisbash 1.4 AssociationsOfReq* msg = (AssociationsOfReq*)interactionParams->msg;
|
1748 mike 1.1
1749 /* find provider */
|
1750 krisbash 1.4 r = _GetProviderByClassName(
1751 self,
1752 proventry,
1753 msg->className,
1754 &msg->base.base,
1755 prov );
|
1756 mike 1.1
1757 if ( MI_RESULT_OK != r )
1758 return r;
1759
1760 /* Invoke provider */
1761 if (!(*prov)->classDecl->providerFT->ReferenceInstances)
1762 return MI_RESULT_NOT_SUPPORTED;
1763
1764 if (!msg->instance)
1765 return MI_RESULT_INVALID_PARAMETER;
1766
1767 {
1768 Provider* provInst = 0;
1769
1770 r = _GetProviderByClassName(
1771 self,
|
1772 krisbash 1.4 proventry,
1773 ((Instance*) msg->instance)->classDecl->name,
1774 &msg->base.base,
|
1775 mike 1.1 &provInst );
1776
1777 if ( MI_RESULT_OK != r )
1778 return r;
1779
1780 r = _Instance_InitConvert_FromBatch(
|
1781 krisbash 1.4 msg->base.base.batch,
|
1782 mike 1.1 provInst->classDecl,
1783 (*prov)->lib->module->schemaDecl,
1784 msg->instance,
1785 MI_TRUE,
1786 MI_FALSE,
|
1787 krisbash 1.4 &inst,
1788 msg->base.base.flags);
|
1789 mike 1.1
1790 Provider_Release(provInst);
1791
1792 if (MI_RESULT_OK != r)
1793 return r;
1794 }
1795
1796 ctx = (Context*)Batch_GetClear(
|
1797 krisbash 1.4 msg->base.base.batch, sizeof(Context));;
|
1798 mike 1.1
1799 if (!ctx)
1800 {
|
1801 krisbash 1.4 trace_ProvMgr_AllocFailed();
|
1802 mike 1.1 return MI_RESULT_FAILED;
1803 }
1804
|
1805 krisbash 1.4 r = Context_Init(ctx, (*prov), interactionParams);
1806 if( MI_RESULT_OK != r )
1807 return r;
|
1808 mike 1.1
1809 /* message will be freed in context release */
1810 (*(*prov)->classDecl->providerFT->ReferenceInstances)(
1811 (*prov)->self,
1812 &ctx->base,
1813 msg->nameSpace,
1814 msg->className,
1815 inst,
1816 msg->role,
1817 NULL, MI_FALSE, NULL);
1818
1819 return MI_RESULT_OK;
1820 }
1821
1822 static void _UnloadAllProviders(
1823 ProvMgr* self,
1824 Library* lib,
1825 MI_Boolean idleOnly,
1826 MI_Uint64 currentTimeUsec,
1827 MI_Uint64* nextFireAtTime)
1828 {
1829 mike 1.1 Provider* p, *p_next;
1830
1831 for (p = lib->head; p; )
1832 {
|
1833 krisbash 1.4 /* ATTN: idleSince is sometimes 0 */
1834
1835 MI_Uint64 provFireAtTime;
1836 if (p->idleSince != 0)
1837 provFireAtTime = p->idleSince + self->idleTimeoutUsec;
1838 else
1839 provFireAtTime = ~((MI_Uint64)0);
|
1840 mike 1.1
1841 p_next = p->next;
1842
1843 /* unload if 'force' option passed or provider is idle long enough */
1844 if (!idleOnly ||
1845 (!p->refusedUnload && 0 == p->refCounter && provFireAtTime <= currentTimeUsec))
1846 {
|
1847 krisbash 1.4 trace_ProvMgr_UnloadingProvider( tcs(p->classDecl->name) );
1848
1849 #ifndef DISABLE_INDICATION
1850 if (p->subMgr)
1851 {
1852 if (p->subMgr->lifecycleCtx)
1853 {
1854 LifeContext_Delete(p->subMgr->lifecycleCtx);
1855 p->subMgr->lifecycleCtx = NULL;
1856 }
1857 }
1858 #endif /* ifndef DISABLE_INDICATION */
|
1859 mike 1.1
1860 /* Call provider unload() method */
|
1861 krisbash 1.4 if (p->classDecl->providerFT && p->classDecl->providerFT->Unload)
|
1862 mike 1.1 {
1863 Context ctx;
|
1864 krisbash 1.4 Context_Init(&ctx, 0, NULL);
|
1865 mike 1.1 (*p->classDecl->providerFT->Unload)(p->self, &ctx.base);
1866
1867 DEBUG_ASSERT(ctx.magic == (MI_Uint32)-1);
1868 }
1869
1870 if (p->refCounter != 0)
1871 {
1872 /* Error condition - unloading active rpovider! */
|
1873 krisbash 1.4 trace_UnloadingActiveProvider(
1874 tcs(p->classDecl->name), (int)p->refCounter);
1875 trace_UnloadingActiveProviderWithLib(
1876 scs(lib->libraryName), (int)p->refCounter);
|
1877 mike 1.1
|
1878 krisbash 1.4 /* ATTN: _exit is a good option here, since provider's behavior maybe undefined */
1879 trace_UnloadingActiveProvider_ServerExit(scs(lib->libraryName));
|
1880 mike 1.1 _exit(1);
1881 }
1882
1883 List_Remove(
1884 (ListElem**)&lib->head,
1885 (ListElem**)&lib->tail,
1886 (ListElem*)p);
1887
|
1888 krisbash 1.4 Provider_Finalize( p );
1889 PAL_Free(p);
|
1890 mike 1.1 }
1891 else if (idleOnly && 0 == p->refCounter && nextFireAtTime)
1892 {
1893 /* re-calculate idle timeout */
1894
1895 if (provFireAtTime < *nextFireAtTime)
1896 *nextFireAtTime = provFireAtTime;
1897 }
1898
1899 /* move to next one */
1900 p = p_next;
1901 }
1902 }
1903
|
1904 krisbash 1.4 /*
1905 * Unload all libraries *NOT* thread safely
1906 */
1907 static void _UnloadAllLibrariesInternal(
|
1908 mike 1.1 ProvMgr* self,
1909 MI_Boolean idleOnly,
1910 MI_Uint64 currentTimeUsec,
1911 MI_Uint64* nextFireAtTime)
1912 {
1913 Library* p, *p_next;
1914
1915 /* release all (or idle-only) opened libraries */
1916 for (p = self->head; p; )
1917 {
1918 p_next = p->next;
1919
|
1920 krisbash 1.4 Lock_Acquire( &p->provlock );
|
1921 mike 1.1 _UnloadAllProviders(self,p,idleOnly,currentTimeUsec,nextFireAtTime);
|
1922 krisbash 1.4 Lock_Release( &p->provlock );
|
1923 mike 1.1
1924 /* Unload libraries that have no loaded providers */
1925 if (!p->head)
1926 {
1927 /* Invoke the module un-initialize function */
1928 if (p->module->Unload)
1929 {
1930 Context ctx;
|
1931 krisbash 1.4 MI_Result r = MI_RESULT_OK;
1932
1933 Context_Init(&ctx, NULL, NULL);
1934 ctx.result = &r;
1935
|
1936 mike 1.1 (p->module->Unload)(p->self, (MI_Context*)&ctx);
|
1937 krisbash 1.4
1938 if (ctx.magic != 0xFFFFFFFF)
1939 {
1940 trace_LibraryUnload_DidnotPostResult();
1941 }
1942
1943 if (MI_RESULT_OK != r)
1944 {
1945 trace_FailedCallLibraryUnload(r, scs(p->libraryName));
1946 }
|
1947 mike 1.1 }
1948
|
1949 krisbash 1.4 Shlib_Close(p->handle);
1950 trace_ProvMgr_UnloadingLibrary( scs(p->libraryName) );
|
1951 mike 1.1
1952 List_Remove(
1953 (ListElem**)&self->head,
1954 (ListElem**)&self->tail,
1955 (ListElem*)p);
1956
|
1957 krisbash 1.4 PAL_Free(p);
|
1958 mike 1.1 }
1959
1960 p = p_next;
1961 }
1962 }
1963
1964 /*
|
1965 krisbash 1.4 * Unload all libraries thread safely
1966 */
1967 static void _UnloadAllLibraries(
1968 ProvMgr* self,
1969 MI_Boolean idleOnly,
1970 MI_Uint64 currentTimeUsec,
1971 MI_Uint64* nextFireAtTime)
1972 {
1973 Lock_Acquire( &self->liblock );
1974 _UnloadAllLibrariesInternal( self, idleOnly, currentTimeUsec, nextFireAtTime );
1975
1976 // If all libraries are gone, notify caller
1977 if (!self->head && self->idleCallback)
1978 (*self->idleCallback)(self,self->idleCallbackData);
1979
1980 Lock_Release( &self->liblock );
1981 }
1982
1983 /*
1984 Timeout handler: unloads idle providers and libraries,
|
1985 mike 1.1 re-calculates new timeout (for next provider),
1986 notifies server/agent if all libraries are unloaded
1987 */
1988 static MI_Boolean _TimeoutCallback(
1989 Selector* sel,
1990 Handler* handler,
1991 MI_Uint32 mask,
1992 MI_Uint64 currentTimeUsec)
1993 {
1994 MI_UNUSED(sel);
1995
1996 if (mask & SELECTOR_TIMEOUT)
1997 {
1998 ProvMgr* self = (ProvMgr*)handler->data;
1999 const MI_Uint64 u64max = ~ MI_ULL(0);
2000 MI_Uint64 nextFireAtTime = u64max;
2001
2002 /* Unload all idle providers */
|
2003 krisbash 1.4 /* trace_UnloadingIdleProviders(); */
|
2004 mike 1.1
2005 _UnloadAllLibraries(self, MI_TRUE, currentTimeUsec, &nextFireAtTime);
2006
2007 if (u64max != nextFireAtTime)
2008 {
2009 /* re-set timeout */
2010 handler->fireTimeoutAt = nextFireAtTime;
2011 }
2012 else
2013 {
2014 /* disbale timeout, since no more idle providers */
2015 handler->fireTimeoutAt = TIME_NEVER;
2016 }
2017
2018 return MI_TRUE;
2019 }
2020
2021 if (mask & (SELECTOR_REMOVE | SELECTOR_DESTROY))
2022 {
2023 /* ignore it */
2024 }
2025 mike 1.1
2026 return MI_TRUE;
2027 }
2028
2029 /*
2030 **=============================================================================
2031 **
2032 ** Public defintions
2033 **
2034 **=============================================================================
2035 */
2036
2037 MI_Result ProvMgr_Init(
2038 ProvMgr* self,
2039 Selector* selector,
2040 ProvMgrCallbackOnIdle idleCallback,
2041 void* idleCallbackData,
2042 const char* providerDir)
2043 {
2044 if (!self || !providerDir)
2045 return MI_RESULT_INVALID_PARAMETER;
2046 mike 1.1
2047 memset(self, 0, sizeof(ProvMgr));
2048
2049 Strlcpy(self->providerDir, providerDir, sizeof(self->providerDir)-1);
2050
|
2051 krisbash 1.4 self->idleTimeoutUsec = PROVMGR_IDLE_TIMEOUT_USEC;
|
2052 mike 1.1
2053 /* Add socket handler to catch timeout event */
2054
2055 self->timeoutHandler.sock = INVALID_SOCK;
2056 self->timeoutHandler.data = self;
2057 self->timeoutHandler.callback = _TimeoutCallback;
2058 self->idleCallback = idleCallback;
2059 self->idleCallbackData = idleCallbackData;
2060 self->selector = selector;
2061
2062 Selector_AddHandler(selector, &self->timeoutHandler);
2063
|
2064 krisbash 1.4 self->ioThreadId = Thread_ID(); /* IO thread always initializes for Linux */
2065 Lock_Init( &self->liblock );
2066
2067 #ifndef DISABLE_INDICATION
2068 RequestHandler_Init(&g_requesthandler);
2069 #endif
2070
|
2071 mike 1.1 return MI_RESULT_OK;
2072 }
2073
2074 MI_Result ProvMgr_Destroy(
2075 ProvMgr* self)
2076 {
2077 if (!self)
2078 return MI_RESULT_INVALID_PARAMETER;
2079
|
2080 krisbash 1.4 #ifndef DISABLE_INDICATION
2081 RequestHandler_Finalize(&g_requesthandler);
2082 #endif
2083
|
2084 mike 1.1 /* release opened libraries */
2085 _UnloadAllLibraries(self, MI_FALSE, 0, NULL);
2086
|
2087 krisbash 1.4 /* If local session is initialized then we need to clean-up */
2088 while (Atomic_Read(&self->localSessionInitialized) != 0)
2089 {
2090 if (Atomic_CompareAndSwap(&self->localSessionInitialized, 2, 1))
2091 {
2092 /* Initialized, so need to deinitialize */
2093 MI_Session_Close(&self->localSession, NULL, NULL);
2094 MI_Application_Close(&self->localApplication);
2095 self->localSessionInitialized = 0;
2096 /* Broadcast does a memory barrier so no need for assignment to be atomic */
2097 CondLock_Broadcast((ptrdiff_t) &self->localSession);
2098 }
2099 else if (self->localSessionInitialized == 1)
2100 {
2101 /* Initializing for some reason so wait for it to complete */
2102 ptrdiff_t init = self->localSessionInitialized;
2103 while (init == 1)
2104 {
2105 CondLock_Wait((ptrdiff_t)&self->localSession, &self->localSessionInitialized, init, CONDLOCK_DEFAULT_SPINCOUNT);
2106 init = self->localSessionInitialized;
2107 }
2108 krisbash 1.4 }
2109 }
2110
|
2111 mike 1.1 memset(self, -1, sizeof(ProvMgr));
2112
2113 return MI_RESULT_OK;
2114 }
2115
2116 /*
2117 Routes incoming message to appropriate
2118 message handler based on message tag
2119 */
|
2120 krisbash 1.4 MI_Result MI_CALL ProvMgr_NewRequest(
2121 _In_ ProvMgr* self,
2122 _In_ const ProvRegEntry* proventry,
2123 _Inout_ InteractionOpenParams* params )
|
2124 mike 1.1 {
2125 Provider* prov = 0;
2126 MI_Result r = MI_RESULT_INVALID_PARAMETER;
2127
2128 /* Check parameters */
|
2129 krisbash 1.4 if( !self || !params || !params->msg || !params->interaction )
|
2130 mike 1.1 return MI_RESULT_INVALID_PARAMETER;
2131
2132 /* Dispatch the message */
|
2133 krisbash 1.4 switch( params->msg->tag )
|
2134 mike 1.1 {
2135 case GetInstanceReqTag:
2136 {
|
2137 krisbash 1.4 r = _HandleGetInstanceReq(self, proventry, params, &prov);
|
2138 mike 1.1 break;
2139 }
|
2140 krisbash 1.4 case GetClassReqTag:
2141 {
2142 r = _HandleGetClassReq(self, proventry, params, &prov);
2143 break;
2144 }
|
2145 mike 1.1 case CreateInstanceReqTag:
2146 {
|
2147 krisbash 1.4 r = _HandleCreateInstanceReq(self, proventry, params, &prov);
|
2148 mike 1.1 break;
2149 }
2150 case ModifyInstanceReqTag:
2151 {
|
2152 krisbash 1.4 r = _HandleModifyInstanceReq(self, proventry, params, &prov);
|
2153 mike 1.1 break;
2154 }
2155 case DeleteInstanceReqTag:
2156 {
|
2157 krisbash 1.4 r = _HandleDeleteInstanceReq(self, proventry, params, &prov);
|
2158 mike 1.1 break;
2159 }
2160 case InvokeReqTag:
2161 {
|
2162 krisbash 1.4 r = _HandleInvokeReq(self, proventry, params, &prov);
|
2163 mike 1.1 break;
2164 }
2165 case EnumerateInstancesReqTag:
2166 {
|
2167 krisbash 1.4 r = _HandleEnumerateInstancesReq(self, proventry, params, &prov);
|
2168 mike 1.1 break;
2169 }
2170 case AssociatorsOfReqTag:
2171 {
|
2172 krisbash 1.4 r = _HandleAssociatorsOfReq(self, proventry, params, &prov);
|
2173 mike 1.1 break;
2174 }
2175 case ReferencesOfReqTag:
2176 {
|
2177 krisbash 1.4 r = _HandleReferencesOfReq(self, proventry, params, &prov);
|
2178 mike 1.1 break;
2179 }
|
2180 krisbash 1.4 #ifndef DISABLE_INDICATION
|
2181 mike 1.1 case SubscribeReqTag:
2182 {
|
2183 krisbash 1.4 r = _HandleSubscribeReq(self, proventry, params, &prov);
|
2184 mike 1.1 break;
2185 }
|
2186 krisbash 1.4 #endif
|
2187 mike 1.1 default:
|
2188 krisbash 1.4 trace_ProvMgr_NewRequest_UnsupportedMessage(
2189 params->msg, MessageName(params->msg->tag));
|
2190 mike 1.1 break;
2191 }
2192
|
2193 krisbash 1.4 Provider_Release(prov); /* Releases hold from Provider_AddRef in _OpenProvider() */
|
2194 mike 1.1 return r;
2195 }
2196
2197 /*
|
2198 krisbash 1.4 * Increments provider's ref-counter
2199 */
|
2200 mike 1.1 void Provider_Addref(Provider* provider)
2201 {
2202 if (provider)
|
2203 krisbash 1.4 Atomic_Inc(&provider->refCounter);
2204 }
2205
2206 /*
2207 * Finalize provider before free memory
2208 */
2209 _Use_decl_annotations_
2210 void Provider_Finalize(Provider* provider)
2211 {
2212 if (provider)
2213 {
2214 #ifndef DISABLE_INDICATION
2215 DEBUG_ASSERT( provider->subMgr );
2216 SubMgr_Finalize( provider->subMgr );
2217 #endif
2218 }
|
2219 mike 1.1 }
2220
2221 /*
|
2222 krisbash 1.4 * Decrements provider's ref-counter and
2223 * marks provider as idle if ref-counter is 0 and
2224 * 'refuse-unload' was not called
2225 */
|
2226 mike 1.1 void Provider_Release(Provider* provider)
2227 {
|
2228 krisbash 1.4 if (provider && Atomic_Dec(&provider->refCounter) == 0)
|
2229 mike 1.1 {
2230 if (!provider->refusedUnload)
2231 {
2232 /* Provider becomes idle */
|
2233 krisbash 1.4 if (PAL_TRUE != PAL_Time(&provider->idleSince))
|
2234 mike 1.1 provider->idleSince = ~ (MI_Uint64)0;
2235
2236 /* Set timer if it's first idle provider */
2237 if (TIME_NEVER == provider->lib->provmgr->timeoutHandler.fireTimeoutAt)
2238 {
|
2239 krisbash 1.4 if (PAL_TRUE == PAL_Time(&provider->lib->provmgr->timeoutHandler.fireTimeoutAt))
|
2240 mike 1.1 {
2241 provider->lib->provmgr->timeoutHandler.fireTimeoutAt += provider->lib->provmgr->idleTimeoutUsec;
2242
2243 /* wakeup main thread */
|
2244 krisbash 1.4 Selector_Wakeup(provider->lib->provmgr->selector, MI_TRUE);
|
2245 mike 1.1 }
2246 }
2247 }
2248 }
2249 }
2250
2251 void Provider_SetRefuseUnloadFlag(Provider* provider, MI_Boolean flag)
2252 {
2253 provider->refusedUnload = flag;
2254 }
2255
|
2256 krisbash 1.4
2257 MI_Result ProvMgr_GetLocalSesson(
2258 _Inout_ ProvMgr* self,
2259 _Out_ MI_Session *localSession)
|
2260 mike 1.1 {
|
2261 krisbash 1.4 #if defined(DISABLE_LOCALSESSION)
2262 MI_UNREFERENCED_PARAMETER(self);
2263 MI_UNREFERENCED_PARAMETER(localSession);
2264
2265 return MI_RESULT_NOT_SUPPORTED;
2266 #else /* defined(DISABLE_LOCALSESSION) */
2267
2268 while (Atomic_Read(&self->localSessionInitialized) != 2)
2269 {
2270 if (Atomic_CompareAndSwap(&self->localSessionInitialized, 0, 1) == 0)
2271 {
2272 /* Need to initialize */
2273 MI_Result miResult;
2274 miResult = MI_Application_Initialize(0, MI_T("OMI Local Session"), NULL, &self->localApplication);
2275 if (miResult == MI_RESULT_OK)
2276 {
2277 miResult = MI_Application_NewSession(&self->localApplication, NULL, NULL, NULL, NULL, NULL, &self->localSession);
2278 if (miResult == MI_RESULT_OK)
2279 {
2280 /* Succeeded, so mark as initialized */
2281 *localSession = self->localSession;
2282 krisbash 1.4 self->localSessionInitialized = 2;
2283 }
2284 else
2285 {
2286 /* Failed, so reset state */
2287 MI_Application_Close(&self->localApplication);
2288 self->localSessionInitialized = 0;
2289 }
2290 }
2291 else
2292 {
2293 /* Failed so reset state */
2294 self->localSessionInitialized = 0;
2295 }
2296 /* memory barrier as part of broadcast which is why state updates were not atomic */
2297 CondLock_Broadcast((ptrdiff_t) &self->localSession);
2298
2299 return miResult;
2300 }
2301 else if (self->localSessionInitialized == 1)
2302 {
2303 krisbash 1.4 /* Wait for the initialization on another thread to complete */
2304 ptrdiff_t init = self->localSessionInitialized;
2305 while (init == 1)
2306 {
2307 CondLock_Wait((ptrdiff_t)&self->localSession, &self->localSessionInitialized, init, CONDLOCK_DEFAULT_SPINCOUNT);
2308 init = self->localSessionInitialized;
2309 }
2310 /* Need to try another trip around the loop to make sure it is initialized this time around */
2311 }
2312 }
2313
2314 *localSession = self->localSession;
2315 return MI_RESULT_OK;
2316 #endif /* defined(DISABLE_LOCALSESSION) */
|
2317 mike 1.1 }
|