(file) Return to provmgr.c CVS log (file) (dir) Up to [OMI] / omi / provmgr

   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 }

ViewCVS 0.9.2