version 1.3, 2015/04/20 18:10:13
|
version 1.4, 2015/04/20 18:19:56
|
|
|
| |
#include "provmgr.h" | #include "provmgr.h" |
#include "context.h" | #include "context.h" |
|
#include "AggregationContext.h" |
|
#include "LifecycleContext.h" |
|
#include "SubMgr.h" |
|
#include "nioproc.h" |
#include <base/log.h> | #include <base/log.h> |
#include <base/strings.h> |
#include <pal/strings.h> |
#include <base/atomic.h> |
#include <pal/atomic.h> |
#include <base/paths.h> | #include <base/paths.h> |
#include <base/time.h> |
#include <pal/sleep.h> |
|
#include <base/class.h> |
#include <wql/wql.h> | #include <wql/wql.h> |
|
#include <wsman/wsbuf.h> |
|
#include <pal/format.h> |
|
#include <indication/common/indilog.h> |
|
#include <indication/common/indicommon.h> |
|
#include <omi_error/errorutil.h> |
|
#include <provreg/provreg.h> |
| |
#if defined(CONFIG_POSIX) | #if defined(CONFIG_POSIX) |
# include <unistd.h> | # include <unistd.h> |
|
|
/* ATTN: implement module provider Unload() methods */ | /* ATTN: implement module provider Unload() methods */ |
/* ATTN: implement propertySet */ | /* ATTN: implement propertySet */ |
| |
/* Suppress casat error from 'void*' to 'MI_Main' */ |
/* Suppress cast error from 'void*' to 'MI_Main' */ |
#if defined(_MSC_VER) | #if defined(_MSC_VER) |
# pragma warning(disable : 4055) | # pragma warning(disable : 4055) |
#endif | #endif |
| |
#define T MI_T |
|
|
|
/* | /* |
**============================================================================= | **============================================================================= |
** | ** |
|
|
**============================================================================= | **============================================================================= |
*/ | */ |
| |
typedef MI_Module* (*MI_Main)(MI_Server* server); |
|
|
|
extern MI_ContextFT __mi_contextFT; | extern MI_ContextFT __mi_contextFT; |
| |
static MI_Result MI_CALL _Server_GetVersion(MI_Uint32* version) | static MI_Result MI_CALL _Server_GetVersion(MI_Uint32* version) |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
static MI_Result MI_CALL _Server_GetSystemName(const MI_Char** systemName) |
static MI_Result MI_CALL _Server_GetSystemName(const ZChar** systemName) |
{ | { |
#if defined(CONFIG_OS_WINDOWS) | #if defined(CONFIG_OS_WINDOWS) |
*systemName = MI_T("unknown"); | *systemName = MI_T("unknown"); |
|
|
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
| |
|
#if (MI_CHAR_TYPE == 1) |
*systemName = buf; | *systemName = buf; |
|
#else |
|
{ |
|
static ZChar wbuf[sizeof(buf)]; |
|
TcsStrlcpy(wbuf, buf, MI_COUNT(wbuf)); |
|
*systemName = wbuf; |
|
} |
|
#endif |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
#endif | #endif |
} | } |
|
|
| |
static void* _FindSymbol(const char* name) | static void* _FindSymbol(const char* name) |
{ | { |
if (strcmp(name, "GetPath") == 0) |
if (strcmp(name, "OMI_GetPath") == 0) |
return (void*)&GetPath; |
return (void*)&OMI_GetPath; |
| |
/* Not found */ | /* Not found */ |
return NULL; | return NULL; |
|
|
NULL, /* MI_FilterFT */ | NULL, /* MI_FilterFT */ |
}; | }; |
| |
typedef struct _Library Library; |
/* |
|
* Try to find specific library and open it if not found, |
struct _Provider |
* this function is not thread-safely operate the library list |
{ |
*/ |
struct _Provider* next; |
static Library* MI_CALL _OpenLibraryInternal( |
struct _Provider* prev; |
|
|
|
const MI_ClassDecl* classDecl; |
|
void* self; |
|
|
|
/* number of outstanding requests */ |
|
AtomicInt refCounter; |
|
|
|
/* time when last outstanding request was handled */ |
|
MI_Uint64 idleSince; |
|
|
|
/* indicator if Provider refused idle-unload */ |
|
MI_Boolean refusedUnload; |
|
|
|
/* pointer to lib object */ |
|
Library* lib; |
|
|
|
/* indications support */ |
|
Context ctxIndications; |
|
|
|
}; |
|
|
|
struct _Library |
|
{ |
|
struct _Library* next; |
|
struct _Library* prev; |
|
char libraryName[MAX_PATH_SIZE]; |
|
void* handle; |
|
const MI_Module* module; |
|
MI_Module_Self* self; |
|
struct _Provider* head; |
|
struct _Provider* tail; |
|
ProvMgr* provmgr; |
|
}; |
|
|
|
static Library* _OpenLibrary( |
|
ProvMgr* self, | ProvMgr* self, |
const char* libraryName) |
_In_ const ProvRegEntry* proventry) |
{ | { |
Library* p; | Library* p; |
| |
/* Search cache first */ | /* Search cache first */ |
for (p = self->head; p; p = p->next) | for (p = self->head; p; p = p->next) |
{ | { |
if (strcmp(p->libraryName, libraryName) == 0) |
if (strcmp(p->libraryName, proventry->libraryName) == 0) |
{ | { |
return p; | return p; |
} | } |
} | } |
| |
/* Allocate new libray object */ | /* Allocate new libray object */ |
p = (Library*)calloc(1, sizeof(Library)); |
p = (Library*)PAL_Calloc(1, sizeof(Library)); |
| |
if (!p) | if (!p) |
return NULL; | return NULL; |
| |
/* Library.refs */ | /* Library.refs */ |
p->provmgr = self; | p->provmgr = self; |
|
|
/* Open the library */ | /* Open the library */ |
{ | { |
char path[MAX_PATH_SIZE]; |
TChar path[PAL_MAX_PATH_SIZE]; |
Lib_Format(path, self->providerDir, libraryName); |
path[0] = '\0'; |
p->handle = Lib_Open(path); |
Shlib_Format(path, self->providerDir, proventry->libraryName); |
|
p->handle = Shlib_Open(path); |
| |
if (!p->handle) | if (!p->handle) |
{ | { |
/* ATTN: one more attempt */ |
TChar Tpath[PAL_MAX_PATH_SIZE]; |
p->handle = Lib_Open(libraryName); |
|
|
if (TcsStrlcpy(Tpath, proventry->libraryName, PAL_MAX_PATH_SIZE) >= PAL_MAX_PATH_SIZE) |
|
{ |
|
trace_SharedLib_CannotOpen(scs(proventry->libraryName)); |
|
PAL_Free(p); |
|
return NULL; |
} | } |
| |
|
trace_SharedLib_CannotOpenFirstTry(tcs(path), tcs(Shlib_Err())); |
|
|
|
// here we are ignoring error from Shlib_Open on first attempt |
|
NitsIgnoringError(); |
|
|
|
/* Try again */ |
|
|
|
p->handle = Shlib_Open(Tpath); |
|
|
if (!p->handle) | if (!p->handle) |
{ | { |
free(p); |
trace_SharedLib_CannotOpenSecondTry(scs(proventry->libraryName), tcs(Shlib_Err())); |
|
PAL_Free(p); |
return NULL; | return NULL; |
} | } |
} | } |
|
} |
| |
/* Lib_Open.libraryName */ | /* Lib_Open.libraryName */ |
Strlcpy(p->libraryName, libraryName, sizeof(p->libraryName)); |
Strlcpy(p->libraryName, proventry->libraryName, sizeof(p->libraryName)); |
|
p->instanceLifetimeContext = proventry->instanceLifetimeContext; |
| |
/* Invoke MI_Main() entry point */ | /* Invoke MI_Main() entry point */ |
{ | { |
MI_Main statikMain; |
MI_MainFunction statikMain; |
| |
/* Lookup symbol */ | /* Lookup symbol */ |
{ | { |
void* ptr = Lib_Sym(p->handle, "MI_Main"); |
void* ptr = Shlib_Sym(p->handle, "MI_Main"); |
| |
statikMain = (MI_Main)ptr; |
statikMain = (MI_MainFunction)ptr; |
| |
if (!statikMain) | if (!statikMain) |
{ | { |
free(p); |
PAL_Free(p); |
|
trace_SharedLibrary_CannotFindSymbol(scs(proventry->libraryName), scs("MI_Main")); |
return NULL; | return NULL; |
} | } |
} | } |
|
|
/* Call MI_Main */ | /* Call MI_Main */ |
{ | { |
p->module = (*statikMain)(&_server); | p->module = (*statikMain)(&_server); |
|
if (!p->module) |
|
{ |
|
PAL_Free(p); |
|
trace_Provmgr_NullModulePointer(scs(proventry->libraryName), scs("MI_Main")); |
|
return NULL; |
|
} |
|
if (p->module->version > MI_VERSION) |
|
{ |
|
MI_Uint32 v = p->module->version; |
|
PAL_Free(p); |
|
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); |
|
return NULL; |
|
} |
} | } |
} | } |
| |
|
|
if (p->module->Load) | if (p->module->Load) |
{ | { |
Context ctx; | Context ctx; |
Context_Init(&ctx, 0); |
MI_Result r = MI_RESULT_OK; |
|
|
|
Context_Init(&ctx, NULL, NULL); |
|
ctx.result = &r; |
|
|
(p->module->Load)(&p->self, (MI_Context*)&ctx); | (p->module->Load)(&p->self, (MI_Context*)&ctx); |
Context_Destroy(&ctx); |
|
|
if (ctx.magic != 0xFFFFFFFF) |
|
{ |
|
trace_ModuleLoad_FailedPostResult(); |
} | } |
| |
|
if (MI_RESULT_OK != r) |
|
{ |
|
trace_FailedCallModuleLoad(r, scs(proventry->libraryName)); |
|
return NULL; |
|
} |
|
} |
|
|
|
Lock_Init( &p->provlock ); |
|
|
/* Add library to the list */ | /* Add library to the list */ |
List_Prepend( | List_Prepend( |
(ListElem**)&self->head, | (ListElem**)&self->head, |
|
|
return p; | return p; |
} | } |
| |
static Provider* _OpenProvider( |
/* |
|
* Try to find specific library and open it if not found, |
|
* this function ensure thread-safe use of the library list |
|
*/ |
|
static Library* MI_CALL _OpenLibrary( |
|
ProvMgr* self, |
|
_In_ const ProvRegEntry* proventry) |
|
{ |
|
Library* lib; |
|
Lock_Acquire( & self->liblock ); |
|
lib = _OpenLibraryInternal( self, proventry ); |
|
Lock_Release( & self->liblock ); |
|
return lib; |
|
} |
|
|
|
/* |
|
* Try to find specific provider (class) and open it if not found, |
|
* this function is NOT thread-safe |
|
*/ |
|
static Provider* MI_CALL _OpenProviderInternal( |
Library* self, | Library* self, |
const MI_Char* className) |
const ZChar* className, |
|
Message* request) |
{ | { |
Provider* p; | Provider* p; |
|
size_t psize = sizeof(Provider); |
| |
/* Search cache first */ | /* Search cache first */ |
for (p = self->head; p; p = p->next) | for (p = self->head; p; p = p->next) |
{ | { |
if (Zcasecmp(p->classDecl->name, className) == 0) |
if (Tcscasecmp(p->classDecl->name, className) == 0) |
{ | { |
AtomicInc(&p->refCounter); |
Provider_Addref(p); |
return p; | return p; |
} | } |
} | } |
| |
|
#ifndef DISABLE_INDICATION |
|
/* Allocate SubscriptionManager along with Provider */ |
|
psize += sizeof( SubscriptionManager ); |
|
#endif |
|
|
/* New Provider */ | /* New Provider */ |
p = (Provider*)calloc(1, sizeof(Provider)); |
p = (Provider*)PAL_Calloc(1, psize); |
| |
if (!p) | if (!p) |
{ | { |
|
LOGD_ALLOC_OOM; |
return NULL; | return NULL; |
} | } |
| |
|
|
p->classDecl = SchemaDecl_FindClassDecl(self->module->schemaDecl, | p->classDecl = SchemaDecl_FindClassDecl(self->module->schemaDecl, |
className); | className); |
| |
if (!p->classDecl) |
if (!p->classDecl || (request->tag != GetClassReqTag && !p->classDecl->providerFT)) |
{ | { |
free(p); |
PAL_Free(p); |
return NULL; | return NULL; |
} | } |
} | } |
| |
/* Initialize context - used for indication providers */ |
#ifndef DISABLE_INDICATION |
Context_Init(&p->ctxIndications, 0); |
/* |
p->ctxIndications.chainType = CTX_TYPE_IND_NOTINITIALIZED; |
* Following picture explains memory layout of provider, |
|
* provider and submgr are sitting side by side, while |
|
* provider.submgr sets to the submgr's memory address |
|
* |
|
* |---------| |
|
* | Provider| |
|
* | ... | |
|
* | submgr* |---| |
|
* |---------|<--| |
|
* | submgr | |
|
* | | |
|
* |---------| |
|
*/ |
|
p->subMgr = (SubscriptionManager*)(p + 1); |
|
SubMgr_Init(p->subMgr, p); |
|
#endif |
| |
|
if(p->classDecl->providerFT) |
|
{ |
/* Call provider Load() method */ | /* Call provider Load() method */ |
if (p->classDecl->providerFT->Load) | if (p->classDecl->providerFT->Load) |
{ | { |
Context ctx; | Context ctx; |
MI_Result r = MI_RESULT_OK; | MI_Result r = MI_RESULT_OK; |
| |
Context_Init(&ctx, p); |
Context_Init(&ctx, p, NULL); |
ctx.result = &r; | ctx.result = &r; |
|
ctx.loadRequest = request; |
|
Message_AddRef(ctx.loadRequest); |
| |
(*p->classDecl->providerFT->Load)(&p->self, self->self, &ctx.base); | (*p->classDecl->providerFT->Load)(&p->self, self->self, &ctx.base); |
| |
DEBUG_ASSERT(ctx.magic == (MI_Uint32)-1); |
if (ctx.magic != 0xFFFFFFFF) |
|
{ |
|
trace_ProviderLoad_DidnotPostResult(); |
|
} |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGW((T("failed to call provider's load with result %d; class: %s"), (int)r, className)); |
trace_FailedProviderLoad(r, tcs(className)); |
free(p); |
PAL_Free(p); |
return NULL; | return NULL; |
} | } |
} | } |
|
} |
| |
/* Prepend to list */ | /* Prepend to list */ |
List_Prepend( | List_Prepend( |
|
|
return p; | return p; |
} | } |
| |
static MI_Result _GetProviderByClassName( |
/* |
ProvMgr* self, |
* Try to find specific provider (class) and open it if not found, |
const char* libraryName, |
* this function is thread-safely operate the provider list |
MI_ConstString cn, |
*/ |
Provider** provOut |
static Provider* MI_CALL _OpenProvider( |
) |
Library* self, |
|
const ZChar* className, |
|
Message* request) |
|
{ |
|
Provider* prov; |
|
Lock_Acquire( & self->provlock ); |
|
prov = _OpenProviderInternal( self, className, request ); |
|
Lock_Release( & self->provlock ); |
|
return prov; |
|
} |
|
|
|
static MI_Result MI_CALL _GetProviderByClassName( |
|
_In_ ProvMgr* self, |
|
_In_ const ProvRegEntry* proventry, |
|
_In_ MI_ConstString cn, |
|
_In_ Message* request, |
|
_Out_ Provider** provOut) |
{ | { |
Library* lib; | Library* lib; |
Provider* prov; | Provider* prov; |
| |
|
trace_GetProviderByClassName(tcs(cn)); |
|
|
/* Open the library */ | /* Open the library */ |
{ | { |
lib = _OpenLibrary(self, libraryName); |
lib = _OpenLibrary(self, proventry); |
| |
if (!lib) | if (!lib) |
{ | { |
LOGW_CHAR(("failed to open provider library: %s", libraryName)); |
trace_OpenProviderLib_Failed(scs(proventry->libraryName)); |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
} | } |
| |
/* Open the provider */ | /* Open the provider */ |
{ | { |
prov = _OpenProvider(lib, cn); |
prov = _OpenProvider(lib, cn, request); |
| |
if (!prov) | if (!prov) |
{ | { |
LOGW_CHAR(("failed to open the provider %s for class %s", |
trace_OpenProvider_FailedForClass(proventry->libraryName, tcs(cn)); |
libraryName, cn)); |
|
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
} | } |
|
|
MI_Instance* inst_in, | MI_Instance* inst_in, |
MI_Boolean keys_only, | MI_Boolean keys_only, |
MI_Boolean allow_keyless_inst, | MI_Boolean allow_keyless_inst, |
MI_Instance** instOut |
MI_Instance** instOut, |
|
MI_Uint32 flags |
) | ) |
{ | { |
MI_Instance* inst; | MI_Instance* inst; |
|
|
| |
if (!inst) | if (!inst) |
{ | { |
LOGF((T("allocation failed"))); |
trace_ProvMgr_AllocFailed(); |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
| |
#if 0 |
/* Convert instance name to provider's format (borrow storage) */ |
if (inst_in) |
r = Instance_InitConvert(inst, cd, inst_in, keys_only, allow_keyless_inst, MI_FALSE, |
|
batch, flags); |
|
|
|
if (r != MI_RESULT_OK) |
|
{ |
|
trace_InstanceConversionFailed(tcs(cd->name), r); |
|
return r; |
|
} |
|
|
|
*instOut = inst; |
|
return MI_RESULT_OK; |
|
} |
|
|
|
#ifndef DISABLE_INDICATION |
|
|
|
/* |
|
* Internal helper function for _Provider_InvokeSubscribe that expects all |
|
* validation to be done beforehand. |
|
*/ |
|
MI_Result _Provider_InvokeEnable( |
|
_Inout_ Provider* provider, |
|
_In_ SubscribeReq* msg ) |
{ | { |
printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); |
SubscriptionManager* subMgr = provider->subMgr; |
MI_Instance_Print(inst_in, stdout, 1); |
AggregationContext* aggrContext; |
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); |
|
|
trace_EnablingIndicationsForClass(provider->classDecl->name, provider); |
|
|
|
aggrContext = SubMgr_CreateAggrContext( subMgr ); |
|
if ( !aggrContext ) |
|
{ |
|
trace_AggregationContext_InitFailed(); |
|
return MI_RESULT_SERVER_LIMITS_EXCEEDED; |
|
} |
|
|
|
/* |
|
* Set enabled to true, which will be set to false if |
|
* posting result during EnableIndications call |
|
* |
|
*/ |
|
SubMgr_SetEnabled( subMgr, MI_TRUE ); |
|
|
|
(*provider->classDecl->providerFT->EnableIndications)( |
|
provider->self, |
|
&aggrContext->baseCtx.base, |
|
msg->nameSpace, |
|
msg->className); |
|
|
|
if ( MI_FALSE == SubMgr_IsEnabled(subMgr) ) |
|
{ |
|
/* |
|
* provider posted a final result during EnableIndications call, |
|
* Clean up already occurred during Post handling, return here |
|
* |
|
*/ |
|
trace_ProviderEnableIndication_Failed(); |
|
return MI_RESULT_FAILED; |
|
} |
|
|
|
return MI_RESULT_OK; |
|
} |
|
|
|
/* |
|
* Internal helper function for _Provider_RemoveSubscription that expects all |
|
* validation to be done beforehand. |
|
*/ |
|
_Use_decl_annotations_ |
|
MI_Result Provider_InvokeDisable( |
|
Provider* provider) |
|
{ |
|
MI_Result result = MI_RESULT_OK; |
|
SubscriptionManager* subMgr; |
|
MI_Boolean locked; |
|
|
|
DEBUG_ASSERT( provider ); |
|
|
|
subMgr = provider->subMgr; |
|
|
|
trace_Provider_InvokeDisable_Start( UintThreadID(), provider->classDecl->name, provider); |
|
|
|
locked = SubMgr_AcquireEnableLock( subMgr, AcquireFromDisable ); |
|
|
|
if ( MI_TRUE == locked ) |
|
{ |
|
MI_Boolean wasEnabled = MI_FALSE; |
|
if ( MI_TRUE == SubMgr_IsEnabled(subMgr) ) |
|
{ |
|
wasEnabled = MI_TRUE; |
|
SubMgr_SetEnabled(subMgr, MI_FALSE); |
|
} |
|
|
|
if ( provider->classDecl->flags & MI_FLAG_INDICATION ) |
|
{ |
|
AggregationContext* aggrContext = SubMgr_RemoveAggrContext( subMgr ); |
|
|
|
if ( MI_FALSE == SubMgr_IsTerminating( subMgr ) ) |
|
{ |
|
DEBUG_ASSERT( (MI_TRUE == wasEnabled) ? (NULL != aggrContext) : (NULL == aggrContext) ); |
|
|
|
if ( aggrContext && ( MI_TRUE == wasEnabled ) ) |
|
{ |
|
provider->classDecl->providerFT->DisableIndications( |
|
provider->self, |
|
&aggrContext->baseCtx.base, |
|
NULL, // TODO: Set this based on the initial SubscribeReq, but copy the value so its lifetime matches the context |
|
provider->classDecl->name ); |
|
} |
|
} |
|
// else don't need to invoke DisableIndications |
|
|
|
if ( aggrContext ) |
|
AggrContext_Delete( aggrContext ); |
|
} |
|
else |
|
{ |
|
// TODO: release lifecycle context |
|
} |
|
} |
|
else |
|
{ |
|
/* active subscription(s) added right before acquire the lock */ |
|
trace_Provider_InvokeDisable_AbandonSinceNewSubscriptionAdded( UintThreadID(), provider->classDecl->name, provider); |
|
return MI_RESULT_OK; |
|
} |
|
|
|
/* |
|
* Disabled the provider, reset flags, |
|
* new subscribe request will success. |
|
*/ |
|
SubMgr_SetTerminating( subMgr, MI_FALSE ); |
|
SubMgr_SetAllCancelledSafe( subMgr, MI_FALSE ); |
|
SubMgr_ReleaseEnableLock( subMgr ); |
|
|
|
trace_Provider_InvokeDisable_Complete( UintThreadID(), provider->classDecl->name, provider); |
|
return result; |
|
} |
|
|
|
void _Provider_SubscribeFail( |
|
_In_ SubscriptionContext* subscrContext, |
|
_In_ SubscribeReq* msg, |
|
_In_ MI_Result result ) |
|
{ |
|
// TODO: Replace this whole func with Cancel and propagate the result to the subscription context |
|
PostResultMsg* finalmsg = PostResultMsg_NewAndSerialize(&msg->base.base, NULL, NULL, MI_RESULT_TYPE_MI, result); |
|
if (finalmsg) |
|
{ |
|
Strand_SchedulePost(&subscrContext->baseCtx.strand,&finalmsg->base); |
|
PostResultMsg_Release(finalmsg); |
|
/* |
|
* subscribe failed and directly send final result to left side strand, |
|
* thus context.c:Context_PostMessageLeft won't be called, |
|
* so release the ref count added by SubscriptionContext.c:SubscrContext_Init |
|
*/ |
|
SubMgrSubscription_Release( subscrContext->subscription ); |
} | } |
|
else |
|
{ |
|
trace_OutOfMemory(); |
|
Strand_ScheduleCancel(&subscrContext->baseCtx.strand); |
|
} |
|
} |
|
|
|
_Use_decl_annotations_ |
|
void Provider_InvokeSubscribe( |
|
Provider* provider, |
|
SubscribeReq* msg, |
|
SubscriptionContext* subscrContext ) |
|
{ |
|
MI_Result result = MI_RESULT_OK; |
|
SubscriptionManager* subMgr; |
|
MI_Boolean locked; |
|
SubscriptionTargetType subType; |
|
SubMgrSubscription* subscription = NULL; |
|
|
|
DEBUG_ASSERT ( provider && subscrContext ); |
|
DEBUG_ASSERT( provider->subMgr ); |
|
STRAND_ASSERTONSTRAND(&subscrContext->baseCtx.strand); |
|
|
|
if( subscrContext->baseCtx.strand.canceled ) |
|
{ |
|
// abort creating subscription |
|
Strand_Leave( &subscrContext->baseCtx.strand ); |
|
return; |
|
} |
|
|
|
subMgr = provider->subMgr; |
|
subType = (SubscriptionTargetType)msg->targetType; |
|
|
|
do |
|
{ |
|
trace_ProviderInvokeSubscribe_Begin(UintThreadID(), provider, msg, msg->base.base.tag, subscrContext ); |
|
|
|
/* To ensure enable/cancel thread safe */ |
|
locked = SubMgr_AcquireEnableLock( subMgr, AcquireFromSubscribe ); |
|
if ( MI_FALSE == locked ) |
|
{ |
|
result = MI_RESULT_FAILED; |
|
Strand_Leave( &subscrContext->baseCtx.strand ); |
|
break; |
|
} |
|
|
|
/* |
|
* Sanity checks of the request prior to initializing the context and |
|
* completing the interaction open. |
|
* |
|
* These checks can return immediate failure without clean up |
|
*/ |
|
if (SUBSCRIP_TARGET_DEFAULT == subType ) |
|
{ |
|
/* |
|
* if class is not indication class, then indication manager has a bug |
|
*/ |
|
DEBUG_ASSERT (provider->classDecl->flags & MI_FLAG_INDICATION); |
|
/* |
|
* if classdecl is not valid, then omireg tool has a bug |
|
*/ |
|
DEBUG_ASSERT ( |
|
provider->classDecl->providerFT->EnableIndications && |
|
provider->classDecl->providerFT->Subscribe); |
|
} |
|
else if (SubscriptionTargetType_IsLifecycle( subType )) |
|
{ |
|
// lifecycleCtx should have been initialized during provider Load(). |
|
if ( ! subMgr->lifecycleCtx ) |
|
{ |
|
trace_LifecycleSubscription_ContextNotInitialized(provider->classDecl->name); |
|
result = MI_RESULT_FAILED; |
|
break; |
|
} |
|
|
|
if ( ! LifeContext_IsTypeSupported(subMgr->lifecycleCtx, msg->targetType) ) |
|
{ |
|
trace_LifecycleSubscription_UnsupportedTargetType( |
|
provider->classDecl->name, msg->targetType, subMgr->lifecycleCtx->supportedTypesFromProv); |
|
result = MI_RESULT_NOT_SUPPORTED; |
|
Strand_Leave( &subscrContext->baseCtx.strand ); |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
trace_InvokeSubscribeWithInvalidTargetType( subType ); |
|
result = MI_RESULT_FAILED; |
|
Strand_Leave( &subscrContext->baseCtx.strand ); |
|
break; |
|
} |
|
|
|
subscription = subscrContext->subscription; |
|
SubscriptionList_AddSubscription( &subMgr->subscrList, subscription ); |
|
|
|
/* |
|
* Upon SubscriptionContext was initialized successfull, |
|
* it hold one refcount of msg, which will be released |
|
* inside _Context_Destory; |
|
* |
|
* SubscriptionContext was initialized successfully, |
|
* following logic should report error through |
|
* interaction interface then. |
|
*/ |
|
|
|
/* |
|
* Acquire post lock, so post indication and result from provider's thread |
|
* will be blocked until Enable/Subscribe call finished |
|
* |
|
*/ |
|
SubMgrSubscription_Addref( subscription ); |
|
SubMgrSubscription_AcuquirePostLock( subscription ); |
|
|
|
/* Alert indication setup */ |
|
if (SUBSCRIP_TARGET_DEFAULT == msg->targetType ) |
|
{ |
|
SubMgr_SetEnableThread( subMgr ); |
|
|
|
Strand_Leave( &subscrContext->baseCtx.strand ); |
|
/* |
|
* EnableIndications must be called for each provider |
|
* prior to the first Subscribe call for alert indication |
|
*/ |
|
if ( MI_FALSE == SubMgr_IsEnabled( subMgr ) ) |
|
{ |
|
result = _Provider_InvokeEnable( provider, msg ); |
|
if (MI_RESULT_OK != result) |
|
{ |
|
trace_EnableIndication_Failed(provider->classDecl->name); |
|
result = MI_RESULT_OK; |
|
break; |
|
} |
|
} |
|
|
|
DEBUG_ASSERT (SubMgr_IsEnabled( subMgr )); |
|
|
|
SubMgrSubscription_SetState(subscription, SubscriptionState_Subscribed); |
|
|
|
/* |
|
* Invoke Subscribe with dummpy context |
|
* provider cannot postinstance or indication to this context |
|
*/ |
|
{ |
|
Context ctx; |
|
MI_Result r = MI_RESULT_OK; |
|
Subunsub_Context_Init(&ctx, &r, &msg->base); |
|
(*provider->classDecl->providerFT->Subscribe)( |
|
provider->self, |
|
&ctx.base, |
|
msg->nameSpace, |
|
msg->className, |
|
&subscrContext->subscription->filter->base, |
|
msg->bookmark, |
|
msg->subscriptionID, |
|
(void**)&subscrContext->subself); |
|
Context_Close(&ctx); |
|
} |
|
|
|
if (SubscriptionState_Subscribed == subscrContext->subscription->state) |
|
{ |
|
trace_Provider_InvokeSubscribe(subscrContext->subscription); |
|
|
|
/* |
|
* Subscribe succeeded, send subscribe response, |
|
* otherwise finalresult already sent within Subscribe call |
|
*/ |
|
SubscrContext_SendSubscribeResponseMsg( subscrContext ); |
|
|
|
#if defined(_MSC_VER) |
|
trace_SubscrForEvents_Succeeded_MSC(provider->classDecl->name, msg->subscriptionID); |
|
#else |
|
trace_SubscrForEvents_Succeeded(provider->classDecl->name, msg->subscriptionID); |
#endif | #endif |
|
result = MI_RESULT_OK; |
|
break; |
|
} |
|
} |
|
/* |
|
* Lifecycle indication setup |
|
*/ |
|
else if (SubscriptionTargetType_IsLifecycle( (SubscriptionTargetType)msg->targetType )) |
|
{ |
|
if ( MI_FALSE == SubMgr_IsEnabled( subMgr ) ) |
|
SubMgr_SetEnabled( subMgr, MI_TRUE ); |
| |
/* Convert instance name to provider's format (borrow storage) */ |
SubMgrSubscription_SetState( subscrContext->subscription, SubscriptionState_Subscribed ); |
r = Instance_InitConvert( |
|
inst, |
|
cd, |
|
inst_in, |
|
keys_only, |
|
allow_keyless_inst, |
|
MI_FALSE, |
|
batch); |
|
| |
if (r != MI_RESULT_OK) |
LifeContext_UpdateSupportedTypes( subMgr->lifecycleCtx ); |
|
|
|
Strand_Leave( &subscrContext->baseCtx.strand ); |
|
SubscrContext_SendSubscribeResponseMsg( subscrContext ); |
|
|
|
#if defined(_MSC_VER) |
|
trace_SubscrForLifecycle_Succeeded_MSC(provider->classDecl->name, msg->subscriptionID); |
|
#else |
|
trace_SubscrForLifecycle_Succeeded(provider->classDecl->name, msg->subscriptionID); |
|
#endif |
|
result = MI_RESULT_OK; |
|
break; |
|
} |
|
} |
|
while( 0 ); |
|
|
|
if ( subscription ) |
{ | { |
LOGW((T("instance conversion failed: %s, err %d"), cd->name, r)); |
/* |
return r; |
* Release post lock, so indication and result |
|
* posted from provider will go through |
|
*/ |
|
SubMgrSubscription_ReleasePostLock( subscription ); |
|
SubMgrSubscription_Release( subscription ); |
|
} |
|
|
|
/* |
|
* Now release lock to allow Disable/other subscribe reqeuest to conitune |
|
*/ |
|
if ( MI_TRUE == locked ) |
|
SubMgr_ReleaseEnableLock( subMgr ); |
|
|
|
trace_ProviderInvokeSubscribe_End(UintThreadID(), provider, result); |
|
|
|
/* |
|
* Once the SubscrContext has been initialized, the interactions is "Open" |
|
* and must be shut down using the appropriate Strand calls. Those calls |
|
* will handle clean up. This must return MI_RESULT_OK for that to happen. |
|
*/ |
|
if ( result != MI_RESULT_OK ) |
|
{ |
|
_Provider_SubscribeFail( subscrContext, msg, result ); |
|
} |
|
} |
|
|
|
/* |
|
* Invoke EnableIndication if not called yet; |
|
* and invoke Subscribe call to provider; |
|
* |
|
* To ensure enable/disable thread-safe, and since |
|
* OMI has single IO thread, this function has to be scheduled |
|
* on separate thread for OMI. |
|
* TODO: remove separate thread if have multi-IO threads implemented |
|
*/ |
|
MI_Result _Provider_InvokeSubscribeWrapper( |
|
_In_ Provider* provider, |
|
_Inout_ InteractionOpenParams* interactionParams ) |
|
{ |
|
SubscriptionContext* subscrContext; |
|
MI_Result result; |
|
|
|
result = SubMgr_CreateSubscription( provider->subMgr, provider, interactionParams, &subscrContext ); |
|
if ( MI_RESULT_OK != result ) |
|
{ |
|
trace_FailedToAddSubscrMgr(); |
|
return result; |
|
} |
|
|
|
//#if defined(_MSC_VER) |
|
// Strand_ScheduleAux( &(subscrContext->baseCtx.strand), CONTEXT_STRANDAUX_INVOKESUBSCRIBE ); |
|
//#else |
|
result = Schedule_SubscribeRequest( provider, (SubscribeReq*)interactionParams->msg, subscrContext ); |
|
if( MI_RESULT_OK != result ) |
|
{ |
|
_Provider_SubscribeFail( subscrContext, (SubscribeReq*)interactionParams->msg, result ); |
|
/* |
|
* schedule failed so CONTEXT_STRANDAUX_INVOKESUBSCRIBE won't be called, |
|
* so release the ref count added by _SubMgrSubscription_New |
|
*/ |
|
SubMgrSubscription_Release( subscrContext->subscription ); |
|
} |
|
//#endif |
|
|
|
return MI_RESULT_OK; |
|
} |
|
|
|
_Use_decl_annotations_ |
|
MI_Result Provider_RemoveSubscription( |
|
Provider* provider, |
|
MI_Uint64 subscriptionID) |
|
{ |
|
SubMgrSubscription* subscription = NULL; |
|
SubscriptionManager* subMgr; |
|
MI_Result result = MI_RESULT_OK; |
|
|
|
DEBUG_ASSERT (provider && provider->subMgr); |
|
subMgr = provider->subMgr; |
|
|
|
#if defined(_MSC_VER) |
|
trace_RemovingSubscriptionForClass_MSC(subscriptionID, provider->classDecl->name); |
|
#else |
|
trace_RemovingSubscriptionForClass(subscriptionID, provider->classDecl->name); |
|
#endif |
|
|
|
subscription = SubMgr_GetSubscription( subMgr, subscriptionID ); |
|
if (NULL == subscription) |
|
{ |
|
/* Not present or not found means that there is nothing to do. */ |
|
return MI_RESULT_OK; |
|
} |
|
|
|
SubMgrSubscription_SetState(subscription, SubscriptionState_Unsubscribed); |
|
|
|
result = SubMgr_DeleteSubscription( subMgr, subscription); |
|
|
|
/* check if the subscription list was empty or not */ |
|
if ( MI_TRUE == SubMgr_IsSubListEmpty( subMgr ) ) |
|
{ |
|
/* |
|
* The specified subscription is the LAST one for its |
|
* SubscriptionManager. Indications should be disabled for this |
|
* provider. There is separate cleanup for Lifecycle and "normal" |
|
* indications. SubscriptionManager will be cleaned up once the |
|
* provider processes the Disable call. |
|
*/ |
|
result = Provider_InvokeDisable ( provider ); |
} | } |
| |
*instOut = inst; |
return result; |
|
} |
|
|
|
_Use_decl_annotations_ |
|
MI_Result Provider_TerminateIndication( |
|
Provider* provider, |
|
MI_Result result, |
|
const ZChar* errorMessage, |
|
const MI_Instance* cimError ) |
|
{ |
|
SubscriptionManager* subMgr; |
|
MI_Boolean locked; |
|
DEBUG_ASSERT (provider && provider->subMgr); |
|
|
|
trace_Provider_TerminateIndication_Start( UintThreadID(), provider->classDecl->name, provider); |
|
|
|
Provider_Addref( provider ); |
|
|
|
subMgr = provider->subMgr; |
|
|
|
/* |
|
* SubMgr_AcquireEnableLock cancel all subscriptions if have any, |
|
* internally it call Provider_InvokeDisable if no subscription; |
|
* otherwise just return; |
|
* Provider_InvokeDisable releases the aggregation context; |
|
*/ |
|
locked = SubMgr_AcquireEnableLock( subMgr, AcquireFromTerminate ); |
|
DEBUG_ASSERT( MI_TRUE == locked ); |
|
SubMgr_ReleaseEnableLock( subMgr ); |
|
|
|
trace_Provider_TerminateIndication_Complete( UintThreadID(), provider->classDecl->name, provider); |
|
|
|
Provider_Release( provider ); |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
|
#endif /* ifndef DISABLE_INDICATION */ |
|
|
static MI_Result _HandleGetInstanceReq( | static MI_Result _HandleGetInstanceReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
GetInstanceReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
MI_Instance* inst; | MI_Instance* inst; |
MI_Result r; | MI_Result r; |
const MI_Char* className; |
const ZChar* className; |
|
GetInstanceReq* msg = (GetInstanceReq*)interactionParams->msg; |
| |
/* Get classname from instance */ | /* Get classname from instance */ |
r = __MI_Instance_GetClassName(msg->instanceName, &className); | r = __MI_Instance_GetClassName(msg->instanceName, &className); |
|
|
return r; | return r; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName(self, libraryName, className, prov); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
/* Allocate the instance for the provider */ | /* Allocate the instance for the provider */ |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
(*prov)->classDecl, | (*prov)->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instanceName, | msg->instanceName, |
MI_TRUE, | MI_TRUE, |
MI_FALSE, | MI_FALSE, |
&inst ); |
&inst, |
|
msg->base.base.flags); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
return r; | return r; |
| |
#if 0 | #if 0 |
/* Print instance */ | /* Print instance */ |
Instance_Print(inst, stdout, 0); |
Instance_Print(inst, stdout, 0, MI_FALSE, MI_FALSE); |
#endif | #endif |
| |
/* If provider's GetInstance method null, use EnumerateInstances */ | /* If provider's GetInstance method null, use EnumerateInstances */ |
|
|
return MI_RESULT_INVALID_CLASS; | return MI_RESULT_INVALID_CLASS; |
| |
/* Create context */ | /* Create context */ |
ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));; |
ctx = (Context*)Batch_GetClear(msg->base.base.batch, sizeof(Context));; |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
| |
/* _PostInstance() filters by this if not null */ | /* _PostInstance() filters by this if not null */ |
ctx->instanceName = inst; | ctx->instanceName = inst; |
| |
/* message will be freed in context release*/ |
|
Message_AddRef(&msg->base); |
|
|
|
/* Invoke provider */ | /* Invoke provider */ |
(*(*prov)->classDecl->providerFT->EnumerateInstances)( | (*(*prov)->classDecl->providerFT->EnumerateInstances)( |
(*prov)->self, | (*prov)->self, |
|
|
Context* ctx; | Context* ctx; |
| |
/* Create context */ | /* Create context */ |
ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));; |
ctx = (Context*)Batch_GetClear(msg->base.base.batch, sizeof(Context));; |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
/* message will be freed in context release*/ |
|
Message_AddRef(&msg->base); |
|
| |
/* Invoke provider */ | /* Invoke provider */ |
(*(*prov)->classDecl->providerFT->GetInstance)( | (*(*prov)->classDecl->providerFT->GetInstance)( |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
|
static void _PostClassToCallback( |
|
Context* self, |
|
InteractionOpenParams* params, |
|
const MI_Class* schema) |
|
{ |
|
MI_Result result = MI_RESULT_OK; |
|
PostSchemaMsg* resp = PostSchemaMsg_New(self->request->base.operationId); |
|
|
|
if (!resp) |
|
{ |
|
trace_PostSchemaMsg_Failed(); |
|
result = MI_RESULT_FAILED; |
|
goto End; |
|
} |
|
|
|
if (self->request->base.flags & WSMANFlag) |
|
{ |
|
result = WSBuf_ClassToBuf( |
|
schema, |
|
self->request->base.flags, |
|
resp->base.batch, |
|
&resp->packedSchemaWsmanPtr, |
|
&resp->packedSchemaWsmanSize); |
|
|
|
trace_ProvMgr_PostingSchemaInWsmanToCallback(); |
|
|
|
if(result != MI_RESULT_OK) |
|
{ |
|
trace_SchemaConversion_ToCimXmlFailed(result); |
|
goto End; |
|
} |
|
|
|
resp->base.flags |= self->request->base.flags; |
|
} |
|
else |
|
{ |
|
result = Instance_New(&resp->schemaInstance, schema->classDecl, resp->base.batch); |
|
if (result != MI_RESULT_OK) |
|
{ |
|
trace_SchemaConversion_ToInstanceFailed(result); |
|
goto End; |
|
} |
|
|
|
result = InstanceToBatch( |
|
resp->schemaInstance, |
|
NULL, |
|
NULL, |
|
resp->base.batch, |
|
&resp->packedSchemaInstancePtr, |
|
&resp->packedSchemaInstanceSize); |
|
if (result != MI_RESULT_OK) |
|
{ |
|
trace_SchemaInstancePackaging_Failed(result); |
|
goto End; |
|
} |
|
|
|
resp->base.flags |= BinaryProtocolFlag; |
|
} |
|
|
|
Context_CompleteOpen( self, params, MI_RESULT_OK ); |
|
Context_PostSchema( self, &resp->base); |
|
{ |
|
PostResultMsg* msg = PostResultMsg_New( self->request->base.operationId ); |
|
if (msg) |
|
{ |
|
Context_PostMessageLeft( self, &msg->base ); |
|
PostResultMsg_Release( msg ); |
|
} |
|
} |
|
|
|
Strand_ScheduleClose(&self->strand); |
|
End: |
|
if(resp) |
|
{ |
|
PostSchemaMsg_Release(resp); |
|
} |
|
|
|
if( MI_RESULT_OK != result ) |
|
{ |
|
Context_CompleteOpen( self, params, result ); |
|
} |
|
} |
|
|
|
|
|
static MI_Result _HandleGetClassReq( |
|
_In_ ProvMgr* self, |
|
_In_ const ProvRegEntry* proventry, |
|
_Inout_ InteractionOpenParams* interactionParams, |
|
_Out_ Provider** prov) |
|
{ |
|
MI_Result r; |
|
MI_Class resultClass; |
|
Context* ctx = NULL; |
|
GetClassReq* msg = (GetClassReq*)interactionParams->msg; |
|
|
|
trace_ProvMgr_GetClassReq(tcs(msg->className), tcs(msg->nameSpace)); |
|
|
|
memset(&resultClass, 0, sizeof(MI_Class)); |
|
|
|
/* find provider */ |
|
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
msg->className, |
|
&msg->base.base, |
|
prov); |
|
|
|
if ( MI_RESULT_OK != r ) |
|
return r; |
|
|
|
ctx = (Context*)Batch_GetClear(msg->base.base.batch, |
|
sizeof(Context));; |
|
r = Context_PartialInit(ctx, (*prov), interactionParams); |
|
if( MI_RESULT_OK != r ) |
|
return r; |
|
|
|
// by default serializer will use the function tables to access resultClass as a wrapper to MI_ClassDecl |
|
// this place will be modified in future to fill in the appropriate extended function tables |
|
// providing access to schema in form of instance of cimclass |
|
Class_Construct(&resultClass, (*prov)->classDecl); |
|
|
|
_PostClassToCallback(ctx, interactionParams, &resultClass); |
|
return MI_RESULT_OK; |
|
} |
|
|
static MI_Result _HandleCreateInstanceReq( | static MI_Result _HandleCreateInstanceReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
CreateInstanceReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
MI_Instance* inst; | MI_Instance* inst; |
MI_Result r; | MI_Result r; |
const MI_Char* className; |
const ZChar* className; |
|
CreateInstanceReq* msg = (CreateInstanceReq*)interactionParams->msg; |
| |
/* Get classname from instance */ | /* Get classname from instance */ |
r = __MI_Instance_GetClassName(msg->instance, &className); | r = __MI_Instance_GetClassName(msg->instance, &className); |
|
|
return r; | return r; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName(self, libraryName, className, prov); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
/* Allocate the instance for the provider */ | /* Allocate the instance for the provider */ |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
(*prov)->classDecl, | (*prov)->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instance, | msg->instance, |
MI_FALSE, | MI_FALSE, |
MI_TRUE, | MI_TRUE, |
&inst ); |
&inst, |
|
msg->base.base.flags); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
return r; | return r; |
|
|
return MI_RESULT_INVALID_CLASS; | return MI_RESULT_INVALID_CLASS; |
| |
{ | { |
Context* ctx = (Context*)Batch_GetClear(msg->base.batch, |
Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch, |
sizeof(Context));; | sizeof(Context));; |
Context_Init(ctx, (*prov)); |
Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
|
|
/* message will be freed in context release*/ | /* message will be freed in context release*/ |
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->CreateInstance)((*prov)->self, &ctx->base, | (*(*prov)->classDecl->providerFT->CreateInstance)((*prov)->self, &ctx->base, |
msg->nameSpace, className, inst); | msg->nameSpace, className, inst); |
} | } |
|
|
} | } |
| |
static MI_Result _HandleModifyInstanceReq( | static MI_Result _HandleModifyInstanceReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
ModifyInstanceReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
MI_Instance* inst; | MI_Instance* inst; |
MI_Result r; | MI_Result r; |
const MI_Char* className; |
const ZChar* className; |
|
ModifyInstanceReq* msg = (ModifyInstanceReq*)interactionParams->msg; |
| |
/* Get classname from instance */ | /* Get classname from instance */ |
r = __MI_Instance_GetClassName(msg->instance, &className); | r = __MI_Instance_GetClassName(msg->instance, &className); |
|
|
return r; | return r; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName(self, libraryName, className, prov); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
/* Allocate the instance for the provider */ | /* Allocate the instance for the provider */ |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
(*prov)->classDecl, | (*prov)->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instance, | msg->instance, |
MI_FALSE, | MI_FALSE, |
MI_FALSE, | MI_FALSE, |
&inst ); |
&inst, |
|
msg->base.base.flags); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
return r; | return r; |
|
|
return MI_RESULT_INVALID_CLASS; | return MI_RESULT_INVALID_CLASS; |
| |
{ | { |
Context* ctx = (Context*)Batch_GetClear(msg->base.batch, |
Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch, |
sizeof(Context));; | sizeof(Context));; |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
|
|
|
/* Need to store instance in case we need to call GetInstance */ |
|
ctx->keyInstance = inst; |
|
|
/* message will be freed in context release*/ | /* message will be freed in context release*/ |
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->ModifyInstance)((*prov)->self, &ctx->base, | (*(*prov)->classDecl->providerFT->ModifyInstance)((*prov)->self, &ctx->base, |
msg->nameSpace, className, inst, NULL); | msg->nameSpace, className, inst, NULL); |
} | } |
|
|
} | } |
| |
static MI_Result _HandleDeleteInstanceReq( | static MI_Result _HandleDeleteInstanceReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
DeleteInstanceReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
MI_Instance* inst; | MI_Instance* inst; |
MI_Result r; | MI_Result r; |
const MI_Char* className; |
const ZChar* className; |
|
DeleteInstanceReq* msg = (DeleteInstanceReq*)interactionParams->msg; |
| |
/* Get classname from instance */ | /* Get classname from instance */ |
r = __MI_Instance_GetClassName(msg->instanceName, &className); | r = __MI_Instance_GetClassName(msg->instanceName, &className); |
|
|
return r; | return r; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName(self, libraryName, className, prov); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
/* Allocate the instance for the provider */ | /* Allocate the instance for the provider */ |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
(*prov)->classDecl, | (*prov)->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instanceName, | msg->instanceName, |
MI_TRUE, | MI_TRUE, |
MI_FALSE, | MI_FALSE, |
&inst); |
&inst, |
|
msg->base.base.flags); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
return r; | return r; |
|
|
return MI_RESULT_INVALID_CLASS; | return MI_RESULT_INVALID_CLASS; |
| |
{ | { |
Context* ctx = (Context*)Batch_GetClear(msg->base.batch, |
Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch, |
sizeof(Context));; | sizeof(Context));; |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
|
|
/* message will be freed in context release*/ | /* message will be freed in context release*/ |
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->DeleteInstance)((*prov)->self, &ctx->base, | (*(*prov)->classDecl->providerFT->DeleteInstance)((*prov)->self, &ctx->base, |
msg->nameSpace, className, inst); | msg->nameSpace, className, inst); |
} | } |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
|
#ifndef DISABLE_INDICATION |
|
|
|
/* |
|
* Behaves conditionally depending on whether or not indications were |
|
* compiled into the product. |
|
*/ |
static MI_Result _HandleSubscribeReq( | static MI_Result _HandleSubscribeReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
SubscribeReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
MI_Result r; | MI_Result r; |
|
SubscribeReq* msg = (SubscribeReq*)interactionParams->msg; |
|
|
|
*prov = NULL; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName( self, libraryName, msg->className, prov ); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
msg->className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; |
|
|
|
/* Invoke provider */ |
|
if (!(*prov)->classDecl->providerFT->EnableIndications || !(*prov)->classDecl->providerFT->Subscribe) |
|
return MI_RESULT_INVALID_CLASS; |
|
|
|
if ((*prov)->ctxIndications.chainType == CTX_TYPE_IND_NOTINITIALIZED) |
|
{ | { |
/* have to initialize provider first */ |
trace_ProvMgr_ClassNotFound( tcs(msg->className) ); |
(*prov)->ctxIndications.chainType = CTX_TYPE_IND_READY; |
return r; |
|
|
(*prov)->classDecl->providerFT->EnableIndications((*prov)->self, |
|
&(*prov)->ctxIndications.base, msg->nameSpace, msg->className); |
|
} | } |
| |
if ((*prov)->ctxIndications.chainType == CTX_TYPE_IND_READY) |
return _Provider_InvokeSubscribeWrapper( *prov, interactionParams ); |
{ |
|
/* provider is ready for subscriptions */ |
|
Context* ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context)); |
|
Context_Init(ctx, (*prov)); |
|
ctx->request = &msg->base; |
|
/* message will be freed in context release*/ |
|
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->Subscribe)((*prov)->self, &ctx->base, |
|
msg->nameSpace, msg->className, 0, __bookmark, msg->subscriptionID, |
|
__subscriptionSelfPtr); |
|
} | } |
else |
|
return MI_RESULT_FAILED; /* unexpected state */ |
|
| |
return MI_RESULT_OK; |
#endif /* ifndef DISABLE_INDICATION */ |
} |
|
| |
static MI_Result _HandleInvokeReq( | static MI_Result _HandleInvokeReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
InvokeReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
MI_Instance* inst = 0; | MI_Instance* inst = 0; |
MI_Instance* instParams = 0; | MI_Instance* instParams = 0; |
MI_Result r; | MI_Result r; |
MI_ConstString cn = 0; | MI_ConstString cn = 0; |
MI_MethodDecl* md = 0; | MI_MethodDecl* md = 0; |
|
InvokeReq* msg = (InvokeReq*)interactionParams->msg; |
|
|
|
#if 0 |
|
MessagePrint(&msg->base, stdout); |
|
#endif |
| |
/* parameter validation */ | /* parameter validation */ |
if (!msg || !msg->function) | if (!msg || !msg->function) |
|
|
return MI_RESULT_INVALID_CLASS; | return MI_RESULT_INVALID_CLASS; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName( self, libraryName, cn, prov ); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
cn, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
|
|
{ | { |
| |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
(*prov)->classDecl, | (*prov)->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instance, | msg->instance, |
MI_TRUE, | MI_TRUE, |
MI_FALSE, | MI_FALSE, |
&inst ); |
&inst, |
|
msg->base.base.flags); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
return r; | return r; |
|
|
{ | { |
/* paramters (if any) */ | /* paramters (if any) */ |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
(const MI_ClassDecl*)md, | (const MI_ClassDecl*)md, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instanceParams, | msg->instanceParams, |
MI_FALSE, | MI_FALSE, |
MI_TRUE, | MI_TRUE, |
&instParams ); |
&instParams, |
|
msg->base.base.flags); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
return r; | return r; |
|
|
| |
#if 0 | #if 0 |
/* Print instance */ | /* Print instance */ |
Instance_Print(inst, stdout, 0); |
Instance_Print(inst, stdout, 0, 0, 0); |
#endif | #endif |
| |
/* Invoke provider */ | /* Invoke provider */ |
|
|
return MI_RESULT_INVALID_CLASS; | return MI_RESULT_INVALID_CLASS; |
| |
{ | { |
Context* ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));; |
Context* ctx = (Context*)Batch_GetClear(msg->base.base.batch, sizeof(Context)); |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
/* message will be freed in context release*/ |
return r; |
Message_AddRef(&msg->base); |
|
| |
/* call get first if fn is non-static */ | /* call get first if fn is non-static */ |
/*if (inst && (*prov)->classDecl->providerFT->GetInstance) | /*if (inst && (*prov)->classDecl->providerFT->GetInstance) |
{ | { |
ctx->chainType = CTX_TYPE_INVOKE_WITH_INSTANCE; |
ctx->ctxType = CTX_TYPE_INVOKE_WITH_INSTANCE; |
ctx->inst = inst; | ctx->inst = inst; |
ctx->instParams = instParams; | ctx->instParams = instParams; |
ctx->md = md; | ctx->md = md; |
|
|
} | } |
| |
static MI_Result _HandleEnumerateInstancesReq( | static MI_Result _HandleEnumerateInstancesReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
EnumerateInstancesReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
Context* ctx; | Context* ctx; |
MI_Result r; | MI_Result r; |
|
EnumerateInstancesReq* msg = (EnumerateInstancesReq*)interactionParams->msg; |
|
InstanceFilter* instanceFilter = NULL; |
|
MI_Filter* filter = NULL; |
|
|
|
#if 0 |
|
MessagePrint(&msg->base, stdout); |
|
#endif |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName( self, libraryName, msg->className, prov ); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
msg->className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
|
DEBUG_ASSERT(msg->wql == NULL); |
|
|
|
/* Get WQL query, if any */ |
|
if (msg->queryLanguage != NULL && msg->queryExpression != NULL) |
|
{ |
|
/* Create filter then Get WQL query */ |
|
instanceFilter = InstanceFilter_New( &(msg->base.base) ); |
|
|
|
if (instanceFilter == NULL) |
|
{ |
|
trace_InstanceFilter_AllocFailed(); |
|
return MI_RESULT_INVALID_QUERY; |
|
} |
|
|
|
filter = &(instanceFilter->base); |
|
|
|
msg->wql = InstanceFilter_GetWQL(instanceFilter); |
|
} |
|
|
/* Validate WQL query (if any) against provider's class declaration */ | /* Validate WQL query (if any) against provider's class declaration */ |
if (msg->wql) | if (msg->wql) |
{ | { |
if (WQL_Validate(msg->wql, (*prov)->classDecl) != 0) | if (WQL_Validate(msg->wql, (*prov)->classDecl) != 0) |
{ | { |
LOGW((T("query validation failed: %s"), msg->wql->text)); |
trace_QueryValidationFailed(tcs(msg->wql->text)); |
return MI_RESULT_INVALID_QUERY; | return MI_RESULT_INVALID_QUERY; |
} | } |
} | } |
|
|
/* Create the context object */ | /* Create the context object */ |
{ | { |
ctx = (Context*)Batch_GetClear( | ctx = (Context*)Batch_GetClear( |
msg->base.batch, sizeof(Context));; |
msg->base.base.batch, sizeof(Context));; |
| |
if (!ctx) | if (!ctx) |
{ | { |
LOGF((T("allocation failed"))); |
trace_ProvMgr_AllocFailed(); |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
| |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
|
|
if( MI_RESULT_OK != r ) |
|
return r; |
} | } |
| |
LOGD((T("enumerate instances of %s"), msg->className)); |
trace_ProvMgr_EnumerateInstancesOfClass( tcs(msg->className) ); |
| |
/* message will be freed in context release */ |
|
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->EnumerateInstances)( | (*(*prov)->classDecl->providerFT->EnumerateInstances)( |
(*prov)->self, &ctx->base, | (*prov)->self, &ctx->base, |
msg->nameSpace, msg->className, NULL, MI_FALSE, NULL); |
msg->nameSpace, msg->className, NULL, MI_FALSE, filter); |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
static MI_Result _HandleAssociatorsOfReq( |
static MI_Result MI_CALL _HandleAssociatorsOfReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
AssociatorsOfReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
Context* ctx; | Context* ctx; |
MI_Result r; | MI_Result r; |
MI_Instance* inst = 0; | MI_Instance* inst = 0; |
|
AssociationsOfReq* msg = (AssociationsOfReq*)interactionParams->msg; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName( self, libraryName, msg->className, prov ); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
msg->className, |
|
&msg->base.base, |
|
prov); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
|
|
{ | { |
Provider* provInst = 0; | Provider* provInst = 0; |
| |
r = _GetProviderByClassName( self, libraryName, ((Instance*) msg->instance)->classDecl->name, &provInst ); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
((Instance*) msg->instance)->classDecl->name, |
|
&msg->base.base, |
|
&provInst ); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
provInst->classDecl, | provInst->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instance, | msg->instance, |
MI_TRUE, | MI_TRUE, |
MI_FALSE, | MI_FALSE, |
&inst ); |
&inst, |
|
msg->base.base.flags); |
| |
Provider_Release(provInst); | Provider_Release(provInst); |
| |
|
|
} | } |
| |
ctx = (Context*)Batch_GetClear( | ctx = (Context*)Batch_GetClear( |
msg->base.batch, sizeof(Context));; |
msg->base.base.batch, sizeof(Context));; |
| |
if (!ctx) | if (!ctx) |
{ | { |
LOGF((T("allocation failed"))); |
trace_ProvMgr_AllocFailed(); |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
| |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
| |
/* message will be freed in context release */ | /* message will be freed in context release */ |
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->AssociatorInstances)( | (*(*prov)->classDecl->providerFT->AssociatorInstances)( |
(*prov)->self, | (*prov)->self, |
&ctx->base, | &ctx->base, |
|
|
} | } |
| |
static MI_Result _HandleReferencesOfReq( | static MI_Result _HandleReferencesOfReq( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
ReferencesOfReq* msg, |
_Inout_ InteractionOpenParams* interactionParams, |
Provider** prov) |
_Out_ Provider** prov) |
{ | { |
Context* ctx; | Context* ctx; |
MI_Result r; | MI_Result r; |
MI_Instance* inst = 0; | MI_Instance* inst = 0; |
|
AssociationsOfReq* msg = (AssociationsOfReq*)interactionParams->msg; |
| |
/* find provider */ | /* find provider */ |
r = _GetProviderByClassName( self, libraryName, msg->className, prov ); |
r = _GetProviderByClassName( |
|
self, |
|
proventry, |
|
msg->className, |
|
&msg->base.base, |
|
prov ); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
|
|
| |
r = _GetProviderByClassName( | r = _GetProviderByClassName( |
self, | self, |
libraryName, |
proventry, |
((Instance*) msg->instance)->classDecl->name, | ((Instance*) msg->instance)->classDecl->name, |
|
&msg->base.base, |
&provInst ); | &provInst ); |
| |
if ( MI_RESULT_OK != r ) | if ( MI_RESULT_OK != r ) |
return r; | return r; |
| |
r = _Instance_InitConvert_FromBatch( | r = _Instance_InitConvert_FromBatch( |
msg->base.batch, |
msg->base.base.batch, |
provInst->classDecl, | provInst->classDecl, |
(*prov)->lib->module->schemaDecl, | (*prov)->lib->module->schemaDecl, |
msg->instance, | msg->instance, |
MI_TRUE, | MI_TRUE, |
MI_FALSE, | MI_FALSE, |
&inst ); |
&inst, |
|
msg->base.base.flags); |
| |
Provider_Release(provInst); | Provider_Release(provInst); |
| |
|
|
} | } |
| |
ctx = (Context*)Batch_GetClear( | ctx = (Context*)Batch_GetClear( |
msg->base.batch, sizeof(Context));; |
msg->base.base.batch, sizeof(Context));; |
| |
if (!ctx) | if (!ctx) |
{ | { |
LOGF((T("allocation failed"))); |
trace_ProvMgr_AllocFailed(); |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
| |
Context_Init(ctx, (*prov)); |
r = Context_Init(ctx, (*prov), interactionParams); |
ctx->request = &msg->base; |
if( MI_RESULT_OK != r ) |
|
return r; |
| |
/* message will be freed in context release */ | /* message will be freed in context release */ |
Message_AddRef(&msg->base); |
|
(*(*prov)->classDecl->providerFT->ReferenceInstances)( | (*(*prov)->classDecl->providerFT->ReferenceInstances)( |
(*prov)->self, | (*prov)->self, |
&ctx->base, | &ctx->base, |
|
|
| |
for (p = lib->head; p; ) | for (p = lib->head; p; ) |
{ | { |
MI_Uint64 provFireAtTime = p->idleSince + self->idleTimeoutUsec; |
/* ATTN: idleSince is sometimes 0 */ |
|
|
|
MI_Uint64 provFireAtTime; |
|
if (p->idleSince != 0) |
|
provFireAtTime = p->idleSince + self->idleTimeoutUsec; |
|
else |
|
provFireAtTime = ~((MI_Uint64)0); |
| |
p_next = p->next; | p_next = p->next; |
| |
|
|
if (!idleOnly || | if (!idleOnly || |
(!p->refusedUnload && 0 == p->refCounter && provFireAtTime <= currentTimeUsec)) | (!p->refusedUnload && 0 == p->refCounter && provFireAtTime <= currentTimeUsec)) |
{ | { |
LOGD((T("Unloading provider %s"), p->classDecl->name)); |
trace_ProvMgr_UnloadingProvider( tcs(p->classDecl->name) ); |
|
|
|
#ifndef DISABLE_INDICATION |
|
if (p->subMgr) |
|
{ |
|
if (p->subMgr->lifecycleCtx) |
|
{ |
|
LifeContext_Delete(p->subMgr->lifecycleCtx); |
|
p->subMgr->lifecycleCtx = NULL; |
|
} |
|
} |
|
#endif /* ifndef DISABLE_INDICATION */ |
| |
/* Call provider unload() method */ | /* Call provider unload() method */ |
if (p->classDecl->providerFT->Unload) |
if (p->classDecl->providerFT && p->classDecl->providerFT->Unload) |
{ | { |
Context ctx; | Context ctx; |
Context_Init(&ctx, 0); |
Context_Init(&ctx, 0, NULL); |
(*p->classDecl->providerFT->Unload)(p->self, &ctx.base); | (*p->classDecl->providerFT->Unload)(p->self, &ctx.base); |
| |
DEBUG_ASSERT(ctx.magic == (MI_Uint32)-1); | DEBUG_ASSERT(ctx.magic == (MI_Uint32)-1); |
} | } |
| |
Context_Destroy(&p->ctxIndications); |
|
|
|
if (p->refCounter != 0) | if (p->refCounter != 0) |
{ | { |
/* Error condition - unloading active rpovider! */ | /* Error condition - unloading active rpovider! */ |
LOGE((T("Unloading active provider %s, with ref counter %d"), p->classDecl->name, (int)p->refCounter)); |
trace_UnloadingActiveProvider( |
LOGE_CHAR(("Unloading active provider for lib %s, with ref counter %d", lib->libraryName, (int)p->refCounter)); |
tcs(p->classDecl->name), (int)p->refCounter); |
|
trace_UnloadingActiveProviderWithLib( |
|
scs(lib->libraryName), (int)p->refCounter); |
| |
// ATTN: _exit is a good option here, since provider's behavior maybe undefined |
/* ATTN: _exit is a good option here, since provider's behavior maybe undefined */ |
|
trace_UnloadingActiveProvider_ServerExit(scs(lib->libraryName)); |
_exit(1); | _exit(1); |
} | } |
| |
|
|
(ListElem**)&lib->tail, | (ListElem**)&lib->tail, |
(ListElem*)p); | (ListElem*)p); |
| |
free(p); |
Provider_Finalize( p ); |
|
PAL_Free(p); |
} | } |
else if (idleOnly && 0 == p->refCounter && nextFireAtTime) | else if (idleOnly && 0 == p->refCounter && nextFireAtTime) |
{ | { |
|
|
} | } |
} | } |
| |
static void _UnloadAllLibraries( |
/* |
|
* Unload all libraries *NOT* thread safely |
|
*/ |
|
static void _UnloadAllLibrariesInternal( |
ProvMgr* self, | ProvMgr* self, |
MI_Boolean idleOnly, | MI_Boolean idleOnly, |
MI_Uint64 currentTimeUsec, | MI_Uint64 currentTimeUsec, |
|
|
{ | { |
p_next = p->next; | p_next = p->next; |
| |
|
Lock_Acquire( &p->provlock ); |
_UnloadAllProviders(self,p,idleOnly,currentTimeUsec,nextFireAtTime); | _UnloadAllProviders(self,p,idleOnly,currentTimeUsec,nextFireAtTime); |
|
Lock_Release( &p->provlock ); |
| |
/* Unload libraries that have no loaded providers */ | /* Unload libraries that have no loaded providers */ |
if (!p->head) | if (!p->head) |
|
|
if (p->module->Unload) | if (p->module->Unload) |
{ | { |
Context ctx; | Context ctx; |
Context_Init(&ctx, 0); |
MI_Result r = MI_RESULT_OK; |
|
|
|
Context_Init(&ctx, NULL, NULL); |
|
ctx.result = &r; |
|
|
(p->module->Unload)(p->self, (MI_Context*)&ctx); | (p->module->Unload)(p->self, (MI_Context*)&ctx); |
Context_Destroy(&ctx); |
|
|
if (ctx.magic != 0xFFFFFFFF) |
|
{ |
|
trace_LibraryUnload_DidnotPostResult(); |
|
} |
|
|
|
if (MI_RESULT_OK != r) |
|
{ |
|
trace_FailedCallLibraryUnload(r, scs(p->libraryName)); |
|
} |
} | } |
| |
Lib_Close(p->handle); |
Shlib_Close(p->handle); |
LOGD_CHAR(("Unloading lib %s", p->libraryName)); |
trace_ProvMgr_UnloadingLibrary( scs(p->libraryName) ); |
| |
List_Remove( | List_Remove( |
(ListElem**)&self->head, | (ListElem**)&self->head, |
(ListElem**)&self->tail, | (ListElem**)&self->tail, |
(ListElem*)p); | (ListElem*)p); |
| |
free(p); |
PAL_Free(p); |
} | } |
| |
p = p_next; | p = p_next; |
|
|
} | } |
| |
/* | /* |
Timeout handler: unloads idle providers and libraris, |
* Unload all libraries thread safely |
|
*/ |
|
static void _UnloadAllLibraries( |
|
ProvMgr* self, |
|
MI_Boolean idleOnly, |
|
MI_Uint64 currentTimeUsec, |
|
MI_Uint64* nextFireAtTime) |
|
{ |
|
Lock_Acquire( &self->liblock ); |
|
_UnloadAllLibrariesInternal( self, idleOnly, currentTimeUsec, nextFireAtTime ); |
|
|
|
// If all libraries are gone, notify caller |
|
if (!self->head && self->idleCallback) |
|
(*self->idleCallback)(self,self->idleCallbackData); |
|
|
|
Lock_Release( &self->liblock ); |
|
} |
|
|
|
/* |
|
Timeout handler: unloads idle providers and libraries, |
re-calculates new timeout (for next provider), | re-calculates new timeout (for next provider), |
notifies server/agent if all libraries are unloaded | notifies server/agent if all libraries are unloaded |
*/ | */ |
|
|
MI_Uint64 nextFireAtTime = u64max; | MI_Uint64 nextFireAtTime = u64max; |
| |
/* Unload all idle providers */ | /* Unload all idle providers */ |
//LOGI((T("Unloading idle providers"))); |
/* trace_UnloadingIdleProviders(); */ |
| |
_UnloadAllLibraries(self, MI_TRUE, currentTimeUsec, &nextFireAtTime); | _UnloadAllLibraries(self, MI_TRUE, currentTimeUsec, &nextFireAtTime); |
| |
|
|
handler->fireTimeoutAt = TIME_NEVER; | handler->fireTimeoutAt = TIME_NEVER; |
} | } |
| |
/* If all libraries are gone, notify caller */ |
|
if (!self->head && self->idleCallback) |
|
(*self->idleCallback)(self,self->idleCallbackData); |
|
|
|
return MI_TRUE; | return MI_TRUE; |
} | } |
| |
|
|
| |
Strlcpy(self->providerDir, providerDir, sizeof(self->providerDir)-1); | Strlcpy(self->providerDir, providerDir, sizeof(self->providerDir)-1); |
| |
self->idleTimeoutUsec = MI_ULL(90) * MI_ULL(1000000); |
self->idleTimeoutUsec = PROVMGR_IDLE_TIMEOUT_USEC; |
| |
/* Add socket handler to catch timeout event */ | /* Add socket handler to catch timeout event */ |
| |
|
|
| |
Selector_AddHandler(selector, &self->timeoutHandler); | Selector_AddHandler(selector, &self->timeoutHandler); |
| |
|
self->ioThreadId = Thread_ID(); /* IO thread always initializes for Linux */ |
|
Lock_Init( &self->liblock ); |
|
|
|
#ifndef DISABLE_INDICATION |
|
RequestHandler_Init(&g_requesthandler); |
|
#endif |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
|
|
if (!self) | if (!self) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
|
#ifndef DISABLE_INDICATION |
|
RequestHandler_Finalize(&g_requesthandler); |
|
#endif |
|
|
/* release opened libraries */ | /* release opened libraries */ |
_UnloadAllLibraries(self, MI_FALSE, 0, NULL); | _UnloadAllLibraries(self, MI_FALSE, 0, NULL); |
| |
|
/* If local session is initialized then we need to clean-up */ |
|
while (Atomic_Read(&self->localSessionInitialized) != 0) |
|
{ |
|
if (Atomic_CompareAndSwap(&self->localSessionInitialized, 2, 1)) |
|
{ |
|
/* Initialized, so need to deinitialize */ |
|
MI_Session_Close(&self->localSession, NULL, NULL); |
|
MI_Application_Close(&self->localApplication); |
|
self->localSessionInitialized = 0; |
|
/* Broadcast does a memory barrier so no need for assignment to be atomic */ |
|
CondLock_Broadcast((ptrdiff_t) &self->localSession); |
|
} |
|
else if (self->localSessionInitialized == 1) |
|
{ |
|
/* Initializing for some reason so wait for it to complete */ |
|
ptrdiff_t init = self->localSessionInitialized; |
|
while (init == 1) |
|
{ |
|
CondLock_Wait((ptrdiff_t)&self->localSession, &self->localSessionInitialized, init, CONDLOCK_DEFAULT_SPINCOUNT); |
|
init = self->localSessionInitialized; |
|
} |
|
} |
|
} |
|
|
memset(self, -1, sizeof(ProvMgr)); | memset(self, -1, sizeof(ProvMgr)); |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
|
|
Routes incoming message to appropriate | Routes incoming message to appropriate |
message handler based on message tag | message handler based on message tag |
*/ | */ |
MI_Result ProvMgr_PostMessage( |
MI_Result MI_CALL ProvMgr_NewRequest( |
ProvMgr* self, |
_In_ ProvMgr* self, |
const char* libraryName, |
_In_ const ProvRegEntry* proventry, |
Message* msg) |
_Inout_ InteractionOpenParams* params ) |
{ | { |
Provider* prov = 0; | Provider* prov = 0; |
MI_Result r = MI_RESULT_INVALID_PARAMETER; | MI_Result r = MI_RESULT_INVALID_PARAMETER; |
| |
/* Check parameters */ | /* Check parameters */ |
if (!self || !msg) |
if( !self || !params || !params->msg || !params->interaction ) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
/* Dispatch the message */ | /* Dispatch the message */ |
switch (msg->tag) |
switch( params->msg->tag ) |
{ | { |
case GetInstanceReqTag: | case GetInstanceReqTag: |
{ | { |
r = _HandleGetInstanceReq(self, libraryName, |
r = _HandleGetInstanceReq(self, proventry, params, &prov); |
(GetInstanceReq*)msg, &prov); |
break; |
|
} |
|
case GetClassReqTag: |
|
{ |
|
r = _HandleGetClassReq(self, proventry, params, &prov); |
break; | break; |
} | } |
case CreateInstanceReqTag: | case CreateInstanceReqTag: |
{ | { |
r = _HandleCreateInstanceReq(self, libraryName, |
r = _HandleCreateInstanceReq(self, proventry, params, &prov); |
(CreateInstanceReq*)msg, &prov); |
|
break; | break; |
} | } |
case ModifyInstanceReqTag: | case ModifyInstanceReqTag: |
{ | { |
r = _HandleModifyInstanceReq(self, libraryName, |
r = _HandleModifyInstanceReq(self, proventry, params, &prov); |
(ModifyInstanceReq*)msg, &prov); |
|
break; | break; |
} | } |
case DeleteInstanceReqTag: | case DeleteInstanceReqTag: |
{ | { |
r = _HandleDeleteInstanceReq(self, libraryName, |
r = _HandleDeleteInstanceReq(self, proventry, params, &prov); |
(DeleteInstanceReq*)msg, &prov); |
|
break; | break; |
} | } |
case InvokeReqTag: | case InvokeReqTag: |
{ | { |
r = _HandleInvokeReq(self, libraryName, |
r = _HandleInvokeReq(self, proventry, params, &prov); |
(InvokeReq*)msg, &prov); |
|
break; | break; |
} | } |
case EnumerateInstancesReqTag: | case EnumerateInstancesReqTag: |
{ | { |
r = _HandleEnumerateInstancesReq(self, libraryName, |
r = _HandleEnumerateInstancesReq(self, proventry, params, &prov); |
(EnumerateInstancesReq*)msg, &prov); |
|
break; | break; |
} | } |
case AssociatorsOfReqTag: | case AssociatorsOfReqTag: |
{ | { |
r = _HandleAssociatorsOfReq(self, libraryName, |
r = _HandleAssociatorsOfReq(self, proventry, params, &prov); |
(AssociatorsOfReq*)msg, &prov); |
|
break; | break; |
} | } |
case ReferencesOfReqTag: | case ReferencesOfReqTag: |
{ | { |
r = _HandleReferencesOfReq(self, libraryName, |
r = _HandleReferencesOfReq(self, proventry, params, &prov); |
(ReferencesOfReq*)msg, &prov); |
|
break; | break; |
} | } |
|
#ifndef DISABLE_INDICATION |
case SubscribeReqTag: | case SubscribeReqTag: |
{ | { |
r = _HandleSubscribeReq(self, libraryName, |
r = _HandleSubscribeReq(self, proventry, params, &prov); |
(SubscribeReq*)msg, &prov); |
|
break; | break; |
} | } |
|
#endif |
default: | default: |
|
trace_ProvMgr_NewRequest_UnsupportedMessage( |
|
params->msg, MessageName(params->msg->tag)); |
break; | break; |
} | } |
| |
Provider_Release(prov); |
Provider_Release(prov); /* Releases hold from Provider_AddRef in _OpenProvider() */ |
return r; | return r; |
} | } |
| |
/* | /* |
Increments provider's ref-counter |
* Increments provider's ref-counter |
*/ | */ |
void Provider_Addref(Provider* provider) | void Provider_Addref(Provider* provider) |
{ | { |
if (provider) | if (provider) |
AtomicInc(&provider->refCounter); |
Atomic_Inc(&provider->refCounter); |
} | } |
| |
/* | /* |
Decrements provider's ref-counter and |
* Finalize provider before free memory |
marks provider as idle if ref-counter is 0 and |
|
'refuse-unload' was not called |
|
*/ | */ |
void Provider_Release(Provider* provider) |
_Use_decl_annotations_ |
|
void Provider_Finalize(Provider* provider) |
{ | { |
if (provider && AtomicDec(&provider->refCounter)) |
if (provider) |
{ | { |
//LOGD((T("Releasing provider %s"), provider->classDecl->name)); |
#ifndef DISABLE_INDICATION |
|
DEBUG_ASSERT( provider->subMgr ); |
|
SubMgr_Finalize( provider->subMgr ); |
|
#endif |
|
} |
|
} |
| |
|
/* |
|
* Decrements provider's ref-counter and |
|
* marks provider as idle if ref-counter is 0 and |
|
* 'refuse-unload' was not called |
|
*/ |
|
void Provider_Release(Provider* provider) |
|
{ |
|
if (provider && Atomic_Dec(&provider->refCounter) == 0) |
|
{ |
if (!provider->refusedUnload) | if (!provider->refusedUnload) |
{ | { |
/* Provider becomes idle */ | /* Provider becomes idle */ |
if (MI_RESULT_OK != Time_Now(&provider->idleSince)) |
if (PAL_TRUE != PAL_Time(&provider->idleSince)) |
provider->idleSince = ~ (MI_Uint64)0; | provider->idleSince = ~ (MI_Uint64)0; |
| |
//LOGD((T("Setting idle-since to ") UINT64_FMT_T T(" for provider %s"), provider->idleSince, provider->classDecl->name)); |
|
|
|
/* Set timer if it's first idle provider */ | /* Set timer if it's first idle provider */ |
if (TIME_NEVER == provider->lib->provmgr->timeoutHandler.fireTimeoutAt) | if (TIME_NEVER == provider->lib->provmgr->timeoutHandler.fireTimeoutAt) |
{ | { |
if (MI_RESULT_OK == Time_Now(&provider->lib->provmgr->timeoutHandler.fireTimeoutAt)) |
if (PAL_TRUE == PAL_Time(&provider->lib->provmgr->timeoutHandler.fireTimeoutAt)) |
{ | { |
provider->lib->provmgr->timeoutHandler.fireTimeoutAt += provider->lib->provmgr->idleTimeoutUsec; | provider->lib->provmgr->timeoutHandler.fireTimeoutAt += provider->lib->provmgr->idleTimeoutUsec; |
| |
//LOGD((T("Setting fire-at to ") UINT64_FMT_T, provider->lib->provmgr->timeoutHandler.fireTimeoutAt)); |
|
|
|
/* wakeup main thread */ | /* wakeup main thread */ |
Selector_Wakeup(provider->lib->provmgr->selector); |
Selector_Wakeup(provider->lib->provmgr->selector, MI_TRUE); |
} | } |
} | } |
} | } |
|
|
provider->refusedUnload = flag; | provider->refusedUnload = flag; |
} | } |
| |
void Provider_NewInstanceCreated( |
|
Provider* provider, |
MI_Result ProvMgr_GetLocalSesson( |
Message* msg) |
_Inout_ ProvMgr* self, |
|
_Out_ MI_Session *localSession) |
|
{ |
|
#if defined(DISABLE_LOCALSESSION) |
|
MI_UNREFERENCED_PARAMETER(self); |
|
MI_UNREFERENCED_PARAMETER(localSession); |
|
|
|
return MI_RESULT_NOT_SUPPORTED; |
|
#else /* defined(DISABLE_LOCALSESSION) */ |
|
|
|
while (Atomic_Read(&self->localSessionInitialized) != 2) |
|
{ |
|
if (Atomic_CompareAndSwap(&self->localSessionInitialized, 0, 1) == 0) |
|
{ |
|
/* Need to initialize */ |
|
MI_Result miResult; |
|
miResult = MI_Application_Initialize(0, MI_T("OMI Local Session"), NULL, &self->localApplication); |
|
if (miResult == MI_RESULT_OK) |
|
{ |
|
miResult = MI_Application_NewSession(&self->localApplication, NULL, NULL, NULL, NULL, NULL, &self->localSession); |
|
if (miResult == MI_RESULT_OK) |
|
{ |
|
/* Succeeded, so mark as initialized */ |
|
*localSession = self->localSession; |
|
self->localSessionInitialized = 2; |
|
} |
|
else |
|
{ |
|
/* Failed, so reset state */ |
|
MI_Application_Close(&self->localApplication); |
|
self->localSessionInitialized = 0; |
|
} |
|
} |
|
else |
|
{ |
|
/* Failed so reset state */ |
|
self->localSessionInitialized = 0; |
|
} |
|
/* memory barrier as part of broadcast which is why state updates were not atomic */ |
|
CondLock_Broadcast((ptrdiff_t) &self->localSession); |
|
|
|
return miResult; |
|
} |
|
else if (self->localSessionInitialized == 1) |
{ | { |
Selector_NewInstanceCreated(provider->lib->provmgr->selector, msg); |
/* Wait for the initialization on another thread to complete */ |
|
ptrdiff_t init = self->localSessionInitialized; |
|
while (init == 1) |
|
{ |
|
CondLock_Wait((ptrdiff_t)&self->localSession, &self->localSessionInitialized, init, CONDLOCK_DEFAULT_SPINCOUNT); |
|
init = self->localSessionInitialized; |
|
} |
|
/* Need to try another trip around the loop to make sure it is initialized this time around */ |
|
} |
|
} |
|
|
|
*localSession = self->localSession; |
|
return MI_RESULT_OK; |
|
#endif /* defined(DISABLE_LOCALSESSION) */ |
} | } |